xref: /freebsd/usr.sbin/bsdconfig/usermgmt/share/user.subr (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1f589320aSDevin Teskeif [ ! "$_USERMGMT_USER_SUBR" ]; then _USERMGMT_USER_SUBR=1
2f589320aSDevin Teske#
3f589320aSDevin Teske# Copyright (c) 2012 Ron McDowell
435994c42SDevin Teske# Copyright (c) 2012-2015 Devin Teske
5f589320aSDevin Teske# All rights reserved.
6f589320aSDevin Teske#
7f589320aSDevin Teske# Redistribution and use in source and binary forms, with or without
8f589320aSDevin Teske# modification, are permitted provided that the following conditions
9f589320aSDevin Teske# are met:
10f589320aSDevin Teske# 1. Redistributions of source code must retain the above copyright
11f589320aSDevin Teske#    notice, this list of conditions and the following disclaimer.
12f589320aSDevin Teske# 2. Redistributions in binary form must reproduce the above copyright
13f589320aSDevin Teske#    notice, this list of conditions and the following disclaimer in the
14f589320aSDevin Teske#    documentation and/or other materials provided with the distribution.
15f589320aSDevin Teske#
16f589320aSDevin Teske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f589320aSDevin Teske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f589320aSDevin Teske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f589320aSDevin Teske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f589320aSDevin Teske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f589320aSDevin Teske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f589320aSDevin Teske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f589320aSDevin Teske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f589320aSDevin Teske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f589320aSDevin Teske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f589320aSDevin Teske# SUCH DAMAGE.
27f589320aSDevin Teske#
28f589320aSDevin Teske#
29f589320aSDevin Teske############################################################ INCLUDES
30f589320aSDevin Teske
31f589320aSDevin TeskeBSDCFG_SHARE="/usr/share/bsdconfig"
32f589320aSDevin Teske. $BSDCFG_SHARE/common.subr || exit 1
33f589320aSDevin Teskef_dprintf "%s: loading includes..." usermgmt/user.subr
34f589320aSDevin Teskef_include $BSDCFG_SHARE/dialog.subr
35f589320aSDevin Teskef_include $BSDCFG_SHARE/strings.subr
36f589320aSDevin Teskef_include $BSDCFG_SHARE/usermgmt/group_input.subr
37f589320aSDevin Teskef_include $BSDCFG_SHARE/usermgmt/user_input.subr
38f589320aSDevin Teske
39f589320aSDevin TeskeBSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
40f589320aSDevin Teskef_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
41f589320aSDevin Teske
42f589320aSDevin Teske############################################################ CONFIGURATION
43f589320aSDevin Teske
44f589320aSDevin Teske# set some reasonable defaults if /etc/adduser.conf does not exist.
45f589320aSDevin Teske[ -f /etc/adduser.conf ] && f_include /etc/adduser.conf
46f589320aSDevin Teske: ${defaultclass:=""}
47f589320aSDevin Teske: ${defaultshell:="/bin/sh"}
48f589320aSDevin Teske: ${homeprefix:="/home"}
49f589320aSDevin Teske: ${passwdtype:="yes"}
50f589320aSDevin Teske: ${udotdir:="/usr/share/skel"}
51f589320aSDevin Teske: ${uexpire:=""}
52f589320aSDevin Teske	# Default account expire time. Format is similar to upwexpire variable.
53f589320aSDevin Teske: ${ugecos:="User &"}
54f589320aSDevin Teske: ${upwexpire:=""}
55f589320aSDevin Teske	# The default password expiration time. Format of the date is either a
56f589320aSDevin Teske	# UNIX time in decimal, or a date in dd-mmm-yy[yy] format, where dd is
57f589320aSDevin Teske	# the day, mmm is the month in either numeric or alphabetic format, and
58f589320aSDevin Teske	# yy[yy] is either a two or four digit year. This variable also accepts
59f589320aSDevin Teske	# a relative date in the form of n[mhdwoy] where n is a decimal, octal
60f589320aSDevin Teske	# (leading 0) or hexadecimal (leading 0x) digit followed by the number
61f589320aSDevin Teske	# of Minutes, Hours, Days, Weeks, Months or Years from the current date
62f589320aSDevin Teske	# at which the expiration time is to be set.
63f589320aSDevin Teske
64f589320aSDevin Teske#
65f589320aSDevin Teske# uexpire and upwexpire from adduser.conf(5) differ only slightly from what
66f589320aSDevin Teske# pw(8) accepts as `date' argument(s); pw(8) requires a leading `+' for the
67f589320aSDevin Teske# relative date syntax (n[mhdwoy]).
68f589320aSDevin Teske#
69f589320aSDevin Teskecase "$uexpire" in *[mhdwoy])
70f589320aSDevin Teske	f_isinteger "${uexpire%[mhdwoy]}" && uexpire="+$uexpire"
71f589320aSDevin Teskeesac
72f589320aSDevin Teskecase "$upwexpire" in *[mhdwoy])
73f589320aSDevin Teske	f_isinteger "${upwexpire%[mhdwoy]}" && upwexpire="+$upwexpire"
74f589320aSDevin Teskeesac
75f589320aSDevin Teske
76f589320aSDevin Teske############################################################ FUNCTIONS
77f589320aSDevin Teske
78f589320aSDevin Teske# f_user_create_homedir $user
79f589320aSDevin Teske#
80f589320aSDevin Teske# Create home directory for $user.
81f589320aSDevin Teske#
82f589320aSDevin Teskef_user_create_homedir()
83f589320aSDevin Teske{
84f589320aSDevin Teske	local funcname=f_user_create_homedir
85f589320aSDevin Teske	local user="$1"
86f589320aSDevin Teske
87f589320aSDevin Teske	[ "$user" ] || return $FAILURE
88f589320aSDevin Teske
89f589320aSDevin Teske	local user_account_expire user_class user_gecos user_gid user_home_dir
90f589320aSDevin Teske	local user_member_groups user_name user_password user_password_expire
91f589320aSDevin Teske	local user_shell user_uid # Variables created by f_input_user() below
92f589320aSDevin Teske	f_input_user "$user" || return $FAILURE
93f589320aSDevin Teske
94f589320aSDevin Teske	f_dprintf "Creating home directory \`%s' for user \`%s'" \
95f589320aSDevin Teske	          "$user_home_dir" "$user"
96f589320aSDevin Teske
97f589320aSDevin Teske	local _user_gid _user_home_dir _user_uid
98f589320aSDevin Teske	f_shell_escape "$user_gid"      _user_gid
99f589320aSDevin Teske	f_shell_escape "$user_home_dir" _user_home_dir
100f589320aSDevin Teske	f_shell_escape "$user_uid"      _user_uid
101f589320aSDevin Teske	f_eval_catch $funcname mkdir "mkdir -p '%s'" "$_user_home_dir" ||
102f589320aSDevin Teske		return $FAILURE
103f589320aSDevin Teske	f_eval_catch $funcname chown "chown '%i:%i' '%s'" \
104f589320aSDevin Teske		"$_user_uid" "$_user_gid" "$_user_home_dir" || return $FAILURE
105f589320aSDevin Teske}
106f589320aSDevin Teske
107f589320aSDevin Teske# f_user_copy_dotfiles $user
108f589320aSDevin Teske#
109f589320aSDevin Teske# Copy `skel' dot-files from $udotdir (global inherited from /etc/adduser.conf)
110f589320aSDevin Teske# to the home-directory of $user. Attempts to create the home-directory first
111f589320aSDevin Teske# if it doesn't exist.
112f589320aSDevin Teske#
113f589320aSDevin Teskef_user_copy_dotfiles()
114f589320aSDevin Teske{
115f589320aSDevin Teske	local funcname=f_user_copy_dotfiles
116f589320aSDevin Teske	local user="$1"
117f589320aSDevin Teske
118f589320aSDevin Teske	[ "$udotdir" ] || return $FAILURE
119f589320aSDevin Teske	[ "$user"    ] || return $FAILURE
120f589320aSDevin Teske
121f589320aSDevin Teske	local user_account_expire user_class user_gecos user_gid user_home_dir
122f589320aSDevin Teske	local user_member_groups user_name user_password user_password_expire
123f589320aSDevin Teske	local user_shell user_uid # Variables created by f_input_user() below
124f589320aSDevin Teske	f_input_user "$user" || return $FAILURE
125f589320aSDevin Teske
126f589320aSDevin Teske	f_dprintf "Copying dot-files from \`%s' to \`%s'" \
127f589320aSDevin Teske	          "$udotdir" "$user_home_dir"
128f589320aSDevin Teske
129f589320aSDevin Teske	# Attempt to create the home directory if it doesn't exist
130f589320aSDevin Teske	[ -d "$user_home_dir" ] ||
131f589320aSDevin Teske		f_user_create_homedir "$user" || return $FAILURE
132f589320aSDevin Teske
133f589320aSDevin Teske	local _user_gid _user_home_dir _user_uid
134f589320aSDevin Teske	f_shell_escape "$user_gid"      _user_gid
135f589320aSDevin Teske	f_shell_escape "$user_home_dir" _user_home_dir
136f589320aSDevin Teske	f_shell_escape "$user_uid"      _user_uid
137f589320aSDevin Teske
138f589320aSDevin Teske	local - # Localize `set' to this function
139f589320aSDevin Teske	set +f # Enable glob pattern-matching for paths
140f589320aSDevin Teske	cd "$udotdir" || return $FAILURE
141f589320aSDevin Teske
142f589320aSDevin Teske	local _file file retval
143f589320aSDevin Teske	for file in dot.*; do
144f589320aSDevin Teske		[ -e "$file" ] || continue # no-match
145f589320aSDevin Teske
146f589320aSDevin Teske		f_shell_escape "$file" "_file"
147f589320aSDevin Teske		f_eval_catch $funcname cp "cp -n '%s' '%s'" \
148f589320aSDevin Teske			"$_file" "$_user_home_dir/${_file#dot}"
149f589320aSDevin Teske		retval=$?
150f589320aSDevin Teske		[ $retval -eq $SUCCESS ] || break
151f589320aSDevin Teske		f_eval_catch $funcname chown \
152f589320aSDevin Teske			"chown -h '%i:%i' '%s'" \
153f589320aSDevin Teske			"$_user_uid" "$_user_gid" \
154f589320aSDevin Teske			"$_user_home_dir/${_file#dot}"
155f589320aSDevin Teske		retval=$?
156f589320aSDevin Teske		[ $retval -eq $SUCCESS ] || break
157f589320aSDevin Teske	done
158f589320aSDevin Teske
159f589320aSDevin Teske	cd -
160f589320aSDevin Teske	return $retval
161f589320aSDevin Teske}
162f589320aSDevin Teske
163f589320aSDevin Teske# f_user_add [$user]
164f589320aSDevin Teske#
165f589320aSDevin Teske# Create a login account. If both $user (as a first argument) and $VAR_USER are
166f589320aSDevin Teske# unset or NULL and we are running interactively, prompt the end-user to enter
167f589320aSDevin Teske# the name of a new login account and (if $VAR_NO_CONFIRM is unset or NULL)
168f589320aSDevin Teske# prompt the end-user to answer some questions about the new account. Variables
169f589320aSDevin Teske# that can be used to script user input:
170f589320aSDevin Teske#
171f589320aSDevin Teske# 	VAR_USER [Optional if running interactively]
172f589320aSDevin Teske# 		The login to add. Ignored if given non-NULL first-argument.
173f589320aSDevin Teske# 	VAR_USER_ACCOUNT_EXPIRE [Optional]
174f589320aSDevin Teske# 		The account expiration time. Format is similar to
175f589320aSDevin Teske# 		VAR_USER_PASSWORD_EXPIRE variable below. Default is to never
176f589320aSDevin Teske# 		expire the account.
177f589320aSDevin Teske# 	VAR_USER_DOTFILES_CREATE [Optional]
178f589320aSDevin Teske# 		If non-NULL, populate the user's home directory with the
179f589320aSDevin Teske# 		template files found in $udotdir (`/usr/share/skel' default).
180f589320aSDevin Teske# 	VAR_USER_GECOS [Optional]
181f589320aSDevin Teske# 		Often the full name of the account holder. Default is NULL.
182f589320aSDevin Teske# 	VAR_USER_GID [Optional]
183f589320aSDevin Teske# 		Numerical primary-group ID to use. If NULL or unset, the group
184f589320aSDevin Teske# 		ID is automatically chosen.
185f589320aSDevin Teske# 	VAR_USER_GROUPS [Optional]
186f589320aSDevin Teske# 		Comma-separated list of additional groups to which the user is
187f589320aSDevin Teske# 		a member of. Default is NULL (no additional groups).
188f589320aSDevin Teske# 	VAR_USER_HOME [Optional]
189f589320aSDevin Teske# 		The home directory to set. If NULL or unset, the home directory
190f589320aSDevin Teske# 		is automatically calculated.
191f589320aSDevin Teske# 	VAR_USER_HOME_CREATE [Optional]
192f589320aSDevin Teske# 		If non-NULL, create the user's home directory if it doesn't
193f589320aSDevin Teske# 		already exist.
194f589320aSDevin Teske# 	VAR_USER_LOGIN_CLASS [Optional]
195f589320aSDevin Teske# 		Login class to use when creating the login. Default is NULL.
196f589320aSDevin Teske# 	VAR_USER_PASSWORD [Optional]
197f589320aSDevin Teske# 		Unencrypted password to use. If unset or NULL, password
198f589320aSDevin Teske# 		authentication for the login is disabled.
199f589320aSDevin Teske# 	VAR_USER_PASSWORD_EXPIRE [Optional]
200f589320aSDevin Teske# 		The password expiration time. Format of the date is either a
201f589320aSDevin Teske# 		UNIX time in decimal, or a date in dd-mmm-yy[yy] format, where
202f589320aSDevin Teske# 		dd is the day, mmm is the month in either numeric or alphabetic
203f589320aSDevin Teske# 		format, and yy[yy] is either a two or four digit year. This
204f589320aSDevin Teske# 		variable also accepts a relative date in the form of +n[mhdwoy]
205f589320aSDevin Teske# 		where n is a decimal, octal (leading 0) or hexadecimal (leading
206f589320aSDevin Teske# 		0x) digit followed by the number of Minutes, Hours, Days,
207f589320aSDevin Teske# 		Weeks, Months or Years from the current date at which the
208f589320aSDevin Teske# 		expiration time is to be set. Default is to never expire the
209f589320aSDevin Teske# 		account password.
210f589320aSDevin Teske# 	VAR_USER_SHELL [Optional]
211f589320aSDevin Teske# 		Path to login shell to use. Default is `/bin/sh'.
212f589320aSDevin Teske# 	VAR_USER_UID [Optional]
213f589320aSDevin Teske# 		Numerical user ID to use. If NULL or unset, the user ID is
214f589320aSDevin Teske# 		automatically chosen.
215f589320aSDevin Teske#
216f589320aSDevin Teske# Returns success if the user account was successfully created.
217f589320aSDevin Teske#
218f589320aSDevin Teskef_user_add()
219f589320aSDevin Teske{
220f589320aSDevin Teske	local funcname=f_user_add
221f589320aSDevin Teske	local title # Calculated below
222f589320aSDevin Teske	local alert=f_show_msg no_confirm=
223f589320aSDevin Teske
224f589320aSDevin Teske	f_getvar $VAR_NO_CONFIRM no_confirm
225f589320aSDevin Teske	[ "$no_confirm" ] && alert=f_show_info
226f589320aSDevin Teske
227f589320aSDevin Teske	local input
228f589320aSDevin Teske	f_getvar 3:-\$$VAR_USER input "$1"
229f589320aSDevin Teske
230f589320aSDevin Teske	#
231f589320aSDevin Teske	# NB: pw(8) has a ``feature'' wherein `-n name' can be taken as UID
232f589320aSDevin Teske	# instead of name. Work-around is to also pass `-u UID' at the same
233*e8e8c939SDevin Teske	# time (the UID is ignored in this case, so any UID will do).
234f589320aSDevin Teske	#
235*e8e8c939SDevin Teske	if [ "$input" ] && f_quietly pw usershow -n "$input" -u 1337; then
236f589320aSDevin Teske		f_show_err "$msg_login_already_used" "$input"
237f589320aSDevin Teske		return $FAILURE
238f589320aSDevin Teske	fi
239f589320aSDevin Teske
240f589320aSDevin Teske	local user_name="$input"
241f589320aSDevin Teske	while f_interactive && [ ! "$user_name" ]; do
242f589320aSDevin Teske		f_dialog_input_name user_name "$user_name" ||
243f589320aSDevin Teske			return $SUCCESS
244f589320aSDevin Teske		[ "$user_name" ] ||
245f589320aSDevin Teske			f_show_err "$msg_please_enter_a_user_name"
246f589320aSDevin Teske	done
247f589320aSDevin Teske	if [ ! "$user_name" ]; then
248f589320aSDevin Teske		f_show_err "$msg_no_user_specified"
249f589320aSDevin Teske		return $FAILURE
250f589320aSDevin Teske	fi
251f589320aSDevin Teske
252f589320aSDevin Teske	local user_account_expire user_class user_gecos user_gid user_home_dir
253f589320aSDevin Teske	local user_member_groups user_password user_password_expire user_shell
254f589320aSDevin Teske	local user_uid user_dotfiles_create= user_home_create=
255f589320aSDevin Teske	f_getvar $VAR_USER_ACCOUNT_EXPIRE-\$uexpire    user_account_expire
256f589320aSDevin Teske	f_getvar $VAR_USER_DOTFILES_CREATE:+\$msg_yes  user_dotfiles_create
257f589320aSDevin Teske	f_getvar $VAR_USER_GECOS-\$ugecos              user_gecos
258f589320aSDevin Teske	f_getvar $VAR_USER_GID                         user_gid
259f589320aSDevin Teske	f_getvar $VAR_USER_GROUPS                      user_member_groups
260f589320aSDevin Teske	f_getvar $VAR_USER_HOME:-\${homeprefix%/}/\$user_name \
261f589320aSDevin Teske	                                               user_home_dir
262f589320aSDevin Teske	f_getvar $VAR_USER_HOME_CREATE:+\$msg_yes      user_home_create
263f589320aSDevin Teske	f_getvar $VAR_USER_LOGIN_CLASS-\$defaultclass  user_class
264f589320aSDevin Teske	f_getvar $VAR_USER_PASSWORD                    user_password
265f589320aSDevin Teske	f_getvar $VAR_USER_PASSWORD_EXPIRE-\$upwexpire user_password_expire
266f589320aSDevin Teske	f_getvar $VAR_USER_SHELL-\$defaultshell        user_shell
267f589320aSDevin Teske	f_getvar $VAR_USER_UID                         user_uid
268f589320aSDevin Teske
269f589320aSDevin Teske	# Create home-dir if no script-override and does not exist
270f589320aSDevin Teske	f_isset $VAR_USER_HOME_CREATE || [ -d "$user_home_dir" ] ||
271f589320aSDevin Teske		user_home_create="$msg_yes"
272f589320aSDevin Teske	# Copy dotfiles if home-dir creation is desired, does not yet exist,
273f589320aSDevin Teske	# and no script-override has been set
274f589320aSDevin Teske	f_isset $VAR_USER_DOTFILES_CREATE ||
275f589320aSDevin Teske		[ "$user_home_create" != "$msg_yes" ] ||
276f589320aSDevin Teske		[ -d "$user_home_dir" ] || user_dotfiles_create="$msg_yes"
277f589320aSDevin Teske	# Create home-dir if copying dotfiles but home-dir does not exist
278f589320aSDevin Teske	[ "$user_dotfiles_create" -a ! -d "$user_home_dir" ] &&
279f589320aSDevin Teske		user_home_create="$msg_yes"
280f589320aSDevin Teske
281f589320aSDevin Teske	# Set flags for meaningful NULL values if-provided
282f589320aSDevin Teske	local no_account_expire= no_password_expire= null_gecos= null_members=
283f589320aSDevin Teske	local user_password_disable=
284f589320aSDevin Teske	f_isset $VAR_USER_ACCOUNT_EXPIRE &&
285f589320aSDevin Teske		[ ! "$user_account_expire"  ] && no_account_expire=1
286f589320aSDevin Teske	f_isset $VAR_USER_GECOS &&
287f589320aSDevin Teske		[ ! "$user_gecos"           ] && null_gecos=1
288f589320aSDevin Teske	f_isset $VAR_USER_GROUPS &&
289f589320aSDevin Teske		[ ! "$user_member_groups"   ] && null_members=1
290f589320aSDevin Teske	f_isset $VAR_USER_PASSWORD &&
291f589320aSDevin Teske		[ ! "$user_password"        ] && user_password_disable=1
292f589320aSDevin Teske	f_isset $VAR_USER_PASSWORD_EXPIRE &&
293f589320aSDevin Teske		[ ! "$user_password_expire" ] && no_password_expire=1
294f589320aSDevin Teske
295f589320aSDevin Teske	if f_interactive && [ ! "$no_confirm" ]; then
296f589320aSDevin Teske		f_dialog_noyes \
297f589320aSDevin Teske			"$msg_use_default_values_for_all_account_details"
298f589320aSDevin Teske		retval=$?
299f589320aSDevin Teske		if [ $retval -eq $DIALOG_ESC ]; then
300f589320aSDevin Teske			return $SUCCESS
301f589320aSDevin Teske		elif [ $retval -ne $DIALOG_OK ]; then
302f589320aSDevin Teske			#
303f589320aSDevin Teske			# Ask series of questions to pre-fill the editor screen
304f589320aSDevin Teske			#
305f589320aSDevin Teske			# Defaults used in each dialog should allow the user to
306f589320aSDevin Teske			# simply hit ENTER to proceed, because cancelling any
307f589320aSDevin Teske			# single dialog will cause them to be returned to the
308f589320aSDevin Teske			# previous menu.
309f589320aSDevin Teske			#
310f589320aSDevin Teske
311f589320aSDevin Teske			f_dialog_input_gecos user_gecos "$user_gecos" ||
312f589320aSDevin Teske				return $FAILURE
313f589320aSDevin Teske			if [ "$passwdtype" = "yes" ]; then
314f589320aSDevin Teske				f_dialog_input_password user_password \
315f589320aSDevin Teske					user_password_disable ||
316f589320aSDevin Teske					return $FAILURE
317f589320aSDevin Teske			fi
318f589320aSDevin Teske			f_dialog_input_uid user_uid "$user_uid" ||
319f589320aSDevin Teske				return $FAILURE
320f589320aSDevin Teske			f_dialog_input_gid user_gid "$user_gid" ||
321f589320aSDevin Teske				return $FAILURE
322f589320aSDevin Teske			f_dialog_input_member_groups user_member_groups \
323f589320aSDevin Teske				"$user_member_groups" || return $FAILURE
324f589320aSDevin Teske			f_dialog_input_class user_class "$user_class" ||
325f589320aSDevin Teske				return $FAILURE
326f589320aSDevin Teske			f_dialog_input_expire_password user_password_expire \
327f589320aSDevin Teske				"$user_password_expire" || return $FAILURE
328f589320aSDevin Teske			f_dialog_input_expire_account user_account_expire \
329f589320aSDevin Teske				"$user_account_expire" || return $FAILURE
330f589320aSDevin Teske			f_dialog_input_home_dir user_home_dir \
331f589320aSDevin Teske				"$user_home_dir" || return $FAILURE
332f589320aSDevin Teske			if [ ! -d "$user_home_dir" ]; then
333f589320aSDevin Teske				f_dialog_input_home_create user_home_create ||
334f589320aSDevin Teske					return $FAILURE
335f589320aSDevin Teske				if [ "$user_home_create" = "$msg_yes" ]; then
336f589320aSDevin Teske					f_dialog_input_dotfiles_create \
337f589320aSDevin Teske						user_dotfiles_create ||
338f589320aSDevin Teske						return $FAILURE
339f589320aSDevin Teske				fi
340f589320aSDevin Teske			fi
341f589320aSDevin Teske			f_dialog_input_shell user_shell "$user_shell" ||
342f589320aSDevin Teske				return $FAILURE
343f589320aSDevin Teske		fi
344f589320aSDevin Teske	fi
345f589320aSDevin Teske
346f589320aSDevin Teske	#
347f589320aSDevin Teske	# Loop until the user decides to Exit, Cancel, or presses ESC
348f589320aSDevin Teske	#
349f589320aSDevin Teske	title="$msg_add $msg_user: $user_name"
350f589320aSDevin Teske	if f_interactive; then
351f589320aSDevin Teske		local mtag retval defaultitem=
352f589320aSDevin Teske		while :; do
353f589320aSDevin Teske			f_dialog_title "$title"
354f589320aSDevin Teske			f_dialog_menu_user_add "$defaultitem"
355f589320aSDevin Teske			retval=$?
356f589320aSDevin Teske			f_dialog_title_restore
357f589320aSDevin Teske			f_dialog_menutag_fetch mtag
358f589320aSDevin Teske			f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
359f589320aSDevin Teske			defaultitem="$mtag"
360f589320aSDevin Teske
361f589320aSDevin Teske			# Return if user either pressed ESC or chose Cancel/No
362f589320aSDevin Teske			[ $retval -eq $DIALOG_OK ] || return $FAILURE
363f589320aSDevin Teske
364f589320aSDevin Teske			case "$mtag" in
365f589320aSDevin Teske			X) # Add/Exit
366f589320aSDevin Teske			   local var
367f589320aSDevin Teske			   for var in account_expire class gecos gid home_dir \
368f589320aSDevin Teske			   	member_groups name password_expire shell uid \
369f589320aSDevin Teske			   ; do
370f589320aSDevin Teske			   	local _user_$var
371f589320aSDevin Teske			   	eval f_shell_escape \"\$user_$var\" _user_$var
372f589320aSDevin Teske			   done
373f589320aSDevin Teske
374f589320aSDevin Teske			   local cmd="pw useradd -n '$_user_name'"
375f589320aSDevin Teske			   [ "$user_gid"   ] && cmd="$cmd -g '$_user_gid'"
376f589320aSDevin Teske			   [ "$user_shell" ] && cmd="$cmd -s '$_user_shell'"
377f589320aSDevin Teske			   [ "$user_uid"   ] && cmd="$cmd -u '$_user_uid'"
378f589320aSDevin Teske			   [ "$user_account_expire" -o \
379f589320aSDevin Teske			     "$no_account_expire" ] &&
380f589320aSDevin Teske			   	cmd="$cmd -e '$_user_account_expire'"
381f589320aSDevin Teske			   [ "$user_class" -o "$null_class" ] &&
382f589320aSDevin Teske			   	cmd="$cmd -L '$_user_class'"
383f589320aSDevin Teske			   [ "$user_gecos" -o "$null_gecos" ] &&
384f589320aSDevin Teske			   	cmd="$cmd -c '$_user_gecos'"
385f589320aSDevin Teske			   [ "$user_home_dir" ] &&
386f589320aSDevin Teske			   	cmd="$cmd -d '$_user_home_dir'"
387f589320aSDevin Teske			   [ "$user_member_groups" ] &&
388f589320aSDevin Teske			   	cmd="$cmd -G '$_user_member_groups'"
389f589320aSDevin Teske			   [ "$user_password_expire" -o \
390f589320aSDevin Teske			     "$no_password_expire" ] &&
391f589320aSDevin Teske			   	cmd="$cmd -p '$_user_password_expire'"
392f589320aSDevin Teske
393f589320aSDevin Teske			   # Execute the command
394f589320aSDevin Teske			   if [ "$user_password_disable" ]; then
395f589320aSDevin Teske			   	f_eval_catch $funcname pw '%s -h -' "$cmd"
396f589320aSDevin Teske			   elif [ "$user_password" ]; then
397f589320aSDevin Teske			   	echo "$user_password" | f_eval_catch \
398f589320aSDevin Teske			   		$funcname pw '%s -h 0' "$cmd"
399f589320aSDevin Teske			   else
400f589320aSDevin Teske			   	f_eval_catch $funcname pw '%s' "$cmd"
401f589320aSDevin Teske			   fi || continue
402f589320aSDevin Teske
403f589320aSDevin Teske			   # Create home directory if desired
404f589320aSDevin Teske			   [ "${user_home_create:-$msg_no}" != "$msg_no" ] &&
405f589320aSDevin Teske			   	f_user_create_homedir "$user_name"
406f589320aSDevin Teske
407f589320aSDevin Teske			   # Copy dotfiles if desired
408f589320aSDevin Teske			   [ "${user_dotfiles_create:-$msg_no}" != \
409f589320aSDevin Teske			     "$msg_no" ] && f_user_copy_dotfiles "$user_name"
410f589320aSDevin Teske
411f589320aSDevin Teske			   break # to success
412f589320aSDevin Teske			   ;;
413f589320aSDevin Teske			1) # Login (prompt for new login name)
414f589320aSDevin Teske			   f_dialog_input_name input "$user_name" ||
415f589320aSDevin Teske			   	continue
416*e8e8c939SDevin Teske			   if f_quietly pw usershow -n "$input" -u 1337; then
417f589320aSDevin Teske			   	f_show_err "$msg_login_already_used" "$input"
418f589320aSDevin Teske			   	continue
419f589320aSDevin Teske			   fi
420f589320aSDevin Teske			   user_name="$input"
421f589320aSDevin Teske			   title="$msg_add $msg_user: $user_name"
422f589320aSDevin Teske			   user_home_dir="${homeprefix%/}/$user_name"
423f589320aSDevin Teske			   ;;
424f589320aSDevin Teske			2) # Full Name
425f589320aSDevin Teske			   f_dialog_input_gecos user_gecos "$user_gecos" &&
426f589320aSDevin Teske			   	[ ! "$user_gecos" ] && null_gecos=1 ;;
427f589320aSDevin Teske			3) # Password
428f589320aSDevin Teske			   f_dialog_input_password \
429f589320aSDevin Teske			   	user_password user_password_disable ;;
430f589320aSDevin Teske			4) # User ID
431f589320aSDevin Teske			   f_dialog_input_uid user_uid "$user_uid" ;;
432f589320aSDevin Teske			5) # Group ID
433f589320aSDevin Teske			   f_dialog_input_gid user_gid "$user_gid" ;;
434f589320aSDevin Teske			6) # Member of Groups
435f589320aSDevin Teske			   f_dialog_input_member_groups \
436f589320aSDevin Teske			   	user_member_groups "$user_member_groups" &&
437f589320aSDevin Teske			   	[ ! "$user_member_groups" ] &&
438f589320aSDevin Teske			   	null_members=1 ;;
439f589320aSDevin Teske			7) # Login Class
440f589320aSDevin Teske			   f_dialog_input_class user_class "$user_class" &&
441f589320aSDevin Teske			   	[ ! "$user_class" ] && null_class=1 ;;
442f589320aSDevin Teske			8) # Password Expires On
443f589320aSDevin Teske			   f_dialog_input_expire_password \
444f589320aSDevin Teske			   	user_password_expire "$user_password_expire" &&
445f589320aSDevin Teske			   	[ ! "$user_password_expire" ] &&
446f589320aSDevin Teske			   	no_password_expire=1 ;;
447f589320aSDevin Teske			9) # Account Expires On
448f589320aSDevin Teske			   f_dialog_input_expire_account \
449f589320aSDevin Teske			   	user_account_expire "$user_account_expire" &&
450f589320aSDevin Teske			   	[ ! "$user_account_expire" ] &&
451f589320aSDevin Teske			   	no_account_expire=1 ;;
452f589320aSDevin Teske			A) # Home Directory
453f589320aSDevin Teske			   f_dialog_input_home_dir \
454f589320aSDevin Teske			   	user_home_dir "$user_home_dir" ;;
455f589320aSDevin Teske			B) # Shell
456f589320aSDevin Teske			   f_dialog_input_shell user_shell "$user_shell" ;;
457f589320aSDevin Teske			C) # Create Home Directory?
458f589320aSDevin Teske			   if [ "${user_home_create:-$msg_no}" != "$msg_no" ]
459f589320aSDevin Teske			   then
460f589320aSDevin Teske			   	user_home_create="$msg_no"
461f589320aSDevin Teske			   else
462f589320aSDevin Teske			   	user_home_create="$msg_yes"
463f589320aSDevin Teske			   fi ;;
464f589320aSDevin Teske			D) # Create Dotfiles?
465f589320aSDevin Teske			   if [ "${user_dotfiles_create:-$msg_no}" != \
466f589320aSDevin Teske			        "$msg_no" ]
467f589320aSDevin Teske			   then
468f589320aSDevin Teske			   	user_dotfiles_create="$msg_no"
469f589320aSDevin Teske			   else
470f589320aSDevin Teske			   	user_dotfiles_create="$msg_yes"
471f589320aSDevin Teske			   fi ;;
472f589320aSDevin Teske			esac
473f589320aSDevin Teske		done
474f589320aSDevin Teske	else
475f589320aSDevin Teske		local var
476f589320aSDevin Teske		for var in account_expire class gecos gid home_dir \
477f589320aSDevin Teske			member_groups name password_expire shell uid \
478f589320aSDevin Teske		; do
479f589320aSDevin Teske			local _user_$var
480f589320aSDevin Teske			eval f_shell_escape \"\$user_$var\" _user_$var
481f589320aSDevin Teske		done
482f589320aSDevin Teske
483f589320aSDevin Teske		# Form the command
484f589320aSDevin Teske		local cmd="pw useradd -n '$_user_name'"
485f589320aSDevin Teske		[ "$user_gid"      ] && cmd="$cmd -g '$_user_gid'"
486f589320aSDevin Teske		[ "$user_home_dir" ] && cmd="$cmd -d '$_user_home_dir'"
487f589320aSDevin Teske		[ "$user_shell"    ] && cmd="$cmd -s '$_user_shell'"
488f589320aSDevin Teske		[ "$user_uid"      ] && cmd="$cmd -u '$_user_uid'"
489f589320aSDevin Teske		[ "$user_account_expire" -o "$no_account_expire" ] &&
490f589320aSDevin Teske			cmd="$cmd -e '$_user_account_expire'"
491f589320aSDevin Teske		[ "$user_class" -o "$null_class" ] &&
492f589320aSDevin Teske			cmd="$cmd -L '$_user_class'"
493f589320aSDevin Teske		[ "$user_gecos" -o "$null_gecos" ] &&
494f589320aSDevin Teske			cmd="$cmd -c '$_user_gecos'"
495f589320aSDevin Teske		[ "$user_member_groups" -o "$null_members" ] &&
496f589320aSDevin Teske			cmd="$cmd -G '$_user_member_groups'"
497f589320aSDevin Teske		[ "$user_password_expire" -o "$no_password_expire" ] &&
498f589320aSDevin Teske			cmd="$cmd -p '$_user_password_expire'"
499f589320aSDevin Teske
500f589320aSDevin Teske		# Execute the command
501f589320aSDevin Teske		local retval err
502f589320aSDevin Teske		if [ "$user_password_disable" ]; then
503f589320aSDevin Teske			f_eval_catch -k err $funcname pw '%s -h -' "$cmd"
504f589320aSDevin Teske		elif [ "$user_password" ]; then
505f589320aSDevin Teske			err=$( echo "$user_password" | f_eval_catch -de \
506f589320aSDevin Teske				$funcname pw '%s -h 0' "$cmd" 2>&1 )
507f589320aSDevin Teske		else
508f589320aSDevin Teske			f_eval_catch -k err $funcname pw '%s' "$cmd"
509f589320aSDevin Teske		fi
510f589320aSDevin Teske		retval=$?
511f589320aSDevin Teske		if [ $retval -ne $SUCCESS ]; then
512f589320aSDevin Teske			f_show_err "%s" "$err"
513f589320aSDevin Teske			return $retval
514f589320aSDevin Teske		fi
515f589320aSDevin Teske
516f589320aSDevin Teske		# Create home directory if desired
517f589320aSDevin Teske		[ "${user_home_create:-$msg_no}" != "$msg_no" ] &&
518f589320aSDevin Teske			f_user_create_homedir "$user_name"
519f589320aSDevin Teske
520f589320aSDevin Teske		# Copy dotfiles if desired
521f589320aSDevin Teske		[ "${user_dotfiles_create:-$msg_no}" != "$msg_no" ] &&
522f589320aSDevin Teske			f_user_copy_dotfiles "$user_name"
523f589320aSDevin Teske	fi
524f589320aSDevin Teske
525f589320aSDevin Teske	f_dialog_title "$title"
526f589320aSDevin Teske	$alert "$msg_login_added"
527f589320aSDevin Teske	f_dialog_title_restore
528f589320aSDevin Teske	[ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
529f589320aSDevin Teske
530f589320aSDevin Teske	return $SUCCESS
531f589320aSDevin Teske}
532f589320aSDevin Teske
533f589320aSDevin Teske# f_user_delete [$user]
534f589320aSDevin Teske#
535f589320aSDevin Teske# Delete a user. If both $user (as a first argument) and $VAR_USER are unset or
536f589320aSDevin Teske# NULL and we are running interactively, prompt the end-user to select a user
537f589320aSDevin Teske# account from a list of those available. Variables that can be used to script
538f589320aSDevin Teske# user input:
539f589320aSDevin Teske#
540f589320aSDevin Teske# 	VAR_USER [Optional if running interactively]
541f589320aSDevin Teske# 		The user to delete. Ignored if given non-NULL first-argument.
542f589320aSDevin Teske#
543f589320aSDevin Teske# Returns success if the user account was successfully deleted.
544f589320aSDevin Teske#
545f589320aSDevin Teskef_user_delete()
546f589320aSDevin Teske{
547f589320aSDevin Teske	local funcname=f_user_delete
548f589320aSDevin Teske	local title # Calculated below
549f589320aSDevin Teske	local alert=f_show_msg no_confirm=
550f589320aSDevin Teske
551f589320aSDevin Teske	f_getvar $VAR_NO_CONFIRM no_confirm
552f589320aSDevin Teske	[ "$no_confirm" ] && alert=f_show_info
553f589320aSDevin Teske
554f589320aSDevin Teske	local input
555f589320aSDevin Teske	f_getvar 3:-\$$VAR_USER input "$1"
556f589320aSDevin Teske
557f589320aSDevin Teske	if f_interactive && [ ! "$input" ]; then
558f589320aSDevin Teske		f_dialog_menu_user_list || return $SUCCESS
559f589320aSDevin Teske		f_dialog_menutag_fetch input
560f589320aSDevin Teske		[ "$input" = "X $msg_exit" ] && return $SUCCESS
561f589320aSDevin Teske	elif [ ! "$input" ]; then
562f589320aSDevin Teske		f_show_err "$msg_no_user_specified"
563f589320aSDevin Teske		return $FAILURE
564f589320aSDevin Teske	fi
565f589320aSDevin Teske
566f589320aSDevin Teske	local user_account_expire user_class user_gecos user_gid user_home_dir
567f589320aSDevin Teske	local user_member_groups user_name user_password user_password_expire
568f589320aSDevin Teske	local user_shell user_uid # Variables created by f_input_user() below
569f589320aSDevin Teske	if [ "$input" ] && ! f_input_user "$input"; then
570f589320aSDevin Teske		f_show_err "$msg_login_not_found" "$input"
571f589320aSDevin Teske		return $FAILURE
572f589320aSDevin Teske	fi
573f589320aSDevin Teske
574f589320aSDevin Teske	local user_group_delete= user_home_delete=
575f589320aSDevin Teske	f_getvar $VAR_USER_GROUP_DELETE:-\$msg_no user_group_delete
576f589320aSDevin Teske	f_getvar $VAR_USER_HOME_DELETE:-\$msg_no  user_home_delete
577f589320aSDevin Teske
578f589320aSDevin Teske	# Attempt to translate user GID into a group name
579f589320aSDevin Teske	local user_group
580f589320aSDevin Teske	if user_group=$( pw groupshow -g "$user_gid" 2> /dev/null ); then
581f589320aSDevin Teske		user_group="${user_group%%:*}"
582f589320aSDevin Teske		# Default to delete the primary group if no script-override and
583f589320aSDevin Teske		# exists with same name as the user (same logic used by pw(8))
584f589320aSDevin Teske		f_isset $VAR_USER_GROUP_DELETE ||
585f589320aSDevin Teske			[ "$user_group" != "$user_name" ] ||
586f589320aSDevin Teske			user_group_delete="$msg_yes"
587f589320aSDevin Teske	fi
588f589320aSDevin Teske
589f589320aSDevin Teske	#
590f589320aSDevin Teske	# Loop until the user decides to Exit, Cancel, or presses ESC
591f589320aSDevin Teske	#
592f589320aSDevin Teske	title="$msg_delete $msg_user: $user_name"
593f589320aSDevin Teske	if f_interactive; then
594f589320aSDevin Teske		local mtag retval defaultitem=
595f589320aSDevin Teske		while :; do
596f589320aSDevin Teske			f_dialog_title "$title"
597f589320aSDevin Teske			f_dialog_menu_user_delete "$user_name" "$defaultitem"
598f589320aSDevin Teske			retval=$?
599f589320aSDevin Teske			f_dialog_title_restore
600f589320aSDevin Teske			f_dialog_menutag_fetch mtag
601f589320aSDevin Teske			f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
602f589320aSDevin Teske			defaultitem="$mtag"
603f589320aSDevin Teske
604f589320aSDevin Teske			# Return if user either pressed ESC or chose Cancel/No
605f589320aSDevin Teske			[ $retval -eq $DIALOG_OK ] || return $FAILURE
606f589320aSDevin Teske
607f589320aSDevin Teske			case "$mtag" in
608f589320aSDevin Teske			X) # Delete/Exit
609f589320aSDevin Teske			   f_shell_escape "$user_uid" _user_uid
610f589320aSDevin Teske
611f589320aSDevin Teske			   # Save group information in case pw(8) deletes it
612f589320aSDevin Teske			   # and we wanted to keep it (to be restored below)
613f589320aSDevin Teske			   if [ "${user_group_delete:-$msg_no}" = "$msg_no" ]
614f589320aSDevin Teske			   then
615f589320aSDevin Teske			   	local v vars="gid members name password"
616f589320aSDevin Teske			   	for v in $vars; do local group_$var; done
617f589320aSDevin Teske			   	f_input_group "$user_group"
618f589320aSDevin Teske
619f589320aSDevin Teske			   	# Remove user-to-delete from group members
620f589320aSDevin Teske			   	# NB: Otherwise group restoration could fail
621f589320aSDevin Teske			   	local name length=0 _members=
622f589320aSDevin Teske			  	while [ $length -ne ${#group_members} ]; do
623f589320aSDevin Teske			   		name="${group_members%%,*}"
624f589320aSDevin Teske			   		[ "$name" != "$user_name" ] &&
625f589320aSDevin Teske			   			_members="$_members,$name"
626f589320aSDevin Teske			   		length=${#group_members}
627f589320aSDevin Teske			   		group_members="${group_members#*,}"
628f589320aSDevin Teske			   	done
629f589320aSDevin Teske			   	group_members="${_members#,}"
630f589320aSDevin Teske
631f589320aSDevin Teske			   	# Create escaped variables for f_eval_catch()
632f589320aSDevin Teske			   	for v in $vars; do
633f589320aSDevin Teske			   		local _group_$v
634f589320aSDevin Teske			   		eval f_shell_escape \
635f589320aSDevin Teske			   			\"\$group_$v\" _group_$v
636f589320aSDevin Teske			   	done
637f589320aSDevin Teske			   fi
638f589320aSDevin Teske
639f589320aSDevin Teske			   # Delete the user (if asked to delete home directory
640f589320aSDevin Teske			   # display [X]dialog notification to show activity)
641f589320aSDevin Teske			   local cmd="pw userdel -u '$_user_uid'"
642f589320aSDevin Teske			   if [ "$user_home_delete" = "$msg_yes" -a \
643f589320aSDevin Teske			        "$USE_XDIALOG" ]
644f589320aSDevin Teske			   then
645f589320aSDevin Teske			   	local err
646f589320aSDevin Teske			   	err=$(
647f589320aSDevin Teske			   		exec 9>&1
648f589320aSDevin Teske			   		f_eval_catch -e $funcname pw \
649f589320aSDevin Teske			   		  "%s -r" "$cmd" \
650f589320aSDevin Teske			   		  >&$DIALOG_TERMINAL_PASSTHRU_FD 2>&9 |
651f589320aSDevin Teske			   		  f_xdialog_info \
652f589320aSDevin Teske			   		  	"$msg_deleting_home_directory"
653f589320aSDevin Teske			   	)
654f589320aSDevin Teske			   	[ ! "$err" ]
655f589320aSDevin Teske			   elif [ "$user_home_delete" = "$msg_yes" ]; then
656f589320aSDevin Teske			   	f_dialog_info "$msg_deleting_home_directory"
657f589320aSDevin Teske			   	f_eval_catch $funcname pw '%s -r' "$cmd"
658f589320aSDevin Teske			   else
659f589320aSDevin Teske			   	f_eval_catch $funcname pw '%s' "$cmd"
660f589320aSDevin Teske			   fi || continue
661f589320aSDevin Teske
662f589320aSDevin Teske			   #
663f589320aSDevin Teske			   # pw(8) may conditionally delete the primary group,
664f589320aSDevin Teske			   # which may not be what is desired.
665f589320aSDevin Teske			   #
666f589320aSDevin Teske			   # If we've been asked to delete the group and pw(8)
667f589320aSDevin Teske			   # chose not to, delete it. Otherwise, if we're told
668f589320aSDevin Teske			   # to NOT delete the group, we may need to restore it
669f589320aSDevin Teske			   # since pw(8) doesn't have a flag to tell `userdel'
670f589320aSDevin Teske			   # to not delete the group.
671f589320aSDevin Teske			   #
672f589320aSDevin Teske			   # NB: If primary group and user have different names
673f589320aSDevin Teske			   # the group may not have been deleted (again, see PR
674f589320aSDevin Teske			   # 169471 and SVN r263114 for details).
675f589320aSDevin Teske			   #
676f589320aSDevin Teske			   if [ "${user_group_delete:-$msg_no}" != "$msg_no" ]
677f589320aSDevin Teske			   then
678f589320aSDevin Teske			   	f_quietly pw groupshow -g "$user_gid" &&
679f589320aSDevin Teske			   	f_eval_catch $funcname pw \
680f589320aSDevin Teske			   		"pw groupdel -g '%s'" "$_user_gid"
681f589320aSDevin Teske			   elif ! f_quietly pw groupshow -g "$group_gid" &&
682f589320aSDevin Teske			        [ "$group_name" -a "$group_gid" ]
683f589320aSDevin Teske			   then
684f589320aSDevin Teske			   	# Group deleted by pw(8), so restore it
685f589320aSDevin Teske			   	local cmd="pw groupadd -n '$_group_name'"
686f589320aSDevin Teske			   	cmd="$cmd -g '$_group_gid'"
687f589320aSDevin Teske			   	cmd="$cmd -M '$_group_members'"
688f589320aSDevin Teske
689f589320aSDevin Teske			   	# Get the group password (pw(8) groupshow does
690f589320aSDevin Teske			  	# NOT provide this (even if running privileged)
691f589320aSDevin Teske			   	local group_password_enc
692f589320aSDevin Teske			   	group_password_enc=$( getent group | awk -F: '
693f589320aSDevin Teske			   		!/^[[:space:]]*(#|$)/ && \
694f589320aSDevin Teske			   		    $1 == ENVIRON["group_name"] && \
695f589320aSDevin Teske			   		    $3 == ENVIRON["group_gid"] && \
696f589320aSDevin Teske			   		    $4 == ENVIRON["group_members"] \
697f589320aSDevin Teske			   		{ print $2; exit }
698f589320aSDevin Teske			   	' )
699f589320aSDevin Teske			   	if [ "$group_password_enc" ]; then
700f589320aSDevin Teske			   		echo "$group_password_enc" |
701f589320aSDevin Teske			   			f_eval_catch $funcname \
702f589320aSDevin Teske			   				pw '%s -H 0' "$cmd"
703f589320aSDevin Teske			   	else
704f589320aSDevin Teske			   		f_eval_catch $funcname \
705f589320aSDevin Teske			   			pw '%s -h -' "$cmd"
706f589320aSDevin Teske			   	fi
707f589320aSDevin Teske			   fi
708f589320aSDevin Teske
709f589320aSDevin Teske			   break # to success
710f589320aSDevin Teske			   ;;
711f589320aSDevin Teske			1) # Login (select different login from list)
712f589320aSDevin Teske			   f_dialog_menu_user_list "$user_name" || continue
713f589320aSDevin Teske			   f_dialog_menutag_fetch mtag
714f589320aSDevin Teske
715f589320aSDevin Teske			   [ "$mtag" = "X $msg_exit" ] && continue
716f589320aSDevin Teske
717f589320aSDevin Teske			   if ! f_input_user "$mtag"; then
718f589320aSDevin Teske			   	f_show_err "$msg_login_not_found" "$mtag"
719f589320aSDevin Teske			   	# Attempt to fall back to previous selection
720f589320aSDevin Teske			   	f_input_user "$input" || return $FAILURE
721f589320aSDevin Teske			   else
722f589320aSDevin Teske			   	input="$mtag"
723f589320aSDevin Teske			   fi
724f589320aSDevin Teske			   title="$msg_delete $msg_user: $user_name"
725f589320aSDevin Teske			   ;;
726f589320aSDevin Teske			C) # Delete Primary Group?
727f589320aSDevin Teske			   if [ "${user_group_delete:-$msg_no}" != "$msg_no" ]
728f589320aSDevin Teske			   then
729f589320aSDevin Teske			   	user_group_delete="$msg_no"
730f589320aSDevin Teske			   else
731f589320aSDevin Teske			   	user_group_delete="$msg_yes"
732f589320aSDevin Teske			   fi ;;
733f589320aSDevin Teske			D) # Delete Home Directory?
734f589320aSDevin Teske			   if [ "${user_home_delete:-$msg_no}" != "$msg_no" ]
735f589320aSDevin Teske			   then
736f589320aSDevin Teske			   	user_home_delete="$msg_no"
737f589320aSDevin Teske			   else
738f589320aSDevin Teske			   	user_home_delete="$msg_yes"
739f589320aSDevin Teske			   fi ;;
740f589320aSDevin Teske			esac
741f589320aSDevin Teske		done
742f589320aSDevin Teske	else
743f589320aSDevin Teske		f_shell_escape "$user_uid" _user_uid
744f589320aSDevin Teske
745f589320aSDevin Teske		# Save group information in case pw(8) deletes it
746f589320aSDevin Teske		# and we wanted to keep it (to be restored below)
747f589320aSDevin Teske		if [ "${user_group_delete:-$msg_no}" = "$msg_no" ]; then
748f589320aSDevin Teske			local v vars="gid members name password"
749f589320aSDevin Teske			for v in $vars; do local group_$v; done
750f589320aSDevin Teske			f_input_group "$user_group"
751f589320aSDevin Teske
752f589320aSDevin Teske			# Remove user we're about to delete from group members
753f589320aSDevin Teske			# NB: Otherwise group restoration could fail
754f589320aSDevin Teske			local name length=0 _members=
755f589320aSDevin Teske			while [ $length -ne ${#group_members} ]; do
756f589320aSDevin Teske				name="${group_members%%,*}"
757f589320aSDevin Teske				[ "$name" != "$user_name" ] &&
758f589320aSDevin Teske					_members="$_members,$name"
759f589320aSDevin Teske				length=${#group_members}
760f589320aSDevin Teske				group_members="${group_members#*,}"
761f589320aSDevin Teske			done
762f589320aSDevin Teske			group_members="${_members#,}"
763f589320aSDevin Teske
764f589320aSDevin Teske			# Create escaped variables for later f_eval_catch()
765f589320aSDevin Teske			for v in $vars; do
766f589320aSDevin Teske				local _group_$v
767f589320aSDevin Teske				eval f_shell_escape \"\$group_$v\" _group_$v
768f589320aSDevin Teske			done
769f589320aSDevin Teske		fi
770f589320aSDevin Teske
771f589320aSDevin Teske		# Delete the user (if asked to delete home directory
772f589320aSDevin Teske		# display [X]dialog notification to show activity)
773f589320aSDevin Teske		local err cmd="pw userdel -u '$_user_uid'"
774f589320aSDevin Teske		if [ "$user_home_delete" = "$msg_yes" -a "$USE_XDIALOG" ]; then
775f589320aSDevin Teske			err=$(
776f589320aSDevin Teske				exec 9>&1
777f589320aSDevin Teske				f_eval_catch -de $funcname pw \
778f589320aSDevin Teske					'%s -r' "$cmd" 2>&9 | f_xdialog_info \
779f589320aSDevin Teske					"$msg_deleting_home_directory"
780f589320aSDevin Teske			)
781f589320aSDevin Teske			[ ! "$err" ]
782f589320aSDevin Teske		elif [ "$user_home_delete" = "$msg_yes" ]; then
783f589320aSDevin Teske			f_dialog_info "$msg_deleting_home_directory"
784f589320aSDevin Teske			f_eval_catch -k err $funcname pw '%s -r' "$cmd"
785f589320aSDevin Teske		else
786f589320aSDevin Teske			f_eval_catch -k err $funcname pw '%s' "$cmd"
787f589320aSDevin Teske		fi
788f589320aSDevin Teske		local retval=$?
789f589320aSDevin Teske		if [ $retval -ne $SUCCESS ]; then
790f589320aSDevin Teske			f_show_err "%s" "$err"
791f589320aSDevin Teske			return $retval
792f589320aSDevin Teske		fi
793f589320aSDevin Teske
794f589320aSDevin Teske		#
795f589320aSDevin Teske		# pw(8) may conditionally delete the primary group, which may
796f589320aSDevin Teske		# not be what is desired.
797f589320aSDevin Teske		#
798f589320aSDevin Teske		# If we've been asked to delete the group and pw(8) chose not
799f589320aSDevin Teske		# to, delete it. Otherwise, if we're told to NOT delete the
800f589320aSDevin Teske		# group, we may need to restore it since pw(8) doesn't have a
801f589320aSDevin Teske		# flag to tell `userdel' to not delete the group.
802f589320aSDevin Teske		#
803f589320aSDevin Teske		# NB: If primary group and user have different names the group
804f589320aSDevin Teske		# may not have been deleted (again, see PR 169471 and SVN
805f589320aSDevin Teske		# r263114 for details).
806f589320aSDevin Teske		#
807f589320aSDevin Teske		if [ "${user_group_delete:-$msg_no}" != "$msg_no" ]
808f589320aSDevin Teske		then
809f589320aSDevin Teske			f_quietly pw groupshow -g "$user_gid" &&
810f589320aSDevin Teske			f_eval_catch $funcname pw \
811f589320aSDevin Teske				"pw groupdel -g '%s'" "$_user_gid"
812f589320aSDevin Teske		elif ! f_quietly pw groupshow -g "$group_gid" &&
813f589320aSDevin Teske		     [ "$group_name" -a "$group_gid" ]
814f589320aSDevin Teske		then
815f589320aSDevin Teske			# Group deleted by pw(8), so restore it
816f589320aSDevin Teske			local cmd="pw groupadd -n '$_group_name'"
817f589320aSDevin Teske			cmd="$cmd -g '$_group_gid'"
818f589320aSDevin Teske			cmd="$cmd -M '$_group_members'"
819f589320aSDevin Teske			local group_password_enc
820f589320aSDevin Teske			group_password_enc=$( getent group | awk -F: '
821f589320aSDevin Teske				!/^[[:space:]]*(#|$)/ && \
822f589320aSDevin Teske				    $1 == ENVIRON["group_name"] && \
823f589320aSDevin Teske				    $3 == ENVIRON["group_gid"] && \
824f589320aSDevin Teske				    $4 == ENVIRON["group_members"] \
825f589320aSDevin Teske				{ print $2; exit }
826f589320aSDevin Teske			' )
827f589320aSDevin Teske			if [ "$group_password_enc" ]; then
828f589320aSDevin Teske				echo "$group_password_enc" |
829f589320aSDevin Teske					f_eval_catch $funcname \
830f589320aSDevin Teske						pw '%s -H 0' "$cmd"
831f589320aSDevin Teske			else
832ad8d629aSDevin Teske				f_eval_catch $funcname pw '%s -h -' "$cmd"
833f589320aSDevin Teske			fi
834f589320aSDevin Teske		fi
835f589320aSDevin Teske	fi
836f589320aSDevin Teske
837f589320aSDevin Teske	f_dialog_title "$title"
838f589320aSDevin Teske	$alert "$msg_login_deleted"
839f589320aSDevin Teske	f_dialog_title_restore
840f589320aSDevin Teske	[ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
841f589320aSDevin Teske
842f589320aSDevin Teske	return $SUCCESS
843f589320aSDevin Teske}
844f589320aSDevin Teske
845f589320aSDevin Teske# f_user_edit [$user]
846f589320aSDevin Teske#
847f589320aSDevin Teske# Modify a login account. If both $user (as a first argument) and $VAR_USER are
848f589320aSDevin Teske# unset or NULL and we are running interactively, prompt the end-user to select
849f589320aSDevin Teske# a login account from a list of those available. Variables that can be used to
850f589320aSDevin Teske# script user input:
851f589320aSDevin Teske#
852f589320aSDevin Teske# 	VAR_USER [Optional if running interactively]
853f589320aSDevin Teske# 		The login to modify. Ignored if given non-NULL first-argument.
854f589320aSDevin Teske# 	VAR_USER_ACCOUNT_EXPIRE [Optional]
855f589320aSDevin Teske# 		The account expiration time. Format is similar to
856f589320aSDevin Teske# 		VAR_USER_PASSWORD_EXPIRE variable below. If unset, account
857f589320aSDevin Teske# 		expiry is unchanged. If set but NULL, account expiration is
858f589320aSDevin Teske# 		disabled (same as setting a value of `0').
859f589320aSDevin Teske# 	VAR_USER_DOTFILES_CREATE [Optional]
860f589320aSDevin Teske# 		If non-NULL, re-populate the user's home directory with the
861f589320aSDevin Teske# 		template files found in $udotdir (`/usr/share/skel' default).
862f589320aSDevin Teske# 	VAR_USER_GECOS [Optional]
863f589320aSDevin Teske# 		Often the full name of the account holder. If unset, the GECOS
864f589320aSDevin Teske# 		field is unmodified. If set but NULL, the field is blanked.
865f589320aSDevin Teske# 	VAR_USER_GID [Optional]
866f589320aSDevin Teske# 		Numerical primary-group ID to set. If NULL or unset, the group
867f589320aSDevin Teske# 		ID is unchanged.
868f589320aSDevin Teske# 	VAR_USER_GROUPS [Optional]
869f589320aSDevin Teske# 		Comma-separated list of additional groups to which the user is
870f589320aSDevin Teske# 		a member of. If set but NULL, group memberships are reset (this
871f589320aSDevin Teske# 		login will not be a member of any additional groups besides the
872f589320aSDevin Teske# 		primary group). If unset, group membership is unmodified.
873f589320aSDevin Teske# 	VAR_USER_HOME [Optional]
874f589320aSDevin Teske# 		The home directory to set. If NULL or unset, the home directory
875f589320aSDevin Teske# 		is unchanged.
876f589320aSDevin Teske# 	VAR_USER_HOME_CREATE [Optional]
877f589320aSDevin Teske# 		If non-NULL, create the user's home directory if it doesn't
878f589320aSDevin Teske# 		already exist.
879f589320aSDevin Teske# 	VAR_USER_LOGIN_CLASS [Optional]
880f589320aSDevin Teske# 		Login class to set. If unset, the login class is unchanged. If
881f589320aSDevin Teske# 		set but NULL, the field is blanked.
882f589320aSDevin Teske# 	VAR_USER_PASSWORD [Optional]
883f589320aSDevin Teske# 		Unencrypted password to set. If unset, the login password is
884f589320aSDevin Teske# 		unmodified. If set but NULL, password authentication for the
885f589320aSDevin Teske# 		login is disabled.
886f589320aSDevin Teske# 	VAR_USER_PASSWORD_EXPIRE [Optional]
887f589320aSDevin Teske# 		The password expiration time. Format of the date is either a
888f589320aSDevin Teske# 		UNIX time in decimal, or a date in dd-mmm-yy[yy] format, where
889f589320aSDevin Teske# 		dd is the day, mmm is the month in either numeric or alphabetic
890f589320aSDevin Teske# 		format, and yy[yy] is either a two or four digit year. This
891f589320aSDevin Teske# 		variable also accepts a relative date in the form of +n[mhdwoy]
892f589320aSDevin Teske# 		where n is a decimal, octal (leading 0) or hexadecimal (leading
893f589320aSDevin Teske# 		0x) digit followed by the number of Minutes, Hours, Days,
894f589320aSDevin Teske# 		Weeks, Months or Years from the current date at which the
895f589320aSDevin Teske# 		expiration time is to be set. If unset, password expiry is
896f589320aSDevin Teske# 		unchanged. If set but NULL, password expiration is disabled
897f589320aSDevin Teske# 		(same as setting a value of `0').
898f589320aSDevin Teske# 	VAR_USER_SHELL [Optional]
899f589320aSDevin Teske# 		Path to login shell to set. If NULL or unset, the shell is
900f589320aSDevin Teske# 		unchanged.
901f589320aSDevin Teske# 	VAR_USER_UID [Optional]
902f589320aSDevin Teske# 		Numerical user ID to set. If NULL or unset, the user ID is
903f589320aSDevin Teske# 		unchanged.
904f589320aSDevin Teske#
905f589320aSDevin Teske# Returns success if the user account was successfully modified.
906f589320aSDevin Teske#
907f589320aSDevin Teskef_user_edit()
908f589320aSDevin Teske{
909f589320aSDevin Teske	local funcname=f_user_edit
910f589320aSDevin Teske	local title # Calculated below
911f589320aSDevin Teske	local alert=f_show_msg no_confirm=
912f589320aSDevin Teske
913f589320aSDevin Teske	f_getvar $VAR_NO_CONFIRM no_confirm
914f589320aSDevin Teske	[ "$no_confirm" ] && alert=f_show_info
915f589320aSDevin Teske
916f589320aSDevin Teske	local input
917f589320aSDevin Teske	f_getvar 3:-\$$VAR_USER input "$1"
918f589320aSDevin Teske
919f589320aSDevin Teske	#
920f589320aSDevin Teske	# NB: pw(8) has a ``feature'' wherein `-n name' can be taken as UID
921f589320aSDevin Teske	# instead of name. Work-around is to also pass `-u UID' at the same
922*e8e8c939SDevin Teske	# time (the UID is ignored in this case, so any UID will do).
923f589320aSDevin Teske	#
924*e8e8c939SDevin Teske	if [ "$input" ] && ! f_quietly pw usershow -n "$input" -u 1337; then
925f589320aSDevin Teske		f_show_err "$msg_login_not_found" "$input"
926f589320aSDevin Teske		return $FAILURE
927f589320aSDevin Teske	fi
928f589320aSDevin Teske
929f589320aSDevin Teske	if f_interactive && [ ! "$input" ]; then
930f589320aSDevin Teske		f_dialog_menu_user_list || return $SUCCESS
931f589320aSDevin Teske		f_dialog_menutag_fetch input
932f589320aSDevin Teske		[ "$input" = "X $msg_exit" ] && return $SUCCESS
933f589320aSDevin Teske	elif [ ! "$input" ]; then
934f589320aSDevin Teske		f_show_err "$msg_no_user_specified"
935f589320aSDevin Teske		return $FAILURE
936f589320aSDevin Teske	fi
937f589320aSDevin Teske
938f589320aSDevin Teske	local user_account_expire user_class user_gecos user_gid user_home_dir
939f589320aSDevin Teske	local user_member_groups user_name user_password user_password_expire
940f589320aSDevin Teske	local user_shell user_uid # Variables created by f_input_user() below
941f589320aSDevin Teske	if ! f_input_user "$input"; then
942f589320aSDevin Teske		f_show_err "$msg_login_not_found" "$input"
943f589320aSDevin Teske		return $FAILURE
944f589320aSDevin Teske	fi
945f589320aSDevin Teske
946f589320aSDevin Teske	#
947f589320aSDevin Teske	# Override values probed by f_input_user() with desired values
948f589320aSDevin Teske	#
949f589320aSDevin Teske	f_isset $VAR_USER_GID   && f_getvar $VAR_USER_GID   user_gid
950f589320aSDevin Teske	f_isset $VAR_USER_HOME  && f_getvar $VAR_USER_HOME  user_home_dir
951f589320aSDevin Teske	f_isset $VAR_USER_SHELL && f_getvar $VAR_USER_SHELL user_shell
952f589320aSDevin Teske	f_isset $VAR_USER_UID   && f_getvar $VAR_USER_UID   user_uid
953f589320aSDevin Teske	local user_dotfiles_create= user_home_create=
954f589320aSDevin Teske	f_getvar $VAR_USER_DOTFILES_CREATE:+\$msg_yes user_dotfiles_create
955f589320aSDevin Teske	f_getvar $VAR_USER_HOME_CREATE:+\$msg_yes     user_home_create
956f589320aSDevin Teske	local no_account_expire=
957f589320aSDevin Teske	if f_isset $VAR_USER_ACCOUNT_EXPIRE; then
958f589320aSDevin Teske		f_getvar $VAR_USER_ACCOUNT_EXPIRE user_account_expire
959f589320aSDevin Teske		[ "$user_account_expire" ] || no_account_expire=1
960f589320aSDevin Teske	fi
961f589320aSDevin Teske	local null_gecos=
962f589320aSDevin Teske	if f_isset $VAR_USER_GECOS; then
963f589320aSDevin Teske		f_getvar $VAR_USER_GECOS user_gecos
964f589320aSDevin Teske		[ "$user_gecos" ] || null_gecos=1
965f589320aSDevin Teske	fi
966f589320aSDevin Teske	local null_members=
967f589320aSDevin Teske	if f_isset $VAR_USER_GROUPS; then
968f589320aSDevin Teske		f_getvar $VAR_USER_GROUPS user_member_groups
969f589320aSDevin Teske		[ "$user_member_groups" ] || null_members=1
970f589320aSDevin Teske	fi
971f589320aSDevin Teske	local null_class=
972f589320aSDevin Teske	if f_isset $VAR_USER_LOGIN_CLASS; then
973f589320aSDevin Teske		f_getvar $VAR_USER_LOGIN_CLASS user_class
974f589320aSDevin Teske		[ "$user_class" ] || null_class=1
975f589320aSDevin Teske	fi
976f589320aSDevin Teske	local user_password_disable=
977f589320aSDevin Teske	if f_isset $VAR_USER_PASSWORD; then
978f589320aSDevin Teske		f_getvar $VAR_USER_PASSWORD user_password
979f589320aSDevin Teske		[ "$user_password" ] || user_password_disable=1
980f589320aSDevin Teske	fi
981f589320aSDevin Teske	local no_password_expire=
982f589320aSDevin Teske	if f_isset $VAR_USER_PASSWORD_EXPIRE; then
983f589320aSDevin Teske		f_getvar $VAR_USER_PASSWORD_EXPIRE user_password_expire
984f589320aSDevin Teske		[ "$user_password_expire" ] || no_password_expire=1
985f589320aSDevin Teske	fi
986f589320aSDevin Teske
987f589320aSDevin Teske	#
988f589320aSDevin Teske	# Loop until the user decides to Exit, Cancel, or presses ESC
989f589320aSDevin Teske	#
990f589320aSDevin Teske	title="$msg_edit_view $msg_user: $user_name"
991f589320aSDevin Teske	if f_interactive; then
992f589320aSDevin Teske		local mtag retval defaultitem=
993f589320aSDevin Teske		while :; do
994f589320aSDevin Teske			f_dialog_title "$title"
995f589320aSDevin Teske			f_dialog_menu_user_edit "$defaultitem"
996f589320aSDevin Teske			retval=$?
997f589320aSDevin Teske			f_dialog_title_restore
998f589320aSDevin Teske			f_dialog_menutag_fetch mtag
999f589320aSDevin Teske			f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
1000f589320aSDevin Teske			defaultitem="$mtag"
1001f589320aSDevin Teske
1002f589320aSDevin Teske			# Return if user either pressed ESC or chose Cancel/No
1003f589320aSDevin Teske			[ $retval -eq $DIALOG_OK ] || return $FAILURE
1004f589320aSDevin Teske
1005f589320aSDevin Teske			case "$mtag" in
1006f589320aSDevin Teske			X) # Save/Exit
1007f589320aSDevin Teske			   local var
1008f589320aSDevin Teske			   for var in account_expire class gecos gid home_dir \
1009f589320aSDevin Teske			   	member_groups name password_expire shell uid \
1010f589320aSDevin Teske			   ; do
1011f589320aSDevin Teske			   	local _user_$var
1012f589320aSDevin Teske			   	eval f_shell_escape \"\$user_$var\" _user_$var
1013f589320aSDevin Teske			   done
1014f589320aSDevin Teske
1015f589320aSDevin Teske			   local cmd="pw usermod -n '$_user_name'"
1016f589320aSDevin Teske			   [ "$user_gid"   ] && cmd="$cmd -g '$_user_gid'"
1017f589320aSDevin Teske			   [ "$user_shell" ] && cmd="$cmd -s '$_user_shell'"
1018f589320aSDevin Teske			   [ "$user_uid"   ] && cmd="$cmd -u '$_user_uid'"
1019f589320aSDevin Teske			   [ "$user_account_expire" -o \
1020f589320aSDevin Teske			     "$no_account_expire" ] &&
1021f589320aSDevin Teske			   	cmd="$cmd -e '$_user_account_expire'"
1022f589320aSDevin Teske			   [ "$user_class" -o "$null_class" ] &&
1023f589320aSDevin Teske			   	cmd="$cmd -L '$_user_class'"
1024f589320aSDevin Teske			   [ "$user_gecos" -o "$null_gecos" ] &&
1025f589320aSDevin Teske			   	cmd="$cmd -c '$_user_gecos'"
1026f589320aSDevin Teske			   [ "$user_home_dir"  ] &&
1027f589320aSDevin Teske			   	cmd="$cmd -d '$_user_home_dir'"
1028f589320aSDevin Teske			   [ "$user_member_groups" -o "$null_members" ] &&
1029f589320aSDevin Teske			   	cmd="$cmd -G '$_user_member_groups'"
1030f589320aSDevin Teske			   [ "$user_password_expire" -o \
1031f589320aSDevin Teske			     "$no_password_expire" ] &&
1032f589320aSDevin Teske			   	cmd="$cmd -p '$_user_password_expire'"
1033f589320aSDevin Teske
1034f589320aSDevin Teske			   # Execute the command
1035f589320aSDevin Teske			   if [ "$user_password_disable" ]; then
1036f589320aSDevin Teske			   	f_eval_catch $funcname pw '%s -h -' "$cmd"
1037f589320aSDevin Teske			   elif [ "$user_password" ]; then
1038f589320aSDevin Teske			   	echo "$user_password" | f_eval_catch \
1039f589320aSDevin Teske			   		$funcname pw '%s -h 0' "$cmd"
1040f589320aSDevin Teske			   else
1041f589320aSDevin Teske			   	f_eval_catch $funcname pw '%s' "$cmd"
1042f589320aSDevin Teske			   fi || continue
1043f589320aSDevin Teske
1044f589320aSDevin Teske			   # Create home directory if desired
1045f589320aSDevin Teske			   [ "${user_home_create:-$msg_no}" != "$msg_no" ] &&
1046f589320aSDevin Teske			   	f_user_create_homedir "$user_name"
1047f589320aSDevin Teske
1048f589320aSDevin Teske			   # Copy dotfiles if desired
1049f589320aSDevin Teske			   [ "${user_dotfiles_create:-$msg_no}" != \
1050f589320aSDevin Teske			     "$msg_no" ] && f_user_copy_dotfiles "$user_name"
1051f589320aSDevin Teske
1052f589320aSDevin Teske			   break # to success
1053f589320aSDevin Teske			   ;;
1054f589320aSDevin Teske			1) # Login (select different login from list)
1055f589320aSDevin Teske			   f_dialog_menu_user_list "$user_name" || continue
1056f589320aSDevin Teske			   f_dialog_menutag_fetch mtag
1057f589320aSDevin Teske
1058f589320aSDevin Teske			   [ "$mtag" = "X $msg_exit" ] && continue
1059f589320aSDevin Teske
1060f589320aSDevin Teske			   if ! f_input_user "$mtag"; then
1061f589320aSDevin Teske			   	f_show_err "$msg_login_not_found" "$mtag"
1062f589320aSDevin Teske			   	# Attempt to fall back to previous selection
1063f589320aSDevin Teske			   	f_input_user "$input" || return $FAILURE
1064f589320aSDevin Teske			   else
1065f589320aSDevin Teske			   	input="$mtag"
1066f589320aSDevin Teske			   fi
1067f589320aSDevin Teske			   title="$msg_edit_view $msg_user: $user_name"
1068f589320aSDevin Teske			   ;;
1069f589320aSDevin Teske			2) # Full Name
1070f589320aSDevin Teske			   f_dialog_input_gecos user_gecos "$user_gecos" &&
1071f589320aSDevin Teske			   	[ ! "$user_gecos" ] && null_gecos=1 ;;
1072f589320aSDevin Teske			3) # Password
1073f589320aSDevin Teske			   f_dialog_input_password \
1074f589320aSDevin Teske			   	user_password user_password_disable ;;
1075f589320aSDevin Teske			4) # User ID
1076f589320aSDevin Teske			   f_dialog_input_uid user_uid "$user_uid" ;;
1077f589320aSDevin Teske			5) # Group ID
1078f589320aSDevin Teske			   f_dialog_input_gid user_gid "$user_gid" ;;
1079f589320aSDevin Teske			6) # Member of Groups
1080f589320aSDevin Teske			   f_dialog_input_member_groups \
1081f589320aSDevin Teske			   	user_member_groups "$user_member_groups" &&
1082f589320aSDevin Teske			   	[ ! "$user_member_groups" ] &&
1083f589320aSDevin Teske			   	null_members=1 ;;
1084f589320aSDevin Teske			7) # Login Class
1085f589320aSDevin Teske			   f_dialog_input_class user_class "$user_class" &&
1086f589320aSDevin Teske			   	[ ! "$user_class" ] && null_class=1 ;;
1087f589320aSDevin Teske			8) # Password Expires On
1088f589320aSDevin Teske			   f_dialog_input_expire_password \
1089f589320aSDevin Teske			   	user_password_expire "$user_password_expire" &&
1090f589320aSDevin Teske			   	[ ! "$user_password_expire" ] &&
1091f589320aSDevin Teske			   	no_password_expire=1 ;;
1092f589320aSDevin Teske			9) # Account Expires On
1093f589320aSDevin Teske			   f_dialog_input_expire_account \
1094f589320aSDevin Teske			   	user_account_expire "$user_account_expire" &&
1095f589320aSDevin Teske			   	[ ! "$user_account_expire" ] &&
1096f589320aSDevin Teske			   	no_account_expire=1 ;;
1097f589320aSDevin Teske			A) # Home Directory
1098f589320aSDevin Teske			   f_dialog_input_home_dir \
1099f589320aSDevin Teske			   	user_home_dir "$user_home_dir" ;;
1100f589320aSDevin Teske			B) # Shell
1101f589320aSDevin Teske			   f_dialog_input_shell user_shell "$user_shell" ;;
1102f589320aSDevin Teske			C) # Create Home Directory?
1103f589320aSDevin Teske			   if [ "${user_home_create:-$msg_no}" != "$msg_no" ]
1104f589320aSDevin Teske			   then
1105f589320aSDevin Teske			   	user_home_create="$msg_no"
1106f589320aSDevin Teske			   else
1107f589320aSDevin Teske			   	user_home_create="$msg_yes"
1108f589320aSDevin Teske			   fi ;;
1109f589320aSDevin Teske			D) # Create Dotfiles?
1110f589320aSDevin Teske			   if [ "${user_dotfiles_create:-$msg_no}" != \
1111f589320aSDevin Teske			        "$msg_no" ]
1112f589320aSDevin Teske			   then
1113f589320aSDevin Teske			   	user_dotfiles_create="$msg_no"
1114f589320aSDevin Teske			   else
1115f589320aSDevin Teske			   	user_dotfiles_create="$msg_yes"
1116f589320aSDevin Teske			   fi ;;
1117f589320aSDevin Teske			esac
1118f589320aSDevin Teske		done
1119f589320aSDevin Teske	else
1120f589320aSDevin Teske		local var
1121f589320aSDevin Teske		for var in account_expire class gecos gid home_dir \
1122f589320aSDevin Teske			member_groups name password_expire shell uid \
1123f589320aSDevin Teske		; do
1124f589320aSDevin Teske			local _user_$var
1125f589320aSDevin Teske			eval f_shell_escape \"\$user_$var\" _user_$var
1126f589320aSDevin Teske		done
1127f589320aSDevin Teske
1128f589320aSDevin Teske		# Form the command
1129f589320aSDevin Teske		local cmd="pw usermod -n '$_user_name'"
1130f589320aSDevin Teske		[ "$user_gid"      ] && cmd="$cmd -g '$_user_gid'"
1131f589320aSDevin Teske		[ "$user_home_dir" ] && cmd="$cmd -d '$_user_home_dir'"
1132f589320aSDevin Teske		[ "$user_shell"    ] && cmd="$cmd -s '$_user_shell'"
1133f589320aSDevin Teske		[ "$user_uid"      ] && cmd="$cmd -u '$_user_uid'"
1134f589320aSDevin Teske		[ "$user_account_expire" -o "$no_account_expire" ] &&
1135f589320aSDevin Teske			cmd="$cmd -e '$_user_account_expire'"
1136f589320aSDevin Teske		[ "$user_class" -o "$null_class" ] &&
1137f589320aSDevin Teske			cmd="$cmd -L '$_user_class'"
1138f589320aSDevin Teske		[ "$user_gecos" -o "$null_gecos" ] &&
1139f589320aSDevin Teske			cmd="$cmd -c '$_user_gecos'"
1140f589320aSDevin Teske		[ "$user_member_groups" -o "$null_members" ] &&
1141f589320aSDevin Teske			cmd="$cmd -G '$_user_member_groups'"
1142f589320aSDevin Teske		[ "$user_password_expire" -o "$no_password_expire" ] &&
1143f589320aSDevin Teske			cmd="$cmd -p '$_user_password_expire'"
1144f589320aSDevin Teske
1145f589320aSDevin Teske		# Execute the command
1146f589320aSDevin Teske		local retval err
1147f589320aSDevin Teske		if [ "$user_password_disable" ]; then
1148f589320aSDevin Teske			f_eval_catch -k err $funcname pw '%s -h -' "$cmd"
1149f589320aSDevin Teske		elif [ "$user_password" ]; then
1150f589320aSDevin Teske			err=$( echo "$user_password" | f_eval_catch -de \
1151f589320aSDevin Teske				$funcname pw '%s -h 0' "$cmd" 2>&1 )
1152f589320aSDevin Teske		else
1153f589320aSDevin Teske			f_eval_catch -k err $funcname pw '%s' "$cmd"
1154f589320aSDevin Teske		fi
1155f589320aSDevin Teske		retval=$?
1156f589320aSDevin Teske		if [ $retval -ne $SUCCESS ]; then
1157f589320aSDevin Teske			f_show_err "%s" "$err"
1158f589320aSDevin Teske			return $retval
1159f589320aSDevin Teske		fi
1160f589320aSDevin Teske
1161f589320aSDevin Teske		# Create home directory if desired
1162f589320aSDevin Teske		[ "${user_home_create:-$msg_no}" != "$msg_no" ] &&
1163f589320aSDevin Teske			f_user_create_homedir "$user_name"
1164f589320aSDevin Teske
1165f589320aSDevin Teske		# Copy dotfiles if desired
1166f589320aSDevin Teske		[ "${user_dotfiles_create:-$msg_no}" != "$msg_no" ] &&
1167f589320aSDevin Teske			f_user_copy_dotfiles "$user_name"
1168f589320aSDevin Teske	fi
1169f589320aSDevin Teske
1170f589320aSDevin Teske	f_dialog_title "$title"
1171f589320aSDevin Teske	$alert "$msg_login_updated"
1172f589320aSDevin Teske	f_dialog_title_restore
1173f589320aSDevin Teske	[ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
1174f589320aSDevin Teske
1175f589320aSDevin Teske	return $SUCCESS
1176f589320aSDevin Teske}
1177f589320aSDevin Teske
1178f589320aSDevin Teske############################################################ MAIN
1179f589320aSDevin Teske
1180f589320aSDevin Teskef_dprintf "%s: Successfully loaded." usermgmt/user.subr
1181f589320aSDevin Teske
1182f589320aSDevin Teskefi # ! $_USERMGMT_USER_SUBR
1183