1 if [ ! "$_USERMGMT_USER_INPUT_SUBR" ]; then _USERMGMT_USER_INPUT_SUBR=1
3 # Copyright (c) 2012 Ron McDowell
4 # Copyright (c) 2012-2014 Devin Teske
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
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.
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
30 ############################################################ INCLUDES
32 BSDCFG_SHARE="/usr/share/bsdconfig"
33 . $BSDCFG_SHARE/common.subr || exit 1
34 f_dprintf "%s: loading includes..." usermgmt/user_input.subr
35 f_include $BSDCFG_SHARE/dialog.subr
36 f_include $BSDCFG_SHARE/strings.subr
38 BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
39 f_include_lang $BSDCFG_LIBE/include/messages.subr
40 f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
42 ############################################################ CONFIGURATION
45 # Default location of shells(5)
47 : ${ETC_SHELLS:=/etc/shells}
49 ############################################################ FUNCTIONS
51 # f_get_member_groups $var_to_set $user
53 # Get a list of additional groups $user is a member of in group(5).
57 f_replaceall "$( pw groupshow -a | awk -F: -v user="$2" '{
58 if (!split($4, users, /,/)) next
59 for (u in users) if (users[u] == user) { print $1; next }
60 }' )" "[$NL]" "," "$1"
65 # Given $user name or id, create the environment variables user_name, user_uid,
66 # user_gid, user_class, user_password_expire, user_account_expire, user_gecos,
67 # user_home_dir, user_shell, and user_member_groups (and user_password is reset
72 local funcname=f_input_user
75 f_dprintf "$funcname: Getting info for user \`%s'" "$user"
76 eval "$( pw usershow "$user" 2> /dev/null | awk -F: '
77 function set_value(var, value) {
78 gsub(/'\''/, "'\''\\'\'\''", value)
79 printf "user_%s='\'%s\''\n", var, value
83 set_value("name", $1 )
84 set_value("password", "" )
87 set_value("class", $5 )
88 set_value("password_expire", $6 )
89 set_value("account_expire", $7 )
90 set_value("gecos", $8 )
91 set_value("home_dir", $9 )
92 set_value("shell", $10)
95 END { if (!found) print "false" }' )"
98 f_dprintf "$funcname: Getting group memberships for user \`%s'" "$user"
99 f_get_member_groups user_member_groups "$user"
104 # f_dialog_menu_user_list [$default]
106 # Allows the user to select a login from a list. Optionally, if present and
107 # non-NULL, initially highlight $default user.
109 f_dialog_menu_user_list()
115 local defaultitem="$1"
116 local hline="$hline_alnum_punc_tab_enter"
118 # Add users from passwd(5)
119 menu_list="$menu_list $( pw usershow -a | awk -F: '
120 function mprint(tag, item) {
121 gsub(/'\''/, "'\''\\'\'\''", tag)
122 gsub(/'\''/, "'\''\\'\'\''", item)
123 printf "'\'%s\'\ \'%s\''\n", tag, item
125 !/^[[:space:]]*(#|$)/ { mprint($1, $8) }
128 local height width rows
129 eval f_dialog_menu_size height width rows \
131 \"\$DIALOG_BACKTITLE\" \
137 menu_choice=$( eval $DIALOG \
138 --title \"\$DIALOG_TITLE\" \
139 --backtitle \"\$DIALOG_BACKTITLE\" \
140 --hline \"\$hline\" \
141 --ok-label \"\$msg_ok\" \
142 --cancel-label \"\$msg_cancel\" \
143 --default-item \"\$defaultitem\" \
144 --menu \"\$prompt\" \
145 $height $width $rows \
147 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
150 f_dialog_menutag_store -s "$menu_choice"
154 # f_dialog_input_member_groups $var_to_set [$member_groups]
156 # Allows the user to edit group memberships for a given user. If the user does
157 # not cancel or press ESC, the $var_to_set variable will hold the newly-
158 # configured value upon return.
160 f_dialog_input_member_groups()
162 local __var_to_set="$1" __input="$2"
163 local __prompt="$msg_member_of_groups"
166 '1' '$msg_select_groups_from_list'
167 '2' '$msg_enter_groups_manually'
170 local __hline="$hline_alnum_space_tab_enter"
172 local __mheight __mwidth __mrows
173 eval f_dialog_menu_size __mheight __mwidth __mrows \
175 \"\$DIALOG_BACKTITLE\" \
180 local __menu_choice __retval
182 __menu_choice=$( eval $DIALOG \
183 --title \"\$DIALOG_TITLE\" \
184 --backtitle \"\$DIALOG_BACKTITLE\" \
185 --hline \"\$__hline\" \
186 --ok-label \"\$msg_ok\" \
187 --cancel-label \"\$msg_cancel\" \
188 --default-item \"\$__defaultitem\" \
189 --menu \"\$__prompt\" \
190 $__mheight $__mwidth $__mrows \
192 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
195 f_dialog_data_sanitize __menu_choice
196 __defaultitem="$__menu_choice"
197 f_dprintf "retval=%u menu_choice=[%s]" \
198 $__retval "$__menu_choice"
200 # Return if user has either pressed ESC or chosen Cancel/No
201 [ $__retval -eq $DIALOG_OK ] || return $__retval
203 local __member_groups
204 case "$__menu_choice" in
207 1) # Select Groups from a list
208 local __check_list= # Calculated below
209 local __group_list __g __grp __length=0
210 __group_list=$( pw groupshow -a |
211 awk -F: '!/^[[:space:]]*(#|$)/{print $1}' )
212 while [ $__length -ne ${#__group_list} ]; do
213 __g="${__group_list%%$NL*}" # First line
214 f_shell_escape "$__g" __grp
216 # Format of a checklist entry: tag item status
217 # NB: Setting both tag/item to group name below
218 __check_list="$__check_list '$__grp' '$__grp'"
220 "$__g"|"$__g",*|*,"$__g",*|*,"$__g")
221 __check_list="$__check_list on" ;;
223 __check_list="$__check_list off"
226 __length=${#__group_list}
227 __group_list="${__group_list#*$NL}" # Kill line
230 local __cheight __cwidth __crows
232 eval f_dialog_checklist_size \
233 __cheight __cwidth __crows \
235 \"\$DIALOG_BACKTITLE\" \
239 __member_groups=$( eval $DIALOG \
240 --title \"\$DIALOG_TITLE\" \
241 --backtitle \"\$DIALOG_BACKTITLE\" \
243 --hline \"\$__hline\" \
244 --ok-label \"\$msg_ok\" \
245 --cancel-label \"\$msg_cancel\" \
246 --checklist \"\$__prompt\" \
247 $__cheight $__cwidth $__crows \
249 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
251 # Return to previous menu if user either
252 # pressed ESC or chose Cancel/No
253 f_dialog_data_sanitize __member_groups
256 # Convert the newline separated list into a comma-
257 # separated one so that if the user switches over to
258 # manual editing, list reflects checklist selections
260 f_replaceall "$__member_groups" "[$NL]" "," __input
262 2) # Enter Groups manually
263 local __prompt2="$msg_groups"
264 __prompt2="$__prompt2 ($msg_separated_by_commas)"
266 f_dialog_input __member_groups \
267 "$__prompt2" "$__input" \
268 "$hline_num_tab_enter" || continue
269 # Return to previous menu if user either
270 # pressed ESC or chose Cancel/No
273 # Validate each of the groups the user has entered
275 local __all_groups_valid=1 __grp __grp_list
276 f_replaceall "$__member_groups" "," " " __grp_list
277 for __grp in $__grp_list; do
278 if ! f_quietly pw groupshow -n "$__grp"; then
279 f_show_msg "$msg_group_not_found" \
285 [ "$__all_groups_valid" ] || continue
287 __input="$__member_groups"
292 setvar "$__var_to_set" "$__input"
296 # f_dialog_input_name $var_to_set [$name]
298 # Allows the user to enter a new username for a given user. If the user does
299 # not cancel or press ESC, the $var_to_set variable will hold the newly-
300 # configured value upon return.
302 f_dialog_input_name()
304 local __var_to_set="$1" __name="$2"
307 # Loop until the user provides taint-free/valid input
309 local __input="$__name"
311 # Return if user has either pressed ESC or chosen Cancel/No
312 f_dialog_input __input "$msg_login" "$__input" \
313 "$hline_alnum_tab_enter" || return $?
315 # Check for no-change
316 if [ "$__input" = "$__name" ]; then
317 setvar "$__var_to_set" "$__input"
321 # Check for NULL entry
322 if [ ! "$__input" ]; then
323 f_show_msg "$msg_login_is_empty"
327 # Check for invalid entry
328 case "$__input" in [!a-zA-Z]*)
329 f_show_msg "$msg_login_must_start_with_letter"
333 # Check for duplicate entry
334 if f_quietly pw usershow -n "$__input"; then
335 f_show_msg "$msg_login_already_used" "$__input"
339 setvar "$__var_to_set" "$__input"
346 # f_dialog_input_password $var_to_set $dvar_to_set
348 # Prompt the user to enter a password (twice). If the user does not cancel or
349 # press ESC, $var_to_set will hold the confirmed user entry. Otherwise, if the
350 # user cancels or enters a NULL password (twice), they are given the choice to
351 # disable password authentication for the given login, wherein $dvar_to_set has
352 # a value of 1 to indicate password authentication should be disabled.
354 f_dialog_input_password()
356 local __var_to_set="$1" __dvar_to_set="$2"
357 local __prompt1="$msg_password"
358 local __prompt2="$msg_reenter_password"
359 local __hline="$hline_alnum_punc_tab_enter"
361 local __height1 __width1
362 f_dialog_inputbox_size __height1 __width1 \
364 "$DIALOG_BACKTITLE" \
368 local __height2 __width2
369 f_dialog_inputbox_size __height2 __width2 \
371 "$DIALOG_BACKTITLE" \
377 # Loop until the user provides taint-free/valid input
379 local __retval __password1 __password2
381 __password1=$( $DIALOG \
382 --title "$DIALOG_TITLE" \
383 --backtitle "$DIALOG_BACKTITLE" \
385 --ok-label "$msg_ok" \
386 --cancel-label "$msg_cancel" \
388 --passwordbox "$__prompt1" \
389 $__height1 $__width1 \
390 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
392 # Return if user either pressed ESC or chose Cancel/No
393 debug= f_dialog_line_sanitize __password1
395 __password2=$( $DIALOG \
396 --title "$DIALOG_TITLE" \
397 --backtitle "$DIALOG_BACKTITLE" \
399 --ok-label "$msg_ok" \
400 --cancel-label "$msg_cancel" \
402 --passwordbox "$__prompt2" \
403 $__height2 $__width2 \
404 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
406 # Return if user either pressed ESC or chose Cancel/No
407 debug= f_dialog_line_sanitize __password2
409 # Check for password mismatch
410 if [ "$__password1" != "$__password2" ]; then
411 f_show_msg "$msg_passwords_do_not_match"
415 # Check for NULL entry
416 if [ ! "$__password1" ]; then
417 f_dialog_yesno "$msg_disable_password_auth_for_account"
419 if [ $__retval -eq $DIALOG_ESC ]; then
421 elif [ $__retval -eq $DIALOG_OK ]; then
422 setvar "$__dvar_to_set" 1
424 continue # back to password prompt
427 setvar "$__dvar_to_set" ""
430 setvar "$__var_to_set" "$__password1"
437 # f_dialog_input_gecos $var_to_set [$gecos]
439 # Allow the user to enter new GECOS information for a given user. This
440 # information is commonly used to store the ``Full Name'' of the user. If the
441 # user does not cancel or press ESC, the $var_to_set variable will hold the
442 # newly-configured value upon return.
444 f_dialog_input_gecos()
446 local __var_to_set="$1" __input="$2"
448 # Return if user has either pressed ESC or chosen Cancel/No
449 f_dialog_input __input "$msg_full_name" "$__input" \
450 "$hline_alnum_punc_tab_enter" || return $?
452 setvar "$__var_to_set" "$__input"
456 # f_dialog_input_uid $var_to_set [$uid]
458 # Allow the user to enter a new UID for a given user. If the user does not
459 # cancel or press ESC, the $var_to_set variable will hold the newly-configured
464 local __var_to_set="$1" __input="$2"
466 # Return if user has either pressed ESC or chosen Cancel/No
467 f_dialog_input __input "$msg_user_id_leave_empty_for_default" \
468 "$__input" "$hline_num_tab_enter" || return $?
470 setvar "$__var_to_set" "$__input"
474 # f_dialog_input_gid $var_to_set [$gid]
476 # Allow the user to enter a new primary GID for a given user. If the user does
477 # not cancel or press ESC, the $var_to_set variable will hold the newly-
478 # configured value upon return.
482 local __var_to_set="$1" __input="$2"
484 # Return if user has either pressed ESC or chosen Cancel/No
485 f_dialog_input __input "$msg_group_id_leave_empty_for_default" \
486 "$__input" "$hline_num_tab_enter" || return $?
488 setvar "$__var_to_set" "$__input"
492 # f_dialog_input_class $var_to_set [$class]
494 # Allow the user to enter a new login class for a given user. If the user does
495 # not cancel or press ESC, the $var_to_set variable will hold the newly-
496 # configured value upon return.
498 f_dialog_input_class()
500 local __var_to_set="$1" __input="$2"
502 # Return if user has either pressed ESC or chosen Cancel/No
503 f_dialog_input __input "$msg_login_class" "$__input" \
504 "$hline_alnum_tab_enter" || return $?
506 setvar "$__var_to_set" "$__input"
510 # f_dialog_input_expire_password $var_to_set [$seconds]
512 # Allow the user to enter a date/time (in number-of-seconds since the `epoch')
513 # for when a given user's password must be changed. If the user does not cancel
514 # or press ESC, the $var_to_set variable will hold the newly-configured value
517 f_dialog_input_expire_password()
519 local __var_to_set="$1" __input="$2"
520 local __prompt="$msg_password_expires_on"
522 '1' '$msg_password_does_not_expire'
523 '2' '$msg_edit_date_time_with_a_calendar'
524 '3' '$msg_enter_value_manually'
526 local __defaultitem= # Calculated below
527 local __hline="$hline_num_arrows_tab_enter"
529 local __mheight __mwidth __mrows
530 eval f_dialog_menu_size __mheight __mwidth __mrows \
532 \"\$DIALOG_BACKTITLE\" \
536 local __cheight __cwidth
537 f_dialog_calendar_size __cheight __cwidth \
539 "$DIALOG_BACKTITLE" \
542 local __theight __twidth
543 f_dialog_timebox_size __theight __twidth \
545 "$DIALOG_BACKTITLE" \
550 # Loop until the user provides taint-free/cancellation-free input
552 local __retval __date_type
554 __date_type=$( eval $DIALOG \
555 --title \"\$DIALOG_TITLE\" \
556 --backtitle \"\$DIALOG_BACKTITLE\" \
557 --hline \"\$__hline\" \
558 --default-item \"\$__defaultitem\" \
559 --ok-label \"\$msg_ok\" \
560 --cancel-label \"\$msg_cancel\" \
561 --menu \"\$__prompt\" \
562 $__mheight $__mwidth $__mrows \
564 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
567 f_dialog_data_sanitize __date_type
568 __defaultitem="$__date_type"
569 f_dprintf "retval=%u date_type=[%s]" $__retval "$__date_type"
571 # Return if user has either pressed ESC or chosen Cancel/No
572 [ $__retval -eq $DIALOG_OK ] || return $__retval
574 case "$__date_type" in
575 1) # Password does not expire
578 2) # Edit date/time with a calendar
579 local __input_date __input_time __ret_date __ret_time
581 local __seconds="$__input"
582 { f_isinteger "$__seconds" && [ $__seconds -gt 0 ]; } ||
584 __input_date=$( date -j -f "%s" -- "$__seconds" \
585 "+%d %m %Y" 2> /dev/null )
586 __ret_date=$( eval $DIALOG \
587 --title \"\$DIALOG_TITLE\" \
588 --backtitle \"\$DIALOG_BACKTITLE\" \
589 --hline \"\$__hline\" \
590 --ok-label \"\$msg_ok\" \
591 --cancel-label \"\$msg_cancel\" \
592 --calendar \"\$__prompt\" \
593 $__cheight $__cwidth \
595 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
598 f_dialog_data_sanitize __ret_date
599 f_dprintf "retval=%u ret_date=[%s]" \
600 $__retval "$__ret_date"
602 # Return to menu if either ESC or Cancel/No
603 [ $__retval -eq $DIALOG_OK ] || continue
606 [ "$__seconds" ] && __input_time=$( date -j \
607 -f %s -- "$__input" "+%H %M %S" 2> /dev/null )
608 __ret_time=$( eval $DIALOG \
609 --title \"\$DIALOG_TITLE\" \
610 --backtitle \"\$DIALOG_BACKTITLE\" \
611 --hline \"\$__hline\" \
612 --ok-label \"\$msg_ok\" \
613 --cancel-label \"\$msg_cancel\" \
614 --timebox \"\$__prompt\" \
615 $__theight $__twidth \
617 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
620 f_dialog_data_sanitize __ret_time
621 f_dprintf "retval=%u ret_time=[%s]" \
622 $__retval "$__ret_time"
624 # Return to menu if either ESC or Cancel/No
625 [ $__retval -eq $DIALOG_OK ] || continue
627 __input=$( date -j -f "%d/%m/%Y %T" -- \
628 "$__ret_date $__ret_time" +%s 2> /dev/null )
629 f_dprintf "input=[%s]" "$__input"
632 3) # Enter value manually
633 local __msg __new_input
634 f_sprintf __msg "$msg_password_expire_manual_edit" \
635 "$( date -r 0 "+%c %Z" )"
637 # Return to menu if either ESC or Cancel/No
638 f_dialog_input __new_input \
639 "$__msg" "$__input" "$__hline" || continue
641 __input="$__new_input"
642 f_dprintf "input=[%s]" "$__input"
649 setvar "$__var_to_set" "$__input"
653 # f_dialog_input_expire_account $var_to_set [$seconds]
655 # Allow the user to enter a date/time (in number-of-seconds since the `epoch')
656 # for when a given user's account should become expired. If the user does not
657 # cancel or press ESC, the $var_to_set variable will hold the newly-configured
660 f_dialog_input_expire_account()
662 local __var_to_set="$1" __input="$2"
663 local __prompt="$msg_account_expires_on"
665 '1' '$msg_account_does_not_expire'
666 '2' '$msg_edit_date_time_with_a_calendar'
667 '3' '$msg_enter_value_manually'
669 local __defaultitem= # Calculated below
670 local __hline="$hline_num_arrows_tab_enter"
672 local __mheight __mwidth __mrows
673 eval f_dialog_menu_size __mheight __mwidth __mrows \
675 \"\$DIALOG_BACKTITLE\" \
679 local __cheight __cwidth
680 f_dialog_calendar_size __cheight __cwidth \
682 "$DIALOG_BACKTITLE" \
685 local __theight __twidth
686 f_dialog_timebox_size __theight __twidth \
688 "$DIALOG_BACKTITLE" \
693 # Loop until the user provides taint-free/cancellation-free input
695 local __retval __date_type
697 __date_type=$( eval $DIALOG \
698 --title \"\$DIALOG_TITLE\" \
699 --backtitle \"\$DIALOG_BACKTITLE\" \
700 --hline \"\$__hline\" \
701 --default-item \"\$__defaultitem\" \
702 --ok-label \"\$msg_ok\" \
703 --cancel-label \"\$msg_cancel\" \
704 --menu \"\$__prompt\" \
705 $__mheight $__mwidth $__mrows \
707 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
710 f_dialog_data_sanitize __date_type
711 __defaultitem="$__date_type"
712 f_dprintf "retval=%u date_type=[%s]" $__retval "$__date_type"
714 # Return if user has either pressed ESC or chosen Cancel/No
715 [ $__retval -eq $DIALOG_OK ] || return $__retval
717 case "$__date_type" in
718 1) # Account does not expire
721 2) # Edit date/time with a calendar
722 local __input_date __input_time __ret_date __ret_time
724 local __seconds="$__input"
725 { f_isinteger "$__seconds" && [ $__seconds -gt 0 ]; } ||
727 __input_date=$( date -j -f "%s" -- "$__seconds" \
728 "+%d %m %Y" 2> /dev/null )
729 __ret_date=$( eval $DIALOG \
730 --title \"\$DIALOG_TITLE\" \
731 --backtitle \"\$DIALOG_BACKTITLE\" \
732 --hline \"\$__hline\" \
733 --ok-label \"\$msg_ok\" \
734 --cancel-label \"\$msg_cancel\" \
735 --calendar \"\$__prompt\" \
736 $__cheight $__cwidth \
738 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
741 f_dialog_data_sanitize __ret_date
742 f_dprintf "retval=%u ret_date=[%s]" \
743 $__retval "$__ret_date"
745 # Return to menu if either ESC or Cancel/No
746 [ $__retval -eq $DIALOG_OK ] || continue
749 [ "$__seconds" ] && __input_time=$( date -j \
750 -f %s -- "$__input" "+%H %M %S" 2> /dev/null )
751 __ret_time=$( eval $DIALOG \
752 --title \"\$DIALOG_TITLE\" \
753 --backtitle \"\$DIALOG_BACKTITLE\" \
754 --hline \"\$__hline\" \
755 --ok-label \"\$msg_ok\" \
756 --cancel-label \"\$msg_cancel\" \
757 --timebox \"\$__prompt\" \
758 $__theight $__twidth \
760 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
763 f_dialog_data_sanitize __ret_time
764 f_dprintf "retval=%u ret_time=[%s]" \
765 $__retval "$__ret_time"
767 # Return to menu if either ESC or Cancel/No
768 [ $__retval -eq $DIALOG_OK ] || continue
770 __input=$( date -j -f "%d/%m/%Y %T" -- \
771 "$ret_date $ret_time" +%s 2> /dev/null )
772 f_dprintf "input=[%s]" "$__input"
775 3) # Enter value manually
776 local __msg __new_input
777 f_sprintf __msg "$msg_account_expire_manual_edit" \
778 "$( date -r 0 "+%c %Z" )"
780 # Return to menu if either ESC or Cancel/No
781 f_dialog_input __new_input \
782 "$__msg" "$__input" "$__hline" || continue
784 __input="$__new_input"
785 f_dprintf "input=[%s]" "$__input"
792 setvar "$__var_to_set" "$__input"
796 # f_dialog_input_home_dir $var_to_set [$home_dir]
798 # Allow the user to enter a new home directory for a given login. If the user
799 # does not cancel or press ESC, the $var_to_set variable will hold the newly-
800 # configured value upon return.
802 f_dialog_input_home_dir()
804 local __var_to_set="$1" __input="$2"
806 # Return if user has either pressed ESC or chosen Cancel/No
807 f_dialog_input __input "$msg_home_directory" "$__input" \
808 "$hline_alnum_punc_tab_enter" || return $?
810 setvar "$__var_to_set" "$__input"
814 # f_dialog_input_home_create $var_to_set
816 # Prompt the user to confirm creation of a given login's home directory. If the
817 # user does not cancel (by choosing "No") or press ESC, the $var_to_set
818 # variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
819 # variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
821 f_dialog_input_home_create()
823 local __var_to_set="$1"
825 f_dialog_yesno "$msg_create_home_directory"
828 if [ $__retval -eq $DIALOG_OK ]; then
829 setvar "$__var_to_set" "$msg_yes"
831 setvar "$__var_to_set" "$msg_no"
834 [ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
837 # f_dialog_input_group_delete $var_to_set [$group]
839 # Prompt the user to confirm deletion of a given login's primary group. If the
840 # user does not cancel (by choosing "No") or press ESC, the $var_to_set
841 # variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
842 # variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
844 f_dialog_input_group_delete()
846 local __var_to_set="$1" __group="$2"
848 if f_isinteger "$__group"; then
849 if [ $__group -lt 1000 ]; then
850 f_dialog_noyes "$msg_delete_primary_group"
852 f_dialog_yesno "$msg_delete_primary_group"
854 elif [ "$__group" ]; then
856 __gid=$( pw groupshow "$__group" | awk -F: '{print $3}' )
857 if f_isinteger "$__gid" && [ $__gid -lt 1000 ]; then
858 f_dialog_noyes "$msg_delete_primary_group"
860 f_dialog_yesno "$msg_delete_primary_group"
863 f_dialog_yesno "$msg_delete_primary_group"
867 if [ $__retval -eq $DIALOG_OK ]; then
868 setvar "$__var_to_set" "$msg_yes"
870 setvar "$__var_to_set" "$msg_no"
873 [ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
876 # f_dialog_input_home_delete $var_to_set
878 # Prompt the user to confirm deletion of a given login's home directory. If the
879 # user does not cancel (by choosing "No") or press ESC, the $var_to_set
880 # variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
881 # variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
883 f_dialog_input_home_delete()
885 local __var_to_set="$1"
887 f_dialog_yesno "$msg_delete_home_directory"
890 if [ $__retval -eq $DIALOG_OK ]; then
891 setvar "$__var_to_set" "$msg_yes"
893 setvar "$__var_to_set" "$msg_no"
896 [ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
899 # f_dialog_input_dotfiles_create $var_to_set
901 # Prompt the user to confirm population of a given login's home directory with
902 # sample dotfiles. If the user does not cancel (by choosing "No") or press ESC,
903 # the $var_to_set variable will hold $msg_yes upon return, otherwise $msg_no.
904 # Use these return variables ($msg_yes and $msg_no) for comparison to be i18n-
907 f_dialog_input_dotfiles_create()
909 local __var_to_set="$1"
911 f_dialog_yesno "$msg_create_dotfiles"
914 if [ $__retval -eq $DIALOG_OK ]; then
915 setvar "$__var_to_set" "$msg_yes"
917 setvar "$__var_to_set" "$msg_no"
920 [ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
923 # f_dialog_input_shell $var_to_set [$shell]
925 # Allow the user to select a new shell for a given login. If the user does not
926 # cancel or press ESC, the $var_to_set variable will hold the newly-configured
929 f_dialog_input_shell()
931 local __funcname=f_dialog_input_shell
932 local __var_to_set="$1" __input="$2"
933 local __prompt="$msg_select_login_shell"
934 local __radio_list= # Calculated below
935 local __defaultitem="$2"
936 local __hline="$hline_arrows_space_tab_enter"
939 # Generate the radiolist of shells
941 local __shell_list __s __shell __length=0
942 f_eval_catch -k __shell_list $__funcname awk "awk '%s' \"%s\"" \
943 '!/^[[:space:]]*(#|$)/{print}' "$ETC_SHELLS" || return $FAILURE
944 while [ $__length -ne ${#__shell_list} ]; do
945 __s="${__shell_list%%$NL*}" # First line
946 f_shell_escape "$__s" __shell
948 # Format of a radiolist entry: tag item status
949 if [ "$__s" = "$__input" ]; then
950 __radio_list="$__radio_list '$__shell' '' 'on'"
952 __radio_list="$__radio_list '$__shell' '' 'off'"
955 __length=${#__shell_list}
956 __shell_list="${__shell_list#*$NL}" # Kill line
959 local __height __width __rows
960 eval f_dialog_radiolist_size __height __width __rows \
962 \"\$DIALOG_BACKTITLE\" \
967 __input=$( eval $DIALOG \
968 --title \"\$DIALOG_TITLE\" \
969 --backtitle \"\$DIALOG_BACKTITLE\" \
970 --hline \"\$__hline\" \
971 --ok-label \"\$msg_ok\" \
972 --cancel-label \"\$msg_cancel\" \
973 --default-item \"\$__defaultitem\" \
974 --radiolist \"\$__prompt\" \
975 $__height $__width $__rows \
977 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
979 # Return if user either pressed ESC or chose Cancel/No
980 f_dialog_data_sanitize __input
982 setvar "$__var_to_set" "$__input"
986 # f_dialog_menu_user_add [$defaultitem]
988 # Present a menu detailing the properties of a login that is about to be added.
989 # The user's menu choice is available using f_dialog_menutag_fetch(). Returns
990 # success unless the user chose Cancel or pressed ESC. Data to display is taken
991 # from environment variables user_account_expire, user_class,
992 # user_dotfiles_create, user_gecos, user_gid, user_home_create, user_home_dir,
993 # user_member_groups, user_name, user_password_expire, user_shell, and
994 # user_uid. If $defaultitem is present and non-NULL, initially highlight the
997 f_dialog_menu_user_add()
999 local funcname=f_dialog_menu_user_add
1000 local prompt="$msg_save_exit_or_cancel"
1001 local menu_list # Calculated below
1002 local defaultitem="$1"
1003 local hline="$hline_arrows_tab_enter"
1005 # Attempt to convert numeric UNIX time to calendar date/time
1006 local user_account_expires_on=
1007 if f_isinteger "$user_account_expire"; then
1008 [ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
1009 date -r "$user_account_expire" "+%F %T %Z"
1012 user_account_expires_on="$user_account_expire"
1014 local user_password_expires_on=
1015 if f_isinteger "$user_password_expire"; then
1016 [ $user_password_expire -ne 0 ] && user_password_expires_on=$(
1017 date -r "$user_password_expire" "+%F %T %Z"
1020 user_password_expires_on="$user_password_expire"
1023 # Attempt to translate a numeric GID into `number (name)'
1024 if f_isinteger "$user_gid"; then
1026 user_group=$( pw groupshow -g "$user_gid" 2> /dev/null ) &&
1027 user_gid="$user_gid (${user_group%%:*})"
1030 # Localize potentially hostile variables and escape their values
1031 # to the local variable (see f_shell_escape() of `strings.subr')
1033 for var in account_expires_on class dotfiles_create gecos gid \
1034 home_create home_dir member_groups name password_expires_on \
1038 eval f_shell_escape \"\$user_$var\" _user_$var
1042 'X' '$msg_add/$msg_exit'
1043 '1' '$msg_login: $_user_name'
1044 '2' '$msg_full_name: $_user_gecos'
1045 '3' '$msg_password: -----'
1046 '4' '$msg_user_id: $_user_uid'
1047 '5' '$msg_group_id: $_user_gid'
1048 '6' '$msg_member_of_groups: $_user_member_groups'
1049 '7' '$msg_login_class: $_user_class'
1050 '8' '$msg_password_expires_on: $_user_password_expires_on'
1051 '9' '$msg_account_expires_on: $_user_account_expires_on'
1052 'A' '$msg_home_directory: $_user_home_dir'
1053 'B' '$msg_shell: $_user_shell'
1055 case "$user_home_dir" in
1056 /|/nonexistent|/var/empty) menu_list="$menu_list
1057 '-' '$msg_create_home_directory: $msg_n_a'
1058 '-' '$msg_create_dotfiles: $msg_n_a'
1061 *) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
1062 '-' '$msg_create_home_directory: $msg_n_a'
1063 'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
1065 else menu_list="$menu_list
1066 'C' '$msg_create_home_directory: ${_user_home_create:-$msg_no}'
1067 'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
1072 local height width rows
1073 eval f_dialog_menu_size height width rows \
1074 \"\$DIALOG_TITLE\" \
1075 \"\$DIALOG_BACKTITLE\" \
1081 menu_choice=$( eval $DIALOG \
1082 --title \"\$DIALOG_TITLE\" \
1083 --backtitle \"\$DIALOG_BACKTITLE\" \
1084 --hline \"\$hline\" \
1085 --ok-label \"\$msg_ok\" \
1086 --cancel-label \"\$msg_cancel\" \
1087 --default-item \"\$defaultitem\" \
1089 --menu \"\$prompt\" \
1090 $height $width $rows \
1092 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1095 f_dialog_data_sanitize menu_choice
1096 f_dialog_menutag_store "$menu_choice"
1100 # f_dialog_menu_user_delete $user [$defaultitem]
1102 # Present a menu detailing the properties of a login that is about to be
1103 # deleted. The user's menu choice is available using f_dialog_menutag_fetch().
1104 # Returns success unless the user chose Cancel or pressed ESC. Data to display
1105 # is populated automatically from the system accounting database for the given
1106 # $user argument with the exception of two environment variables:
1107 # user_group_delete and user_home_delete. If $defaultitem is present and non-
1108 # NULL, initially highlight the item in the menu.
1110 f_dialog_menu_user_delete()
1112 local prompt="$msg_delete_exit_or_cancel"
1113 local menu_list # Calculated below
1114 local defaultitem="$2"
1115 local hline="$hline_arrows_tab_enter"
1117 local user_name user_password user_uid user_gid user_class
1118 local user_password_expire user_account_expire user_gecos
1119 local user_home_dir user_shell user_member_groups
1122 # Attempt to convert numeric UNIX time to calendar date/time
1123 local user_account_expires_on=
1124 if f_isinteger "$user_account_expire"; then
1125 [ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
1126 date -r "$user_account_expire" "+%F %T %Z"
1129 user_account_expires_on="$user_account_expire"
1131 local user_password_expires_on=
1132 if f_isinteger "$user_password_expire"; then
1133 [ $user_password_expire -ne 0 ] && user_password_expires_on=$(
1134 date -r "$user_password_expire" "+%F %T %Z"
1137 user_password_expires_on="$user_password_expire"
1140 # Attempt to translate a numeric GID into `number (name)'
1141 if f_isinteger "$user_gid"; then
1143 user_group=$( pw groupshow -g "$user_gid" 2> /dev/null ) &&
1144 user_gid="$user_gid (${user_group%%:*})"
1147 # Localize potentially hostile variables and escape their values
1148 # to the local variable (see f_shell_escape() of `strings.subr')
1150 for var in account_expires_on class gecos gid group_delete \
1151 home_delete home_dir member_groups name password_expires_on \
1155 eval f_shell_escape \"\$user_$var\" _user_$var
1159 'X' '$msg_delete/$msg_exit'
1160 '1' '$msg_login: $_user_name'
1161 '-' '$msg_full_name: $_user_gecos'
1162 '-' '$msg_password: -----'
1163 '-' '$msg_user_id: $_user_uid'
1164 '-' '$msg_group_id: $_user_gid'
1165 '-' '$msg_group_members: $_user_member_groups'
1166 '-' '$msg_login_class: $_user_class'
1167 '-' '$msg_password_expires_on: $_user_password_expires_on'
1168 '-' '$msg_account_expires_on: $_user_account_expires_on'
1169 '-' '$msg_home_directory: $_user_home_dir'
1170 '-' '$msg_shell: $_user_shell'
1172 if f_quietly pw groupshow -g "$user_gid"; then menu_list="$menu_list
1173 'C' '$msg_delete_primary_group: ${_user_group_delete:-$msg_no}'
1175 else menu_list="$menu_list
1176 '-' '$msg_delete_primary_group: $msg_n_a'
1179 case "$user_home_dir" in
1180 /|/nonexistent|/var/empty) menu_list="$menu_list
1181 '-' '$msg_delete_home_directory: $msg_n_a'
1184 *) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
1185 'D' '$msg_delete_home_directory: ${_user_home_delete:-$msg_no}'
1187 else menu_list="$menu_list
1188 '-' '$msg_delete_home_directory: $msg_n_a'
1193 local height width rows
1194 eval f_dialog_menu_size height width rows \
1195 \"\$DIALOG_TITLE\" \
1196 \"\$DIALOG_BACKTITLE\" \
1202 menu_choice=$( eval $DIALOG \
1203 --title \"\$DIALOG_TITLE\" \
1204 --backtitle \"\$DIALOG_BACKTITLE\" \
1205 --hline \"\$hline\" \
1206 --ok-label \"\$msg_ok\" \
1207 --cancel-label \"\$msg_cancel\" \
1208 --default-item \"\$defaultitem\" \
1210 --menu \"\$prompt\" \
1211 $height $width $rows \
1213 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1216 f_dialog_data_sanitize menu_choice
1217 f_dialog_menutag_store "$menu_choice"
1221 # f_dialog_menu_user_edit [$defaultitem]
1223 # Present a menu detailing the properties of a login that is about to be
1224 # modified. The user's menu choice is available using f_dialog_menutag_fetch().
1225 # Returns success unless the user chose Cancel or pressed ESC. Data to display
1226 # is taken from environment variables user_account_expire, user_class,
1227 # user_dotfiles_create, user_gecos, user_gid, user_home_create, user_home_dir,
1228 # user_member_groups, user_name, user_password_expire, user_shell, and
1229 # user_uid. If $defaultitem is present and non-NULL, initially highlight the
1232 f_dialog_menu_user_edit()
1234 local prompt="$msg_save_exit_or_cancel"
1235 local menu_list # Calculated below
1236 local defaultitem="$1"
1237 local hline="$hline_arrows_tab_enter"
1239 # Attempt to convert numeric UNIX time to calendar date/time
1240 local user_account_expires_on=
1241 if f_isinteger "$user_account_expire"; then
1242 [ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
1243 date -r "$user_account_expire" "+%F %T %Z"
1246 user_account_expires_on="$user_account_expire"
1248 local user_password_expires_on=
1249 if f_isinteger "$user_password_expire"; then
1250 [ $user_password_expire -ne 0 ] && user_password_expires_on=$(
1251 date -r "$user_password_expire" "+%F %T %Z"
1254 user_password_expires_on="$user_password_expire"
1257 # Attempt to translate a numeric GID into `number (name)'
1258 if f_isinteger "$user_gid"; then
1260 user_group=$( pw groupshow -g "$user_gid" 2> /dev/null ) &&
1261 user_gid="$user_gid (${user_group%%:*})"
1264 # Localize potentially hostile variables and escape their values
1265 # to the local variable (see f_shell_escape() of `strings.subr')
1267 for var in account_expires_on class dotfiles_create gecos gid \
1268 home_create home_dir member_groups name password_expires_on \
1272 eval f_shell_escape \"\$user_$var\" _user_$var
1276 'X' '$msg_save/$msg_exit'
1277 '1' '$msg_login: $_user_name'
1278 '2' '$msg_full_name: $_user_gecos'
1279 '3' '$msg_password: -----'
1280 '4' '$msg_user_id: $_user_uid'
1281 '5' '$msg_group_id: $_user_gid'
1282 '6' '$msg_member_of_groups: $_user_member_groups'
1283 '7' '$msg_login_class: $_user_class'
1284 '8' '$msg_password_expires_on: $_user_password_expires_on'
1285 '9' '$msg_account_expires_on: $_user_account_expires_on'
1286 'A' '$msg_home_directory: $_user_home_dir'
1287 'B' '$msg_shell: $_user_shell'
1289 case "$user_home_dir" in
1290 /|/nonexistent|/var/empty) menu_list="$menu_list
1291 '-' '$msg_create_home_directory: $msg_n_a'
1292 '-' '$msg_create_dotfiles: $msg_n_a'
1295 *) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
1296 '-' '$msg_create_home_directory: $msg_n_a'
1297 'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
1299 else menu_list="$menu_list
1300 'C' '$msg_create_home_directory: ${_user_home_create:-$msg_no}'
1301 'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
1306 local height width rows
1307 eval f_dialog_menu_size height width rows \
1308 \"\$DIALOG_TITLE\" \
1309 \"\$DIALOG_BACKTITLE\" \
1315 menu_choice=$( eval $DIALOG \
1316 --title \"\$DIALOG_TITLE\" \
1317 --backtitle \"\$DIALOG_BACKTITLE\" \
1318 --hline \"\$hline\" \
1319 --ok-label \"\$msg_ok\" \
1320 --cancel-label \"\$msg_cancel\" \
1321 --default-item \"\$defaultitem\" \
1323 --menu \"\$prompt\" \
1324 $height $width $rows \
1326 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1329 f_dialog_data_sanitize menu_choice
1330 f_dialog_menutag_store "$menu_choice"
1334 ############################################################ MAIN
1336 f_dprintf "%s: Successfully loaded." usermgmt/user_input.subr
1338 fi # ! $_USERMGMT_USER_INPUT_SUBR