1if [ ! "$_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# 29############################################################ INCLUDES 30 31BSDCFG_SHARE="/usr/share/bsdconfig" 32. $BSDCFG_SHARE/common.subr || exit 1 33f_dprintf "%s: loading includes..." usermgmt/group.subr 34f_include $BSDCFG_SHARE/dialog.subr 35f_include $BSDCFG_SHARE/usermgmt/group_input.subr 36 37BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="070.usermgmt" 38f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr 39 40############################################################ CONFIGURATION 41 42# set some reasonable defaults if /etc/adduser.conf does not exist. 43[ -f /etc/adduser.conf ] && f_include /etc/adduser.conf 44: ${passwdtype:="yes"} 45 46############################################################ FUNCTIONS 47 48# f_group_add [$group] 49# 50# Add a group. If both $group (as a first argument) and $VAR_GROUP are unset 51# or NULL and we are running interactively, prompt the user to enter the name 52# of a new group and (if $VAR_NO_CONFIRM is unset or NULL) prompt the user to 53# answer some questions about the new group. Variables that can be used to 54# script user input: 55# 56# VAR_GROUP [Optional if running interactively] 57# The group to add. Ignored if given non-NULL first-argument. 58# VAR_GROUP_GID [Optional] 59# Numerical group ID to use. If NULL or unset, the group ID is 60# automatically chosen. 61# VAR_GROUP_MEMBERS [Optional] 62# Comma separated list of users that are a member of this group. 63# VAR_GROUP_PASSWORD [Optional] 64# newgrp(1) password to set for the group. Default if NULL or 65# unset is to disable newgrp(1) password authentication. 66# 67# Returns success if the group was successfully added. 68# 69f_group_add() 70{ 71 local funcname=f_group_add 72 local title # Calculated below 73 local alert=f_show_msg no_confirm= 74 75 f_getvar $VAR_NO_CONFIRM no_confirm 76 [ "$no_confirm" ] && alert=f_show_info 77 78 local input 79 f_getvar 3:-\$$VAR_GROUP input "$1" 80 81 # 82 # NB: pw(8) has a ``feature'' wherein `-n name' can be taken as GID 83 # instead of name. Work-around is to also pass `-g GID' at the same 84 # time (the GID is ignored in this case, so any GID will do). 85 # 86 if [ "$input" ] && f_quietly pw groupshow -n "$input" -g 1337; then 87 f_show_err "$msg_group_already_used" "$input" 88 return $FAILURE 89 fi 90 91 local group_name="$input" 92 while f_interactive && [ ! "$group_name" ]; do 93 f_dialog_input_group_name group_name "$group_name" || 94 return $SUCCESS 95 [ "$group_name" ] || 96 f_show_err "$msg_please_enter_a_group_name" 97 done 98 if [ ! "$group_name" ]; then 99 f_show_err "$msg_no_group_specified" 100 return $FAILURE 101 fi 102 103 local group_password group_gid group_members 104 f_getvar $VAR_GROUP_PASSWORD group_password 105 f_getvar $VAR_GROUP_GID group_gid 106 f_getvar $VAR_GROUP_MEMBERS group_members 107 108 local group_password_disable= 109 f_interactive || [ "$group_password" ] || group_password_disable=1 110 111 if f_interactive && [ ! "$no_confirm" ]; then 112 f_dialog_noyes \ 113 "$msg_use_default_values_for_all_account_details" 114 retval=$? 115 if [ $retval -eq $DIALOG_ESC ]; then 116 return $SUCCESS 117 elif [ $retval -ne $DIALOG_OK ]; then 118 # 119 # Ask series of questions to pre-fill the editor screen 120 # 121 # Defaults used in each dialog should allow the user to 122 # simply hit ENTER to proceed and cancelling a single 123 # dialog cause them to return to the previous menu. 124 # 125 126 if [ "$passwdtype" = "yes" ]; then 127 f_dialog_input_group_password group_password \ 128 group_password_disable || 129 return $FAILURE 130 fi 131 f_dialog_input_group_gid group_gid "$group_gid" || 132 return $FAILURE 133 f_dialog_input_group_members group_members \ 134 "$group_members" || return $FAILURE 135 fi 136 fi 137 138 # 139 # Loop until the user decides to Exit, Cancel, or presses ESC 140 # 141 title="$msg_add $msg_group: $group_name" 142 if f_interactive; then 143 local mtag retval defaultitem= 144 while :; do 145 f_dialog_title "$title" 146 f_dialog_menu_group_add "$defaultitem" 147 retval=$? 148 f_dialog_title_restore 149 f_dialog_menutag_fetch mtag 150 f_dprintf "retval=%u mtag=[%s]" $retval "$mtag" 151 defaultitem="$mtag" 152 153 # Return if user either pressed ESC or chose Cancel/No 154 [ $retval -eq $DIALOG_OK ] || return $FAILURE 155 156 case "$mtag" in 157 X) # Add/Exit 158 local var 159 for var in gid members name; do 160 local _group_$var 161 eval f_shell_escape \ 162 \"\$group_$var\" _group_$var 163 done 164 165 local cmd="pw groupadd -n '$_group_name'" 166 [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'" 167 [ "$group_members" ] && 168 cmd="$cmd -M '$_group_members'" 169 170 # Execute the command (break on success) 171 if [ "$group_password_disable" ]; then 172 f_eval_catch $funcname pw '%s -h -' "$cmd" 173 elif [ "$group_password" ]; then 174 echo "$group_password" | 175 f_eval_catch $funcname \ 176 pw '%s -h 0' "$cmd" 177 else 178 f_eval_catch $funcname pw '%s' "$cmd" 179 fi && break 180 ;; 181 1) # Group Name (prompt for new group name) 182 f_dialog_input_group_name input "$group_name" || 183 continue 184 if f_quietly pw groupshow -n "$input" -g 1337; then 185 f_show_err "$msg_group_already_used" "$input" 186 continue 187 fi 188 group_name="$input" 189 title="$msg_add $msg_group: $group_name" 190 ;; 191 2) # Password 192 f_dialog_input_group_password group_password \ 193 group_password_disable 194 ;; 195 3) # Group ID 196 f_dialog_input_group_gid group_gid "$group_gid" 197 ;; 198 4) # Group Members 199 f_dialog_input_group_members group_members \ 200 "$group_members" 201 ;; 202 esac 203 done 204 else 205 local var 206 for var in gid members name; do 207 local _group_$var 208 eval f_shell_escape \"\$group_$var\" _group_$var 209 done 210 211 # Form the command 212 local cmd="pw groupadd -n '$_group_name'" 213 [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'" 214 [ "$group_members" ] && cmd="$cmd -M '$_group_members'" 215 216 # Execute the command 217 local retval err 218 if [ "$group_password_disable" ]; then 219 f_eval_catch -k err $funcname pw '%s -h -' "$cmd" 220 elif [ "$group_password" ]; then 221 err=$( echo "$group_password" | f_eval_catch -de \ 222 $funcname pw '%s -h 0' "$cmd" 2>&1 ) 223 else 224 f_eval_catch -k err $funcname pw '%s' "$cmd" 225 fi 226 retval=$? 227 if [ $retval -ne $SUCCESS ]; then 228 f_show_err "%s" "$err" 229 return $retval 230 fi 231 fi 232 233 f_dialog_title "$title" 234 $alert "$msg_group_added" 235 f_dialog_title_restore 236 [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1 237 238 return $SUCCESS 239} 240 241# f_group_delete [$group] 242# 243# Delete a group. If both $group (as a first argument) and $VAR_GROUP are unset 244# or NULL and we are running interactively, prompt the user to select a group 245# from a list of available groups. Variables that can be used to script user 246# input: 247# 248# VAR_GROUP [Optional if running interactively] 249# The group to delete. Ignored if given non-NULL first-argument. 250# 251# Returns success if the group was successfully deleted. 252# 253f_group_delete() 254{ 255 local funcname=f_group_delete 256 local title # Calculated below 257 local alert=f_show_msg no_confirm= 258 259 f_getvar $VAR_NO_CONFIRM no_confirm 260 [ "$no_confirm" ] && alert=f_show_info 261 262 local input 263 f_getvar 3:-\$$VAR_GROUP input "$1" 264 265 local group_name group_password group_gid group_members 266 if [ "$input" ] && ! f_input_group "$input"; then 267 f_show_err "$msg_group_not_found" "$input" 268 return $FAILURE 269 fi 270 271 # 272 # Loop until the user decides to Exit, Cancel, or presses ESC 273 # 274 title="$msg_delete $msg_group: $group_name" 275 if f_interactive; then 276 local mtag retval defaultitem= 277 while :; do 278 f_dialog_title "$title" 279 f_dialog_menu_group_delete "$group_name" "$defaultitem" 280 retval=$? 281 f_dialog_title_restore 282 f_dialog_menutag_fetch mtag 283 f_dprintf "retval=%u mtag=[%s]" $retval "$mtag" 284 defaultitem="$mtag" 285 286 # Return if user either pressed ESC or chose Cancel/No 287 [ $retval -eq $DIALOG_OK ] || return $FAILURE 288 289 case "$mtag" in 290 X) # Delete/Exit 291 local _group_name 292 f_shell_escape "$group_name" _group_name 293 f_eval_catch $funcname pw 'pw groupdel "%s"' \ 294 "$_group_name" && break 295 ;; 296 1) # Group Name (select different group from list) 297 f_dialog_menu_group_list "$group_name" || continue 298 f_dialog_menutag_fetch mtag 299 300 [ "$mtag" = "X $msg_exit" ] && continue 301 302 if ! f_input_group "$mtag"; then 303 f_show_err "$msg_group_not_found" "$mtag" 304 # Attempt to fall back to previous selection 305 f_input_group "$input" || return $FAILURE 306 else 307 input="$mtag" 308 fi 309 ;; 310 esac 311 done 312 else 313 local retval err _group_name 314 f_shell_escape "$group_name" _group_name 315 f_eval_catch -k err $funcname pw \ 316 "pw groupdel '%s'" "$_group_name" 317 retval=$? 318 if [ $retval -ne $SUCCESS ]; then 319 f_show_err "%s" "$err" 320 return $retval 321 fi 322 fi 323 324 f_dialog_title "$title" 325 $alert "$msg_group_deleted" 326 f_dialog_title_restore 327 [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1 328 329 return $SUCCESS 330} 331 332# f_group_edit [$group] 333# 334# Modify a group. If both $group (as a first argument) and $VAR_GROUP are unset 335# or NULL and we are running interactively, prompt the user to select a group 336# from a list of available groups. Variables that can be used to script user 337# input: 338# 339# VAR_GROUP [Optional if running interactively] 340# The group to modify. Ignored if given non-NULL first-argument. 341# VAR_GROUP_GID [Optional] 342# Numerical group ID to set. If NULL or unset, the group ID is 343# unchanged. 344# VAR_GROUP_MEMBERS [Optional] 345# Comma separated list of users that are a member of this group. 346# If set but NULL, group memberships are reset (no users will be 347# a member of this group). If unset, group membership is 348# unmodified. 349# VAR_GROUP_PASSWORD [Optional] 350# newgrp(1) password to set for the group. If unset, the password 351# is unmodified. If NULL, the newgrp(1) password is disabled. 352# 353# Returns success if the group was successfully modified. 354# 355f_group_edit() 356{ 357 local funcname=f_group_edit 358 local title # Calculated below 359 local alert=f_show_msg no_confirm= 360 361 f_getvar $VAR_NO_CONFIRM no_confirm 362 [ "$no_confirm" ] && alert=f_show_info 363 364 local input 365 f_getvar 3:-\$$VAR_GROUP input "$1" 366 367 # 368 # NB: pw(8) has a ``feature'' wherein `-n name' can be taken as GID 369 # instead of name. Work-around is to also pass `-g GID' at the same 370 # time (the GID is ignored in this case, so any GID will do). 371 # 372 if [ "$input" ] && ! f_quietly pw groupshow -n "$input" -g 1337; then 373 f_show_err "$msg_group_not_found" "$input" 374 return $FAILURE 375 fi 376 377 if f_interactive && [ ! "$input" ]; then 378 f_dialog_menu_group_list || return $SUCCESS 379 f_dialog_menutag_fetch input 380 [ "$input" = "X $msg_exit" ] && return $SUCCESS 381 elif [ ! "$input" ]; then 382 f_show_err "$msg_no_group_specified" 383 return $FAILURE 384 fi 385 386 local group_name group_password group_gid group_members 387 if ! f_input_group "$input"; then 388 f_show_err "$msg_group_not_found" "$input" 389 return $FAILURE 390 fi 391 392 f_isset $VAR_GROUP_GID && f_getvar $VAR_GROUP_GID group_gid 393 local null_members= 394 if f_isset $VAR_GROUP_MEMBERS; then 395 f_getvar $VAR_GROUP_MEMBERS group_members 396 [ "$group_members" ] || null_members=1 397 fi 398 local group_password_disable= 399 if f_isset $VAR_GROUP_PASSWORD; then 400 f_getvar $VAR_GROUP_PASSWORD group_password 401 [ "$group_password" ] || group_password_disable=1 402 fi 403 404 # 405 # Loop until the user decides to Exit, Cancel, or presses ESC 406 # 407 title="$msg_edit_view $msg_group: $group_name" 408 if f_interactive; then 409 local mtag retval defaultitem= 410 while :; do 411 f_dialog_title "$title" 412 f_dialog_menu_group_edit "$defaultitem" 413 retval=$? 414 f_dialog_title_restore 415 f_dialog_menutag_fetch mtag 416 f_dprintf "retval=%u mtag=[%s]" $retval "$mtag" 417 defaultitem="$mtag" 418 419 # Return if user either pressed ESC or chose Cancel/No 420 [ $retval -eq $DIALOG_OK ] || return $FAILURE 421 422 case "$mtag" in 423 X) # Save/Exit 424 local var 425 for var in gid members name; do 426 local _group_$var 427 eval f_shell_escape \ 428 \"\$group_$var\" _group_$var 429 done 430 431 local cmd="pw groupmod -n '$_group_name'" 432 [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'" 433 [ "$group_members" -o "$null_members" ] && 434 cmd="$cmd -M '$_group_members'" 435 436 # Execute the command (break on success) 437 if [ "$group_password_disable" ]; then 438 f_eval_catch $funcname pw '%s -h -' "$cmd" 439 elif [ "$group_password" ]; then 440 echo "$group_password" | f_eval_catch \ 441 $funcname pw '%s -h 0' "$cmd" 442 else 443 f_eval_catch $funcname pw '%s' "$cmd" 444 fi && break 445 ;; 446 1) # Group Name (select different group from list) 447 f_dialog_menu_group_list "$group_name" || continue 448 f_dialog_menutag_fetch mtag 449 450 [ "$mtag" = "X $msg_exit" ] && continue 451 452 if ! f_input_group "$mtag"; then 453 f_show_err "$msg_group_not_found" "$mtag" 454 # Attempt to fall back to previous selection 455 f_input_group "$input" || return $FAILURE 456 else 457 input="$mtag" 458 fi 459 title="$msg_edit_view $msg_group: $group_name" 460 ;; 461 2) # Password 462 f_dialog_input_group_password group_password \ 463 group_password_disable 464 ;; 465 3) # Group ID 466 f_dialog_input_group_gid group_gid "$group_gid" 467 ;; 468 4) # Group Members 469 f_dialog_input_group_members group_members \ 470 "$group_members" && [ ! "$group_members" ] && 471 null_members=1 472 ;; 473 esac 474 done 475 else 476 local var 477 for var in gid members name; do 478 local _group_$var 479 eval f_shell_escape \"\$group_$var\" _group_$var 480 done 481 482 # Form the command 483 local cmd="pw groupmod -n '$_group_name'" 484 [ "$group_gid" ] && cmd="$cmd -g '$_group_gid'" 485 [ "$group_members" -o "$null_members" ] && 486 cmd="$cmd -M '$_group_members'" 487 488 # Execute the command 489 local retval err 490 if [ "$group_password_disable" ]; then 491 f_eval_catch -k err $funcname pw '%s -h -' "$cmd" 492 elif [ "$group_password" -o "$null_password" ]; then 493 err=$( echo "$group_password" | f_eval_catch -de \ 494 $funcname pw '%s -h 0' "$cmd" 2>&1 ) 495 else 496 f_eval_catch -k err $funcname pw '%s' "$cmd" 497 fi 498 retval=$? 499 if [ $retval -ne $SUCCESS ]; then 500 f_show_err "%s" "$err" 501 return $retval 502 fi 503 fi 504 505 f_dialog_title "$title" 506 $alert "$msg_group_updated" 507 f_dialog_title_restore 508 [ "$no_confirm" -a "$USE_DIALOG" ] && sleep 1 509 510 return $SUCCESS 511} 512 513############################################################ MAIN 514 515f_dprintf "%s: Successfully loaded." usermgmt/group.subr 516 517fi # ! $_USERMGMT_GROUP_SUBR 518