diff --git a/sdk_container/src/third_party/portage-stable/acct-group/sshd/metadata.xml b/sdk_container/src/third_party/portage-stable/acct-group/sshd/metadata.xml
new file mode 100644
index 0000000000..3e60a9a347
--- /dev/null
+++ b/sdk_container/src/third_party/portage-stable/acct-group/sshd/metadata.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ base-system@gentoo.org
+ Gentoo Base System
+
+
diff --git a/sdk_container/src/third_party/portage-stable/acct-group/sshd/sshd-0.ebuild b/sdk_container/src/third_party/portage-stable/acct-group/sshd/sshd-0.ebuild
new file mode 100644
index 0000000000..d54032fc8a
--- /dev/null
+++ b/sdk_container/src/third_party/portage-stable/acct-group/sshd/sshd-0.ebuild
@@ -0,0 +1,8 @@
+# Copyright 2020 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=7
+
+inherit acct-group
+
+ACCT_GROUP_ID=22
diff --git a/sdk_container/src/third_party/portage-stable/acct-user/sshd/metadata.xml b/sdk_container/src/third_party/portage-stable/acct-user/sshd/metadata.xml
new file mode 100644
index 0000000000..3e60a9a347
--- /dev/null
+++ b/sdk_container/src/third_party/portage-stable/acct-user/sshd/metadata.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ base-system@gentoo.org
+ Gentoo Base System
+
+
diff --git a/sdk_container/src/third_party/portage-stable/acct-user/sshd/sshd-0.ebuild b/sdk_container/src/third_party/portage-stable/acct-user/sshd/sshd-0.ebuild
new file mode 100644
index 0000000000..06703c1956
--- /dev/null
+++ b/sdk_container/src/third_party/portage-stable/acct-user/sshd/sshd-0.ebuild
@@ -0,0 +1,15 @@
+# Copyright 2020 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=7
+
+inherit acct-user
+
+DESCRIPTION="User for ssh"
+
+ACCT_USER_ID=22
+ACCT_USER_HOME=/var/empty
+ACCT_USER_HOME_OWNER=root:root
+ACCT_USER_GROUPS=( sshd )
+
+acct-user_add_deps
diff --git a/sdk_container/src/third_party/portage-stable/eclass/acct-group.eclass b/sdk_container/src/third_party/portage-stable/eclass/acct-group.eclass
new file mode 100644
index 0000000000..0b943454a9
--- /dev/null
+++ b/sdk_container/src/third_party/portage-stable/eclass/acct-group.eclass
@@ -0,0 +1,129 @@
+# Copyright 2019 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: acct-group.eclass
+# @MAINTAINER:
+# Michał Górny
+# @AUTHOR:
+# Michael Orlitzky
+# Michał Górny
+# @SUPPORTED_EAPIS: 7
+# @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:-0} 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.
+#
+# Overlays should set this to -1 to dynamically allocate GID. Using -1
+# in ::gentoo is prohibited by policy.
+
+# @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}"}
+: ${SLOT:=0}
+: ${KEYWORDS:=alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 ~riscv s390 sh sparc x86 ~ppc-aix ~x64-cygwin ~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} -eq -1 ]] && return
+ [[ ${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 GID: ${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 ${ACCT_GROUP_ENFORCE_ID:+-F} "${ACCT_GROUP_NAME}" \
+ "${ACCT_GROUP_ID}"
+}
+
+fi
diff --git a/sdk_container/src/third_party/portage-stable/eclass/acct-user.eclass b/sdk_container/src/third_party/portage-stable/eclass/acct-user.eclass
new file mode 100644
index 0000000000..e3ec396603
--- /dev/null
+++ b/sdk_container/src/third_party/portage-stable/eclass/acct-user.eclass
@@ -0,0 +1,403 @@
+# Copyright 2019 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: acct-user.eclass
+# @MAINTAINER:
+# Michał Górny
+# @AUTHOR:
+# Michael Orlitzky
+# Michał Górny
+# @SUPPORTED_EAPIS: 7
+# @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:-0} 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.
+#
+# Overlays should set this to -1 to dynamically allocate UID. Using -1
+# in ::gentoo is prohibited by policy.
+
+# @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. The first group specified is the user's primary group, while
+# the remaining groups (if any) become supplementary groups.
+
+
+# << Boilerplate ebuild variables >>
+: ${DESCRIPTION:="System user: ${ACCT_USER_NAME}"}
+: ${SLOT:=0}
+: ${KEYWORDS:=alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 ~riscv s390 sh sparc x86 ~ppc-aix ~x64-cygwin ~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:
+# @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} "
+
+ 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 "$1" | cut -d: -f2) == '!'* ]] &&
+ [[ $(getent shadow "$1" | cut -d: -f8) == 1 ]]
+ ;;
+ esac
+}
+
+# @FUNCTION: elockuser
+# @INTERNAL
+# @USAGE:
+# @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} "
+
+ 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:
+# @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} "
+
+ 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} -eq -1 ]] && return
+ [[ ${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 ${ACCT_USER_ENFORCE_ID:+-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
+ # Path might be missing due to INSTALL_MASK, etc.
+ # https://bugs.gentoo.org/691478
+ if [[ ! -e "${ED}/${ACCT_USER_HOME#/}" ]]; then
+ eerror "Home directory is missing from the installation image:"
+ eerror " ${ACCT_USER_HOME}"
+ eerror "Check INSTALL_MASK for entries that would cause this."
+ die "${ACCT_USER_HOME} does not exist"
+ 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} "${@}"
+
+ if [[ ${EUID} != 0 ]] ; then
+ einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
+ return 0
+ fi
+
+ # 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 [[ ${EUID} != 0 ]] ; then
+ einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
+ return 0
+ fi
+
+ if [[ -z ${REPLACED_BY_VERSION} ]]; then
+ if [[ -z $(egetent passwd "${ACCT_USER_NAME}") ]]; then
+ ewarn "User account not found: ${ACCT_USER_NAME}"
+ ewarn "Locking process will be skipped."
+ return
+ fi
+
+ 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
diff --git a/sdk_container/src/third_party/portage-stable/eclass/user-info.eclass b/sdk_container/src/third_party/portage-stable/eclass/user-info.eclass
new file mode 100644
index 0000000000..15e9238ab4
--- /dev/null
+++ b/sdk_container/src/third_party/portage-stable/eclass/user-info.eclass
@@ -0,0 +1,158 @@
+# Copyright 1999-2020 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: user-info.eclass
+# @MAINTAINER:
+# base-system@gentoo.org (Linux)
+# Michał Górny (NetBSD)
+# @BLURB: Read-only access to user and group information
+
+if [[ -z ${_USER_INFO_ECLASS} ]]; then
+_USER_INFO_ECLASS=1
+
+# @FUNCTION: egetent
+# @USAGE:
+# @DESCRIPTION:
+# Small wrapper for getent (Linux), nidump (< Mac OS X 10.5),
+# dscl (Mac OS X 10.5), and pw (FreeBSD) used in enewuser()/enewgroup().
+#
+# Supported databases: group passwd
+egetent() {
+ local db=$1 key=$2
+
+ [[ $# -ge 3 ]] && die "usage: egetent "
+
+ case ${db} in
+ passwd|group) ;;
+ *) die "sorry, database '${db}' not yet supported; file a bug" ;;
+ esac
+
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ case ${db} in
+ passwd) db="user" ;;
+ *) ;;
+ esac
+
+ # lookup by uid/gid
+ local opts
+ if [[ ${key} == [[:digit:]]* ]] ; then
+ [[ ${db} == "user" ]] && opts="-u" || opts="-g"
+ fi
+
+ pw show ${db} ${opts} "${key}" -q
+ ;;
+ *-openbsd*)
+ grep "${key}:\*:" /etc/${db}
+ ;;
+ *)
+ # ignore nscd output if we're not running as root
+ type -p nscd >/dev/null && nscd -i "${db}" 2>/dev/null
+ getent "${db}" "${key}"
+ ;;
+ esac
+}
+
+# @FUNCTION: egetusername
+# @USAGE:
+# @DESCRIPTION:
+# Gets the username for given UID.
+egetusername() {
+ [[ $# -eq 1 ]] || die "usage: egetusername "
+
+ egetent passwd "$1" | cut -d: -f1
+}
+
+# @FUNCTION: egetgroupname
+# @USAGE:
+# @DESCRIPTION:
+# Gets the group name for given GID.
+egetgroupname() {
+ [[ $# -eq 1 ]] || die "usage: egetgroupname "
+
+ egetent group "$1" | cut -d: -f1
+}
+
+# @FUNCTION: egethome
+# @USAGE:
+# @DESCRIPTION:
+# Gets the home directory for the specified user.
+egethome() {
+ local pos
+
+ [[ $# -eq 1 ]] || die "usage: egethome "
+
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pos=9
+ ;;
+ *) # Linux, NetBSD, OpenBSD, etc...
+ pos=6
+ ;;
+ esac
+
+ egetent passwd "$1" | cut -d: -f${pos}
+}
+
+# @FUNCTION: egetshell
+# @USAGE:
+# @DESCRIPTION:
+# Gets the shell for the specified user.
+egetshell() {
+ local pos
+
+ [[ $# -eq 1 ]] || die "usage: egetshell "
+
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pos=10
+ ;;
+ *) # Linux, NetBSD, OpenBSD, etc...
+ pos=7
+ ;;
+ esac
+
+ egetent passwd "$1" | cut -d: -f${pos}
+}
+
+# @FUNCTION: egetcomment
+# @USAGE:
+# @DESCRIPTION:
+# Gets the comment field for the specified user.
+egetcomment() {
+ local pos
+
+ [[ $# -eq 1 ]] || die "usage: egetcomment "
+
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pos=8
+ ;;
+ *) # Linux, NetBSD, OpenBSD, etc...
+ pos=5
+ ;;
+ esac
+
+ egetent passwd "$1" | cut -d: -f${pos}
+}
+
+# @FUNCTION: egetgroups
+# @USAGE:
+# @DESCRIPTION:
+# Gets all the groups user belongs to. The primary group is returned
+# first, then all supplementary groups. Groups are ','-separated.
+egetgroups() {
+ [[ $# -eq 1 ]] || die "usage: egetgroups "
+
+ local egroups_arr
+ read -r -a egroups_arr < <(id -G -n "$1")
+
+ local g groups=${egroups_arr[0]}
+ # sort supplementary groups to make comparison possible
+ while read -r g; do
+ [[ -n ${g} ]] && groups+=",${g}"
+ done < <(printf '%s\n' "${egroups_arr[@]:1}" | sort)
+ echo "${groups}"
+}
+
+fi
diff --git a/sdk_container/src/third_party/portage-stable/eclass/user.eclass b/sdk_container/src/third_party/portage-stable/eclass/user.eclass
index f6a10a6bee..b70698356a 100644
--- a/sdk_container/src/third_party/portage-stable/eclass/user.eclass
+++ b/sdk_container/src/third_party/portage-stable/eclass/user.eclass
@@ -1,9 +1,10 @@
-# Copyright 1999-2017 Gentoo Foundation
+# Copyright 1999-2020 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
# @ECLASS: user.eclass
# @MAINTAINER:
# base-system@gentoo.org (Linux)
+# Michał Górny (NetBSD)
# @BLURB: user management in ebuilds
# @DESCRIPTION:
# The user eclass contains a suite of functions that allow ebuilds
@@ -12,103 +13,76 @@
if [[ -z ${_USER_ECLASS} ]]; then
_USER_ECLASS=1
+inherit user-info
+
# @FUNCTION: _assert_pkg_ebuild_phase
# @INTERNAL
# @USAGE:
_assert_pkg_ebuild_phase() {
case ${EBUILD_PHASE} in
- setup|preinst|postinst) ;;
+ setup|preinst|postinst|prerm|postrm) ;;
*)
eerror "'$1()' called from '${EBUILD_PHASE}' phase which is not OK:"
- eerror "You may only call from pkg_{setup,preinst,postinst} functions."
+ eerror "You may only call from pkg_{setup,{pre,post}{inst,rm}} functions."
eerror "Package fails at QA and at life. Please file a bug."
die "Bad package! $1 is only for use in some pkg_* functions!"
esac
}
-# @FUNCTION: egetent
-# @USAGE:
+# @FUNCTION: user_get_nologin
+# @INTERNAL
# @DESCRIPTION:
-# Small wrapper for getent (Linux), nidump (< Mac OS X 10.5),
-# dscl (Mac OS X 10.5), and pw (FreeBSD) used in enewuser()/enewgroup().
-#
-# Supported databases: group passwd
-egetent() {
- local db=$1 key=$2
+# Find an appropriate 'nologin' shell for the platform, and output
+# its path.
+user_get_nologin() {
+ local eshell
- [[ $# -ge 3 ]] && die "usage: egetent "
+ for eshell in /sbin/nologin /usr/sbin/nologin /bin/false /usr/bin/false /dev/null ; do
+ [[ -x ${ROOT}${eshell} ]] && break
+ done
- case ${db} in
- passwd|group) ;;
- *) die "sorry, database '${db}' not yet supported; file a bug" ;;
- esac
-
- case ${CHOST} in
- *-darwin[678])
- case ${key} in
- *[!0-9]*) # Non numeric
- nidump ${db} . | awk -F: "(\$1 ~ /^${key}\$/) {print;exit;}"
- ;;
- *) # Numeric
- nidump ${db} . | awk -F: "(\$3 == ${key}) {print;exit;}"
- ;;
- esac
- ;;
- *-darwin*)
- local mykey
- case ${db} in
- passwd) db="Users" mykey="UniqueID" ;;
- group) db="Groups" mykey="PrimaryGroupID" ;;
+ if [[ ${eshell} == "/dev/null" ]] ; then
+ ewarn "Unable to identify the shell to use, proceeding with userland default."
+ case ${USERLAND} in
+ GNU) eshell="/bin/false" ;;
+ BSD) eshell="/sbin/nologin" ;;
+ Darwin) eshell="/usr/sbin/nologin" ;;
+ *) die "Unable to identify the default shell for userland ${USERLAND}"
esac
+ fi
- case ${key} in
- *[!0-9]*) # Non numeric
- dscl . -read /${db}/${key} 2>/dev/null |grep RecordName
- ;;
- *) # Numeric
- dscl . -search /${db} ${mykey} ${key} 2>/dev/null
- ;;
- esac
- ;;
- *-freebsd*|*-dragonfly*)
- case ${db} in
- passwd) db="user" ;;
- *) ;;
- esac
-
- # lookup by uid/gid
- local opts
- if [[ ${key} == [[:digit:]]* ]] ; then
- [[ ${db} == "user" ]] && opts="-u" || opts="-g"
- fi
-
- pw show ${db} ${opts} "${key}" -q
- ;;
- *-netbsd*|*-openbsd*)
- grep "${key}:\*:" /etc/${db}
- ;;
- *)
- # ignore nscd output if we're not running as root
- type -p nscd >/dev/null && nscd -i "${db}" 2>/dev/null
- getent "${db}" "${key}"
- ;;
- esac
+ echo "${eshell}"
}
# @FUNCTION: enewuser
-# @USAGE: [uid] [shell] [homedir] [groups]
+# @USAGE: [-F] [-M] [uid] [shell] [homedir] [groups]
# @DESCRIPTION:
# Same as enewgroup, you are not required to understand how to properly add
# a user to the system. The only required parameter is the username.
# Default uid is (pass -1 for this) next available, default shell is
# /bin/false, default homedir is /dev/null, and there are no default groups.
+#
+# If -F is passed, enewuser will always enforce specified UID and fail if it
+# can not be assigned.
+# If -M is passed, enewuser does not create the home directory if it does not
+# exist.
enewuser() {
if [[ ${EUID} != 0 ]] ; then
- einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
+ ewarn "Insufficient privileges to execute ${FUNCNAME[0]}"
return 0
fi
_assert_pkg_ebuild_phase ${FUNCNAME}
+ local create_home=1 force_uid=
+ while [[ $1 == -* ]]; do
+ case $1 in
+ -F) force_uid=1;;
+ -M) create_home=;;
+ *) die "${FUNCNAME}: invalid option ${1}";;
+ esac
+ shift
+ done
+
# get the username
local euser=$1; shift
if [[ -z ${euser} ]] ; then
@@ -120,7 +94,7 @@ enewuser() {
if [[ -n $(egetent passwd "${euser}") ]] ; then
return 0
fi
- einfo "Adding user '${euser}' to your system ..."
+ elog "Adding user '${euser}' to your system ..."
# options to pass to useradd
local opts=()
@@ -130,6 +104,7 @@ enewuser() {
if [[ -n ${euid} && ${euid} != -1 ]] ; then
if [[ ${euid} -gt 0 ]] ; then
if [[ -n $(egetent passwd ${euid}) ]] ; then
+ [[ -n ${force_uid} ]] && die "${FUNCNAME}: UID ${euid} already taken"
euid="next"
fi
else
@@ -137,15 +112,17 @@ enewuser() {
die "${euid} is not a valid UID"
fi
else
+ [[ -n ${force_uid} ]] && die "${FUNCNAME}: -F with uid==-1 makes no sense"
euid="next"
fi
if [[ ${euid} == "next" ]] ; then
- for ((euid = 101; euid <= 999; euid++)); do
+ for ((euid = 999; euid >= 101; euid--)); do
[[ -z $(egetent passwd ${euid}) ]] && break
done
+ [[ ${euid} -ge 101 ]] || die "${FUNCNAME}: no free UID found"
fi
opts+=( -u ${euid} )
- einfo " - Userid: ${euid}"
+ elog " - Userid: ${euid}"
# handle shell
local eshell=$1; shift
@@ -159,21 +136,9 @@ enewuser() {
die "Pass '-1' as the shell parameter"
fi
else
- for eshell in /sbin/nologin /usr/sbin/nologin /bin/false /usr/bin/false /dev/null ; do
- [[ -x ${ROOT}${eshell} ]] && break
- done
-
- if [[ ${eshell} == "/dev/null" ]] ; then
- eerror "Unable to identify the shell to use, proceeding with userland default."
- case ${USERLAND} in
- GNU) eshell="/bin/false" ;;
- BSD) eshell="/sbin/nologin" ;;
- Darwin) eshell="/usr/sbin/nologin" ;;
- *) die "Unable to identify the default shell for userland ${USERLAND}"
- esac
- fi
+ eshell=$(user_get_nologin)
fi
- einfo " - Shell: ${eshell}"
+ elog " - Shell: ${eshell}"
opts+=( -s "${eshell}" )
# handle homedir
@@ -181,7 +146,7 @@ enewuser() {
if [[ -z ${ehome} ]] || [[ ${ehome} == "-1" ]] ; then
ehome="/dev/null"
fi
- einfo " - Home: ${ehome}"
+ elog " - Home: ${ehome}"
opts+=( -d "${ehome}" )
# handle groups
@@ -206,7 +171,7 @@ enewuser() {
opts+=( -G "${exgroups:1}" )
fi
fi
- einfo " - Groups: ${egroups:-(none)}"
+ elog " - Groups: ${egroups:-(none)}"
# handle extra args
if [[ $# -gt 0 ]] ; then
@@ -214,23 +179,11 @@ enewuser() {
else
local comment="added by portage for ${PN}"
opts+=( -c "${comment}" )
- einfo " - GECOS: ${comment}"
+ elog " - GECOS: ${comment}"
fi
# add the user
case ${CHOST} in
- *-darwin*)
- ### Make the user
- dscl . create "/users/${euser}" uid ${euid}
- dscl . create "/users/${euser}" shell "${eshell}"
- dscl . create "/users/${euser}" home "${ehome}"
- dscl . create "/users/${euser}" realname "added by portage for ${PN}"
- ### Add the user to the groups specified
- for g in "${egroups_arr[@]}" ; do
- dscl . merge "/groups/${g}" users "${euser}"
- done
- ;;
-
*-freebsd*|*-dragonfly*)
pw useradd "${euser}" "${opts[@]}" || die
;;
@@ -246,12 +199,12 @@ enewuser() {
;;
*)
- useradd -r "${opts[@]}" "${euser}" || die
+ useradd -M -N -r "${opts[@]}" "${euser}" || die
;;
esac
- if [[ ! -e ${ROOT}/${ehome} ]] ; then
- einfo " - Creating ${ehome} in ${ROOT}"
+ if [[ -n ${create_home} && ! -e ${ROOT}/${ehome} ]] ; then
+ elog " - Creating ${ehome} in ${ROOT}"
mkdir -p "${ROOT}/${ehome}"
chown "${euser}" "${ROOT}/${ehome}"
chmod 755 "${ROOT}/${ehome}"
@@ -265,13 +218,25 @@ enewuser() {
# group to the system. Just give it a group name to add and enewgroup will
# do the rest. You may specify the gid for the group or allow the group to
# allocate the next available one.
+#
+# If -F is passed, enewgroup will always enforce specified GID and fail if it
+# can not be assigned.
enewgroup() {
if [[ ${EUID} != 0 ]] ; then
- einfo "Insufficient privileges to execute ${FUNCNAME[0]}"
+ ewarn "Insufficient privileges to execute ${FUNCNAME[0]}"
return 0
fi
_assert_pkg_ebuild_phase ${FUNCNAME}
+ local force_gid=
+ while [[ $1 == -* ]]; do
+ case $1 in
+ -F) force_gid=1;;
+ *) die "${FUNCNAME}: invalid option ${1}";;
+ esac
+ shift
+ done
+
# get the group
local egroup=$1; shift
if [[ -z ${egroup} ]] ; then
@@ -283,13 +248,14 @@ enewgroup() {
if [[ -n $(egetent group "${egroup}") ]] ; then
return 0
fi
- einfo "Adding group '${egroup}' to your system ..."
+ elog "Adding group '${egroup}' to your system ..."
# handle gid
local egid=$1; shift
- if [[ ! -z ${egid} ]] ; then
+ if [[ -n ${egid} && ${egid} != -1 ]] ; then
if [[ ${egid} -gt 0 ]] ; then
if [[ -n $(egetent group ${egid}) ]] ; then
+ [[ -n ${force_gid} ]] && die "${FUNCNAME}: GID ${egid} already taken"
egid="next available; requested gid taken"
fi
else
@@ -297,9 +263,10 @@ enewgroup() {
die "${egid} is not a valid GID"
fi
else
+ [[ -n ${force_gid} ]] && die "${FUNCNAME}: -F with gid==-1 makes no sense"
egid="next available"
fi
- einfo " - Groupid: ${egid}"
+ elog " - Groupid: ${egid}"
# handle extra
if [[ $# -gt 0 ]] ; then
@@ -310,20 +277,15 @@ enewgroup() {
_enewgroup_next_gid() {
if [[ ${egid} == *[!0-9]* ]] ; then
# Non numeric
- for ((egid = 101; egid <= 999; egid++)) ; do
+ for ((egid = 999; egid >= 101; egid--)) ; do
[[ -z $(egetent group ${egid}) ]] && break
done
+ [[ ${egid} -ge 101 ]] || die "${FUNCNAME}: no free GID found"
fi
}
# add the group
case ${CHOST} in
- *-darwin*)
- _enewgroup_next_gid
- dscl . create "/groups/${egroup}" gid ${egid}
- dscl . create "/groups/${egroup}" passwd '*'
- ;;
-
*-freebsd*|*-dragonfly*)
_enewgroup_next_gid
pw groupadd "${egroup}" -g ${egid} || die
@@ -348,48 +310,6 @@ enewgroup() {
esac
}
-# @FUNCTION: egethome
-# @USAGE:
-# @DESCRIPTION:
-# Gets the home directory for the specified user.
-egethome() {
- local pos
-
- [[ $# -eq 1 ]] || die "usage: egethome "
-
- case ${CHOST} in
- *-darwin*|*-freebsd*|*-dragonfly*)
- pos=9
- ;;
- *) # Linux, NetBSD, OpenBSD, etc...
- pos=6
- ;;
- esac
-
- egetent passwd "$1" | cut -d: -f${pos}
-}
-
-# @FUNCTION: egetshell
-# @USAGE:
-# @DESCRIPTION:
-# Gets the shell for the specified user.
-egetshell() {
- local pos
-
- [[ $# -eq 1 ]] || die "usage: egetshell "
-
- case ${CHOST} in
- *-darwin*|*-freebsd*|*-dragonfly*)
- pos=10
- ;;
- *) # Linux, NetBSD, OpenBSD, etc...
- pos=7
- ;;
- esac
-
- egetent passwd "$1" | cut -d: -f${pos}
-}
-
# @FUNCTION: esethome
# @USAGE:
# @DESCRIPTION:
@@ -431,12 +351,12 @@ esethome() {
return 0
fi
- einfo "Updating home for user '${euser}' ..."
- einfo " - Home: ${ehome}"
+ elog "Updating home for user '${euser}' ..."
+ elog " - Home: ${ehome}"
# ensure home directory exists, otherwise update will fail
if [[ ! -e ${ROOT}/${ehome} ]] ; then
- einfo " - Creating ${ehome} in ${ROOT}"
+ elog " - Creating ${ehome} in ${ROOT}"
mkdir -p "${ROOT}/${ehome}"
chown "${euser}" "${ROOT}/${ehome}"
chmod 755 "${ROOT}/${ehome}"
@@ -444,10 +364,6 @@ esethome() {
# update the home directory
case ${CHOST} in
- *-darwin*)
- dscl . change "/users/${euser}" home "${ehome}"
- ;;
-
*-freebsd*|*-dragonfly*)
pw usermod "${euser}" -d "${ehome}" && return 0
[[ $? == 8 ]] && eerror "${euser} is in use, cannot update home"
@@ -466,4 +382,191 @@ esethome() {
esac
}
+# @FUNCTION: esetshell
+# @USAGE:
+# @DESCRIPTION:
+# Update the shell in a platform-agnostic way.
+# Required parameters is the username and the new shell.
+# Specify -1 if you want to set shell to platform-specific nologin.
+esetshell() {
+ _assert_pkg_ebuild_phase ${FUNCNAME}
+
+ # get the username
+ local euser=$1; shift
+ if [[ -z ${euser} ]] ; then
+ eerror "No username specified !"
+ die "Cannot call esetshell without a username"
+ fi
+
+ # lets see if the username already exists
+ if [[ -z $(egetent passwd "${euser}") ]] ; then
+ ewarn "User does not exist, cannot set shell -- skipping."
+ return 1
+ fi
+
+ # handle shell
+ local eshell=$1; shift
+ if [[ -z ${eshell} ]] ; then
+ eerror "No shell specified !"
+ die "Cannot call esetshell without a shell or '-1'"
+ fi
+
+ if [[ ${eshell} == "-1" ]] ; then
+ eshell=$(user_get_nologin)
+ fi
+
+ # exit with no message if shell is up to date
+ if [[ $(egetshell "${euser}") == ${eshell} ]]; then
+ return 0
+ fi
+
+ elog "Updating shell for user '${euser}' ..."
+ elog " - Shell: ${eshell}"
+
+ # update the shell
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pw usermod "${euser}" -s "${eshell}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update shell"
+ eerror "There was an error when attempting to update the shell for ${euser}"
+ eerror "Please update it manually on your system:"
+ eerror "\t pw usermod \"${euser}\" -s \"${eshell}\""
+ ;;
+
+ *)
+ usermod -s "${eshell}" "${euser}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update shell"
+ eerror "There was an error when attempting to update the shell for ${euser}"
+ eerror "Please update it manually on your system (as root):"
+ eerror "\t usermod -s \"${eshell}\" \"${euser}\""
+ ;;
+ esac
+}
+
+# @FUNCTION: esetcomment
+# @USAGE:
+# @DESCRIPTION:
+# Update the comment field in a platform-agnostic way.
+# Required parameters is the username and the new comment.
+esetcomment() {
+ _assert_pkg_ebuild_phase ${FUNCNAME}
+
+ # get the username
+ local euser=$1; shift
+ if [[ -z ${euser} ]] ; then
+ eerror "No username specified !"
+ die "Cannot call esetcomment without a username"
+ fi
+
+ # lets see if the username already exists
+ if [[ -z $(egetent passwd "${euser}") ]] ; then
+ ewarn "User does not exist, cannot set comment -- skipping."
+ return 1
+ fi
+
+ # handle comment
+ local ecomment=$1; shift
+ if [[ -z ${ecomment} ]] ; then
+ eerror "No comment specified !"
+ die "Cannot call esetcomment without a comment"
+ fi
+
+ # exit with no message if comment is up to date
+ if [[ $(egetcomment "${euser}") == ${ecomment} ]]; then
+ return 0
+ fi
+
+ elog "Updating comment for user '${euser}' ..."
+ elog " - Comment: ${ecomment}"
+
+ # update the comment
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pw usermod "${euser}" -c "${ecomment}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update comment"
+ eerror "There was an error when attempting to update the comment for ${euser}"
+ eerror "Please update it manually on your system:"
+ eerror "\t pw usermod \"${euser}\" -c \"${ecomment}\""
+ ;;
+
+ *)
+ usermod -c "${ecomment}" "${euser}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update comment"
+ eerror "There was an error when attempting to update the comment for ${euser}"
+ eerror "Please update it manually on your system (as root):"
+ eerror "\t usermod -c \"${ecomment}\" \"${euser}\""
+ ;;
+ esac
+}
+
+# @FUNCTION: esetgroups
+# @USAGE:
+# @DESCRIPTION:
+# Update the group field in a platform-agnostic way.
+# Required parameters is the username and the new list of groups,
+# primary group first.
+esetgroups() {
+ _assert_pkg_ebuild_phase ${FUNCNAME}
+
+ [[ ${#} -eq 2 ]] || die "Usage: ${FUNCNAME} "
+
+ # get the username
+ local euser=$1; shift
+
+ # lets see if the username already exists
+ if [[ -z $(egetent passwd "${euser}") ]] ; then
+ ewarn "User does not exist, cannot set group -- skipping."
+ return 1
+ fi
+
+ # handle group
+ local egroups=$1; shift
+
+ local g egroups_arr=()
+ IFS="," read -r -a egroups_arr <<<"${egroups}"
+ [[ ${#egroups_arr[@]} -gt 0 ]] || die "${FUNCNAME}: no groups specified"
+
+ for g in "${egroups_arr[@]}" ; do
+ if [[ -z $(egetent group "${g}") ]] ; then
+ eerror "You must add group ${g} to the system first"
+ die "${g} is not a valid GID"
+ fi
+ done
+
+ local defgroup=${egroups_arr[0]} exgroups_arr=()
+ # sort supplementary groups to make comparison possible
+ readarray -t exgroups_arr < <(printf '%s\n' "${egroups_arr[@]:1}" | sort)
+ local exgroups=${exgroups_arr[*]}
+ exgroups=${exgroups// /,}
+ egroups=${defgroup}${exgroups:+,${exgroups}}
+
+ # exit with no message if group membership is up to date
+ if [[ $(egetgroups "${euser}") == ${egroups} ]]; then
+ return 0
+ fi
+
+ local opts=( -g "${defgroup}" -G "${exgroups}" )
+ elog "Updating groups for user '${euser}' ..."
+ elog " - Groups: ${egroups}"
+
+ # update the group
+ case ${CHOST} in
+ *-freebsd*|*-dragonfly*)
+ pw usermod "${euser}" "${opts[@]}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update groups"
+ eerror "There was an error when attempting to update the groups for ${euser}"
+ eerror "Please update it manually on your system:"
+ eerror "\t pw usermod \"${euser}\" ${opts[*]}"
+ ;;
+
+ *)
+ usermod "${opts[@]}" "${euser}" && return 0
+ [[ $? == 8 ]] && eerror "${euser} is in use, cannot update groups"
+ eerror "There was an error when attempting to update the groups for ${euser}"
+ eerror "Please update it manually on your system (as root):"
+ eerror "\t usermod ${opts[*]} \"${euser}\""
+ ;;
+ esac
+}
+
fi
diff --git a/sdk_container/src/third_party/portage-stable/metadata/md5-cache/acct-group/sshd-0 b/sdk_container/src/third_party/portage-stable/metadata/md5-cache/acct-group/sshd-0
new file mode 100644
index 0000000000..a508a4d575
--- /dev/null
+++ b/sdk_container/src/third_party/portage-stable/metadata/md5-cache/acct-group/sshd-0
@@ -0,0 +1,7 @@
+DEFINED_PHASES=preinst pretend
+DESCRIPTION=System group: sshd
+EAPI=7
+KEYWORDS=alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 ~riscv s390 sh sparc x86 ~ppc-aix ~x64-cygwin ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris
+SLOT=0
+_eclasses_=acct-group 7126fca4f6bf56620d1ce1fd317066fc user 8bd74731cafdcdad8f7a63637302e073
+_md5_=806fe511e66eff6943cb9b40e5f0d87a
diff --git a/sdk_container/src/third_party/portage-stable/metadata/md5-cache/acct-user/sshd-0 b/sdk_container/src/third_party/portage-stable/metadata/md5-cache/acct-user/sshd-0
new file mode 100644
index 0000000000..34bb524bd6
--- /dev/null
+++ b/sdk_container/src/third_party/portage-stable/metadata/md5-cache/acct-user/sshd-0
@@ -0,0 +1,8 @@
+DEFINED_PHASES=install postinst preinst prerm pretend
+DESCRIPTION=User for ssh
+EAPI=7
+KEYWORDS=alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 ~riscv s390 sh sparc x86 ~ppc-aix ~x64-cygwin ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris
+RDEPEND=acct-group/sshd
+SLOT=0
+_eclasses_=acct-user 1729414f09229fbe725c2bc404e60fac user 8bd74731cafdcdad8f7a63637302e073
+_md5_=c0e562c32c3c8bdc95c2071812b7eba3
diff --git a/sdk_container/src/third_party/portage-stable/metadata/md5-cache/virtual/libcrypt-1 b/sdk_container/src/third_party/portage-stable/metadata/md5-cache/virtual/libcrypt-1
new file mode 100644
index 0000000000..8cdc4bb925
--- /dev/null
+++ b/sdk_container/src/third_party/portage-stable/metadata/md5-cache/virtual/libcrypt-1
@@ -0,0 +1,9 @@
+DEFINED_PHASES=-
+DESCRIPTION=Virtual for libcrypt.so
+EAPI=7
+IUSE=+static-libs abi_x86_32 abi_x86_64 abi_x86_x32 abi_mips_n32 abi_mips_n64 abi_mips_o32 abi_riscv_lp64d abi_riscv_lp64 abi_s390_32 abi_s390_64
+KEYWORDS=~alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 ~riscv s390 sh sparc x86 ~ppc-aix ~x64-cygwin ~x86-cygwin ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos ~m68k-mint ~sparc-solaris ~sparc64-solaris ~x64-solaris ~x86-solaris
+RDEPEND=elibc_glibc? ( || ( >=sys-libs/glibc-2.30-r2[crypt(-),static-libs(+)?] =sys-libs/glibc-2.30-r2[crypt(-),static-libs(+)?]
+
+
+
+
+ base-system@gentoo.org
+ Gentoo base-system Project
+
+