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 v3 15/19] acct-user.eclass: A new eclass to maintain user accounts
Date: Sun, 09 Jun 2019 11:33:47
Message-Id: 20190609112814.15907-16-mgorny@gentoo.org
In Reply to: [gentoo-dev] [PATCH v3 00/19] User/group packages by "Michał Górny"
1 A GLEP 81-compliant eclass to create user account packages.
2 ---
3 eclass/acct-user.eclass | 249 ++++++++++++++++++++++++++++++++++++++++
4 1 file changed, 249 insertions(+)
5 create mode 100644 eclass/acct-user.eclass
6
7 diff --git a/eclass/acct-user.eclass b/eclass/acct-user.eclass
8 new file mode 100644
9 index 000000000000..b856a350083d
10 --- /dev/null
11 +++ b/eclass/acct-user.eclass
12 @@ -0,0 +1,249 @@
13 +# Copyright 2019 Gentoo Authors
14 +# Distributed under the terms of the GNU General Public License v2
15 +
16 +# @ECLASS: acct-user.eclass
17 +# @MAINTAINER:
18 +# Michał Górny <mgorny@g.o>
19 +# @AUTHOR:
20 +# Michael Orlitzky <mjo@g.o>
21 +# Michał Górny <mgorny@g.o>
22 +# @BLURB: Eclass used to create and maintain a single user entry
23 +# @DESCRIPTION:
24 +# This eclass represents and creates a single user entry. The name
25 +# of the user is derived from ${PN}, while (preferred) UID needs to
26 +# be specified via ACCT_USER_ID. Additional variables are provided
27 +# to override the default home directory, shell and add group
28 +# membership. Packages needing the user in question should depend
29 +# on the package providing it.
30 +#
31 +# The ebuild needs to call acct-user_add_deps after specifying
32 +# ACCT_USER_GROUPS.
33 +#
34 +# Example:
35 +# If your package needs user 'foo' belonging to same-named group, you
36 +# create 'acct-user/foo' package and add an ebuild with the following
37 +# contents:
38 +#
39 +# @CODE
40 +# EAPI=7
41 +# inherit acct-user
42 +# ACCT_USER_ID=200
43 +# ACCT_USER_GROUPS=( foo )
44 +# acct-user_add_deps
45 +# @CODE
46 +#
47 +# Then you add appropriate dependency to your package. The dependency
48 +# type(s) should be:
49 +# - DEPEND (+ RDEPEND) if the user is already needed at build time,
50 +# - RDEPEND if it is needed at install time (e.g. you 'fowners' files
51 +# in pkg_preinst) or run time.
52 +
53 +if [[ -z ${_ACCT_USER_ECLASS} ]]; then
54 +_ACCT_USER_ECLASS=1
55 +
56 +case ${EAPI:-0} in
57 + 7) ;;
58 + *) die "EAPI=${EAPI} not supported";;
59 +esac
60 +
61 +inherit user
62 +
63 +[[ ${CATEGORY} == acct-user ]] ||
64 + die "Ebuild error: this eclass can be used only in acct-user category!"
65 +
66 +
67 +# << Eclass variables >>
68 +
69 +# @ECLASS-VARIABLE: ACCT_USER_NAME
70 +# @INTERNAL
71 +# @DESCRIPTION:
72 +# The name of the user. This is forced to ${PN} and the policy prohibits
73 +# it from being changed.
74 +ACCT_USER_NAME=${PN}
75 +readonly ACCT_USER_NAME
76 +
77 +# @ECLASS-VARIABLE: ACCT_USER_ID
78 +# @REQUIRED
79 +# @DESCRIPTION:
80 +# Preferred UID for the new user. This variable is obligatory, and its
81 +# value must be unique across all user packages.
82 +
83 +# @ECLASS-VARIABLE: ACCT_USER_ENFORCE_ID
84 +# @DESCRIPTION:
85 +# If set to a non-null value, the eclass will require the user to have
86 +# specified UID. If the user already exists with another UID, or
87 +# the UID is taken by another user, the install will fail.
88 +: ${ACCT_USER_ENFORCE_ID:=}
89 +
90 +# @ECLASS-VARIABLE: ACCT_USER_SHELL
91 +# @DESCRIPTION:
92 +# The shell to use for the user. If not specified, a 'nologin' variant
93 +# for the system is used.
94 +: ${ACCT_USER_SHELL:=-1}
95 +
96 +# @ECLASS-VARIABLE: ACCT_USER_HOME
97 +# @DESCRIPTION:
98 +# The home directory for the user. If not specified, /dev/null is used.
99 +# The directory will be created with appropriate permissions if it does
100 +# not exist. When updating, existing home directory will not be moved.
101 +: ${ACCT_USER_HOME:=/dev/null}
102 +
103 +# @ECLASS-VARIABLE: ACCT_USER_HOME_OWNER
104 +# @DEFAULT_UNSET
105 +# @DESCRIPTION:
106 +# The ownership to use for the home directory, in chown ([user][:group])
107 +# syntax. Defaults to the newly created user, and its primary group.
108 +
109 +# @ECLASS-VARIABLE: ACCT_USER_HOME_PERMS
110 +# @DESCRIPTION:
111 +# The permissions to use for the home directory, in chmod (octal
112 +# or verbose) form.
113 +: ${ACCT_USER_HOME_PERMS:=0755}
114 +
115 +# @ECLASS-VARIABLE: ACCT_USER_GROUPS
116 +# @REQUIRED
117 +# @DESCRIPTION:
118 +# List of groups the user should belong to. This must be a bash
119 +# array.
120 +
121 +
122 +# << Boilerplate ebuild variables >>
123 +: ${DESCRIPTION:="Service user: ${ACCT_USER_NAME}"}
124 +: ${HOMEPAGE:=https://www.gentoo.org/}
125 +: ${SLOT:=0}
126 +: ${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}
127 +S=${WORKDIR}
128 +
129 +
130 +# << API functions >>
131 +
132 +# @FUNCTION: acct-user_add_deps
133 +# @DESCRIPTION:
134 +# Generate appropriate RDEPEND from ACCT_USER_GROUPS. This must be
135 +# called if ACCT_USER_GROUPS are set.
136 +acct-user_add_deps() {
137 + debug-print-function ${FUNCNAME} "${@}"
138 +
139 + # ACCT_USER_GROUPS sanity check
140 + if ! declare -p ACCT_USER_GROUPS &>/dev/null; then
141 + die 'ACCT_USER_GROUPS must be specified.'
142 + elif [[ $(declare -p ACCT_USER_GROUPS) != "declare -a"* ]]; then
143 + die 'ACCT_USER_GROUPS must be an array.'
144 + fi
145 +
146 + RDEPEND+=${ACCT_USER_GROUPS[*]/#/ acct-group/}
147 + _ACCT_USER_ADD_DEPS_CALLED=1
148 +}
149 +
150 +
151 +# << Phase functions >>
152 +EXPORT_FUNCTIONS pkg_pretend src_install pkg_preinst pkg_postinst \
153 + pkg_prerm
154 +
155 +# @FUNCTION: acct-user_pkg_pretend
156 +# @DESCRIPTION:
157 +# Performs sanity checks for correct eclass usage, and early-checks
158 +# whether requested UID can be enforced.
159 +acct-user_pkg_pretend() {
160 + debug-print-function ${FUNCNAME} "${@}"
161 +
162 + # verify that acct-user_add_deps() has been called
163 + # (it verifies ACCT_USER_GROUPS itself)
164 + if [[ -z ${_ACCT_USER_ADD_DEPS_CALLED} ]]; then
165 + die "Ebuild error: acct-user_add_deps must have been called in global scope!"
166 + fi
167 +
168 + # verify ACCT_USER_ID
169 + [[ -n ${ACCT_USER_ID} ]] || die "Ebuild error: ACCT_USER_ID must be set!"
170 + [[ ${ACCT_USER_ID} -ge 0 ]] || die "Ebuild errors: ACCT_USER_ID=${ACCT_USER_ID} invalid!"
171 +
172 + # check for ACCT_USER_ID collisions early
173 + if [[ -n ${ACCT_USER_ENFORCE_ID} ]]; then
174 + local user_by_id=$(egetusername "${ACCT_USER_ID}")
175 + local user_by_name=$(egetent passwd "${ACCT_USER_NAME}")
176 + if [[ -n ${user_by_id} ]]; then
177 + if [[ ${user_by_id} != ${ACCT_USER_NAME} ]]; then
178 + eerror "The required UID is already taken by another user."
179 + eerror " UID: ${ACCT_USER_ID}"
180 + eerror " needed for: ${ACCT_USER_NAME}"
181 + eerror " current user: ${user_by_id}"
182 + die "UID ${ACCT_USER_ID} taken already"
183 + fi
184 + elif [[ -n ${user_by_name} ]]; then
185 + eerror "The requested user exists already with wrong UID."
186 + eerror " username: ${ACCT_USER_NAME}"
187 + eerror " requested UID: ${ACCT_USER_ID}"
188 + eerror " current entry: ${user_by_name}"
189 + die "Username ${ACCT_USER_NAME} exists with wrong UID"
190 + fi
191 + fi
192 +}
193 +
194 +# @FUNCTION: acct-user_src_install
195 +# @DESCRIPTION:
196 +# Installs a keep-file into the user's home directory to ensure it is
197 +# owned by the package.
198 +acct-user_src_install() {
199 + debug-print-function ${FUNCNAME} "${@}"
200 +
201 + if [[ ${ACCT_USER_HOME} != /dev/null ]]; then
202 + # note: we can't set permissions here since the user isn't
203 + # created yet
204 + keepdir "${ACCT_USER_HOME}"
205 + fi
206 +}
207 +
208 +# @FUNCTION: acct-user_pkg_preinst
209 +# @DESCRIPTION:
210 +# Creates the user if it does not exist yet. Sets permissions
211 +# of the home directory in install image.
212 +acct-user_pkg_preinst() {
213 + debug-print-function ${FUNCNAME} "${@}"
214 +
215 + local groups=${ACCT_USER_GROUPS[*]}
216 + enewuser -F -M "${ACCT_USER_NAME}" "${ACCT_USER_ID}" \
217 + "${ACCT_USER_SHELL}" "${ACCT_USER_HOME}" "${groups// /,}"
218 +
219 + if [[ ${ACCT_USER_HOME} != /dev/null ]]; then
220 + # default ownership to user:group
221 + if [[ -z ${ACCT_USER_HOME_OWNER} ]]; then
222 + ACCT_USER_HOME_OWNER=${ACCT_USER_NAME}
223 + if [[ -n ${ACCT_USER_GROUPS[0]} ]]; then
224 + ACCT_USER_HOME_OWNER+=":${ACCT_USER_GROUPS[0]}"
225 + fi
226 + fi
227 + fowners "${ACCT_USER_HOME_OWNER}" "${ACCT_USER_HOME}"
228 + fperms "${ACCT_USER_HOME_PERMS}" "${ACCT_USER_HOME}"
229 + fi
230 +}
231 +
232 +# @FUNCTION: acct-user_pkg_postinst
233 +# @DESCRIPTION:
234 +# Updates user properties if necessary. This needs to be done after
235 +# new home directory is installed.
236 +acct-user_pkg_postinst() {
237 + debug-print-function ${FUNCNAME} "${@}"
238 +
239 + # NB: eset* functions check current value
240 + esethome "${ACCT_USER_NAME}" "${ACCT_USER_HOME}"
241 + esetshell "${ACCT_USER_NAME}" "${ACCT_USER_SHELL}"
242 + local groups=${ACCT_USER_GROUPS[*]}
243 + esetgroups "${ACCT_USER_NAME}" "${groups// /,}"
244 + # comment field can not contain colons
245 + esetcomment "${ACCT_USER_NAME}" "${DESCRIPTION//[:,=]/;}"
246 +}
247 +
248 +# @FUNCTION: acct-user_pkg_prerm
249 +# @DESCRIPTION:
250 +# Ensures that the user account is locked out when it is removed.
251 +acct-user_pkg_prerm() {
252 + debug-print-function ${FUNCNAME} "${@}"
253 +
254 + if [[ -z ${REPLACED_BY_VERSION} ]]; then
255 + esetshell "${ACCT_USER_NAME}" -1
256 + esetcomment "${ACCT_USER_NAME}" \
257 + "$(egetcomment "${ACCT_USER_NAME}"); user account removed @ $(date +%Y-%m-%d)"
258 + fi
259 +}
260 +
261 +fi
262 --
263 2.22.0.rc3

Replies