1263150Sdteskeif [ ! "$_USERMGMT_USER_SUBR" ]; then _USERMGMT_USER_SUBR=1 2263150Sdteske# 3263150Sdteske# Copyright (c) 2012 Ron McDowell 4263150Sdteske# Copyright (c) 2012-2014 Devin Teske 5263150Sdteske# All rights reserved. 6263150Sdteske# 7263150Sdteske# Redistribution and use in source and binary forms, with or without 8263150Sdteske# modification, are permitted provided that the following conditions 9263150Sdteske# are met: 10263150Sdteske# 1. Redistributions of source code must retain the above copyright 11263150Sdteske# notice, this list of conditions and the following disclaimer. 12263150Sdteske# 2. Redistributions in binary form must reproduce the above copyright 13263150Sdteske# notice, this list of conditions and the following disclaimer in the 14263150Sdteske# documentation and/or other materials provided with the distribution. 15263150Sdteske# 16263150Sdteske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17263150Sdteske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18263150Sdteske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19263150Sdteske# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20263150Sdteske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21263150Sdteske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22263150Sdteske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23263150Sdteske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24263150Sdteske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25263150Sdteske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26263150Sdteske# SUCH DAMAGE. 27263150Sdteske# 28263150Sdteske# $FreeBSD$ 29263150Sdteske# 30263150Sdteske############################################################ INCLUDES 31263150Sdteske 32263150SdteskeBSDCFG_SHARE="/usr/share/bsdconfig" 33263150Sdteske. $BSDCFG_SHARE/common.subr || exit 1 34263150Sdteskef_dprintf "%s: loading includes..." usermgmt/user.subr 35263150Sdteskef_include $BSDCFG_SHARE/dialog.subr 36263150Sdteskef_include $BSDCFG_SHARE/strings.subr 37263150Sdteskef_include $BSDCFG_SHARE/usermgmt/group_input.subr 38263150Sdteskef_include $BSDCFG_SHARE/usermgmt/user_input.subr 39263150Sdteske 40263150SdteskeBSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt" 41263150Sdteskef_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr 42263150Sdteske 43263150Sdteske############################################################ CONFIGURATION 44263150Sdteske 45263150Sdteske# set some reasonable defaults if /etc/adduser.conf does not exist. 46263150Sdteske[ -f /etc/adduser.conf ] && f_include /etc/adduser.conf 47263150Sdteske: ${defaultclass:=""} 48263150Sdteske: ${defaultshell:="/bin/sh"} 49263150Sdteske: ${homeprefix:="/home"} 50263150Sdteske: ${passwdtype:="yes"} 51263150Sdteske: ${udotdir:="/usr/share/skel"} 52263150Sdteske: ${uexpire:=""} 53263150Sdteske # Default account expire time. Format is similar to upwexpire variable. 54263150Sdteske: ${ugecos:="User &"} 55263150Sdteske: ${upwexpire:=""} 56263150Sdteske # The default password expiration time. Format of the date is either a 57263150Sdteske # UNIX time in decimal, or a date in dd-mmm-yy[yy] format, where dd is 58263150Sdteske # the day, mmm is the month in either numeric or alphabetic format, and 59263150Sdteske # yy[yy] is either a two or four digit year. This variable also accepts 60263150Sdteske # a relative date in the form of n[mhdwoy] where n is a decimal, octal 61263150Sdteske # (leading 0) or hexadecimal (leading 0x) digit followed by the number 62263150Sdteske # of Minutes, Hours, Days, Weeks, Months or Years from the current date 63263150Sdteske # at which the expiration time is to be set. 64263150Sdteske 65263150Sdteske# 66263150Sdteske# uexpire and upwexpire from adduser.conf(5) differ only slightly from what 67263150Sdteske# pw(8) accepts as `date' argument(s); pw(8) requires a leading `+' for the 68263150Sdteske# relative date syntax (n[mhdwoy]). 69263150Sdteske# 70263150Sdteskecase "$uexpire" in *[mhdwoy]) 71263150Sdteske f_isinteger "${uexpire%[mhdwoy]}" && uexpire="+$uexpire" 72263150Sdteskeesac 73263150Sdteskecase "$upwexpire" in *[mhdwoy]) 74263150Sdteske f_isinteger "${upwexpire%[mhdwoy]}" && upwexpire="+$upwexpire" 75263150Sdteskeesac 76263150Sdteske 77263150Sdteske############################################################ FUNCTIONS 78263150Sdteske 79263150Sdteske# f_user_create_homedir $user 80263150Sdteske# 81263150Sdteske# Create home directory for $user. 82263150Sdteske# 83263150Sdteskef_user_create_homedir() 84263150Sdteske{ 85263150Sdteske local funcname=f_user_create_homedir 86263150Sdteske local user="$1" 87263150Sdteske 88263150Sdteske [ "$user" ] || return $FAILURE 89263150Sdteske 90263150Sdteske local user_account_expire user_class user_gecos user_gid user_home_dir 91263150Sdteske local user_member_groups user_name user_password user_password_expire 92263150Sdteske local user_shell user_uid # Variables created by f_input_user() below 93263150Sdteske f_input_user "$user" || return $FAILURE 94263150Sdteske 95263150Sdteske f_dprintf "Creating home directory \`%s' for user \`%s'" \ 96263150Sdteske "$user_home_dir" "$user" 97263150Sdteske 98263150Sdteske local _user_gid _user_home_dir _user_uid 99263150Sdteske f_shell_escape "$user_gid" _user_gid 100263150Sdteske f_shell_escape "$user_home_dir" _user_home_dir 101263150Sdteske f_shell_escape "$user_uid" _user_uid 102263150Sdteske f_eval_catch $funcname mkdir "mkdir -p '%s'" "$_user_home_dir" || 103263150Sdteske return $FAILURE 104263150Sdteske f_eval_catch $funcname chown "chown '%i:%i' '%s'" \ 105263150Sdteske "$_user_uid" "$_user_gid" "$_user_home_dir" || return $FAILURE 106263150Sdteske} 107263150Sdteske 108263150Sdteske# f_user_copy_dotfiles $user 109263150Sdteske# 110263150Sdteske# Copy `skel' dot-files from $udotdir (global inherited from /etc/adduser.conf) 111263150Sdteske# to the home-directory of $user. Attempts to create the home-directory first 112263150Sdteske# if it doesn't exist. 113263150Sdteske# 114263150Sdteskef_user_copy_dotfiles() 115263150Sdteske{ 116263150Sdteske local funcname=f_user_copy_dotfiles 117263150Sdteske local user="$1" 118263150Sdteske 119263150Sdteske [ "$udotdir" ] || return $FAILURE 120263150Sdteske [ "$user" ] || return $FAILURE 121263150Sdteske 122263150Sdteske local user_account_expire user_class user_gecos user_gid user_home_dir 123263150Sdteske local user_member_groups user_name user_password user_password_expire 124263150Sdteske local user_shell user_uid # Variables created by f_input_user() below 125263150Sdteske f_input_user "$user" || return $FAILURE 126263150Sdteske 127263150Sdteske f_dprintf "Copying dot-files from \`%s' to \`%s'" \ 128263150Sdteske "$udotdir" "$user_home_dir" 129263150Sdteske 130263150Sdteske # Attempt to create the home directory if it doesn't exist 131263150Sdteske [ -d "$user_home_dir" ] || 132263150Sdteske f_user_create_homedir "$user" || return $FAILURE 133263150Sdteske 134263150Sdteske local _user_gid _user_home_dir _user_uid 135263150Sdteske f_shell_escape "$user_gid" _user_gid 136263150Sdteske f_shell_escape "$user_home_dir" _user_home_dir 137263150Sdteske f_shell_escape "$user_uid" _user_uid 138263150Sdteske 139263150Sdteske local - # Localize `set' to this function 140263150Sdteske set +f # Enable glob pattern-matching for paths 141263150Sdteske cd "$udotdir" || return $FAILURE 142263150Sdteske 143263150Sdteske local _file file retval 144263150Sdteske for file in dot.*; do 145263150Sdteske [ -e "$file" ] || continue # no-match 146263150Sdteske 147263150Sdteske f_shell_escape "$file" "_file" 148263150Sdteske f_eval_catch $funcname cp "cp -n '%s' '%s'" \ 149263150Sdteske "$_file" "$_user_home_dir/${_file#dot}" 150263150Sdteske retval=$? 151263150Sdteske [ $retval -eq $SUCCESS ] || break 152263150Sdteske f_eval_catch $funcname chown \ 153263150Sdteske "chown -h '%i:%i' '%s'" \ 154263150Sdteske "$_user_uid" "$_user_gid" \ 155263150Sdteske "$_user_home_dir/${_file#dot}" 156263150Sdteske retval=$? 157263150Sdteske [ $retval -eq $SUCCESS ] || break 158263150Sdteske done 159263150Sdteske 160263150Sdteske cd - 161263150Sdteske return $retval 162263150Sdteske} 163263150Sdteske 164263150Sdteske# f_user_add [$user] 165263150Sdteske# 166263150Sdteske# Create a login account. If both $user (as a first argument) and $VAR_USER are 167263150Sdteske# unset or NULL and we are running interactively, prompt the end-user to enter 168263150Sdteske# the name of a new login account and (if $VAR_NO_CONFIRM is unset or NULL) 169263150Sdteske# prompt the end-user to answer some questions about the new account. Variables 170263150Sdteske# that can be used to script user input: 171263150Sdteske# 172263150Sdteske# VAR_USER [Optional if running interactively] 173263150Sdteske# The login to add. Ignored if given non-NULL first-argument. 174263150Sdteske# VAR_USER_ACCOUNT_EXPIRE [Optional] 175263150Sdteske# The account expiration time. Format is similar to 176263150Sdteske# VAR_USER_PASSWORD_EXPIRE variable below. Default is to never 177263150Sdteske# expire the account. 178263150Sdteske# VAR_USER_DOTFILES_CREATE [Optional] 179263150Sdteske# If non-NULL, populate the user's home directory with the 180263150Sdteske# template files found in $udotdir (`/usr/share/skel' default). 181263150Sdteske# VAR_USER_GECOS [Optional] 182263150Sdteske# Often the full name of the account holder. Default is NULL. 183263150Sdteske# VAR_USER_GID [Optional] 184263150Sdteske# Numerical primary-group ID to use. If NULL or unset, the group 185263150Sdteske# ID is automatically chosen. 186263150Sdteske# VAR_USER_GROUPS [Optional] 187263150Sdteske# Comma-separated list of additional groups to which the user is 188263150Sdteske# a member of. Default is NULL (no additional groups). 189263150Sdteske# VAR_USER_HOME [Optional] 190263150Sdteske# The home directory to set. If NULL or unset, the home directory 191263150Sdteske# is automatically calculated. 192263150Sdteske# VAR_USER_HOME_CREATE [Optional] 193263150Sdteske# If non-NULL, create the user's home directory if it doesn't 194263150Sdteske# already exist. 195263150Sdteske# VAR_USER_LOGIN_CLASS [Optional] 196263150Sdteske# Login class to use when creating the login. Default is NULL. 197263150Sdteske# VAR_USER_PASSWORD [Optional] 198263150Sdteske# Unencrypted password to use. If unset or NULL, password 199263150Sdteske# authentication for the login is disabled. 200263150Sdteske# VAR_USER_PASSWORD_EXPIRE [Optional] 201263150Sdteske# The password expiration time. Format of the date is either a 202263150Sdteske# UNIX time in decimal, or a date in dd-mmm-yy[yy] format, where 203263150Sdteske# dd is the day, mmm is the month in either numeric or alphabetic 204263150Sdteske# format, and yy[yy] is either a two or four digit year. This 205263150Sdteske# variable also accepts a relative date in the form of +n[mhdwoy] 206263150Sdteske# where n is a decimal, octal (leading 0) or hexadecimal (leading 207263150Sdteske# 0x) digit followed by the number of Minutes, Hours, Days, 208263150Sdteske# Weeks, Months or Years from the current date at which the 209263150Sdteske# expiration time is to be set. Default is to never expire the 210263150Sdteske# account password. 211263150Sdteske# VAR_USER_SHELL [Optional] 212263150Sdteske# Path to login shell to use. Default is `/bin/sh'. 213263150Sdteske# VAR_USER_UID [Optional] 214263150Sdteske# Numerical user ID to use. If NULL or unset, the user ID is 215263150Sdteske# automatically chosen. 216263150Sdteske# 217263150Sdteske# Returns success if the user account was successfully created. 218263150Sdteske# 219263150Sdteskef_user_add() 220263150Sdteske{ 221263150Sdteske local funcname=f_user_add 222263150Sdteske local title # Calculated below 223263150Sdteske local alert=f_show_msg no_confirm= 224263150Sdteske 225263150Sdteske f_getvar $VAR_NO_CONFIRM no_confirm 226263150Sdteske [ "$no_confirm" ] && alert=f_show_info 227263150Sdteske 228263150Sdteske local input 229263150Sdteske f_getvar 3:-\$$VAR_USER input "$1" 230263150Sdteske 231263150Sdteske # 232263150Sdteske # NB: pw(8) has a ``feature'' wherein `-n name' can be taken as UID 233263150Sdteske # instead of name. Work-around is to also pass `-u UID' at the same 234263150Sdteske # time (any UID will do; but `-1' is appropriate for this context). 235263150Sdteske # 236263150Sdteske if [ "$input" ] && f_quietly pw usershow -n "$input" -u -1; then 237263150Sdteske f_show_err "$msg_login_already_used" "$input" 238263150Sdteske return $FAILURE 239263150Sdteske fi 240263150Sdteske 241263150Sdteske local user_name="$input" 242263150Sdteske while f_interactive && [ ! "$user_name" ]; do 243263150Sdteske f_dialog_input_name user_name "$user_name" || 244263150Sdteske return $SUCCESS 245263150Sdteske [ "$user_name" ] || 246263150Sdteske f_show_err "$msg_please_enter_a_user_name" 247263150Sdteske done 248263150Sdteske if [ ! "$user_name" ]; then 249263150Sdteske f_show_err "$msg_no_user_specified" 250263150Sdteske return $FAILURE 251263150Sdteske fi 252263150Sdteske 253263150Sdteske local user_account_expire user_class user_gecos user_gid user_home_dir 254263150Sdteske local user_member_groups user_password user_password_expire user_shell 255263150Sdteske local user_uid user_dotfiles_create= user_home_create= 256263150Sdteske f_getvar $VAR_USER_ACCOUNT_EXPIRE-\$uexpire user_account_expire 257263150Sdteske f_getvar $VAR_USER_DOTFILES_CREATE:+\$msg_yes user_dotfiles_create 258263150Sdteske f_getvar $VAR_USER_GECOS-\$ugecos user_gecos 259263150Sdteske f_getvar $VAR_USER_GID user_gid 260263150Sdteske f_getvar $VAR_USER_GROUPS user_member_groups 261263150Sdteske f_getvar $VAR_USER_HOME:-\${homeprefix%/}/\$user_name \ 262263150Sdteske user_home_dir 263263150Sdteske f_getvar $VAR_USER_HOME_CREATE:+\$msg_yes user_home_create 264263150Sdteske f_getvar $VAR_USER_LOGIN_CLASS-\$defaultclass user_class 265263150Sdteske f_getvar $VAR_USER_PASSWORD user_password 266263150Sdteske f_getvar $VAR_USER_PASSWORD_EXPIRE-\$upwexpire user_password_expire 267263150Sdteske f_getvar $VAR_USER_SHELL-\$defaultshell user_shell 268263150Sdteske f_getvar $VAR_USER_UID user_uid 269263150Sdteske 270263150Sdteske # Create home-dir if no script-override and does not exist 271263150Sdteske f_isset $VAR_USER_HOME_CREATE || [ -d "$user_home_dir" ] || 272263150Sdteske user_home_create="$msg_yes" 273263150Sdteske # Copy dotfiles if home-dir creation is desired, does not yet exist, 274263150Sdteske # and no script-override has been set 275263150Sdteske f_isset $VAR_USER_DOTFILES_CREATE || 276263150Sdteske [ "$user_home_create" != "$msg_yes" ] || 277263150Sdteske [ -d "$user_home_dir" ] || user_dotfiles_create="$msg_yes" 278263150Sdteske # Create home-dir if copying dotfiles but home-dir does not exist 279263150Sdteske [ "$user_dotfiles_create" -a ! -d "$user_home_dir" ] && 280263150Sdteske user_home_create="$msg_yes" 281263150Sdteske 282263150Sdteske # Set flags for meaningful NULL values if-provided 283263150Sdteske local no_account_expire= no_password_expire= null_gecos= null_members= 284263150Sdteske local user_password_disable= 285263150Sdteske f_isset $VAR_USER_ACCOUNT_EXPIRE && 286263150Sdteske [ ! "$user_account_expire" ] && no_account_expire=1 287263150Sdteske f_isset $VAR_USER_GECOS && 288263150Sdteske [ ! "$user_gecos" ] && null_gecos=1 289263150Sdteske f_isset $VAR_USER_GROUPS && 290263150Sdteske [ ! "$user_member_groups" ] && null_members=1 291263150Sdteske f_isset $VAR_USER_PASSWORD && 292263150Sdteske [ ! "$user_password" ] && user_password_disable=1 293263150Sdteske f_isset $VAR_USER_PASSWORD_EXPIRE && 294263150Sdteske [ ! "$user_password_expire" ] && no_password_expire=1 295263150Sdteske 296263150Sdteske if f_interactive && [ ! "$no_confirm" ]; then 297263150Sdteske f_dialog_noyes \ 298263150Sdteske "$msg_use_default_values_for_all_account_details" 299263150Sdteske retval=$? 300263150Sdteske if [ $retval -eq $DIALOG_ESC ]; then 301263150Sdteske return $SUCCESS 302263150Sdteske elif [ $retval -ne $DIALOG_OK ]; then 303263150Sdteske # 304263150Sdteske # Ask series of questions to pre-fill the editor screen 305263150Sdteske # 306263150Sdteske # Defaults used in each dialog should allow the user to 307263150Sdteske # simply hit ENTER to proceed, because cancelling any 308263150Sdteske # single dialog will cause them to be returned to the 309263150Sdteske # previous menu. 310263150Sdteske # 311263150Sdteske 312263150Sdteske f_dialog_input_gecos user_gecos "$user_gecos" || 313263150Sdteske return $FAILURE 314263150Sdteske if [ "$passwdtype" = "yes" ]; then 315263150Sdteske f_dialog_input_password user_password \ 316263150Sdteske user_password_disable || 317263150Sdteske return $FAILURE 318263150Sdteske fi 319263150Sdteske f_dialog_input_uid user_uid "$user_uid" || 320263150Sdteske return $FAILURE 321263150Sdteske f_dialog_input_gid user_gid "$user_gid" || 322263150Sdteske return $FAILURE 323263150Sdteske f_dialog_input_member_groups user_member_groups \ 324263150Sdteske "$user_member_groups" || return $FAILURE 325263150Sdteske f_dialog_input_class user_class "$user_class" || 326263150Sdteske return $FAILURE 327263150Sdteske f_dialog_input_expire_password user_password_expire \ 328263150Sdteske "$user_password_expire" || return $FAILURE 329263150Sdteske f_dialog_input_expire_account user_account_expire \ 330263150Sdteske "$user_account_expire" || return $FAILURE 331263150Sdteske f_dialog_input_home_dir user_home_dir \ 332263150Sdteske "$user_home_dir" || return $FAILURE 333263150Sdteske if [ ! -d "$user_home_dir" ]; then 334263150Sdteske f_dialog_input_home_create user_home_create || 335263150Sdteske return $FAILURE 336263150Sdteske if [ "$user_home_create" = "$msg_yes" ]; then 337263150Sdteske f_dialog_input_dotfiles_create \ 338263150Sdteske user_dotfiles_create || 339263150Sdteske return $FAILURE 340263150Sdteske fi 341263150Sdteske fi 342263150Sdteske f_dialog_input_shell user_shell "$user_shell" || 343263150Sdteske return $FAILURE 344263150Sdteske fi 345263150Sdteske fi 346263150Sdteske 347263150Sdteske # 348263150Sdteske # Loop until the user decides to Exit, Cancel, or presses ESC 349263150Sdteske # 350263150Sdteske title="$msg_add $msg_user: $user_name" 351263150Sdteske if f_interactive; then 352263150Sdteske local mtag retval defaultitem= 353263150Sdteske while :; do 354263150Sdteske f_dialog_title "$title" 355263150Sdteske f_dialog_menu_user_add "$defaultitem" 356263150Sdteske retval=$? 357263150Sdteske f_dialog_title_restore 358263150Sdteske f_dialog_menutag_fetch mtag 359263150Sdteske f_dprintf "retval=%u mtag=[%s]" $retval "$mtag" 360263150Sdteske defaultitem="$mtag" 361263150Sdteske 362263150Sdteske # Return if user either pressed ESC or chose Cancel/No 363263150Sdteske [ $retval -eq $DIALOG_OK ] || return $FAILURE 364263150Sdteske 365263150Sdteske case "$mtag" in 366263150Sdteske X) # Add/Exit 367263150Sdteske local var 368263150Sdteske for var in account_expire class gecos gid home_dir \ 369263150Sdteske member_groups name password_expire shell uid \ 370263150Sdteske ; do 371263150Sdteske local _user_$var 372263150Sdteske eval f_shell_escape \"\$user_$var\" _user_$var 373263150Sdteske done 374263150Sdteske 375263150Sdteske local cmd="pw useradd -n '$_user_name'" 376263150Sdteske [ "$user_gid" ] && cmd="$cmd -g '$_user_gid'" 377263150Sdteske [ "$user_shell" ] && cmd="$cmd -s '$_user_shell'" 378263150Sdteske [ "$user_uid" ] && cmd="$cmd -u '$_user_uid'" 379263150Sdteske [ "$user_account_expire" -o \ 380263150Sdteske "$no_account_expire" ] && 381263150Sdteske cmd="$cmd -e '$_user_account_expire'" 382263150Sdteske [ "$user_class" -o "$null_class" ] && 383263150Sdteske cmd="$cmd -L '$_user_class'" 384263150Sdteske [ "$user_gecos" -o "$null_gecos" ] && 385263150Sdteske cmd="$cmd -c '$_user_gecos'" 386263150Sdteske [ "$user_home_dir" ] && 387263150Sdteske cmd="$cmd -d '$_user_home_dir'" 388263150Sdteske [ "$user_member_groups" ] && 389263150Sdteske cmd="$cmd -G '$_user_member_groups'" 390263150Sdteske [ "$user_password_expire" -o \ 391263150Sdteske "$no_password_expire" ] && 392263150Sdteske cmd="$cmd -p '$_user_password_expire'" 393263150Sdteske 394263150Sdteske # Execute the command 395263150Sdteske if [ "$user_password_disable" ]; then 396263150Sdteske f_eval_catch $funcname pw '%s -h -' "$cmd" 397263150Sdteske elif [ "$user_password" ]; then 398263150Sdteske echo "$user_password" | f_eval_catch \ 399263150Sdteske $funcname pw '%s -h 0' "$cmd" 400263150Sdteske else 401263150Sdteske f_eval_catch $funcname pw '%s' "$cmd" 402263150Sdteske fi || continue 403263150Sdteske 404263150Sdteske # Create home directory if desired 405263150Sdteske [ "${user_home_create:-$msg_no}" != "$msg_no" ] && 406263150Sdteske f_user_create_homedir "$user_name" 407263150Sdteske 408263150Sdteske # Copy dotfiles if desired 409263150Sdteske [ "${user_dotfiles_create:-$msg_no}" != \ 410263150Sdteske "$msg_no" ] && f_user_copy_dotfiles "$user_name" 411263150Sdteske 412263150Sdteske break # to success 413263150Sdteske ;; 414263150Sdteske 1) # Login (prompt for new login name) 415263150Sdteske f_dialog_input_name input "$user_name" || 416263150Sdteske continue 417263150Sdteske if f_quietly pw usershow -n "$input" -u -1; then 418263150Sdteske f_show_err "$msg_login_already_used" "$input" 419263150Sdteske continue 420263150Sdteske fi 421263150Sdteske user_name="$input" 422263150Sdteske title="$msg_add $msg_user: $user_name" 423263150Sdteske user_home_dir="${homeprefix%/}/$user_name" 424263150Sdteske ;; 425263150Sdteske 2) # Full Name 426263150Sdteske f_dialog_input_gecos user_gecos "$user_gecos" && 427263150Sdteske [ ! "$user_gecos" ] && null_gecos=1 ;; 428263150Sdteske 3) # Password 429263150Sdteske f_dialog_input_password \ 430263150Sdteske user_password user_password_disable ;; 431263150Sdteske 4) # User ID 432263150Sdteske f_dialog_input_uid user_uid "$user_uid" ;; 433263150Sdteske 5) # Group ID 434263150Sdteske f_dialog_input_gid user_gid "$user_gid" ;; 435263150Sdteske 6) # Member of Groups 436263150Sdteske f_dialog_input_member_groups \ 437263150Sdteske user_member_groups "$user_member_groups" && 438263150Sdteske [ ! "$user_member_groups" ] && 439263150Sdteske null_members=1 ;; 440263150Sdteske 7) # Login Class 441263150Sdteske f_dialog_input_class user_class "$user_class" && 442263150Sdteske [ ! "$user_class" ] && null_class=1 ;; 443263150Sdteske 8) # Password Expires On 444263150Sdteske f_dialog_input_expire_password \ 445263150Sdteske user_password_expire "$user_password_expire" && 446263150Sdteske [ ! "$user_password_expire" ] && 447263150Sdteske no_password_expire=1 ;; 448263150Sdteske 9) # Account Expires On 449263150Sdteske f_dialog_input_expire_account \ 450263150Sdteske user_account_expire "$user_account_expire" && 451263150Sdteske [ ! "$user_account_expire" ] && 452263150Sdteske no_account_expire=1 ;; 453263150Sdteske A) # Home Directory 454263150Sdteske f_dialog_input_home_dir \ 455263150Sdteske user_home_dir "$user_home_dir" ;; 456263150Sdteske B) # Shell 457263150Sdteske f_dialog_input_shell user_shell "$user_shell" ;; 458263150Sdteske C) # Create Home Directory? 459263150Sdteske if [ "${user_home_create:-$msg_no}" != "$msg_no" ] 460263150Sdteske then 461263150Sdteske user_home_create="$msg_no" 462263150Sdteske else 463263150Sdteske user_home_create="$msg_yes" 464263150Sdteske fi ;; 465263150Sdteske D) # Create Dotfiles? 466263150Sdteske if [ "${user_dotfiles_create:-$msg_no}" != \ 467263150Sdteske "$msg_no" ] 468263150Sdteske then 469263150Sdteske user_dotfiles_create="$msg_no" 470263150Sdteske else 471263150Sdteske user_dotfiles_create="$msg_yes" 472263150Sdteske fi ;; 473263150Sdteske esac 474263150Sdteske done 475263150Sdteske else 476263150Sdteske local var 477263150Sdteske for var in account_expire class gecos gid home_dir \ 478263150Sdteske member_groups name password_expire shell uid \ 479263150Sdteske ; do 480263150Sdteske local _user_$var 481263150Sdteske eval f_shell_escape \"\$user_$var\" _user_$var 482263150Sdteske done 483263150Sdteske 484263150Sdteske # Form the command 485263150Sdteske local cmd="pw useradd -n '$_user_name'" 486263150Sdteske [ "$user_gid" ] && cmd="$cmd -g '$_user_gid'" 487263150Sdteske [ "$user_home_dir" ] && cmd="$cmd -d '$_user_home_dir'" 488263150Sdteske [ "$user_shell" ] && cmd="$cmd -s '$_user_shell'" 489263150Sdteske [ "$user_uid" ] && cmd="$cmd -u '$_user_uid'" 490263150Sdteske [ "$user_account_expire" -o "$no_account_expire" ] && 491263150Sdteske cmd="$cmd -e '$_user_account_expire'" 492263150Sdteske [ "$user_class" -o "$null_class" ] && 493263150Sdteske cmd="$cmd -L '$_user_class'" 494263150Sdteske [ "$user_gecos" -o "$null_gecos" ] && 495263150Sdteske cmd="$cmd -c '$_user_gecos'" 496263150Sdteske [ "$user_member_groups" -o "$null_members" ] && 497263150Sdteske cmd="$cmd -G '$_user_member_groups'" 498263150Sdteske [ "$user_password_expire" -o "$no_password_expire" ] && 499263150Sdteske cmd="$cmd -p '$_user_password_expire'" 500263150Sdteske 501263150Sdteske # Execute the command 502263150Sdteske local retval err 503263150Sdteske if [ "$user_password_disable" ]; then 504263150Sdteske f_eval_catch -k err $funcname pw '%s -h -' "$cmd" 505263150Sdteske elif [ "$user_password" ]; then 506263150Sdteske err=$( echo "$user_password" | f_eval_catch -de \ 507263150Sdteske $funcname pw '%s -h 0' "$cmd" 2>&1 ) 508263150Sdteske else 509263150Sdteske f_eval_catch -k err $funcname pw '%s' "$cmd" 510263150Sdteske fi 511263150Sdteske retval=$? 512263150Sdteske if [ $retval -ne $SUCCESS ]; then 513263150Sdteske f_show_err "%s" "$err" 514263150Sdteske return $retval 515263150Sdteske fi 516263150Sdteske 517263150Sdteske # Create home directory if desired 518263150Sdteske [ "${user_home_create:-$msg_no}" != "$msg_no" ] && 519263150Sdteske f_user_create_homedir "$user_name" 520263150Sdteske 521263150Sdteske # Copy dotfiles if desired 522263150Sdteske [ "${user_dotfiles_create:-$msg_no}" != "$msg_no" ] && 523263150Sdteske f_user_copy_dotfiles "$user_name" 524263150Sdteske fi 525263150Sdteske 526263150Sdteske f_dialog_title "$title" 527263150Sdteske $alert "$msg_login_added" 528263150Sdteske f_dialog_title_restore 529263150Sdteske [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1 530263150Sdteske 531263150Sdteske return $SUCCESS 532263150Sdteske} 533263150Sdteske 534263150Sdteske# f_user_delete [$user] 535263150Sdteske# 536263150Sdteske# Delete a user. If both $user (as a first argument) and $VAR_USER are unset or 537263150Sdteske# NULL and we are running interactively, prompt the end-user to select a user 538263150Sdteske# account from a list of those available. Variables that can be used to script 539263150Sdteske# user input: 540263150Sdteske# 541263150Sdteske# VAR_USER [Optional if running interactively] 542263150Sdteske# The user to delete. Ignored if given non-NULL first-argument. 543263150Sdteske# 544263150Sdteske# Returns success if the user account was successfully deleted. 545263150Sdteske# 546263150Sdteskef_user_delete() 547263150Sdteske{ 548263150Sdteske local funcname=f_user_delete 549263150Sdteske local title # Calculated below 550263150Sdteske local alert=f_show_msg no_confirm= 551263150Sdteske 552263150Sdteske f_getvar $VAR_NO_CONFIRM no_confirm 553263150Sdteske [ "$no_confirm" ] && alert=f_show_info 554263150Sdteske 555263150Sdteske local input 556263150Sdteske f_getvar 3:-\$$VAR_USER input "$1" 557263150Sdteske 558263150Sdteske if f_interactive && [ ! "$input" ]; then 559263150Sdteske f_dialog_menu_user_list || return $SUCCESS 560263150Sdteske f_dialog_menutag_fetch input 561263150Sdteske [ "$input" = "X $msg_exit" ] && return $SUCCESS 562263150Sdteske elif [ ! "$input" ]; then 563263150Sdteske f_show_err "$msg_no_user_specified" 564263150Sdteske return $FAILURE 565263150Sdteske fi 566263150Sdteske 567263150Sdteske local user_account_expire user_class user_gecos user_gid user_home_dir 568263150Sdteske local user_member_groups user_name user_password user_password_expire 569263150Sdteske local user_shell user_uid # Variables created by f_input_user() below 570263150Sdteske if [ "$input" ] && ! f_input_user "$input"; then 571263150Sdteske f_show_err "$msg_login_not_found" "$input" 572263150Sdteske return $FAILURE 573263150Sdteske fi 574263150Sdteske 575263150Sdteske local user_group_delete= user_home_delete= 576263150Sdteske f_getvar $VAR_USER_GROUP_DELETE:-\$msg_no user_group_delete 577263150Sdteske f_getvar $VAR_USER_HOME_DELETE:-\$msg_no user_home_delete 578263150Sdteske 579263150Sdteske # Attempt to translate user GID into a group name 580263150Sdteske local user_group 581263150Sdteske if user_group=$( pw groupshow -g "$user_gid" 2> /dev/null ); then 582263150Sdteske user_group="${user_group%%:*}" 583263150Sdteske # Default to delete the primary group if no script-override and 584263150Sdteske # exists with same name as the user (same logic used by pw(8)) 585263150Sdteske f_isset $VAR_USER_GROUP_DELETE || 586263150Sdteske [ "$user_group" != "$user_name" ] || 587263150Sdteske user_group_delete="$msg_yes" 588263150Sdteske fi 589263150Sdteske 590263150Sdteske # 591263150Sdteske # Loop until the user decides to Exit, Cancel, or presses ESC 592263150Sdteske # 593263150Sdteske title="$msg_delete $msg_user: $user_name" 594263150Sdteske if f_interactive; then 595263150Sdteske local mtag retval defaultitem= 596263150Sdteske while :; do 597263150Sdteske f_dialog_title "$title" 598263150Sdteske f_dialog_menu_user_delete "$user_name" "$defaultitem" 599263150Sdteske retval=$? 600263150Sdteske f_dialog_title_restore 601263150Sdteske f_dialog_menutag_fetch mtag 602263150Sdteske f_dprintf "retval=%u mtag=[%s]" $retval "$mtag" 603263150Sdteske defaultitem="$mtag" 604263150Sdteske 605263150Sdteske # Return if user either pressed ESC or chose Cancel/No 606263150Sdteske [ $retval -eq $DIALOG_OK ] || return $FAILURE 607263150Sdteske 608263150Sdteske case "$mtag" in 609263150Sdteske X) # Delete/Exit 610263150Sdteske f_shell_escape "$user_uid" _user_uid 611263150Sdteske 612263150Sdteske # Save group information in case pw(8) deletes it 613263150Sdteske # and we wanted to keep it (to be restored below) 614263150Sdteske if [ "${user_group_delete:-$msg_no}" = "$msg_no" ] 615263150Sdteske then 616263150Sdteske local v vars="gid members name password" 617263150Sdteske for v in $vars; do local group_$var; done 618263150Sdteske f_input_group "$user_group" 619263150Sdteske 620263150Sdteske # Remove user-to-delete from group members 621263150Sdteske # NB: Otherwise group restoration could fail 622263150Sdteske local name length=0 _members= 623263150Sdteske while [ $length -ne ${#group_members} ]; do 624263150Sdteske name="${group_members%%,*}" 625263150Sdteske [ "$name" != "$user_name" ] && 626263150Sdteske _members="$_members,$name" 627263150Sdteske length=${#group_members} 628263150Sdteske group_members="${group_members#*,}" 629263150Sdteske done 630263150Sdteske group_members="${_members#,}" 631263150Sdteske 632263150Sdteske # Create escaped variables for f_eval_catch() 633263150Sdteske for v in $vars; do 634263150Sdteske local _group_$v 635263150Sdteske eval f_shell_escape \ 636263150Sdteske \"\$group_$v\" _group_$v 637263150Sdteske done 638263150Sdteske fi 639263150Sdteske 640263150Sdteske # Delete the user (if asked to delete home directory 641263150Sdteske # display [X]dialog notification to show activity) 642263150Sdteske local cmd="pw userdel -u '$_user_uid'" 643263150Sdteske if [ "$user_home_delete" = "$msg_yes" -a \ 644263150Sdteske "$USE_XDIALOG" ] 645263150Sdteske then 646263150Sdteske local err 647263150Sdteske err=$( 648263150Sdteske exec 9>&1 649263150Sdteske f_eval_catch -e $funcname pw \ 650263150Sdteske "%s -r" "$cmd" \ 651263150Sdteske >&$DIALOG_TERMINAL_PASSTHRU_FD 2>&9 | 652263150Sdteske f_xdialog_info \ 653263150Sdteske "$msg_deleting_home_directory" 654263150Sdteske ) 655263150Sdteske [ ! "$err" ] 656263150Sdteske elif [ "$user_home_delete" = "$msg_yes" ]; then 657263150Sdteske f_dialog_info "$msg_deleting_home_directory" 658263150Sdteske f_eval_catch $funcname pw '%s -r' "$cmd" 659263150Sdteske else 660263150Sdteske f_eval_catch $funcname pw '%s' "$cmd" 661263150Sdteske fi || continue 662263150Sdteske 663263150Sdteske # 664263150Sdteske # pw(8) may conditionally delete the primary group, 665263150Sdteske # which may not be what is desired. 666263150Sdteske # 667263150Sdteske # If we've been asked to delete the group and pw(8) 668263150Sdteske # chose not to, delete it. Otherwise, if we're told 669263150Sdteske # to NOT delete the group, we may need to restore it 670263150Sdteske # since pw(8) doesn't have a flag to tell `userdel' 671263150Sdteske # to not delete the group. 672263150Sdteske # 673263150Sdteske # NB: If primary group and user have different names 674263150Sdteske # the group may not have been deleted (again, see PR 675263150Sdteske # 169471 and SVN r263114 for details). 676263150Sdteske # 677263150Sdteske if [ "${user_group_delete:-$msg_no}" != "$msg_no" ] 678263150Sdteske then 679263150Sdteske f_quietly pw groupshow -g "$user_gid" && 680263150Sdteske f_eval_catch $funcname pw \ 681263150Sdteske "pw groupdel -g '%s'" "$_user_gid" 682263150Sdteske elif ! f_quietly pw groupshow -g "$group_gid" && 683263150Sdteske [ "$group_name" -a "$group_gid" ] 684263150Sdteske then 685263150Sdteske # Group deleted by pw(8), so restore it 686263150Sdteske local cmd="pw groupadd -n '$_group_name'" 687263150Sdteske cmd="$cmd -g '$_group_gid'" 688263150Sdteske cmd="$cmd -M '$_group_members'" 689263150Sdteske 690263150Sdteske # Get the group password (pw(8) groupshow does 691263150Sdteske # NOT provide this (even if running privileged) 692263150Sdteske local group_password_enc 693263150Sdteske group_password_enc=$( getent group | awk -F: ' 694263150Sdteske !/^[[:space:]]*(#|$)/ && \ 695263150Sdteske $1 == ENVIRON["group_name"] && \ 696263150Sdteske $3 == ENVIRON["group_gid"] && \ 697263150Sdteske $4 == ENVIRON["group_members"] \ 698263150Sdteske { print $2; exit } 699263150Sdteske ' ) 700263150Sdteske if [ "$group_password_enc" ]; then 701263150Sdteske echo "$group_password_enc" | 702263150Sdteske f_eval_catch $funcname \ 703263150Sdteske pw '%s -H 0' "$cmd" 704263150Sdteske else 705263150Sdteske f_eval_catch $funcname \ 706263150Sdteske pw '%s -h -' "$cmd" 707263150Sdteske fi 708263150Sdteske fi 709263150Sdteske 710263150Sdteske break # to success 711263150Sdteske ;; 712263150Sdteske 1) # Login (select different login from list) 713263150Sdteske f_dialog_menu_user_list "$user_name" || continue 714263150Sdteske f_dialog_menutag_fetch mtag 715263150Sdteske 716263150Sdteske [ "$mtag" = "X $msg_exit" ] && continue 717263150Sdteske 718263150Sdteske if ! f_input_user "$mtag"; then 719263150Sdteske f_show_err "$msg_login_not_found" "$mtag" 720263150Sdteske # Attempt to fall back to previous selection 721263150Sdteske f_input_user "$input" || return $FAILURE 722263150Sdteske else 723263150Sdteske input="$mtag" 724263150Sdteske fi 725263150Sdteske title="$msg_delete $msg_user: $user_name" 726263150Sdteske ;; 727263150Sdteske C) # Delete Primary Group? 728263150Sdteske if [ "${user_group_delete:-$msg_no}" != "$msg_no" ] 729263150Sdteske then 730263150Sdteske user_group_delete="$msg_no" 731263150Sdteske else 732263150Sdteske user_group_delete="$msg_yes" 733263150Sdteske fi ;; 734263150Sdteske D) # Delete Home Directory? 735263150Sdteske if [ "${user_home_delete:-$msg_no}" != "$msg_no" ] 736263150Sdteske then 737263150Sdteske user_home_delete="$msg_no" 738263150Sdteske else 739263150Sdteske user_home_delete="$msg_yes" 740263150Sdteske fi ;; 741263150Sdteske esac 742263150Sdteske done 743263150Sdteske else 744263150Sdteske f_shell_escape "$user_uid" _user_uid 745263150Sdteske 746263150Sdteske # Save group information in case pw(8) deletes it 747263150Sdteske # and we wanted to keep it (to be restored below) 748263150Sdteske if [ "${user_group_delete:-$msg_no}" = "$msg_no" ]; then 749263150Sdteske local v vars="gid members name password" 750263150Sdteske for v in $vars; do local group_$v; done 751263150Sdteske f_input_group "$user_group" 752263150Sdteske 753263150Sdteske # Remove user we're about to delete from group members 754263150Sdteske # NB: Otherwise group restoration could fail 755263150Sdteske local name length=0 _members= 756263150Sdteske while [ $length -ne ${#group_members} ]; do 757263150Sdteske name="${group_members%%,*}" 758263150Sdteske [ "$name" != "$user_name" ] && 759263150Sdteske _members="$_members,$name" 760263150Sdteske length=${#group_members} 761263150Sdteske group_members="${group_members#*,}" 762263150Sdteske done 763263150Sdteske group_members="${_members#,}" 764263150Sdteske 765263150Sdteske # Create escaped variables for later f_eval_catch() 766263150Sdteske for v in $vars; do 767263150Sdteske local _group_$v 768263150Sdteske eval f_shell_escape \"\$group_$v\" _group_$v 769263150Sdteske done 770263150Sdteske fi 771263150Sdteske 772263150Sdteske # Delete the user (if asked to delete home directory 773263150Sdteske # display [X]dialog notification to show activity) 774263150Sdteske local err cmd="pw userdel -u '$_user_uid'" 775263150Sdteske if [ "$user_home_delete" = "$msg_yes" -a "$USE_XDIALOG" ]; then 776263150Sdteske err=$( 777263150Sdteske exec 9>&1 778263150Sdteske f_eval_catch -de $funcname pw \ 779263150Sdteske '%s -r' "$cmd" 2>&9 | f_xdialog_info \ 780263150Sdteske "$msg_deleting_home_directory" 781263150Sdteske ) 782263150Sdteske [ ! "$err" ] 783263150Sdteske elif [ "$user_home_delete" = "$msg_yes" ]; then 784263150Sdteske f_dialog_info "$msg_deleting_home_directory" 785263150Sdteske f_eval_catch -k err $funcname pw '%s -r' "$cmd" 786263150Sdteske else 787263150Sdteske f_eval_catch -k err $funcname pw '%s' "$cmd" 788263150Sdteske fi 789263150Sdteske local retval=$? 790263150Sdteske if [ $retval -ne $SUCCESS ]; then 791263150Sdteske f_show_err "%s" "$err" 792263150Sdteske return $retval 793263150Sdteske fi 794263150Sdteske 795263150Sdteske # 796263150Sdteske # pw(8) may conditionally delete the primary group, which may 797263150Sdteske # not be what is desired. 798263150Sdteske # 799263150Sdteske # If we've been asked to delete the group and pw(8) chose not 800263150Sdteske # to, delete it. Otherwise, if we're told to NOT delete the 801263150Sdteske # group, we may need to restore it since pw(8) doesn't have a 802263150Sdteske # flag to tell `userdel' to not delete the group. 803263150Sdteske # 804263150Sdteske # NB: If primary group and user have different names the group 805263150Sdteske # may not have been deleted (again, see PR 169471 and SVN 806263150Sdteske # r263114 for details). 807263150Sdteske # 808263150Sdteske if [ "${user_group_delete:-$msg_no}" != "$msg_no" ] 809263150Sdteske then 810263150Sdteske f_quietly pw groupshow -g "$user_gid" && 811263150Sdteske f_eval_catch $funcname pw \ 812263150Sdteske "pw groupdel -g '%s'" "$_user_gid" 813263150Sdteske elif ! f_quietly pw groupshow -g "$group_gid" && 814263150Sdteske [ "$group_name" -a "$group_gid" ] 815263150Sdteske then 816263150Sdteske # Group deleted by pw(8), so restore it 817263150Sdteske local cmd="pw groupadd -n '$_group_name'" 818263150Sdteske cmd="$cmd -g '$_group_gid'" 819263150Sdteske cmd="$cmd -M '$_group_members'" 820263150Sdteske local group_password_enc 821263150Sdteske group_password_enc=$( getent group | awk -F: ' 822263150Sdteske !/^[[:space:]]*(#|$)/ && \ 823263150Sdteske $1 == ENVIRON["group_name"] && \ 824263150Sdteske $3 == ENVIRON["group_gid"] && \ 825263150Sdteske $4 == ENVIRON["group_members"] \ 826263150Sdteske { print $2; exit } 827263150Sdteske ' ) 828263150Sdteske if [ "$group_password_enc" ]; then 829263150Sdteske echo "$group_password_enc" | 830263150Sdteske f_eval_catch $funcname \ 831263150Sdteske pw '%s -H 0' "$cmd" 832263150Sdteske else 833263150Sdteske f_eval_catch $funcname \ 834263150Sdteske pw '%s -h -' "$cmd" 835263150Sdteske fi 836263150Sdteske fi 837263150Sdteske fi 838263150Sdteske 839263150Sdteske f_dialog_title "$title" 840263150Sdteske $alert "$msg_login_deleted" 841263150Sdteske f_dialog_title_restore 842263150Sdteske [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1 843263150Sdteske 844263150Sdteske return $SUCCESS 845263150Sdteske} 846263150Sdteske 847263150Sdteske# f_user_edit [$user] 848263150Sdteske# 849263150Sdteske# Modify a login account. If both $user (as a first argument) and $VAR_USER are 850263150Sdteske# unset or NULL and we are running interactively, prompt the end-user to select 851263150Sdteske# a login account from a list of those available. Variables that can be used to 852263150Sdteske# script user input: 853263150Sdteske# 854263150Sdteske# VAR_USER [Optional if running interactively] 855263150Sdteske# The login to modify. Ignored if given non-NULL first-argument. 856263150Sdteske# VAR_USER_ACCOUNT_EXPIRE [Optional] 857263150Sdteske# The account expiration time. Format is similar to 858263150Sdteske# VAR_USER_PASSWORD_EXPIRE variable below. If unset, account 859263150Sdteske# expiry is unchanged. If set but NULL, account expiration is 860263150Sdteske# disabled (same as setting a value of `0'). 861263150Sdteske# VAR_USER_DOTFILES_CREATE [Optional] 862263150Sdteske# If non-NULL, re-populate the user's home directory with the 863263150Sdteske# template files found in $udotdir (`/usr/share/skel' default). 864263150Sdteske# VAR_USER_GECOS [Optional] 865263150Sdteske# Often the full name of the account holder. If unset, the GECOS 866263150Sdteske# field is unmodified. If set but NULL, the field is blanked. 867263150Sdteske# VAR_USER_GID [Optional] 868263150Sdteske# Numerical primary-group ID to set. If NULL or unset, the group 869263150Sdteske# ID is unchanged. 870263150Sdteske# VAR_USER_GROUPS [Optional] 871263150Sdteske# Comma-separated list of additional groups to which the user is 872263150Sdteske# a member of. If set but NULL, group memberships are reset (this 873263150Sdteske# login will not be a member of any additional groups besides the 874263150Sdteske# primary group). If unset, group membership is unmodified. 875263150Sdteske# VAR_USER_HOME [Optional] 876263150Sdteske# The home directory to set. If NULL or unset, the home directory 877263150Sdteske# is unchanged. 878263150Sdteske# VAR_USER_HOME_CREATE [Optional] 879263150Sdteske# If non-NULL, create the user's home directory if it doesn't 880263150Sdteske# already exist. 881263150Sdteske# VAR_USER_LOGIN_CLASS [Optional] 882263150Sdteske# Login class to set. If unset, the login class is unchanged. If 883263150Sdteske# set but NULL, the field is blanked. 884263150Sdteske# VAR_USER_PASSWORD [Optional] 885263150Sdteske# Unencrypted password to set. If unset, the login password is 886263150Sdteske# unmodified. If set but NULL, password authentication for the 887263150Sdteske# login is disabled. 888263150Sdteske# VAR_USER_PASSWORD_EXPIRE [Optional] 889263150Sdteske# The password expiration time. Format of the date is either a 890263150Sdteske# UNIX time in decimal, or a date in dd-mmm-yy[yy] format, where 891263150Sdteske# dd is the day, mmm is the month in either numeric or alphabetic 892263150Sdteske# format, and yy[yy] is either a two or four digit year. This 893263150Sdteske# variable also accepts a relative date in the form of +n[mhdwoy] 894263150Sdteske# where n is a decimal, octal (leading 0) or hexadecimal (leading 895263150Sdteske# 0x) digit followed by the number of Minutes, Hours, Days, 896263150Sdteske# Weeks, Months or Years from the current date at which the 897263150Sdteske# expiration time is to be set. If unset, password expiry is 898263150Sdteske# unchanged. If set but NULL, password expiration is disabled 899263150Sdteske# (same as setting a value of `0'). 900263150Sdteske# VAR_USER_SHELL [Optional] 901263150Sdteske# Path to login shell to set. If NULL or unset, the shell is 902263150Sdteske# unchanged. 903263150Sdteske# VAR_USER_UID [Optional] 904263150Sdteske# Numerical user ID to set. If NULL or unset, the user ID is 905263150Sdteske# unchanged. 906263150Sdteske# 907263150Sdteske# Returns success if the user account was successfully modified. 908263150Sdteske# 909263150Sdteskef_user_edit() 910263150Sdteske{ 911263150Sdteske local funcname=f_user_edit 912263150Sdteske local title # Calculated below 913263150Sdteske local alert=f_show_msg no_confirm= 914263150Sdteske 915263150Sdteske f_getvar $VAR_NO_CONFIRM no_confirm 916263150Sdteske [ "$no_confirm" ] && alert=f_show_info 917263150Sdteske 918263150Sdteske local input 919263150Sdteske f_getvar 3:-\$$VAR_USER input "$1" 920263150Sdteske 921263150Sdteske # 922263150Sdteske # NB: pw(8) has a ``feature'' wherein `-n name' can be taken as UID 923263150Sdteske # instead of name. Work-around is to also pass `-u UID' at the same 924263150Sdteske # time (any UID will do; but `-1' is appropriate for this context). 925263150Sdteske # 926263150Sdteske if [ "$input" ] && ! f_quietly pw usershow -n "$input" -u -1; then 927263150Sdteske f_show_err "$msg_login_not_found" "$input" 928263150Sdteske return $FAILURE 929263150Sdteske fi 930263150Sdteske 931263150Sdteske if f_interactive && [ ! "$input" ]; then 932263150Sdteske f_dialog_menu_user_list || return $SUCCESS 933263150Sdteske f_dialog_menutag_fetch input 934263150Sdteske [ "$input" = "X $msg_exit" ] && return $SUCCESS 935263150Sdteske elif [ ! "$input" ]; then 936263150Sdteske f_show_err "$msg_no_user_specified" 937263150Sdteske return $FAILURE 938263150Sdteske fi 939263150Sdteske 940263150Sdteske local user_account_expire user_class user_gecos user_gid user_home_dir 941263150Sdteske local user_member_groups user_name user_password user_password_expire 942263150Sdteske local user_shell user_uid # Variables created by f_input_user() below 943263150Sdteske if ! f_input_user "$input"; then 944263150Sdteske f_show_err "$msg_login_not_found" "$input" 945263150Sdteske return $FAILURE 946263150Sdteske fi 947263150Sdteske 948263150Sdteske # 949263150Sdteske # Override values probed by f_input_user() with desired values 950263150Sdteske # 951263150Sdteske f_isset $VAR_USER_GID && f_getvar $VAR_USER_GID user_gid 952263150Sdteske f_isset $VAR_USER_HOME && f_getvar $VAR_USER_HOME user_home_dir 953263150Sdteske f_isset $VAR_USER_SHELL && f_getvar $VAR_USER_SHELL user_shell 954263150Sdteske f_isset $VAR_USER_UID && f_getvar $VAR_USER_UID user_uid 955263150Sdteske local user_dotfiles_create= user_home_create= 956263150Sdteske f_getvar $VAR_USER_DOTFILES_CREATE:+\$msg_yes user_dotfiles_create 957263150Sdteske f_getvar $VAR_USER_HOME_CREATE:+\$msg_yes user_home_create 958263150Sdteske local no_account_expire= 959263150Sdteske if f_isset $VAR_USER_ACCOUNT_EXPIRE; then 960263150Sdteske f_getvar $VAR_USER_ACCOUNT_EXPIRE user_account_expire 961263150Sdteske [ "$user_account_expire" ] || no_account_expire=1 962263150Sdteske fi 963263150Sdteske local null_gecos= 964263150Sdteske if f_isset $VAR_USER_GECOS; then 965263150Sdteske f_getvar $VAR_USER_GECOS user_gecos 966263150Sdteske [ "$user_gecos" ] || null_gecos=1 967263150Sdteske fi 968263150Sdteske local null_members= 969263150Sdteske if f_isset $VAR_USER_GROUPS; then 970263150Sdteske f_getvar $VAR_USER_GROUPS user_member_groups 971263150Sdteske [ "$user_member_groups" ] || null_members=1 972263150Sdteske fi 973263150Sdteske local null_class= 974263150Sdteske if f_isset $VAR_USER_LOGIN_CLASS; then 975263150Sdteske f_getvar $VAR_USER_LOGIN_CLASS user_class 976263150Sdteske [ "$user_class" ] || null_class=1 977263150Sdteske fi 978263150Sdteske local user_password_disable= 979263150Sdteske if f_isset $VAR_USER_PASSWORD; then 980263150Sdteske f_getvar $VAR_USER_PASSWORD user_password 981263150Sdteske [ "$user_password" ] || user_password_disable=1 982263150Sdteske fi 983263150Sdteske local no_password_expire= 984263150Sdteske if f_isset $VAR_USER_PASSWORD_EXPIRE; then 985263150Sdteske f_getvar $VAR_USER_PASSWORD_EXPIRE user_password_expire 986263150Sdteske [ "$user_password_expire" ] || no_password_expire=1 987263150Sdteske fi 988263150Sdteske 989263150Sdteske # 990263150Sdteske # Loop until the user decides to Exit, Cancel, or presses ESC 991263150Sdteske # 992263150Sdteske title="$msg_edit_view $msg_user: $user_name" 993263150Sdteske if f_interactive; then 994263150Sdteske local mtag retval defaultitem= 995263150Sdteske while :; do 996263150Sdteske f_dialog_title "$title" 997263150Sdteske f_dialog_menu_user_edit "$defaultitem" 998263150Sdteske retval=$? 999263150Sdteske f_dialog_title_restore 1000263150Sdteske f_dialog_menutag_fetch mtag 1001263150Sdteske f_dprintf "retval=%u mtag=[%s]" $retval "$mtag" 1002263150Sdteske defaultitem="$mtag" 1003263150Sdteske 1004263150Sdteske # Return if user either pressed ESC or chose Cancel/No 1005263150Sdteske [ $retval -eq $DIALOG_OK ] || return $FAILURE 1006263150Sdteske 1007263150Sdteske case "$mtag" in 1008263150Sdteske X) # Save/Exit 1009263150Sdteske local var 1010263150Sdteske for var in account_expire class gecos gid home_dir \ 1011263150Sdteske member_groups name password_expire shell uid \ 1012263150Sdteske ; do 1013263150Sdteske local _user_$var 1014263150Sdteske eval f_shell_escape \"\$user_$var\" _user_$var 1015263150Sdteske done 1016263150Sdteske 1017263150Sdteske local cmd="pw usermod -n '$_user_name'" 1018263150Sdteske [ "$user_gid" ] && cmd="$cmd -g '$_user_gid'" 1019263150Sdteske [ "$user_shell" ] && cmd="$cmd -s '$_user_shell'" 1020263150Sdteske [ "$user_uid" ] && cmd="$cmd -u '$_user_uid'" 1021263150Sdteske [ "$user_account_expire" -o \ 1022263150Sdteske "$no_account_expire" ] && 1023263150Sdteske cmd="$cmd -e '$_user_account_expire'" 1024263150Sdteske [ "$user_class" -o "$null_class" ] && 1025263150Sdteske cmd="$cmd -L '$_user_class'" 1026263150Sdteske [ "$user_gecos" -o "$null_gecos" ] && 1027263150Sdteske cmd="$cmd -c '$_user_gecos'" 1028263150Sdteske [ "$user_home_dir" ] && 1029263150Sdteske cmd="$cmd -d '$_user_home_dir'" 1030263150Sdteske [ "$user_member_groups" -o "$null_members" ] && 1031263150Sdteske cmd="$cmd -G '$_user_member_groups'" 1032263150Sdteske [ "$user_password_expire" -o \ 1033263150Sdteske "$no_password_expire" ] && 1034263150Sdteske cmd="$cmd -p '$_user_password_expire'" 1035263150Sdteske 1036263150Sdteske # Execute the command 1037263150Sdteske if [ "$user_password_disable" ]; then 1038263150Sdteske f_eval_catch $funcname pw '%s -h -' "$cmd" 1039263150Sdteske elif [ "$user_password" ]; then 1040263150Sdteske echo "$user_password" | f_eval_catch \ 1041263150Sdteske $funcname pw '%s -h 0' "$cmd" 1042263150Sdteske else 1043263150Sdteske f_eval_catch $funcname pw '%s' "$cmd" 1044263150Sdteske fi || continue 1045263150Sdteske 1046263150Sdteske # Create home directory if desired 1047263150Sdteske [ "${user_home_create:-$msg_no}" != "$msg_no" ] && 1048263150Sdteske f_user_create_homedir "$user_name" 1049263150Sdteske 1050263150Sdteske # Copy dotfiles if desired 1051263150Sdteske [ "${user_dotfiles_create:-$msg_no}" != \ 1052263150Sdteske "$msg_no" ] && f_user_copy_dotfiles "$user_name" 1053263150Sdteske 1054263150Sdteske break # to success 1055263150Sdteske ;; 1056263150Sdteske 1) # Login (select different login from list) 1057263150Sdteske f_dialog_menu_user_list "$user_name" || continue 1058263150Sdteske f_dialog_menutag_fetch mtag 1059263150Sdteske 1060263150Sdteske [ "$mtag" = "X $msg_exit" ] && continue 1061263150Sdteske 1062263150Sdteske if ! f_input_user "$mtag"; then 1063263150Sdteske f_show_err "$msg_login_not_found" "$mtag" 1064263150Sdteske # Attempt to fall back to previous selection 1065263150Sdteske f_input_user "$input" || return $FAILURE 1066263150Sdteske else 1067263150Sdteske input="$mtag" 1068263150Sdteske fi 1069263150Sdteske title="$msg_edit_view $msg_user: $user_name" 1070263150Sdteske ;; 1071263150Sdteske 2) # Full Name 1072263150Sdteske f_dialog_input_gecos user_gecos "$user_gecos" && 1073263150Sdteske [ ! "$user_gecos" ] && null_gecos=1 ;; 1074263150Sdteske 3) # Password 1075263150Sdteske f_dialog_input_password \ 1076263150Sdteske user_password user_password_disable ;; 1077263150Sdteske 4) # User ID 1078263150Sdteske f_dialog_input_uid user_uid "$user_uid" ;; 1079263150Sdteske 5) # Group ID 1080263150Sdteske f_dialog_input_gid user_gid "$user_gid" ;; 1081263150Sdteske 6) # Member of Groups 1082263150Sdteske f_dialog_input_member_groups \ 1083263150Sdteske user_member_groups "$user_member_groups" && 1084263150Sdteske [ ! "$user_member_groups" ] && 1085263150Sdteske null_members=1 ;; 1086263150Sdteske 7) # Login Class 1087263150Sdteske f_dialog_input_class user_class "$user_class" && 1088263150Sdteske [ ! "$user_class" ] && null_class=1 ;; 1089263150Sdteske 8) # Password Expires On 1090263150Sdteske f_dialog_input_expire_password \ 1091263150Sdteske user_password_expire "$user_password_expire" && 1092263150Sdteske [ ! "$user_password_expire" ] && 1093263150Sdteske no_password_expire=1 ;; 1094263150Sdteske 9) # Account Expires On 1095263150Sdteske f_dialog_input_expire_account \ 1096263150Sdteske user_account_expire "$user_account_expire" && 1097263150Sdteske [ ! "$user_account_expire" ] && 1098263150Sdteske no_account_expire=1 ;; 1099263150Sdteske A) # Home Directory 1100263150Sdteske f_dialog_input_home_dir \ 1101263150Sdteske user_home_dir "$user_home_dir" ;; 1102263150Sdteske B) # Shell 1103263150Sdteske f_dialog_input_shell user_shell "$user_shell" ;; 1104263150Sdteske C) # Create Home Directory? 1105263150Sdteske if [ "${user_home_create:-$msg_no}" != "$msg_no" ] 1106263150Sdteske then 1107263150Sdteske user_home_create="$msg_no" 1108263150Sdteske else 1109263150Sdteske user_home_create="$msg_yes" 1110263150Sdteske fi ;; 1111263150Sdteske D) # Create Dotfiles? 1112263150Sdteske if [ "${user_dotfiles_create:-$msg_no}" != \ 1113263150Sdteske "$msg_no" ] 1114263150Sdteske then 1115263150Sdteske user_dotfiles_create="$msg_no" 1116263150Sdteske else 1117263150Sdteske user_dotfiles_create="$msg_yes" 1118263150Sdteske fi ;; 1119263150Sdteske esac 1120263150Sdteske done 1121263150Sdteske else 1122263150Sdteske local var 1123263150Sdteske for var in account_expire class gecos gid home_dir \ 1124263150Sdteske member_groups name password_expire shell uid \ 1125263150Sdteske ; do 1126263150Sdteske local _user_$var 1127263150Sdteske eval f_shell_escape \"\$user_$var\" _user_$var 1128263150Sdteske done 1129263150Sdteske 1130263150Sdteske # Form the command 1131263150Sdteske local cmd="pw usermod -n '$_user_name'" 1132263150Sdteske [ "$user_gid" ] && cmd="$cmd -g '$_user_gid'" 1133263150Sdteske [ "$user_home_dir" ] && cmd="$cmd -d '$_user_home_dir'" 1134263150Sdteske [ "$user_shell" ] && cmd="$cmd -s '$_user_shell'" 1135263150Sdteske [ "$user_uid" ] && cmd="$cmd -u '$_user_uid'" 1136263150Sdteske [ "$user_account_expire" -o "$no_account_expire" ] && 1137263150Sdteske cmd="$cmd -e '$_user_account_expire'" 1138263150Sdteske [ "$user_class" -o "$null_class" ] && 1139263150Sdteske cmd="$cmd -L '$_user_class'" 1140263150Sdteske [ "$user_gecos" -o "$null_gecos" ] && 1141263150Sdteske cmd="$cmd -c '$_user_gecos'" 1142263150Sdteske [ "$user_member_groups" -o "$null_members" ] && 1143263150Sdteske cmd="$cmd -G '$_user_member_groups'" 1144263150Sdteske [ "$user_password_expire" -o "$no_password_expire" ] && 1145263150Sdteske cmd="$cmd -p '$_user_password_expire'" 1146263150Sdteske 1147263150Sdteske # Execute the command 1148263150Sdteske local retval err 1149263150Sdteske if [ "$user_password_disable" ]; then 1150263150Sdteske f_eval_catch -k err $funcname pw '%s -h -' "$cmd" 1151263150Sdteske elif [ "$user_password" ]; then 1152263150Sdteske err=$( echo "$user_password" | f_eval_catch -de \ 1153263150Sdteske $funcname pw '%s -h 0' "$cmd" 2>&1 ) 1154263150Sdteske else 1155263150Sdteske f_eval_catch -k err $funcname pw '%s' "$cmd" 1156263150Sdteske fi 1157263150Sdteske retval=$? 1158263150Sdteske if [ $retval -ne $SUCCESS ]; then 1159263150Sdteske f_show_err "%s" "$err" 1160263150Sdteske return $retval 1161263150Sdteske fi 1162263150Sdteske 1163263150Sdteske # Create home directory if desired 1164263150Sdteske [ "${user_home_create:-$msg_no}" != "$msg_no" ] && 1165263150Sdteske f_user_create_homedir "$user_name" 1166263150Sdteske 1167263150Sdteske # Copy dotfiles if desired 1168263150Sdteske [ "${user_dotfiles_create:-$msg_no}" != "$msg_no" ] && 1169263150Sdteske f_user_copy_dotfiles "$user_name" 1170263150Sdteske fi 1171263150Sdteske 1172263150Sdteske f_dialog_title "$title" 1173263150Sdteske $alert "$msg_login_updated" 1174263150Sdteske f_dialog_title_restore 1175263150Sdteske [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1 1176263150Sdteske 1177263150Sdteske return $SUCCESS 1178263150Sdteske} 1179263150Sdteske 1180263150Sdteske############################################################ MAIN 1181263150Sdteske 1182263150Sdteskef_dprintf "%s: Successfully loaded." usermgmt/user.subr 1183263150Sdteske 1184263150Sdteskefi # ! $_USERMGMT_USER_SUBR 1185