summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsdconfig
diff options
context:
space:
mode:
authordteske <dteske@FreeBSD.org>2014-04-01 00:19:13 +0000
committerdteske <dteske@FreeBSD.org>2014-04-01 00:19:13 +0000
commit33929c79234f299c2c45f4278f4f6194993341f1 (patch)
tree88dc95c2cdf07db9c66e2f378ca9a7b0fbd47237 /usr.sbin/bsdconfig
parent2b41b2e9047fbca25082d749ffc237b6d7156dc7 (diff)
downloadFreeBSD-src-33929c79234f299c2c45f4278f4f6194993341f1.zip
FreeBSD-src-33929c79234f299c2c45f4278f4f6194993341f1.tar.gz
MFC revisions 260894,260899,262895-262902,262904,262908-262910,262982,
262984,263133-263137,263139,263141,263144-263150, and (partially) 263249 (31 revisions; summarized below)... r260894: Optimize f_expand_number(), improving performance r260899: s/__number/__num/ in f_expand_number() r262895: Allow dispatched reswords to carry arguments r262896: Add missing local declaration r262897: Fix a typo in a comment r262898: Fix incorrect return status if var_to_set and var_to_get are same r262899: Make f_show_err non-fatal r262900: Centralize function name; Update a comment while here r262901: s/__num/__number/ in f_expand_number() r262902: Comment to go with NL global introduced by previous commit r262904: Rewrite groupmgmt -- hooking it into the scripting system r262908: Change dispatch words from group* to *Group for backward compat r262909: Fix copy/paste error in a comment r262910: Take a group name on the command-line if available r262982: Whitespace r262984: Remove vestigial global, no longer used since r262904 r263133: Remove indexfile from debug statement (already logged) r263134: Add debug statement just before attempting to exec a module r263135: Comments r263136: Update copyright r263137: Fix future namespace issues for functions taking $var_to_set r263139: Remove useless NULL string in compound strings r263141: Pointy hat! Fix a broken f_isinteger() r263144: Fix a code-typo that prevented auto-sizing of a dialog r263145: Fix comments and whitespace r263146: Reduce the sleep cycle when using dialog(1) [infobox] to 1-second r263147: Fix a bug preventing errors from pw(8) from appearing r263148: For non-interactive scripts, forgot to check argument r263149: Add protection against input containing single-quotes r263150: Rewrite usermgmt r263249: (partial) Add more obsolete files
Diffstat (limited to 'usr.sbin/bsdconfig')
-rwxr-xr-xusr.sbin/bsdconfig/bsdconfig8
-rw-r--r--usr.sbin/bsdconfig/share/common.subr13
-rw-r--r--usr.sbin/bsdconfig/share/device.subr10
-rw-r--r--usr.sbin/bsdconfig/share/dialog.subr74
-rw-r--r--usr.sbin/bsdconfig/share/keymap.subr2
-rw-r--r--usr.sbin/bsdconfig/share/script.subr36
-rw-r--r--usr.sbin/bsdconfig/share/strings.subr41
-rw-r--r--usr.sbin/bsdconfig/share/variable.subr21
-rw-r--r--usr.sbin/bsdconfig/timezone/share/menus.subr4
-rw-r--r--usr.sbin/bsdconfig/usermgmt/Makefile3
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupadd19
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupdel16
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupedit18
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupinput293
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/messages.subr17
-rw-r--r--usr.sbin/bsdconfig/usermgmt/share/Makefile2
-rw-r--r--usr.sbin/bsdconfig/usermgmt/share/group.subr518
-rw-r--r--usr.sbin/bsdconfig/usermgmt/share/group_input.subr480
-rw-r--r--usr.sbin/bsdconfig/usermgmt/share/user.subr1184
-rw-r--r--usr.sbin/bsdconfig/usermgmt/share/user_input.subr1345
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/useradd19
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/userdel16
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/useredit18
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/userinput508
24 files changed, 3085 insertions, 1580 deletions
diff --git a/usr.sbin/bsdconfig/bsdconfig b/usr.sbin/bsdconfig/bsdconfig
index c158bfa..62699f2 100755
--- a/usr.sbin/bsdconfig/bsdconfig
+++ b/usr.sbin/bsdconfig/bsdconfig
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -315,8 +315,7 @@ if [ "$pgm" != "bsdconfig" ]; then
if indexfile=$( f_index_file "$pgm" ) &&
cmd=$( f_index_menusel_command "$indexfile" "$pgm" )
then
- f_dprintf "pgm=[%s] indexfile=[%s] cmd=[%s]" \
- "$pgm" "$indexfile" "$cmd"
+ f_dprintf "pgm=[%s] cmd=[%s] *=[%s]" "$pgm" "$cmd" "$*"
exec "$cmd" "$@" || exit 1
else
f_include $BSDCFG_SHARE/script.subr
@@ -324,7 +323,7 @@ if [ "$pgm" != "bsdconfig" ]; then
[ "$pgm" = "$resword" ] || continue
# Found a match
f_dprintf "pgm=[%s] A valid resWord!" "$pgm"
- f_dispatch $resword
+ f_dispatch $resword $resword "$@"
exit $?
done
fi
@@ -382,6 +381,7 @@ if [ "$1" ]; then
# Not reached
fi
+ f_dprintf "cmd=[%s] *=[%s]" "$cmd" "$*"
shift
exec $cmd ${USE_XDIALOG:+-X} "$@" || exit 1
# Not reached
diff --git a/usr.sbin/bsdconfig/share/common.subr b/usr.sbin/bsdconfig/share/common.subr
index 94b5cfd..7c3379e 100644
--- a/usr.sbin/bsdconfig/share/common.subr
+++ b/usr.sbin/bsdconfig/share/common.subr
@@ -1,7 +1,7 @@
if [ ! "$_COMMON_SUBR" ]; then _COMMON_SUBR=1
#
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -153,7 +153,7 @@ f_debug_init()
# Process stored command-line arguments
#
set -- $ARGV
- local OPTIND
+ local OPTIND flag
f_dprintf "f_debug_init: ARGV=[%s] GETOPTS_STDARGS=[%s]" \
"$ARGV" "$GETOPTS_STDARGS"
while getopts "$GETOPTS_STDARGS$GETOPTS_EXTRA$GETOPTS_ALLFLAGS" flag \
@@ -270,9 +270,9 @@ f_getvar()
{
local __var_to_get="$1" __var_to_set="$2"
[ "$__var_to_set" ] || local value
- eval ${__var_to_set:-value}=\"\${$__var_to_get}\"
eval [ \"\${$__var_to_get+set}\" ]
local __retval=$?
+ eval ${__var_to_set:-value}=\"\${$__var_to_get}\"
eval f_dprintf '"f_getvar: var=[%s] value=[%s] r=%u"' \
\"\$__var_to_get\" \"\$${__var_to_set:-value}\" \$__retval
[ "$__var_to_set" ] || { [ "$value" ] && echo "$value"; }
@@ -368,13 +368,10 @@ f_show_msg()
# f_show_err $format [$arguments ...]
#
# Display a message in a dialog box with ``Error'' i18n title (overridden by
-# setting msg_error) using printf(1) syntax. If running non-interactively,
-# the process will terminate (using [above] f_die()).
+# setting msg_error) using printf(1) syntax.
#
f_show_err()
{
- [ "$nonInteractive" ] && f_die
-
local msg
msg=$( printf "$@" )
@@ -523,7 +520,7 @@ f_include_lang()
# f_usage $file "FOO" "BAR"
#
# Will cause instances of "@FOO@" appearing in $file to be replaced with the
-# text "BAR" before bering printed to the screen.
+# text "BAR" before being printed to the screen.
#
# This function is a two-parter. Below is the awk(1) portion of the function,
# afterward is the sh(1) function which utilizes the below awk script.
diff --git a/usr.sbin/bsdconfig/share/device.subr b/usr.sbin/bsdconfig/share/device.subr
index e42751e..9201b95 100644
--- a/usr.sbin/bsdconfig/share/device.subr
+++ b/usr.sbin/bsdconfig/share/device.subr
@@ -1,6 +1,6 @@
if [ ! "$_DEVICE_SUBR" ]; then _DEVICE_SUBR=1
#
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -170,11 +170,10 @@ f_device_reset()
for dev in $DEVICES; do
f_device_shutdown $dev
- #
- # XXX this potentially leaks $dev->private if it's being
+ # XXX This potentially leaks $dev->private if it's being
# used to point to something dynamic, but you're not supposed
# to call this routine at such times that some open instance
- # has its private member pointing somewhere anyway. XXX
+ # has its private member pointing somewhere anyway.
#
f_struct_free device_$dev
done
@@ -325,8 +324,7 @@ f_device_get_all()
case "$diskname" in
cd*)
- # XXX
- # Due to unknown reasons, kern.disks returns SCSI
+ # XXX Due to unknown reasons, kern.disks returns SCSI
# CDROM as a valid disk. This will prevent bsdconfig
# from presenting SCSI CDROMs as available disks in
# various menus. Why GEOM treats SCSI CDROM as a disk
diff --git a/usr.sbin/bsdconfig/share/dialog.subr b/usr.sbin/bsdconfig/share/dialog.subr
index d05d4fb..e0dfe80 100644
--- a/usr.sbin/bsdconfig/share/dialog.subr
+++ b/usr.sbin/bsdconfig/share/dialog.subr
@@ -1,6 +1,6 @@
if [ ! "$_DIALOG_SUBR" ]; then _DIALOG_SUBR=1
#
-# Copyright (c) 2006-2013 Devin Teske
+# Copyright (c) 2006-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -469,16 +469,17 @@ f_dialog_menu_constrain()
# Print debug warnings if any given (non-NULL) argument are invalid
# NOTE: Don't change the name of $__{var,min,}{height,width,rows}
#
- local __height __width __rows
+ local __height_menu_constrain __width_menu_constrain
+ local __rows_menu_constrain
local __arg __cp __fname=f_dialog_menu_constrain
for __arg in height width rows; do
debug= f_getvar __var_$__arg __cp
[ "$__cp" ] || continue
- if ! debug= f_getvar "$__cp" __$__arg; then
+ if ! debug= f_getvar "$__cp" __${__arg}_menu_constrain; then
f_dprintf "%s: var_%s variable \`%s' not set" \
$__fname $__arg "$__cp"
__retval=$FAILURE
- elif ! eval f_isinteger \$__$__arg; then
+ elif ! eval f_isinteger \$__${__arg}_menu_constrain; then
f_dprintf "%s: var_%s variable value not a number" \
$__fname $__arg
__retval=$FAILURE
@@ -502,9 +503,11 @@ f_dialog_menu_constrain()
# Adjust height if desired
if [ "$__var_height" ]; then
- if [ $__height -lt ${__min_height:-0} ]; then
+ if [ $__height_menu_constrain -lt ${__min_height:-0} ]; then
setvar "$__var_height" $__min_height
- elif [ $__height -gt $__max_height_menu_constrain ]; then
+ elif [ $__height_menu_constrain -gt \
+ $__max_height_menu_constrain ]
+ then
setvar "$__var_height" $__max_height_menu_constrain
fi
fi
@@ -516,9 +519,11 @@ f_dialog_menu_constrain()
else
: ${__min_width:=${DIALOG_MIN_WIDTH:-24}}
fi
- if [ $__width -lt $__min_width ]; then
+ if [ $__width_menu_constrain -lt $__min_width ]; then
setvar "$__var_width" $__min_width
- elif [ $__width -gt $__max_width_menu_constrain ]; then
+ elif [ $__width_menu_constrain -gt \
+ $__max_width_menu_constrain ]
+ then
setvar "$__var_width" $__max_width_menu_constrain
fi
fi
@@ -531,16 +536,20 @@ f_dialog_menu_constrain()
: ${__min_rows:=0}
fi
- local __max_rows=$(( $__max_height_menu_constrain - 7 ))
+ local __max_rows_menu_constrain=$((
+ $__max_height_menu_constrain - 7
+ ))
# If prompt_len is zero (no prompt), bump the max-rows by 1
# Default assumption is (if no argument) that there's no prompt
- [ ${__prompt_len:-0} -gt 0 ] ||
- __max_rows=$(( $__max_rows + 1 ))
+ [ ${__prompt_len:-0} -gt 0 ] || __max_rows_menu_constrain=$((
+ $__max_rows_menu_constrain + 1
+ ))
- if [ $__rows -lt $__min_rows ]; then
+ if [ $__rows_menu_constrain -lt $__min_rows ]; then
setvar "$__var_rows" $__min_rows
- elif [ $__rows -gt $__max_rows ]; then
- setvar "$__var_rows" $__max_rows
+ elif [ $__rows_menu_constrain -gt $__max_rows_menu_constrain ]
+ then
+ setvar "$__var_rows" $__max_rows_menu_constrain
fi
fi
@@ -1100,19 +1109,20 @@ f_dialog_radiolist_size()
# longest item-length (both used to bump the width), and the number of
# rows (used to bump the height).
#
- local __longest_tag=0 __longest_item=0 __rows=0
+ local __longest_tag=0 __longest_item=0 __rows_rlist_size=0
while [ $# -ge 3 ]; do
local __tag="$1" __item="$2"
shift 3 # tag/item/status
[ ${#__tag} -gt $__longest_tag ] && __longest_tag=${#__tag}
[ ${#__item} -gt $__longest_item ] && __longest_item=${#__item}
- __rows=$(( $__rows + 1 ))
+ __rows_rlist_size=$(( $__rows_rlist_size + 1 ))
done
# Adjust rows early (for up-coming height calculation)
if [ "$__var_height" -o "$__var_rows" ]; then
# Add a row for visual aid if using Xdialog(1)
- [ "$USE_XDIALOG" ] && __rows=$(( $__rows + 1 ))
+ [ "$USE_XDIALOG" ] &&
+ __rows_rlist_size=$(( $__rows_rlist_size + 1 ))
fi
# Adjust height if desired
@@ -1120,10 +1130,12 @@ f_dialog_radiolist_size()
# Add rows to height
if [ "$USE_XDIALOG" ]; then
__height_rlist_size=$((
- $__height_rlist_size + $__rows + 7 ))
+ $__height_rlist_size + $__rows_rlist_size + 7
+ ))
else
__height_rlist_size=$((
- $__height_rlist_size + $__rows + 4 ))
+ $__height_rlist_size + $__rows_rlist_size + 4
+ ))
fi
setvar "$__var_height" $__height_rlist_size
fi
@@ -1140,7 +1152,7 @@ f_dialog_radiolist_size()
fi
# Store adjusted rows if desired
- [ "$__var_rows" ] && setvar "$__var_rows" $__rows
+ [ "$__var_rows" ] && setvar "$__var_rows" $__rows_rlist_size
# Constrain height, width, and rows to sensible minimum/maximum values
# Return success if no-constrain, else return status from constrain
@@ -1220,20 +1232,26 @@ f_dialog_radiolist_with_help_size()
# all used to bump the width -- and the number of rows (used to bump
# the height).
#
- local __longest_tag=0 __longest_item=0 __longest_help=0 __rows=0
+ local __longest_tag=0 __longest_item=0 __longest_help=0
+ local __rows_rlist_with_help_size=0
while [ $# -ge 4 ]; do
local __tag="$1" __item="$2" __status="$3" __help="$4"
shift 4 # tag/item/status/help
[ ${#__tag} -gt $__longest_tag ] && __longest_tag=${#__tag}
[ ${#__item} -gt $__longest_item ] && __longest_item=${#__item}
[ ${#__help} -gt $__longest_help ] && __longest_help=${#__help}
- __rows=$(( $__rows + 1 ))
+ __rows_rlist_with_help_size=$((
+ $__rows_rlist_with_help_size + 1
+ ))
done
# Adjust rows early (for up-coming height calculation)
if [ "$__var_height" -o "$__var_rows" ]; then
# Add a row for visual aid if using Xdialog(1)
- [ "$USE_XDIALOG" ] && __rows=$(( $__rows + 1 ))
+ [ "$USE_XDIALOG" ] &&
+ __rows_rlist_with_help_size=$((
+ $__rows_rlist_with_help_size + 1
+ ))
fi
# Adjust height if desired
@@ -1241,10 +1259,14 @@ f_dialog_radiolist_with_help_size()
# Add rows to height
if [ "$USE_XDIALOG" ]; then
__height_rlist_with_help_size=$((
- $__height_rlist_with_help_size + $__rows + 7 ))
+ $__height_rlist_with_help_size +
+ $__rows_rlist_with_help_size + 7
+ ))
else
__height_rlist_with_help_size=$((
- $__height_rlist_with_help_size + $__rows + 4 ))
+ $__height_rlist_with_help_size +
+ $__rows_rlist_with_help_size + 4
+ ))
fi
setvar "$__var_height" $__height
fi
@@ -1270,7 +1292,7 @@ f_dialog_radiolist_with_help_size()
fi
# Store adjusted rows if desired
- [ "$__var_rows" ] && setvar "$__var_rows" $__rows
+ [ "$__var_rows" ] && setvar "$__var_rows" $__rows_rlist_with_help_size
# Constrain height, width, and rows to sensible minimum/maximum values
# Return success if no-constrain, else return status from constrain
diff --git a/usr.sbin/bsdconfig/share/keymap.subr b/usr.sbin/bsdconfig/share/keymap.subr
index 39b6b54..d4f391c 100644
--- a/usr.sbin/bsdconfig/share/keymap.subr
+++ b/usr.sbin/bsdconfig/share/keymap.subr
@@ -165,7 +165,7 @@ f_keymap_get_all()
marks[keym] = mark
name = keym
gsub(/[^[:alnum:]_]/, "_", name)
- gsub(/'\''/, "'\''\\'\'''\''", desc);
+ gsub(/'\''/, "'\''\\'\'\''", desc);
printf "f_keymap_checkfile %s && " \
"f_keymap_register %s '\'%s\'' %s %u\n",
keym, name, desc, keym, mark
diff --git a/usr.sbin/bsdconfig/share/script.subr b/usr.sbin/bsdconfig/share/script.subr
index a227419..b562e99 100644
--- a/usr.sbin/bsdconfig/share/script.subr
+++ b/usr.sbin/bsdconfig/share/script.subr
@@ -1,6 +1,6 @@
if [ ! "$_SCRIPT_SUBR" ]; then _SCRIPT_SUBR=1
#
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,8 @@ f_include $BSDCFG_SHARE/media/tcpip.subr
f_include $BSDCFG_SHARE/mustberoot.subr
f_include $BSDCFG_SHARE/networking/services.subr
f_include $BSDCFG_SHARE/packages/packages.subr
+f_include $BSDCFG_SHARE/usermgmt/group.subr
+f_include $BSDCFG_SHARE/usermgmt/user.subr
f_include $BSDCFG_SHARE/variable.subr
############################################################ GLOBALS
@@ -50,25 +52,23 @@ RESWORDS=
# Create a new `reserved' word for scripting purposes. Reswords call pre-
# defined functions but differ from those functions in the following ways:
#
-# + Reswords do not take arguments but instead get all their data from
-# the environment variable namespace.
# + Unless noError is set (must be non-NULL), if calling the resword
# results in failure, the application will terminate prematurely.
# + noError is unset after each/every resword is called.
#
# Reswords should not be used in bsdconfig itself (hence the name `reserved
-# word') but instead only in scripts loaded through f_script_load()).
+# word') but instead only in scripts loaded through f_script_load().
#
f_resword_new()
{
local resword="$1" func="$2"
[ "$resword" ] || return $FAILURE
f_dprintf "script.subr: New resWord %s -> %s" "$resword" "$func"
- eval $resword\(\){ f_dispatch $func $resword\; }
+ eval $resword\(\){ f_dispatch $func $resword \"\$@\"\; }
RESWORDS="$RESWORDS${RESWORDS:+ }$resword"
}
-# f_dispatch $func [$resword]
+# f_dispatch $func $resword
#
# Wrapper function used by `reserved words' (reswords) to call other functions.
# If $noError is set and non-NULL, a failure result from $func is ignored,
@@ -78,9 +78,10 @@ f_resword_new()
#
f_dispatch()
{
- local func="$1" resword="${2:-$1}"
+ local func="$1" resword="$2"
+ shift 2 # func resword
f_dprintf "f_dispatch: calling resword \`%s'" "$resword"
- eval $func
+ eval $func "$@"
local retval=$?
if [ $retval -ne $SUCCESS ]; then
local _ignore_this_error
@@ -96,7 +97,7 @@ f_dispatch()
# Load a script (usually filled with reswords). If $file is missing or NULL,
# use one of the following instead (in order):
#
-# $configFile
+# $configFile (global)
# install.cfg
# /stand/install.fg
# /tmp/install.cfg
@@ -108,9 +109,10 @@ f_dispatch()
#
f_script_load()
{
+ local funcname=f_script_load
local script="$1" config_file retval=$SUCCESS
- f_dprintf "f_script_load: script=[%s]" "$script"
+ f_dprintf "$funcname: script=[%s]" "$script"
if [ ! "$script" ]; then
f_getvar $VAR_CONFIG_FILE config_file
for script in \
@@ -130,11 +132,11 @@ f_script_load()
setvar $VAR_NONINTERACTIVE yes
if [ "$script" = "-" ]; then
- f_dprintf "f_script_load: Loading script from stdin"
+ f_dprintf "$funcname: Loading script from stdin"
eval "$( cat )"
retval=$?
else
- f_dprintf "f_script_load: Loading script \`%s'" "$script"
+ f_dprintf "$funcname: Loading script \`%s'" "$script"
if [ ! -e "$script" ]; then
f_show_msg "$msg_unable_to_open" "$script"
return $FAILURE
@@ -198,6 +200,16 @@ f_resword_new packageAdd f_package_add
f_resword_new packageDelete f_package_delete
f_resword_new packageReinstall f_package_reinstall
+# usermgmt/group.subr
+f_resword_new addGroup f_group_add
+f_resword_new deleteGroup f_group_delete
+f_resword_new editGroup f_group_edit
+
+# usermgmt/user.subr
+f_resword_new addUser f_user_add
+f_resword_new deleteUser f_user_delete
+f_resword_new editUser f_user_edit
+
# variable.subr
f_resword_new installVarDefaults f_variable_set_defaults
f_resword_new dumpVariables f_dump_variables
diff --git a/usr.sbin/bsdconfig/share/strings.subr b/usr.sbin/bsdconfig/share/strings.subr
index 9b0014f..487e061 100644
--- a/usr.sbin/bsdconfig/share/strings.subr
+++ b/usr.sbin/bsdconfig/share/strings.subr
@@ -34,6 +34,12 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
############################################################ GLOBALS
#
+# A Literal newline (for use with f_replace_all(), or IFS, or whatever)
+#
+NL="
+" # END-QUOTE
+
+#
# Valid characters that can appear in an sh(1) variable name
#
# Please note that the character ranges A-Z and a-z should be avoided because
@@ -189,7 +195,7 @@ f_number_of_lines()
f_isinteger()
{
local arg="${1#-}"
- [ "${arg:-x}" = "${arg#[!0-9]*}" ]
+ [ "${arg:-x}" = "${arg%[!0-9]*}" ]
}
# f_uriencode [$text]
@@ -265,6 +271,9 @@ f_uridecode()
# capturing in a sub-shell (which is less recommended due to performance
# degradation).
#
+# To replace newlines or a sequence containing the newline character, use $NL
+# as `\n' is not supported.
+#
f_replaceall()
{
local __left="" __right="$1"
@@ -372,14 +381,13 @@ f_expand_number()
local __cp __num __bshift __maxinput
# Remove any leading non-digits
- while :; do
- __cp="$__string"
- __string="${__cp#[!0-9]}"
- [ "$__string" = "$__cp" ] && break
- done
+ __string="${__string#${__string%%[0-9]*}}"
+
+ # Store the numbers (no trailing suffix)
+ __num="${__string%%[!0-9]*}"
# Produce `-1' if string didn't contain any digits
- if [ ! "$__string" ]; then
+ if [ ! "$__num" ]; then
if [ "$__var_to_set" ]; then
setvar "$__var_to_set" -1
else
@@ -388,25 +396,8 @@ f_expand_number()
return 1 # 1 = "Given $string contains no digits"
fi
- # Store the numbers
- __num="${__string%%[!0-9]*}"
-
- # Shortcut
- if [ $__num -eq 0 ]; then
- if [ "$__var_to_set" ]; then
- setvar "$__var_to_set" 0
- else
- echo 0
- fi
- return $SUCCESS
- fi
-
# Remove all the leading numbers from the string to get at the prefix
- while :; do
- __cp="$__string"
- __string="${__cp#[0-9]}"
- [ "$__string" = "$__cp" ] && break
- done
+ __string="${__string#"$__num"}"
#
# Test for invalid prefix (and determine bitshift length)
diff --git a/usr.sbin/bsdconfig/share/variable.subr b/usr.sbin/bsdconfig/share/variable.subr
index 55bc850..c453f67 100644
--- a/usr.sbin/bsdconfig/share/variable.subr
+++ b/usr.sbin/bsdconfig/share/variable.subr
@@ -1,6 +1,6 @@
if [ ! "$_VARIABLE_SUBR" ]; then _VARIABLE_SUBR=1
#
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -241,6 +241,10 @@ f_variable_new VAR_FTP_PORT ftpPort
f_variable_new VAR_FTP_STATE ftpState
f_variable_new VAR_FTP_USER ftpUser
f_variable_new VAR_GATEWAY defaultrouter
+f_variable_new VAR_GROUP group
+f_variable_new VAR_GROUP_GID groupGid
+f_variable_new VAR_GROUP_MEMBERS groupMembers
+f_variable_new VAR_GROUP_PASSWORD groupPassword
f_variable_new VAR_HOSTNAME hostname
f_variable_new VAR_HTTP_DIR httpDirectory
f_variable_new VAR_HTTP_FTP_MODE httpFtpMode
@@ -279,6 +283,21 @@ f_variable_new VAR_SLOW_ETHER slowEthernetCard
f_variable_new VAR_TRY_DHCP tryDHCP
f_variable_new VAR_TRY_RTSOL tryRTSOL
f_variable_new VAR_UFS_PATH ufs
+f_variable_new VAR_USER user
+f_variable_new VAR_USER_ACCOUNT_EXPIRE userAccountExpire
+f_variable_new VAR_USER_DOTFILES_CREATE userDotfilesCreate
+f_variable_new VAR_USER_GECOS userGecos
+f_variable_new VAR_USER_GID userGid
+f_variable_new VAR_USER_GROUPS userGroups
+f_variable_new VAR_USER_GROUP_DELETE userGroupDelete
+f_variable_new VAR_USER_HOME userHome
+f_variable_new VAR_USER_HOME_CREATE userHomeCreate
+f_variable_new VAR_USER_HOME_DELETE userHomeDelete
+f_variable_new VAR_USER_LOGIN_CLASS userLoginClass
+f_variable_new VAR_USER_PASSWORD userPassword
+f_variable_new VAR_USER_PASSWORD_EXPIRE userPasswordExpire
+f_variable_new VAR_USER_SHELL userShell
+f_variable_new VAR_USER_UID userUid
f_variable_new VAR_ZFSINTERACTIVE zfsInteractive
#
diff --git a/usr.sbin/bsdconfig/timezone/share/menus.subr b/usr.sbin/bsdconfig/timezone/share/menus.subr
index 2028bf3..ef3979b 100644
--- a/usr.sbin/bsdconfig/timezone/share/menus.subr
+++ b/usr.sbin/bsdconfig/timezone/share/menus.subr
@@ -104,7 +104,7 @@ f_make_menus_awk='
function add_zone_n_to_country_menu(tlc, n)
{
zone_title = ENVIRON["country_" tlc "_descr_" n]
- gsub(/'\''/, "'\''\\'\'''\''", zone_title)
+ gsub(/'\''/, "'\''\\'\'\''", zone_title)
country_menu_list[tlc] = country_menu_list[tlc] \
( length(country_menu_list[tlc]) > 0 ? "\n" : "" ) \
n " '\''" zone_title "'\''"
@@ -121,7 +121,7 @@ BEGIN {
{
tlc = countries[cp]
title = ENVIRON["country_" tlc "_name"]
- gsub(/'\''/, "'\''\\'\'''\''", title)
+ gsub(/'\''/, "'\''\\'\'\''", title)
nzones = ENVIRON["country_" tlc "_nzones"]
if (!nzones)
{
diff --git a/usr.sbin/bsdconfig/usermgmt/Makefile b/usr.sbin/bsdconfig/usermgmt/Makefile
index 910d380..5211c3c 100644
--- a/usr.sbin/bsdconfig/usermgmt/Makefile
+++ b/usr.sbin/bsdconfig/usermgmt/Makefile
@@ -8,8 +8,7 @@ FILESDIR= ${LIBEXECDIR}/bsdconfig/070.usermgmt
FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
-SCRIPTS= groupadd groupdel groupedit groupinput \
- useradd userdel useredit userinput usermgmt
+SCRIPTS= groupadd groupdel groupedit useradd userdel useredit usermgmt
beforeinstall:
mkdir -p ${DESTDIR}${FILESDIR}
diff --git a/usr.sbin/bsdconfig/usermgmt/groupadd b/usr.sbin/bsdconfig/usermgmt/groupadd
index 62f062d..cba0f2b 100755
--- a/usr.sbin/bsdconfig/usermgmt/groupadd
+++ b/usr.sbin/bsdconfig/usermgmt/groupadd
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,11 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
. $BSDCFG_SHARE/common.subr || exit 1
f_dprintf "%s: loading includes..." "$0"
f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/mustberoot.subr
+f_include $BSDCFG_SHARE/usermgmt/group.subr
BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
f_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" ipgm &&
pgm="${ipgm:-$pgm}"
@@ -55,9 +58,19 @@ done
shift $(( $OPTIND - 1 ))
#
-# Chain-load to groupinput to centralize code and minimize duplication
+# Initialize
#
-$BSDCFG_LIBE/$APP_DIR/groupinput ${USE_XDIALOG:+-X} mode="Add"
+f_dialog_title "$msg_add $msg_group"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Add a group
+#
+# NB: If given an argument on the command-line use it; otherwise fall-back to
+# environment variable $group (handle $VAR_GROUP).
+#
+f_group_add ${1:+"$1"}
################################################################################
# END
diff --git a/usr.sbin/bsdconfig/usermgmt/groupdel b/usr.sbin/bsdconfig/usermgmt/groupdel
index aa1c305..ea55489 100755
--- a/usr.sbin/bsdconfig/usermgmt/groupdel
+++ b/usr.sbin/bsdconfig/usermgmt/groupdel
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
f_dprintf "%s: loading includes..." "$0"
f_include $BSDCFG_SHARE/dialog.subr
f_include $BSDCFG_SHARE/mustberoot.subr
+f_include $BSDCFG_SHARE/usermgmt/group.subr
f_include $BSDCFG_SHARE/usermgmt/group_input.subr
BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
@@ -65,9 +66,17 @@ f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
f_mustberoot_init
#
+# If given a group name, operate on it and exit
+#
+if [ "$1" ]; then
+ f_group_delete "$1"
+ exit $SUCCESS
+fi
+
+#
# Loop until the user Exits, Cancels or presses ESC
#
-defaultitem=""
+defaultitem=
while :; do
f_dialog_menu_group_list "$defaultitem"
retval=$?
@@ -81,8 +90,7 @@ while :; do
# Anything else is a group name
- $BSDCFG_LIBE/$APP_DIR/groupinput \
- ${USE_XDIALOG:+-X} mode="Delete" group="$mtag"
+ f_group_delete "$mtag"
done
exit $SUCCESS
diff --git a/usr.sbin/bsdconfig/usermgmt/groupedit b/usr.sbin/bsdconfig/usermgmt/groupedit
index 953f4f5..2338d57 100755
--- a/usr.sbin/bsdconfig/usermgmt/groupedit
+++ b/usr.sbin/bsdconfig/usermgmt/groupedit
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
f_dprintf "%s: loading includes..." "$0"
f_include $BSDCFG_SHARE/dialog.subr
f_include $BSDCFG_SHARE/mustberoot.subr
+f_include $BSDCFG_SHARE/usermgmt/group.subr
f_include $BSDCFG_SHARE/usermgmt/group_input.subr
BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
@@ -65,9 +66,17 @@ f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
f_mustberoot_init
#
-# Loop until the user Exits, Cancels or presses ESC
+# If given a group name, operate on it and exit
#
-defaultitem=""
+if [ "$1" ]; then
+ f_group_edit "$1"
+ exit $SUCCESS
+fi
+
+#
+# Present a list of groups and loop until user Exits, Cancels or presses ESC
+#
+defaultitem=
while :; do
f_dialog_menu_group_list "$defaultitem"
retval=$?
@@ -81,8 +90,7 @@ while :; do
# Anything else is a group name
- $BSDCFG_LIBE/$APP_DIR/groupinput \
- ${USE_XDIALOG:+-X} mode="Edit/View" group="$mtag"
+ f_group_edit "$mtag"
done
exit $SUCCESS
diff --git a/usr.sbin/bsdconfig/usermgmt/groupinput b/usr.sbin/bsdconfig/usermgmt/groupinput
deleted file mode 100755
index f98e890..0000000
--- a/usr.sbin/bsdconfig/usermgmt/groupinput
+++ /dev/null
@@ -1,293 +0,0 @@
-#!/bin/sh
-#-
-# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 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.
-#
-# $FreeBSD$
-#
-############################################################ INCLUDES
-
-BSDCFG_SHARE="/usr/share/bsdconfig"
-. $BSDCFG_SHARE/common.subr || exit 1
-f_dprintf "%s: loading includes..." "$0"
-f_include $BSDCFG_SHARE/dialog.subr
-f_include $BSDCFG_SHARE/mustberoot.subr
-f_include $BSDCFG_SHARE/usermgmt/group_input.subr
-
-BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
-f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
-
-f_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" ipgm &&
- pgm="${ipgm:-$pgm}"
-
-############################################################ CONFIGURATION
-
-# set some reasonable defaults if /etc/adduser.conf does not exist.
-[ -f /etc/adduser.conf ] && f_include /etc/adduser.conf
-: ${passwdtype:="yes"}
-
-############################################################ FUNCTIONS
-
-# save_changes
-#
-# Save any/all settings (actions performed depend on $mode value).
-#
-save_changes()
-{
- local funcname=save_changes
-
- case "$mode" in
- Delete)
- f_eval_catch $funcname pw 'pw groupdel "%s"' "$group_name" ||
- return $?
- f_show_msg "$msg_group_deleted"
- ;;
- Add)
- local cmd="pw groupadd -n '$group_name'"
- [ "$group_gid" ] && cmd="$cmd -g '$group_gid'"
- [ "$group_members" != "$cur_group_members" ] &&
- cmd="$cmd -M '$group_members'"
- if [ "$pw_group_password_disable" ]; then
- f_eval_catch $funcname pw '%s -h -' "$cmd"
- elif [ "$group_password" ]; then
- echo "$group_password" |
- f_eval_catch $funcname pw '%s -h 0' "$cmd"
- else
- f_eval_catch $funcname pw '%s' "$cmd"
- fi || return $?
- f_show_msg "$msg_group_added"
- ;;
- Edit/View)
- local cmd="pw groupmod -n '$group_name'"
- [ "$group_gid" ] && cmd="$cmd -g '$group_gid'"
- [ "$group_members" != "$cur_group_members" ] &&
- cmd="$cmd -M '$group_members'"
- if [ "$pw_group_password_disable" ]; then
- f_eval_catch $funcname pw '%s -h -' "$cmd"
- elif [ "$group_password" ]; then
- echo "$group_password" |
- f_eval_catch $funcname pw '%s -h 0' "$cmd"
- else
- f_eval_catch $funcname pw '%s' "$cmd"
- fi || return $?
- f_show_msg "$msg_group_updated"
- ;;
- esac
-
- save_flag=
- return $SUCCESS
-}
-
-# dialog_title_update $mode
-#
-# Set the title based on the given $mode.
-#
-dialog_title_update()
-{
- local mode="$1"
- case "$mode" in
- Add) f_dialog_title "$msg_add $msg_group" ;;
- Edit/View) f_dialog_title "$msg_edit_view $msg_group: $group" ;;
- Delete) f_dialog_title "$msg_delete $msg_group: $group" ;;
- esac
-}
-
-############################################################ MAIN
-
-# Incorporate rc-file if it exists
-[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
-
-#
-# Process command-line arguments
-#
-while [ $# -gt 0 ]; do
- key="${1%%=*}"
- value="${1#*=}"
- f_dprintf "key=[%s] value=[%s]" "$key" "$value"
- case "$key" in
- mode) mode="$value" ;;
- group) group="$value" ;;
- esac
- shift
-done
-f_dprintf "mode=[%s] group=[%s]" "$mode" "$group"
-
-#
-# Initialize
-#
-dialog_title_update "$mode"
-f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
-f_mustberoot_init
-menu_text=
-save_flag=
-hline="$hline_arrows_tab_enter"
-
-if [ "$mode" = "Add" ]; then
- f_dialog_input_group_name || exit 0
-
- f_dialog_noyes "$msg_use_default_values_for_all_account_details"
- retval=$?
-
- if [ $retval -eq $DIALOG_ESC ]; then
- exit $SUCCESS
- elif [ $retval -ne $DIALOG_OK ]; then
- #
- # Ask a series of questions to pre-fill the editor screen.
- #
- # The defaults used in each dialog should allow the user to
- # simply hit ENTER to proceed, because cancelling a single
- # dialog will cause them to be returned to the main groupmenu.
- #
-
- [ "$passwdtype" = "yes" ] &&
- { f_dialog_input_group_password || exit $SUCCESS; }
- f_dialog_input_group_gid || exit $SUCCESS
- f_dialog_input_group_members || exit $SUCCESS
- fi
-fi
-
-if [ "$mode" = "Edit/View" -o "$mode" = "Delete" ]; then
- f_input_group "$group" || f_die 1 "$msg_group_not_found"
-fi
-
-cur_group_name="$group_name"
-cur_group_password="$group_password"
-cur_group_gid="$group_gid"
-cur_group_members="$group_members"
-
-[ "$mode" = "Delete" ] && save_flag=1
-
-#
-# Loop until the user decides to Exit, Cancel, or presses ESC
-#
-while :; do
- dialog_title_update "$mode"
-
- menu_text=
- menu_exit="$msg_exit"
- if [ "$save_flag" ]; then
- if [ "$mode" = "Delete" ]; then
- menu_exit="$msg_delete/$msg_exit"
- menu_text="$msg_delete_exit_or_cancel"
- else
- menu_exit="$msg_save/$msg_exit"
- menu_text="$msg_save_exit_or_cancel"
- fi
- fi
-
- case "$mode" in
- Delete)
- menu_items="
- 'X' '$menu_exit'
- '1' '$msg_group: $group_name'
- '-' '$msg_password: -----'
- '-' '$msg_group_id: $group_gid'
- '-' '$msg_group_members: $group_members'
- " # END-QUOTE
- ;;
- *)
- menu_items="
- 'X' '$menu_exit'
- '1' '$msg_group: $group_name'
- '2' '$msg_password: -----'
- '3' '$msg_group_id: $group_gid'
- '4' '$msg_group_members: $group_members'
- " # END-QUOTE
- esac
-
- eval f_dialog_menu_size height width rows \
- \"\$DIALOG_TITLE\" \
- \"\$DIALOG_BACKTITLE\" \
- \"\$menu_text\" \
- \"\$hline\" \
- $menu_items
-
- f_dialog_default_fetch defaultitem
- mtag=$( eval $DIALOG \
- --title \"\$DIALOG_TITLE\" \
- --backtitle \"\$DIALOG_BACKTITLE\" \
- --hline \"\$hline\" \
- --ok-label \"\$msg_ok\" \
- --cancel-label \"\$msg_cancel\" \
- --default-item \"\$defaultitem\" \
- --menu \"\$menu_text\" \
- $height $width $rows \
- $menu_items \
- 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
- )
- retval=$?
- f_dialog_data_sanitize mtag
- f_dialog_default_store "$mtag"
- f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
-
- # Exit if user has either pressed ESC or chosen Cancel/No
- [ $retval -eq $DIALOG_OK ] || f_die
-
- case "$mtag" in
- X) # Exit
- [ "$save_flag" ] && { save_changes || continue; }
- break
- ;;
- 1) # Group Name
- case "$mode" in
- Add) f_dialog_input_group_name "$group_name" ;;
- Edit/View|Delete)
- f_dialog_menu_group_list "$group_name"
- retval=$?
- f_dialog_menutag_fetch mtag
- f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
-
- # Loop if user has either pressed ESC or chosen Cancel/No
- [ $retval -eq $DIALOG_OK ] || continue
-
- [ "$mtag" = "X $msg_exit" ] && continue
-
- group="$mtag"
- f_input_group "$group" || f_die 1 "$msg_group_not_found"
- cur_group_name="$group_name"
- cur_group_password="$group_password"
- cur_group_gid="$group_gid"
- cur_group_members="$group_members"
- [ "$mode" != "Delete" ] && save_flag=
- esac
- ;;
- 2) # Password
- f_dialog_input_group_password
- ;;
- 3) # GID
- f_dialog_input_group_gid "$group_gid"
- ;;
- 4) # Users in Group
- f_dialog_input_group_members "$group_members"
- ;;
- esac
-
-done
-
-exit $SUCCESS
-
-################################################################################
-# END
-################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/include/messages.subr b/usr.sbin/bsdconfig/usermgmt/include/messages.subr
index e139f32..f56b844 100644
--- a/usr.sbin/bsdconfig/usermgmt/include/messages.subr
+++ b/usr.sbin/bsdconfig/usermgmt/include/messages.subr
@@ -1,5 +1,5 @@
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,7 @@ hline_arrows_tab_enter="Press arrows, TAB or ENTER"
hline_num_arrows_tab_enter="Use numbers, arrows, TAB or ENTER"
hline_num_tab_enter="Use numbers, TAB or ENTER"
msg_account_does_not_expire="Account does not expire"
-msg_account_expires_in_how_many_days="Account expires in how many days?"
+msg_account_expire_manual_edit="Enter account expiration time. Format is one of:\n\n a) decimal for UNIX time since %s\n b) dd-mmm-yy[yy] for day, month, and 2- or 4-digit year\n c) +n[mhdwoy] for relative time from current date\n\nNOTE: Value of zero disables expiration."
msg_account_expires_on="Account Expires on"
msg_add="Add"
msg_add_group="Add Group"
@@ -56,6 +56,7 @@ msg_edit_group="Edit/View Group"
msg_edit_login="Edit/View Login"
msg_edit_view="Edit/View"
msg_enter_group_members_manually="Enter Group Members manually"
+msg_enter_groups_manually="Enter Groups manually"
msg_enter_number_of_days_into_the_future="Enter number of days into the future"
msg_enter_value_manually="Edit value manually"
msg_error="ERROR!"
@@ -74,9 +75,8 @@ msg_group_not_found="%s: Group not found."
msg_group_password="Group Password"
msg_group_passwords_do_not_match="Group Passwords do not match."
msg_group_updated="Group Updated"
+msg_groups="Groups"
msg_home_directory="Home Directory"
-msg_invalid_number_of_days="Invalid number of days."
-msg_invalid_number_of_seconds="Invalid number of seconds."
msg_login="Login"
msg_login_added="Login Added"
msg_login_already_used="%s: Login is already used."
@@ -85,23 +85,28 @@ msg_login_deleted="Login Deleted"
msg_login_is_empty="Login is empty."
msg_login_management="Login/Group Management"
msg_login_must_start_with_letter="Login must start with a letter."
-msg_login_not_found="Login not found."
+msg_login_not_found="%s: Login not found."
msg_login_updated="Login Updated"
msg_member_of_groups="Member of Groups"
msg_n_a="N/A"
msg_no="No"
+msg_no_group_specified="No group specified!"
+msg_no_user_specified="No user specified!"
msg_number_of_seconds_since_epoch="Number of seconds since the Epoch\n(1 = %s)\nNULL or zero to disable:"
msg_ok="OK"
msg_password="Password"
msg_password_does_not_expire="Password does not expire"
-msg_password_expires_in_how_many_days="Password expires in how many days?"
+msg_password_expire_manual_edit="Enter password expiration time. Format is one of:\n\n a) decimal for UNIX time since %s\n b) dd-mmm-yy[yy] for day, month, and 2- or 4-digit year\n c) +n[mhdwoy] for relative time from current date\n\nNOTE: Value of zero disables expiration."
msg_password_expires_on="Password Expires on"
msg_passwords_do_not_match="Passwords do not match."
+msg_please_enter_a_group_name="Please enter a group name!"
+msg_please_enter_a_user_name="Please enter a user name!"
msg_reenter_group_password="Re-enter Group Password"
msg_reenter_password="Re-enter Password"
msg_save="Save"
msg_save_exit_or_cancel="Choose Save/Exit when finished or Cancel."
msg_select_group_members_from_list="Select Group Members from a list"
+msg_select_groups_from_list="Select Groups from a list"
msg_select_login_shell="Select Login Shell"
msg_separated_by_commas="Separated by commas"
msg_shell="Shell"
diff --git a/usr.sbin/bsdconfig/usermgmt/share/Makefile b/usr.sbin/bsdconfig/usermgmt/share/Makefile
index d6b9e3a..7f27c92 100644
--- a/usr.sbin/bsdconfig/usermgmt/share/Makefile
+++ b/usr.sbin/bsdconfig/usermgmt/share/Makefile
@@ -3,7 +3,7 @@
NO_OBJ=
FILESDIR= ${SHAREDIR}/bsdconfig/usermgmt
-FILES= group_input.subr user_input.subr
+FILES= group.subr group_input.subr user.subr user_input.subr
beforeinstall:
mkdir -p ${DESTDIR}${FILESDIR}
diff --git a/usr.sbin/bsdconfig/usermgmt/share/group.subr b/usr.sbin/bsdconfig/usermgmt/share/group.subr
new file mode 100644
index 0000000..fb320d1
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/share/group.subr
@@ -0,0 +1,518 @@
+if [ ! "$_USERMGMT_GROUP_SUBR" ]; then _USERMGMT_GROUP_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.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." usermgmt/group.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/usermgmt/group_input.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ CONFIGURATION
+
+# set some reasonable defaults if /etc/adduser.conf does not exist.
+[ -f /etc/adduser.conf ] && f_include /etc/adduser.conf
+: ${passwdtype:="yes"}
+
+############################################################ FUNCTIONS
+
+# f_group_add [$group]
+#
+# Add a group. If both $group (as a first argument) and $VAR_GROUP are unset
+# or NULL and we are running interactively, prompt the user to enter the name
+# of a new group and (if $VAR_NO_CONFIRM is unset or NULL) prompt the user to
+# answer some questions about the new group. Variables that can be used to
+# script user input:
+#
+# VAR_GROUP [Optional if running interactively]
+# The group to add. Ignored if given non-NULL first-argument.
+# VAR_GROUP_GID [Optional]
+# Numerical group ID to use. If NULL or unset, the group ID is
+# automatically chosen.
+# VAR_GROUP_MEMBERS [Optional]
+# Comma separated list of users that are a member of this group.
+# VAR_GROUP_PASSWORD [Optional]
+# newgrp(1) password to set for the group. Default if NULL or
+# unset is to disable newgrp(1) password authentication.
+#
+# Returns success if the group was successfully added.
+#
+f_group_add()
+{
+ local funcname=f_group_add
+ local title # Calculated below
+ local alert=f_show_msg no_confirm=
+
+ f_getvar $VAR_NO_CONFIRM no_confirm
+ [ "$no_confirm" ] && alert=f_show_info
+
+ local input
+ f_getvar 3:-\$$VAR_GROUP input "$1"
+
+ #
+ # NB: pw(8) has a ``feature'' wherein `-n name' can be taken as GID
+ # instead of name. Work-around is to also pass `-g GID' at the same
+ # time (any GID will do; but `-1' is appropriate for this context).
+ #
+ if [ "$input" ] && f_quietly pw groupshow -n "$input" -g -1; then
+ f_show_err "$msg_group_already_used" "$input"
+ return $FAILURE
+ fi
+
+ local group_name="$input"
+ while f_interactive && [ ! "$group_name" ]; do
+ f_dialog_input_group_name group_name "$group_name" ||
+ return $SUCCESS
+ [ "$group_name" ] ||
+ f_show_err "$msg_please_enter_a_group_name"
+ done
+ if [ ! "$group_name" ]; then
+ f_show_err "$msg_no_group_specified"
+ return $FAILURE
+ fi
+
+ local group_password group_gid group_members
+ f_getvar $VAR_GROUP_PASSWORD group_password
+ f_getvar $VAR_GROUP_GID group_gid
+ f_getvar $VAR_GROUP_MEMBERS group_members
+
+ local group_password_disable=
+ f_interactive || [ "$group_password" ] || group_password_disable=1
+
+ if f_interactive && [ ! "$no_confirm" ]; then
+ f_dialog_noyes \
+ "$msg_use_default_values_for_all_account_details"
+ retval=$?
+ if [ $retval -eq $DIALOG_ESC ]; then
+ return $SUCCESS
+ elif [ $retval -ne $DIALOG_OK ]; then
+ #
+ # Ask series of questions to pre-fill the editor screen
+ #
+ # Defaults used in each dialog should allow the user to
+ # simply hit ENTER to proceed and cancelling a single
+ # dialog cause them to return to the previous menu.
+ #
+
+ if [ "$passwdtype" = "yes" ]; then
+ f_dialog_input_group_password group_password \
+ group_password_disable ||
+ return $FAILURE
+ fi
+ f_dialog_input_group_gid group_gid "$group_gid" ||
+ return $FAILURE
+ f_dialog_input_group_members group_members \
+ "$group_members" || return $FAILURE
+ fi
+ fi
+
+ #
+ # Loop until the user decides to Exit, Cancel, or presses ESC
+ #
+ title="$msg_add $msg_group: $group_name"
+ if f_interactive; then
+ local mtag retval defaultitem=
+ while :; do
+ f_dialog_title "$title"
+ f_dialog_menu_group_add "$defaultitem"
+ retval=$?
+ f_dialog_title_restore
+ f_dialog_menutag_fetch mtag
+ f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
+ defaultitem="$mtag"
+
+ # Return if user either pressed ESC or chose Cancel/No
+ [ $retval -eq $DIALOG_OK ] || return $FAILURE
+
+ case "$mtag" in
+ X) # Add/Exit
+ local var
+ for var in gid members name; do
+ local _group_$var
+ eval f_shell_escape \
+ \"\$group_$var\" _group_$var
+ done
+
+ local cmd="pw groupadd -n '$_group_name'"
+ [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'"
+ [ "$group_members" ] &&
+ cmd="$cmd -M '$_group_members'"
+
+ # Execute the command (break on success)
+ if [ "$group_password_disable" ]; then
+ f_eval_catch $funcname pw '%s -h -' "$cmd"
+ elif [ "$group_password" ]; then
+ echo "$group_password" |
+ f_eval_catch $funcname \
+ pw '%s -h 0' "$cmd"
+ else
+ f_eval_catch $funcname pw '%s' "$cmd"
+ fi && break
+ ;;
+ 1) # Group Name (prompt for new group name)
+ f_dialog_input_group_name input "$group_name" ||
+ continue
+ if f_quietly pw groupshow -n "$input" -g -1; then
+ f_show_err "$msg_group_already_used" "$input"
+ continue
+ fi
+ group_name="$input"
+ title="$msg_add $msg_group: $group_name"
+ ;;
+ 2) # Password
+ f_dialog_input_group_password group_password \
+ group_password_disable
+ ;;
+ 3) # Group ID
+ f_dialog_input_group_gid group_gid "$group_gid"
+ ;;
+ 4) # Group Members
+ f_dialog_input_group_members group_members \
+ "$group_members"
+ ;;
+ esac
+ done
+ else
+ local var
+ for var in gid members name; do
+ local _group_$var
+ eval f_shell_escape \"\$group_$var\" _group_$var
+ done
+
+ # Form the command
+ local cmd="pw groupadd -n '$_group_name'"
+ [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'"
+ [ "$group_members" ] && cmd="$cmd -M '$_group_members'"
+
+ # Execute the command
+ local retval err
+ if [ "$group_password_disable" ]; then
+ f_eval_catch -k err $funcname pw '%s -h -' "$cmd"
+ elif [ "$group_password" ]; then
+ err=$( echo "$group_password" | f_eval_catch -de \
+ $funcname pw '%s -h 0' "$cmd" 2>&1 )
+ else
+ f_eval_catch -k err $funcname pw '%s' "$cmd"
+ fi
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_err "%s" "$err"
+ return $retval
+ fi
+ fi
+
+ f_dialog_title "$title"
+ $alert "$msg_group_added"
+ f_dialog_title_restore
+ [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
+
+ return $SUCCESS
+}
+
+# f_group_delete [$group]
+#
+# Delete a group. If both $group (as a first argument) and $VAR_GROUP are unset
+# or NULL and we are running interactively, prompt the user to select a group
+# from a list of available groups. Variables that can be used to script user
+# input:
+#
+# VAR_GROUP [Optional if running interactively]
+# The group to delete. Ignored if given non-NULL first-argument.
+#
+# Returns success if the group was successfully deleted.
+#
+f_group_delete()
+{
+ local funcname=f_group_delete
+ local title # Calculated below
+ local alert=f_show_msg no_confirm=
+
+ f_getvar $VAR_NO_CONFIRM no_confirm
+ [ "$no_confirm" ] && alert=f_show_info
+
+ local input
+ f_getvar 3:-\$$VAR_GROUP input "$1"
+
+ local group_name group_password group_gid group_members
+ if [ "$input" ] && ! f_input_group "$input"; then
+ f_show_err "$msg_group_not_found" "$input"
+ return $FAILURE
+ fi
+
+ #
+ # Loop until the user decides to Exit, Cancel, or presses ESC
+ #
+ title="$msg_delete $msg_group: $group_name"
+ if f_interactive; then
+ local mtag retval defaultitem=
+ while :; do
+ f_dialog_title "$title"
+ f_dialog_menu_group_delete "$group_name" "$defaultitem"
+ retval=$?
+ f_dialog_title_restore
+ f_dialog_menutag_fetch mtag
+ f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
+ defaultitem="$mtag"
+
+ # Return if user either pressed ESC or chose Cancel/No
+ [ $retval -eq $DIALOG_OK ] || return $FAILURE
+
+ case "$mtag" in
+ X) # Delete/Exit
+ local _group_name
+ f_shell_escape "$group_name" _group_name
+ f_eval_catch $funcname pw 'pw groupdel "%s"' \
+ "$_group_name" && break
+ ;;
+ 1) # Group Name (select different group from list)
+ f_dialog_menu_group_list "$group_name" || continue
+ f_dialog_menutag_fetch mtag
+
+ [ "$mtag" = "X $msg_exit" ] && continue
+
+ if ! f_input_group "$mtag"; then
+ f_show_err "$msg_group_not_found" "$mtag"
+ # Attempt to fall back to previous selection
+ f_input_group "$input" || return $FAILURE
+ else
+ input="$mtag"
+ fi
+ ;;
+ esac
+ done
+ else
+ local retval err _group_name
+ f_shell_escape "$group_name" _group_name
+ f_eval_catch -k err $funcname pw \
+ "pw groupdel '%s'" "$_group_name"
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_err "%s" "$err"
+ return $retval
+ fi
+ fi
+
+ f_dialog_title "$title"
+ $alert "$msg_group_deleted"
+ f_dialog_title_restore
+ [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
+
+ return $SUCCESS
+}
+
+# f_group_edit [$group]
+#
+# Modify a group. If both $group (as a first argument) and $VAR_GROUP are unset
+# or NULL and we are running interactively, prompt the user to select a group
+# from a list of available groups. Variables that can be used to script user
+# input:
+#
+# VAR_GROUP [Optional if running interactively]
+# The group to modify. Ignored if given non-NULL first-argument.
+# VAR_GROUP_GID [Optional]
+# Numerical group ID to set. If NULL or unset, the group ID is
+# unchanged.
+# VAR_GROUP_MEMBERS [Optional]
+# Comma separated list of users that are a member of this group.
+# If set but NULL, group memberships are reset (no users will be
+# a member of this group). If unset, group membership is
+# unmodified.
+# VAR_GROUP_PASSWORD [Optional]
+# newgrp(1) password to set for the group. If unset, the password
+# is unmodified. If NULL, the newgrp(1) password is disabled.
+#
+# Returns success if the group was successfully modified.
+#
+f_group_edit()
+{
+ local funcname=f_group_edit
+ local title # Calculated below
+ local alert=f_show_msg no_confirm=
+
+ f_getvar $VAR_NO_CONFIRM no_confirm
+ [ "$no_confirm" ] && alert=f_show_info
+
+ local input
+ f_getvar 3:-\$$VAR_GROUP input "$1"
+
+ #
+ # NB: pw(8) has a ``feature'' wherein `-n name' can be taken as GID
+ # instead of name. Work-around is to also pass `-g GID' at the same
+ # time (any GID will do; but `-1' is appropriate for this context).
+ #
+ if [ "$input" ] && ! f_quietly pw groupshow -n "$input" -g -1; then
+ f_show_err "$msg_group_not_found" "$input"
+ return $FAILURE
+ fi
+
+ if f_interactive && [ ! "$input" ]; then
+ f_dialog_menu_group_list || return $SUCCESS
+ f_dialog_menutag_fetch input
+ [ "$input" = "X $msg_exit" ] && return $SUCCESS
+ elif [ ! "$input" ]; then
+ f_show_err "$msg_no_group_specified"
+ return $FAILURE
+ fi
+
+ local group_name group_password group_gid group_members
+ if ! f_input_group "$input"; then
+ f_show_err "$msg_group_not_found" "$input"
+ return $FAILURE
+ fi
+
+ f_isset $VAR_GROUP_GID && f_getvar $VAR_GROUP_GID group_gid
+ local null_members=
+ if f_isset $VAR_GROUP_MEMBERS; then
+ f_getvar $VAR_GROUP_MEMBERS group_members
+ [ "$group_members" ] || null_members=1
+ fi
+ local group_password_disable=
+ if f_isset $VAR_GROUP_PASSWORD; then
+ f_getvar $VAR_GROUP_PASSWORD group_password
+ [ "$group_password" ] || group_password_disable=1
+ fi
+
+ #
+ # Loop until the user decides to Exit, Cancel, or presses ESC
+ #
+ title="$msg_edit_view $msg_group: $group_name"
+ if f_interactive; then
+ local mtag retval defaultitem=
+ while :; do
+ f_dialog_title "$title"
+ f_dialog_menu_group_edit "$defaultitem"
+ retval=$?
+ f_dialog_title_restore
+ f_dialog_menutag_fetch mtag
+ f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
+ defaultitem="$mtag"
+
+ # Return if user either pressed ESC or chose Cancel/No
+ [ $retval -eq $DIALOG_OK ] || return $FAILURE
+
+ case "$mtag" in
+ X) # Save/Exit
+ local var
+ for var in gid members name; do
+ local _group_$var
+ eval f_shell_escape \
+ \"\$group_$var\" _group_$var
+ done
+
+ local cmd="pw groupmod -n '$_group_name'"
+ [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'"
+ [ "$group_members" -o "$null_members" ] &&
+ cmd="$cmd -M '$_group_members'"
+
+ # Execute the command (break on success)
+ if [ "$group_password_disable" ]; then
+ f_eval_catch $funcname pw '%s -h -' "$cmd"
+ elif [ "$group_password" ]; then
+ echo "$group_password" | f_eval_catch \
+ $funcname pw '%s -h 0' "$cmd"
+ else
+ f_eval_catch $funcname pw '%s' "$cmd"
+ fi && break
+ ;;
+ 1) # Group Name (select different group from list)
+ f_dialog_menu_group_list "$group_name" || continue
+ f_dialog_menutag_fetch mtag
+
+ [ "$mtag" = "X $msg_exit" ] && continue
+
+ if ! f_input_group "$mtag"; then
+ f_show_err "$msg_group_not_found" "$mtag"
+ # Attempt to fall back to previous selection
+ f_input_group "$input" || return $FAILURE
+ else
+ input="$mtag"
+ fi
+ title="$msg_edit_view $msg_group: $group_name"
+ ;;
+ 2) # Password
+ f_dialog_input_group_password group_password \
+ group_password_disable
+ ;;
+ 3) # Group ID
+ f_dialog_input_group_gid group_gid "$group_gid"
+ ;;
+ 4) # Group Members
+ f_dialog_input_group_members group_members \
+ "$group_members" && [ ! "$group_members" ] &&
+ null_members=1
+ ;;
+ esac
+ done
+ else
+ local var
+ for var in gid members name; do
+ local _group_$var
+ eval f_shell_escape \"\$group_$var\" _group_$var
+ done
+
+ # Form the command
+ local cmd="pw groupmod -n '$_group_name'"
+ [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'"
+ [ "$group_members" -o "$null_members" ] &&
+ cmd="$cmd -M '$_group_members'"
+
+ # Execute the command
+ local retval err
+ if [ "$group_password_disable" ]; then
+ f_eval_catch -k err $funcname pw '%s -h -' "$cmd"
+ elif [ "$group_password" -o "$null_password" ]; then
+ err=$( echo "$group_password" | f_eval_catch -de \
+ $funcname pw '%s -h 0' "$cmd" 2>&1 )
+ else
+ f_eval_catch -k err $funcname pw '%s' "$cmd"
+ fi
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_err "%s" "$err"
+ return $retval
+ fi
+ fi
+
+ f_dialog_title "$title"
+ $alert "$msg_group_updated"
+ f_dialog_title_restore
+ [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
+
+ return $SUCCESS
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." usermgmt/group.subr
+
+fi # ! $_USERMGMT_GROUP_SUBR
diff --git a/usr.sbin/bsdconfig/usermgmt/share/group_input.subr b/usr.sbin/bsdconfig/usermgmt/share/group_input.subr
index e0f47f7..2e8c086 100644
--- a/usr.sbin/bsdconfig/usermgmt/share/group_input.subr
+++ b/usr.sbin/bsdconfig/usermgmt/share/group_input.subr
@@ -1,7 +1,7 @@
if [ ! "$_USERMGMT_GROUP_INPUT_SUBR" ]; then _USERMGMT_GROUP_INPUT_SUBR=1
#
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -48,14 +48,24 @@ f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
#
f_input_group()
{
- eval $( pw groupshow "$1" | awk -F: '
+ 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
+ }
{
- printf "group_name='\'%s\''\n", $1
- printf "group_password=\n"
- printf "group_gid='\'%s\''\n", $3
- printf "group_members='\'%s\''\n", $4
+ 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]
@@ -74,10 +84,13 @@ f_dialog_menu_group_list()
# Add groups from group(5)
menu_list="$menu_list $( pw groupshow -a | awk -F: '
- !/^[[:space:]]*(#|$)/ {
- printf "'\'%s\'\ \'%s\''\n", $1, $1
- }'
- )"
+ 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 \
@@ -105,300 +118,477 @@ f_dialog_menu_group_list()
return $retval
}
-# f_dialog_input_group_name [$group_name]
+# f_dialog_input_group_name $var_to_set [$group_name]
#
-# Allows the user to enter a new groupname for a given group. If the user does
-# not cancel or press ESC, the $group_name variable will hold the
-# newly-configured value upon return.
-#
-# If $cur_group_name is defined, the user can enter that and by-pass error-
-# checking (allowing the user to "revert" to an old value without, for example,
-# being told that the groupname already exists).
+# 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 _name="$1" _input="$1"
+ local __input="$__name"
while :; do
-
# Return if user has either pressed ESC or chosen Cancel/No
- f_dialog_input _input "$msg_group" "$_input" \
+ f_dialog_input __input "$msg_group" "$__input" \
"$hline_alnum_tab_enter" || return $?
# Check for no-change
- [ "$_input" = "$_name" ] && return $DIALOG_OK
-
- # Check for reversion
- if [ "$_input" = "$cur_group_name" ]; then
- group_name="$cur_group_name"
+ if [ "$__input" = "$__name" ]; then
+ setvar "$__var_to_set" "$__input"
return $DIALOG_OK
fi
# Check for NULL entry
- if [ ! "$_input" ]; then
+ if [ ! "$__input" ]; then
f_show_msg "$msg_group_is_empty"
continue
fi
# Check for invalid entry
- if ! echo "$_input" | grep -q "^[[:alpha:]]"; then
+ case "$__input" in [!a-zA-Z]*)
f_show_msg "$msg_group_must_start_with_letter"
continue
- fi
+ esac
# Check for duplicate entry
- if f_quietly pw groupshow -n "$_input"; then
- f_show_msg "$msg_group_already_used" "$_input"
+ if f_quietly pw groupshow -n "$__input"; then
+ f_show_msg "$msg_group_already_used" "$__input"
continue
fi
- group_name="$_input"
+ setvar "$__var_to_set" "$__input"
break
done
- save_flag=1
-
- f_dprintf "group_name: [%s]->[%s]" "$cur_group_name" "$group_name"
return $DIALOG_OK
}
-# f_dialog_input_group_password
+# f_dialog_input_group_password $var_to_set $dvar_to_set
#
-# Prompt the user to enter a password (twice).
+# 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 prompt1="$msg_group_password"
- local prompt2="$msg_reenter_group_password"
- local hline="$hline_alnum_punc_tab_enter"
+ 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 \
+ local __height1 __width1
+ f_dialog_inputbox_size __height1 __width1 \
"$DIALOG_TITLE" \
"$DIALOG_BACKTITLE" \
- "$prompt1" \
+ "$__prompt1" \
"" \
- "$hline"
+ "$__hline"
- local height2 width2
- f_dialog_inputbox_size height2 width2 \
+ local __height2 __width2
+ f_dialog_inputbox_size __height2 __width2 \
"$DIALOG_TITLE" \
"$DIALOG_BACKTITLE" \
- "$prompt2" \
+ "$__prompt2" \
"" \
- "$hline"
+ "$__hline"
#
# Loop until the user provides taint-free/valid input
#
- local retval _password1 _password2
+ local __retval __password1 __password2
while :; do
- _password1=$( $DIALOG \
+ __password1=$( $DIALOG \
--title "$DIALOG_TITLE" \
--backtitle "$DIALOG_BACKTITLE" \
- --hline "$hline" \
+ --hline "$__hline" \
--ok-label "$msg_ok" \
--cancel-label "$msg_cancel" \
--insecure \
- --passwordbox "$prompt1" \
- $height1 $width1 \
+ --passwordbox "$__prompt1" \
+ $__height1 $__width1 \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
)
- retval=$?
- debug= f_dialog_line_sanitize _password1
+ __retval=$?
+ debug= f_dialog_line_sanitize __password1
# Return if user has either pressed ESC or chosen Cancel/No
- [ $retval -eq $DIALOG_OK ] || return $retval
+ [ $__retval -eq $DIALOG_OK ] || return $__retval
- _password2=$( $DIALOG \
+ __password2=$( $DIALOG \
--title "$DIALOG_TITLE" \
--backtitle "$DIALOG_BACKTITLE" \
- --hline "$hline" \
+ --hline "$__hline" \
--ok-label "$msg_ok" \
--cancel-label "$msg_cancel" \
--insecure \
- --passwordbox "$prompt2" \
- $height2 $width2 \
+ --passwordbox "$__prompt2" \
+ $__height2 $__width2 \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
)
- retval=$?
- debug= f_dialog_line_sanitize _password2
+ __retval=$?
+ debug= f_dialog_line_sanitize __password2
# Return if user has either pressed ESC or chosen Cancel/No
- [ $retval -eq $DIALOG_OK ] || return $retval
+ [ $__retval -eq $DIALOG_OK ] || return $__retval
# Check for password mismatch
- if [ "$_password1" != "$_password2" ]; then
+ if [ "$__password1" != "$__password2" ]; then
f_show_msg "$msg_group_passwords_do_not_match"
continue
fi
# Check for NULL entry
- if [ ! "$_password1" ]; then
+ if [ ! "$__password1" ]; then
f_dialog_yesno "$msg_disable_password_auth_for_group"
- local retval=$?
- if [ $retval -eq $DIALOG_ESC ]; then
- return $retval
- elif [ $retval -eq $DIALOG_OK ]; then
- pw_group_password_disable=1
+ __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
- pw_group_password_disable=
+ setvar "$__dvar_to_set" ""
fi
- group_password="$_password1"
+ setvar "$__var_to_set" "$__password1"
break
done
- save_flag=1
-
- f_dprintf "group_password: [%s]->[%s]" \
- "$cur_group_password" "$group_password"
return $DIALOG_OK
}
-# f_dialog_input_group_gid [$group_gid]
+# 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 $group_gid variable will hold the newly-configured
+# cancel or press ESC, the $var_to_set variable will hold the newly-configured
# value upon return.
#
f_dialog_input_group_gid()
{
- local _input="$1"
+ 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 $?
-
- group_gid="$_input"
- save_flag=1
-
- f_dprintf "group_gid: [%s]->[%s]" "$cur_group_gid" "$group_gid"
+ 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 [$group_members]
+# 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 $group_members variable will hold the
-# newly-configured value upon return.
+# 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 _input="$1"
- local prompt="$msg_group_members:"
- local menu_list="
+ 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 __defaultitem=
+ local __hline="$hline_num_arrows_tab_enter"
- local mheight mwidth mrows
- eval f_dialog_menu_size mheight mwidth mrows \
+ local __mheight __mwidth __mrows
+ eval f_dialog_menu_size __mheight __mwidth __mrows \
\"\$DIALOG_TITLE\" \
\"\$DIALOG_BACKTITLE\" \
- \"\$prompt\" \
- \"\$hline\" \
- $menu_list
+ \"\$__prompt\" \
+ \"\$__hline\" \
+ $__menu_list
- local menu_choice retval
+ local __menu_choice __retval
while :; do
- menu_choice=$( eval $DIALOG \
+ __menu_choice=$( eval $DIALOG \
--title \"\$DIALOG_TITLE\" \
--backtitle \"\$DIALOG_BACKTITLE\" \
- --hline \"\$hline\" \
+ --hline \"\$__hline\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
- --default-item \"\$defaultitem\" \
- --menu \"\$prompt\" \
- $mheight $mwidth $mrows \
- $menu_list \
+ --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"
+ __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
+ [ $__retval -eq $DIALOG_OK ] || return $__retval
- local _group_members
- case "$menu_choice" in
+ local __group_members
+ case "$__menu_choice" in
X) # Exit
break ;;
1) # Select Group Members from a list
- local user check_list=
- for user in $( pw usershow -a |
- awk -F: '!/^[[:space:]]*(#|$)/{print $1}'
- ); do
+ 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
- if echo "$_input" | grep -q "\<$user\>"; then
- check_list="$check_list $user '' on"
- else
- check_list="$check_list $user '' off"
- fi
+ __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 \
+ 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\" \
+ --hline \"\$__hline\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
- --checklist \"\$prompt\" \
- $cheight $cwidth $crows \
- $check_list \
+ --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
+ 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" "[$IFS]" "," _input
+ f_replaceall "$__group_members" "[$NL]" "," __input
;;
2) # Enter Group Members manually
- local p="$msg_group_members ($msg_separated_by_commas)"
+ local __prompt2="$msg_group_members"
+ __prompt2="$__prompt2 ($msg_separated_by_commas)"
- f_dialog_input _group_members "$p" "$_input" \
+ 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"
+ __input="$__group_members"
;;
esac
done
- group_members="$_input"
- save_flag=1
- f_dprintf "group_members: [%s]->[%s]" \
- "$cur_group_members" "$group_members"
-
+ 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
diff --git a/usr.sbin/bsdconfig/usermgmt/share/user.subr b/usr.sbin/bsdconfig/usermgmt/share/user.subr
new file mode 100644
index 0000000..5fd65fb
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/share/user.subr
@@ -0,0 +1,1184 @@
+if [ ! "$_USERMGMT_USER_SUBR" ]; then _USERMGMT_USER_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.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." usermgmt/user.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/strings.subr
+f_include $BSDCFG_SHARE/usermgmt/group_input.subr
+f_include $BSDCFG_SHARE/usermgmt/user_input.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ CONFIGURATION
+
+# set some reasonable defaults if /etc/adduser.conf does not exist.
+[ -f /etc/adduser.conf ] && f_include /etc/adduser.conf
+: ${defaultclass:=""}
+: ${defaultshell:="/bin/sh"}
+: ${homeprefix:="/home"}
+: ${passwdtype:="yes"}
+: ${udotdir:="/usr/share/skel"}
+: ${uexpire:=""}
+ # Default account expire time. Format is similar to upwexpire variable.
+: ${ugecos:="User &"}
+: ${upwexpire:=""}
+ # The default password expiration time. Format of the date is either a
+ # UNIX time in decimal, or a date in dd-mmm-yy[yy] format, where dd is
+ # the day, mmm is the month in either numeric or alphabetic format, and
+ # yy[yy] is either a two or four digit year. This variable also accepts
+ # a relative date in the form of n[mhdwoy] where n is a decimal, octal
+ # (leading 0) or hexadecimal (leading 0x) digit followed by the number
+ # of Minutes, Hours, Days, Weeks, Months or Years from the current date
+ # at which the expiration time is to be set.
+
+#
+# uexpire and upwexpire from adduser.conf(5) differ only slightly from what
+# pw(8) accepts as `date' argument(s); pw(8) requires a leading `+' for the
+# relative date syntax (n[mhdwoy]).
+#
+case "$uexpire" in *[mhdwoy])
+ f_isinteger "${uexpire%[mhdwoy]}" && uexpire="+$uexpire"
+esac
+case "$upwexpire" in *[mhdwoy])
+ f_isinteger "${upwexpire%[mhdwoy]}" && upwexpire="+$upwexpire"
+esac
+
+############################################################ FUNCTIONS
+
+# f_user_create_homedir $user
+#
+# Create home directory for $user.
+#
+f_user_create_homedir()
+{
+ local funcname=f_user_create_homedir
+ local user="$1"
+
+ [ "$user" ] || return $FAILURE
+
+ local user_account_expire user_class user_gecos user_gid user_home_dir
+ local user_member_groups user_name user_password user_password_expire
+ local user_shell user_uid # Variables created by f_input_user() below
+ f_input_user "$user" || return $FAILURE
+
+ f_dprintf "Creating home directory \`%s' for user \`%s'" \
+ "$user_home_dir" "$user"
+
+ local _user_gid _user_home_dir _user_uid
+ f_shell_escape "$user_gid" _user_gid
+ f_shell_escape "$user_home_dir" _user_home_dir
+ f_shell_escape "$user_uid" _user_uid
+ f_eval_catch $funcname mkdir "mkdir -p '%s'" "$_user_home_dir" ||
+ return $FAILURE
+ f_eval_catch $funcname chown "chown '%i:%i' '%s'" \
+ "$_user_uid" "$_user_gid" "$_user_home_dir" || return $FAILURE
+}
+
+# f_user_copy_dotfiles $user
+#
+# Copy `skel' dot-files from $udotdir (global inherited from /etc/adduser.conf)
+# to the home-directory of $user. Attempts to create the home-directory first
+# if it doesn't exist.
+#
+f_user_copy_dotfiles()
+{
+ local funcname=f_user_copy_dotfiles
+ local user="$1"
+
+ [ "$udotdir" ] || return $FAILURE
+ [ "$user" ] || return $FAILURE
+
+ local user_account_expire user_class user_gecos user_gid user_home_dir
+ local user_member_groups user_name user_password user_password_expire
+ local user_shell user_uid # Variables created by f_input_user() below
+ f_input_user "$user" || return $FAILURE
+
+ f_dprintf "Copying dot-files from \`%s' to \`%s'" \
+ "$udotdir" "$user_home_dir"
+
+ # Attempt to create the home directory if it doesn't exist
+ [ -d "$user_home_dir" ] ||
+ f_user_create_homedir "$user" || return $FAILURE
+
+ local _user_gid _user_home_dir _user_uid
+ f_shell_escape "$user_gid" _user_gid
+ f_shell_escape "$user_home_dir" _user_home_dir
+ f_shell_escape "$user_uid" _user_uid
+
+ local - # Localize `set' to this function
+ set +f # Enable glob pattern-matching for paths
+ cd "$udotdir" || return $FAILURE
+
+ local _file file retval
+ for file in dot.*; do
+ [ -e "$file" ] || continue # no-match
+
+ f_shell_escape "$file" "_file"
+ f_eval_catch $funcname cp "cp -n '%s' '%s'" \
+ "$_file" "$_user_home_dir/${_file#dot}"
+ retval=$?
+ [ $retval -eq $SUCCESS ] || break
+ f_eval_catch $funcname chown \
+ "chown -h '%i:%i' '%s'" \
+ "$_user_uid" "$_user_gid" \
+ "$_user_home_dir/${_file#dot}"
+ retval=$?
+ [ $retval -eq $SUCCESS ] || break
+ done
+
+ cd -
+ return $retval
+}
+
+# f_user_add [$user]
+#
+# Create a login account. If both $user (as a first argument) and $VAR_USER are
+# unset or NULL and we are running interactively, prompt the end-user to enter
+# the name of a new login account and (if $VAR_NO_CONFIRM is unset or NULL)
+# prompt the end-user to answer some questions about the new account. Variables
+# that can be used to script user input:
+#
+# VAR_USER [Optional if running interactively]
+# The login to add. Ignored if given non-NULL first-argument.
+# VAR_USER_ACCOUNT_EXPIRE [Optional]
+# The account expiration time. Format is similar to
+# VAR_USER_PASSWORD_EXPIRE variable below. Default is to never
+# expire the account.
+# VAR_USER_DOTFILES_CREATE [Optional]
+# If non-NULL, populate the user's home directory with the
+# template files found in $udotdir (`/usr/share/skel' default).
+# VAR_USER_GECOS [Optional]
+# Often the full name of the account holder. Default is NULL.
+# VAR_USER_GID [Optional]
+# Numerical primary-group ID to use. If NULL or unset, the group
+# ID is automatically chosen.
+# VAR_USER_GROUPS [Optional]
+# Comma-separated list of additional groups to which the user is
+# a member of. Default is NULL (no additional groups).
+# VAR_USER_HOME [Optional]
+# The home directory to set. If NULL or unset, the home directory
+# is automatically calculated.
+# VAR_USER_HOME_CREATE [Optional]
+# If non-NULL, create the user's home directory if it doesn't
+# already exist.
+# VAR_USER_LOGIN_CLASS [Optional]
+# Login class to use when creating the login. Default is NULL.
+# VAR_USER_PASSWORD [Optional]
+# Unencrypted password to use. If unset or NULL, password
+# authentication for the login is disabled.
+# VAR_USER_PASSWORD_EXPIRE [Optional]
+# The password expiration time. Format of the date is either a
+# UNIX time in decimal, or a date in dd-mmm-yy[yy] format, where
+# dd is the day, mmm is the month in either numeric or alphabetic
+# format, and yy[yy] is either a two or four digit year. This
+# variable also accepts a relative date in the form of +n[mhdwoy]
+# where n is a decimal, octal (leading 0) or hexadecimal (leading
+# 0x) digit followed by the number of Minutes, Hours, Days,
+# Weeks, Months or Years from the current date at which the
+# expiration time is to be set. Default is to never expire the
+# account password.
+# VAR_USER_SHELL [Optional]
+# Path to login shell to use. Default is `/bin/sh'.
+# VAR_USER_UID [Optional]
+# Numerical user ID to use. If NULL or unset, the user ID is
+# automatically chosen.
+#
+# Returns success if the user account was successfully created.
+#
+f_user_add()
+{
+ local funcname=f_user_add
+ local title # Calculated below
+ local alert=f_show_msg no_confirm=
+
+ f_getvar $VAR_NO_CONFIRM no_confirm
+ [ "$no_confirm" ] && alert=f_show_info
+
+ local input
+ f_getvar 3:-\$$VAR_USER input "$1"
+
+ #
+ # NB: pw(8) has a ``feature'' wherein `-n name' can be taken as UID
+ # instead of name. Work-around is to also pass `-u UID' at the same
+ # time (any UID will do; but `-1' is appropriate for this context).
+ #
+ if [ "$input" ] && f_quietly pw usershow -n "$input" -u -1; then
+ f_show_err "$msg_login_already_used" "$input"
+ return $FAILURE
+ fi
+
+ local user_name="$input"
+ while f_interactive && [ ! "$user_name" ]; do
+ f_dialog_input_name user_name "$user_name" ||
+ return $SUCCESS
+ [ "$user_name" ] ||
+ f_show_err "$msg_please_enter_a_user_name"
+ done
+ if [ ! "$user_name" ]; then
+ f_show_err "$msg_no_user_specified"
+ return $FAILURE
+ fi
+
+ local user_account_expire user_class user_gecos user_gid user_home_dir
+ local user_member_groups user_password user_password_expire user_shell
+ local user_uid user_dotfiles_create= user_home_create=
+ f_getvar $VAR_USER_ACCOUNT_EXPIRE-\$uexpire user_account_expire
+ f_getvar $VAR_USER_DOTFILES_CREATE:+\$msg_yes user_dotfiles_create
+ f_getvar $VAR_USER_GECOS-\$ugecos user_gecos
+ f_getvar $VAR_USER_GID user_gid
+ f_getvar $VAR_USER_GROUPS user_member_groups
+ f_getvar $VAR_USER_HOME:-\${homeprefix%/}/\$user_name \
+ user_home_dir
+ f_getvar $VAR_USER_HOME_CREATE:+\$msg_yes user_home_create
+ f_getvar $VAR_USER_LOGIN_CLASS-\$defaultclass user_class
+ f_getvar $VAR_USER_PASSWORD user_password
+ f_getvar $VAR_USER_PASSWORD_EXPIRE-\$upwexpire user_password_expire
+ f_getvar $VAR_USER_SHELL-\$defaultshell user_shell
+ f_getvar $VAR_USER_UID user_uid
+
+ # Create home-dir if no script-override and does not exist
+ f_isset $VAR_USER_HOME_CREATE || [ -d "$user_home_dir" ] ||
+ user_home_create="$msg_yes"
+ # Copy dotfiles if home-dir creation is desired, does not yet exist,
+ # and no script-override has been set
+ f_isset $VAR_USER_DOTFILES_CREATE ||
+ [ "$user_home_create" != "$msg_yes" ] ||
+ [ -d "$user_home_dir" ] || user_dotfiles_create="$msg_yes"
+ # Create home-dir if copying dotfiles but home-dir does not exist
+ [ "$user_dotfiles_create" -a ! -d "$user_home_dir" ] &&
+ user_home_create="$msg_yes"
+
+ # Set flags for meaningful NULL values if-provided
+ local no_account_expire= no_password_expire= null_gecos= null_members=
+ local user_password_disable=
+ f_isset $VAR_USER_ACCOUNT_EXPIRE &&
+ [ ! "$user_account_expire" ] && no_account_expire=1
+ f_isset $VAR_USER_GECOS &&
+ [ ! "$user_gecos" ] && null_gecos=1
+ f_isset $VAR_USER_GROUPS &&
+ [ ! "$user_member_groups" ] && null_members=1
+ f_isset $VAR_USER_PASSWORD &&
+ [ ! "$user_password" ] && user_password_disable=1
+ f_isset $VAR_USER_PASSWORD_EXPIRE &&
+ [ ! "$user_password_expire" ] && no_password_expire=1
+
+ if f_interactive && [ ! "$no_confirm" ]; then
+ f_dialog_noyes \
+ "$msg_use_default_values_for_all_account_details"
+ retval=$?
+ if [ $retval -eq $DIALOG_ESC ]; then
+ return $SUCCESS
+ elif [ $retval -ne $DIALOG_OK ]; then
+ #
+ # Ask series of questions to pre-fill the editor screen
+ #
+ # Defaults used in each dialog should allow the user to
+ # simply hit ENTER to proceed, because cancelling any
+ # single dialog will cause them to be returned to the
+ # previous menu.
+ #
+
+ f_dialog_input_gecos user_gecos "$user_gecos" ||
+ return $FAILURE
+ if [ "$passwdtype" = "yes" ]; then
+ f_dialog_input_password user_password \
+ user_password_disable ||
+ return $FAILURE
+ fi
+ f_dialog_input_uid user_uid "$user_uid" ||
+ return $FAILURE
+ f_dialog_input_gid user_gid "$user_gid" ||
+ return $FAILURE
+ f_dialog_input_member_groups user_member_groups \
+ "$user_member_groups" || return $FAILURE
+ f_dialog_input_class user_class "$user_class" ||
+ return $FAILURE
+ f_dialog_input_expire_password user_password_expire \
+ "$user_password_expire" || return $FAILURE
+ f_dialog_input_expire_account user_account_expire \
+ "$user_account_expire" || return $FAILURE
+ f_dialog_input_home_dir user_home_dir \
+ "$user_home_dir" || return $FAILURE
+ if [ ! -d "$user_home_dir" ]; then
+ f_dialog_input_home_create user_home_create ||
+ return $FAILURE
+ if [ "$user_home_create" = "$msg_yes" ]; then
+ f_dialog_input_dotfiles_create \
+ user_dotfiles_create ||
+ return $FAILURE
+ fi
+ fi
+ f_dialog_input_shell user_shell "$user_shell" ||
+ return $FAILURE
+ fi
+ fi
+
+ #
+ # Loop until the user decides to Exit, Cancel, or presses ESC
+ #
+ title="$msg_add $msg_user: $user_name"
+ if f_interactive; then
+ local mtag retval defaultitem=
+ while :; do
+ f_dialog_title "$title"
+ f_dialog_menu_user_add "$defaultitem"
+ retval=$?
+ f_dialog_title_restore
+ f_dialog_menutag_fetch mtag
+ f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
+ defaultitem="$mtag"
+
+ # Return if user either pressed ESC or chose Cancel/No
+ [ $retval -eq $DIALOG_OK ] || return $FAILURE
+
+ case "$mtag" in
+ X) # Add/Exit
+ local var
+ for var in account_expire class gecos gid home_dir \
+ member_groups name password_expire shell uid \
+ ; do
+ local _user_$var
+ eval f_shell_escape \"\$user_$var\" _user_$var
+ done
+
+ local cmd="pw useradd -n '$_user_name'"
+ [ "$user_gid" ] && cmd="$cmd -g '$_user_gid'"
+ [ "$user_shell" ] && cmd="$cmd -s '$_user_shell'"
+ [ "$user_uid" ] && cmd="$cmd -u '$_user_uid'"
+ [ "$user_account_expire" -o \
+ "$no_account_expire" ] &&
+ cmd="$cmd -e '$_user_account_expire'"
+ [ "$user_class" -o "$null_class" ] &&
+ cmd="$cmd -L '$_user_class'"
+ [ "$user_gecos" -o "$null_gecos" ] &&
+ cmd="$cmd -c '$_user_gecos'"
+ [ "$user_home_dir" ] &&
+ cmd="$cmd -d '$_user_home_dir'"
+ [ "$user_member_groups" ] &&
+ cmd="$cmd -G '$_user_member_groups'"
+ [ "$user_password_expire" -o \
+ "$no_password_expire" ] &&
+ cmd="$cmd -p '$_user_password_expire'"
+
+ # Execute the command
+ if [ "$user_password_disable" ]; then
+ f_eval_catch $funcname pw '%s -h -' "$cmd"
+ elif [ "$user_password" ]; then
+ echo "$user_password" | f_eval_catch \
+ $funcname pw '%s -h 0' "$cmd"
+ else
+ f_eval_catch $funcname pw '%s' "$cmd"
+ fi || continue
+
+ # Create home directory if desired
+ [ "${user_home_create:-$msg_no}" != "$msg_no" ] &&
+ f_user_create_homedir "$user_name"
+
+ # Copy dotfiles if desired
+ [ "${user_dotfiles_create:-$msg_no}" != \
+ "$msg_no" ] && f_user_copy_dotfiles "$user_name"
+
+ break # to success
+ ;;
+ 1) # Login (prompt for new login name)
+ f_dialog_input_name input "$user_name" ||
+ continue
+ if f_quietly pw usershow -n "$input" -u -1; then
+ f_show_err "$msg_login_already_used" "$input"
+ continue
+ fi
+ user_name="$input"
+ title="$msg_add $msg_user: $user_name"
+ user_home_dir="${homeprefix%/}/$user_name"
+ ;;
+ 2) # Full Name
+ f_dialog_input_gecos user_gecos "$user_gecos" &&
+ [ ! "$user_gecos" ] && null_gecos=1 ;;
+ 3) # Password
+ f_dialog_input_password \
+ user_password user_password_disable ;;
+ 4) # User ID
+ f_dialog_input_uid user_uid "$user_uid" ;;
+ 5) # Group ID
+ f_dialog_input_gid user_gid "$user_gid" ;;
+ 6) # Member of Groups
+ f_dialog_input_member_groups \
+ user_member_groups "$user_member_groups" &&
+ [ ! "$user_member_groups" ] &&
+ null_members=1 ;;
+ 7) # Login Class
+ f_dialog_input_class user_class "$user_class" &&
+ [ ! "$user_class" ] && null_class=1 ;;
+ 8) # Password Expires On
+ f_dialog_input_expire_password \
+ user_password_expire "$user_password_expire" &&
+ [ ! "$user_password_expire" ] &&
+ no_password_expire=1 ;;
+ 9) # Account Expires On
+ f_dialog_input_expire_account \
+ user_account_expire "$user_account_expire" &&
+ [ ! "$user_account_expire" ] &&
+ no_account_expire=1 ;;
+ A) # Home Directory
+ f_dialog_input_home_dir \
+ user_home_dir "$user_home_dir" ;;
+ B) # Shell
+ f_dialog_input_shell user_shell "$user_shell" ;;
+ C) # Create Home Directory?
+ if [ "${user_home_create:-$msg_no}" != "$msg_no" ]
+ then
+ user_home_create="$msg_no"
+ else
+ user_home_create="$msg_yes"
+ fi ;;
+ D) # Create Dotfiles?
+ if [ "${user_dotfiles_create:-$msg_no}" != \
+ "$msg_no" ]
+ then
+ user_dotfiles_create="$msg_no"
+ else
+ user_dotfiles_create="$msg_yes"
+ fi ;;
+ esac
+ done
+ else
+ local var
+ for var in account_expire class gecos gid home_dir \
+ member_groups name password_expire shell uid \
+ ; do
+ local _user_$var
+ eval f_shell_escape \"\$user_$var\" _user_$var
+ done
+
+ # Form the command
+ local cmd="pw useradd -n '$_user_name'"
+ [ "$user_gid" ] && cmd="$cmd -g '$_user_gid'"
+ [ "$user_home_dir" ] && cmd="$cmd -d '$_user_home_dir'"
+ [ "$user_shell" ] && cmd="$cmd -s '$_user_shell'"
+ [ "$user_uid" ] && cmd="$cmd -u '$_user_uid'"
+ [ "$user_account_expire" -o "$no_account_expire" ] &&
+ cmd="$cmd -e '$_user_account_expire'"
+ [ "$user_class" -o "$null_class" ] &&
+ cmd="$cmd -L '$_user_class'"
+ [ "$user_gecos" -o "$null_gecos" ] &&
+ cmd="$cmd -c '$_user_gecos'"
+ [ "$user_member_groups" -o "$null_members" ] &&
+ cmd="$cmd -G '$_user_member_groups'"
+ [ "$user_password_expire" -o "$no_password_expire" ] &&
+ cmd="$cmd -p '$_user_password_expire'"
+
+ # Execute the command
+ local retval err
+ if [ "$user_password_disable" ]; then
+ f_eval_catch -k err $funcname pw '%s -h -' "$cmd"
+ elif [ "$user_password" ]; then
+ err=$( echo "$user_password" | f_eval_catch -de \
+ $funcname pw '%s -h 0' "$cmd" 2>&1 )
+ else
+ f_eval_catch -k err $funcname pw '%s' "$cmd"
+ fi
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_err "%s" "$err"
+ return $retval
+ fi
+
+ # Create home directory if desired
+ [ "${user_home_create:-$msg_no}" != "$msg_no" ] &&
+ f_user_create_homedir "$user_name"
+
+ # Copy dotfiles if desired
+ [ "${user_dotfiles_create:-$msg_no}" != "$msg_no" ] &&
+ f_user_copy_dotfiles "$user_name"
+ fi
+
+ f_dialog_title "$title"
+ $alert "$msg_login_added"
+ f_dialog_title_restore
+ [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
+
+ return $SUCCESS
+}
+
+# f_user_delete [$user]
+#
+# Delete a user. If both $user (as a first argument) and $VAR_USER are unset or
+# NULL and we are running interactively, prompt the end-user to select a user
+# account from a list of those available. Variables that can be used to script
+# user input:
+#
+# VAR_USER [Optional if running interactively]
+# The user to delete. Ignored if given non-NULL first-argument.
+#
+# Returns success if the user account was successfully deleted.
+#
+f_user_delete()
+{
+ local funcname=f_user_delete
+ local title # Calculated below
+ local alert=f_show_msg no_confirm=
+
+ f_getvar $VAR_NO_CONFIRM no_confirm
+ [ "$no_confirm" ] && alert=f_show_info
+
+ local input
+ f_getvar 3:-\$$VAR_USER input "$1"
+
+ if f_interactive && [ ! "$input" ]; then
+ f_dialog_menu_user_list || return $SUCCESS
+ f_dialog_menutag_fetch input
+ [ "$input" = "X $msg_exit" ] && return $SUCCESS
+ elif [ ! "$input" ]; then
+ f_show_err "$msg_no_user_specified"
+ return $FAILURE
+ fi
+
+ local user_account_expire user_class user_gecos user_gid user_home_dir
+ local user_member_groups user_name user_password user_password_expire
+ local user_shell user_uid # Variables created by f_input_user() below
+ if [ "$input" ] && ! f_input_user "$input"; then
+ f_show_err "$msg_login_not_found" "$input"
+ return $FAILURE
+ fi
+
+ local user_group_delete= user_home_delete=
+ f_getvar $VAR_USER_GROUP_DELETE:-\$msg_no user_group_delete
+ f_getvar $VAR_USER_HOME_DELETE:-\$msg_no user_home_delete
+
+ # Attempt to translate user GID into a group name
+ local user_group
+ if user_group=$( pw groupshow -g "$user_gid" 2> /dev/null ); then
+ user_group="${user_group%%:*}"
+ # Default to delete the primary group if no script-override and
+ # exists with same name as the user (same logic used by pw(8))
+ f_isset $VAR_USER_GROUP_DELETE ||
+ [ "$user_group" != "$user_name" ] ||
+ user_group_delete="$msg_yes"
+ fi
+
+ #
+ # Loop until the user decides to Exit, Cancel, or presses ESC
+ #
+ title="$msg_delete $msg_user: $user_name"
+ if f_interactive; then
+ local mtag retval defaultitem=
+ while :; do
+ f_dialog_title "$title"
+ f_dialog_menu_user_delete "$user_name" "$defaultitem"
+ retval=$?
+ f_dialog_title_restore
+ f_dialog_menutag_fetch mtag
+ f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
+ defaultitem="$mtag"
+
+ # Return if user either pressed ESC or chose Cancel/No
+ [ $retval -eq $DIALOG_OK ] || return $FAILURE
+
+ case "$mtag" in
+ X) # Delete/Exit
+ f_shell_escape "$user_uid" _user_uid
+
+ # Save group information in case pw(8) deletes it
+ # and we wanted to keep it (to be restored below)
+ if [ "${user_group_delete:-$msg_no}" = "$msg_no" ]
+ then
+ local v vars="gid members name password"
+ for v in $vars; do local group_$var; done
+ f_input_group "$user_group"
+
+ # Remove user-to-delete from group members
+ # NB: Otherwise group restoration could fail
+ local name length=0 _members=
+ while [ $length -ne ${#group_members} ]; do
+ name="${group_members%%,*}"
+ [ "$name" != "$user_name" ] &&
+ _members="$_members,$name"
+ length=${#group_members}
+ group_members="${group_members#*,}"
+ done
+ group_members="${_members#,}"
+
+ # Create escaped variables for f_eval_catch()
+ for v in $vars; do
+ local _group_$v
+ eval f_shell_escape \
+ \"\$group_$v\" _group_$v
+ done
+ fi
+
+ # Delete the user (if asked to delete home directory
+ # display [X]dialog notification to show activity)
+ local cmd="pw userdel -u '$_user_uid'"
+ if [ "$user_home_delete" = "$msg_yes" -a \
+ "$USE_XDIALOG" ]
+ then
+ local err
+ err=$(
+ exec 9>&1
+ f_eval_catch -e $funcname pw \
+ "%s -r" "$cmd" \
+ >&$DIALOG_TERMINAL_PASSTHRU_FD 2>&9 |
+ f_xdialog_info \
+ "$msg_deleting_home_directory"
+ )
+ [ ! "$err" ]
+ elif [ "$user_home_delete" = "$msg_yes" ]; then
+ f_dialog_info "$msg_deleting_home_directory"
+ f_eval_catch $funcname pw '%s -r' "$cmd"
+ else
+ f_eval_catch $funcname pw '%s' "$cmd"
+ fi || continue
+
+ #
+ # pw(8) may conditionally delete the primary group,
+ # which may not be what is desired.
+ #
+ # If we've been asked to delete the group and pw(8)
+ # chose not to, delete it. Otherwise, if we're told
+ # to NOT delete the group, we may need to restore it
+ # since pw(8) doesn't have a flag to tell `userdel'
+ # to not delete the group.
+ #
+ # NB: If primary group and user have different names
+ # the group may not have been deleted (again, see PR
+ # 169471 and SVN r263114 for details).
+ #
+ if [ "${user_group_delete:-$msg_no}" != "$msg_no" ]
+ then
+ f_quietly pw groupshow -g "$user_gid" &&
+ f_eval_catch $funcname pw \
+ "pw groupdel -g '%s'" "$_user_gid"
+ elif ! f_quietly pw groupshow -g "$group_gid" &&
+ [ "$group_name" -a "$group_gid" ]
+ then
+ # Group deleted by pw(8), so restore it
+ local cmd="pw groupadd -n '$_group_name'"
+ cmd="$cmd -g '$_group_gid'"
+ cmd="$cmd -M '$_group_members'"
+
+ # Get the group password (pw(8) groupshow does
+ # NOT provide this (even if running privileged)
+ local group_password_enc
+ group_password_enc=$( getent group | awk -F: '
+ !/^[[:space:]]*(#|$)/ && \
+ $1 == ENVIRON["group_name"] && \
+ $3 == ENVIRON["group_gid"] && \
+ $4 == ENVIRON["group_members"] \
+ { print $2; exit }
+ ' )
+ if [ "$group_password_enc" ]; then
+ echo "$group_password_enc" |
+ f_eval_catch $funcname \
+ pw '%s -H 0' "$cmd"
+ else
+ f_eval_catch $funcname \
+ pw '%s -h -' "$cmd"
+ fi
+ fi
+
+ break # to success
+ ;;
+ 1) # Login (select different login from list)
+ f_dialog_menu_user_list "$user_name" || continue
+ f_dialog_menutag_fetch mtag
+
+ [ "$mtag" = "X $msg_exit" ] && continue
+
+ if ! f_input_user "$mtag"; then
+ f_show_err "$msg_login_not_found" "$mtag"
+ # Attempt to fall back to previous selection
+ f_input_user "$input" || return $FAILURE
+ else
+ input="$mtag"
+ fi
+ title="$msg_delete $msg_user: $user_name"
+ ;;
+ C) # Delete Primary Group?
+ if [ "${user_group_delete:-$msg_no}" != "$msg_no" ]
+ then
+ user_group_delete="$msg_no"
+ else
+ user_group_delete="$msg_yes"
+ fi ;;
+ D) # Delete Home Directory?
+ if [ "${user_home_delete:-$msg_no}" != "$msg_no" ]
+ then
+ user_home_delete="$msg_no"
+ else
+ user_home_delete="$msg_yes"
+ fi ;;
+ esac
+ done
+ else
+ f_shell_escape "$user_uid" _user_uid
+
+ # Save group information in case pw(8) deletes it
+ # and we wanted to keep it (to be restored below)
+ if [ "${user_group_delete:-$msg_no}" = "$msg_no" ]; then
+ local v vars="gid members name password"
+ for v in $vars; do local group_$v; done
+ f_input_group "$user_group"
+
+ # Remove user we're about to delete from group members
+ # NB: Otherwise group restoration could fail
+ local name length=0 _members=
+ while [ $length -ne ${#group_members} ]; do
+ name="${group_members%%,*}"
+ [ "$name" != "$user_name" ] &&
+ _members="$_members,$name"
+ length=${#group_members}
+ group_members="${group_members#*,}"
+ done
+ group_members="${_members#,}"
+
+ # Create escaped variables for later f_eval_catch()
+ for v in $vars; do
+ local _group_$v
+ eval f_shell_escape \"\$group_$v\" _group_$v
+ done
+ fi
+
+ # Delete the user (if asked to delete home directory
+ # display [X]dialog notification to show activity)
+ local err cmd="pw userdel -u '$_user_uid'"
+ if [ "$user_home_delete" = "$msg_yes" -a "$USE_XDIALOG" ]; then
+ err=$(
+ exec 9>&1
+ f_eval_catch -de $funcname pw \
+ '%s -r' "$cmd" 2>&9 | f_xdialog_info \
+ "$msg_deleting_home_directory"
+ )
+ [ ! "$err" ]
+ elif [ "$user_home_delete" = "$msg_yes" ]; then
+ f_dialog_info "$msg_deleting_home_directory"
+ f_eval_catch -k err $funcname pw '%s -r' "$cmd"
+ else
+ f_eval_catch -k err $funcname pw '%s' "$cmd"
+ fi
+ local retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_err "%s" "$err"
+ return $retval
+ fi
+
+ #
+ # pw(8) may conditionally delete the primary group, which may
+ # not be what is desired.
+ #
+ # If we've been asked to delete the group and pw(8) chose not
+ # to, delete it. Otherwise, if we're told to NOT delete the
+ # group, we may need to restore it since pw(8) doesn't have a
+ # flag to tell `userdel' to not delete the group.
+ #
+ # NB: If primary group and user have different names the group
+ # may not have been deleted (again, see PR 169471 and SVN
+ # r263114 for details).
+ #
+ if [ "${user_group_delete:-$msg_no}" != "$msg_no" ]
+ then
+ f_quietly pw groupshow -g "$user_gid" &&
+ f_eval_catch $funcname pw \
+ "pw groupdel -g '%s'" "$_user_gid"
+ elif ! f_quietly pw groupshow -g "$group_gid" &&
+ [ "$group_name" -a "$group_gid" ]
+ then
+ # Group deleted by pw(8), so restore it
+ local cmd="pw groupadd -n '$_group_name'"
+ cmd="$cmd -g '$_group_gid'"
+ cmd="$cmd -M '$_group_members'"
+ local group_password_enc
+ group_password_enc=$( getent group | awk -F: '
+ !/^[[:space:]]*(#|$)/ && \
+ $1 == ENVIRON["group_name"] && \
+ $3 == ENVIRON["group_gid"] && \
+ $4 == ENVIRON["group_members"] \
+ { print $2; exit }
+ ' )
+ if [ "$group_password_enc" ]; then
+ echo "$group_password_enc" |
+ f_eval_catch $funcname \
+ pw '%s -H 0' "$cmd"
+ else
+ f_eval_catch $funcname \
+ pw '%s -h -' "$cmd"
+ fi
+ fi
+ fi
+
+ f_dialog_title "$title"
+ $alert "$msg_login_deleted"
+ f_dialog_title_restore
+ [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
+
+ return $SUCCESS
+}
+
+# f_user_edit [$user]
+#
+# Modify a login account. If both $user (as a first argument) and $VAR_USER are
+# unset or NULL and we are running interactively, prompt the end-user to select
+# a login account from a list of those available. Variables that can be used to
+# script user input:
+#
+# VAR_USER [Optional if running interactively]
+# The login to modify. Ignored if given non-NULL first-argument.
+# VAR_USER_ACCOUNT_EXPIRE [Optional]
+# The account expiration time. Format is similar to
+# VAR_USER_PASSWORD_EXPIRE variable below. If unset, account
+# expiry is unchanged. If set but NULL, account expiration is
+# disabled (same as setting a value of `0').
+# VAR_USER_DOTFILES_CREATE [Optional]
+# If non-NULL, re-populate the user's home directory with the
+# template files found in $udotdir (`/usr/share/skel' default).
+# VAR_USER_GECOS [Optional]
+# Often the full name of the account holder. If unset, the GECOS
+# field is unmodified. If set but NULL, the field is blanked.
+# VAR_USER_GID [Optional]
+# Numerical primary-group ID to set. If NULL or unset, the group
+# ID is unchanged.
+# VAR_USER_GROUPS [Optional]
+# Comma-separated list of additional groups to which the user is
+# a member of. If set but NULL, group memberships are reset (this
+# login will not be a member of any additional groups besides the
+# primary group). If unset, group membership is unmodified.
+# VAR_USER_HOME [Optional]
+# The home directory to set. If NULL or unset, the home directory
+# is unchanged.
+# VAR_USER_HOME_CREATE [Optional]
+# If non-NULL, create the user's home directory if it doesn't
+# already exist.
+# VAR_USER_LOGIN_CLASS [Optional]
+# Login class to set. If unset, the login class is unchanged. If
+# set but NULL, the field is blanked.
+# VAR_USER_PASSWORD [Optional]
+# Unencrypted password to set. If unset, the login password is
+# unmodified. If set but NULL, password authentication for the
+# login is disabled.
+# VAR_USER_PASSWORD_EXPIRE [Optional]
+# The password expiration time. Format of the date is either a
+# UNIX time in decimal, or a date in dd-mmm-yy[yy] format, where
+# dd is the day, mmm is the month in either numeric or alphabetic
+# format, and yy[yy] is either a two or four digit year. This
+# variable also accepts a relative date in the form of +n[mhdwoy]
+# where n is a decimal, octal (leading 0) or hexadecimal (leading
+# 0x) digit followed by the number of Minutes, Hours, Days,
+# Weeks, Months or Years from the current date at which the
+# expiration time is to be set. If unset, password expiry is
+# unchanged. If set but NULL, password expiration is disabled
+# (same as setting a value of `0').
+# VAR_USER_SHELL [Optional]
+# Path to login shell to set. If NULL or unset, the shell is
+# unchanged.
+# VAR_USER_UID [Optional]
+# Numerical user ID to set. If NULL or unset, the user ID is
+# unchanged.
+#
+# Returns success if the user account was successfully modified.
+#
+f_user_edit()
+{
+ local funcname=f_user_edit
+ local title # Calculated below
+ local alert=f_show_msg no_confirm=
+
+ f_getvar $VAR_NO_CONFIRM no_confirm
+ [ "$no_confirm" ] && alert=f_show_info
+
+ local input
+ f_getvar 3:-\$$VAR_USER input "$1"
+
+ #
+ # NB: pw(8) has a ``feature'' wherein `-n name' can be taken as UID
+ # instead of name. Work-around is to also pass `-u UID' at the same
+ # time (any UID will do; but `-1' is appropriate for this context).
+ #
+ if [ "$input" ] && ! f_quietly pw usershow -n "$input" -u -1; then
+ f_show_err "$msg_login_not_found" "$input"
+ return $FAILURE
+ fi
+
+ if f_interactive && [ ! "$input" ]; then
+ f_dialog_menu_user_list || return $SUCCESS
+ f_dialog_menutag_fetch input
+ [ "$input" = "X $msg_exit" ] && return $SUCCESS
+ elif [ ! "$input" ]; then
+ f_show_err "$msg_no_user_specified"
+ return $FAILURE
+ fi
+
+ local user_account_expire user_class user_gecos user_gid user_home_dir
+ local user_member_groups user_name user_password user_password_expire
+ local user_shell user_uid # Variables created by f_input_user() below
+ if ! f_input_user "$input"; then
+ f_show_err "$msg_login_not_found" "$input"
+ return $FAILURE
+ fi
+
+ #
+ # Override values probed by f_input_user() with desired values
+ #
+ f_isset $VAR_USER_GID && f_getvar $VAR_USER_GID user_gid
+ f_isset $VAR_USER_HOME && f_getvar $VAR_USER_HOME user_home_dir
+ f_isset $VAR_USER_SHELL && f_getvar $VAR_USER_SHELL user_shell
+ f_isset $VAR_USER_UID && f_getvar $VAR_USER_UID user_uid
+ local user_dotfiles_create= user_home_create=
+ f_getvar $VAR_USER_DOTFILES_CREATE:+\$msg_yes user_dotfiles_create
+ f_getvar $VAR_USER_HOME_CREATE:+\$msg_yes user_home_create
+ local no_account_expire=
+ if f_isset $VAR_USER_ACCOUNT_EXPIRE; then
+ f_getvar $VAR_USER_ACCOUNT_EXPIRE user_account_expire
+ [ "$user_account_expire" ] || no_account_expire=1
+ fi
+ local null_gecos=
+ if f_isset $VAR_USER_GECOS; then
+ f_getvar $VAR_USER_GECOS user_gecos
+ [ "$user_gecos" ] || null_gecos=1
+ fi
+ local null_members=
+ if f_isset $VAR_USER_GROUPS; then
+ f_getvar $VAR_USER_GROUPS user_member_groups
+ [ "$user_member_groups" ] || null_members=1
+ fi
+ local null_class=
+ if f_isset $VAR_USER_LOGIN_CLASS; then
+ f_getvar $VAR_USER_LOGIN_CLASS user_class
+ [ "$user_class" ] || null_class=1
+ fi
+ local user_password_disable=
+ if f_isset $VAR_USER_PASSWORD; then
+ f_getvar $VAR_USER_PASSWORD user_password
+ [ "$user_password" ] || user_password_disable=1
+ fi
+ local no_password_expire=
+ if f_isset $VAR_USER_PASSWORD_EXPIRE; then
+ f_getvar $VAR_USER_PASSWORD_EXPIRE user_password_expire
+ [ "$user_password_expire" ] || no_password_expire=1
+ fi
+
+ #
+ # Loop until the user decides to Exit, Cancel, or presses ESC
+ #
+ title="$msg_edit_view $msg_user: $user_name"
+ if f_interactive; then
+ local mtag retval defaultitem=
+ while :; do
+ f_dialog_title "$title"
+ f_dialog_menu_user_edit "$defaultitem"
+ retval=$?
+ f_dialog_title_restore
+ f_dialog_menutag_fetch mtag
+ f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
+ defaultitem="$mtag"
+
+ # Return if user either pressed ESC or chose Cancel/No
+ [ $retval -eq $DIALOG_OK ] || return $FAILURE
+
+ case "$mtag" in
+ X) # Save/Exit
+ local var
+ for var in account_expire class gecos gid home_dir \
+ member_groups name password_expire shell uid \
+ ; do
+ local _user_$var
+ eval f_shell_escape \"\$user_$var\" _user_$var
+ done
+
+ local cmd="pw usermod -n '$_user_name'"
+ [ "$user_gid" ] && cmd="$cmd -g '$_user_gid'"
+ [ "$user_shell" ] && cmd="$cmd -s '$_user_shell'"
+ [ "$user_uid" ] && cmd="$cmd -u '$_user_uid'"
+ [ "$user_account_expire" -o \
+ "$no_account_expire" ] &&
+ cmd="$cmd -e '$_user_account_expire'"
+ [ "$user_class" -o "$null_class" ] &&
+ cmd="$cmd -L '$_user_class'"
+ [ "$user_gecos" -o "$null_gecos" ] &&
+ cmd="$cmd -c '$_user_gecos'"
+ [ "$user_home_dir" ] &&
+ cmd="$cmd -d '$_user_home_dir'"
+ [ "$user_member_groups" -o "$null_members" ] &&
+ cmd="$cmd -G '$_user_member_groups'"
+ [ "$user_password_expire" -o \
+ "$no_password_expire" ] &&
+ cmd="$cmd -p '$_user_password_expire'"
+
+ # Execute the command
+ if [ "$user_password_disable" ]; then
+ f_eval_catch $funcname pw '%s -h -' "$cmd"
+ elif [ "$user_password" ]; then
+ echo "$user_password" | f_eval_catch \
+ $funcname pw '%s -h 0' "$cmd"
+ else
+ f_eval_catch $funcname pw '%s' "$cmd"
+ fi || continue
+
+ # Create home directory if desired
+ [ "${user_home_create:-$msg_no}" != "$msg_no" ] &&
+ f_user_create_homedir "$user_name"
+
+ # Copy dotfiles if desired
+ [ "${user_dotfiles_create:-$msg_no}" != \
+ "$msg_no" ] && f_user_copy_dotfiles "$user_name"
+
+ break # to success
+ ;;
+ 1) # Login (select different login from list)
+ f_dialog_menu_user_list "$user_name" || continue
+ f_dialog_menutag_fetch mtag
+
+ [ "$mtag" = "X $msg_exit" ] && continue
+
+ if ! f_input_user "$mtag"; then
+ f_show_err "$msg_login_not_found" "$mtag"
+ # Attempt to fall back to previous selection
+ f_input_user "$input" || return $FAILURE
+ else
+ input="$mtag"
+ fi
+ title="$msg_edit_view $msg_user: $user_name"
+ ;;
+ 2) # Full Name
+ f_dialog_input_gecos user_gecos "$user_gecos" &&
+ [ ! "$user_gecos" ] && null_gecos=1 ;;
+ 3) # Password
+ f_dialog_input_password \
+ user_password user_password_disable ;;
+ 4) # User ID
+ f_dialog_input_uid user_uid "$user_uid" ;;
+ 5) # Group ID
+ f_dialog_input_gid user_gid "$user_gid" ;;
+ 6) # Member of Groups
+ f_dialog_input_member_groups \
+ user_member_groups "$user_member_groups" &&
+ [ ! "$user_member_groups" ] &&
+ null_members=1 ;;
+ 7) # Login Class
+ f_dialog_input_class user_class "$user_class" &&
+ [ ! "$user_class" ] && null_class=1 ;;
+ 8) # Password Expires On
+ f_dialog_input_expire_password \
+ user_password_expire "$user_password_expire" &&
+ [ ! "$user_password_expire" ] &&
+ no_password_expire=1 ;;
+ 9) # Account Expires On
+ f_dialog_input_expire_account \
+ user_account_expire "$user_account_expire" &&
+ [ ! "$user_account_expire" ] &&
+ no_account_expire=1 ;;
+ A) # Home Directory
+ f_dialog_input_home_dir \
+ user_home_dir "$user_home_dir" ;;
+ B) # Shell
+ f_dialog_input_shell user_shell "$user_shell" ;;
+ C) # Create Home Directory?
+ if [ "${user_home_create:-$msg_no}" != "$msg_no" ]
+ then
+ user_home_create="$msg_no"
+ else
+ user_home_create="$msg_yes"
+ fi ;;
+ D) # Create Dotfiles?
+ if [ "${user_dotfiles_create:-$msg_no}" != \
+ "$msg_no" ]
+ then
+ user_dotfiles_create="$msg_no"
+ else
+ user_dotfiles_create="$msg_yes"
+ fi ;;
+ esac
+ done
+ else
+ local var
+ for var in account_expire class gecos gid home_dir \
+ member_groups name password_expire shell uid \
+ ; do
+ local _user_$var
+ eval f_shell_escape \"\$user_$var\" _user_$var
+ done
+
+ # Form the command
+ local cmd="pw usermod -n '$_user_name'"
+ [ "$user_gid" ] && cmd="$cmd -g '$_user_gid'"
+ [ "$user_home_dir" ] && cmd="$cmd -d '$_user_home_dir'"
+ [ "$user_shell" ] && cmd="$cmd -s '$_user_shell'"
+ [ "$user_uid" ] && cmd="$cmd -u '$_user_uid'"
+ [ "$user_account_expire" -o "$no_account_expire" ] &&
+ cmd="$cmd -e '$_user_account_expire'"
+ [ "$user_class" -o "$null_class" ] &&
+ cmd="$cmd -L '$_user_class'"
+ [ "$user_gecos" -o "$null_gecos" ] &&
+ cmd="$cmd -c '$_user_gecos'"
+ [ "$user_member_groups" -o "$null_members" ] &&
+ cmd="$cmd -G '$_user_member_groups'"
+ [ "$user_password_expire" -o "$no_password_expire" ] &&
+ cmd="$cmd -p '$_user_password_expire'"
+
+ # Execute the command
+ local retval err
+ if [ "$user_password_disable" ]; then
+ f_eval_catch -k err $funcname pw '%s -h -' "$cmd"
+ elif [ "$user_password" ]; then
+ err=$( echo "$user_password" | f_eval_catch -de \
+ $funcname pw '%s -h 0' "$cmd" 2>&1 )
+ else
+ f_eval_catch -k err $funcname pw '%s' "$cmd"
+ fi
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_err "%s" "$err"
+ return $retval
+ fi
+
+ # Create home directory if desired
+ [ "${user_home_create:-$msg_no}" != "$msg_no" ] &&
+ f_user_create_homedir "$user_name"
+
+ # Copy dotfiles if desired
+ [ "${user_dotfiles_create:-$msg_no}" != "$msg_no" ] &&
+ f_user_copy_dotfiles "$user_name"
+ fi
+
+ f_dialog_title "$title"
+ $alert "$msg_login_updated"
+ f_dialog_title_restore
+ [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
+
+ return $SUCCESS
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." usermgmt/user.subr
+
+fi # ! $_USERMGMT_USER_SUBR
diff --git a/usr.sbin/bsdconfig/usermgmt/share/user_input.subr b/usr.sbin/bsdconfig/usermgmt/share/user_input.subr
index c95685c..39578c8 100644
--- a/usr.sbin/bsdconfig/usermgmt/share/user_input.subr
+++ b/usr.sbin/bsdconfig/usermgmt/share/user_input.subr
@@ -1,7 +1,7 @@
if [ ! "$_USERMGMT_USER_INPUT_SUBR" ]; then _USERMGMT_USER_INPUT_SUBR=1
#
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -48,39 +48,57 @@ f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
############################################################ FUNCTIONS
-# f_get_member_groups $user
+# f_get_member_groups $var_to_set $user
#
# Get a list of additional groups $user is a member of in group(5).
#
f_get_member_groups()
{
- echo $( pw groupshow -a | awk -F: "/[:,]$1(,|\$)/{print \$1}" )
+ f_replaceall "$( pw groupshow -a | awk -F: -v user="$2" '{
+ if (!split($4, users, /,/)) next
+ for (u in users) if (users[u] == user) { print $1; next }
+ }' )" "[$NL]" "," "$1"
}
# f_input_user $user
#
-# Given $user name or id, create the environment variables pw_name, pw_uid,
-# pw_gid, pw_class, pw_password_expire, pw_account_expire, pw_gecos,
-# pw_home_dir, pw_shell, and pw_member_groups (and pw_password is reset to
-# NULL).
+# Given $user name or id, create the environment variables user_name, user_uid,
+# user_gid, user_class, user_password_expire, user_account_expire, user_gecos,
+# user_home_dir, user_shell, and user_member_groups (and user_password is reset
+# to NULL).
#
f_input_user()
{
+ local funcname=f_input_user
local user="$1"
- eval $( pw usershow "$user" | awk -F: '
+
+ f_dprintf "$funcname: Getting info for user \`%s'" "$user"
+ eval "$( pw usershow "$user" 2> /dev/null | awk -F: '
+ function set_value(var, value) {
+ gsub(/'\''/, "'\''\\'\'\''", value)
+ printf "user_%s='\'%s\''\n", var, value
+ }
{
- printf "pw_name='\'%s\''\n", $1
- printf "pw_password=\n"
- printf "pw_uid='\'%s\''\n", $3
- printf "pw_gid='\'%s\''\n", $4
- printf "pw_class='\'%s\''\n", $5
- printf "pw_password_expire='\'%s\''\n", $6
- printf "pw_account_expire='\'%s\''\n", $7
- printf "pw_gecos='\'%s\''\n", $8
- printf "pw_home_dir='\'%s\''\n", $9
- printf "pw_shell='\'%s\''\n", $10
- }' )
- pw_member_groups=$( f_get_member_groups "$user" )
+ found = $1 != ""
+ set_value("name", $1 )
+ set_value("password", "" )
+ set_value("uid", $3 )
+ set_value("gid", $4 )
+ set_value("class", $5 )
+ set_value("password_expire", $6 )
+ set_value("account_expire", $7 )
+ set_value("gecos", $8 )
+ set_value("home_dir", $9 )
+ set_value("shell", $10)
+ exit
+ }
+ END { if (!found) print "false" }' )"
+ local retval=$?
+
+ f_dprintf "$funcname: Getting group memberships for user \`%s'" "$user"
+ f_get_member_groups user_member_groups "$user"
+
+ return $retval
}
# f_dialog_menu_user_list [$default]
@@ -99,10 +117,13 @@ f_dialog_menu_user_list()
# Add users from passwd(5)
menu_list="$menu_list $( pw usershow -a | awk -F: '
- !/^[[:space:]]*(#|$)/ {
- printf "'\'%s\'\ \'%s\''\n", $1, $8
- }'
- )"
+ function mprint(tag, item) {
+ gsub(/'\''/, "'\''\\'\'\''", tag)
+ gsub(/'\''/, "'\''\\'\'\''", item)
+ printf "'\'%s\'\ \'%s\''\n", tag, item
+ }
+ !/^[[:space:]]*(#|$)/ { mprint($1, $8) }
+ ' )"
local height width rows
eval f_dialog_menu_size height width rows \
@@ -130,760 +151,710 @@ f_dialog_menu_user_list()
return $retval
}
-# f_dialog_input_member_groups [$member_groups]
+# f_dialog_input_member_groups $var_to_set [$member_groups]
#
# Allows the user to edit group memberships for a given user. If the user does
-# not cancel or press ESC, the $pw_member_groups variable will hold the newly-
+# not cancel or press ESC, the $var_to_set variable will hold the newly-
# configured value upon return.
#
f_dialog_input_member_groups()
{
- local _member_groups="$1"
- local prompt="$msg_member_of_groups"
- local check_list= # Calculated below
- local hline="$hline_alnum_space_tab_enter"
- local group
+ local __var_to_set="$1" __input="$2"
+ local __prompt="$msg_member_of_groups"
+ local __menu_list="
+ 'X' '$msg_continue'
+ '1' '$msg_select_groups_from_list'
+ '2' '$msg_enter_groups_manually'
+ " # END-QUOTE
+ local __defaultitem=
+ local __hline="$hline_alnum_space_tab_enter"
- #
- # Generate the checklist menu
- #
- for group in $(
- pw groupshow -a | awk -F: '!/^[[:space:]]*(#|$)/{print $1}'
- ); do
- # Format of a checklist menu entry is "tag item status"
- # (setting both tag and item to the group name below).
- if echo "$_member_groups" | grep -q "\<$group\>"; then
- check_list="$check_list $group $group on"
- else
- check_list="$check_list $group $group off"
- fi
- done
+ local __mheight __mwidth __mrows
+ eval f_dialog_menu_size __mheight __mwidth __mrows \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$__prompt\" \
+ \"\$__hline\" \
+ $__menu_list
- #
- # Loop until the user provides taint-free/valid input
- #
- local height width rows
+ local __menu_choice __retval
while :; do
- eval f_dialog_checklist_size height width rows \
- \"\$DIALOG_TITLE\" \
- \"\$DIALOG_BACKTITLE\" \
- \"\$prompt\" \
- \"\$hline\" \
- $check_list
- _member_groups=$( eval $DIALOG \
+ __menu_choice=$( eval $DIALOG \
--title \"\$DIALOG_TITLE\" \
--backtitle \"\$DIALOG_BACKTITLE\" \
- --separate-output \
- --hline \"\$hline\" \
+ --hline \"\$__hline\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
- --checklist \"\$prompt\" \
- $height $width $rows \
- $check_list \
+ --default-item \"\$__defaultitem\" \
+ --menu \"\$__prompt\" \
+ $__mheight $__mwidth $__mrows \
+ $__menu_list \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
- ) || return $?
- # Return if user either pressed ESC or chose Cancel/No
- f_dialog_data_sanitize _member_groups
-
- #
- # Validate each of the groups the user has entered
- #
- local all_groups_valid=1
- for group in $_member_groups; do
- if ! f_quietly pw groupshow -n "$group"; then
- f_show_msg "$msg_group_not_found" "$group"
- all_groups_valid=
- break
- fi
- done
- [ "$all_groups_valid" ] || continue
+ )
+ __retval=$?
+ f_dialog_data_sanitize __menu_choice
+ __defaultitem="$__menu_choice"
+ f_dprintf "retval=%u menu_choice=[%s]" \
+ $__retval "$__menu_choice"
- pw_member_groups="$_member_groups"
- break
- done
- save_flag=1
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $__retval -eq $DIALOG_OK ] || return $__retval
- f_dprintf "pw_member_groups: [%s]->[%s]" \
- "$cur_pw_member_groups" "$pw_member_groups"
+ local __member_groups
+ case "$__menu_choice" in
+ X) # Exit
+ break ;;
+ 1) # Select Groups from a list
+ local __check_list= # Calculated below
+ local __group_list __g __grp __length=0
+ __group_list=$( pw groupshow -a |
+ awk -F: '!/^[[:space:]]*(#|$)/{print $1}' )
+ while [ $__length -ne ${#__group_list} ]; do
+ __g="${__group_list%%$NL*}" # First line
+ f_shell_escape "$__g" __grp
+
+ # Format of a checklist entry: tag item status
+ # NB: Setting both tag/item to group name below
+ __check_list="$__check_list '$__grp' '$__grp'"
+ case "$__input" in
+ "$__g"|"$__g",*|*,"$__g",*|*,"$__g")
+ __check_list="$__check_list on" ;;
+ *)
+ __check_list="$__check_list off"
+ esac
+
+ __length=${#__group_list}
+ __group_list="${__group_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
+ __member_groups=$( 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 __member_groups
+
+ #
+ # 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 "$__member_groups" "[$NL]" "," __input
+ ;;
+ 2) # Enter Groups manually
+ local __prompt2="$msg_groups"
+ __prompt2="$__prompt2 ($msg_separated_by_commas)"
+
+ f_dialog_input __member_groups \
+ "$__prompt2" "$__input" \
+ "$hline_num_tab_enter" || continue
+ # Return to previous menu if user either
+ # pressed ESC or chose Cancel/No
+
+ #
+ # Validate each of the groups the user has entered
+ #
+ local __all_groups_valid=1 __grp __grp_list
+ f_replaceall "$__member_groups" "," " " __grp_list
+ for __grp in $__grp_list; do
+ if ! f_quietly pw groupshow -n "$__grp"; then
+ f_show_msg "$msg_group_not_found" \
+ "$__grp"
+ __all_groups_valid=
+ break
+ fi
+ done
+ [ "$__all_groups_valid" ] || continue
+
+ __input="$__member_groups"
+ ;;
+ esac
+ done
+ setvar "$__var_to_set" "$__input"
return $DIALOG_OK
}
-# f_dialog_input_name [$name]
+# f_dialog_input_name $var_to_set [$name]
#
# Allows the user to enter a new username for a given user. If the user does
-# not cancel or press ESC, the $pw_name variable will hold the newly-configured
-# value upon return.
-#
-# If $cur_pw_name is defined, the user can enter that and by-pass error-
-# checking (allowing the user to "revert" to an old value without, for example,
-# being told that the username already exists).
+# not cancel or press ESC, the $var_to_set variable will hold the newly-
+# configured value upon return.
#
f_dialog_input_name()
{
+ local __var_to_set="$1" __name="$2"
+
#
# Loop until the user provides taint-free/valid input
#
- local _name="$1" _input="$1"
+ local __input="$__name"
while :; do
-
# Return if user has either pressed ESC or chosen Cancel/No
- f_dialog_input _input "$msg_login" "$_input" \
+ f_dialog_input __input "$msg_login" "$__input" \
"$hline_alnum_tab_enter" || return $?
# Check for no-change
- [ "$_input" = "$_name" ] && return $DIALOG_OK
-
- # Check for reversion
- if [ "$_input" = "$cur_pw_name" ]; then
- pw_name="$cur_pw_name"
+ if [ "$__input" = "$__name" ]; then
+ setvar "$__var_to_set" "$__input"
return $DIALOG_OK
fi
# Check for NULL entry
- if [ ! "$_input" ]; then
+ if [ ! "$__input" ]; then
f_show_msg "$msg_login_is_empty"
continue
fi
# Check for invalid entry
- if ! echo "$_input" | grep -q "^[[:alpha:]]"; then
+ case "$__input" in [!a-zA-Z]*)
f_show_msg "$msg_login_must_start_with_letter"
continue
- fi
+ esac
# Check for duplicate entry
- if f_quietly pw usershow -n "$_input"; then
- f_show_msg "$msg_login_already_used" "$_input"
+ if f_quietly pw usershow -n "$__input"; then
+ f_show_msg "$msg_login_already_used" "$__input"
continue
fi
- pw_name="$_input"
+ setvar "$__var_to_set" "$__input"
break
done
- save_flag=1
-
- f_dprintf "pw_name: [%s]->[%s]" "$cur_pw_name" "$pw_name"
return $DIALOG_OK
}
-# f_dialog_input_password
+# f_dialog_input_password $var_to_set $dvar_to_set
#
-# Prompt the user to enter a password (twice).
+# 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 login, wherein $dvar_to_set has
+# a value of 1 to indicate password authentication should be disabled.
#
f_dialog_input_password()
{
- local prompt1="$msg_password"
- local prompt2="$msg_reenter_password"
- local hline="$hline_alnum_punc_tab_enter"
+ local __var_to_set="$1" __dvar_to_set="$2"
+ local __prompt1="$msg_password"
+ local __prompt2="$msg_reenter_password"
+ local __hline="$hline_alnum_punc_tab_enter"
- local height1 width1
- f_dialog_inputbox_size height1 width1 \
+ local __height1 __width1
+ f_dialog_inputbox_size __height1 __width1 \
"$DIALOG_TITLE" \
"$DIALOG_BACKTITLE" \
- "$prompt1" \
+ "$__prompt1" \
"" \
- "$hline"
- local height2 width2
- f_dialog_inputbox_size height2 width2 \
+ "$__hline"
+ local __height2 __width2
+ f_dialog_inputbox_size __height2 __width2 \
"$DIALOG_TITLE" \
"$DIALOG_BACKTITLE" \
- "$prompt2" \
+ "$__prompt2" \
"" \
- "$hline"
+ "$__hline"
#
# Loop until the user provides taint-free/valid input
#
- local _password1 _password2
+ local __retval __password1 __password2
while :; do
- _password1=$( $DIALOG \
+ __password1=$( $DIALOG \
--title "$DIALOG_TITLE" \
--backtitle "$DIALOG_BACKTITLE" \
- --hline "$hline" \
+ --hline "$__hline" \
--ok-label "$msg_ok" \
--cancel-label "$msg_cancel" \
--insecure \
- --passwordbox "$prompt1" \
- $height1 $width1 \
+ --passwordbox "$__prompt1" \
+ $__height1 $__width1 \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
) || return $?
# Return if user either pressed ESC or chose Cancel/No
- debug= f_dialog_line_sanitize _password1
+ debug= f_dialog_line_sanitize __password1
- _password2=$( $DIALOG \
+ __password2=$( $DIALOG \
--title "$DIALOG_TITLE" \
--backtitle "$DIALOG_BACKTITLE" \
- --hline "$hline" \
+ --hline "$__hline" \
--ok-label "$msg_ok" \
--cancel-label "$msg_cancel" \
--insecure \
- --passwordbox "$prompt2" \
- $height2 $width2 \
+ --passwordbox "$__prompt2" \
+ $__height2 $__width2 \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
) || return $?
# Return if user either pressed ESC or chose Cancel/No
- debug= f_dialog_line_sanitize _password2
+ debug= f_dialog_line_sanitize __password2
# Check for password mismatch
- if [ "$_password1" != "$_password2" ]; then
+ if [ "$__password1" != "$__password2" ]; then
f_show_msg "$msg_passwords_do_not_match"
continue
fi
# Check for NULL entry
- if [ ! "$_password1" ]; then
+ if [ ! "$__password1" ]; then
f_dialog_yesno "$msg_disable_password_auth_for_account"
- local retval=$?
- if [ $retval -eq $DIALOG_ESC ]; then
- return $retval
- elif [ $retval -eq $DIALOG_OK ]; then
- pw_password_disable=1
+ __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
- pw_password_disable=
+ setvar "$__dvar_to_set" ""
fi
- pw_password="$_password1"
+ setvar "$__var_to_set" "$__password1"
break
done
- save_flag=1
-
- f_dprintf "pw_password: [%s]->[%s]" "$cur_pw_password" "$pw_password"
return $DIALOG_OK
}
-# f_dialog_input_gecos [$gecos]
+# f_dialog_input_gecos $var_to_set [$gecos]
#
# Allow the user to enter new GECOS information for a given user. This
# information is commonly used to store the ``Full Name'' of the user. If the
-# user does not cancel or press ESC, the $pw_gecos variable will hold the
+# user does not cancel or press ESC, the $var_to_set variable will hold the
# newly-configured value upon return.
#
f_dialog_input_gecos()
{
- local _input="$1"
+ local __var_to_set="$1" __input="$2"
# Return if user has either pressed ESC or chosen Cancel/No
- f_dialog_input _input "$msg_full_name" "$_input" \
+ f_dialog_input __input "$msg_full_name" "$__input" \
"$hline_alnum_punc_tab_enter" || return $?
- pw_gecos="$_input"
- save_flag=1
-
- f_dprintf "pw_gecos: [%s]->[%s]" "$cur_pw_gecos" "$pw_gecos"
-
+ setvar "$__var_to_set" "$__input"
return $DIALOG_OK
}
-# f_dialog_input_uid [$uid]
+# f_dialog_input_uid $var_to_set [$uid]
#
# Allow the user to enter a new UID for a given user. If the user does not
-# cancel or press ESC, the $pw_uid variable will hold the newly-configured
+# cancel or press ESC, the $var_to_set variable will hold the newly-configured
# value upon return.
#
f_dialog_input_uid()
{
- local _input="$1"
+ local __var_to_set="$1" __input="$2"
# Return if user has either pressed ESC or chosen Cancel/No
- f_dialog_input _input "$msg_user_id_leave_empty_for_default" \
- "$_input" "$hline_num_tab_enter" || return $?
-
- pw_uid="$_input"
- save_flag=1
-
- f_dprintf "pw_uid: [%s]->[%s]" "$cur_pw_uid" "$pw_uid"
+ f_dialog_input __input "$msg_user_id_leave_empty_for_default" \
+ "$__input" "$hline_num_tab_enter" || return $?
+ setvar "$__var_to_set" "$__input"
return $DIALOG_OK
}
-# f_dialog_input_gid [$gid]
+# f_dialog_input_gid $var_to_set [$gid]
#
# Allow the user to enter a new primary GID for a given user. If the user does
-# not cancel or press ESC, the $pw_gid variable will hold the newly-configured
-# value upon return.
+# not cancel or press ESC, the $var_to_set variable will hold the newly-
+# configured value upon return.
#
f_dialog_input_gid()
{
- local _input="$1"
+ 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 $?
-
- pw_gid="$_input"
- save_flag=1
-
- f_dprintf "pw_gid: [%s]->[%s]" "$cur_pw_gid" "$pw_gid"
+ 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_class [$class]
+# f_dialog_input_class $var_to_set [$class]
#
# Allow the user to enter a new login class for a given user. If the user does
-# not cancel or press ESC, the $pw_class variable will hold the newly-
+# not cancel or press ESC, the $var_to_set variable will hold the newly-
# configured value upon return.
#
f_dialog_input_class()
{
- local _input="$1"
+ local __var_to_set="$1" __input="$2"
# Return if user has either pressed ESC or chosen Cancel/No
- f_dialog_input _input "$msg_login_class" "$_input" \
+ f_dialog_input __input "$msg_login_class" "$__input" \
"$hline_alnum_tab_enter" || return $?
- pw_class="$_input"
- save_flag=1
-
- f_dprintf "pw_class: [%s]->[%s]" "$cur_pw_class" "$pw_class"
-
+ setvar "$__var_to_set" "$__input"
return $DIALOG_OK
}
-# f_dialog_input_expire_password [$seconds]
+# f_dialog_input_expire_password $var_to_set [$seconds]
#
# Allow the user to enter a date/time (in number-of-seconds since the `epoch')
# for when a given user's password must be changed. If the user does not cancel
-# or press ESC, the $pw_password_expire variable will hold the newly-
-# configured value upon return.
+# or press ESC, the $var_to_set variable will hold the newly-configured value
+# upon return.
#
f_dialog_input_expire_password()
{
- local prompt="$msg_password_expires_on"
- local menu_list="
+ local __var_to_set="$1" __input="$2"
+ local __prompt="$msg_password_expires_on"
+ local __menu_list="
'1' '$msg_password_does_not_expire'
'2' '$msg_edit_date_time_with_a_calendar'
- '3' '$msg_enter_number_of_days_into_the_future'
- '4' '$msg_enter_value_manually'
+ '3' '$msg_enter_value_manually'
" # END-QUOTE
- local hline="$hline_num_arrows_tab_enter"
- local retval _input="$1"
+ local __defaultitem= # Calculated below
+ local __hline="$hline_num_arrows_tab_enter"
- local mheight mwidth mrows
- eval f_dialog_menu_size mheight mwidth mrows \
+ local __mheight __mwidth __mrows
+ eval f_dialog_menu_size __mheight __mwidth __mrows \
\"\$DIALOG_TITLE\" \
\"\$DIALOG_BACKTITLE\" \
- \"\$prompt\" \
- \"\$hline\" \
- $menu_list
- local cheight cwidth
- f_dialog_calendar_size cheight cwidth \
+ \"\$__prompt\" \
+ \"\$__hline\" \
+ $__menu_list
+ local __cheight __cwidth
+ f_dialog_calendar_size __cheight __cwidth \
"$DIALOG_TITLE" \
"$DIALOG_BACKTITLE" \
- "$prompt" \
- "$hline"
- local theight twidth
- f_dialog_timebox_size theight twidth \
+ "$__prompt" \
+ "$__hline"
+ local __theight __twidth
+ f_dialog_timebox_size __theight __twidth \
"$DIALOG_TITLE" \
"$DIALOG_BACKTITLE" \
- "$prompt" \
- "$hline"
+ "$__prompt" \
+ "$__hline"
#
# Loop until the user provides taint-free/cancellation-free input
#
- local date_type defaultitem=
+ local __retval __date_type
while :; do
- date_type=$( eval $DIALOG \
+ __date_type=$( eval $DIALOG \
--title \"\$DIALOG_TITLE\" \
--backtitle \"\$DIALOG_BACKTITLE\" \
- --hline \"\$hline\" \
- --default-item \"\$defaultitem\" \
+ --hline \"\$__hline\" \
+ --default-item \"\$__defaultitem\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
- --menu \"\$prompt\" \
- $mheight $mwidth $mrows \
- $menu_list \
+ --menu \"\$__prompt\" \
+ $__mheight $__mwidth $__mrows \
+ $__menu_list \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
)
- retval=$?
- f_dialog_data_sanitize date_type
- defaultitem="$date_type"
- f_dprintf "retval=%u date_type=[%s]" $retval "$date_type"
+ __retval=$?
+ f_dialog_data_sanitize __date_type
+ __defaultitem="$__date_type"
+ f_dprintf "retval=%u date_type=[%s]" $__retval "$__date_type"
# Return if user has either pressed ESC or chosen Cancel/No
- [ $retval -eq $DIALOG_OK ] || return $retval
+ [ $__retval -eq $DIALOG_OK ] || return $__retval
- case "$date_type" in
+ case "$__date_type" in
1) # Password does not expire
- _input=""
- break ;;
+ __input= break ;;
2) # Edit date/time with a calendar
- local _input_date _input_time ret_date ret_time
+ local __input_date __input_time __ret_date __ret_time
- local secs="$_input"
- { f_isinteger "$secs" && [ $secs -gt 0 ]; } || secs=
- _input_date=$( date -j -f "%s" -- "$secs" \
+ local __seconds="$__input"
+ { f_isinteger "$__seconds" && [ $__seconds -gt 0 ]; } ||
+ __seconds=
+ __input_date=$( date -j -f "%s" -- "$__seconds" \
"+%d %m %Y" 2> /dev/null )
- ret_date=$( eval $DIALOG \
+ __ret_date=$( eval $DIALOG \
--title \"\$DIALOG_TITLE\" \
--backtitle \"\$DIALOG_BACKTITLE\" \
- --hline \"\$hline\" \
+ --hline \"\$__hline\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
- --calendar \"\$prompt\" \
- $cheight $cwidth \
- $_input_date \
+ --calendar \"\$__prompt\" \
+ $__cheight $__cwidth \
+ $__input_date \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
)
- retval=$?
- f_dialog_data_sanitize ret_date
- f_dprintf "retval=%u ret_date=[%s]" $retval "$ret_date"
+ __retval=$?
+ f_dialog_data_sanitize __ret_date
+ f_dprintf "retval=%u ret_date=[%s]" \
+ $__retval "$__ret_date"
# Return to menu if either ESC or Cancel/No
- [ $retval -eq $DIALOG_OK ] || continue
+ [ $__retval -eq $DIALOG_OK ] || continue
- _input_time=
- [ "$secs" ] && _input_time=$( date -j \
- -f %s -- "$_input" "+%H %M %S" 2> /dev/null )
- ret_time=$( eval $DIALOG \
+ __input_time=
+ [ "$__seconds" ] && __input_time=$( date -j \
+ -f %s -- "$__input" "+%H %M %S" 2> /dev/null )
+ __ret_time=$( eval $DIALOG \
--title \"\$DIALOG_TITLE\" \
--backtitle \"\$DIALOG_BACKTITLE\" \
- --hline \"\$hline\" \
+ --hline \"\$__hline\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
- --timebox \"\$prompt\" \
- $theight $twidth \
- $_input_time \
+ --timebox \"\$__prompt\" \
+ $__theight $__twidth \
+ $__input_time \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
)
- retval=$?
- f_dialog_data_sanitize ret_time
- f_dprintf "retval=%u ret_time=[%s]" $retval "$ret_time"
+ __retval=$?
+ f_dialog_data_sanitize __ret_time
+ f_dprintf "retval=%u ret_time=[%s]" \
+ $__retval "$__ret_time"
# Return to menu if either ESC or Cancel/No
- [ $retval -eq $DIALOG_OK ] || continue
+ [ $__retval -eq $DIALOG_OK ] || continue
- _input=$( date \
- -j -f "%d/%m/%Y %T" \
- -- "$ret_date $ret_time" \
- +%s 2> /dev/null )
- f_dprintf "_input=[%s]" "$_input"
+ __input=$( date -j -f "%d/%m/%Y %T" -- \
+ "$__ret_date $__ret_time" +%s 2> /dev/null )
+ f_dprintf "input=[%s]" "$__input"
break ;;
- 3) # Enter number of days into the future
- local ret_days seconds="$( date +%s )"
-
- f_isinteger "$_input" || _input=0
- [ $_input -gt 0 -a $_input -gt $seconds ] &&
- ret_days=$(( ( $_input - $seconds ) / 86400 ))
- f_isinteger "$ret_days" &&
- ret_days=$(( $ret_days + 1 ))
+ 3) # Enter value manually
+ local __msg __new_input
+ f_sprintf __msg "$msg_password_expire_manual_edit" \
+ "$( date -r 0 "+%c %Z" )"
# Return to menu if either ESC or Cancel/No
- f_dialog_input ret_days \
- "$msg_password_expires_in_how_many_days" \
- "$ret_days" "$hline" || continue
-
- # Taint-check the user's input
- if ! f_isinteger "$ret_days"; then
- f_show_msg "$msg_invalid_number_of_days"
- continue
- fi
+ f_dialog_input __new_input \
+ "$__msg" "$__input" "$__hline" || continue
- f_dprintf "ret_days=[%s]" "$ret_days"
- case "$ret_days" in
- [-+]*) _input=$( date -v${ret_days}d +%s ) ;;
- 0) _input=$( date +%s ) ;;
- *) _input=$( date -v+${ret_days}d +%s ) ;;
- esac
- f_dprintf "_input=[%s]" "$_input"
- break ;;
-
- 4) # Enter value manually
- local msg ret_secs
- f_sprintf msg "$msg_number_of_seconds_since_epoch" \
- "$( date -r 1 "+%c %Z" )"
-
- # Return to menu if either ESC or Cancel/No
- f_dialog_input ret_secs \
- "$msg" "$_input" "$hline" || continue
-
- _input="$ret_secs"
-
- # Taint-check the user's input
- if ! f_isinteger "${_input:-0}"; then
- f_show_msg "$msg_invalid_number_of_seconds"
- continue
- fi
-
- f_dprintf "_input=[%s]" "$_input"
+ __input="$__new_input"
+ f_dprintf "input=[%s]" "$__input"
break ;;
esac
done # Loop forever
- pw_password_expire="$_input"
- save_flag=1
-
- f_dprintf "pw_password_expire: [%s]->[%s]" \
- "$cur_pw_password_expire" "$pw_password_expire"
-
+ setvar "$__var_to_set" "$__input"
return $DIALOG_OK
}
-# f_dialog_input_expire_account [$seconds]
+# f_dialog_input_expire_account $var_to_set [$seconds]
#
# Allow the user to enter a date/time (in number-of-seconds since the `epoch')
# for when a given user's account should become expired. If the user does not
-# cancel or press ESC, the $pw_account_expire variable will hold the newly-
-# configured value upon return.
+# cancel or press ESC, the $var_to_set variable will hold the newly-configured
+# value upon return.
#
f_dialog_input_expire_account()
{
- local prompt="$msg_account_expires_on"
- local menu_list="
+ local __var_to_set="$1" __input="$2"
+ local __prompt="$msg_account_expires_on"
+ local __menu_list="
'1' '$msg_account_does_not_expire'
'2' '$msg_edit_date_time_with_a_calendar'
- '3' '$msg_enter_number_of_days_into_the_future'
- '4' '$msg_enter_value_manually'
+ '3' '$msg_enter_value_manually'
" # END-QUOTE
- local hline="$hline_num_arrows_tab_enter"
- local retval _input="$1"
+ local __defaultitem= # Calculated below
+ local __hline="$hline_num_arrows_tab_enter"
- local mheight mwidth mrows
- eval f_dialog_menu_size mheight mwidth mrows \
+ local __mheight __mwidth __mrows
+ eval f_dialog_menu_size __mheight __mwidth __mrows \
\"\$DIALOG_TITLE\" \
\"\$DIALOG_BACKTITLE\" \
- \"\$prompt\" \
- \"\$hline\" \
- $menu_list
- local cheight cwidth
- f_dialog_calendar_size cheight cwidth \
+ \"\$__prompt\" \
+ \"\$__hline\" \
+ $__menu_list
+ local __cheight __cwidth
+ f_dialog_calendar_size __cheight __cwidth \
"$DIALOG_TITLE" \
"$DIALOG_BACKTITLE" \
- "$prompt" \
- "$hline"
- local theight twidth
- f_dialog_timebox_size theight twidth \
+ "$__prompt" \
+ "$__hline"
+ local __theight __twidth
+ f_dialog_timebox_size __theight __twidth \
"$DIALOG_TITLE" \
"$DIALOG_BACKTITLE" \
- "$prompt" \
- "$hline"
+ "$__prompt" \
+ "$__hline"
#
# Loop until the user provides taint-free/cancellation-free input
#
- local date_type defaultitem=
+ local __retval __date_type
while :; do
- date_type=$( eval $DIALOG \
+ __date_type=$( eval $DIALOG \
--title \"\$DIALOG_TITLE\" \
--backtitle \"\$DIALOG_BACKTITLE\" \
- --hline \"\$hline\" \
- --default-item \"\$defaultitem\" \
+ --hline \"\$__hline\" \
+ --default-item \"\$__defaultitem\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
- --menu \"\$prompt\" \
- $mheight $mwidth $mrows \
- $menu_list \
+ --menu \"\$__prompt\" \
+ $__mheight $__mwidth $__mrows \
+ $__menu_list \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
)
- retval=$?
- f_dialog_data_sanitize date_type
- defaultitem="$date_type"
- f_dprintf "retval=%u date_type=[%s]" $retval "$date_type"
+ __retval=$?
+ f_dialog_data_sanitize __date_type
+ __defaultitem="$__date_type"
+ f_dprintf "retval=%u date_type=[%s]" $__retval "$__date_type"
# Return if user has either pressed ESC or chosen Cancel/No
- [ $retval -eq $DIALOG_OK ] || return $retval
+ [ $__retval -eq $DIALOG_OK ] || return $__retval
- case "$date_type" in
+ case "$__date_type" in
1) # Account does not expire
- _input=""
- break ;;
+ __input= break ;;
2) # Edit date/time with a calendar
- local _input_date _input_time ret_date ret_time
+ local __input_date __input_time __ret_date __ret_time
- local secs="$_input"
- { f_isinteger "$secs" && [ $secs -gt 0 ]; } || secs=
- _input_date=$( date -j -f "%s" -- "$secs" \
+ local __seconds="$__input"
+ { f_isinteger "$__seconds" && [ $__seconds -gt 0 ]; } ||
+ __seconds=
+ __input_date=$( date -j -f "%s" -- "$__seconds" \
"+%d %m %Y" 2> /dev/null )
- ret_date=$( eval $DIALOG \
+ __ret_date=$( eval $DIALOG \
--title \"\$DIALOG_TITLE\" \
--backtitle \"\$DIALOG_BACKTITLE\" \
- --hline \"\$hline\" \
+ --hline \"\$__hline\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
- --calendar \"\$prompt\" \
- $cheight $cwidth \
- $_input_date \
+ --calendar \"\$__prompt\" \
+ $__cheight $__cwidth \
+ $__input_date \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
)
- retval=$?
- f_dialog_data_sanitize ret_date
- f_dprintf "retval=%u ret_date=[%s]" $retval "$ret_date"
+ __retval=$?
+ f_dialog_data_sanitize __ret_date
+ f_dprintf "retval=%u ret_date=[%s]" \
+ $__retval "$__ret_date"
# Return to menu if either ESC or Cancel/No
- [ $retval -eq $DIALOG_OK ] || continue
+ [ $__retval -eq $DIALOG_OK ] || continue
- _input_time=
- [ "$secs" ] && _input_time=$( date -j \
- -f %s -- "$_input" "+%H %M %S" 2> /dev/null )
- ret_time=$( eval $DIALOG \
+ __input_time=
+ [ "$__seconds" ] && __input_time=$( date -j \
+ -f %s -- "$__input" "+%H %M %S" 2> /dev/null )
+ __ret_time=$( eval $DIALOG \
--title \"\$DIALOG_TITLE\" \
--backtitle \"\$DIALOG_BACKTITLE\" \
- --hline \"\$hline\" \
+ --hline \"\$__hline\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
- --timebox \"\$prompt\" \
- $theight $twidth \
- $_input_time \
+ --timebox \"\$__prompt\" \
+ $__theight $__twidth \
+ $__input_time \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
)
- retval=$?
- f_dialog_data_sanitize ret_time
- f_dprintf "retval=%u ret_time=[%s]" $retval "$ret_time"
-
- # Return to menu if either ESC or Cancel/No
- [ $retval -eq $DIALOG_OK ] || continue
-
- _input=$( date \
- -j -f "%d/%m/%Y %T" \
- -- "$ret_date $ret_time" \
- +%s 2> /dev/null )
- f_dprintf "_input=[%s]" "$_input"
- break ;;
-
- 3) # Enter number of days into the future
- local ret_days seconds="$( date +%s )"
-
- f_isinteger "$_input" || _input=0
- [ $_input -gt 0 -a $_input -gt $seconds ] &&
- ret_days=$(( ( $_input - $seconds ) / 86400 ))
- f_isinteger "$ret_days" &&
- ret_days=$(( $ret_days + 1 ))
+ __retval=$?
+ f_dialog_data_sanitize __ret_time
+ f_dprintf "retval=%u ret_time=[%s]" \
+ $__retval "$__ret_time"
# Return to menu if either ESC or Cancel/No
- f_dialog_input ret_days \
- "$msg_account_expires_in_how_many_days" \
- "$ret_days" "$hline" || continue
-
- # Taint-check the user's input
- if ! f_isinteger "$ret_days"; then
- f_show_msg "$msg_invalid_number_of_days"
- continue
- fi
+ [ $__retval -eq $DIALOG_OK ] || continue
- f_dprintf "ret_days=[%s]" "$ret_days"
- case "$ret_days" in
- [-+]*) _input=$( date -v${ret_days}d +%s ) ;;
- 0) _input=$( date +%s ) ;;
- *) _input=$( date -v+${ret_days}d +%s ) ;;
- esac
- f_dprintf "_input=[%s]" "$_input"
+ __input=$( date -j -f "%d/%m/%Y %T" -- \
+ "$ret_date $ret_time" +%s 2> /dev/null )
+ f_dprintf "input=[%s]" "$__input"
break ;;
- 4) # Enter value manually
- local msg ret_secs
- f_sprintf msg "$msg_number_of_seconds_since_epoch" \
- "$( date -r 1 "+%c %Z" )"
+ 3) # Enter value manually
+ local __msg __new_input
+ f_sprintf __msg "$msg_account_expire_manual_edit" \
+ "$( date -r 0 "+%c %Z" )"
# Return to menu if either ESC or Cancel/No
- f_dialog_input ret_secs "$msg" \
- "$_input" "$hline" || continue
-
- _input="$ret_secs"
-
- # Taint-check the user's input
- if ! f_isinteger "${_input:-0}"; then
- f_show_msg "$msg_invalid_number_of_seconds"
- continue
- fi
+ f_dialog_input __new_input \
+ "$__msg" "$__input" "$__hline" || continue
- f_dprintf "_input=[%s]" "$_input"
+ __input="$__new_input"
+ f_dprintf "input=[%s]" "$__input"
break ;;
esac
done # Loop forever
- pw_account_expire="$_input"
- save_flag=1
-
- f_dprintf "pw_account_expire: [%s]->[%s]" \
- "$cur_pw_account_expire" "$pw_account_expire"
-
+ setvar "$__var_to_set" "$__input"
return $DIALOG_OK
}
-# f_dialog_input_home_dir [$home_dir]
+# f_dialog_input_home_dir $var_to_set [$home_dir]
#
-# Allow the user to enter a new home directory for a given user. If the user
-# does not cancel or press ESC, the $pw_home_dir variable will hold the newly-
+# Allow the user to enter a new home directory for a given login. 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_home_dir()
{
- local _input="$1"
+ local __var_to_set="$1" __input="$2"
# Return if user has either pressed ESC or chosen Cancel/No
- f_dialog_input _input "$msg_home_directory" "$_input" \
+ f_dialog_input __input "$msg_home_directory" "$__input" \
"$hline_alnum_punc_tab_enter" || return $?
- pw_home_dir="$_input"
- save_flag=1
-
- f_dprintf "pw_home_dir: [%s]->[%s]" "$cur_pw_home_dir" "$pw_home_dir"
-
+ setvar "$__var_to_set" "$__input"
return $DIALOG_OK
}
-# f_dialog_input_home_create
+# f_dialog_input_home_create $var_to_set
#
-# Prompt the user to confirm creation of a given user's home directory. If the
-# user does not cancel (by choosing "No") or press ESC, the $pw_home_create
+# Prompt the user to confirm creation of a given login's home directory. If the
+# user does not cancel (by choosing "No") or press ESC, the $var_to_set
# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
#
f_dialog_input_home_create()
{
- local retval
+ local __var_to_set="$1"
f_dialog_yesno "$msg_create_home_directory"
- retval=$?
+ local __retval=$?
- if [ $retval -eq $DIALOG_OK ]; then
- pw_home_create="$msg_yes"
+ if [ $__retval -eq $DIALOG_OK ]; then
+ setvar "$__var_to_set" "$msg_yes"
else
- pw_home_create="$msg_no"
+ setvar "$__var_to_set" "$msg_no"
fi
- save_flag=1
- f_dprintf "pw_home_create: [%s]->[%s]" \
- "$cur_pw_home_create" "$pw_home_create"
-
- [ $retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
+ [ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
}
-# f_dialog_input_group_delete
+# f_dialog_input_group_delete $var_to_set [$group]
#
-# Prompt the user to confirm deletion of a given user's primary group. If the
-# user does not cancel (by choosing "No") or press ESC, the $pw_group_delete
+# Prompt the user to confirm deletion of a given login's primary group. If the
+# user does not cancel (by choosing "No") or press ESC, the $var_to_set
# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
#
f_dialog_input_group_delete()
{
- local retval
+ local __var_to_set="$1" __group="$2"
- if f_isinteger "$pw_gid"; then
- if [ $pw_gid -lt 1000 ]; then
+ if f_isinteger "$__group"; then
+ if [ $__group -lt 1000 ]; then
f_dialog_noyes "$msg_delete_primary_group"
else
f_dialog_yesno "$msg_delete_primary_group"
fi
- elif [ "$pw_gid" ]; then
- local gid=0
- gid=$( pw groupshow "$pw_gid" | awk -F: '{print $3}' )
- if f_isinteger "$gid" && [ $gid -lt 1000 ]; then
+ elif [ "$__group" ]; then
+ local __gid=0
+ __gid=$( pw groupshow "$__group" | awk -F: '{print $3}' )
+ if f_isinteger "$__gid" && [ $__gid -lt 1000 ]; then
f_dialog_noyes "$msg_delete_primary_group"
else
f_dialog_yesno "$msg_delete_primary_group"
@@ -891,131 +862,473 @@ f_dialog_input_group_delete()
else
f_dialog_yesno "$msg_delete_primary_group"
fi
- retval=$?
+ local __retval=$?
- if [ $retval -eq $DIALOG_OK ]; then
- pw_group_delete="$msg_yes"
+ if [ $__retval -eq $DIALOG_OK ]; then
+ setvar "$__var_to_set" "$msg_yes"
else
- pw_group_delete="$msg_no"
+ setvar "$__var_to_set" "$msg_no"
fi
- save_flag=1
-
- f_dprintf "pw_group_delete: [%s]->[%s]" \
- "$cur_pw_group_delete" "$pw_group_delete"
- [ $retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
+ [ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
}
-# f_dialog_input_home_delete
+# f_dialog_input_home_delete $var_to_set
#
-# Prompt the user to confirm deletion of a given user's home directory. If the
-# user does not cancel (by choosing "No") or press ESC, the $pw_home_delete
+# Prompt the user to confirm deletion of a given login's home directory. If the
+# user does not cancel (by choosing "No") or press ESC, the $var_to_set
# variable will hold $msg_yes upon return, otherwise $msg_no. Use these return
# variables ($msg_yes and $msg_no) for comparisons to be i18n-compatible.
#
f_dialog_input_home_delete()
{
- local retval
+ local __var_to_set="$1"
f_dialog_yesno "$msg_delete_home_directory"
- retval=$?
+ local __retval=$?
- if [ $retval -eq $DIALOG_OK ]; then
- pw_home_delete="$msg_yes"
+ if [ $__retval -eq $DIALOG_OK ]; then
+ setvar "$__var_to_set" "$msg_yes"
else
- pw_home_delete="$msg_no"
+ setvar "$__var_to_set" "$msg_no"
fi
- save_flag=1
- f_dprintf "pw_home_delete: [%s]->[%s]" \
- "$cur_pw_home_delete" "$pw_home_delete"
-
- [ $retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
+ [ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
}
-# f_dialog_input_dotfiles_create
+# f_dialog_input_dotfiles_create $var_to_set
#
-# Prompt the user to confirm population of a given user's home directory with
+# Prompt the user to confirm population of a given login's home directory with
# sample dotfiles. If the user does not cancel (by choosing "No") or press ESC,
-# the $pw_dotfiles_create variable will hold $msg_yes upon return, otherwise
-# $msg_no. Use these return variables ($msg_yes and $msg_no) for comparison to
-# be i18n-compatible.
+# the $var_to_set variable will hold $msg_yes upon return, otherwise $msg_no.
+# Use these return variables ($msg_yes and $msg_no) for comparison to be i18n-
+# compatible.
#
f_dialog_input_dotfiles_create()
{
- local retval
+ local __var_to_set="$1"
f_dialog_yesno "$msg_create_dotfiles"
- retval=$?
+ local __retval=$?
- if [ $retval -eq $DIALOG_OK ]; then
- pw_dotfiles_create="$msg_yes"
+ if [ $__retval -eq $DIALOG_OK ]; then
+ setvar "$__var_to_set" "$msg_yes"
else
- pw_dotfiles_create="$msg_no"
+ setvar "$__var_to_set" "$msg_no"
fi
- save_flag=1
-
- f_dprintf "pw_dotfiles_create: [%s]->[%s]" \
- "$cur_pw_dotfiles_create" "$pw_dotfiles_create"
- [ $retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
+ [ $__retval -ne $DIALOG_ESC ] # return failure if user pressed ESC
}
-# f_dialog_input_shell [$shell]
-#
-# Allow the user to select a new login shell for a given user. If the user does
-# not cancel or press ESC, the $pw_home_dir variable will hold the newly-
-# configured value upon return.
+# f_dialog_input_shell $var_to_set [$shell]
#
+# Allow the user to select a new shell for a given login. 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_shell()
{
- local _input="$1"
- local prompt="$msg_select_login_shell"
- local radio_list= # Calculated below
- local hline="$hline_arrows_space_tab_enter"
+ local __funcname=f_dialog_input_shell
+ local __var_to_set="$1" __input="$2"
+ local __prompt="$msg_select_login_shell"
+ local __radio_list= # Calculated below
+ local __defaultitem="$2"
+ local __hline="$hline_arrows_space_tab_enter"
#
# Generate the radiolist of shells
#
- local shell
- for shell in $( awk '!/^[[:space:]]*(#|$)/{print}' "$ETC_SHELLS" ); do
- # Format of a radiolist menu entry is "tag item status"
- if [ "$shell" = "$_input" ]; then
- radio_list="$radio_list '$shell' '' 'on'"
+ local __shell_list __s __shell __length=0
+ f_eval_catch -k __shell_list $__funcname awk "awk '%s' \"%s\"" \
+ '!/^[[:space:]]*(#|$)/{print}' "$ETC_SHELLS" || return $FAILURE
+ while [ $__length -ne ${#__shell_list} ]; do
+ __s="${__shell_list%%$NL*}" # First line
+ f_shell_escape "$__s" __shell
+
+ # Format of a radiolist entry: tag item status
+ if [ "$__s" = "$__input" ]; then
+ __radio_list="$__radio_list '$__shell' '' 'on'"
else
- radio_list="$radio_list '$shell' '' 'off'"
+ __radio_list="$__radio_list '$__shell' '' 'off'"
fi
+
+ __length=${#__shell_list}
+ __shell_list="${__shell_list#*$NL}" # Kill line
done
- local height width rows
- eval f_dialog_radiolist_size height width rows \
+ local __height __width __rows
+ eval f_dialog_radiolist_size __height __width __rows \
\"\$DIALOG_TITLE\" \
\"\$DIALOG_BACKTITLE\" \
- \"\$prompt\" \
- \"\$hline\" \
- $radio_list
+ \"\$__prompt\" \
+ \"\$__hline\" \
+ $__radio_list
- _input=$( eval $DIALOG \
+ __input=$( eval $DIALOG \
--title \"\$DIALOG_TITLE\" \
--backtitle \"\$DIALOG_BACKTITLE\" \
- --hline \"\$hline\" \
+ --hline \"\$__hline\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
- --radiolist \"\$prompt\" \
- $height $width $rows \
- $radio_list \
+ --default-item \"\$__defaultitem\" \
+ --radiolist \"\$__prompt\" \
+ $__height $__width $__rows \
+ $__radio_list \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
) || return $?
# Return if user either pressed ESC or chose Cancel/No
- f_dialog_data_sanitize _input
+ f_dialog_data_sanitize __input
- pw_shell="$_input"
- save_flag=1
+ setvar "$__var_to_set" "$__input"
+ return $DIALOG_OK
+}
- f_dprintf "pw_shell: [%s]->[%s]" "$cur_pw_shell" "$pw_shell"
+# f_dialog_menu_user_add [$defaultitem]
+#
+# Present a menu detailing the properties of a login 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 user_account_expire, user_class,
+# user_dotfiles_create, user_gecos, user_gid, user_home_create, user_home_dir,
+# user_member_groups, user_name, user_password_expire, user_shell, and
+# user_uid. If $defaultitem is present and non-NULL, initially highlight the
+# item in the menu.
+#
+f_dialog_menu_user_add()
+{
+ local funcname=f_dialog_menu_user_add
+ local prompt="$msg_save_exit_or_cancel"
+ local menu_list # Calculated below
+ local defaultitem="$1"
+ local hline="$hline_arrows_tab_enter"
- return $DIALOG_OK
+ # Attempt to convert numeric UNIX time to calendar date/time
+ local user_account_expires_on=
+ if f_isinteger "$user_account_expire"; then
+ [ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
+ date -r "$user_account_expire" "+%F %T %Z"
+ )
+ else
+ user_account_expires_on="$user_account_expire"
+ fi
+ local user_password_expires_on=
+ if f_isinteger "$user_password_expire"; then
+ [ $user_password_expire -ne 0 ] && user_password_expires_on=$(
+ date -r "$user_password_expire" "+%F %T %Z"
+ )
+ else
+ user_password_expires_on="$user_password_expire"
+ fi
+
+ # Attempt to translate a numeric GID into `number (name)'
+ if f_isinteger "$user_gid"; then
+ local user_group
+ user_group=$( pw groupshow -g "$user_gid" 2> /dev/null ) &&
+ user_gid="$user_gid (${user_group%%:*})"
+ fi
+
+ # Localize potentially hostile variables and escape their values
+ # to the local variable (see f_shell_escape() of `strings.subr')
+ local var
+ for var in account_expires_on class dotfiles_create gecos gid \
+ home_create home_dir member_groups name password_expires_on \
+ shell uid \
+ ; do
+ local _user_$var
+ eval f_shell_escape \"\$user_$var\" _user_$var
+ done
+
+ menu_list="
+ 'X' '$msg_add/$msg_exit'
+ '1' '$msg_login: $_user_name'
+ '2' '$msg_full_name: $_user_gecos'
+ '3' '$msg_password: -----'
+ '4' '$msg_user_id: $_user_uid'
+ '5' '$msg_group_id: $_user_gid'
+ '6' '$msg_member_of_groups: $_user_member_groups'
+ '7' '$msg_login_class: $_user_class'
+ '8' '$msg_password_expires_on: $_user_password_expires_on'
+ '9' '$msg_account_expires_on: $_user_account_expires_on'
+ 'A' '$msg_home_directory: $_user_home_dir'
+ 'B' '$msg_shell: $_user_shell'
+ " # END-QUOTE
+ case "$user_home_dir" in
+ /|/nonexistent|/var/empty) menu_list="$menu_list
+ '-' '$msg_create_home_directory: $msg_n_a'
+ '-' '$msg_create_dotfiles: $msg_n_a'
+ " # END-QUOTE
+ ;;
+ *) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
+ '-' '$msg_create_home_directory: $msg_n_a'
+ 'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
+ " # END-QUOTE
+ else menu_list="$menu_list
+ 'C' '$msg_create_home_directory: ${_user_home_create:-$msg_no}'
+ 'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
+ " # END-QUOTE
+ fi
+ esac
+
+ 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\" \
+ --keep-tite \
+ --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_user_delete $user [$defaultitem]
+#
+# Present a menu detailing the properties of a login 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
+# $user argument with the exception of two environment variables:
+# user_group_delete and user_home_delete. If $defaultitem is present and non-
+# NULL, initially highlight the item in the menu.
+#
+f_dialog_menu_user_delete()
+{
+ local prompt="$msg_delete_exit_or_cancel"
+ local menu_list # Calculated below
+ local defaultitem="$2"
+ local hline="$hline_arrows_tab_enter"
+
+ local user_name user_password user_uid user_gid user_class
+ local user_password_expire user_account_expire user_gecos
+ local user_home_dir user_shell user_member_groups
+ f_input_user "$1"
+
+ # Attempt to convert numeric UNIX time to calendar date/time
+ local user_account_expires_on=
+ if f_isinteger "$user_account_expire"; then
+ [ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
+ date -r "$user_account_expire" "+%F %T %Z"
+ )
+ else
+ user_account_expires_on="$user_account_expire"
+ fi
+ local user_password_expires_on=
+ if f_isinteger "$user_password_expire"; then
+ [ $user_password_expire -ne 0 ] && user_password_expires_on=$(
+ date -r "$user_password_expire" "+%F %T %Z"
+ )
+ else
+ user_password_expires_on="$user_password_expire"
+ fi
+
+ # Attempt to translate a numeric GID into `number (name)'
+ if f_isinteger "$user_gid"; then
+ local user_group
+ user_group=$( pw groupshow -g "$user_gid" 2> /dev/null ) &&
+ user_gid="$user_gid (${user_group%%:*})"
+ fi
+
+ # Localize potentially hostile variables and escape their values
+ # to the local variable (see f_shell_escape() of `strings.subr')
+ local var
+ for var in account_expires_on class gecos gid group_delete \
+ home_delete home_dir member_groups name password_expires_on \
+ shell uid \
+ ; do
+ local _user_$var
+ eval f_shell_escape \"\$user_$var\" _user_$var
+ done
+
+ menu_list="
+ 'X' '$msg_delete/$msg_exit'
+ '1' '$msg_login: $_user_name'
+ '-' '$msg_full_name: $_user_gecos'
+ '-' '$msg_password: -----'
+ '-' '$msg_user_id: $_user_uid'
+ '-' '$msg_group_id: $_user_gid'
+ '-' '$msg_group_members: $_user_member_groups'
+ '-' '$msg_login_class: $_user_class'
+ '-' '$msg_password_expires_on: $_user_password_expires_on'
+ '-' '$msg_account_expires_on: $_user_account_expires_on'
+ '-' '$msg_home_directory: $_user_home_dir'
+ '-' '$msg_shell: $_user_shell'
+ " # END-QUOTE
+ if f_quietly pw groupshow -g "$user_gid"; then menu_list="$menu_list
+ 'C' '$msg_delete_primary_group: ${_user_group_delete:-$msg_no}'
+ " # END-QUOTE
+ else menu_list="$menu_list
+ '-' '$msg_delete_primary_group: $msg_n_a'
+ " # END-QUOTE
+ fi
+ case "$user_home_dir" in
+ /|/nonexistent|/var/empty) menu_list="$menu_list
+ '-' '$msg_delete_home_directory: $msg_n_a'
+ " # END-QUOTE
+ ;;
+ *) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
+ 'D' '$msg_delete_home_directory: ${_user_home_delete:-$msg_no}'
+ " # END-QUOTE
+ else menu_list="$menu_list
+ '-' '$msg_delete_home_directory: $msg_n_a'
+ " # END-QUOTE
+ fi
+ esac
+
+ 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\" \
+ --keep-tite \
+ --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_user_edit [$defaultitem]
+#
+# Present a menu detailing the properties of a login 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 user_account_expire, user_class,
+# user_dotfiles_create, user_gecos, user_gid, user_home_create, user_home_dir,
+# user_member_groups, user_name, user_password_expire, user_shell, and
+# user_uid. If $defaultitem is present and non-NULL, initially highlight the
+# item in the menu.
+#
+f_dialog_menu_user_edit()
+{
+ local prompt="$msg_save_exit_or_cancel"
+ local menu_list # Calculated below
+ local defaultitem="$1"
+ local hline="$hline_arrows_tab_enter"
+
+ # Attempt to convert numeric UNIX time to calendar date/time
+ local user_account_expires_on=
+ if f_isinteger "$user_account_expire"; then
+ [ "$user_account_expire" -ne 0 ] && user_account_expires_on=$(
+ date -r "$user_account_expire" "+%F %T %Z"
+ )
+ else
+ user_account_expires_on="$user_account_expire"
+ fi
+ local user_password_expires_on=
+ if f_isinteger "$user_password_expire"; then
+ [ $user_password_expire -ne 0 ] && user_password_expires_on=$(
+ date -r "$user_password_expire" "+%F %T %Z"
+ )
+ else
+ user_password_expires_on="$user_password_expire"
+ fi
+
+ # Attempt to translate a numeric GID into `number (name)'
+ if f_isinteger "$user_gid"; then
+ local user_group
+ user_group=$( pw groupshow -g "$user_gid" 2> /dev/null ) &&
+ user_gid="$user_gid (${user_group%%:*})"
+ fi
+
+ # Localize potentially hostile variables and escape their values
+ # to the local variable (see f_shell_escape() of `strings.subr')
+ local var
+ for var in account_expires_on class dotfiles_create gecos gid \
+ home_create home_dir member_groups name password_expires_on \
+ shell uid \
+ ; do
+ local _user_$var
+ eval f_shell_escape \"\$user_$var\" _user_$var
+ done
+
+ menu_list="
+ 'X' '$msg_save/$msg_exit'
+ '1' '$msg_login: $_user_name'
+ '2' '$msg_full_name: $_user_gecos'
+ '3' '$msg_password: -----'
+ '4' '$msg_user_id: $_user_uid'
+ '5' '$msg_group_id: $_user_gid'
+ '6' '$msg_member_of_groups: $_user_member_groups'
+ '7' '$msg_login_class: $_user_class'
+ '8' '$msg_password_expires_on: $_user_password_expires_on'
+ '9' '$msg_account_expires_on: $_user_account_expires_on'
+ 'A' '$msg_home_directory: $_user_home_dir'
+ 'B' '$msg_shell: $_user_shell'
+ " # END-QUOTE
+ case "$user_home_dir" in
+ /|/nonexistent|/var/empty) menu_list="$menu_list
+ '-' '$msg_create_home_directory: $msg_n_a'
+ '-' '$msg_create_dotfiles: $msg_n_a'
+ " # END-QUOTE
+ ;;
+ *) if [ -d "$user_home_dir" ]; then menu_list="$menu_list
+ '-' '$msg_create_home_directory: $msg_n_a'
+ 'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
+ " # END-QUOTE
+ else menu_list="$menu_list
+ 'C' '$msg_create_home_directory: ${_user_home_create:-$msg_no}'
+ 'D' '$msg_create_dotfiles: ${_user_dotfiles_create:-$msg_no}'
+ " # END-QUOTE
+ fi
+ esac
+
+ 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\" \
+ --keep-tite \
+ --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
diff --git a/usr.sbin/bsdconfig/usermgmt/useradd b/usr.sbin/bsdconfig/usermgmt/useradd
index 2d6b4d0..d372be4 100755
--- a/usr.sbin/bsdconfig/usermgmt/useradd
+++ b/usr.sbin/bsdconfig/usermgmt/useradd
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,11 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
. $BSDCFG_SHARE/common.subr || exit 1
f_dprintf "%s: loading includes..." "$0"
f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/mustberoot.subr
+f_include $BSDCFG_SHARE/usermgmt/user.subr
BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
f_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" ipgm &&
pgm="${ipgm:-$pgm}"
@@ -55,9 +58,19 @@ done
shift $(( $OPTIND - 1 ))
#
-# Chain-load to userinput to centralize code and minimize duplication
+# Initialize
#
-$BSDCFG_LIBE/$APP_DIR/userinput ${USE_XDIALOG:+-X} mode="Add"
+f_dialog_title "$msg_add $msg_user"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Add a user
+#
+# NB: If given an argument on the command-line use it; otherwise fall-back to
+# environment variable $user (handle $VAR_USER).
+#
+f_user_add ${1:+"$1"}
################################################################################
# END
diff --git a/usr.sbin/bsdconfig/usermgmt/userdel b/usr.sbin/bsdconfig/usermgmt/userdel
index 33aa062..9425c7b 100755
--- a/usr.sbin/bsdconfig/usermgmt/userdel
+++ b/usr.sbin/bsdconfig/usermgmt/userdel
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
f_dprintf "%s: loading includes..." "$0"
f_include $BSDCFG_SHARE/dialog.subr
f_include $BSDCFG_SHARE/mustberoot.subr
+f_include $BSDCFG_SHARE/usermgmt/user.subr
f_include $BSDCFG_SHARE/usermgmt/user_input.subr
BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
@@ -65,9 +66,17 @@ f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
f_mustberoot_init
#
+# If given a user name, operate on it and exit
+#
+if [ "$1" ]; then
+ f_user_delete "$1"
+ exit $SUCCESS
+fi
+
+#
# Loop until the user Exits, Cancels or presses ESC
#
-defaultitem=""
+defaultitem=
while :; do
f_dialog_menu_user_list "$defaultitem"
retval=$?
@@ -81,8 +90,7 @@ while :; do
# Anything else is a userid
- $BSDCFG_LIBE/$APP_DIR/userinput \
- ${USE_XDIALOG:+-X} mode="Delete" user="$mtag"
+ f_user_delete "$mtag"
done
exit $SUCCESS
diff --git a/usr.sbin/bsdconfig/usermgmt/useredit b/usr.sbin/bsdconfig/usermgmt/useredit
index 30ee578..612f3a6 100755
--- a/usr.sbin/bsdconfig/usermgmt/useredit
+++ b/usr.sbin/bsdconfig/usermgmt/useredit
@@ -1,7 +1,7 @@
#!/bin/sh
#-
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
f_dprintf "%s: loading includes..." "$0"
f_include $BSDCFG_SHARE/dialog.subr
f_include $BSDCFG_SHARE/mustberoot.subr
+f_include $BSDCFG_SHARE/usermgmt/user.subr
f_include $BSDCFG_SHARE/usermgmt/user_input.subr
BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
@@ -65,9 +66,17 @@ f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
f_mustberoot_init
#
-# Loop until the user Exits, Cancels or presses ESC
+# If given a user name, operate on it and exit
#
-defaultitem=""
+if [ "$1" ]; then
+ f_user_edit "$1"
+ exit $SUCCESS
+fi
+
+#
+# Present a list of users and loop until user Exits, Cancels or presses ESC
+#
+defaultitem=
while :; do
f_dialog_menu_user_list "$defaultitem"
retval=$?
@@ -81,8 +90,7 @@ while :; do
# Anything else is a userid
- $BSDCFG_LIBE/$APP_DIR/userinput \
- ${USE_XDIALOG:+-X} mode="Edit/View" user="$mtag"
+ f_user_edit "$mtag"
done
exit $SUCCESS
diff --git a/usr.sbin/bsdconfig/usermgmt/userinput b/usr.sbin/bsdconfig/usermgmt/userinput
deleted file mode 100755
index 5cf5554..0000000
--- a/usr.sbin/bsdconfig/usermgmt/userinput
+++ /dev/null
@@ -1,508 +0,0 @@
-#!/bin/sh
-#-
-# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 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.
-#
-# $FreeBSD$
-#
-############################################################ INCLUDES
-
-BSDCFG_SHARE="/usr/share/bsdconfig"
-. $BSDCFG_SHARE/common.subr || exit 1
-f_dprintf "%s: loading includes..." "$0"
-f_include $BSDCFG_SHARE/dialog.subr
-f_include $BSDCFG_SHARE/mustberoot.subr
-f_include $BSDCFG_SHARE/usermgmt/user_input.subr
-
-BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
-f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
-
-f_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" ipgm &&
- pgm="${ipgm:-$pgm}"
-
-############################################################ CONFIGURATION
-
-# set some reasonable defaults if /etc/adduser.conf does not exist.
-[ -f /etc/adduser.conf ] && f_include /etc/adduser.conf
-: ${passwdtype:="yes"}
-: ${homeprefix:="/home"}
-: ${defaultshell:="/bin/sh"}
-: ${udotdir:="/usr/share/skel"}
-
-############################################################ FUNCTIONS
-
-# copy_dotfiles
-#
-# Copy `skel' dot-files to a new home directory.
-#
-copy_dotfiles()
-{
- ( # Operate within sub-shell to protect CWD/glob of parent
- cd "$udotdir" || exit $?
- set +f # glob
- for file in dot.*; do
- cp -n "$file" "$pw_home_dir/${file#dot}" || exit $?
- done
- )
-}
-
-# save_changes
-#
-# Save any/all settings (actions performed depend on $mode value).
-#
-save_changes()
-{
- local funcname=save_changes
-
- case "$mode" in
- Delete)
- f_eval_catch $funcname pw 'pw userdel -u "%s"' "$pw_uid" ||
- return $?
- f_show_msg "$msg_login_deleted"
-
- if [ "$pw_group_delete" = "$msg_yes" ] &&
- f_quietly pw groupshow -g "$pw_gid"
- then
- f_eval_catch $funcname pw \
- 'pw groupdel -g "%s"' "$pw_gid"
- fi
-
- if [ "$pw_home_delete" = "$msg_yes" ]; then
- f_dialog_info "$msg_deleting_home_directory"
- f_eval_catch $funcname rm 'rm -Rf "%s"' "$pw_home_dir"
- fi
- ;;
- Add)
- local cmd="pw useradd -n '$pw_name'"
- [ "$pw_member_groups" ] && cmd="$cmd -G '$pw_member_groups'"
- [ "$pw_class" ] && cmd="$cmd -L '$pw_class'"
- [ "$pw_gecos" ] && cmd="$cmd -c '$pw_gecos'"
- [ "$pw_home_dir" ] && cmd="$cmd -d '$pw_home_dir'"
- [ "$pw_account_expire" ] && cmd="$cmd -e '$pw_account_expire'"
- [ "$pw_gid" ] && cmd="$cmd -g '$pw_gid'"
- [ "$pw_password_expire" ] && cmd="$cmd -p '$pw_password_expire'"
- [ "$pw_shell" ] && cmd="$cmd -s '$pw_shell'"
- [ "$pw_uid" ] && cmd="$cmd -u '$pw_uid'"
- if [ "$pw_password_disable" ]; then
- f_eval_catch $funcname pw '%s -h -' "$cmd"
- elif [ "$pw_password" ]; then
- echo "$pw_password" |
- f_eval_catch $funcname pw '%s -h 0' "$cmd"
- else
- f_eval_catch $funcname pw '%s' "$cmd"
- fi || return $?
- f_show_msg "$msg_login_added"
-
- if [ "$pw_home_create" = "$msg_yes" ]; then
- if f_eval_catch $funcname mkdir \
- 'mkdir -p "%s"' "$pw_home_dir"
- then
- f_eval_catch $funcname chown \
- 'chown -R "%s" "%s"' \
- "$pw_uid:$pw_gid" "$pw_home_dir"
- fi
- fi
-
- [ "$pw_dotfiles_create" = "$msg_yes" ] &&
- f_eval_catch $funcname copy_dotfiles copy_dotfiles
-
- user="$pw_name"
- f_quietly pw usershow -n "$pw_name" &&
- mode="Edit/View" # Change mode
- ;;
- Edit/View)
- local cmd="pw usermod -n '$pw_name'"
- [ "$pw_member_groups" ] && cmd="$cmd -G '$pw_member_groups'"
- [ "$pw_class" ] && cmd="$cmd -L '$pw_class'"
- [ "$pw_gecos" ] && cmd="$cmd -c '$pw_gecos'"
- [ "$pw_home_dir" ] && cmd="$cmd -d '$pw_home_dir'"
- [ "$pw_account_expire" ] && cmd="$cmd -e '$pw_account_expire'"
- [ "$pw_gid" ] && cmd="$cmd -g '$pw_gid'"
- [ "$pw_password_expire" ] && cmd="$cmd -p '$pw_password_expire'"
- [ "$pw_shell" ] && cmd="$cmd -s '$pw_shell'"
- [ "$pw_uid" ] && cmd="$cmd -u '$pw_uid'"
- if [ "$pw_password_disable" ]; then
- f_eval_catch $funcname pw '%s -h -' "$cmd"
- elif [ "$pw_password" ]; then
- echo "$pw_password" |
- f_eval_catch $funcname pw '%s -h 0' "$cmd"
- else
- f_eval_catch $funcname pw '%s' "$cmd"
- fi || return $?
- f_show_msg "$msg_login_updated"
-
- if [ "$pw_home_create" = "$msg_yes" ]; then
- if f_eval_catch $funcname mkdir \
- 'mkdir -p "%s"' "$pw_home_dir"
- then
- f_eval_catch $funcname chown \
- 'chown -R "%i:%i" "%s"' \
- "$pw_uid" "$pw_gid" "$pw_home_dir"
- fi
- fi
-
- [ "$pw_dotfiles_create" = "$msg_yes" ] &&
- f_eval_catch $funcname copy_dotfiles copy_dotfiles
- ;;
- esac
-
- save_flag=
- return $SUCCESS
-}
-
-# dialog_title_update $mode
-#
-# Set the title based on the given $mode.
-#
-dialog_title_update()
-{
- local mode="$1"
- case "$mode" in
- Add) f_dialog_title "$msg_add $msg_user" ;;
- Edit/View) f_dialog_title "$msg_edit_view $msg_user: $user" ;;
- Delete) f_dialog_title "$msg_delete $msg_user: $user" ;;
- esac
-}
-
-############################################################ MAIN
-
-# Incorporate rc-file if it exists
-[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
-
-#
-# Process command-line arguments
-#
-while [ $# -gt 0 ]; do
- key="${1%%=*}"
- value="${1#*=}"
- f_dprintf "key=[%s] value=[%s]" "$key" "$value"
- case "$key" in
- mode) mode="$value" ;;
- user) user="$value" ;;
- esac
- shift
-done
-f_dprintf "mode=[%s] user=[%s]" "$mode" "$user"
-
-#
-# Initialize
-#
-dialog_title_update "$mode"
-f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
-f_mustberoot_init
-menu_text=
-save_flag=
-hline="$hline_arrows_tab_enter"
-
-if [ "$mode" = "Add" ]; then
- f_dialog_input_name || exit 0
-
- #
- # Set some sensible defaults for account attributes
- #
- pw_gecos="${pw_gecos-$pw_name}"
- pw_home_dir="${pw_home_dir:-$homeprefix/$pw_name}"
- if [ -d "$pw_home_dir" ]; then
- pw_home_create="${pw_home_create:-$msg_no}"
- pw_dotfiles_create="${pw_dotfiles_create:-$msg_no}"
- else
- pw_home_create="${pw_home_create:-$msg_yes}"
- pw_dotfiles_create="${pw_dotfiles_create:-$msg_yes}"
- fi
- pw_shell="${pw_shell:-$defaultshell}"
-
- f_dialog_noyes "$msg_use_default_values_for_all_account_details"
- retval=$?
-
- if [ $retval -eq $DIALOG_ESC ]; then
- exit $SUCCESS
- elif [ $retval -ne $DIALOG_OK ]; then
- #
- # Ask a series of questions to pre-fill the editor screen.
- #
- # The defaults used in each dialog should allow the user to
- # simply hit ENTER to proceed, because cancelling a single
- # dialog will cause them to be returned to the main usermenu.
- #
-
- f_dialog_input_gecos "$pw_gecos" || exit 0
- [ "$passwdtype" = "yes" ] &&
- { f_dialog_input_password || exit 0; }
- f_dialog_input_uid || exit 0
- f_dialog_input_gid || exit 0
- f_dialog_input_member_groups || exit 0
- f_dialog_input_class || exit 0
- f_dialog_input_expire_password || exit 0
- f_dialog_input_expire_account || exit 0
- f_dialog_input_home_dir "$pw_home_dir" || exit 0
- if [ ! -d "$pw_home_dir" ]; then
- f_dialog_input_home_create || exit 0
- [ "$pw_home_create" = "$msg_yes" ] &&
- { f_dialog_input_dotfiles_create || exit 0; }
- fi
- f_dialog_input_shell "$pw_shell" || exit 0
- fi
-fi
-
-if [ "$mode" = "Edit/View" -o "$mode" = "Delete" ]; then
- f_input_user "$user" || f_die 1 "$msg_login_not_found"
-fi
-
-if [ "$mode" = "Edit/View" ]; then
- [ -d "$pw_home_dir" ] || pw_home_create="$msg_no"
- pw_dotfiles_create="$msg_no"
-fi
-
-if [ "$mode" = "Delete" ]; then
- f_dialog_input_group_delete || exit 0
- pw_home_delete="$msg_no"
- [ -d "$pw_home_dir" ] &&
- { f_dialog_input_home_delete || exit 0; }
-fi
-
-cur_pw_name="$pw_name"
-cur_pw_password="$pw_password"
-cur_pw_uid="$pw_uid"
-cur_pw_gid="$pw_gid"
-cur_pw_member_groups="$pw_member_groups"
-cur_pw_class="$pw_class"
-cur_pw_password_expire="$pw_password_expire"
-cur_pw_account_expire="$pw_account_expire"
-cur_pw_gecos="$pw_gecos"
-cur_pw_home_dir="$pw_home_dir"
-cur_pw_shell="$pw_shell"
-cur_pw_group_delete="$pw_group_delete"
-cur_pw_home_create="$pw_home_create"
-cur_pw_home_delete="$pw_home_delete"
-cur_pw_dotfiles_create="$pw_dotfiles_create"
-
-[ "$mode" = "Delete" ] && save_flag=1
-
-#
-# Loop until the user decides to Exit, Cancel, or presses ESC
-#
-while :; do
- dialog_title_update "$mode"
-
- menu_text=
- menu_exit="$msg_exit"
- if [ "$save_flag" ]; then
- if [ "$mode" = "Delete" ]; then
- menu_exit="$msg_delete/$msg_exit"
- menu_text="$msg_delete_exit_or_cancel"
- else
- menu_exit="$msg_save/$msg_exit"
- menu_text="$msg_save_exit_or_cancel"
- fi
- fi
-
- pw_password_expires_on="$pw_password_expire"
- f_isinteger "$pw_password_expire" && [ $pw_password_expire -ne 0 ] &&
- pw_password_expires_on=$(
- date -r "$pw_password_expire" "+%F %T %Z"
- )
- pw_account_expires_on="$pw_account_expire"
- f_isinteger "$pw_account_expire" && [ "$pw_account_expire" -ne 0 ] &&
- pw_account_expires_on=$(
- date -r "$pw_account_expire" "+%F %T %Z"
- )
-
- case "$mode" in
- Delete)
- menu_items="
- 'X' '$menu_exit'
- '1' '$msg_login: $pw_name'
- '-' '$msg_full_name: $pw_gecos'
- '-' '$msg_password: -----'
- '-' '$msg_user_id: $pw_uid'
- '-' '$msg_group_id: $pw_gid'
- '-' '$msg_member_of_groups: $pw_member_groups'
- '-' '$msg_login_class: $pw_class'
- '-' '$msg_password_expires_on: $pw_password_expires_on'
- '-' '$msg_account_expires_on: $pw_account_expires_on'
- '-' '$msg_home_directory: $pw_home_dir'
- '-' '$msg_shell: $pw_shell'
- " # END-QUOTE
- ;;
- *)
- menu_items="
- 'X' '$menu_exit'
- '1' '$msg_login: $pw_name'
- '2' '$msg_full_name: $pw_gecos'
- '3' '$msg_password: -----'
- '4' '$msg_user_id: $pw_uid'
- '5' '$msg_group_id: $pw_gid'
- '6' '$msg_member_of_groups: $pw_member_groups'
- '7' '$msg_login_class: $pw_class'
- '8' '$msg_password_expires_on: $pw_password_expires_on'
- '9' '$msg_account_expires_on: $pw_account_expires_on'
- 'A' '$msg_home_directory: $pw_home_dir'
- 'B' '$msg_shell: $pw_shell'
- " # END-QUOTE
- esac
-
- case "$mode" in
- Add|Edit/View)
- if [ -d "$pw_home_dir" ]; then menu_items="$menu_items
- '-' '$msg_create_home_directory: $msg_n_a'
- 'D' '$msg_create_dotfiles: $pw_dotfiles_create'
- "; else menu_items="$menu_items
- 'C' '$msg_create_home_directory: $pw_home_create'
- 'D' '$msg_create_dotfiles: $pw_dotfiles_create'
- "; fi
- ;;
- Delete)
- if [ -d "$pw_home_dir" ]; then menu_items="$menu_items
- 'C' '$msg_delete_primary_group: $pw_group_delete'
- 'D' '$msg_delete_home_directory: $pw_home_delete'
- "; else menu_items="$menu_items
- 'C' '$msg_delete_primary_group: $pw_group_delete'
- '-' '$msg_delete_home_directory: $msg_n_a'
- "; fi
- ;;
- esac
-
- eval f_dialog_menu_size height width rows \
- \"\$DIALOG_TITLE\" \
- \"\$DIALOG_BACKTITLE\" \
- \"\$menu_text\" \
- \"\$hline\" \
- $menu_items
-
- f_dialog_default_fetch defaultitem
- mtag=$( eval $DIALOG \
- --title \"\$DIALOG_TITLE\" \
- --backtitle \"\$DIALOG_BACKTITLE\" \
- --hline \"\$hline\" \
- --ok-label \"\$msg_ok\" \
- --cancel-label \"\$msg_cancel\" \
- --default-item \"\$defaultitem\" \
- --menu \"\$menu_text\" \
- $height $width $rows \
- $menu_items \
- 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
- )
- retval=$?
- f_dialog_data_sanitize mtag
- f_dialog_default_store "$mtag"
- f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
-
- # Exit if user has either pressed ESC or chosen Cancel/No
- [ $retval -eq $DIALOG_OK ] || f_die
-
- case "$mtag" in
- X) # Exit
- if [ "$save_flag" ]; then
- save_changes || continue
- fi
- break
- ;;
- 1) # Login
- case "$mode" in
- Add) f_dialog_input_name "$pw_name" ;;
- Edit/View|Delete)
- f_dialog_menu_user_list "$pw_name"
- retval=$?
- f_dialog_menutag_fetch mtag
- f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
-
- # Loop if user has either pressed ESC or chosen Cancel/No
- [ $retval -eq $DIALOG_OK ] || continue
-
- [ "$mtag" = "X $msg_exit" ] && continue
-
- user="$mtag"
- f_input_user "$user" || f_die 1 "$msg_login_not_found"
- cur_pw_name="$pw_name"
- cur_pw_password="$pw_password"
- cur_pw_uid="$pw_uid"
- cur_pw_gid="$pw_gid"
- cur_pw_member_groups="$pw_member_groups"
- cur_pw_class="$pw_class"
- cur_pw_password_expire="$pw_password_expire"
- cur_pw_account_expire="$pw_account_expire"
- cur_pw_gecos="$pw_gecos"
- cur_pw_home_dir="$pw_home_dir"
- cur_pw_shell="$pw_shell"
- cur_pw_group_delete="$pw_group_delete"
- cur_pw_home_create="$pw_home_create"
- cur_pw_home_delete="$pw_home_delete"
- cur_pw_dotfiles_create="$pw_dotfiles_create"
- [ "$mode" != "Delete" ] && save_flag=
- esac
- ;;
- 2) # Full Name
- f_dialog_input_gecos "$pw_gecos" ;;
- 3) # Password
- f_dialog_input_password ;;
- 4) # UID
- f_dialog_input_uid "$pw_uid" ;;
- 5) # Default Group
- f_dialog_input_gid "$pw_gid" ;;
- 6) # Member of Groups
- f_dialog_input_member_groups "$pw_member_groups" ;;
- 7) # Login Class
- f_dialog_input_class "$pw_class" ;;
- 8) # Password Expire on
- f_dialog_input_expire_password "$pw_password_expire" ;;
- 9) # Account Expire on
- f_dialog_input_expire_account "$pw_account_expire" ;;
- A) # Home Directory
- f_dialog_input_home_dir "$pw_home_dir" ;;
- B) # Shell
- f_dialog_input_shell "$pw_shell" ;;
- esac
-
- case "$mode" in
- Delete)
- case "$mtag" in
- C) # Delete Primary Group
- f_dialog_input_group_delete ;;
- D) # Delete Home Directory
- f_dialog_input_home_delete ;;
- esac
- ;;
- Add|Edit/View)
- case "$mtag" in
- C) # Create Home Directory
- f_dialog_input_home_create
- [ "$pw_home_create" = "$msg_no" ] &&
- pw_dotfiles_create="$msg_no"
- ;;
- D) # Create Dotfiles
- f_dialog_input_dotfiles_create
- [ "$pw_dotfiles_create" = "$msg_yes" ] &&
- pw_home_create="$msg_yes"
- ;;
- esac
- ;;
- esac
-done
-
-exit $SUCCESS
-
-################################################################################
-# END
-################################################################################
OpenPOWER on IntegriCloud