user.eclass: Add sysroot/etc/shadow support
Upgrading sudo created auth issues during build_image traced to a lack of entries in etc/shadow.
This is a patch to populate entries in etc/shadow for proper auth.
BUG=chromium:905444
TEST=Built image with fresh board setup, rebuilt image, built from master then from changes
Cq-Depend: chromium:1828146
Change-Id: I3debc26a0e4110dc6015a8b4f910b24592b98970
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/overlays/eclass-overlay/+/1825515
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Benjamin Gordon <bmgordon@chromium.org>
Tested-by: Pranay Shoroff <pshoroff@google.com>
Commit-Queue: Pranay Shoroff <pshoroff@google.com>
diff --git a/eclass/user.eclass b/eclass/user.eclass
index 3874fb6..c4352d3 100644
--- a/eclass/user.eclass
+++ b/eclass/user.eclass
@@ -213,13 +213,13 @@
# @USAGE: <entry> <database> <root>
# @DESCRIPTION:
# Writes an entry to the specified database under the specified root.
+# Supported databases: passwd group shadow
_write_entry_to_db() {
local entry=$1 db=$2 root=$3
-
[[ $# -ne 3 ]] && die "usage: _write_entry_to_db <entry> <database> <root>"
case ${db} in
- passwd|group) ;;
+ passwd|group|shadow) ;;
*) die "sorry, database '${db}' not supported." ;;
esac
@@ -253,16 +253,22 @@
# @DESCRIPTION:
# Provides getent-like functionality for databases under [root]. Defaults to ${ROOT}.
#
-# Supported databases: group passwd
+# Supported databases: group passwd shadow
egetent() {
local use_lock=true
- [[ $1 == "--nolock" ]] && use_lock=false && shift
- [[ $# -ne 2 && $# -ne 3 ]] && die "usage: egetent <database> <key> [root]"
+ if [[ $1 == "--nolock" ]]; then
+ use_lock=false
+ shift
+ fi
+
+ if [[ $# -ne 2 && $# -ne 3 ]]; then
+ die "usage: egetent <database> <key> [root]"
+ fi
local db=$1 key=$2 root=${3:-"${ROOT}"}
case ${db} in
- passwd|group) ;;
+ passwd|group|shadow) ;;
*) die "sorry, database '${db}' not yet supported; file a bug" ;;
esac
@@ -301,14 +307,18 @@
# Lets see if the username already exists in ${ROOT} or in the system.
local is_in_root=false
- [[ -n "$(egetent passwd ${euser})" ]] && is_in_root=true
- local is_in_system=false
- [[ -n "$(egetent passwd ${euser} /)" ]] && is_in_system=true
- local should_be_in_system=false
- [[ "${EBUILD_PHASE}" == "setup" ]] && should_be_in_system=true
+ if [[ -n "$(egetent passwd "${euser}")" ]]; then
+ is_in_root=true
+ fi
- if "${is_in_root}" && (! "${should_be_in_system}" || "${is_in_system}") ; then
- return 0
+ local is_in_system=false
+ if [[ -n "$(egetent passwd "${euser}" /)" ]]; then
+ is_in_system=true
+ fi
+
+ local should_be_in_system=false
+ if [[ "${EBUILD_PHASE}" == "setup" ]]; then
+ should_be_in_system=true
fi
# We can't support creating accounts on the system yet.
@@ -326,6 +336,26 @@
return 0
fi
+ # Check if user entry requires password (has a password of "x").
+ # If so, check if shadow file already contains an entry for the user.
+ # About passwords in shadow files: src/third_party/eclass-overlay/profiles/base/accounts/README.md
+ local epassword=$(_get_value_for_user "${euser}" password)
+ : "${epassword:="!"}"
+ local should_have_shadow_entry=false
+ local is_in_shadow=false
+ if [[ ${epassword} == "x" ]]; then
+ should_have_shadow_entry=true
+ if [[ -n "$(egetent shadow "${euser}")" ]]; then
+ is_in_shadow=true
+ fi
+ fi
+
+ if "${is_in_root}" &&
+ (! "${should_have_shadow_entry}" || "${is_in_shadow}") &&
+ (! "${should_be_in_system}" || "${is_in_system}") ; then
+ return 0
+ fi
+
# Ensure username exists in profile.
if [[ -z $(_get_value_for_user "${euser}" user) ]] ; then
die "'${euser}' does not exist in profile!"
@@ -358,7 +388,7 @@
# If profile has UID and caller specified same, OK.
if [[ ${euid} == -1 ]] ; then
euid=${provided_uid}
- elif [[ ${euid} != ${provided_uid} ]] ; then
+ elif [[ ${euid} != "${provided_uid}" ]] ; then
eerror "Userid differs from the profile!"
die "${euid} != ${provided_uid} from profile."
# else...they're already equal, so do nothing.
@@ -433,12 +463,22 @@
einfo " - GECOS: ${comment}"
fi
- local epassword=$(_get_value_for_user "${euser}" password)
- : ${epassword:="!"}
local entry="${euser}:${epassword}:${euid}:${egid}:${comment}:${ehome}:${eshell}"
+ local sentry="${euser}:x:::::::"
+
if ! "${is_in_system}" && "${should_be_in_system}" ; then
_write_entry_to_db "${entry}" passwd / || die "Must be able to add users during setup."
fi
+
+ local is_in_system_shadow=false
+ if [[ -n "$(egetent shadow "${euser}" /)" ]]; then
+ is_in_system_shadow=true
+ fi
+
+ if ! "${is_in_system_shadow}" && "${should_be_in_system}" && "${should_have_shadow_entry}" ; then
+ _write_entry_to_db "${sentry}" shadow / || die "Must be able to add users during setup."
+ fi
+
if ! "${is_in_root}" ; then
if _write_entry_to_db "${entry}" passwd "${ROOT}" ; then
if [[ ! -e ${ROOT}/${ehome} ]] ; then
@@ -448,6 +488,9 @@
chmod 755 "${ROOT}/${ehome}"
fi
fi
+ if "${should_have_shadow_entry}" ; then
+ _write_entry_to_db "${sentry}" shadow "${ROOT}"
+ fi
fi
}
@@ -470,9 +513,9 @@
# Lets see if the group already exists in ${ROOT} or in the system.
local is_in_root=false
- [[ -n "$(egetent group ${egroup})" ]] && is_in_root=true
+ [[ -n "$(egetent group "${egroup}")" ]] && is_in_root=true
local is_in_system=false
- [[ -n "$(egetent group ${egroup} /)" ]] && is_in_system=true
+ [[ -n "$(egetent group "${egroup}" /)" ]] && is_in_system=true
local should_be_in_system=false
[[ "${EBUILD_PHASE}" == "setup" ]] && should_be_in_system=true
@@ -516,7 +559,7 @@
if [[ -z ${egid} ]] ; then
# If caller specified nothing and profile has GID, use profile.
# If caller specified nothing and profile has no GID, barf.
- if [[ ! -z ${provided_gid} ]] ; then
+ if [[ -n ${provided_gid} ]] ; then
egid=${provided_gid}
else
die "No gid provided in PROFILE or in args!"
@@ -548,7 +591,7 @@
# Allow group passwords, if profile asks for it.
local epassword=$(_get_value_for_group "${egroup}" password)
- : ${epassword:="!"}
+ : "${epassword:="!"}"
einfo " - Password entry: ${epassword}"
# Pre-populate group with users.