if [ ! "$_USERMGMT_GROUP_INPUT_SUBR" ]; then _USERMGMT_GROUP_INPUT_SUBR=1 # # Copyright (c) 2012 Ron McDowell # Copyright (c) 2012-2014 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # ############################################################ INCLUDES BSDCFG_SHARE="/usr/share/bsdconfig" . $BSDCFG_SHARE/common.subr || exit 1 f_dprintf "%s: loading includes..." usermgmt/group_input.subr f_include $BSDCFG_SHARE/dialog.subr f_include $BSDCFG_SHARE/strings.subr BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt" f_include_lang $BSDCFG_LIBE/include/messages.subr f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr ############################################################ FUNCTIONS # f_input_group $group # # Given $group name or id, create the environment variables group_name, # group_gid, and group_members (and group_password is reset to NULL). # f_input_group() { local funcname=f_input_group local group="$1" f_dprintf "$funcname: Getting info for group \`%s'" "$group" eval "$( pw groupshow "$group" 2> /dev/null | awk -F: ' function set_value(var, value) { gsub(/'\''/, "'\''\\'\'\''", value) printf "group_%s='\'%s\''\n", var, value } { found = $1 != "" set_value("name", $1) set_value("password", "") set_value("gid", $3) set_value("members", $4) exit } END { if (!found) print "false" }' )" } # f_dialog_menu_group_list [$default] # # Allows the user to select a group from a list. Optionally, if present and # non-NULL, initially highlight $default group. # f_dialog_menu_group_list() { local prompt= local menu_list=" 'X $msg_exit' '' " # END-QUOTE local defaultitem="$1" local hline="$hline_alnum_punc_tab_enter" # Add groups from group(5) menu_list="$menu_list $( pw groupshow -a | awk -F: ' function mprint(tag, item) { gsub(/'\''/, "'\''\\'\'\''", tag) gsub(/'\''/, "'\''\\'\'\''", item) printf "'\'%s\'\ \'%s\''\n", tag, item } !/^[[:space:]]*(#|$)/ { mprint($1, $1) } ' )" local height width rows eval f_dialog_menu_size height width rows \ \"\$DIALOG_TITLE\" \ \"\$DIALOG_BACKTITLE\" \ \"\$prompt\" \ \"\$hline\" \ $menu_list local menu_choice menu_choice=$( eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_cancel\" \ --default-item \"\$defaultitem\" \ --menu \"\$prompt\" \ $height $width $rows \ $menu_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) local retval=$? f_dialog_menutag_store -s "$menu_choice" return $retval } # f_dialog_input_group_name $var_to_set [$group_name] # # Allows the user to enter a name for a new group. If the user does not cancel # or press ESC, the $var_to_set variable will hold the newly-configured value # upon return. # f_dialog_input_group_name() { local __var_to_set="$1" __name="$2" # # Loop until the user provides taint-free/valid input # local __input="$__name" while :; do # Return if user has either pressed ESC or chosen Cancel/No f_dialog_input __input "$msg_group" "$__input" \ "$hline_alnum_tab_enter" || return $? # Check for no-change if [ "$__input" = "$__name" ]; then setvar "$__var_to_set" "$__input" return $DIALOG_OK fi # Check for NULL entry if [ ! "$__input" ]; then f_show_msg "$msg_group_is_empty" continue fi # Check for invalid entry case "$__input" in [!a-zA-Z]*) f_show_msg "$msg_group_must_start_with_letter" continue esac # Check for duplicate entry if f_quietly pw groupshow -n "$__input"; then f_show_msg "$msg_group_already_used" "$__input" continue fi setvar "$__var_to_set" "$__input" break done return $DIALOG_OK } # f_dialog_input_group_password $var_to_set $dvar_to_set # # Prompt the user to enter a password (twice). If the user does not cancel or # press ESC, $var_to_set will hold the confirmed user entry. Otherwise, if the # user cancels or enters a NULL password (twice), they are given the choice to # disable password authentication for the given group, wherein $dvar_to_set has # a value of 1 to indicate password authentication should be disabled. # f_dialog_input_group_password() { local __var_to_set="$1" __dvar_to_set="$2" local __prompt1="$msg_group_password" local __prompt2="$msg_reenter_group_password" local __hline="$hline_alnum_punc_tab_enter" local __height1 __width1 f_dialog_inputbox_size __height1 __width1 \ "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$__prompt1" \ "" \ "$__hline" local __height2 __width2 f_dialog_inputbox_size __height2 __width2 \ "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$__prompt2" \ "" \ "$__hline" # # Loop until the user provides taint-free/valid input # local __retval __password1 __password2 while :; do __password1=$( $DIALOG \ --title "$DIALOG_TITLE" \ --backtitle "$DIALOG_BACKTITLE" \ --hline "$__hline" \ --ok-label "$msg_ok" \ --cancel-label "$msg_cancel" \ --insecure \ --passwordbox "$__prompt1" \ $__height1 $__width1 \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) __retval=$? debug= f_dialog_line_sanitize __password1 # Return if user has either pressed ESC or chosen Cancel/No [ $__retval -eq $DIALOG_OK ] || return $__retval __password2=$( $DIALOG \ --title "$DIALOG_TITLE" \ --backtitle "$DIALOG_BACKTITLE" \ --hline "$__hline" \ --ok-label "$msg_ok" \ --cancel-label "$msg_cancel" \ --insecure \ --passwordbox "$__prompt2" \ $__height2 $__width2 \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) __retval=$? debug= f_dialog_line_sanitize __password2 # Return if user has either pressed ESC or chosen Cancel/No [ $__retval -eq $DIALOG_OK ] || return $__retval # Check for password mismatch if [ "$__password1" != "$__password2" ]; then f_show_msg "$msg_group_passwords_do_not_match" continue fi # Check for NULL entry if [ ! "$__password1" ]; then f_dialog_yesno "$msg_disable_password_auth_for_group" __retval=$? if [ $__retval -eq $DIALOG_ESC ]; then return $__retval elif [ $__retval -eq $DIALOG_OK ]; then setvar "$__dvar_to_set" 1 else continue # back to password prompt fi else setvar "$__dvar_to_set" "" fi setvar "$__var_to_set" "$__password1" break done return $DIALOG_OK } # f_dialog_input_group_gid $var_to_set [$group_gid] # # Allow the user to enter a new GID for a given group. If the user does not # cancel or press ESC, the $var_to_set variable will hold the newly-configured # value upon return. # f_dialog_input_group_gid() { local __var_to_set="$1" __input="$2" # Return if user has either pressed ESC or chosen Cancel/No f_dialog_input __input "$msg_group_id_leave_empty_for_default" \ "$__input" "$hline_num_tab_enter" || return $? setvar "$__var_to_set" "$__input" return $DIALOG_OK } # f_dialog_input_group_members $var_to_set [$group_members] # # Allow the user to modify a list of members for a given group. If the user # does not cancel or press ESC, the $var_to_set variable will hold the newly- # configured value upon return. # f_dialog_input_group_members() { local __var_to_set="$1" __input="$2" local __prompt="$msg_group_members:" local __menu_list=" 'X' '$msg_continue' '1' '$msg_select_group_members_from_list' '2' '$msg_enter_group_members_manually' " # END-QUOTE local __defaultitem= local __hline="$hline_num_arrows_tab_enter" local __mheight __mwidth __mrows eval f_dialog_menu_size __mheight __mwidth __mrows \ \"\$DIALOG_TITLE\" \ \"\$DIALOG_BACKTITLE\" \ \"\$__prompt\" \ \"\$__hline\" \ $__menu_list local __menu_choice __retval while :; do __menu_choice=$( eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$__hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_cancel\" \ --default-item \"\$__defaultitem\" \ --menu \"\$__prompt\" \ $__mheight $__mwidth $__mrows \ $__menu_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) __retval=$? f_dialog_data_sanitize __menu_choice __defaultitem="$__menu_choice" f_dprintf "retval=%u menu_choice=[%s]" \ $__retval "$__menu_choice" # Return if user has either pressed ESC or chosen Cancel/No [ $__retval -eq $DIALOG_OK ] || return $__retval local __group_members case "$__menu_choice" in X) # Exit break ;; 1) # Select Group Members from a list local __check_list= # Calculated below local __user_list __u __user __length=0 __user_list=$( pw usershow -a | awk -F: '!/^[[:space:]]*(#|$)/{print $1}' ) while [ $__length -ne ${#__user_list} ]; do __u="${__user_list%%$NL*}" # First line f_shell_escape "$__u" __user # Format of a checklist entry: tag item status __check_list="$__check_list '$__user' ''" case "$__input" in "$__u"|"$__u",*|*,"$__u",*|*,"$__u") __check_list="$__check_list on" ;; *) __check_list="$__check_list off" esac __length=${#__user_list} __user_list="${__user_list#*$NL}" # Kill line done local __cheight __cwidth __crows eval f_dialog_checklist_size \ __cheight __cwidth __crows \ \"\$DIALOG_TITLE\" \ \"\$DIALOG_BACKTITLE\" \ \"\$__prompt\" \ \"\$__hline\" \ $__check_list __group_members=$( eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --separate-output \ --hline \"\$__hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_cancel\" \ --checklist \"\$__prompt\" \ $__cheight $__cwidth $__crows \ $__check_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) || continue # Return to previous menu if user either # pressed ESC or chose Cancel/No f_dialog_data_sanitize __group_members # # Convert the newline separated list into a comma- # separated one so that if the user switches over to # manual editing, list reflects checklist selections # f_replaceall "$__group_members" "[$NL]" "," __input ;; 2) # Enter Group Members manually local __prompt2="$msg_group_members" __prompt2="$__prompt2 ($msg_separated_by_commas)" f_dialog_input __group_members \ "$__prompt2" "$__input" \ "$hline_num_tab_enter" || continue # Return to previous menu if user either # pressed ESC or chose Cancel/No __input="$__group_members" ;; esac done setvar "$__var_to_set" "$__input" return $DIALOG_OK } # f_dialog_menu_group_add [$defaultitem] # # Present a menu detailing the properties of a group that is about to be added. # The user's menu choice is available using f_dialog_menutag_fetch(). Returns # success unless the user chose Cancel or pressed ESC. Data to display is taken # from environment variables group_name, group_gid, and group_members. If # $defaultitem is present and non-NULL, initially highlight the item in the # menu. # f_dialog_menu_group_add() { local prompt="$msg_save_exit_or_cancel" local menu_list # Calculated below local defaultitem="$1" local hline="$hline_arrows_tab_enter" # Localize potentially hostile variables and escape their values # to the local variable (see f_shell_escape() of `strings.subr') local var for var in gid members name; do local _group_$var eval f_shell_escape \"\$group_$var\" _group_$var done menu_list=" 'X' '$msg_add/$msg_exit' '1' '$msg_group: $_group_name' '2' '$msg_password: -----' '3' '$msg_group_id: $_group_gid' '4' '$msg_group_members: $_group_members' " # END-QUOTE local height width rows eval f_dialog_menu_size height width rows \ \"\$DIALOG_TITLE\" \ \"\$DIALOG_BACKTITLE\" \ \"\$prompt\" \ \"\$hline\" \ $menu_list local menu_choice menu_choice=$( eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_cancel\" \ --default-item \"\$defaultitem\" \ --menu \"\$prompt\" \ $height $width $rows \ $menu_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) local retval=$? f_dialog_data_sanitize menu_choice f_dialog_menutag_store "$menu_choice" return $retval } # f_dialog_menu_group_delete $group [$defaultitem] # # Present a menu detailing the properties of a group that is about to be # deleted. The user's menu choice is available using f_dialog_menutag_fetch(). # Returns success unless the user chose Cancel or pressed ESC. Data to display # is populated automatically from the system accounting database for the given # $group argument. If $defaultitem is present and non-NULL, initially highlight # the item in the menu. # f_dialog_menu_group_delete() { local prompt="$msg_delete_exit_or_cancel" local menu_list # Calculated below local defaultitem="$2" local hline="$hline_arrows_tab_enter" local group_name group_password group_gid group_members f_input_group "$1" # Localize potentially hostile variables and escape their values # to the local variable (see f_shell_escape() of `strings.subr') local var for var in gid members name; do local _group_$var eval f_shell_escape \"\$group_$var\" _group_$var done menu_list=" 'X' '$msg_delete/$msg_exit' '1' '$msg_group: $_group_name' '-' '$msg_password: -----' '-' '$msg_group_id: $_group_gid' '-' '$msg_group_members: $_group_members' " # END-QUOTE local height width rows eval f_dialog_menu_size height width rows \ \"\$DIALOG_TITLE\" \ \"\$DIALOG_BACKTITLE\" \ \"\$prompt\" \ \"\$hline\" \ $menu_list local menu_choice menu_choice=$( eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_cancel\" \ --default-item \"\$defaultitem\" \ --menu \"\$prompt\" \ $height $width $rows \ $menu_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) local retval=$? f_dialog_data_sanitize menu_choice f_dialog_menutag_store "$menu_choice" return $retval } # f_dialog_menu_group_edit [$defaultitem] # # Present a menu detailing the properties of a group that is about to be # modified. The user's menu choice is available using f_dialog_menutag_fetch(). # Returns success unless the user chose Cancel or pressed ESC. Data to display # is taken from environment variables group_name, group_gid, and group_members. # If $defaultitem is present and non-NULL, initially highlight the item in the # menu. # f_dialog_menu_group_edit() { local prompt="$msg_save_exit_or_cancel" local menu_list # Calculated below local defaultitem="$1" local hline="$hline_arrows_tab_enter" # Localize potentially hostile variables and escape their values # to the local variable (see f_shell_escape() of `strings.subr') local var for var in gid members name; do local _group_$var eval f_shell_escape \"\$group_$var\" _group_$var done menu_list=" 'X' '$msg_save/$msg_exit' '1' '$msg_group: $_group_name' '2' '$msg_password: -----' '3' '$msg_group_id: $_group_gid' '4' '$msg_group_members: $_group_members' " # END-QUOTE local height width rows eval f_dialog_menu_size height width rows \ \"\$DIALOG_TITLE\" \ \"\$DIALOG_BACKTITLE\" \ \"\$prompt\" \ \"\$hline\" \ $menu_list local menu_choice menu_choice=$( eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_cancel\" \ --default-item \"\$defaultitem\" \ --menu \"\$prompt\" \ $height $width $rows \ $menu_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) local retval=$? f_dialog_data_sanitize menu_choice f_dialog_menutag_store "$menu_choice" return $retval } ############################################################ MAIN f_dprintf "%s: Successfully loaded." usermgmt/group_input.subr fi # ! $_USERMGMT_GROUP_INPUT_SUBR