#!/bin/sh -e

test -f /usr/share/debconf/confmodule || exit 0

# Check to see if the package is being reconfigured.
# I don't want to bother on an initial install or on upgrade, because
# some of the password stuff below could mess with a perfectly working
# system when passwd was just harmlessly upgraded (that has happened
# in the past).
if [ "$1" != reconfigure ]; then
	exit 0
fi

# 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 egrep -q '^+:' /etc/passwd || \
           egrep -q '^[^:]*:[^:]*:[1-9][0-9][0-9][0-9]:' /etc/passwd || \
           egrep -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 egrep -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`" -a \
	     "`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).
#
# Pass in two arguments: the user and the password.
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.
#	db_get passwd/md5
#	if [ "$RET" = true ]; then
		USE_MD5=1
#	else
#		USE_MD5=''
#	fi
	export USE_MD5
	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"
	SETPASSWD_PW=''
	USE_MD5=''
}

# Main loop starts here. Use a state machine to allow jumping back to
# previous questions.
STATE=0
while [ "$STATE" != '9' -a "$STATE" != '-1' ]; do
	case "$STATE" in
	0)
		# Ask how the password files should be set up.
		db_input low passwd/shadow || true
	;;
	1)	
# 		# Turn md5 passwords on/off now, so the two passwords set
# 		# below can use it.
# 		db_get passwd/md5
# 		for file in /etc/pam.d/*; do
# 			if [ -e $file ]; then
# 				if [ "$RET" = true ]; then
# 					# On.
# 					if ! egrep -q "^password.*pam_(unix|ldap)\.so.*md5" $file ; then
# 						sed 's/^\(password.*\)/\1 md5/' \
# 							< $file > $file.new
# 						mv -f $file.new $file
# 					fi
# 				else
# 					# Off.
# 					if egrep -q "^password.*pam_(unix|ldap)\.so.*md5" $file ; then
# 						sed 's/^\(password.*\)md5/\1/' \
# 							< $file > $file.new
# 						mv -f $file.new $file
# 					fi
# 				fi
# 			fi
# 		done
	:
	;;
	2)
		# Enable shadowed passwords...or not
		db_get passwd/shadow
		if [ "$RET" = true ]; then
			shadowconfig on >/dev/null
		else
			shadowconfig off >/dev/null
		fi
	;;
	3)
		# Prompt for a root password if there is none.
		if ! root_password; then
			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 high passwd/root-password-again \
				&& COMPARE_PW=1 || true
		fi
	;;
	4)
		# Verify and set a root password.
		if ! root_password; 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" -a "$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=''
			
			# 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
			db_input critical passwd/user-password || true
			COMPARE_PW=''
			db_input high passwd/user-password-again \
				&& COMPARE_PW=1 || 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
			
			# 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" -a "$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=5
				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=5
				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
