1 if [ ! "$_USERMGMT_GROUP_SUBR" ]; then _USERMGMT_GROUP_SUBR=1
3 # Copyright (c) 2012 Ron McDowell
4 # Copyright (c) 2012-2014 Devin Teske
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 ############################################################ INCLUDES
32 BSDCFG_SHARE="/usr/share/bsdconfig"
33 . $BSDCFG_SHARE/common.subr || exit 1
34 f_dprintf "%s: loading includes..." usermgmt/group.subr
35 f_include $BSDCFG_SHARE/dialog.subr
36 f_include $BSDCFG_SHARE/usermgmt/group_input.subr
38 BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
39 f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
41 ############################################################ CONFIGURATION
43 # set some reasonable defaults if /etc/adduser.conf does not exist.
44 [ -f /etc/adduser.conf ] && f_include /etc/adduser.conf
45 : ${passwdtype:="yes"}
47 ############################################################ FUNCTIONS
49 # f_group_add [$group]
51 # Add a group. If both $group (as a first argument) and $VAR_GROUP are unset
52 # or NULL and we are running interactively, prompt the user to enter the name
53 # of a new group and (if $VAR_NO_CONFIRM is unset or NULL) prompt the user to
54 # answer some questions about the new group. Variables that can be used to
57 # VAR_GROUP [Optional if running interactively]
58 # The group to add. Ignored if given non-NULL first-argument.
59 # VAR_GROUP_GID [Optional]
60 # Numerical group ID to use. If NULL or unset, the group ID is
61 # automatically chosen.
62 # VAR_GROUP_MEMBERS [Optional]
63 # Comma separated list of users that are a member of this group.
64 # VAR_GROUP_PASSWORD [Optional]
65 # newgrp(1) password to set for the group. Default if NULL or
66 # unset is to disable newgrp(1) password authentication.
68 # Returns success if the group was successfully added.
72 local funcname=f_group_add
73 local title # Calculated below
74 local alert=f_show_msg no_confirm=
76 f_getvar $VAR_NO_CONFIRM no_confirm
77 [ "$no_confirm" ] && alert=f_show_info
80 f_getvar 3:-\$$VAR_GROUP input "$1"
83 # NB: pw(8) has a ``feature'' wherein `-n name' can be taken as GID
84 # instead of name. Work-around is to also pass `-g GID' at the same
85 # time (the GID is ignored in this case, so any GID will do).
87 if [ "$input" ] && f_quietly pw groupshow -n "$input" -g 1337; then
88 f_show_err "$msg_group_already_used" "$input"
92 local group_name="$input"
93 while f_interactive && [ ! "$group_name" ]; do
94 f_dialog_input_group_name group_name "$group_name" ||
97 f_show_err "$msg_please_enter_a_group_name"
99 if [ ! "$group_name" ]; then
100 f_show_err "$msg_no_group_specified"
104 local group_password group_gid group_members
105 f_getvar $VAR_GROUP_PASSWORD group_password
106 f_getvar $VAR_GROUP_GID group_gid
107 f_getvar $VAR_GROUP_MEMBERS group_members
109 local group_password_disable=
110 f_interactive || [ "$group_password" ] || group_password_disable=1
112 if f_interactive && [ ! "$no_confirm" ]; then
114 "$msg_use_default_values_for_all_account_details"
116 if [ $retval -eq $DIALOG_ESC ]; then
118 elif [ $retval -ne $DIALOG_OK ]; then
120 # Ask series of questions to pre-fill the editor screen
122 # Defaults used in each dialog should allow the user to
123 # simply hit ENTER to proceed and cancelling a single
124 # dialog cause them to return to the previous menu.
127 if [ "$passwdtype" = "yes" ]; then
128 f_dialog_input_group_password group_password \
129 group_password_disable ||
132 f_dialog_input_group_gid group_gid "$group_gid" ||
134 f_dialog_input_group_members group_members \
135 "$group_members" || return $FAILURE
140 # Loop until the user decides to Exit, Cancel, or presses ESC
142 title="$msg_add $msg_group: $group_name"
143 if f_interactive; then
144 local mtag retval defaultitem=
146 f_dialog_title "$title"
147 f_dialog_menu_group_add "$defaultitem"
149 f_dialog_title_restore
150 f_dialog_menutag_fetch mtag
151 f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
154 # Return if user either pressed ESC or chose Cancel/No
155 [ $retval -eq $DIALOG_OK ] || return $FAILURE
160 for var in gid members name; do
162 eval f_shell_escape \
163 \"\$group_$var\" _group_$var
166 local cmd="pw groupadd -n '$_group_name'"
167 [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'"
168 [ "$group_members" ] &&
169 cmd="$cmd -M '$_group_members'"
171 # Execute the command (break on success)
172 if [ "$group_password_disable" ]; then
173 f_eval_catch $funcname pw '%s -h -' "$cmd"
174 elif [ "$group_password" ]; then
175 echo "$group_password" |
176 f_eval_catch $funcname \
179 f_eval_catch $funcname pw '%s' "$cmd"
182 1) # Group Name (prompt for new group name)
183 f_dialog_input_group_name input "$group_name" ||
185 if f_quietly pw groupshow -n "$input" -g 1337; then
186 f_show_err "$msg_group_already_used" "$input"
190 title="$msg_add $msg_group: $group_name"
193 f_dialog_input_group_password group_password \
194 group_password_disable
197 f_dialog_input_group_gid group_gid "$group_gid"
200 f_dialog_input_group_members group_members \
207 for var in gid members name; do
209 eval f_shell_escape \"\$group_$var\" _group_$var
213 local cmd="pw groupadd -n '$_group_name'"
214 [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'"
215 [ "$group_members" ] && cmd="$cmd -M '$_group_members'"
217 # Execute the command
219 if [ "$group_password_disable" ]; then
220 f_eval_catch -k err $funcname pw '%s -h -' "$cmd"
221 elif [ "$group_password" ]; then
222 err=$( echo "$group_password" | f_eval_catch -de \
223 $funcname pw '%s -h 0' "$cmd" 2>&1 )
225 f_eval_catch -k err $funcname pw '%s' "$cmd"
228 if [ $retval -ne $SUCCESS ]; then
229 f_show_err "%s" "$err"
234 f_dialog_title "$title"
235 $alert "$msg_group_added"
236 f_dialog_title_restore
237 [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
242 # f_group_delete [$group]
244 # Delete a group. If both $group (as a first argument) and $VAR_GROUP are unset
245 # or NULL and we are running interactively, prompt the user to select a group
246 # from a list of available groups. Variables that can be used to script user
249 # VAR_GROUP [Optional if running interactively]
250 # The group to delete. Ignored if given non-NULL first-argument.
252 # Returns success if the group was successfully deleted.
256 local funcname=f_group_delete
257 local title # Calculated below
258 local alert=f_show_msg no_confirm=
260 f_getvar $VAR_NO_CONFIRM no_confirm
261 [ "$no_confirm" ] && alert=f_show_info
264 f_getvar 3:-\$$VAR_GROUP input "$1"
266 local group_name group_password group_gid group_members
267 if [ "$input" ] && ! f_input_group "$input"; then
268 f_show_err "$msg_group_not_found" "$input"
273 # Loop until the user decides to Exit, Cancel, or presses ESC
275 title="$msg_delete $msg_group: $group_name"
276 if f_interactive; then
277 local mtag retval defaultitem=
279 f_dialog_title "$title"
280 f_dialog_menu_group_delete "$group_name" "$defaultitem"
282 f_dialog_title_restore
283 f_dialog_menutag_fetch mtag
284 f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
287 # Return if user either pressed ESC or chose Cancel/No
288 [ $retval -eq $DIALOG_OK ] || return $FAILURE
293 f_shell_escape "$group_name" _group_name
294 f_eval_catch $funcname pw 'pw groupdel "%s"' \
295 "$_group_name" && break
297 1) # Group Name (select different group from list)
298 f_dialog_menu_group_list "$group_name" || continue
299 f_dialog_menutag_fetch mtag
301 [ "$mtag" = "X $msg_exit" ] && continue
303 if ! f_input_group "$mtag"; then
304 f_show_err "$msg_group_not_found" "$mtag"
305 # Attempt to fall back to previous selection
306 f_input_group "$input" || return $FAILURE
314 local retval err _group_name
315 f_shell_escape "$group_name" _group_name
316 f_eval_catch -k err $funcname pw \
317 "pw groupdel '%s'" "$_group_name"
319 if [ $retval -ne $SUCCESS ]; then
320 f_show_err "%s" "$err"
325 f_dialog_title "$title"
326 $alert "$msg_group_deleted"
327 f_dialog_title_restore
328 [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
333 # f_group_edit [$group]
335 # Modify a group. If both $group (as a first argument) and $VAR_GROUP are unset
336 # or NULL and we are running interactively, prompt the user to select a group
337 # from a list of available groups. Variables that can be used to script user
340 # VAR_GROUP [Optional if running interactively]
341 # The group to modify. Ignored if given non-NULL first-argument.
342 # VAR_GROUP_GID [Optional]
343 # Numerical group ID to set. If NULL or unset, the group ID is
345 # VAR_GROUP_MEMBERS [Optional]
346 # Comma separated list of users that are a member of this group.
347 # If set but NULL, group memberships are reset (no users will be
348 # a member of this group). If unset, group membership is
350 # VAR_GROUP_PASSWORD [Optional]
351 # newgrp(1) password to set for the group. If unset, the password
352 # is unmodified. If NULL, the newgrp(1) password is disabled.
354 # Returns success if the group was successfully modified.
358 local funcname=f_group_edit
359 local title # Calculated below
360 local alert=f_show_msg no_confirm=
362 f_getvar $VAR_NO_CONFIRM no_confirm
363 [ "$no_confirm" ] && alert=f_show_info
366 f_getvar 3:-\$$VAR_GROUP input "$1"
369 # NB: pw(8) has a ``feature'' wherein `-n name' can be taken as GID
370 # instead of name. Work-around is to also pass `-g GID' at the same
371 # time (the GID is ignored in this case, so any GID will do).
373 if [ "$input" ] && ! f_quietly pw groupshow -n "$input" -g 1337; then
374 f_show_err "$msg_group_not_found" "$input"
378 if f_interactive && [ ! "$input" ]; then
379 f_dialog_menu_group_list || return $SUCCESS
380 f_dialog_menutag_fetch input
381 [ "$input" = "X $msg_exit" ] && return $SUCCESS
382 elif [ ! "$input" ]; then
383 f_show_err "$msg_no_group_specified"
387 local group_name group_password group_gid group_members
388 if ! f_input_group "$input"; then
389 f_show_err "$msg_group_not_found" "$input"
393 f_isset $VAR_GROUP_GID && f_getvar $VAR_GROUP_GID group_gid
395 if f_isset $VAR_GROUP_MEMBERS; then
396 f_getvar $VAR_GROUP_MEMBERS group_members
397 [ "$group_members" ] || null_members=1
399 local group_password_disable=
400 if f_isset $VAR_GROUP_PASSWORD; then
401 f_getvar $VAR_GROUP_PASSWORD group_password
402 [ "$group_password" ] || group_password_disable=1
406 # Loop until the user decides to Exit, Cancel, or presses ESC
408 title="$msg_edit_view $msg_group: $group_name"
409 if f_interactive; then
410 local mtag retval defaultitem=
412 f_dialog_title "$title"
413 f_dialog_menu_group_edit "$defaultitem"
415 f_dialog_title_restore
416 f_dialog_menutag_fetch mtag
417 f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
420 # Return if user either pressed ESC or chose Cancel/No
421 [ $retval -eq $DIALOG_OK ] || return $FAILURE
426 for var in gid members name; do
428 eval f_shell_escape \
429 \"\$group_$var\" _group_$var
432 local cmd="pw groupmod -n '$_group_name'"
433 [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'"
434 [ "$group_members" -o "$null_members" ] &&
435 cmd="$cmd -M '$_group_members'"
437 # Execute the command (break on success)
438 if [ "$group_password_disable" ]; then
439 f_eval_catch $funcname pw '%s -h -' "$cmd"
440 elif [ "$group_password" ]; then
441 echo "$group_password" | f_eval_catch \
442 $funcname pw '%s -h 0' "$cmd"
444 f_eval_catch $funcname pw '%s' "$cmd"
447 1) # Group Name (select different group from list)
448 f_dialog_menu_group_list "$group_name" || continue
449 f_dialog_menutag_fetch mtag
451 [ "$mtag" = "X $msg_exit" ] && continue
453 if ! f_input_group "$mtag"; then
454 f_show_err "$msg_group_not_found" "$mtag"
455 # Attempt to fall back to previous selection
456 f_input_group "$input" || return $FAILURE
460 title="$msg_edit_view $msg_group: $group_name"
463 f_dialog_input_group_password group_password \
464 group_password_disable
467 f_dialog_input_group_gid group_gid "$group_gid"
470 f_dialog_input_group_members group_members \
471 "$group_members" && [ ! "$group_members" ] &&
478 for var in gid members name; do
480 eval f_shell_escape \"\$group_$var\" _group_$var
484 local cmd="pw groupmod -n '$_group_name'"
485 [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'"
486 [ "$group_members" -o "$null_members" ] &&
487 cmd="$cmd -M '$_group_members'"
489 # Execute the command
491 if [ "$group_password_disable" ]; then
492 f_eval_catch -k err $funcname pw '%s -h -' "$cmd"
493 elif [ "$group_password" -o "$null_password" ]; then
494 err=$( echo "$group_password" | f_eval_catch -de \
495 $funcname pw '%s -h 0' "$cmd" 2>&1 )
497 f_eval_catch -k err $funcname pw '%s' "$cmd"
500 if [ $retval -ne $SUCCESS ]; then
501 f_show_err "%s" "$err"
506 f_dialog_title "$title"
507 $alert "$msg_group_updated"
508 f_dialog_title_restore
509 [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
514 ############################################################ MAIN
516 f_dprintf "%s: Successfully loaded." usermgmt/group.subr
518 fi # ! $_USERMGMT_GROUP_SUBR