summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsdconfig/usermgmt
diff options
context:
space:
mode:
authordteske <dteske@FreeBSD.org>2012-07-14 03:16:57 +0000
committerdteske <dteske@FreeBSD.org>2012-07-14 03:16:57 +0000
commit3981b9b76aa0266598ee7b724e5981627d8ac129 (patch)
tree8b439d31cf63b5d5c97b653a3cd721fd9961baa5 /usr.sbin/bsdconfig/usermgmt
parent5d2a55de5070f6d3a8e4b9762a397596e7b308ae (diff)
downloadFreeBSD-src-3981b9b76aa0266598ee7b724e5981627d8ac129.zip
FreeBSD-src-3981b9b76aa0266598ee7b724e5981627d8ac129.tar.gz
Import bsdconfig(8) as a replacement for the post-install abilities of
deprecated sysinstall(8). NOTE: WITH_BSDCONFIG is currently required. Submitted by: Devin Teske (dteske), Ron McDowell <rcm@fuzzwad.org> Reviewed by: Ron McDowell <rcm@fuzzwad.org> Approved by: Ed Maste (emaste)
Diffstat (limited to 'usr.sbin/bsdconfig/usermgmt')
-rw-r--r--usr.sbin/bsdconfig/usermgmt/INDEX60
-rw-r--r--usr.sbin/bsdconfig/usermgmt/Makefile17
-rw-r--r--usr.sbin/bsdconfig/usermgmt/USAGE33
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupadd64
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupdel93
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupedit93
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/groupinput295
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/Makefile11
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/group_input.subr437
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/messages.subr111
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/user_input.subr1180
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/useradd64
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/userdel93
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/useredit93
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/userinput515
-rwxr-xr-xusr.sbin/bsdconfig/usermgmt/usermgmt150
16 files changed, 3309 insertions, 0 deletions
diff --git a/usr.sbin/bsdconfig/usermgmt/INDEX b/usr.sbin/bsdconfig/usermgmt/INDEX
new file mode 100644
index 0000000..81e43aa
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/INDEX
@@ -0,0 +1,60 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+#
+# Title that will be shown on the bsdconfig menu
+menu_title="Login/Group Management"
+#
+# a short descriptive line shown at the bottom of the bsdconfig menu.
+# keep it short because any line longer than the terminal width will
+# be truncated.
+menu_help="Manage system user and/or group information"
+#
+# two-part variable that defines an action to take when 'keyword'
+# is passed on a bsdconfig command line. variable takes the form
+# "keyword|command" and multiple occurrences of the variable
+# (with different 'keyword's, or different 'keyword's AND 'command's)
+# are allowed. If 'command' begins with a '/' then the full
+# path to the program is needed. If 'command' begins with anything
+# else it is a path relative to the directory this INDEX file is in.
+# 'keyword' can be i18n'ed but 'command' is the name of a script.
+menu_selection="usermgmt|usermgmt"
+menu_selection="useradd|useradd"
+menu_selection="useredit|useredit"
+menu_selection="userdel|userdel"
+menu_selection="groupmgmt|usermgmt"
+menu_selection="groupadd|groupadd"
+menu_selection="groupedit|groupedit"
+menu_selection="groupdel|groupdel"
+#
+# Items below this line do NOT need i18n translation----------------------
+#
+# Name of the program to be run when this menu choice is selected.
+# if it begins with a '/' then the full path to the program is needed.
+# if it begins with anything else it is a path relative to the directory
+# this INDEX file is in.
+menu_program="usermgmt"
diff --git a/usr.sbin/bsdconfig/usermgmt/Makefile b/usr.sbin/bsdconfig/usermgmt/Makefile
new file mode 100644
index 0000000..7c1b3e5
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+SUBDIR= include
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/070.usermgmt
+FILES= INDEX USAGE
+
+SCRIPTSDIR= ${FILESDIR}
+SCRIPTS= groupadd groupdel groupedit groupinput \
+ useradd userdel useredit userinput usermgmt
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/usermgmt/USAGE b/usr.sbin/bsdconfig/usermgmt/USAGE
new file mode 100644
index 0000000..9aa4dca
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/USAGE
@@ -0,0 +1,33 @@
+# Copyright (c) 2012 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 (INLUDING, 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$
+
+Usage: bsdconfig @PROGRAM_NAME@ [OPTIONS]
+
+OPTIONS:
+ -h Print usage statement and exit.
+ -S Secure X11 mode (implies `-X'). As root, always prompt-for
+ and validate sudo(8) username/password before starting.
+ -X Use Xdialog(1) in place of dialog(1).
diff --git a/usr.sbin/bsdconfig/usermgmt/groupadd b/usr.sbin/bsdconfig/usermgmt/groupadd
new file mode 100755
index 0000000..c4f4fde
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/groupadd
@@ -0,0 +1,64 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+
+APP_DIR="070.usermgmt"
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Chain-load to groupinput to centralize code and minimize duplication
+#
+f_dialog_init
+$BSDCFG_LIBE/$APP_DIR/groupinput ${USE_XDIALOG:+-X} mode="Add"
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/groupdel b/usr.sbin/bsdconfig/usermgmt/groupdel
new file mode 100755
index 0000000..aa5a71d
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/groupdel
@@ -0,0 +1,93 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/group_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_delete $msg_group"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Loop until the user Exits, Cancels or presses ESC
+#
+while :; do
+ f_dialog_menu_group_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+
+ *) # anything else is a group name
+ $BSDCFG_LIBE/$APP_DIR/groupinput \
+ ${USE_XDIALOG:+-X} mode="Delete" group="$mtag"
+ ;;
+
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/groupedit b/usr.sbin/bsdconfig/usermgmt/groupedit
new file mode 100755
index 0000000..beb11af
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/groupedit
@@ -0,0 +1,93 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/group_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_edit_view $msg_group"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Loop until the user Exits, Cancels or presses ESC
+#
+while :; do
+ f_dialog_menu_group_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+
+ *) # anything else is a group name
+ $BSDCFG_LIBE/$APP_DIR/groupinput \
+ ${USE_XDIALOG:+-X} mode="Edit/View" group="$mtag"
+ ;;
+
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/groupinput b/usr.sbin/bsdconfig/usermgmt/groupinput
new file mode 100755
index 0000000..96186be
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/groupinput
@@ -0,0 +1,295 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/group_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ 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 err retval=$SUCCESS
+
+ case "$mode" in
+ Delete)
+ err=$( pw groupdel "$group_name" 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ 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
+ cmd="$cmd -h -"
+ elif [ "$group_password" ]; then
+ cmd="echo \"\$group_password\" | $cmd -h 0"
+ fi
+ f_dprintf "cmd=$cmd"
+ err=$( eval $cmd 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ 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
+ cmd="$cmd -h -"
+ elif [ "$group_password" ]; then
+ cmd="echo \"\$group_password\" | $cmd -h 0"
+ fi
+ f_dprintf "cmd=$cmd"
+ err=$( eval $cmd 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ 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=[$key] value=[$value]"
+ case "$key" in
+ mode) mode="$value";;
+ group) group="$value";;
+ esac
+ shift
+done
+f_dprintf "mode=[$mode] group=[$group]"
+
+#
+# Initialize
+#
+f_dialog_init
+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
+ #
+ # 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.
+ #
+
+ f_dialog_input_group_name || exit 0
+ [ "$passwdtype" = "yes" ] &&
+ { f_dialog_input_group_password || exit 0; }
+ f_dialog_input_group_gid || exit 0
+ f_dialog_input_group_members || exit 0
+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
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$menu_text\" \
+ \"\$hline\" \
+ $menu_items )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$menu_text\" $size \
+ $menu_items \
+ 2> $DIALOG_TMPDIR/dialog.menu.$$
+
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ # Exit if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || f_die
+
+ case "$mtag" in
+ X) # Exit
+ if [ "$save_flag" ]; then
+ save_changes || continue
+ fi
+ break
+ ;;
+ 1) # Group Name
+ case "$mode" in
+ Add) f_dialog_input_group_name "$group_name" ;;
+ Edit/View|Delete)
+ f_dialog_menu_group_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ # Loop if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || 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/Makefile b/usr.sbin/bsdconfig/usermgmt/include/Makefile
new file mode 100644
index 0000000..15f88aa
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/include/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${LIBEXECDIR}/bsdconfig/070.usermgmt/include
+FILES= group_input.subr messages.subr user_input.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/usermgmt/include/group_input.subr b/usr.sbin/bsdconfig/usermgmt/include/group_input.subr
new file mode 100644
index 0000000..b4121b1
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/include/group_input.subr
@@ -0,0 +1,437 @@
+if [ ! "$_USERMGMT_GROUP_INPUT_SUBR" ]; then _USERMGMT_GROUP_INPUT_SUBR=1
+#
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/strings.subr
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+APP_DIR="070.usermgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_input_group $group
+#
+# Given $group name or id, create the environment variables group_name,
+# group_gid, and group_members (and group_password is reset to NULL).
+#
+f_input_group()
+{
+ eval $( pw groupshow "$1" | awk -F: '
+ {
+ printf "group_name='\'%s\''\n", $1
+ printf "group_password=\n"
+ printf "group_gid='\'%s\''\n", $3
+ printf "group_members='\'%s\''\n", $4
+ exit
+ }' )
+}
+
+# f_dialog_menu_group_list
+#
+# Allows the user to select a group from a list.
+#
+f_dialog_menu_group_list()
+{
+ local menu_list size
+ local hline="$hline_alnum_punc_tab_enter"
+
+ menu_list="
+ 'X $msg_exit' ''
+ " # END-QUOTE
+
+ # Add groups from group(5)
+ menu_list="$menu_list $( pw groupshow -a | awk -F: '
+ !/^[[:space:]]*(#|$)/ {
+ printf "'\'%s\'\ \'%s\''\n", $1, $1
+ }'
+ )"
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\" $size $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+# f_dialog_input_group_name [$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).
+#
+f_dialog_input_group_name()
+{
+ local msg="$( printf "$msg_group" )"
+ local hline="$hline_alnum_tab_enter"
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local size retval _name="$1" _input="$1"
+ while :; do
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Check for no-change
+ [ "$_input" = "$_name" ] && return $SUCCESS
+
+ # Check for reversion
+ if [ "$_input" = "$cur_group_name" ]; then
+ group_name="$cur_group_name"
+ return $SUCCESS
+ fi
+
+ # Check for NULL entry
+ if [ ! "$_input" ]; then
+ f_show_msg "$msg_group_is_empty"
+ continue
+ fi
+
+ # Check for invalid entry
+ if ! echo "$_input" | grep -q "^[[:alpha:]]"; then
+ f_show_msg "$msg_group_must_start_with_letter"
+ continue
+ fi
+
+ # Check for duplicate entry
+ if f_quietly pw groupshow -n "$_input"; then
+ f_show_msg "$msg_group_already_used" "$_input"
+ continue
+ fi
+
+ group_name="$_input"
+ break
+ done
+ save_flag=1
+
+ f_dprintf "group_name: [$cur_group_name]->[$group_name]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_group_password
+#
+# Prompt the user to enter a password (twice).
+#
+f_dialog_input_group_password()
+{
+ local hline="$hline_alnum_punc_tab_enter"
+ local msg size rmsg rsize
+
+ msg=$( printf "$msg_group_password" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "" \
+ "$hline" )
+
+ rmsg=$( printf "$msg_reenter_group_password" )
+ rsize=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$rmsg" \
+ "" \
+ "$hline" )
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local retval _password1 _password2
+ while :; do
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --insecure \
+ --passwordbox \"\$msg\" $size \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _password1=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --insecure \
+ --passwordbox \"\$rmsg\" $rsize \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _password2=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Check for password mismatch
+ if [ "$_password1" != "$_password2" ]; then
+ f_show_msg "$msg_group_passwords_do_not_match"
+ continue
+ fi
+
+ # Check for NULL entry
+ if [ ! "$_password1" ]; then
+ f_dialog_yesno \
+ "$msg_disable_password_auth_for_group" ||
+ continue
+ pw_group_password_disable=1
+ else
+ pw_group_password_disable=
+ fi
+
+ group_password="$_password1"
+ break
+ done
+ save_flag=1
+
+ f_dprintf "group_password: [$cur_group_password]->[$group_password]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_group_gid [$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
+# value upon return.
+#
+f_dialog_input_group_gid()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_num_tab_enter"
+
+ msg=$( printf "$msg_group_id_leave_empty_for_default" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ group_gid="$_input"
+ save_flag=1
+
+ f_dprintf "group_gid: [$cur_group_gid]->[$group_gid]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_group_members [$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.
+#
+f_dialog_input_group_members()
+{
+ local menu_choice msg size retval _input="$1"
+ local hline="$hline_num_arrows_tab_enter"
+ local user
+ local menu_list
+ local all_users_valid
+ local _group_members
+ local checklist_users
+
+ menu_list="
+ 'X' '$msg_continue'
+ '1' '$msg_select_group_members_from_list'
+ '2' '$msg_enter_group_members_manually'
+ " # END-QUOTE
+
+ while :; do
+ msg="$msg_group_members:"
+ menu_size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$msg\" \
+ \"\$hline\" \
+ $menu_list )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$msg\" $menu_size \
+ $menu_list \
+ 2> $DIALOG_TMPDIR/dialog.menu.$$
+ retval=$?
+ menu_choice=$( f_dialog_menutag )
+ f_dprintf "retval=$retval menu_choice=[$menu_choice]"
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ case "$menu_choice" in
+ X) # Exit
+ break ;;
+ 1) # Select Group Members from a list
+ user_list=$( pw usershow -a | awk -F: '
+ !/^[[:space:]]*(#|$)/ { printf "%s\n", $1 }' )
+ checklist_users=
+ for user in $user_list; do
+ checklist_users="$checklist_users $user \"\""
+ if echo "$_input" | grep -q "\<$user\>"; then
+ checklist_users="$checklist_users on"
+ else
+ checklist_users="$checklist_users off"
+ fi
+ done
+
+ size=$( eval f_dialog_radiolist_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $checklist_users )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --separate-output \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --checklist \"\$msg\" $size \
+ $checklist_users \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ _group_members=$( f_dialog_inputstr | tr '\n' ' ' |
+ sed -e 's/[[:space:]]\{1,\}/,/g;s/^,//;s/,$//' )
+
+ # Return to previous menu if user has either
+ # pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input="$_group_members"
+ ;;
+ 2) # Enter Group Members manually
+ hline="$hline_num_tab_enter"
+ msg=$(
+ printf "$msg_group_members ($msg_separated_by_commas)"
+ )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _group_members=$( f_dialog_inputstr )
+
+ # Return to previous menu if user has either
+ # pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input="$_group_members"
+ ;;
+ esac
+ done
+
+ group_members="$_input"
+ save_flag=1
+ f_dprintf "group_members: [$cur_group_members]->[$group_members]"
+
+ return $SUCCESS
+}
+
+fi # ! $_USERMGMT_GROUP_INPUT_SUBR
diff --git a/usr.sbin/bsdconfig/usermgmt/include/messages.subr b/usr.sbin/bsdconfig/usermgmt/include/messages.subr
new file mode 100644
index 0000000..e2e7bf3
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/include/messages.subr
@@ -0,0 +1,111 @@
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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$
+
+hline_alnum_punc_tab_enter="Use alpha-numeric, punctuation, TAB or ENTER"
+hline_alnum_tab_enter="Use alpha-numeric, TAB or ENTER"
+hline_arrows_space_tab_enter="Use arrows, SPACE, TAB or ENTER"
+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_expires_in_how_many_days="Account expires in how many days?"
+msg_account_expires_on="Account Expires on"
+msg_account_does_not_expire="Account does not expire"
+msg_add="Add"
+msg_add_group="Add Group"
+msg_add_login="Add Login"
+msg_cancel="Cancel"
+msg_continue="Continue"
+msg_create_dotfiles="Create Dotfiles"
+msg_create_home_directory="Create Home Directory"
+msg_delete="Delete"
+msg_delete_exit_or_cancel="Choose Delete/Exit when finished or Cancel."
+msg_delete_group="Delete Group"
+msg_delete_home_directory="Delete Home Directory"
+msg_delete_login="Delete Login"
+msg_delete_primary_group="Delete Primary Group"
+msg_deleting_home_directory="Deleting home directory..."
+msg_disable_password_auth_for_account="Disable password authentication for this account?"
+msg_disable_password_auth_for_group="Disable password authentication for this group?"
+msg_edit_date_time_with_a_calendar="Edit date/time with a calendar"
+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_number_of_days_into_the_future="Enter number of days into the future"
+msg_enter_value_manually="Edit value manually"
+msg_error="ERROR!"
+msg_exit="Exit"
+msg_full_name="Full Name"
+msg_group="Group"
+msg_group_added="Group Added"
+msg_group_already_used="%s: Group is already used."
+msg_group_deleted="Group Deleted"
+msg_group_is_empty="Group is empty."
+msg_group_id="Group ID"
+msg_group_id_leave_empty_for_default="Group ID (Leave empty for default)"
+msg_group_members="Group Members"
+msg_group_must_start_with_letter="Group must start with a letter."
+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_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."
+msg_login_class="Login Class"
+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_updated="Login Updated"
+msg_member_of_groups="Member of Groups"
+msg_n_a="N/A"
+msg_number_of_seconds_since_epoch="Number of seconds since the Epoch\n(1 = %s)\nNULL or zero to disable:"
+msg_no="No"
+msg_ok="OK"
+msg_password="Password"
+msg_password_expires_in_how_many_days="Password expires in how many days?"
+msg_password_expires_on="Password Expires on"
+msg_passwords_do_not_match="Passwords do not match."
+msg_password_does_not_expire="Password does not expire"
+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_separated_by_commas="Separated by commas"
+msg_select_group_members_from_list="Select Group Members from a list"
+msg_select_login_shell="Select Login Shell"
+msg_shell="Shell"
+msg_user="User"
+msg_user_id="UID"
+msg_user_id_leave_empty_for_default="UID (Leave empty for default)"
+msg_warning="WARNING!"
+msg_yes="Yes"
diff --git a/usr.sbin/bsdconfig/usermgmt/include/user_input.subr b/usr.sbin/bsdconfig/usermgmt/include/user_input.subr
new file mode 100644
index 0000000..a522f9d
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/include/user_input.subr
@@ -0,0 +1,1180 @@
+if [ ! "$_USERMGMT_USER_INPUT_SUBR" ]; then _USERMGMT_USER_INPUT_SUBR=1
+#
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/strings.subr
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+APP_DIR="070.usermgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ CONFIGURATION
+
+#
+# Default location of shells(5)
+#
+: ${ETC_SHELLS:=/etc/shells}
+
+############################################################ FUNCTIONS
+
+# f_get_member_groups $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_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).
+#
+f_input_user()
+{
+ local user="$1"
+ eval $( pw usershow "$user" | awk -F: '
+ {
+ 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" )
+}
+
+# f_dialog_menu_user_list
+#
+# Allows the user to select a login from a list.
+#
+f_dialog_menu_user_list()
+{
+ local menu_list size
+ local hline="$hline_alnum_punc_tab_enter"
+
+ menu_list="
+ 'X $msg_exit' ''
+ " # END-QUOTE
+
+ # Add users from passwd(5)
+ menu_list="$menu_list $( pw usershow -a | awk -F: '
+ !/^[[:space:]]*(#|$)/ {
+ printf "'\'%s\'\ \'%s\''\n", $1, $8
+ }'
+ )"
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\" $size $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+# f_dialog_input_member_groups [$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-
+# configured value upon return.
+#
+f_dialog_input_member_groups()
+{
+ local msg="$( printf "$msg_member_of_groups" )"
+ local hline="$hline_alnum_tab_enter"
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local size retval all_groups checklist_groups="" _member_groups="$1"
+ all_groups=$( pw groupshow -a | awk -F: '
+ !/^[[:space:]]*(#|$)/ {
+ printf "%s\n", $1
+ }'
+ )
+ for grp in $all_groups; do
+ checklist_groups="$checklist_groups $grp $grp"
+ if echo "$_member_groups" | grep -q "\<$grp\>"; then
+ checklist_groups="$checklist_groups on"
+ else
+ checklist_groups="$checklist_groups off"
+ fi
+ done
+
+ while :; do
+ size=$( eval f_dialog_radiolist_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $checklist_groups )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --separate-output \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --checklist \"\$msg\" $size \
+ $checklist_groups \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _member_groups=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ #
+ # Validate each of the groups the user has entered
+ #
+ local group 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
+
+ pw_member_groups="$_member_groups"
+ break
+ done
+ save_flag=1
+
+ local debug="pw_member_groups:"
+ f_dprintf "$debug [$cur_pw_member_groups]->[$pw_member_groups]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_name [$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).
+#
+f_dialog_input_name()
+{
+ local msg="$( printf "$msg_login" )"
+ local hline="$hline_alnum_tab_enter"
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local size retval _name="$1" _input="$1"
+ while :; do
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Check for no-change
+ [ "$_input" = "$_name" ] && return $SUCCESS
+
+ # Check for reversion
+ if [ "$_input" = "$cur_pw_name" ]; then
+ pw_name="$cur_pw_name"
+ return $SUCCESS
+ fi
+
+ # Check for NULL entry
+ if [ ! "$_input" ]; then
+ f_show_msg "$msg_login_is_empty"
+ continue
+ fi
+
+ # Check for invalid entry
+ if ! echo "$_input" | grep -q "^[[:alpha:]]"; then
+ f_show_msg "$msg_login_must_start_with_letter"
+ continue
+ fi
+
+ # Check for duplicate entry
+ if f_quietly pw usershow -n "$_input"; then
+ f_show_msg "$msg_login_already_used" "$_input"
+ continue
+ fi
+
+ pw_name="$_input"
+ break
+ done
+ save_flag=1
+
+ f_dprintf "pw_name: [$cur_pw_name]->[$pw_name]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_password
+#
+# Prompt the user to enter a password (twice).
+#
+f_dialog_input_password()
+{
+ local hline="$hline_alnum_punc_tab_enter"
+ local msg size rmsg rsize
+
+ msg=$( printf "$msg_password" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "" \
+ "$hline" )
+
+ rmsg=$( printf "$msg_reenter_password" )
+ rsize=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$rmsg" \
+ "" \
+ "$hline" )
+
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local retval _password1 _password2
+ while :; do
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --insecure \
+ --passwordbox \"\$msg\" $size \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _password1=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --insecure \
+ --passwordbox \"\$rmsg\" $rsize \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _password2=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ # Check for password mismatch
+ if [ "$_password1" != "$_password2" ]; then
+ f_show_msg "$msg_passwords_do_not_match"
+ continue
+ fi
+
+ # Check for NULL entry
+ if [ ! "$_password1" ]; then
+ f_dialog_yesno \
+ "$msg_disable_password_auth_for_account" ||
+ continue
+ pw_password_disable=1
+ else
+ pw_password_disable=
+ fi
+
+ pw_password="$_password1"
+ break
+ done
+ save_flag=1
+
+ f_dprintf "pw_password: [$cur_pw_password]->[$pw_password]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_gecos [$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
+# newly-configured value upon return.
+#
+f_dialog_input_gecos()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_alnum_punc_tab_enter"
+
+ msg=$( printf "$msg_full_name" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_gecos="$_input"
+ save_flag=1
+
+ f_dprintf "pw_gecos: [$cur_pw_gecos]->[$pw_gecos]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_uid [$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
+# value upon return.
+#
+f_dialog_input_uid()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_num_tab_enter"
+
+ msg=$( printf "$msg_user_id_leave_empty_for_default" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_uid="$_input"
+ save_flag=1
+
+ f_dprintf "pw_uid: [$cur_pw_uid]->[$pw_uid]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_gid [$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.
+#
+f_dialog_input_gid()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_num_tab_enter"
+
+ msg=$( printf "$msg_group_id_leave_empty_for_default" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_gid="$_input"
+ save_flag=1
+
+ f_dprintf "pw_gid: [$cur_pw_gid]->[$pw_gid]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_class [$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-
+# configured value upon return.
+#
+f_dialog_input_class()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_alnum_tab_enter"
+
+ msg=$( printf "$msg_login_class" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_class="$_input"
+ save_flag=1
+
+ f_dprintf "pw_class: [$cur_pw_class]->[$pw_class]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_change [$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.
+#
+f_dialog_input_change()
+{
+ local calendar_size timebox_size
+ local msg menu_size size retval _input="$1"
+ local hline="$hline_num_arrows_tab_enter"
+
+ 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'
+ " # END-QUOTE
+
+ #
+ # Loop until the user provides taint-free/cancellation-free input
+ #
+ while :; do
+ msg="$msg_password_expires_on"
+ menu_size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$msg\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$msg\" $menu_size \
+ $menu_list \
+ 2> $DIALOG_TMPDIR/dialog.menu.$$
+ retval=$?
+ date_type=$( f_dialog_menutag )
+ f_dprintf "retval=$retval date_type=[$date_type]"
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ case "$date_type" in
+ 1) # Password does not expire
+ _input=""
+ break ;;
+
+ 2) # Edit date/time with a calendar
+ 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" \
+ "+%d %m %Y" 2> /dev/null )
+ calendar_size=$( f_dialog_calendar_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --calendar \"\$msg\" $calendar_size \
+ $_input_date \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_date=$( f_dialog_inputstr )
+ f_dprintf "retval=$retval ret_date=[$ret_date]"
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input_time=
+ [ "$secs" ] && _input_time=$( date -j \
+ -f %s -- "$_input" "+%H %M %S" 2> /dev/null )
+ timebox_size=$( f_dialog_timebox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --timebox \"\$msg\" $timebox_size \
+ $_input_time \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_time=$( f_dialog_inputstr )
+ f_dprintf "retval=$retval ret_time=[$ret_time]"
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input=$( date \
+ -j -f "%d/%m/%Y %T" \
+ -- "$ret_date $ret_time" \
+ +%s 2> /dev/null )
+ f_dprintf "_input=[$_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 ))
+
+ msg="$msg_password_expires_in_how_many_days"
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$ret_days" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$ret_days\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_days=$( f_dialog_inputstr )
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ # Taint-check the user's input
+ if ! f_isinteger "$ret_days"; then
+ f_show_msg "$msg_invalid_number_of_days"
+ continue
+ fi
+
+ f_dprintf "ret_days=[$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=[$_input]"
+ break ;;
+
+ 4) # Enter value manually
+ local ret_secs
+
+ msg=$( printf "$msg_number_of_seconds_since_epoch" \
+ "$( date -r 1 "+%c %Z" )" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ ret_secs=$( f_dialog_inputstr )
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || 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=[$_input]"
+ break ;;
+
+ esac
+
+ done # Loop forever
+
+ pw_password_expire="$_input"
+ save_flag=1
+
+ local debug=pw_password_expire
+ f_dprintf "$debug: [$cur_pw_password_expire]->[$pw_password_expire]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_expire [$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.
+#
+f_dialog_input_expire()
+{
+ local calendar_size timebox_size
+ local msg menu_size size retval _input="$1"
+ local hline="$hline_num_arrows_tab_enter"
+
+ 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'
+ " # END-QUOTE
+
+ #
+ # Loop until the user provides taint-free/cancellation-free input
+ #
+ while :; do
+ msg="$msg_account_expires_on"
+ menu_size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$msg\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$msg\" $menu_size \
+ $menu_list \
+ 2> $DIALOG_TMPDIR/dialog.menu.$$
+ retval=$?
+ date_type=$( f_dialog_menutag )
+ f_dprintf "retval=$retval date_type=[$date_type]"
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ case "$date_type" in
+ 1) # Account does not expire
+ _input=""
+ break ;;
+
+ 2) # Edit date/time with a calendar
+ 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" \
+ "+%d %m %Y" 2> /dev/null )
+ calendar_size=$( f_dialog_calendar_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --calendar \"\$msg\" $calendar_size \
+ $_input_date \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_date=$( f_dialog_inputstr )
+ f_dprintf "retval=$retval ret_date=[$ret_date]"
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input_time=
+ [ "$secs" ] && _input_time=$( date -j \
+ -f %s -- "$_input" "+%H %M %S" 2> /dev/null )
+ timebox_size=$( f_dialog_timebox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --timebox \"\$msg\" $timebox_size \
+ $_input_time \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_time=$( f_dialog_inputstr )
+ f_dprintf "retval=$retval ret_time=[$ret_time]"
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ _input=$( date \
+ -j -f "%d/%m/%Y %T" \
+ -- "$ret_date $ret_time" \
+ +%s 2> /dev/null )
+ f_dprintf "_input=[$_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 ))
+
+ msg="$msg_account_expires_in_how_many_days"
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$ret_days" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$ret_days\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+ retval=$?
+ ret_days=$( f_dialog_inputstr )
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || continue
+
+ # Taint-check the user's input
+ if ! f_isinteger "$ret_days"; then
+ f_show_msg "$msg_invalid_number_of_days"
+ continue
+ fi
+
+ f_dprintf "ret_days=[$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=[$_input]"
+ break ;;
+
+ 4) # Enter value manually
+ local ret_secs
+
+ msg=$( printf "$msg_number_of_seconds_since_epoch" \
+ "$( date -r 1 "+%c %Z" )" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ ret_secs=$( f_dialog_inputstr )
+
+ # Return to menu if either ESC or Cancel/No
+ [ $retval -eq $SUCCESS ] || 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=[$_input]"
+ break ;;
+
+ esac
+
+ done # Loop forever
+
+ pw_account_expire="$_input"
+ save_flag=1
+
+ local debug=pw_account_expire
+ f_dprintf "$debug: [$cur_pw_account_expire]->[$pw_account_expire]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_home_dir [$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-
+# configured value upon return.
+#
+f_dialog_input_home_dir()
+{
+ local msg size retval _input="$1"
+ local hline="$hline_alnum_punc_tab_enter"
+
+ msg=$( printf "$msg_home_directory" )
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$_input" \
+ "$hline" )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --inputbox \"\$msg\" $size \
+ \"\$_input\" \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_home_dir="$_input"
+ save_flag=1
+
+ f_dprintf "pw_home_dir: [$cur_pw_home_dir]->[$pw_home_dir]"
+
+ return $SUCCESS
+}
+
+# f_dialog_input_home_create
+#
+# 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
+# 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
+
+ f_dialog_yesno "$msg_create_home_directory"
+ retval=$?
+
+ if [ $retval -eq $SUCCESS ]; then
+ pw_home_create="$msg_yes"
+ else
+ pw_home_create="$msg_no"
+ fi
+ save_flag=1
+
+ f_dprintf "pw_home_create: [$cur_pw_home_create]->[$pw_home_create]"
+
+ [ $retval -ne 255 ] # return failure if user pressed ESC
+}
+
+# f_dialog_input_group_delete
+#
+# 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
+# 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
+
+ if f_isinteger "$pw_gid"; then
+ if [ $pw_gid -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
+ f_dialog_noyes "$msg_delete_primary_group"
+ else
+ f_dialog_yesno "$msg_delete_primary_group"
+ fi
+ else
+ f_dialog_yesno "$msg_delete_primary_group"
+ fi
+ retval=$?
+
+ if [ $retval -eq $SUCCESS ]; then
+ pw_group_delete="$msg_yes"
+ else
+ pw_group_delete="$msg_no"
+ fi
+ save_flag=1
+
+ f_dprintf "pw_group_delete: [$cur_pw_group_delete]->[$pw_group_delete]"
+
+ [ $retval -ne 255 ] # return failure if user pressed ESC
+}
+
+# f_dialog_input_home_delete
+#
+# 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
+# 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
+
+ f_dialog_yesno "$msg_delete_home_directory"
+ retval=$?
+
+ if [ $retval -eq $SUCCESS ]; then
+ pw_home_delete="$msg_yes"
+ else
+ pw_home_delete="$msg_no"
+ fi
+ save_flag=1
+
+ f_dprintf "pw_home_delete: [$cur_pw_home_delete]->[$pw_home_delete]"
+
+ [ $retval -ne 255 ] # return failure if user pressed ESC
+}
+
+# f_dialog_input_dotfiles_create
+#
+# Prompt the user to confirm population of a given user'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.
+#
+f_dialog_input_dotfiles_create()
+{
+ local retval
+
+ f_dialog_yesno "$msg_create_dotfiles"
+ retval=$?
+
+ if [ $retval -eq $SUCCESS ]; then
+ pw_dotfiles_create="$msg_yes"
+ else
+ pw_dotfiles_create="$msg_no"
+ fi
+ save_flag=1
+
+ local debug="pw_dotfiles_create:"
+ f_dprintf "$debug: [$cur_pw_dotfiles_create]->[$pw_dotfiles_create]"
+
+ [ $retval -ne 255 ] # 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()
+{
+ local size retval shells shell_list _input="$1"
+ local hline="$hline_arrows_space_tab_enter"
+ local prompt="$msg_select_login_shell"
+
+ shells=$( awk '!/^[[:space:]]*(#|$)/{print}' "$ETC_SHELLS" )
+ shell_list=$(
+ for shell in $shells; do
+ if [ "$shell" = "$_input" ]; then
+ echo "'$shell' '' 'on'"
+ else
+ echo "'$shell' '' 'off'"
+ fi
+ done
+ )
+
+ size=$( eval f_dialog_radiolist_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $shell_list )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --radiolist \"\$prompt\" $size \
+ $shell_list \
+ 2> $DIALOG_TMPDIR/dialog.inputbox.$$
+
+ retval=$?
+ _input=$( f_dialog_inputstr )
+
+ # Return if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || return $retval
+
+ pw_shell="$_input"
+ save_flag=1
+
+ f_dprintf "pw_shell: [$cur_pw_shell]->[$pw_shell]"
+
+ return $SUCCESS
+}
+
+fi # ! $_USERMGMT_USER_INPUT_SUBR
diff --git a/usr.sbin/bsdconfig/usermgmt/useradd b/usr.sbin/bsdconfig/usermgmt/useradd
new file mode 100755
index 0000000..8dc1934
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/useradd
@@ -0,0 +1,64 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+
+APP_DIR="070.usermgmt"
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Chain-load to userinput to centralize code and minimize duplication
+#
+f_dialog_init
+$BSDCFG_LIBE/$APP_DIR/userinput ${USE_XDIALOG:+-X} mode="Add"
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/userdel b/usr.sbin/bsdconfig/usermgmt/userdel
new file mode 100755
index 0000000..49a54c4
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/userdel
@@ -0,0 +1,93 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/user_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_delete $msg_login"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Loop until the user Exits, Cancels or presses ESC
+#
+while :; do
+ f_dialog_menu_user_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+
+ *) # anything else is a userid
+ $BSDCFG_LIBE/$APP_DIR/userinput \
+ ${USE_XDIALOG:+-X} mode="Delete" user="$mtag"
+ ;;
+
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/useredit b/usr.sbin/bsdconfig/usermgmt/useredit
new file mode 100755
index 0000000..3109d36
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/useredit
@@ -0,0 +1,93 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/user_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_edit_view $msg_login"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Loop until the user Exits, Cancels or presses ESC
+#
+while :; do
+ f_dialog_menu_user_list
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ "X $msg_exit") break ;;
+
+ *) # anything else is a userid
+ $BSDCFG_LIBE/$APP_DIR/userinput \
+ ${USE_XDIALOG:+-X} mode="Edit/View" user="$mtag"
+ ;;
+
+ esac
+done
+
+exit $SUCCESS
+
+################################################################################
+# END
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/userinput b/usr.sbin/bsdconfig/usermgmt/userinput
new file mode 100755
index 0000000..43a750e
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/userinput
@@ -0,0 +1,515 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include $BSDCFG_LIBE/$APP_DIR/include/user_input.subr
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ 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 err retval=$SUCCESS
+
+ case "$mode" in
+ Delete)
+ err=$( pw userdel -u "$pw_uid" 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ f_show_msg "$msg_login_deleted"
+
+ if [ "$pw_group_delete" = "$msg_yes" ] &&
+ f_quietly pw groupshow -g "$pw_gid"
+ then
+ err=$( pw groupdel -g "$pw_gid" 2>&1 ) ||
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ fi
+
+ if [ "$pw_home_delete" = "$msg_yes" ]; then
+ f_dialog_info "$msg_deleting_home_directory"
+ err=$( rm -Rf "$pw_home_dir" 2>&1 ) ||
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ 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
+ cmd="$cmd -h -"
+ elif [ "$pw_password" ]; then
+ cmd="echo \"\$pw_password\" | $cmd -h 0"
+ fi
+ f_dprintf "cmd=$cmd"
+ err=$( eval $cmd 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ f_show_msg "$msg_login_added"
+
+ if [ "$pw_home_create" = "$msg_yes" ]; then
+ err=$( mkdir -p "$pw_home_dir" 2>&1 )
+ if [ $? -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ elif [ -e "$pw_home_dir" ]; then
+ err=$( chown -R "$pw_uid:$pw_gid" \
+ "$pw_home_dir" 2>&1 )
+ [ $? -eq $SUCCESS ] || f_show_msg \
+ "%s %s\n" "$msg_warning" "$err"
+ fi
+ fi
+
+ if [ "$pw_dotfiles_create" = "$msg_yes" ]; then
+ err=$( copy_dotfiles 2>&1 ) ||
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ fi
+
+ 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
+ cmd="$cmd -h -"
+ elif [ "$pw_password" ]; then
+ cmd="echo \"\$pw_password\" | $cmd -h 0"
+ fi
+ f_dprintf "cmd=$cmd"
+ err=$( eval $cmd 2>&1 )
+ retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_error" "$err"
+ return $retval
+ fi
+ f_show_msg "$msg_login_updated"
+
+ if [ "$pw_home_create" = "$msg_yes" ]; then
+ err=$( mkdir -p "$pw_home_dir" )
+ if [ $? -ne $SUCCESS ]; then
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ elif [ -e "$pw_home_dir" ]; then
+ err=$( chown -R "$pw_uid:$pw_gid" \
+ "$pw_home_dir" 2>&1 )
+ [ $? -eq $SUCCESS ] || f_show_msg \
+ "%s %s\n" "$msg_warning" "$err"
+ fi
+ fi
+
+ if [ "$pw_dotfiles_create" = "$msg_yes" ]; then
+ err=$( copy_dotfiles 2>&1 ) ||
+ f_show_msg "%s %s\n" "$msg_warning" "$err"
+ fi
+ ;;
+ 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=[$key] value=[$value]"
+ case "$key" in
+ mode) mode="$value";;
+ user) user="$value";;
+ esac
+ shift
+done
+f_dprintf "mode=[$mode] user=[$user]"
+
+#
+# Initialize
+#
+f_dialog_init
+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
+ #
+ # 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_name || exit 0
+ f_dialog_input_gecos "$pw_name" || 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_change || exit 0
+ f_dialog_input_expire || exit 0
+ f_dialog_input_home_dir "$homeprefix/$pw_name" || exit 0
+ pw_dotfiles_create="$msg_no"
+ if [ ! -d "$homeprefix/$pw_name" ]; 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 "$defaultshell" || exit 0
+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
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$menu_text\" \
+ \"\$hline\" \
+ $menu_items )
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$menu_text\" $size \
+ $menu_items \
+ 2> $DIALOG_TMPDIR/dialog.menu.$$
+
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ # Exit if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || 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
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ # Loop if user has either pressed ESC or chosen Cancel/No
+ [ $retval -eq $SUCCESS ] || 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_change "$pw_password_expire"
+ ;;
+ 9) # Account Expire on
+ f_dialog_input_expire "$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
+################################################################################
diff --git a/usr.sbin/bsdconfig/usermgmt/usermgmt b/usr.sbin/bsdconfig/usermgmt/usermgmt
new file mode 100755
index 0000000..460f46b
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/usermgmt
@@ -0,0 +1,150 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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_LIBE="/usr/libexec/bsdconfig"
+. $BSDCFG_LIBE/include/common.subr || exit 1
+f_include $BSDCFG_LIBE/include/dialog.subr
+f_include $BSDCFG_LIBE/include/mustberoot.subr
+
+APP_DIR="070.usermgmt"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+ipgm=$( f_index_menu_selection $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
+[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
+
+############################################################ FUNCTIONS
+
+# dialog_menu_main
+#
+# Display the dialog(1)-based application main menu.
+#
+dialog_menu_main()
+{
+ local menu_list size
+ local hline="$hline_arrows_tab_enter"
+
+ menu_list="
+ 'X' '$msg_exit'
+ '1' '$msg_add_login'
+ '2' '$msg_edit_login'
+ '3' '$msg_delete_login'
+ '-' '-'
+ '4' '$msg_add_group'
+ '5' '$msg_edit_group'
+ '6' '$msg_delete_group'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\" \
+ \"\$hline\" \
+ $menu_list )
+
+ eval $DIALOG \
+ --clear --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\" $size $menu_list \
+ 2> "$DIALOG_TMPDIR/dialog.menu.$$"
+}
+
+############################################################ MAIN
+
+# Incorporate rc-file if it exists
+[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
+
+#
+# Process command-line arguments
+#
+while getopts hSX flag; do
+ case "$flag" in
+ h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# Initialize
+#
+f_dialog_init
+f_dialog_title "$msg_login_management"
+f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
+f_mustberoot_init
+
+#
+# Launch application main menu
+#
+while :; do
+ dialog_menu_main
+ retval=$?
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=$retval mtag=[$mtag]"
+
+ [ $retval -eq 0 ] || f_die
+
+ case "$mtag" in
+ X) # Exit
+ exit 0
+ ;;
+
+ 1) # Add User
+ $BSDCFG_LIBE/$APP_DIR/useradd ${USE_XDIALOG:+-X}
+ ;;
+
+ 2) # Edit/View User
+ $BSDCFG_LIBE/$APP_DIR/useredit ${USE_XDIALOG:+-X}
+ ;;
+
+ 3) # Delete User
+ $BSDCFG_LIBE/$APP_DIR/userdel ${USE_XDIALOG:+-X}
+ ;;
+
+ 4) # Add Group
+ $BSDCFG_LIBE/$APP_DIR/groupadd ${USE_XDIALOG:+-X}
+ ;;
+
+ 5) # Edit/View Group
+ $BSDCFG_LIBE/$APP_DIR/groupedit ${USE_XDIALOG:+-X}
+ ;;
+
+ 6) # Delete Group
+ $BSDCFG_LIBE/$APP_DIR/groupdel ${USE_XDIALOG:+-X}
+ ;;
+
+ esac
+done
+
+################################################################################
+# END
+################################################################################
OpenPOWER on IntegriCloud