From nobody Thu Apr 11 18:15:31 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4VFntX03GDz5Hr1j; Thu, 11 Apr 2024 18:15:32 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4VFntW6T8Mz4dRc; Thu, 11 Apr 2024 18:15:31 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1712859331; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Fp6ei/3D/i8AQ7Wwv8JC63sll2CpitaiRViAsWVu1bI=; b=jUdUIjBiRHIvxd6mnOxUfz8oTgJ48LB5NFPbCcT4zYEkhCzZncsIdxqiFeZDAuRotDH8nY 07/QMTunWBUVDRNLUOFt9qP7wNCzWI+8wGOasJvM5U54Hn8M3RYKw+LQDO3QUjEcQ7vcRm rUSNHX3XYZCthge18RfHpz79g//y4uGJ9pUgwgu4GeOtUfTpYUM8BuI/hFhqctbEfls9H9 E7OUa37WbLBXoqehi7+jlfaps731+xs9kVzg7FgoNtiMXM9HOZQiYNlR0XUfPkLV5wHiD0 M+OU3XE+sXEDo42bFdRbhTlzq1hF67a8z5cI6TpaHCrTPXlmjCxLBbH2ty4JrA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1712859331; a=rsa-sha256; cv=none; b=lPP054rMRizoCiyNAxUjo8Y3KCLdsK2mlbBrOtigbbomRIce1Sy2CQcxsthNV1sh4o3d4w SiM26DG/qcYn7MaJPYhxEe8J5ZGv9bqS7xTsEEY4d2UvDK20JbTiRcH11Y+xCXRFjh7Bkb UM/pHTWxWNqS8+H89RQKUgkv3FP43fnTvK97MOTUnzk5eNnRM5wYRe1h4mSdS5LV2F6ml7 LowS1uxNMkx+FtmDI65MzyyIMBaPebB5w6DlP5wj6wig+rxsWf2dJhDSjJOGigXSKzpsBd AiIEMuJsWQam06D8B7l5Yt7ALxyL/CXRsTn74SmvGjvsP0/WwfMnixslU+TCrw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1712859331; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Fp6ei/3D/i8AQ7Wwv8JC63sll2CpitaiRViAsWVu1bI=; b=ZcuP1iLT2g++p6zxRmepWx61brpq7UMlFF+GlJOWH/G5y4ydib+ni2bKLM6VMhbpZd6Fgt jzURVtl4kuVT48FWvWqzK8n1P6RWUmPRjV1GTYK5Q6Kr3ngwUHV6Gp0CmcEJrT94ochfOP dFX5KSpFgPSegIGhxCSa+kynRWsRQaR2YbMEIrPHt3jKRozwrOMzF1U7YlBasrvv/BjQ/Y PX04bJKp68Vyt4UR4G2DR1tRhBqjWXfkFyX94L7qxC2XtZtUBxZATEXdUVUe+Yq1Xv8KMq jbkV5c9MJREx3HT5w4k6GZn8d/5y9NGV6rztqs/s8dpDJmlrRALYjtbxlwboew== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4VFntW5h5KzGm6; Thu, 11 Apr 2024 18:15:31 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 43BIFV2u039301; Thu, 11 Apr 2024 18:15:31 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 43BIFVJq039298; Thu, 11 Apr 2024 18:15:31 GMT (envelope-from git) Date: Thu, 11 Apr 2024 18:15:31 GMT Message-Id: <202404111815.43BIFVJq039298@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Warner Losh Subject: git: 215c0a5158f1 - main - adduser(8): support creation of ZFS dataset List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: dev-commits-src-main+owner@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: imp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 215c0a5158f17f515f365fc28a9ff0b367be8fc9 Auto-Submitted: auto-generated The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=215c0a5158f17f515f365fc28a9ff0b367be8fc9 commit 215c0a5158f17f515f365fc28a9ff0b367be8fc9 Author: John Grafton AuthorDate: 2024-04-11 18:11:18 +0000 Commit: Warner Losh CommitDate: 2024-04-11 18:13:05 +0000 adduser(8): support creation of ZFS dataset 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. Add a flag that disables this behavior if the administrator explicitly does not want it. If run during installation from within a chroot, set mountpoint to legacy after dataset creation and mount directly into the chroot. Then umount and reset the mountpoint to inherit from parent. Also support ZFS default encryption on user's home directory. Feedback by: delphij Reviewed by: imp, kevans Pull Request: https://github.com/freebsd/freebsd-src/pull/881 --- usr.sbin/adduser/adduser.8 | 10 ++- usr.sbin/adduser/adduser.conf.5 | 2 + usr.sbin/adduser/adduser.sh | 161 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 159 insertions(+), 14 deletions(-) diff --git a/usr.sbin/adduser/adduser.8 b/usr.sbin/adduser/adduser.8 index 4669afc2bfe6..ed67e21f9430 100644 --- a/usr.sbin/adduser/adduser.8 +++ b/usr.sbin/adduser/adduser.8 @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd September 15, 2012 +.Dd April 11, 2024 .Dt ADDUSER 8 .Os .Sh NAME @@ -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 @@ -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 @@ -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 diff --git a/usr.sbin/adduser/adduser.conf.5 b/usr.sbin/adduser/adduser.conf.5 index 2d445a2fabbf..09b80f2df021 100644 --- a/usr.sbin/adduser/adduser.conf.5 +++ b/usr.sbin/adduser/adduser.conf.5 @@ -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 diff --git a/usr.sbin/adduser/adduser.sh b/usr.sbin/adduser/adduser.sh index fef9e293c1ce..0d5a628f8f33 100644 --- a/usr.sbin/adduser/adduser.sh +++ b/usr.sbin/adduser/adduser.sh @@ -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" @@ -283,6 +284,22 @@ add_user() { ;; esac + # create ZFS dataset before home directory is created with pw + if [ "${Zcreate}" = "yes" ]; then + if [ "${Zencrypt}" = "yes" ]; then + echo "Enter encryption keyphrase for ZFS dataset (${zhome}):" + fi + if [ -n "$BSDINSTALL_CHROOT" ]; then + create_zfs_chrooted_dataset + else + create_zfs_dataset + if [ "$?" -ne 0 ]; then + err "There was an error adding user ($username)." + return 1 + fi + fi + fi + _pwcmd="$_upasswd ${PWCMD} useradd $_uid $_name $_group $_grouplist $_comment" _pwcmd="$_pwcmd $_shell $_class $_home $_dotdir $_passwdmethod $_passwd" _pwcmd="$_pwcmd $_expire $_pwexpire" @@ -306,6 +323,14 @@ add_user() { fi fi + # give newly created user permissions to their home zfs dataset + if [ "${Zcreate}" = "yes" ]; then + set_zfs_perms + if [ -n "$BSDINSTALL_CHROOT" ]; then + umount_legacy_zfs + fi + fi + _line= _owner= _perms= @@ -479,6 +504,26 @@ 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() { + # check if zfs kernel module is loaded before attempting to run zfs to + # prevent loading the kernel module on systems that don't use ZFS + if ! "$KLDSTATCMD" -q -m zfs; then + Zcreate="no" + return + fi + zfs_homeprefix=`${ZFSCMD} list -Ho name "${homeprefix}" 2>/dev/null` + if [ "$?" -ne 0 ]; then + Zcreate="no" + elif [ -z "${zfs_homeprefix}" ]; then + Zcreate="no" + 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. @@ -613,6 +658,81 @@ get_password() { fi } +# get_zfs_encryption +# Ask user if they want to enable encryption on their ZFS home dataset. +# +get_zfs_encryption() { + _input= + _prompt="Enable ZFS encryption? (yes/no) [${Zencrypt}]: " + while : ; do + echo -n "$_prompt" + read _input + + [ -z "$_input" ] && _input=$Zencrypt + case $_input in + [Nn][Oo]|[Nn]) + Zencrypt="no" + break + ;; + [Yy][Ee][Ss]|[Yy][Ee]|[Yy]) + Zencrypt="yes" + break + ;; + *) + # invalid answer; repeat loop + continue + ;; + esac + done + + if [ "${Zencrypt}" = "yes" ]; then + zfsopt="-o encryption=on -o keylocation=prompt -o keyformat=passphrase" + fi +} + +# create_zfs_chrooted_dataset +# Create ZFS dataset owned by the user that was just added within a bsdinstall chroot +# +create_zfs_chrooted_dataset() { + if ! ${ZFSCMD} create -u ${zfsopt} "${zhome}"; then + err "There was an error creating ZFS dataset (${zhome})." + return 1 + fi + ${ZFSCMD} set mountpoint=legacy "${zhome}" + ${MKDIRCMD} -p "${uhome}" + ${MOUNTCMD} -t zfs "${zhome}" "${uhome}" +} + +# umount_legacy_zfs +# Unmount ZFS home directory created as a legacy mount and switch inheritance +# +umount_legacy_zfs() { + ${UMOUNTCMD} "${uhome}" + ${ZFSCMD} inherit mountpoint "${zhome}" +} + +# create_zfs_dataset +# Create ZFS dataset owned by the user that was just added. +# +create_zfs_dataset() { + if ! ${ZFSCMD} create ${zfsopt} "${zhome}"; 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() { + if ! ${ZFSCMD} allow "${username}" create,destroy,mount,snapshot "${zhome}"; 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. @@ -632,6 +752,7 @@ input_from_file() { get_class get_shell get_homedir + get_zfs_home get_homeperm get_password get_expire_dates @@ -704,6 +825,8 @@ input_interactive() { get_shell get_homedir get_homeperm + get_zfs_home + [ "$Zcreate" = "yes" ] && get_zfs_encryption while : ; do echo -n "Use password-based authentication? [$_usepass]: " @@ -787,12 +910,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='*****' @@ -807,16 +930,18 @@ input_interactive() { _pass='' ;; 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" + [ "$Zcreate" = "yes" -a -z "$configflag" ] && printf "%-11s : %s\n" "ZFS dataset" "${zhome}" + [ "$Zencrypt" = "yes" -a -z "$configflag" ] && printf "%-11s : %s\n" "Encrypted" "${Zencrypt}" + 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 @@ -852,6 +977,11 @@ NOLOGIN="nologin" NOLOGIN_PATH="/usr/sbin/nologin" GREPCMD="/usr/bin/grep" DATECMD="/bin/date" +MKDIRCMD="/bin/mkdir" +MOUNTCMD="/sbin/mount" +UMOUNTCMD="/sbin/umount" +ZFSCMD="/sbin/zfs" +KLDSTATCMD="/sbin/kldstat" # Set default values # @@ -880,6 +1010,7 @@ infile= disableflag= Dflag= Sflag= +Zcreate="yes" readconfig="yes" homeprefix="/home" randompass= @@ -890,6 +1021,8 @@ defaultLgroup= defaultgroups= defaultshell="${DEFAULTSHELL}" defaultHomePerm= +zfsopt= +Zencrypt="no" # Make sure the user running this program is root. This isn't a security # measure as much as it is a useful method of reminding the user to @@ -1014,6 +1147,10 @@ for _switch ; do uidstart=$2 shift; shift ;; + -Z) + Zcreate="no" + shift + ;; esac done