Gentoo Archives: gentoo-dev

From: "Michał Górny" <mgorny@g.o>
To: gentoo-dev@l.g.o
Cc: "Michał Górny" <mgorny@g.o>
Subject: [gentoo-dev] [PATCH v2 6/9] acct-{group,user}.eclass: WIP eclasses to maintain users/groups
Date: Wed, 05 Jun 2019 09:15:15
Message-Id: 20190605091257.12127-7-mgorny@gentoo.org
In Reply to: [gentoo-dev] [PATCH v2 0/9] User/group packages by "Michał Górny"
1 ---
2 eclass/acct-group.eclass | 105 +++++++++++++++++++
3 eclass/acct-user.eclass | 217 +++++++++++++++++++++++++++++++++++++++
4 2 files changed, 322 insertions(+)
5 create mode 100644 eclass/acct-group.eclass
6 create mode 100644 eclass/acct-user.eclass
7
8 diff --git a/eclass/acct-group.eclass b/eclass/acct-group.eclass
9 new file mode 100644
10 index 000000000000..8b3b2202aa35
11 --- /dev/null
12 +++ b/eclass/acct-group.eclass
13 @@ -0,0 +1,105 @@
14 +# Copyright 2019 Gentoo Authors
15 +# Distributed under the terms of the GNU General Public License v2
16 +
17 +# @ECLASS: acct-group.eclass
18 +# @MAINTAINER:
19 +# Michał Górny <mgorny@g.o>
20 +# @AUTHOR:
21 +# Michael Orlitzky <mjo@g.o>
22 +# Michał Górny <mgorny@g.o>
23 +# @BLURB: Eclass used to create and maintain a single group entry
24 +# @DESCRIPTION:
25 +# This eclass represents and creates a single group entry. The name
26 +# of the group is derived from ${PN}, while (preferred) GID needs to
27 +# be specified via ACCT_GROUP_ID. Packages (and users) needing the group
28 +# in question should depend on the package providing it.
29 +#
30 +# Example:
31 +# If your package needs group 'foo', you create 'acct-group/foo' package
32 +# and add an ebuild with the following contents:
33 +#
34 +# @CODE
35 +# EAPI=7
36 +# inherit acct-group
37 +# ACCT_GROUP_ID=200
38 +# @CODE
39 +#
40 +# Then you add appropriate dependency to your package. The dependency
41 +# type(s) should be:
42 +# - DEPEND (+ RDEPEND) if the group is already needed at build time,
43 +# - RDEPEND if it is needed at install time (e.g. you 'fowners' files
44 +# in pkg_preinst),
45 +# - PDEPEND if it is only needed at runtime.
46 +
47 +
48 +if [[ -z ${_ACCT_GROUP_ECLASS} ]]; then
49 +_ACCT_GROUP_ECLASS=1
50 +
51 +case ${EAPI:-0} in
52 + 7) ;;
53 + *) die "EAPI=${EAPI} not supported";;
54 +esac
55 +
56 +inherit user
57 +
58 +
59 +# << Eclass variables >>
60 +
61 +# @ECLASS-VARIABLE: ACCT_GROUP_ID
62 +# @REQUIRED
63 +# @DESCRIPTION:
64 +# Preferred GID for the new group. This variable is obligatory, and its
65 +# value must be unique across all group packages.
66 +
67 +# @ECLASS-VARIABLE: ACCT_GROUP_ENFORCE_ID
68 +# @DESCRIPTION:
69 +# If set to a non-null value, the eclass will require the group to have
70 +# specified GID. If the group already exists with another GID, or
71 +# the GID is taken by another group, the install will fail.
72 +: ${ACCT_GROUP_ENFORCE_ID:=}
73 +
74 +
75 +# << Boilerplate ebuild variables >>
76 +: ${DESCRIPTION:="Service group: ${PN}"}
77 +: ${HOMEPAGE:=https://www.gentoo.org/}
78 +: ${SLOT:=0}
79 +: ${KEYWORDS:=alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 ~riscv s390 sh sparc x86 ~ppc-aix ~x64-cygwin ~amd64-fbsd ~x86-fbsd ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris}
80 +S=${WORKDIR}
81 +
82 +
83 +# << Phase functions >>
84 +EXPORT_FUNCTIONS pkg_pretend pkg_preinst
85 +
86 +# @FUNCTION: acct-group_pkg_pretend
87 +# @DESCRIPTION:
88 +# Performs sanity checks for correct eclass usage, and early-checks
89 +# whether requested GID can be enforced.
90 +acct-group_pkg_pretend() {
91 + debug-print-function ${FUNCNAME} "${@}"
92 +
93 + # verify ACCT_GROUP_ID
94 + [[ -n ${ACCT_GROUP_ID} ]] || die "Ebuild error: ACCT_GROUP_ID must be set!"
95 + [[ ${ACCT_GROUP_ID} -ge 0 ]] || die "Ebuild errors: ACCT_GROUP_ID=${ACCT_GROUP_ID} invalid!"
96 +
97 + # check for ACCT_GROUP_ID collisions early
98 + if [[ -n ${ACCT_GROUP_ENFORCE_ID} ]]; then
99 + local grp=$(egetent group "${ACCT_GROUP_ID}")
100 + if [[ -n ${grp} ]]; then
101 + eerror "The required GID is already taken by another group."
102 + eerror " GID: ${ACCT_GROUP_ID} (needed for ${PN})"
103 + eerror " current group: ${grp}"
104 + die "GID ${ACCT_GROUP_ID} taken already"
105 + fi
106 + fi
107 +}
108 +
109 +# @FUNCTION: acct-group_pkg_preinst
110 +# @DESCRIPTION:
111 +# Creates the group if it does not exist yet.
112 +acct-group_pkg_preinst() {
113 + debug-print-function ${FUNCNAME} "${@}"
114 +
115 + enewgroup -F "${PN}" "${ACCT_GROUP_ID}"
116 +}
117 +
118 +fi
119 diff --git a/eclass/acct-user.eclass b/eclass/acct-user.eclass
120 new file mode 100644
121 index 000000000000..12bc3652f333
122 --- /dev/null
123 +++ b/eclass/acct-user.eclass
124 @@ -0,0 +1,217 @@
125 +# Copyright 2019 Gentoo Authors
126 +# Distributed under the terms of the GNU General Public License v2
127 +
128 +# @ECLASS: acct-user.eclass
129 +# @MAINTAINER:
130 +# Michał Górny <mgorny@g.o>
131 +# @AUTHOR:
132 +# Michael Orlitzky <mjo@g.o>
133 +# Michał Górny <mgorny@g.o>
134 +# @BLURB: Eclass used to create and maintain a single user entry
135 +# @DESCRIPTION:
136 +# This eclass represents and creates a single user entry. The name
137 +# of the user is derived from ${PN}, while (preferred) UID needs to
138 +# be specified via ACCT_USER_ID. Additional variables are provided
139 +# to override the default home directory, shell and add group
140 +# membership. Packages needing the user in question should depend
141 +# on the package providing it.
142 +#
143 +# Example:
144 +# If your package needs user 'foo' belonging to same-named group, you
145 +# create 'acct-user/foo' package and add an ebuild with the following
146 +# contents:
147 +#
148 +# @CODE
149 +# EAPI=7
150 +# inherit acct-user
151 +# ACCT_USER_ID=200
152 +# ACCT_USER_GROUPS=( foo )
153 +# acct-user_add_deps
154 +# @CODE
155 +#
156 +# Then you add appropriate dependency to your package. The dependency
157 +# type(s) should be:
158 +# - DEPEND (+ RDEPEND) if the user is already needed at build time,
159 +# - RDEPEND if it is needed at install time (e.g. you 'fowners' files
160 +# in pkg_preinst),
161 +# - PDEPEND if it is only needed at runtime.
162 +
163 +if [[ -z ${_ACCT_USER_ECLASS} ]]; then
164 +_ACCT_USER_ECLASS=1
165 +
166 +case ${EAPI:-0} in
167 + 7) ;;
168 + *) die "EAPI=${EAPI} not supported";;
169 +esac
170 +
171 +inherit user
172 +
173 +
174 +# << Eclass variables >>
175 +
176 +# @ECLASS-VARIABLE: ACCT_USER_ID
177 +# @REQUIRED
178 +# @DESCRIPTION:
179 +# Preferred UID for the new user. This variable is obligatory, and its
180 +# value must be unique across all user packages.
181 +
182 +# @ECLASS-VARIABLE: ACCT_USER_ENFORCE_ID
183 +# @DESCRIPTION:
184 +# If set to a non-null value, the eclass will require the user to have
185 +# specified UID. If the user already exists with another UID, or
186 +# the UID is taken by another user, the install will fail.
187 +: ${ACCT_USER_ENFORCE_ID:=}
188 +
189 +# @ECLASS-VARIABLE: ACCT_USER_SHELL
190 +# @DESCRIPTION:
191 +# The shell to use for the new user. If not specified, a 'nologin'
192 +# variant for the system is used. This affects only new user accounts.
193 +: ${ACCT_USER_SHELL:=-1}
194 +
195 +# @ECLASS-VARIABLE: ACCT_USER_HOME
196 +# @DESCRIPTION:
197 +# The home directory for the new user. If not specified, /dev/null
198 +# is used. This affects only new user accounts. The directory will
199 +# be created with appropriate permissions if it does not exist.
200 +: ${ACCT_USER_HOME:=/dev/null}
201 +
202 +# @ECLASS-VARIABLE: ACCT_USER_HOME_OWNER
203 +# @DEFAULT_UNSET
204 +# @DESCRIPTION:
205 +# The ownership to use for the home directory, in chown ([user][:group])
206 +# syntax. Defaults to the newly created user, and its primary group
207 +# (if any; :root otherwise).
208 +
209 +# @ECLASS-VARIABLE: ACCT_USER_HOME_PERMS
210 +# @DESCRIPTION:
211 +# The permissions to use for the home directory, in chmod (octal
212 +# or verbose) form.
213 +: ${ACCT_USER_HOME_PERMS:=0755}
214 +
215 +# @ECLASS-VARIABLE: ACCT_USER_GROUPS
216 +# @DEFAULT_UNSET
217 +# @DESCRIPTION:
218 +# List of groups the user should belong to. This must be a bash
219 +# array. If not specified, the user is not added to any groups.
220 +# This affects only new user accounts.
221 +#
222 +# If ACCT_USER_GROUPS is specified, the ebuild needs to call
223 +# acct-user_add_deps in global scope to add appropriate dependencies.
224 +
225 +
226 +# << Boilerplate ebuild variables >>
227 +: ${DESCRIPTION:="Service user: ${PN}"}
228 +: ${HOMEPAGE:=https://www.gentoo.org/}
229 +: ${SLOT:=0}
230 +: ${KEYWORDS:=alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 ~riscv s390 sh sparc x86 ~ppc-aix ~x64-cygwin ~amd64-fbsd ~x86-fbsd ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris}
231 +S=${WORKDIR}
232 +
233 +
234 +# << API functions >>
235 +
236 +# @FUNCTION: acct-user_add_deps
237 +# @DESCRIPTION:
238 +# Generate appropriate RDEPEND from ACCT_USER_GROUPS. This must be
239 +# called if ACCT_USER_GROUPS are set.
240 +acct-user_add_deps() {
241 + debug-print-function ${FUNCNAME} "${@}"
242 +
243 + # ACCT_USER_GROUPS sanity check
244 + if ! declare -p ACCT_USER_GROUPS &>/dev/null; then
245 + return
246 + elif [[ $(declare -p ACCT_USER_GROUPS) != "declare -a"* ]]; then
247 + die 'ACCT_USER_GROUPS must be an array.'
248 + fi
249 +
250 + RDEPEND+=${ACCT_USER_GROUPS[*]/#/ acct-group/}
251 + _ACCT_USER_ADD_DEPS_CALLED=1
252 +}
253 +
254 +
255 +# << Phase functions >>
256 +EXPORT_FUNCTIONS pkg_pretend src_install pkg_preinst pkg_prerm
257 +
258 +# @FUNCTION: acct-user_pkg_pretend
259 +# @DESCRIPTION:
260 +# Performs sanity checks for correct eclass usage, and early-checks
261 +# whether requested UID can be enforced.
262 +acct-user_pkg_pretend() {
263 + debug-print-function ${FUNCNAME} "${@}"
264 +
265 + # verify that acct-user_add_deps() has been called
266 + # (it verifies ACCT_USER_GROUPS itself)
267 + if [[ -z ${_ACCT_USER_ADD_DEPS_CALLED} ]]; then
268 + if declare -p ACCT_USER_GROUPS &>/dev/null; then
269 + die "Ebuild error: acct-user_add_deps must have been called in global scope!"
270 + fi
271 + fi
272 +
273 + # verify ACCT_USER_ID
274 + [[ -n ${ACCT_USER_ID} ]] || die "Ebuild error: ACCT_USER_ID must be set!"
275 + [[ ${ACCT_USER_ID} -ge 0 ]] || die "Ebuild errors: ACCT_USER_ID=${ACCT_USER_ID} invalid!"
276 +
277 + # check for ACCT_USER_ID collisions early
278 + if [[ -n ${ACCT_USER_ENFORCE_ID} ]]; then
279 + local pwd=$(egetent passwd "${ACCT_USER_ID}")
280 + if [[ -n ${pwd} ]]; then
281 + eerror "The required UID is already taken by another user."
282 + eerror " UID: ${ACCT_USER_ID} (needed for ${PN})"
283 + eerror " current user: ${pwd}"
284 + die "UID ${ACCT_USER_ID} taken already"
285 + fi
286 + fi
287 +}
288 +
289 +# @FUNCTION: acct-user_src_install
290 +# @DESCRIPTION:
291 +# Installs a keep-file into the user's home directory to ensure it is
292 +# owned by the package.
293 +acct-user_src_install() {
294 + debug-print-function ${FUNCNAME} "${@}"
295 +
296 + if [[ ${ACCT_USER_HOME} != /dev/null ]]; then
297 + # note: we can't set permissions here since the user isn't
298 + # created yet
299 + keepdir "${ACCT_USER_HOME}"
300 + fi
301 +}
302 +
303 +# @FUNCTION: acct-user_pkg_preinst
304 +# @DESCRIPTION:
305 +# Creates the user if it does not exist yet. Sets permissions
306 +# of the home directory in install image.
307 +acct-user_pkg_preinst() {
308 + debug-print-function ${FUNCNAME} "${@}"
309 +
310 + local groups=${ACCT_USER_GROUPS[*]}
311 + enewuser -F -M "${PN}" "${ACCT_USER_ID}" "${ACCT_USER_SHELL}" \
312 + "${ACCT_USER_HOME}" "${groups// /,}"
313 +
314 + if [[ ${ACCT_USER_HOME} != /dev/null ]]; then
315 + # default ownership to user:group
316 + if [[ -z ${ACCT_USER_HOME_OWNER} ]]; then
317 + ACCT_USER_HOME_OWNER=${PN}
318 + if [[ -n ${ACCT_USER_GROUPS[0]} ]]; then
319 + ACCT_USER_HOME_OWNER+=:${ACCT_USER_GROUPS[0]}
320 + fi
321 + fi
322 + fowners "${ACCT_USER_HOME_OWNER}" "${ACCT_USER_HOME}"
323 + fperms "${ACCT_USER_HOME_PERMS}" "${ACCT_USER_HOME}"
324 + fi
325 +}
326 +
327 +# @FUNCTION: acct-user_pkg_prerm
328 +# @DESCRIPTION:
329 +# Ensures that the user account is locked out when it is removed.
330 +acct-user_pkg_prerm() {
331 + debug-print-function ${FUNCNAME} "${@}"
332 +
333 + if [[ -z ${REPLACED_BY_VERSION} ]]; then
334 + :
335 + # TODO: what should we do here, exactly? we shouldn't touch
336 + # shell, and it should be nologin anyway. we could reset
337 + # the password but it should not be set anyway.
338 + fi
339 +}
340 +
341 +fi
342 --
343 2.22.0.rc3

Replies