]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/bsdconfig/usermgmt/share/user_input.subr
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / bsdconfig / usermgmt / share / user_input.subr
1 if [ ! "$_USERMGMT_USER_INPUT_SUBR" ]; then _USERMGMT_USER_INPUT_SUBR=1
2 #
3 # Copyright (c) 2012 Ron McDowell
4 # Copyright (c) 2012-2013 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
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
37
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
41
42 ############################################################ CONFIGURATION
43
44 #
45 # Default location of shells(5)
46 #
47 : ${ETC_SHELLS:=/etc/shells}
48
49 ############################################################ FUNCTIONS
50
51 # f_get_member_groups $user
52 #
53 # Get a list of additional groups $user is a member of in group(5).
54 #
55 f_get_member_groups()
56 {
57         echo $( pw groupshow -a | awk -F: "/[:,]$1(,|\$)/{print \$1}" )
58 }
59
60 # f_input_user $user
61 #
62 # Given $user name or id, create the environment variables pw_name, pw_uid,
63 # pw_gid, pw_class, pw_password_expire, pw_account_expire, pw_gecos,
64 # pw_home_dir, pw_shell, and pw_member_groups (and pw_password is reset to
65 # NULL).
66 #
67 f_input_user()
68 {
69         local user="$1"
70         eval $( pw usershow "$user" | awk -F: '
71         {
72                 printf "pw_name='\'%s\''\n", $1
73                 printf "pw_password=\n"
74                 printf "pw_uid='\'%s\''\n", $3
75                 printf "pw_gid='\'%s\''\n", $4
76                 printf "pw_class='\'%s\''\n", $5
77                 printf "pw_password_expire='\'%s\''\n", $6
78                 printf "pw_account_expire='\'%s\''\n", $7
79                 printf "pw_gecos='\'%s\''\n", $8
80                 printf "pw_home_dir='\'%s\''\n", $9
81                 printf "pw_shell='\'%s\''\n", $10
82         }' )
83         pw_member_groups=$( f_get_member_groups "$user" )
84 }
85
86 # f_dialog_menu_user_list [$default]
87 #
88 # Allows the user to select a login from a list. Optionally, if present and
89 # non-NULL, initially highlight $default user.
90 #
91 f_dialog_menu_user_list()
92 {
93         local prompt=
94         local menu_list="
95                 'X $msg_exit' ''
96         " # END-QUOTE
97         local defaultitem="$1"
98         local hline="$hline_alnum_punc_tab_enter"
99
100         # Add users from passwd(5)
101         menu_list="$menu_list $( pw usershow -a | awk -F: '
102                 !/^[[:space:]]*(#|$)/ {
103                         printf "'\'%s\'\ \'%s\''\n", $1, $8
104                 }'
105         )"
106
107         local height width rows
108         eval f_dialog_menu_size height width rows \
109                                 \"\$DIALOG_TITLE\"     \
110                                 \"\$DIALOG_BACKTITLE\" \
111                                 \"\$prompt\"           \
112                                 \"\$hline\"            \
113                                 $menu_list
114
115         local menu_choice
116         menu_choice=$( eval $DIALOG \
117                 --title \"\$DIALOG_TITLE\"         \
118                 --backtitle \"\$DIALOG_BACKTITLE\" \
119                 --hline \"\$hline\"                \
120                 --ok-label \"\$msg_ok\"            \
121                 --cancel-label \"\$msg_cancel\"    \
122                 --default-item \"\$defaultitem\"   \
123                 --menu \"\$prompt\"                \
124                 $height $width $rows               \
125                 $menu_list                         \
126                 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
127         )
128         local retval=$?
129         f_dialog_menutag_store -s "$menu_choice"
130         return $retval
131 }
132
133 # f_dialog_input_member_groups [$member_groups]
134 #
135 # Allows the user to edit group memberships for a given user. If the user does
136 # not cancel or press ESC, the $pw_member_groups variable will hold the newly-
137 # configured value upon return.
138 #
139 f_dialog_input_member_groups()
140 {
141         local _member_groups="$1"
142         local prompt="$msg_member_of_groups"
143         local check_list= # Calculated below
144         local hline="$hline_alnum_space_tab_enter"
145         local group
146
147         #
148         # Generate the checklist menu
149         #
150         for group in $(
151                 pw groupshow -a | awk -F: '!/^[[:space:]]*(#|$)/{print $1}'
152         ); do
153                 # Format of a checklist menu entry is "tag item status"
154                 # (setting both tag and item to the group name below).
155                 if echo "$_member_groups" | grep -q "\<$group\>"; then
156                         check_list="$check_list $group $group on"
157                 else
158                         check_list="$check_list $group $group off"
159                 fi
160         done
161
162         #
163         # Loop until the user provides taint-free/valid input
164         #
165         local height width rows
166         while :; do
167                 eval f_dialog_checklist_size height width rows \
168                                 \"\$DIALOG_TITLE\"     \
169                                 \"\$DIALOG_BACKTITLE\" \
170                                 \"\$prompt\"           \
171                                 \"\$hline\"            \
172                                 $check_list
173                 _member_groups=$( eval $DIALOG \
174                         --title \"\$DIALOG_TITLE\"         \
175                         --backtitle \"\$DIALOG_BACKTITLE\" \
176                         --separate-output                  \
177                         --hline \"\$hline\"                \
178                         --ok-label \"\$msg_ok\"            \
179                         --cancel-label \"\$msg_cancel\"    \
180                         --checklist \"\$prompt\"           \
181                         $height $width $rows               \
182                         $check_list                        \
183                         2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
184                 ) || return $?
185                         # Return if user either pressed ESC or chose Cancel/No
186                 f_dialog_data_sanitize _member_groups
187
188                 #
189                 # Validate each of the groups the user has entered
190                 #
191                 local all_groups_valid=1
192                 for group in $_member_groups; do
193                         if ! f_quietly pw groupshow -n "$group"; then
194                                 f_show_msg "$msg_group_not_found" "$group"
195                                 all_groups_valid=
196                                 break
197                         fi
198                 done
199                 [ "$all_groups_valid" ] || continue
200
201                 pw_member_groups="$_member_groups"
202                 break
203         done
204         save_flag=1
205
206         f_dprintf "pw_member_groups: [%s]->[%s]" \
207                   "$cur_pw_member_groups" "$pw_member_groups"
208
209         return $DIALOG_OK
210 }
211
212 # f_dialog_input_name [$name]
213 #
214 # Allows the user to enter a new username for a given user. If the user does
215 # not cancel or press ESC, the $pw_name variable will hold the newly-configured
216 # value upon return.
217 #
218 # If $cur_pw_name is defined, the user can enter that and by-pass error-
219 # checking (allowing the user to "revert" to an old value without, for example,
220 # being told that the username already exists).
221 #
222 f_dialog_input_name()
223 {
224         #
225         # Loop until the user provides taint-free/valid input
226         #
227         local _name="$1" _input="$1"
228         while :; do
229
230                 # Return if user has either pressed ESC or chosen Cancel/No
231                 f_dialog_input _input "$msg_login" "$_input" \
232                                "$hline_alnum_tab_enter" || return $?
233
234                 # Check for no-change
235                 [ "$_input" = "$_name" ] && return $DIALOG_OK
236
237                 # Check for reversion
238                 if [ "$_input" = "$cur_pw_name" ]; then
239                         pw_name="$cur_pw_name"
240                         return $DIALOG_OK
241                 fi
242
243                 # Check for NULL entry
244                 if [ ! "$_input" ]; then
245                         f_show_msg "$msg_login_is_empty"
246                         continue
247                 fi
248
249                 # Check for invalid entry
250                 if ! echo "$_input" | grep -q "^[[:alpha:]]"; then
251                         f_show_msg "$msg_login_must_start_with_letter"
252                         continue
253                 fi
254
255                 # Check for duplicate entry
256                 if f_quietly pw usershow -n "$_input"; then
257                         f_show_msg "$msg_login_already_used" "$_input"
258                         continue
259                 fi
260
261                 pw_name="$_input"
262                 break
263         done
264         save_flag=1
265
266         f_dprintf "pw_name: [%s]->[%s]" "$cur_pw_name" "$pw_name"
267
268         return $DIALOG_OK
269 }
270
271 # f_dialog_input_password
272 #
273 # Prompt the user to enter a password (twice).
274 #
275 f_dialog_input_password()
276 {
277         local prompt1="$msg_password"
278         local prompt2="$msg_reenter_password"
279         local hline="$hline_alnum_punc_tab_enter"
280
281         local height1 width1
282         f_dialog_inputbox_size height1 width1 \
283                                "$DIALOG_TITLE"     \
284                                "$DIALOG_BACKTITLE" \
285                                "$prompt1"          \
286                                ""                  \
287                                "$hline"
288         local height2 width2
289         f_dialog_inputbox_size height2 width2 \
290                                "$DIALOG_TITLE"     \
291                                "$DIALOG_BACKTITLE" \
292                                "$prompt2"          \
293                                ""                  \
294                                "$hline"
295
296         #
297         # Loop until the user provides taint-free/valid input
298         #
299         local _password1 _password2
300         while :; do
301                 _password1=$( $DIALOG \
302                         --title "$DIALOG_TITLE"         \
303                         --backtitle "$DIALOG_BACKTITLE" \
304                         --hline "$hline"                \
305                         --ok-label "$msg_ok"            \
306                         --cancel-label "$msg_cancel"    \
307                         --insecure                      \
308                         --passwordbox "$prompt1"        \
309                         $height1 $width1                \
310                         2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
311                 ) || return $?
312                         # Return if user either pressed ESC or chose Cancel/No
313                 debug= f_dialog_line_sanitize _password1
314
315                 _password2=$( $DIALOG \
316                         --title "$DIALOG_TITLE"         \
317                         --backtitle "$DIALOG_BACKTITLE" \
318                         --hline "$hline"                \
319                         --ok-label "$msg_ok"            \
320                         --cancel-label "$msg_cancel"    \
321                         --insecure                      \
322                         --passwordbox "$prompt2"        \
323                         $height2 $width2                \
324                         2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
325                 ) || return $?
326                         # Return if user either pressed ESC or chose Cancel/No
327                 debug= f_dialog_line_sanitize _password2
328
329                 # Check for password mismatch
330                 if [ "$_password1" != "$_password2" ]; then
331                         f_show_msg "$msg_passwords_do_not_match"
332                         continue
333                 fi
334
335                 # Check for NULL entry
336                 if [ ! "$_password1" ]; then
337                         f_dialog_yesno "$msg_disable_password_auth_for_account"
338                         local retval=$?
339                         if [ $retval -eq $DIALOG_ESC ]; then
340                                 return $retval
341                         elif [ $retval -eq $DIALOG_OK ]; then
342                                 pw_password_disable=1
343                         else
344                                 continue # back to password prompt
345                         fi
346                 else
347                         pw_password_disable=
348                 fi
349
350                 pw_password="$_password1"
351                 break
352         done
353         save_flag=1
354
355         f_dprintf "pw_password: [%s]->[%s]" "$cur_pw_password" "$pw_password"
356
357         return $DIALOG_OK
358 }
359
360 # f_dialog_input_gecos [$gecos]
361 #
362 # Allow the user to enter new GECOS information for a given user. This
363 # information is commonly used to store the ``Full Name'' of the user. If the
364 # user does not cancel or press ESC, the $pw_gecos variable will hold the
365 # newly-configured value upon return.
366 #
367 f_dialog_input_gecos()
368 {
369         local _input="$1"
370
371         # Return if user has either pressed ESC or chosen Cancel/No
372         f_dialog_input _input "$msg_full_name" "$_input" \
373                        "$hline_alnum_punc_tab_enter" || return $?
374
375         pw_gecos="$_input"
376         save_flag=1
377
378         f_dprintf "pw_gecos: [%s]->[%s]" "$cur_pw_gecos" "$pw_gecos"
379
380         return $DIALOG_OK
381 }
382
383 # f_dialog_input_uid [$uid]
384 #
385 # Allow the user to enter a new UID for a given user. If the user does not
386 # cancel or press ESC, the $pw_uid variable will hold the newly-configured
387 # value upon return.
388 #
389 f_dialog_input_uid()
390 {
391         local _input="$1"
392
393         # Return if user has either pressed ESC or chosen Cancel/No
394         f_dialog_input _input "$msg_user_id_leave_empty_for_default" \
395                        "$_input" "$hline_num_tab_enter" || return $?
396
397         pw_uid="$_input"
398         save_flag=1
399
400         f_dprintf "pw_uid: [%s]->[%s]" "$cur_pw_uid" "$pw_uid"
401
402         return $DIALOG_OK
403 }
404
405 # f_dialog_input_gid [$gid]
406 #
407 # Allow the user to enter a new primary GID for a given user. If the user does
408 # not cancel or press ESC, the $pw_gid variable will hold the newly-configured
409 # value upon return.
410 #
411 f_dialog_input_gid()
412 {
413         local _input="$1"
414
415         # Return if user has either pressed ESC or chosen Cancel/No
416         f_dialog_input _input "$msg_group_id_leave_empty_for_default" \
417                        "$_input" "$hline_num_tab_enter" || return $?
418
419         pw_gid="$_input"
420         save_flag=1
421
422         f_dprintf "pw_gid: [%s]->[%s]" "$cur_pw_gid" "$pw_gid"
423
424         return $DIALOG_OK
425 }
426
427 # f_dialog_input_class [$class]
428 #
429 # Allow the user to enter a new login class for a given user. If the user does
430 # not cancel or press ESC, the $pw_class variable will hold the newly-
431 # configured value upon return.
432 #
433 f_dialog_input_class()
434 {
435         local _input="$1"
436
437         # Return if user has either pressed ESC or chosen Cancel/No
438         f_dialog_input _input "$msg_login_class" "$_input" \
439                        "$hline_alnum_tab_enter" || return $?
440
441         pw_class="$_input"
442         save_flag=1
443
444         f_dprintf "pw_class: [%s]->[%s]" "$cur_pw_class" "$pw_class"
445
446         return $DIALOG_OK
447 }
448
449 # f_dialog_input_expire_password [$seconds]
450 #
451 # Allow the user to enter a date/time (in number-of-seconds since the `epoch')
452 # for when a given user's password must be changed. If the user does not cancel
453 # or press ESC, the $pw_password_expire variable will hold the newly-
454 # configured value upon return.
455 #
456 f_dialog_input_expire_password()
457 {
458         local prompt="$msg_password_expires_on"
459         local menu_list="
460                 '1' '$msg_password_does_not_expire'
461                 '2' '$msg_edit_date_time_with_a_calendar'
462                 '3' '$msg_enter_number_of_days_into_the_future'
463                 '4' '$msg_enter_value_manually'
464         " # END-QUOTE
465         local hline="$hline_num_arrows_tab_enter"
466         local retval _input="$1"
467
468         local mheight mwidth mrows
469         eval f_dialog_menu_size mheight mwidth mrows \
470                                 \"\$DIALOG_TITLE\"     \
471                                 \"\$DIALOG_BACKTITLE\" \
472                                 \"\$prompt\"           \
473                                 \"\$hline\"            \
474                                 $menu_list
475         local cheight cwidth
476         f_dialog_calendar_size cheight cwidth \
477                                "$DIALOG_TITLE"     \
478                                "$DIALOG_BACKTITLE" \
479                                "$prompt"           \
480                                "$hline"
481         local theight twidth
482         f_dialog_timebox_size theight twidth \
483                               "$DIALOG_TITLE"     \
484                               "$DIALOG_BACKTITLE" \
485                               "$prompt"           \
486                               "$hline"
487
488         #
489         # Loop until the user provides taint-free/cancellation-free input
490         #
491         local date_type defaultitem=
492         while :; do
493                 date_type=$( eval $DIALOG \
494                         --title \"\$DIALOG_TITLE\"         \
495                         --backtitle \"\$DIALOG_BACKTITLE\" \
496                         --hline \"\$hline\"                \
497                         --default-item \"\$defaultitem\"   \
498                         --ok-label \"\$msg_ok\"            \
499                         --cancel-label \"\$msg_cancel\"    \
500                         --menu \"\$prompt\"                \
501                         $mheight $mwidth $mrows            \
502                         $menu_list                         \
503                         2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
504                 )
505                 retval=$?
506                 f_dialog_data_sanitize date_type
507                 defaultitem="$date_type"
508                 f_dprintf "retval=%u date_type=[%s]" $retval "$date_type"
509
510                 # Return if user has either pressed ESC or chosen Cancel/No
511                 [ $retval -eq $DIALOG_OK ] || return $retval
512
513                 case "$date_type" in
514                 1) # Password does not expire
515                         _input=""
516                         break ;;
517
518                 2) # Edit date/time with a calendar
519                         local _input_date _input_time ret_date ret_time
520
521                         local secs="$_input"
522                         { f_isinteger "$secs" && [ $secs -gt 0 ]; } || secs=
523                         _input_date=$( date -j -f "%s" -- "$secs" \
524                                                 "+%d %m %Y" 2> /dev/null )
525                         ret_date=$( eval $DIALOG \
526                                 --title \"\$DIALOG_TITLE\"          \
527                                 --backtitle \"\$DIALOG_BACKTITLE\"  \
528                                 --hline \"\$hline\"                 \
529                                 --ok-label \"\$msg_ok\"             \
530                                 --cancel-label \"\$msg_cancel\"     \
531                                 --calendar \"\$prompt\"             \
532                                 $cheight $cwidth                    \
533                                 $_input_date                        \
534                                 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
535                         )
536                         retval=$?
537                         f_dialog_data_sanitize ret_date
538                         f_dprintf "retval=%u ret_date=[%s]" $retval "$ret_date"
539
540                         # Return to menu if either ESC or Cancel/No
541                         [ $retval -eq $DIALOG_OK ] || continue
542
543                         _input_time=
544                         [ "$secs" ] && _input_time=$( date -j \
545                                 -f %s -- "$_input" "+%H %M %S" 2> /dev/null )
546                         ret_time=$( eval $DIALOG \
547                                 --title \"\$DIALOG_TITLE\"         \
548                                 --backtitle \"\$DIALOG_BACKTITLE\" \
549                                 --hline \"\$hline\"                \
550                                 --ok-label \"\$msg_ok\"            \
551                                 --cancel-label \"\$msg_cancel\"    \
552                                 --timebox \"\$prompt\"             \
553                                 $theight $twidth                   \
554                                 $_input_time                       \
555                                 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
556                         )
557                         retval=$?
558                         f_dialog_data_sanitize ret_time
559                         f_dprintf "retval=%u ret_time=[%s]" $retval "$ret_time"
560
561                         # Return to menu if either ESC or Cancel/No
562                         [ $retval -eq $DIALOG_OK ] || continue
563
564                         _input=$( date \
565                                         -j -f "%d/%m/%Y %T" \
566                                         -- "$ret_date $ret_time" \
567                                         +%s 2> /dev/null )
568                         f_dprintf "_input=[%s]" "$_input"
569                         break ;;
570
571                 3) # Enter number of days into the future
572                         local ret_days seconds="$( date +%s )"
573
574                         f_isinteger "$_input" || _input=0
575                         [ $_input -gt 0 -a $_input -gt $seconds ] &&
576                                 ret_days=$(( ( $_input - $seconds ) / 86400 ))
577                         f_isinteger "$ret_days" &&
578                                 ret_days=$(( $ret_days + 1 ))
579
580                         # Return to menu if either ESC or Cancel/No
581                         f_dialog_input ret_days \
582                                 "$msg_password_expires_in_how_many_days" \
583                                 "$ret_days" "$hline" || continue
584
585                         # Taint-check the user's input
586                         if ! f_isinteger "$ret_days"; then
587                                 f_show_msg "$msg_invalid_number_of_days"
588                                 continue
589                         fi
590
591                         f_dprintf "ret_days=[%s]" "$ret_days"
592                         case "$ret_days" in
593                         [-+]*) _input=$( date -v${ret_days}d +%s ) ;;
594                             0) _input=$( date +%s ) ;;
595                             *) _input=$( date -v+${ret_days}d +%s ) ;;
596                         esac
597                         f_dprintf "_input=[%s]" "$_input"
598                         break ;;
599
600                 4) # Enter value manually
601                         local msg ret_secs
602                         msg=$( printf "$msg_number_of_seconds_since_epoch" \
603                                       "$( date -r 1 "+%c %Z" )" )
604
605                         # Return to menu if either ESC or Cancel/No
606                         f_dialog_input ret_secs \
607                                        "$msg" "$_input" "$hline" || continue
608
609                         _input="$ret_secs"
610
611                         # Taint-check the user's input
612                         if ! f_isinteger "${_input:-0}"; then
613                                 f_show_msg "$msg_invalid_number_of_seconds"
614                                 continue
615                         fi
616
617                         f_dprintf "_input=[%s]" "$_input"
618                         break ;;
619
620                 esac
621
622         done # Loop forever
623
624         pw_password_expire="$_input"
625         save_flag=1
626
627         f_dprintf "pw_password_expire: [%s]->[%s]" \
628                   "$cur_pw_password_expire" "$pw_password_expire"
629
630         return $DIALOG_OK
631 }
632
633 # f_dialog_input_expire_account [$seconds]
634 #
635 # Allow the user to enter a date/time (in number-of-seconds since the `epoch')
636 # for when a given user's account should become expired. If the user does not
637 # cancel or press ESC, the $pw_account_expire variable will hold the newly-
638 # configured value upon return.
639 #
640 f_dialog_input_expire_account()
641 {
642         local prompt="$msg_account_expires_on"
643         local menu_list="
644                 '1' '$msg_account_does_not_expire'
645                 '2' '$msg_edit_date_time_with_a_calendar'
646                 '3' '$msg_enter_number_of_days_into_the_future'
647                 '4' '$msg_enter_value_manually'
648         " # END-QUOTE
649         local hline="$hline_num_arrows_tab_enter"
650         local retval _input="$1"
651
652         local mheight mwidth mrows 
653         eval f_dialog_menu_size mheight mwidth mrows \
654                                 \"\$DIALOG_TITLE\"     \
655                                 \"\$DIALOG_BACKTITLE\" \
656                                 \"\$prompt\"           \
657                                 \"\$hline\"            \
658                                 $menu_list
659         local cheight cwidth
660         f_dialog_calendar_size cheight cwidth \
661                                "$DIALOG_TITLE"     \
662                                "$DIALOG_BACKTITLE" \
663                                "$prompt"           \
664                                "$hline"
665         local theight twidth
666         f_dialog_timebox_size theight twidth \
667                               "$DIALOG_TITLE"     \
668                               "$DIALOG_BACKTITLE" \
669                               "$prompt"           \
670                               "$hline"
671
672         #
673         # Loop until the user provides taint-free/cancellation-free input
674         #
675         local date_type defaultitem=
676         while :; do
677                 date_type=$( eval $DIALOG \
678                         --title \"\$DIALOG_TITLE\"         \
679                         --backtitle \"\$DIALOG_BACKTITLE\" \
680                         --hline \"\$hline\"                \
681                         --default-item \"\$defaultitem\"   \
682                         --ok-label \"\$msg_ok\"            \
683                         --cancel-label \"\$msg_cancel\"    \
684                         --menu \"\$prompt\"                \
685                         $mheight $mwidth $mrows            \
686                         $menu_list                         \
687                         2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
688                 )
689                 retval=$?
690                 f_dialog_data_sanitize date_type
691                 defaultitem="$date_type"
692                 f_dprintf "retval=%u date_type=[%s]" $retval "$date_type"
693
694                 # Return if user has either pressed ESC or chosen Cancel/No
695                 [ $retval -eq $DIALOG_OK ] || return $retval
696
697                 case "$date_type" in
698                 1) # Account does not expire
699                         _input=""
700                         break ;;
701
702                 2) # Edit date/time with a calendar
703                         local _input_date _input_time ret_date ret_time
704
705                         local secs="$_input"
706                         { f_isinteger "$secs" && [ $secs -gt 0 ]; } || secs=
707                         _input_date=$( date -j -f "%s" -- "$secs" \
708                                                 "+%d %m %Y" 2> /dev/null )
709                         ret_date=$( eval $DIALOG \
710                                 --title \"\$DIALOG_TITLE\"          \
711                                 --backtitle \"\$DIALOG_BACKTITLE\"  \
712                                 --hline \"\$hline\"                 \
713                                 --ok-label \"\$msg_ok\"             \
714                                 --cancel-label \"\$msg_cancel\"     \
715                                 --calendar \"\$prompt\"             \
716                                 $cheight $cwidth                    \
717                                 $_input_date                        \
718                                 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
719                         )
720                         retval=$?
721                         f_dialog_data_sanitize ret_date
722                         f_dprintf "retval=%u ret_date=[%s]" $retval "$ret_date"
723
724                         # Return to menu if either ESC or Cancel/No
725                         [ $retval -eq $DIALOG_OK ] || continue
726
727                         _input_time=
728                         [ "$secs" ] && _input_time=$( date -j \
729                                 -f %s -- "$_input" "+%H %M %S" 2> /dev/null )
730                         ret_time=$( eval $DIALOG \
731                                 --title \"\$DIALOG_TITLE\"         \
732                                 --backtitle \"\$DIALOG_BACKTITLE\" \
733                                 --hline \"\$hline\"                \
734                                 --ok-label \"\$msg_ok\"            \
735                                 --cancel-label \"\$msg_cancel\"    \
736                                 --timebox \"\$prompt\"             \
737                                 $theight $twidth                   \
738                                 $_input_time                       \
739                                 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
740                         )
741                         retval=$?
742                         f_dialog_data_sanitize ret_time
743                         f_dprintf "retval=%u ret_time=[%s]" $retval "$ret_time"
744
745                         # Return to menu if either ESC or Cancel/No
746                         [ $retval -eq $DIALOG_OK ] || continue
747
748                         _input=$( date \
749                                         -j -f "%d/%m/%Y %T" \
750                                         -- "$ret_date $ret_time" \
751                                         +%s 2> /dev/null )
752                         f_dprintf "_input=[%s]" "$_input"
753                         break ;;
754
755                 3) # Enter number of days into the future
756                         local ret_days seconds="$( date +%s )"
757
758                         f_isinteger "$_input" || _input=0
759                         [ $_input -gt 0 -a $_input -gt $seconds ] &&
760                                 ret_days=$(( ( $_input - $seconds ) / 86400 ))
761                         f_isinteger "$ret_days" &&
762                                 ret_days=$(( $ret_days + 1 ))
763
764                         # Return to menu if either ESC or Cancel/No
765                         f_dialog_input ret_days \
766                                 "$msg_account_expires_in_how_many_days" \
767                                 "$ret_days" "$hline" || continue
768
769                         # Taint-check the user's input
770                         if ! f_isinteger "$ret_days"; then
771                                 f_show_msg "$msg_invalid_number_of_days"
772                                 continue
773                         fi
774
775                         f_dprintf "ret_days=[%s]" "$ret_days"
776                         case "$ret_days" in
777                         [-+]*) _input=$( date -v${ret_days}d +%s ) ;;
778                             0) _input=$( date +%s ) ;;
779                             *) _input=$( date -v+${ret_days}d +%s ) ;;
780                         esac
781                         f_dprintf "_input=[%s]" "$_input"
782                         break ;;
783
784                 4) # Enter value manually
785                         local msg ret_secs
786                         msg=$( printf "$msg_number_of_seconds_since_epoch" \
787                                       "$( date -r 1 "+%c %Z" )" )
788
789                         # Return to menu if either ESC or Cancel/No
790                         f_dialog_input ret_secs "$msg" \
791                                        "$_input" "$hline" || continue
792
793                         _input="$ret_secs"
794
795                         # Taint-check the user's input
796                         if ! f_isinteger "${_input:-0}"; then
797                                 f_show_msg "$msg_invalid_number_of_seconds"
798                                 continue
799                         fi
800
801                         f_dprintf "_input=[%s]" "$_input"
802                         break ;;
803
804                 esac
805
806         done # Loop forever
807
808         pw_account_expire="$_input"
809         save_flag=1
810
811         f_dprintf "pw_account_expire: [%s]->[%s]" \
812                   "$cur_pw_account_expire" "$pw_account_expire"
813
814         return $DIALOG_OK
815 }
816
817 # f_dialog_input_home_dir [$home_dir]
818 #
819 # Allow the user to enter a new home directory for a given user. If the user
820 # does not cancel or press ESC, the $pw_home_dir variable will hold the newly-
821 # configured value upon return.
822 #
823 f_dialog_input_home_dir()
824 {
825         local _input="$1"
826
827         # Return if user has either pressed ESC or chosen Cancel/No
828         f_dialog_input _input "$msg_home_directory" "$_input" \
829                        "$hline_alnum_punc_tab_enter" || return $?
830
831         pw_home_dir="$_input"
832         save_flag=1
833
834         f_dprintf "pw_home_dir: [%s]->[%s]" "$cur_pw_home_dir" "$pw_home_dir"
835
836         return $DIALOG_OK
837 }
838
839 # f_dialog_input_home_create
840 #
841 # Prompt the user to confirm creation of a given user's home directory. If the
842 # user does not cancel (by choosing "No") or press ESC, the $pw_home_create
843 # variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
844 # variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
845 #
846 f_dialog_input_home_create()
847 {
848         local retval
849
850         f_dialog_yesno "$msg_create_home_directory"
851         retval=$?
852
853         if [ $retval -eq $DIALOG_OK ]; then
854                 pw_home_create="$msg_yes"
855         else
856                 pw_home_create="$msg_no"
857         fi
858         save_flag=1
859
860         f_dprintf "pw_home_create: [%s]->[%s]" \
861                   "$cur_pw_home_create" "$pw_home_create"
862
863         [ $retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
864 }
865
866 # f_dialog_input_group_delete
867 #
868 # Prompt the user to confirm deletion of a given user's primary group. If the
869 # user does not cancel (by choosing "No") or press ESC, the $pw_group_delete
870 # variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
871 # variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
872 #
873 f_dialog_input_group_delete()
874 {
875         local retval
876
877         if f_isinteger "$pw_gid"; then
878                 if [ $pw_gid -lt 1000 ]; then
879                         f_dialog_noyes "$msg_delete_primary_group"
880                 else
881                         f_dialog_yesno "$msg_delete_primary_group"
882                 fi
883         elif [ "$pw_gid" ]; then
884                 local gid=0
885                 gid=$( pw groupshow "$pw_gid" | awk -F: '{print $3}' )
886                 if f_isinteger "$gid" && [ $gid -lt 1000 ]; then
887                         f_dialog_noyes "$msg_delete_primary_group"
888                 else
889                         f_dialog_yesno "$msg_delete_primary_group"
890                 fi
891         else
892                 f_dialog_yesno "$msg_delete_primary_group"
893         fi
894         retval=$?
895
896         if [ $retval -eq $DIALOG_OK ]; then
897                 pw_group_delete="$msg_yes"
898         else
899                 pw_group_delete="$msg_no"
900         fi
901         save_flag=1
902
903         f_dprintf "pw_group_delete: [%s]->[%s]" \
904                   "$cur_pw_group_delete" "$pw_group_delete"
905
906         [ $retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
907 }
908
909 # f_dialog_input_home_delete
910 #
911 # Prompt the user to confirm deletion of a given user's home directory. If the
912 # user does not cancel (by choosing "No") or press ESC, the $pw_home_delete
913 # variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
914 # variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
915 #
916 f_dialog_input_home_delete()
917 {
918         local retval
919
920         f_dialog_yesno "$msg_delete_home_directory"
921         retval=$?
922
923         if [ $retval -eq $DIALOG_OK ]; then
924                 pw_home_delete="$msg_yes"
925         else
926                 pw_home_delete="$msg_no"
927         fi
928         save_flag=1
929
930         f_dprintf "pw_home_delete: [%s]->[%s]" \
931                   "$cur_pw_home_delete" "$pw_home_delete"
932
933         [ $retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
934 }
935
936 # f_dialog_input_dotfiles_create
937 #
938 # Prompt the user to confirm population of a given user's home directory with
939 # sample dotfiles. If the user does not cancel (by choosing "No") or press ESC,
940 # the $pw_dotfiles_create variable will hold $msg_yes upon return, otherwise
941 # $msg_no. Use these return variables ($msg_yes and $msg_no) for comparison to
942 # be i18n-compatible.
943 #
944 f_dialog_input_dotfiles_create()
945 {
946         local retval
947
948         f_dialog_yesno "$msg_create_dotfiles"
949         retval=$?
950
951         if [ $retval -eq $DIALOG_OK ]; then
952                 pw_dotfiles_create="$msg_yes"
953         else
954                 pw_dotfiles_create="$msg_no"
955         fi
956         save_flag=1
957
958         f_dprintf "pw_dotfiles_create: [%s]->[%s]" \
959                   "$cur_pw_dotfiles_create" "$pw_dotfiles_create"
960
961         [ $retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
962 }
963
964 # f_dialog_input_shell [$shell]
965 #
966 # Allow the user to select a new login shell for a given user. If the user does
967 # not cancel or press ESC, the $pw_home_dir variable will hold the newly-
968 # configured value upon return.
969 #
970 #
971 f_dialog_input_shell()
972 {
973         local _input="$1"
974         local prompt="$msg_select_login_shell"
975         local radio_list= # Calculated below
976         local hline="$hline_arrows_space_tab_enter"
977
978         #
979         # Generate the radiolist of shells
980         #
981         local shell
982         for shell in $( awk '!/^[[:space:]]*(#|$)/{print}' "$ETC_SHELLS" ); do
983                 # Format of a radiolist menu entry is "tag item status"
984                 if [ "$shell" = "$_input" ]; then
985                         radio_list="$radio_list '$shell' '' 'on'"
986                 else
987                         radio_list="$radio_list '$shell' '' 'off'"
988                 fi
989         done
990
991         local height width rows
992         eval f_dialog_radiolist_size height width rows \
993                                      \"\$DIALOG_TITLE\"     \
994                                      \"\$DIALOG_BACKTITLE\" \
995                                      \"\$prompt\"           \
996                                      \"\$hline\"            \
997                                      $radio_list
998
999         _input=$( eval $DIALOG \
1000                 --title \"\$DIALOG_TITLE\"         \
1001                 --backtitle \"\$DIALOG_BACKTITLE\" \
1002                 --hline \"\$hline\"                \
1003                 --ok-label \"\$msg_ok\"            \
1004                 --cancel-label \"\$msg_cancel\"    \
1005                 --radiolist \"\$prompt\"           \
1006                 $height $width $rows               \
1007                 $radio_list                        \
1008                 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1009         ) || return $?
1010                 # Return if user either pressed ESC or chose Cancel/No
1011         f_dialog_data_sanitize _input
1012
1013         pw_shell="$_input"
1014         save_flag=1
1015
1016         f_dprintf "pw_shell: [%s]->[%s]" "$cur_pw_shell" "$pw_shell"
1017
1018         return $DIALOG_OK
1019 }
1020
1021 ############################################################ MAIN
1022
1023 f_dprintf "%s: Successfully loaded." usermgmt/user_input.subr
1024
1025 fi # ! $_USERMGMT_USER_INPUT_SUBR