xref: /freebsd/usr.sbin/bsdconfig/usermgmt/share/group_input.subr (revision bc3f5ec90bde2f3a5e4021d133c89793d68b8c73)
1if [ ! "$_USERMGMT_GROUP_INPUT_SUBR" ]; then _USERMGMT_GROUP_INPUT_SUBR=1
2#
3# Copyright (c) 2012 Ron McDowell
4# Copyright (c) 2012-2014 Devin Teske
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28# $FreeBSD$
29#
30############################################################ INCLUDES
31
32BSDCFG_SHARE="/usr/share/bsdconfig"
33. $BSDCFG_SHARE/common.subr || exit 1
34f_dprintf "%s: loading includes..." usermgmt/group_input.subr
35f_include $BSDCFG_SHARE/dialog.subr
36f_include $BSDCFG_SHARE/strings.subr
37
38BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
39f_include_lang $BSDCFG_LIBE/include/messages.subr
40f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
41
42############################################################ FUNCTIONS
43
44# f_input_group $group
45#
46# Given $group name or id, create the environment variables group_name,
47# group_gid, and group_members (and group_password is reset to NULL).
48#
49f_input_group()
50{
51	local funcname=f_input_group
52	local group="$1"
53
54	f_dprintf "$funcname: Getting info for group \`%s'" "$group"
55	eval "$( pw groupshow "$group" 2> /dev/null | awk -F: '
56	{
57		found = $1 != ""
58		printf "group_name='\'%s\''\n",    $1
59		printf "group_password=\n"
60		printf "group_gid='\'%s\''\n",     $3
61		printf "group_members='\'%s\''\n", $4
62		exit
63	}
64	END { if (!found) print "false" }' )"
65}
66
67# f_dialog_menu_group_list [$default]
68#
69# Allows the user to select a group from a list. Optionally, if present and
70# non-NULL, initially highlight $default group.
71#
72f_dialog_menu_group_list()
73{
74	local prompt=
75	local menu_list="
76		'X $msg_exit' ''
77	" # END-QUOTE
78	local defaultitem="$1"
79	local hline="$hline_alnum_punc_tab_enter"
80
81	# Add groups from group(5)
82	menu_list="$menu_list $( pw groupshow -a | awk -F: '
83		!/^[[:space:]]*(#|$)/ {
84			printf "'\'%s\'\ \'%s\''\n", $1, $1
85		}'
86	)"
87
88	local height width rows
89	eval f_dialog_menu_size height width rows \
90	                        \"\$DIALOG_TITLE\"     \
91	                        \"\$DIALOG_BACKTITLE\" \
92	                        \"\$prompt\"           \
93	                        \"\$hline\"            \
94	                        $menu_list
95
96	local menu_choice
97	menu_choice=$( eval $DIALOG \
98		--title \"\$DIALOG_TITLE\"         \
99		--backtitle \"\$DIALOG_BACKTITLE\" \
100		--hline \"\$hline\"                \
101		--ok-label \"\$msg_ok\"            \
102		--cancel-label \"\$msg_cancel\"    \
103		--default-item \"\$defaultitem\"   \
104		--menu \"\$prompt\"                \
105		$height $width $rows               \
106		$menu_list                         \
107		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
108	)
109	local retval=$?
110	f_dialog_menutag_store -s "$menu_choice"
111	return $retval
112}
113
114# f_dialog_input_group_name $var_to_set [$group_name]
115#
116# Allows the user to enter a name for a new group. If the user does not cancel
117# or press ESC, the $var_to_set variable will hold the newly-configured value
118# upon return.
119#
120f_dialog_input_group_name()
121{
122	local __var_to_set="$1" __name="$2"
123
124	#
125	# Loop until the user provides taint-free/valid input
126	#
127	local __input="$__name"
128	while :; do
129		# Return if user has either pressed ESC or chosen Cancel/No
130		f_dialog_input __input "$msg_group" "$__input" \
131		               "$hline_alnum_tab_enter" || return $?
132
133		# Check for no-change
134		if [ "$__input" = "$__name" ]; then
135			setvar "$__var_to_set" "$__input"
136			return $DIALOG_OK
137		fi
138
139		# Check for NULL entry
140		if [ ! "$__input" ]; then
141			f_show_msg "$msg_group_is_empty"
142			continue
143		fi
144
145		# Check for invalid entry
146		case "$__input" in [!a-zA-Z]*)
147			f_show_msg "$msg_group_must_start_with_letter"
148			continue
149		esac
150
151		# Check for duplicate entry
152		if f_quietly pw groupshow -n "$__input"; then
153			f_show_msg "$msg_group_already_used" "$__input"
154			continue
155		fi
156
157		setvar "$__var_to_set" "$__input"
158		break
159	done
160
161	return $DIALOG_OK
162}
163
164# f_dialog_input_group_password $var_to_set $dvar_to_set
165#
166# Prompt the user to enter a password (twice). If the user does not cancel or
167# press ESC, $var_to_set will hold the confirmed user entry. Otherwise, if the
168# user cancels or enters a NULL password (twice), they are given the choice to
169# disable password authentication for the given group, wherein $dvar_to_set has
170# a value of 1 to indicate password authentication should be disabled.
171#
172f_dialog_input_group_password()
173{
174	local __var_to_set="$1" __dvar_to_set="$2"
175	local __prompt1="$msg_group_password"
176	local __prompt2="$msg_reenter_group_password"
177	local __hline="$hline_alnum_punc_tab_enter"
178
179	local __height1 __width1
180	f_dialog_inputbox_size __height1 __width1 \
181	        	"$DIALOG_TITLE"     \
182	        	"$DIALOG_BACKTITLE" \
183	        	"$__prompt1"        \
184	        	""                  \
185	        	"$__hline"
186
187	local __height2 __width2
188	f_dialog_inputbox_size __height2 __width2 \
189	        	"$DIALOG_TITLE"     \
190	        	"$DIALOG_BACKTITLE" \
191	        	"$__prompt2"        \
192	        	""                  \
193	        	"$__hline"
194
195	#
196	# Loop until the user provides taint-free/valid input
197	#
198	local __retval __password1 __password2
199	while :; do
200		__password1=$( $DIALOG \
201			--title "$DIALOG_TITLE"         \
202			--backtitle "$DIALOG_BACKTITLE" \
203			--hline "$__hline"              \
204			--ok-label "$msg_ok"            \
205			--cancel-label "$msg_cancel"    \
206			--insecure                      \
207			--passwordbox "$__prompt1"      \
208			$__height1 $__width1            \
209			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
210		)
211		__retval=$?
212		debug= f_dialog_line_sanitize __password1
213
214		# Return if user has either pressed ESC or chosen Cancel/No
215		[ $__retval -eq $DIALOG_OK ] || return $__retval
216
217		__password2=$( $DIALOG \
218			--title "$DIALOG_TITLE"         \
219			--backtitle "$DIALOG_BACKTITLE" \
220			--hline "$__hline"              \
221			--ok-label "$msg_ok"            \
222			--cancel-label "$msg_cancel"    \
223			--insecure                      \
224			--passwordbox "$__prompt2"      \
225			$__height2 $__width2            \
226			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
227		)
228		__retval=$?
229		debug= f_dialog_line_sanitize __password2
230
231		# Return if user has either pressed ESC or chosen Cancel/No
232		[ $__retval -eq $DIALOG_OK ] || return $__retval
233
234		# Check for password mismatch
235		if [ "$__password1" != "$__password2" ]; then
236			f_show_msg "$msg_group_passwords_do_not_match"
237			continue
238		fi
239
240		# Check for NULL entry
241		if [ ! "$__password1" ]; then
242			f_dialog_yesno "$msg_disable_password_auth_for_group"
243			__retval=$?
244			if [ $__retval -eq $DIALOG_ESC ]; then
245				return $__retval
246			elif [ $__retval -eq $DIALOG_OK ]; then
247				setvar "$__dvar_to_set" 1
248			else
249				continue # back to password prompt
250			fi
251		else
252			setvar "$__dvar_to_set" ""
253		fi
254
255		setvar "$__var_to_set" "$__password1"
256		break
257	done
258
259	return $DIALOG_OK
260}
261
262# f_dialog_input_group_gid $var_to_set [$group_gid]
263#
264# Allow the user to enter a new GID for a given group. If the user does not
265# cancel or press ESC, the $var_to_set variable will hold the newly-configured
266# value upon return.
267#
268f_dialog_input_group_gid()
269{
270	local __var_to_set="$1" __input="$2"
271
272	# Return if user has either pressed ESC or chosen Cancel/No
273	f_dialog_input __input "$msg_group_id_leave_empty_for_default" \
274	               "$__input" "$hline_num_tab_enter" || return $?
275
276	setvar "$__var_to_set" "$__input"
277	return $DIALOG_OK
278}
279
280# f_dialog_input_group_members $var_to_set [$group_members]
281#
282# Allow the user to modify a list of members for a given group. If the user
283# does not cancel or press ESC, the $var_to_set variable will hold the newly-
284# configured value upon return.
285#
286f_dialog_input_group_members()
287{
288	local __var_to_set="$1" __input="$2"
289	local __prompt="$msg_group_members:"
290	local __menu_list="
291		'X' '$msg_continue'
292		'1' '$msg_select_group_members_from_list'
293		'2' '$msg_enter_group_members_manually'
294	" # END-QUOTE
295	local __defaultitem=
296	local __hline="$hline_num_arrows_tab_enter"
297
298	local __mheight __mwidth __mrows
299	eval f_dialog_menu_size __mheight __mwidth __mrows \
300	                        \"\$DIALOG_TITLE\"     \
301	                        \"\$DIALOG_BACKTITLE\" \
302	                        \"\$__prompt\"         \
303	                        \"\$__hline\"          \
304	                        $menu_list
305
306	local __menu_choice __retval
307	while :; do
308		__menu_choice=$( eval $DIALOG \
309			--title \"\$DIALOG_TITLE\"         \
310			--backtitle \"\$DIALOG_BACKTITLE\" \
311			--hline \"\$__hline\"              \
312			--ok-label \"\$msg_ok\"            \
313			--cancel-label \"\$msg_cancel\"    \
314			--default-item \"\$__defaultitem\" \
315			--menu \"\$__prompt\"              \
316			$__mheight $__mwidth $__mrows      \
317			$__menu_list                       \
318			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
319		)
320		__retval=$?
321		f_dialog_data_sanitize __menu_choice
322		__defaultitem="$__menu_choice"
323		f_dprintf "retval=%u menu_choice=[%s]" \
324		          $__retval "$__menu_choice"
325
326		# Return if user has either pressed ESC or chosen Cancel/No
327		[ $__retval -eq $DIALOG_OK ] || return $__retval
328
329		local __group_members
330		case "$__menu_choice" in
331		X) # Exit
332			break ;;
333		1) # Select Group Members from a list
334			local __user_list __length=0 __user __check_list=
335			__user_list=$( pw usershow -a |
336				awk -F: '!/^[[:space:]]*(#|$)/{print $1}' )
337			while [ $__length -ne ${#__user_list} ]; do
338				__user="${__user_list%%$NL*}" # First line
339
340				# Format of a checklist entry: tag item status
341				__check_list="$__check_list '$__user' ''"
342				case "$__input" in
343				"$__user"|"$__user",*|*,"$__user",*|*,"$__user")
344					__check_list="$__check_list on" ;;
345				*)
346					__check_list="$__check_list off"
347				esac
348
349				__length=${#__user_list}
350				__user_list="${__user_list#*$NL}" # Kill line
351			done
352
353			local __cheight __cwidth __crows
354			eval f_dialog_checklist_size \
355				__cheight __cwidth __crows \
356				\"\$DIALOG_TITLE\"     \
357				\"\$DIALOG_BACKTITLE\" \
358				\"\$__prompt\"         \
359				\"\$__hline\"          \
360				$__check_list
361			__group_members=$( eval $DIALOG \
362				--title \"\$DIALOG_TITLE\"         \
363				--backtitle \"\$DIALOG_BACKTITLE\" \
364				--separate-output                  \
365				--hline \"\$__hline\"              \
366				--ok-label \"\$msg_ok\"            \
367				--cancel-label \"\$msg_cancel\"    \
368				--checklist \"\$__prompt\"         \
369				$__cheight $__cwidth $__crows      \
370				$__check_list                      \
371				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
372			) || continue
373				# Return to previous menu if user either
374				# pressed ESC or chose Cancel/No
375			f_dialog_data_sanitize __group_members
376
377			#
378			# Convert the newline separated list into a comma-
379			# separated one so that if the user switches over to
380			# manual editing, list reflects checklist selections
381			#
382			f_replaceall "$__group_members" "[$NL]" "," __input
383			;;
384		2) # Enter Group Members manually
385			local __prompt2="$msg_group_members"
386			__prompt2="$__prompt2 ($msg_separated_by_commas)"
387
388			f_dialog_input __group_members \
389			               "$__prompt2" "$__input" \
390			               "$hline_num_tab_enter" || continue
391				# Return to previous menu if user either
392				# pressed ESC or chose Cancel/No
393
394			__input="$__group_members"
395			;;
396		esac
397	done
398
399	setvar "$__var_to_set" "$__input"
400	return $DIALOG_OK
401}
402
403# f_dialog_menu_group_add [$defaultitem]
404#
405# Present a menu detailing the properties of a group that is about to be added.
406# The user's menu choice is available using f_dialog_menutag_fetch(). Returns
407# success unless the user chose Cancel or pressed ESC. Data to display is taken
408# from environment variables group_name, group_gid, and group_members. If
409# $defaultitem is present and non-NULL, initially highlight the item in the
410# menu.
411#
412f_dialog_menu_group_add()
413{
414	local prompt="$msg_save_exit_or_cancel"
415	local menu_list # Calculated below
416	local defaultitem="$1"
417	local hline="$hline_arrows_tab_enter"
418
419	menu_list="
420		'X' '$msg_add/$msg_exit'
421		'1' '$msg_group: $group_name'
422		'2' '$msg_password: -----'
423		'3' '$msg_group_id: $group_gid'
424		'4' '$msg_group_members: $group_members'
425	" # END-QUOTE
426
427	local height width rows
428	eval f_dialog_menu_size height width rows \
429	                        \"\$DIALOG_TITLE\"     \
430	                        \"\$DIALOG_BACKTITLE\" \
431	                        \"\$prompt\"           \
432	                        \"\$hline\"            \
433	                        $menu_list
434
435	local menu_choice
436	menu_choice=$( eval $DIALOG \
437		--title \"\$DIALOG_TITLE\"         \
438		--backtitle \"\$DIALOG_BACKTITLE\" \
439		--hline \"\$hline\"                \
440		--ok-label \"\$msg_ok\"            \
441		--cancel-label \"\$msg_cancel\"    \
442		--default-item \"\$defaultitem\"   \
443		--menu \"\$prompt\"                \
444		$height $width $rows               \
445		$menu_list                         \
446		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
447	)
448	local retval=$?
449	f_dialog_data_sanitize menu_choice
450	f_dialog_menutag_store "$menu_choice"
451	return $retval
452}
453
454# f_dialog_menu_group_delete $group [$defaultitem]
455#
456# Present a menu detailing the properties of a group that is about to be
457# deleted. The user's menu choice is available using f_dialog_menutag_fetch().
458# Returns success unless the user chose Cancel or pressed ESC. Data to display
459# is populated automatically from the system accounting database for the given
460# $group argument. If $defaultitem is present and non-NULL, initially highlight
461# the item in the menu.
462#
463f_dialog_menu_group_delete()
464{
465	local prompt="$msg_delete_exit_or_cancel"
466	local menu_list # Calculated below
467	local defaultitem="$2"
468	local hline="$hline_arrows_tab_enter"
469
470	local group_name group_password group_gid group_members
471	f_input_group "$1"
472
473	menu_list="
474		'X' '$msg_delete/$msg_exit'
475		'1' '$msg_group: $group_name'
476		'-' '$msg_password: -----'
477		'-' '$msg_group_id: $group_gid'
478		'-' '$msg_group_members: $group_members'
479	" # END-QUOTE
480
481	local height width rows
482	eval f_dialog_menu_size height width rows \
483	                        \"\$DIALOG_TITLE\"     \
484	                        \"\$DIALOG_BACKTITLE\" \
485	                        \"\$prompt\"           \
486	                        \"\$hline\"            \
487	                        $menu_list
488
489	local menu_choice
490	menu_choice=$( eval $DIALOG \
491		--title \"\$DIALOG_TITLE\"         \
492		--backtitle \"\$DIALOG_BACKTITLE\" \
493		--hline \"\$hline\"                \
494		--ok-label \"\$msg_ok\"            \
495		--cancel-label \"\$msg_cancel\"    \
496		--default-item \"\$defaultitem\"   \
497		--menu \"\$prompt\"                \
498		$height $width $rows               \
499		$menu_list                         \
500		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
501	)
502	local retval=$?
503	f_dialog_data_sanitize menu_choice
504	f_dialog_menutag_store "$menu_choice"
505	return $retval
506}
507
508# f_dialog_menu_group_edit [$defaultitem]
509#
510# Present a menu detailing the properties of a group that is about to be
511# modified. The user's menu choice is available using f_dialog_menutag_fetch().
512# Returns success unless the user chose Cancel or pressed ESC. Data to display
513# is taken from environment variables group_name, group_gid, and group_members.
514# If $defaultitem is present and non-NULL, initially highlight the item in the
515# menu.
516#
517f_dialog_menu_group_edit()
518{
519	local prompt="$msg_save_exit_or_cancel"
520	local menu_list # Calculated below
521	local defaultitem="$1"
522	local hline="$hline_arrows_tab_enter"
523
524	menu_list="
525		'X' '$msg_save/$msg_exit'
526		'1' '$msg_group: $group_name'
527		'2' '$msg_password: -----'
528		'3' '$msg_group_id: $group_gid'
529		'4' '$msg_group_members: $group_members'
530	" # END-QUOTE
531
532	local height width rows
533	eval f_dialog_menu_size height width rows \
534	                        \"\$DIALOG_TITLE\"     \
535	                        \"\$DIALOG_BACKTITLE\" \
536	                        \"\$prompt\"           \
537	                        \"\$hline\"            \
538	                        $menu_list
539
540	local menu_choice
541	menu_choice=$( eval $DIALOG \
542		--title \"\$DIALOG_TITLE\"         \
543		--backtitle \"\$DIALOG_BACKTITLE\" \
544		--hline \"\$hline\"                \
545		--ok-label \"\$msg_ok\"            \
546		--cancel-label \"\$msg_cancel\"    \
547		--default-item \"\$defaultitem\"   \
548		--menu \"\$prompt\"                \
549		$height $width $rows               \
550		$menu_list                         \
551		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
552	)
553	local retval=$?
554	f_dialog_data_sanitize menu_choice
555	f_dialog_menutag_store "$menu_choice"
556	return $retval
557}
558
559############################################################ MAIN
560
561f_dprintf "%s: Successfully loaded." usermgmt/group_input.subr
562
563fi # ! $_USERMGMT_GROUP_INPUT_SUBR
564