Bug#304343: [Pkg-shadow-devel] Bug#304352: Patch to allow preseeding
hashes for passwords (root and user) in passwd
Christian Perrier
bubulle at debian.org
Thu Oct 6 05:04:49 UTC 2005
Quoting Christian Perrier (bubulle at debian.org):
> tags 275343 patch
> tags 304343 patch
> merge 305352 275343
> thanks
>
> Attached is the first draft of a patch that should allow preseeding
> MD5 hash paasswords for both the root and the first created user
> passwords.
Testing this is a little bit tricky because the relevant code actually
runs only when calling "dpkg-reconfigure passwd". Also, when run on a
live system, where root already has a password, it does nothing.
The key is emptying the root password before manually running a modified
passwd.config script where the test about $1 being "reconfigure" is
removed.
See attached "test" script which is such a modified version.
The attached "set" script allow to set the root password hash to a
hash corresponding to "r00tme".
The similar code for the user password preseeding is NOT included in
this test. Actually, testing this is even more tricky on a live system
because the script first test about the presence of an existing
unprivileged user and only proposes a user creation when such a user
does not exist.
-------------- next part --------------
#!/bin/sh -e
test -f /usr/share/debconf/confmodule || exit 0
# don't make assumptions about the umask
umask 022
. /usr/share/debconf/confmodule
db_capb "backup"
# Remove this : not translatable and looks ugly in d-i process
# db_title "Password setup"
# Returns a true value if there seems to be a system user account.
is_system_user () {
# Assume NIS, or any uid from 1000 to 29999, means there is a user.
if grep -q '^+:' /etc/passwd || \
grep -q '^[^:]*:[^:]*:[1-9][0-9][0-9][0-9]:' /etc/passwd || \
grep -q '^[^:]*:[^:]*:[12][0-9][0-9][0-9][0-9]:' /etc/passwd; then
return 0
else
return 1
fi
}
# Returns a true value if root already has a password.
root_password () {
# Assume there is a root password if NIS is being used.
if grep -q '^+:' /etc/passwd; then
return 0
fi
if [ -e /etc/shadow ] && \
[ "`grep ^root: /etc/shadow | cut -d : -f 2`" ]; then
return 0
fi
if [ "`grep ^root: /etc/passwd | cut -d : -f 2`" ] && \
[ "`grep ^root: /etc/passwd | cut -d : -f 2`" != 'x' ]; then
return 0
fi
return 1
}
# Set a password, via chpasswd.
# Use perl rather than echo, to avoid the password
# showing in the process table. (However, this is normally
# only called when first booting the system, when root has no
# password at all, so that should be an unnecessary precaution).
#
# Arguments:
# 1) (mandatory) username
# 2) (mandatory) password
# 3) (optional) 1 for meaning "the passed password is a MD5 hash"
setpassword () {
SETPASSWD_PW="$2"
export SETPASSWD_PW
# This is very annoying. chpasswd cannot handle generating md5
# passwords as it is not PAM-aware. Thus, I have to work around
# that by crypting the password myself if md5 is used.
USE_MD5=1
export USE_MD5
if test "$3" ; then
echo $1:${SETPASSWD_PW} | chpasswd -e
else
perl -e '
sub CreateCryptSalt {
my $md5 = shift;
my @valid = split(//, "./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
my ($in, $out);
my $cryptsaltlen = ($md5 ? 8 : 2);
open (F, "</dev/urandom") || die "No /dev/urandom found!";
foreach (1..$cryptsaltlen) {
read(F, $in, 1);
$out .= $valid[ord($in) % ($#valid + 1)];
}
close F;
return ($md5 ? "\$1\$$out\$" : $out);
}
open(P,"| chpasswd -e");
print P shift().":".
crypt($ENV{SETPASSWD_PW}, CreateCryptSalt($ENV{USE_MD5})).
"\n";
close P;
' "$1"
fi
SETPASSWD_PW=''
USE_MD5=''
}
# Main loop starts here. Use a state machine to allow jumping back to
# previous questions.
STATE=0
while [ "$STATE" != '10' ] && [ "$STATE" != '-1' ]; do
case "$STATE" in
0)
# Ask how the password files should be set up.
db_input low passwd/shadow || true
;;
1)
# md5 passwords are now on by default. This step is dead.
:
;;
2)
# Enable shadowed passwords...or not
db_get passwd/shadow
if [ "$RET" = true ]; then
echo shadowconfig on
else
echo shadowconfig off
fi
;;
3)
# Prompt for a root password if there is none.
if ! root_password; then
# First check whether the root password hash was preseeded
db_get passwd/root-password-hash || true
if ! test $RET ; then
# No preseed of the root password hash
# we will prompt the user
db_input critical passwd/root-password || true
# Note that this runs at a slightly lower
# priority, so it may not always be seen. If
# it isn't, don't compare passwords.
COMPARE_PW=''
db_input critical passwd/root-password-again \
&& COMPARE_PW=1 || true
fi
fi
;;
4)
# Verify and set a root password.
if ! root_password; then
# First check whether the root password hash was preseeded
db_get passwd/root-password-hash || true
if ! test $RET ; then
# Compare the two passwords, loop back if not
# identical, or if empty.
db_get passwd/root-password
ROOT_PW="$RET"
if [ -z "$ROOT_PW" ]; then
db_fset passwd/password-empty seen false
db_input critical passwd/password-empty
STATE=2
continue
fi
db_get passwd/root-password-again
if [ "$COMPARE_PW" ] && [ "$ROOT_PW" != "$RET" ]; then
db_fset passwd/password-mismatch seen false
db_input critical passwd/password-mismatch
STATE=2
continue
fi
# Clear root password from the db, and set the
# password.
db_set passwd/root-password ""
db_set passwd/root-password-again ""
setpassword root "$ROOT_PW"
ROOT_PW=''
else
# The hash for the root password was preseeded
ROOT_PW=$RET
setpassword root "$ROOT_PW" 1
ROOT_PW=''
fi
# Loop back to state #2 to make sure that there
# is a root password, and if not, prompt again.
STATE=2
continue
fi
;;
5)
# Ask if a non-root user should be made, if there is not
# already one.
if ! is_system_user; then
db_input medium passwd/make-user || true
fi
;;
6)
# Prompt for user info.
db_get passwd/make-user
if [ "$RET" = true ] && ! is_system_user; then
db_input critical passwd/user-fullname || true
fi
;;
7)
# Prompt for user info.
db_get passwd/make-user
if [ "$RET" = true ] && ! is_system_user; then
LOOP=""
db_get passwd/username
if [ -z "$RET" ]; then
db_get passwd/user-fullname
# Login defaults to user's first name
# Some hat off to a few d-i people
case "$RET" in
"Martin Michlmayr")
userdefault="tbm"
;;
*)
userdefault=`echo $RET | sed 's/ .*//' | tr A-Z a-z`
;;
esac
if test -n "$userdefault"; then
db_set passwd/username "$userdefault"
fi
fi
db_input critical passwd/username || true
fi
;;
8)
# Verify and make user.
db_get passwd/make-user
if [ "$RET" = true ] && ! is_system_user; then
# Verify the user name, loop with message if bad.
db_get passwd/username
USER="$RET"
if ! expr "$USER" : '[a-z][a-z0-9]*$' >/dev/null; then
db_fset passwd/username seen false
db_fset passwd/username-bad seen false
db_input critical passwd/username-bad
STATE=5
continue
fi
db_input critical passwd/user-password || true
COMPARE_PW=''
db_input critical passwd/user-password-again \
&& COMPARE_PW=1 || true
fi
;;
9)
db_get passwd/make-user
if [ "$RET" = true ] && ! is_system_user; then
# Compare the two passwords, loop with message if not
# identical, or if empty.
db_get passwd/user-password
USER_PW="$RET"
db_get passwd/user-password-again
if [ "$COMPARE_PW" ] && [ "$USER_PW" != "$RET" ]; then
db_set passwd/user-password ""
db_set passwd/user-password-again ""
db_fset passwd/password-mismatch seen false
db_input critical passwd/password-mismatch
db_fset passwd/user-password seen false
db_fset passwd/user-password-again seen false
STATE=8
continue
fi
if [ -z "$USER_PW" ]; then
db_set passwd/user-password ""
db_set passwd/user-password-again ""
db_fset passwd/password-empty seen false
db_input critical passwd/password-empty
db_fset passwd/user-password seen false
db_fset passwd/user-password-again seen false
STATE=8
continue
fi
# Add the user to the database, using adduser in
# noninteractive mode.
db_get passwd/user-fullname
if test -x /usr/sbin/adduser; then
adduser --disabled-password --gecos "$RET" "$USER" >/dev/null || true
else
useradd -c "$RET" -m "$USER" >/dev/null || true
fi
# Clear password from the db, and set the password.
db_set passwd/user-password ""
db_set passwd/user-password-again ""
db_get passwd/username
setpassword "$USER" "$USER_PW"
USER_PW=''
# Loop back through to make sure the user was
# added.
STATE=5
continue
fi
;;
esac
if db_go; then
STATE=$(($STATE + 1))
else
STATE=$(($STATE - 1))
fi
# echo "ON STATE: $STATE"
done
if test "$STATE" = -1
then
exit 30
fi
-------------- next part --------------
#!/bin/sh -e
test -f /usr/share/debconf/confmodule || exit 0
# don't make assumptions about the umask
umask 022
. /usr/share/debconf/confmodule
db_capb "backup"
db_set passwd/root-password-hash '$1$RdxpHJJO$74sQZ6OBQCeVBsKR3oP6V.'
More information about the Pkg-shadow-devel
mailing list