Skip to content

Commit

Permalink
adduser(8): support creation of ZFS dataset
Browse files Browse the repository at this point in the history
On systems utilizing ZFS, default to creating a ZFS dataset for a new
user's home directory if the parent directory resides on a ZFS dataset.
Also add a flag that disables this behavior if the administrator
explicitly does not want it.
  • Loading branch information
jgrafton committed Nov 1, 2023
1 parent ca9dbde commit 11a9dd4
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 13 deletions.
8 changes: 7 additions & 1 deletion usr.sbin/adduser/adduser.8
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
.Nd command for adding new users
.Sh SYNOPSIS
.Nm
.Op Fl CDENShq
.Op Fl CDENSZhq
.Op Fl G Ar groups
.Op Fl L Ar login_class
.Op Fl M Ar mode
Expand All @@ -52,6 +52,10 @@ utility is a shell script, implemented around the
command, for adding new users.
It creates passwd/group entries, a home directory,
copies dotfiles and sends the new user a welcome message.
On systems where the parent of home directory is a ZFS dataset,
.Nm
will create the home directory as a ZFS dataset by default,
unless the system administrator specified otherwise.
It supports two modes of operation.
It may be used interactively
at the command line to add one user at a time, or it may be directed
Expand Down Expand Up @@ -295,6 +299,8 @@ In addition, it will be available for inclusion in the message file in the
.Va randompass
variable.
.El
.It Fl Z
Do not attempt to create ZFS home dataset.
.El
.Sh FORMAT
When the
Expand Down
2 changes: 2 additions & 0 deletions usr.sbin/adduser/adduser.conf.5
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ The default information to be held in the GECOS field of
.It Va uidstart
The default user ID setting.
This must be a number above 1000 and fewer than 65534.
.It Va Zflag
Do not attempt to create ZFS home dataset.
.El
.Sh EXAMPLES
The following is an example
Expand Down
87 changes: 75 additions & 12 deletions usr.sbin/adduser/adduser.sh
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ show_usage() {
echo " -L login class of the user"
echo " -M file permission for home directory"
echo " -N do not read configuration file"
echo " -Z do not attempt to create ZFS home dataset"
echo " -S a nonexistent shell is not an error"
echo " -d home directory"
echo " -f file from which input will be received"
Expand Down Expand Up @@ -202,6 +203,7 @@ save_config() {
echo "msgfile=$msgfile" >> ${ADDUSERCONF}
echo "disableflag=$disableflag" >> ${ADDUSERCONF}
echo "uidstart=$uidstart" >> ${ADDUSERCONF}
echo "Zflag=$Zflag" >> ${ADDUSERCONF}
}

# add_user
Expand Down Expand Up @@ -283,6 +285,15 @@ add_user() {
;;
esac

# create ZFS dataset before home directory is created with pw
if [ -z "$Zflag" ]; then
create_zfs_dataset
if [ "$?" -ne 0 ]; then
err "There was an error adding user ($username)."
return 1
fi
fi

_pwcmd="$_upasswd ${PWCMD} useradd $_uid $_name $_group $_grouplist $_comment"
_pwcmd="$_pwcmd $_shell $_class $_home $_dotdir $_passwdmethod $_passwd"
_pwcmd="$_pwcmd $_expire $_pwexpire"
Expand All @@ -306,6 +317,11 @@ add_user() {
fi
fi

# give newly created user permissions to their home zfs dataset
if [ -z "$Zflag" ]; then
set_zfs_perms
fi

_line=
_owner=
_perms=
Expand Down Expand Up @@ -479,6 +495,20 @@ get_homeperm() {
fi
}

# get_zfs_home
# Determine if homeprefix is located on a ZFS filesystem and if
# so, enable ZFS home dataset creation.
#
get_zfs_home() {
zfs_homeprefix=`${ZFSCMD} list -Ho name "${homeprefix}" 2>/dev/null`
if [ "$?" -ne 0 ]; then
Zflag=yes
elif [ -z "${zfs_homeprefix}" ]; then
Zflag=yes
fi
zhome="${zfs_homeprefix}/${username}"
}

# get_uid
# Reads a numeric userid in an interactive or batch session. Automatically
# allocates one if it is not specified.
Expand Down Expand Up @@ -613,6 +643,30 @@ get_password() {
fi
}

# create_zfs_dataset
# Create ZFS dataset owned by the user that was just added.
#
create_zfs_dataset() {
${ZFSCMD} create "${zhome}"
if [ "$?" -ne 0 ]; then
err "There was an error creating ZFS dataset (${zhome})."
return 1
else
info "Successfully created ZFS dataset (${zhome})."
fi
}

# set_zfs_perms
# Give new user ownership of newly created zfs dataset.
#
set_zfs_perms() {
${ZFSCMD} allow "${username}" create,destroy,mount,snapshot "${zhome}"
if [ "$?" -ne 0 ]; then
err "There was an error setting permissions on ZFS dataset (${zhome})."
return 1
fi
}

# input_from_file
# Reads a line of account information from standard input and
# adds it to the user database.
Expand All @@ -632,6 +686,7 @@ input_from_file() {
get_class
get_shell
get_homedir
get_zfs_home
get_homeperm
get_password
get_expire_dates
Expand Down Expand Up @@ -704,6 +759,7 @@ input_interactive() {
get_shell
get_homedir
get_homeperm
get_zfs_home

while : ; do
echo -n "Use password-based authentication? [$_usepass]: "
Expand Down Expand Up @@ -787,12 +843,12 @@ input_interactive() {
esac
break
done

# Display the information we have so far and prompt to
# commit it.
#
_disable=${disableflag:-"no"}
[ -z "$configflag" ] && printf "%-10s : %s\n" Username $username
[ -z "$configflag" ] && printf "%-11s : %s\n" Username $username
case $passwdtype in
yes)
_pass='*****'
Expand All @@ -807,16 +863,17 @@ input_interactive() {
_pass='<random>'
;;
esac
[ -z "$configflag" ] && printf "%-10s : %s\n" "Password" "$_pass"
[ -n "$configflag" ] && printf "%-10s : %s\n" "Pass Type" "$passwdtype"
[ -z "$configflag" ] && printf "%-10s : %s\n" "Full Name" "$ugecos"
[ -z "$configflag" ] && printf "%-10s : %s\n" "Uid" "$uuid"
printf "%-10s : %s\n" "Class" "$uclass"
printf "%-10s : %s %s\n" "Groups" "${ulogingroup:-$username}" "$ugroups"
printf "%-10s : %s\n" "Home" "$uhome"
printf "%-10s : %s\n" "Home Mode" "$uhomeperm"
printf "%-10s : %s\n" "Shell" "$ushell"
printf "%-10s : %s\n" "Locked" "$_disable"
[ -z "$configflag" ] && printf "%-11s : %s\n" "Password" "$_pass"
[ -n "$configflag" ] && printf "%-11s : %s\n" "Pass Type" "$passwdtype"
[ -z "$configflag" ] && printf "%-11s : %s\n" "Full Name" "$ugecos"
[ -z "$configflag" ] && printf "%-11s : %s\n" "Uid" "$uuid"
[ -z "$Zflag" -a -z "$configflag" ] && printf "%-11s : %s\n" "ZFS dataset" "${zhome}"
printf "%-11s : %s\n" "Class" "$uclass"
printf "%-11s : %s %s\n" "Groups" "${ulogingroup:-$username}" "$ugroups"
printf "%-11s : %s\n" "Home" "$uhome"
printf "%-11s : %s\n" "Home Mode" "$uhomeperm"
printf "%-11s : %s\n" "Shell" "$ushell"
printf "%-11s : %s\n" "Locked" "$_disable"
while : ; do
echo -n "OK? (yes/no) [$_all_ok]: "
read _input
Expand Down Expand Up @@ -852,6 +909,7 @@ NOLOGIN="nologin"
NOLOGIN_PATH="/usr/sbin/nologin"
GREPCMD="/usr/bin/grep"
DATECMD="/bin/date"
ZFSCMD="/sbin/zfs"

# Set default values
#
Expand Down Expand Up @@ -880,6 +938,7 @@ infile=
disableflag=
Dflag=
Sflag=
Zflag=
readconfig="yes"
homeprefix="/home"
randompass=
Expand Down Expand Up @@ -1014,6 +1073,10 @@ for _switch ; do
uidstart=$2
shift; shift
;;
-Z)
Zflag=yes
shift
;;
esac
done

Expand Down

0 comments on commit 11a9dd4

Please sign in to comment.