public inbox for gentoo-dev@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Michał Górny" <mgorny@gentoo.org>
To: gentoo-dev@lists.gentoo.org
Cc: "Michał Górny" <mgorny@gentoo.org>
Subject: [gentoo-dev] [PATCH v2 6/9] acct-{group,user}.eclass: WIP eclasses to maintain users/groups
Date: Wed,  5 Jun 2019 11:12:54 +0200	[thread overview]
Message-ID: <20190605091257.12127-7-mgorny@gentoo.org> (raw)
In-Reply-To: <20190605091257.12127-1-mgorny@gentoo.org>

---
 eclass/acct-group.eclass | 105 +++++++++++++++++++
 eclass/acct-user.eclass  | 217 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 322 insertions(+)
 create mode 100644 eclass/acct-group.eclass
 create mode 100644 eclass/acct-user.eclass

diff --git a/eclass/acct-group.eclass b/eclass/acct-group.eclass
new file mode 100644
index 000000000000..8b3b2202aa35
--- /dev/null
+++ b/eclass/acct-group.eclass
@@ -0,0 +1,105 @@
+# Copyright 2019 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: acct-group.eclass
+# @MAINTAINER:
+# Michał Górny <mgorny@gentoo.org>
+# @AUTHOR:
+# Michael Orlitzky <mjo@gentoo.org>
+# Michał Górny <mgorny@gentoo.org>
+# @BLURB: Eclass used to create and maintain a single group entry
+# @DESCRIPTION:
+# This eclass represents and creates a single group entry.  The name
+# of the group is derived from ${PN}, while (preferred) GID needs to
+# be specified via ACCT_GROUP_ID.  Packages (and users) needing the group
+# in question should depend on the package providing it.
+#
+# Example:
+# If your package needs group 'foo', you create 'acct-group/foo' package
+# and add an ebuild with the following contents:
+#
+# @CODE
+# EAPI=7
+# inherit acct-group
+# ACCT_GROUP_ID=200
+# @CODE
+#
+# Then you add appropriate dependency to your package.  The dependency
+# type(s) should be:
+# - DEPEND (+ RDEPEND) if the group is already needed at build time,
+# - RDEPEND if it is needed at install time (e.g. you 'fowners' files
+#   in pkg_preinst),
+# - PDEPEND if it is only needed at runtime.
+
+
+if [[ -z ${_ACCT_GROUP_ECLASS} ]]; then
+_ACCT_GROUP_ECLASS=1
+
+case ${EAPI:-0} in
+	7) ;;
+	*) die "EAPI=${EAPI} not supported";;
+esac
+
+inherit user
+
+
+# << Eclass variables >>
+
+# @ECLASS-VARIABLE: ACCT_GROUP_ID
+# @REQUIRED
+# @DESCRIPTION:
+# Preferred GID for the new group.  This variable is obligatory, and its
+# value must be unique across all group packages.
+
+# @ECLASS-VARIABLE: ACCT_GROUP_ENFORCE_ID
+# @DESCRIPTION:
+# If set to a non-null value, the eclass will require the group to have
+# specified GID.  If the group already exists with another GID, or
+# the GID is taken by another group, the install will fail.
+: ${ACCT_GROUP_ENFORCE_ID:=}
+
+
+# << Boilerplate ebuild variables >>
+: ${DESCRIPTION:="Service group: ${PN}"}
+: ${HOMEPAGE:=https://www.gentoo.org/}
+: ${SLOT:=0}
+: ${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}
+S=${WORKDIR}
+
+
+# << Phase functions >>
+EXPORT_FUNCTIONS pkg_pretend pkg_preinst
+
+# @FUNCTION: acct-group_pkg_pretend
+# @DESCRIPTION:
+# Performs sanity checks for correct eclass usage, and early-checks
+# whether requested GID can be enforced.
+acct-group_pkg_pretend() {
+	debug-print-function ${FUNCNAME} "${@}"
+
+	# verify ACCT_GROUP_ID
+	[[ -n ${ACCT_GROUP_ID} ]] || die "Ebuild error: ACCT_GROUP_ID must be set!"
+	[[ ${ACCT_GROUP_ID} -ge 0 ]] || die "Ebuild errors: ACCT_GROUP_ID=${ACCT_GROUP_ID} invalid!"
+
+	# check for ACCT_GROUP_ID collisions early
+	if [[ -n ${ACCT_GROUP_ENFORCE_ID} ]]; then
+		local grp=$(egetent group "${ACCT_GROUP_ID}")
+		if [[ -n ${grp} ]]; then
+			eerror "The required GID is already taken by another group."
+			eerror "  GID: ${ACCT_GROUP_ID} (needed for ${PN})"
+			eerror "  current group: ${grp}"
+			die "GID ${ACCT_GROUP_ID} taken already"
+		fi
+	fi
+}
+
+# @FUNCTION: acct-group_pkg_preinst
+# @DESCRIPTION:
+# Creates the group if it does not exist yet.
+acct-group_pkg_preinst() {
+	debug-print-function ${FUNCNAME} "${@}"
+
+	enewgroup -F "${PN}" "${ACCT_GROUP_ID}"
+}
+
+fi
diff --git a/eclass/acct-user.eclass b/eclass/acct-user.eclass
new file mode 100644
index 000000000000..12bc3652f333
--- /dev/null
+++ b/eclass/acct-user.eclass
@@ -0,0 +1,217 @@
+# Copyright 2019 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: acct-user.eclass
+# @MAINTAINER:
+# Michał Górny <mgorny@gentoo.org>
+# @AUTHOR:
+# Michael Orlitzky <mjo@gentoo.org>
+# Michał Górny <mgorny@gentoo.org>
+# @BLURB: Eclass used to create and maintain a single user entry
+# @DESCRIPTION:
+# This eclass represents and creates a single user entry.  The name
+# of the user is derived from ${PN}, while (preferred) UID needs to
+# be specified via ACCT_USER_ID.  Additional variables are provided
+# to override the default home directory, shell and add group
+# membership.  Packages needing the user in question should depend
+# on the package providing it.
+#
+# Example:
+# If your package needs user 'foo' belonging to same-named group, you
+# create 'acct-user/foo' package and add an ebuild with the following
+# contents:
+#
+# @CODE
+# EAPI=7
+# inherit acct-user
+# ACCT_USER_ID=200
+# ACCT_USER_GROUPS=( foo )
+# acct-user_add_deps
+# @CODE
+#
+# Then you add appropriate dependency to your package.  The dependency
+# type(s) should be:
+# - DEPEND (+ RDEPEND) if the user is already needed at build time,
+# - RDEPEND if it is needed at install time (e.g. you 'fowners' files
+#   in pkg_preinst),
+# - PDEPEND if it is only needed at runtime.
+
+if [[ -z ${_ACCT_USER_ECLASS} ]]; then
+_ACCT_USER_ECLASS=1
+
+case ${EAPI:-0} in
+	7) ;;
+	*) die "EAPI=${EAPI} not supported";;
+esac
+
+inherit user
+
+
+# << Eclass variables >>
+
+# @ECLASS-VARIABLE: ACCT_USER_ID
+# @REQUIRED
+# @DESCRIPTION:
+# Preferred UID for the new user.  This variable is obligatory, and its
+# value must be unique across all user packages.
+
+# @ECLASS-VARIABLE: ACCT_USER_ENFORCE_ID
+# @DESCRIPTION:
+# If set to a non-null value, the eclass will require the user to have
+# specified UID.  If the user already exists with another UID, or
+# the UID is taken by another user, the install will fail.
+: ${ACCT_USER_ENFORCE_ID:=}
+
+# @ECLASS-VARIABLE: ACCT_USER_SHELL
+# @DESCRIPTION:
+# The shell to use for the new user.  If not specified, a 'nologin'
+# variant for the system is used.  This affects only new user accounts.
+: ${ACCT_USER_SHELL:=-1}
+
+# @ECLASS-VARIABLE: ACCT_USER_HOME
+# @DESCRIPTION:
+# The home directory for the new user.  If not specified, /dev/null
+# is used.  This affects only new user accounts.  The directory will
+# be created with appropriate permissions if it does not exist.
+: ${ACCT_USER_HOME:=/dev/null}
+
+# @ECLASS-VARIABLE: ACCT_USER_HOME_OWNER
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# The ownership to use for the home directory, in chown ([user][:group])
+# syntax.  Defaults to the newly created user, and its primary group
+# (if any; :root otherwise).
+
+# @ECLASS-VARIABLE: ACCT_USER_HOME_PERMS
+# @DESCRIPTION:
+# The permissions to use for the home directory, in chmod (octal
+# or verbose) form.
+: ${ACCT_USER_HOME_PERMS:=0755}
+
+# @ECLASS-VARIABLE: ACCT_USER_GROUPS
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# List of groups the user should belong to.  This must be a bash
+# array.  If not specified, the user is not added to any groups.
+# This affects only new user accounts.
+#
+# If ACCT_USER_GROUPS is specified, the ebuild needs to call
+# acct-user_add_deps in global scope to add appropriate dependencies.
+
+
+# << Boilerplate ebuild variables >>
+: ${DESCRIPTION:="Service user: ${PN}"}
+: ${HOMEPAGE:=https://www.gentoo.org/}
+: ${SLOT:=0}
+: ${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}
+S=${WORKDIR}
+
+
+# << API functions >>
+
+# @FUNCTION: acct-user_add_deps
+# @DESCRIPTION:
+# Generate appropriate RDEPEND from ACCT_USER_GROUPS.  This must be
+# called if ACCT_USER_GROUPS are set.
+acct-user_add_deps() {
+	debug-print-function ${FUNCNAME} "${@}"
+
+	# ACCT_USER_GROUPS sanity check
+	if ! declare -p ACCT_USER_GROUPS &>/dev/null; then
+		return
+	elif [[ $(declare -p ACCT_USER_GROUPS) != "declare -a"* ]]; then
+		die 'ACCT_USER_GROUPS must be an array.'
+	fi
+
+	RDEPEND+=${ACCT_USER_GROUPS[*]/#/ acct-group/}
+	_ACCT_USER_ADD_DEPS_CALLED=1
+}
+
+
+# << Phase functions >>
+EXPORT_FUNCTIONS pkg_pretend src_install pkg_preinst pkg_prerm
+
+# @FUNCTION: acct-user_pkg_pretend
+# @DESCRIPTION:
+# Performs sanity checks for correct eclass usage, and early-checks
+# whether requested UID can be enforced.
+acct-user_pkg_pretend() {
+	debug-print-function ${FUNCNAME} "${@}"
+
+	# verify that acct-user_add_deps() has been called
+	# (it verifies ACCT_USER_GROUPS itself)
+	if [[ -z ${_ACCT_USER_ADD_DEPS_CALLED} ]]; then
+		if declare -p ACCT_USER_GROUPS &>/dev/null; then
+			die "Ebuild error: acct-user_add_deps must have been called in global scope!"
+		fi
+	fi
+
+	# verify ACCT_USER_ID
+	[[ -n ${ACCT_USER_ID} ]] || die "Ebuild error: ACCT_USER_ID must be set!"
+	[[ ${ACCT_USER_ID} -ge 0 ]] || die "Ebuild errors: ACCT_USER_ID=${ACCT_USER_ID} invalid!"
+
+	# check for ACCT_USER_ID collisions early
+	if [[ -n ${ACCT_USER_ENFORCE_ID} ]]; then
+		local pwd=$(egetent passwd "${ACCT_USER_ID}")
+		if [[ -n ${pwd} ]]; then
+			eerror "The required UID is already taken by another user."
+			eerror "  UID: ${ACCT_USER_ID} (needed for ${PN})"
+			eerror "  current user: ${pwd}"
+			die "UID ${ACCT_USER_ID} taken already"
+		fi
+	fi
+}
+
+# @FUNCTION: acct-user_src_install
+# @DESCRIPTION:
+# Installs a keep-file into the user's home directory to ensure it is
+# owned by the package.
+acct-user_src_install() {
+	debug-print-function ${FUNCNAME} "${@}"
+
+	if [[ ${ACCT_USER_HOME} != /dev/null ]]; then
+		# note: we can't set permissions here since the user isn't
+		# created yet
+		keepdir "${ACCT_USER_HOME}"
+	fi
+}
+
+# @FUNCTION: acct-user_pkg_preinst
+# @DESCRIPTION:
+# Creates the user if it does not exist yet.  Sets permissions
+# of the home directory in install image.
+acct-user_pkg_preinst() {
+	debug-print-function ${FUNCNAME} "${@}"
+
+	local groups=${ACCT_USER_GROUPS[*]}
+	enewuser -F -M "${PN}" "${ACCT_USER_ID}" "${ACCT_USER_SHELL}" \
+		"${ACCT_USER_HOME}" "${groups// /,}"
+
+	if [[ ${ACCT_USER_HOME} != /dev/null ]]; then
+		# default ownership to user:group
+		if [[ -z ${ACCT_USER_HOME_OWNER} ]]; then
+			ACCT_USER_HOME_OWNER=${PN}
+			if [[ -n ${ACCT_USER_GROUPS[0]} ]]; then
+				ACCT_USER_HOME_OWNER+=:${ACCT_USER_GROUPS[0]}
+			fi
+		fi
+		fowners "${ACCT_USER_HOME_OWNER}" "${ACCT_USER_HOME}"
+		fperms "${ACCT_USER_HOME_PERMS}" "${ACCT_USER_HOME}"
+	fi
+}
+
+# @FUNCTION: acct-user_pkg_prerm
+# @DESCRIPTION:
+# Ensures that the user account is locked out when it is removed.
+acct-user_pkg_prerm() {
+	debug-print-function ${FUNCNAME} "${@}"
+
+	if [[ -z ${REPLACED_BY_VERSION} ]]; then
+		:
+		# TODO: what should we do here, exactly?  we shouldn't touch
+		# shell, and it should be nologin anyway.  we could reset
+		# the password but it should not be set anyway.
+	fi
+}
+
+fi
-- 
2.22.0.rc3



  parent reply	other threads:[~2019-06-05  9:15 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-05  9:12 [gentoo-dev] [PATCH v2 0/9] User/group packages Michał Górny
2019-06-05  9:12 ` [gentoo-dev] [PATCH v2 1/9] user.eclass: Do not create user-group automatically Michał Górny
2019-06-05  9:12 ` [gentoo-dev] [PATCH v2 2/9] user.eclass: Prevent automated home creation in useradd Michał Górny
2019-06-05  9:12 ` [gentoo-dev] [PATCH v2 3/9] user.eclass: Support disabling home directory creation Michał Górny
2019-06-05  9:12 ` [gentoo-dev] [PATCH v2 4/9] user.eclass: Support forcing specified UID/GID Michał Górny
2019-06-05  9:12 ` [gentoo-dev] [PATCH v2 5/9] user.eclass: Die if no free UID/GID is found Michał Górny
2019-06-05  9:12 ` Michał Górny [this message]
2019-06-05 11:46   ` [gentoo-dev] [PATCH v2 6/9] acct-{group,user}.eclass: WIP eclasses to maintain users/groups Ulrich Mueller
2019-06-06  4:56     ` Michał Górny
2019-06-05 19:10   ` Pacho Ramos
2019-06-06  4:57     ` Michał Górny
2019-06-06  7:05       ` Ulrich Mueller
2019-06-05 21:14   ` Michael Orlitzky
2019-06-06  5:02     ` Michał Górny
2019-06-05  9:12 ` [gentoo-dev] [PATCH v2 7/9] acct-group/ftp: Add 'ftp' group (GID 21) Michał Górny
     [not found]   ` <3868289f-1e37-631a-daeb-d1a4b2454669@gentoo.org>
2019-06-07  5:01     ` Michał Górny
2019-06-05  9:12 ` [gentoo-dev] [PATCH v2 8/9] acct-user/ftp: Add 'ftp' user (UID 21) Michał Górny
2019-06-05  9:12 ` [gentoo-dev] [PATCH v2 9/9] net-ftp/ftpbase: Utilize {group,user}/ftp Michał Górny

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190605091257.12127-7-mgorny@gentoo.org \
    --to=mgorny@gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox