--- a/eclass/acct-user.eclass 2021-01-10 16:09:37.000000000 -0500 +++ b/eclass/acct-user.eclass 2021-02-23 20:24:26.373000000 -0500 @@ -194,8 +194,8 @@ *) # 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 ]] + [[ $(egetent shadow "$1" | cut -d: -f2) == '!'* ]] && + [[ $(egetent shadow "$1" | cut -d: -f8) == 1 ]] ;; esac } @@ -237,7 +237,11 @@ ;; *) - usermod -e 1 -L "$1" || die "Locking account $1 failed" + if [[ "${ROOT}" == "/" ]] ; then + usermod -e 1 -L "$1" || die "Locking account $1 failed" + else + usermod --prefix "$ROOT" -e 1 -L "$1" || die "Locking account $1 failed" + fi ;; esac @@ -281,7 +285,11 @@ *) # silence warning if account does not have a password - usermod -e "" -U "$1" 2>/dev/null || die "Unlocking account $1 failed" + if [[ "${ROOT}" == "/" ]] ; then + usermod -e "" -U "$1" 2>/dev/null || die "Unlocking account $1 failed" + else + usermod --prefix "$ROOT" -e "" -U "$1" 2>/dev/null || die "Unlocking account $1 failed" + fi ;; esac @@ -427,7 +435,7 @@ 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}" + efowners "${_ACCT_USER_HOME_OWNER}" "${_ACCT_USER_HOME}" fperms "${_ACCT_USER_HOME_PERMS}" "${_ACCT_USER_HOME}" fi } --- a/eclass/user.eclass 2020-11-06 06:44:36.000000000 -0500 +++ b/eclass/user.eclass 2021-02-23 20:20:56.456000000 -0500 @@ -108,7 +108,11 @@ if [[ -n $(egetent passwd "${euser}") ]] ; then return 0 fi - elog "Adding user '${euser}' to your system ..." + if [[ "${ROOT}" == "/" ]] ; then + einfo "Adding user '${euser}' to your system ..." + else + einfo "Adding user '${euser}' to ${ROOT} ..." + fi # options to pass to useradd local opts=() @@ -213,6 +217,9 @@ ;; *) + if [[ "${ROOT}" != "/" ]] ; then + opts+=( --prefix "${ROOT}" ) + fi useradd -M -N -r "${opts[@]}" "${euser}" || die ;; esac @@ -220,7 +227,7 @@ if [[ -n ${create_home} && ! -e ${ROOT}/${ehome} ]] ; then elog " - Creating ${ehome} in ${ROOT}" mkdir -p "${ROOT}/${ehome}" - chown "${euser}" "${ROOT}/${ehome}" + chown "${euid}" "${ROOT}/${ehome}" chmod 755 "${ROOT}/${ehome}" fi } @@ -262,7 +269,11 @@ if [[ -n $(egetent group "${egroup}") ]] ; then return 0 fi - elog "Adding group '${egroup}' to your system ..." + if [[ "${ROOT}" == "/" ]] ; then + einfo "Adding group '${egroup}' to your system ..." + else + einfo "Adding group '${egroup}' to ${ROOT} ..." + fi # handle gid local egid=$1; shift @@ -318,8 +329,13 @@ else opts="-g ${egid}" fi - # We specify -r so that we get a GID in the system range from login.defs - groupadd -r ${opts} "${egroup}" || die + + if [[ "${ROOT}" == "/" ]] ; then + # We specify -r so that we get a GID in the system range from login.defs + groupadd -r ${opts} "${egroup}" || die + else + groupadd --prefix "${ROOT}" -r ${opts} "${egroup}" || die + fi ;; esac } @@ -372,7 +388,7 @@ if [[ ! -e ${ROOT}/${ehome} ]] ; then elog " - Creating ${ehome} in ${ROOT}" mkdir -p "${ROOT}/${ehome}" - chown "${euser}" "${ROOT}/${ehome}" + echown "${euser}" "${ROOT}/${ehome}" chmod 755 "${ROOT}/${ehome}" fi @@ -387,7 +403,11 @@ ;; *) - usermod -d "${ehome}" "${euser}" && return 0 + if [[ "${ROOT}" == "/" ]] ; then + usermod -d "${ehome}" "${euser}" && return 0 + else + usermod --prefix "${ROOT}" -d "${ehome}" "${euser}" && return 0 + fi [[ $? == 8 ]] && eerror "${euser} is in use, cannot update home" eerror "There was an error when attempting to update the home directory for ${euser}" eerror "Please update it manually on your system (as root):" @@ -448,7 +468,11 @@ ;; *) - usermod -s "${eshell}" "${euser}" && return 0 + if [[ "${ROOT}" == "/" ]] ; then + usermod -s "${eshell}" "${euser}" && return 0 + else + usermod --prefix "${ROOT}" -s "${eshell}" "${euser}" && return 0 + fi [[ $? == 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):" @@ -574,6 +598,9 @@ ;; *) + if [[ "${ROOT}" != "/" ]] ; then + opts+=( --prefix "${ROOT}" ) + fi 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}" @@ -583,4 +610,77 @@ esac } +# @USAGE: : +# @DESCRIPTION: +# chown portage equivalent, honoring the ${ROOT} variable. +echown() { + # get the user + local a=$1; shift + if [[ -z ${a} ]] ; then + eerror "No user specified !" + die "Cannot call echown without a user" + fi + + local euid + local egid + + IFS=':' read -a fields <<< "${a}" + + euser=${fields[0]} + egroup=${fields[1]} + if [[ "${euser}" != "" ]]; then + euid="$(egetuid "${euser}")" + fi + if [[ "${egroup}" != "" ]]; then + egid="$(egetgid "${egroup}")" + fi + + local opt="" + + if [[ "${euid}" != "" ]]; then + opt+="${euid}" + fi + if [[ "${egid}" != "" ]] ; then + opt+=":${egid}" + fi + + chown "${opt}" "$@" || die +} + +# @DESCRIPTION: +# fowners honoring the ${ROOT} variable. +efowners() { + # get the user:group + local a=$1; shift + if [[ -z ${a} ]] ; then + eerror "No user:group specified !" + die "Cannot call echown without a user" + fi + + local euid + local egid + + IFS=':' read -a fields <<< "${a}" + + euser=${fields[0]} + egroup=${fields[1]} + if [[ "${euser}" != "" ]] ; then + euid="$(egetuid "${euser}")" + fi + if [[ "${egroup}" != "" ]] ; then + egid="$(egetgid "${egroup}")" + fi + + local opt="" + + if [[ "${euid}" != "" ]]; then + opt+="${euid}" + fi + if [[ "${egid}" != "" ]] ; then + opt+=":${egid}" + fi + + fowners "${opt}" "$@" || die +} + fi --- a/eclass/user-info.eclass 2020-02-07 12:40:22.000000000 -0500 +++ b/eclass/user-info.eclass 2021-02-23 20:17:29.476000000 -0500 @@ -16,14 +16,15 @@ # 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 +# Supported databases: group passwd shadow +# note that shadow may not be supported depending on configuration egetent() { local db=$1 key=$2 [[ $# -ge 3 ]] && die "usage: egetent " case ${db} in - passwd|group) ;; + passwd|group|shadow) ;; *) die "sorry, database '${db}' not yet supported; file a bug" ;; esac @@ -31,6 +32,7 @@ *-freebsd*|*-dragonfly*) case ${db} in passwd) db="user" ;; + shadow) die "sorry, database '${db}' not yet supported; file a bug" ;; *) ;; esac @@ -47,8 +49,24 @@ ;; *) # ignore nscd output if we're not running as root - type -p nscd >/dev/null && nscd -i "${db}" 2>/dev/null - getent "${db}" "${key}" + case ${db} in + passwd|group) type -p nscd >/dev/null && nscd -i "${db}" 2>/dev/null;; + *) ;; + esac + + if [[ "${ROOT}" == "/" ]] ; then + getent "${db}" "${key}" + else + local euser + if [[ ${key} == [[:digit:]]* ]] ; then + euser=$(awk -F: '$3 == '"${key}"'{print $1}' "${ROOT}/etc/passwd") + else + euser=${key} + fi + if [[ "${euser}" != "" ]] ; then + grep --color=never "^${euser}" "${ROOT}/etc/${db}" + fi + fi ;; esac } @@ -145,7 +163,11 @@ [[ $# -eq 1 ]] || die "usage: egetgroups " local egroups_arr - read -r -a egroups_arr < <(id -G -n "$1") + if [[ "${ROOT}" == "/" ]] ; then + read -r -a egroups_arr < <(id -G -n "$1") + else + read -r -a egroups_arr < <(egetent group | grep --color=never -E "$1[^:]*$" | cut -d':' -f1) + fi local g groups=${egroups_arr[0]} # sort supplementary groups to make comparison possible @@ -155,4 +177,22 @@ echo "${groups}" } +# @USAGE: +# @DESCRIPTION: +# Gets the uid for the specified user. +egetuid() { + [[ $# -eq 1 ]] || die "usage: egetuid " + + egetent passwd "$1" | cut -d: -f3 || die +} + +# @USAGE: +# @DESCRIPTION: +# Gets the gid for the specified group. +egetgid() { + [[ $# -eq 1 ]] || die "usage: egetgid " + + egetent group "$1" | cut -d: -f3 || die +} + fi