summaryrefslogtreecommitdiff
path: root/eclass
diff options
context:
space:
mode:
authorV3n3RiX <venerix@redcorelinux.org>2019-06-22 11:40:06 +0100
committerV3n3RiX <venerix@redcorelinux.org>2019-06-22 11:40:06 +0100
commit7a86906b67693cc65671d3e1476835d3a7e13092 (patch)
tree9de1b9e2cf77833183d4e5ffab2e94d0403ef725 /eclass
parentd56d144655e3785864da43c9acb6c228ef9360ae (diff)
gentoo resync : 22.06.2019
Diffstat (limited to 'eclass')
-rw-r--r--eclass/acct-group.eclass124
-rw-r--r--eclass/acct-user.eclass373
2 files changed, 497 insertions, 0 deletions
diff --git a/eclass/acct-group.eclass b/eclass/acct-group.eclass
new file mode 100644
index 000000000000..7fe9f19effc7
--- /dev/null
+++ b/eclass/acct-group.eclass
@@ -0,0 +1,124 @@
+# 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) or run time.
+
+if [[ -z ${_ACCT_GROUP_ECLASS} ]]; then
+_ACCT_GROUP_ECLASS=1
+
+case ${EAPI:-0} in
+ 7) ;;
+ *) die "EAPI=${EAPI} not supported";;
+esac
+
+inherit user
+
+[[ ${CATEGORY} == acct-group ]] ||
+ die "Ebuild error: this eclass can be used only in acct-group category!"
+
+
+# << Eclass variables >>
+
+# @ECLASS-VARIABLE: ACCT_GROUP_NAME
+# @INTERNAL
+# @DESCRIPTION:
+# The name of the group. This is forced to ${PN} and the policy
+# prohibits it from being changed.
+ACCT_GROUP_NAME=${PN}
+readonly ACCT_GROUP_NAME
+
+# @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:="System group: ${ACCT_GROUP_NAME}"}
+: ${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 group_by_id=$(egetgroupname "${ACCT_GROUP_ID}")
+ local group_by_name=$(egetent group "${ACCT_GROUP_NAME}")
+ if [[ -n ${group_by_id} ]]; then
+ if [[ ${group_by_id} != ${ACCT_GROUP_NAME} ]]; then
+ eerror "The required GID is already taken by another group."
+ eerror " GID: ${ACCT_GROUP_ID}"
+ eerror " needed for: ${ACCT_GROUP_NAME}"
+ eerror " current group: ${group_by_id}"
+ die "GID ${ACCT_GROUP_ID} taken already"
+ fi
+ elif [[ -n ${group_by_name} ]]; then
+ eerror "The requested group exists already with wrong GID."
+ eerror " groupname: ${ACCT_GROUP_NAME}"
+ eerror " requested UID: ${ACCT_GROUP_ID}"
+ eerror " current entry: ${group_by_name}"
+ die "Group ${ACCT_GROUP_NAME} exists with wrong GID"
+ 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 "${ACCT_GROUP_NAME}" "${ACCT_GROUP_ID}"
+}
+
+fi
diff --git a/eclass/acct-user.eclass b/eclass/acct-user.eclass
new file mode 100644
index 000000000000..1b8a0bf94a62
--- /dev/null
+++ b/eclass/acct-user.eclass
@@ -0,0 +1,373 @@
+# 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.
+#
+# The ebuild needs to call acct-user_add_deps after specifying
+# ACCT_USER_GROUPS.
+#
+# 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) or run time.
+
+if [[ -z ${_ACCT_USER_ECLASS} ]]; then
+_ACCT_USER_ECLASS=1
+
+case ${EAPI:-0} in
+ 7) ;;
+ *) die "EAPI=${EAPI} not supported";;
+esac
+
+inherit user
+
+[[ ${CATEGORY} == acct-user ]] ||
+ die "Ebuild error: this eclass can be used only in acct-user category!"
+
+
+# << Eclass variables >>
+
+# @ECLASS-VARIABLE: ACCT_USER_NAME
+# @INTERNAL
+# @DESCRIPTION:
+# The name of the user. This is forced to ${PN} and the policy prohibits
+# it from being changed.
+ACCT_USER_NAME=${PN}
+readonly ACCT_USER_NAME
+
+# @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 user. If not specified, a 'nologin' variant
+# for the system is used.
+: ${ACCT_USER_SHELL:=-1}
+
+# @ECLASS-VARIABLE: ACCT_USER_HOME
+# @DESCRIPTION:
+# The home directory for the user. If not specified, /dev/null is used.
+# The directory will be created with appropriate permissions if it does
+# not exist. When updating, existing home directory will not be moved.
+: ${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.
+
+# @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
+# @REQUIRED
+# @DESCRIPTION:
+# List of groups the user should belong to. This must be a bash
+# array.
+
+
+# << Boilerplate ebuild variables >>
+: ${DESCRIPTION:="System user: ${ACCT_USER_NAME}"}
+: ${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) != "declare -a"* ]]; then
+ die 'ACCT_USER_GROUPS must be an array.'
+ elif [[ ${#ACCT_USER_GROUPS[@]} -eq 0 ]]; then
+ die 'ACCT_USER_GROUPS must not be empty.'
+ fi
+
+ RDEPEND+=${ACCT_USER_GROUPS[*]/#/ acct-group/}
+ _ACCT_USER_ADD_DEPS_CALLED=1
+}
+
+
+# << Helper functions >>
+
+# @FUNCTION: eislocked
+# @INTERNAL
+# @USAGE: <user>
+# @DESCRIPTION:
+# Check whether the specified user account is currently locked.
+# Returns 0 if it is locked, 1 if it is not, 2 if the platform
+# does not support determining it.
+eislocked() {
+ [[ $# -eq 1 ]] || die "usage: ${FUNCNAME} <user>"
+
+ if [[ ${EUID} != 0 ]] ; then
+ einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
+ return 0
+ fi
+
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*|*-netbsd*)
+ [[ $(egetent "$1" | cut -d: -f2) == '*LOCKED*'* ]]
+ ;;
+
+ *-openbsd*)
+ return 2
+ ;;
+
+ *)
+ # NB: 'no password' and 'locked' are indistinguishable
+ # but we also expire the account which is more clear
+ [[ $(getent shadow ftp | cut -d: -f2) == '!'* ]] &&
+ [[ $(getent shadow ftp | cut -d: -f8) == 1 ]]
+ ;;
+ esac
+}
+
+# @FUNCTION: elockuser
+# @INTERNAL
+# @USAGE: <user>
+# @DESCRIPTION:
+# Lock the specified user account, using the available platform-specific
+# functions. This should prevent any login to the account.
+#
+# Established lock can be reverted using eunlockuser.
+#
+# This function returns 0 if locking succeeded, 2 if it is not supported
+# by the platform code or dies if it fails.
+elockuser() {
+ [[ $# -eq 1 ]] || die "usage: ${FUNCNAME} <user>"
+
+ if [[ ${EUID} != 0 ]] ; then
+ einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
+ return 0
+ fi
+
+ eislocked "$1"
+ [[ $? -eq 0 ]] && return 0
+
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pw lock "$1" || die "Locking account $1 failed"
+ pw user mod "$1" -e 1 || die "Expiring account $1 failed"
+ ;;
+
+ *-netbsd*)
+ usermod -e 1 -C yes "$1" || die "Locking account $1 failed"
+ ;;
+
+ *-openbsd*)
+ return 2
+ ;;
+
+ *)
+ usermod -e 1 -L "$1" || die "Locking account $1 failed"
+ ;;
+ esac
+
+ elog "User account $1 locked"
+ return 0
+}
+
+# @FUNCTION: eunlockuser
+# @INTERNAL
+# @USAGE: <user>
+# @DESCRIPTION:
+# Unlock the specified user account, using the available platform-
+# specific functions.
+#
+# This function returns 0 if unlocking succeeded, 1 if it is not
+# supported by the platform code or dies if it fails.
+eunlockuser() {
+ [[ $# -eq 1 ]] || die "usage: ${FUNCNAME} <user>"
+
+ if [[ ${EUID} != 0 ]] ; then
+ einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
+ return 0
+ fi
+
+ eislocked "$1"
+ [[ $? -eq 1 ]] && return 0
+
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pw user mod "$1" -e 0 || die "Unexpiring account $1 failed"
+ pw unlock "$1" || die "Unlocking account $1 failed"
+ ;;
+
+ *-netbsd*)
+ usermod -e 0 -C no "$1" || die "Unlocking account $1 failed"
+ ;;
+
+ *-openbsd*)
+ return 1
+ ;;
+
+ *)
+ # silence warning if account does not have a password
+ usermod -e "" -U "$1" 2>/dev/null || die "Unlocking account $1 failed"
+ ;;
+ esac
+
+ ewarn "User account $1 unlocked after reinstating."
+ return 0
+}
+
+
+# << Phase functions >>
+EXPORT_FUNCTIONS pkg_pretend src_install pkg_preinst pkg_postinst \
+ 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
+ die "Ebuild error: acct-user_add_deps must have been called in global scope!"
+ 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 user_by_id=$(egetusername "${ACCT_USER_ID}")
+ local user_by_name=$(egetent passwd "${ACCT_USER_NAME}")
+ if [[ -n ${user_by_id} ]]; then
+ if [[ ${user_by_id} != ${ACCT_USER_NAME} ]]; then
+ eerror "The required UID is already taken by another user."
+ eerror " UID: ${ACCT_USER_ID}"
+ eerror " needed for: ${ACCT_USER_NAME}"
+ eerror " current user: ${user_by_id}"
+ die "UID ${ACCT_USER_ID} taken already"
+ fi
+ elif [[ -n ${user_by_name} ]]; then
+ eerror "The requested user exists already with wrong UID."
+ eerror " username: ${ACCT_USER_NAME}"
+ eerror " requested UID: ${ACCT_USER_ID}"
+ eerror " current entry: ${user_by_name}"
+ die "Username ${ACCT_USER_NAME} exists with wrong UID"
+ 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 "${ACCT_USER_NAME}" "${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=${ACCT_USER_NAME}:${ACCT_USER_GROUPS[0]}
+ fi
+ fowners "${ACCT_USER_HOME_OWNER}" "${ACCT_USER_HOME}"
+ fperms "${ACCT_USER_HOME_PERMS}" "${ACCT_USER_HOME}"
+ fi
+}
+
+# @FUNCTION: acct-user_pkg_postinst
+# @DESCRIPTION:
+# Updates user properties if necessary. This needs to be done after
+# new home directory is installed.
+acct-user_pkg_postinst() {
+ debug-print-function ${FUNCNAME} "${@}"
+
+ # NB: eset* functions check current value
+ esethome "${ACCT_USER_NAME}" "${ACCT_USER_HOME}"
+ esetshell "${ACCT_USER_NAME}" "${ACCT_USER_SHELL}"
+ local groups=${ACCT_USER_GROUPS[*]}
+ esetgroups "${ACCT_USER_NAME}" "${groups// /,}"
+ # comment field can not contain colons
+ esetcomment "${ACCT_USER_NAME}" "${DESCRIPTION//[:,=]/;}"
+ eunlockuser "${ACCT_USER_NAME}"
+}
+
+# @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
+ esetshell "${ACCT_USER_NAME}" -1
+ esetcomment "${ACCT_USER_NAME}" \
+ "$(egetcomment "${ACCT_USER_NAME}"); user account removed @ $(date +%Y-%m-%d)"
+ elockuser "${ACCT_USER_NAME}"
+ fi
+}
+
+fi