]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/bsdconfig/usermgmt/share/group.subr
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.sbin / bsdconfig / usermgmt / share / group.subr
1 if [ ! "$_USERMGMT_GROUP_SUBR" ]; then _USERMGMT_GROUP_SUBR=1
2 #
3 # Copyright (c) 2012 Ron McDowell
4 # Copyright (c) 2012-2014 Devin Teske
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 #    notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 #    notice, this list of conditions and the following disclaimer in the
14 #    documentation and/or other materials provided with the distribution.
15 #
16 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 # SUCH DAMAGE.
27 #
28 # $FreeBSD$
29 #
30 ############################################################ INCLUDES
31
32 BSDCFG_SHARE="/usr/share/bsdconfig"
33 . $BSDCFG_SHARE/common.subr || exit 1
34 f_dprintf "%s: loading includes..." usermgmt/group.subr
35 f_include $BSDCFG_SHARE/dialog.subr
36 f_include $BSDCFG_SHARE/usermgmt/group_input.subr
37
38 BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt"
39 f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
40
41 ############################################################ CONFIGURATION
42
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"}
46
47 ############################################################ FUNCTIONS
48
49 # f_group_add [$group]
50 #
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
55 # script user input:
56 #
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.
67 #
68 # Returns success if the group was successfully added.
69 #
70 f_group_add()
71 {
72         local funcname=f_group_add
73         local title # Calculated below
74         local alert=f_show_msg no_confirm=
75
76         f_getvar $VAR_NO_CONFIRM no_confirm
77         [ "$no_confirm" ] && alert=f_show_info
78
79         local input
80         f_getvar 3:-\$$VAR_GROUP input "$1"
81
82         #
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).
86         #
87         if [ "$input" ] && f_quietly pw groupshow -n "$input" -g 1337; then
88                 f_show_err "$msg_group_already_used" "$input"
89                 return $FAILURE
90         fi
91
92         local group_name="$input"
93         while f_interactive && [ ! "$group_name" ]; do
94                 f_dialog_input_group_name group_name "$group_name" ||
95                         return $SUCCESS
96                 [ "$group_name" ] ||
97                         f_show_err "$msg_please_enter_a_group_name"
98         done
99         if [ ! "$group_name" ]; then
100                 f_show_err "$msg_no_group_specified"
101                 return $FAILURE
102         fi
103
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
108
109         local group_password_disable=
110         f_interactive || [ "$group_password" ] || group_password_disable=1
111
112         if f_interactive && [ ! "$no_confirm" ]; then
113                 f_dialog_noyes \
114                         "$msg_use_default_values_for_all_account_details"
115                 retval=$?
116                 if [ $retval -eq $DIALOG_ESC ]; then
117                         return $SUCCESS
118                 elif [ $retval -ne $DIALOG_OK ]; then
119                         #
120                         # Ask series of questions to pre-fill the editor screen
121                         #
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.
125                         #
126         
127                         if [ "$passwdtype" = "yes" ]; then
128                                 f_dialog_input_group_password group_password \
129                                         group_password_disable ||
130                                         return $FAILURE
131                         fi
132                         f_dialog_input_group_gid group_gid "$group_gid" ||
133                                 return $FAILURE
134                         f_dialog_input_group_members group_members \
135                                 "$group_members" || return $FAILURE
136                 fi
137         fi
138
139         #
140         # Loop until the user decides to Exit, Cancel, or presses ESC
141         #
142         title="$msg_add $msg_group: $group_name"
143         if f_interactive; then
144                 local mtag retval defaultitem=
145                 while :; do
146                         f_dialog_title "$title"
147                         f_dialog_menu_group_add "$defaultitem"
148                         retval=$?
149                         f_dialog_title_restore
150                         f_dialog_menutag_fetch mtag
151                         f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
152                         defaultitem="$mtag"
153
154                         # Return if user either pressed ESC or chose Cancel/No
155                         [ $retval -eq $DIALOG_OK ] || return $FAILURE
156
157                         case "$mtag" in
158                         X) # Add/Exit
159                            local var
160                            for var in gid members name; do
161                                 local _group_$var
162                                 eval f_shell_escape \
163                                         \"\$group_$var\" _group_$var
164                            done
165
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'"
170
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 \
177                                                 pw '%s -h 0' "$cmd"
178                            else
179                                 f_eval_catch $funcname pw '%s' "$cmd"
180                            fi && break
181                            ;;
182                         1) # Group Name (prompt for new group name)
183                            f_dialog_input_group_name input "$group_name" ||
184                                 continue
185                            if f_quietly pw groupshow -n "$input" -g 1337; then
186                                 f_show_err "$msg_group_already_used" "$input"
187                                 continue
188                            fi
189                            group_name="$input"
190                            title="$msg_add $msg_group: $group_name"
191                            ;;
192                         2) # Password
193                            f_dialog_input_group_password group_password \
194                                 group_password_disable
195                            ;;
196                         3) # Group ID
197                            f_dialog_input_group_gid group_gid "$group_gid"
198                            ;;
199                         4) # Group Members
200                            f_dialog_input_group_members group_members \
201                                         "$group_members"
202                            ;;
203                         esac
204                 done
205         else
206                 local var
207                 for var in gid members name; do
208                         local _group_$var
209                         eval f_shell_escape \"\$group_$var\" _group_$var
210                 done
211
212                 # Form the command
213                 local cmd="pw groupadd -n '$_group_name'"
214                 [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'"
215                 [ "$group_members" ] && cmd="$cmd -M '$_group_members'"
216
217                 # Execute the command
218                 local retval err
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 )
224                 else
225                         f_eval_catch -k err $funcname pw '%s' "$cmd"
226                 fi
227                 retval=$?
228                 if [ $retval -ne $SUCCESS ]; then
229                         f_show_err "%s" "$err"
230                         return $retval
231                 fi
232         fi
233
234         f_dialog_title "$title"
235         $alert "$msg_group_added"
236         f_dialog_title_restore
237         [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
238
239         return $SUCCESS
240 }
241
242 # f_group_delete [$group]
243 #
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
247 # input:
248 #
249 #       VAR_GROUP [Optional if running interactively]
250 #               The group to delete. Ignored if given non-NULL first-argument.
251 #
252 # Returns success if the group was successfully deleted.
253 #
254 f_group_delete()
255 {
256         local funcname=f_group_delete
257         local title # Calculated below
258         local alert=f_show_msg no_confirm=
259
260         f_getvar $VAR_NO_CONFIRM no_confirm
261         [ "$no_confirm" ] && alert=f_show_info
262
263         local input
264         f_getvar 3:-\$$VAR_GROUP input "$1"
265
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"
269                 return $FAILURE
270         fi
271
272         #
273         # Loop until the user decides to Exit, Cancel, or presses ESC
274         #
275         title="$msg_delete $msg_group: $group_name"
276         if f_interactive; then
277                 local mtag retval defaultitem=
278                 while :; do
279                         f_dialog_title "$title"
280                         f_dialog_menu_group_delete "$group_name" "$defaultitem"
281                         retval=$?
282                         f_dialog_title_restore
283                         f_dialog_menutag_fetch mtag
284                         f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
285                         defaultitem="$mtag"
286
287                         # Return if user either pressed ESC or chose Cancel/No
288                         [ $retval -eq $DIALOG_OK ] || return $FAILURE
289
290                         case "$mtag" in
291                         X) # Delete/Exit
292                            local _group_name
293                            f_shell_escape "$group_name" _group_name
294                            f_eval_catch $funcname pw 'pw groupdel "%s"' \
295                                         "$_group_name" && break
296                            ;;
297                         1) # Group Name (select different group from list)
298                            f_dialog_menu_group_list "$group_name" || continue
299                            f_dialog_menutag_fetch mtag
300
301                            [ "$mtag" = "X $msg_exit" ] && continue
302
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
307                            else
308                                 input="$mtag"
309                            fi
310                            ;;
311                         esac
312                 done
313         else
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"
318                 retval=$?
319                 if [ $retval -ne $SUCCESS ]; then
320                         f_show_err "%s" "$err"
321                         return $retval
322                 fi
323         fi
324
325         f_dialog_title "$title"
326         $alert "$msg_group_deleted"
327         f_dialog_title_restore
328         [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
329
330         return $SUCCESS
331 }
332
333 # f_group_edit [$group]
334 #
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
338 # input:
339 #
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
344 #               unchanged.
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
349 #               unmodified.
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.
353 #
354 # Returns success if the group was successfully modified.
355 #
356 f_group_edit()
357 {
358         local funcname=f_group_edit
359         local title # Calculated below
360         local alert=f_show_msg no_confirm=
361
362         f_getvar $VAR_NO_CONFIRM no_confirm
363         [ "$no_confirm" ] && alert=f_show_info
364
365         local input
366         f_getvar 3:-\$$VAR_GROUP input "$1"
367
368         #
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).
372         #
373         if [ "$input" ] && ! f_quietly pw groupshow -n "$input" -g 1337; then
374                 f_show_err "$msg_group_not_found" "$input"
375                 return $FAILURE
376         fi
377
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"
384                 return $FAILURE
385         fi
386
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"
390                 return $FAILURE
391         fi
392
393         f_isset $VAR_GROUP_GID && f_getvar $VAR_GROUP_GID group_gid
394         local null_members=
395         if f_isset $VAR_GROUP_MEMBERS; then
396                 f_getvar $VAR_GROUP_MEMBERS group_members
397                 [ "$group_members" ] || null_members=1
398         fi
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
403         fi
404
405         #
406         # Loop until the user decides to Exit, Cancel, or presses ESC
407         #
408         title="$msg_edit_view $msg_group: $group_name"
409         if f_interactive; then
410                 local mtag retval defaultitem=
411                 while :; do
412                         f_dialog_title "$title"
413                         f_dialog_menu_group_edit "$defaultitem"
414                         retval=$?
415                         f_dialog_title_restore
416                         f_dialog_menutag_fetch mtag
417                         f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
418                         defaultitem="$mtag"
419
420                         # Return if user either pressed ESC or chose Cancel/No
421                         [ $retval -eq $DIALOG_OK ] || return $FAILURE
422
423                         case "$mtag" in
424                         X) # Save/Exit
425                            local var
426                            for var in gid members name; do
427                                 local _group_$var
428                                 eval f_shell_escape \
429                                         \"\$group_$var\" _group_$var
430                            done
431
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'"
436
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"
443                            else
444                                 f_eval_catch $funcname pw '%s' "$cmd"
445                            fi && break
446                            ;;
447                         1) # Group Name (select different group from list)
448                            f_dialog_menu_group_list "$group_name" || continue
449                            f_dialog_menutag_fetch mtag
450
451                            [ "$mtag" = "X $msg_exit" ] && continue
452
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
457                            else
458                                 input="$mtag"
459                            fi
460                            title="$msg_edit_view $msg_group: $group_name"
461                            ;;
462                         2) # Password
463                            f_dialog_input_group_password group_password \
464                                 group_password_disable
465                            ;;
466                         3) # Group ID
467                            f_dialog_input_group_gid group_gid "$group_gid"
468                            ;;
469                         4) # Group Members
470                            f_dialog_input_group_members group_members \
471                                 "$group_members" && [ ! "$group_members" ] &&
472                                 null_members=1
473                            ;;
474                         esac
475                 done
476         else
477                 local var
478                 for var in gid members name; do
479                         local _group_$var
480                         eval f_shell_escape \"\$group_$var\" _group_$var
481                 done
482
483                 # Form the command
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'"
488
489                 # Execute the command
490                 local retval err
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 )
496                 else
497                         f_eval_catch -k err $funcname pw '%s' "$cmd"
498                 fi
499                 retval=$?
500                 if [ $retval -ne $SUCCESS ]; then
501                         f_show_err "%s" "$err"
502                         return $retval
503                 fi
504         fi
505
506         f_dialog_title "$title"
507         $alert "$msg_group_updated"
508         f_dialog_title_restore
509         [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1
510
511         return $SUCCESS
512 }
513
514 ############################################################ MAIN
515
516 f_dprintf "%s: Successfully loaded." usermgmt/group.subr
517
518 fi # ! $_USERMGMT_GROUP_SUBR