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