mustberoot.subr revision 251236
1227825Stheravenif [ ! "$_MUSTBEROOT_SUBR" ]; then _MUSTBEROOT_SUBR=1 2227825Stheraven# 3227825Stheraven# Copyright (c) 2006-2013 Devin Teske 4227825Stheraven# All Rights Reserved. 5227825Stheraven# 6227825Stheraven# Redistribution and use in source and binary forms, with or without 7227825Stheraven# modification, are permitted provided that the following conditions 8227825Stheraven# are met: 9227825Stheraven# 1. Redistributions of source code must retain the above copyright 10227825Stheraven# notice, this list of conditions and the following disclaimer. 11227825Stheraven# 2. Redistributions in binary form must reproduce the above copyright 12227825Stheraven# notice, this list of conditions and the following disclaimer in the 13227825Stheraven# documentation and/or other materials provided with the distribution. 14227825Stheraven# 15227825Stheraven# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16227825Stheraven# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE 17227825Stheraven# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18227825Stheraven# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19227825Stheraven# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20227825Stheraven# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21227825Stheraven# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22227825Stheraven# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23227825Stheraven# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24227825Stheraven# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25227825Stheraven# SUCH DAMAGE. 26227825Stheraven# 27227825Stheraven# $FreeBSD: head/usr.sbin/bsdconfig/share/mustberoot.subr 251236 2013-06-01 23:58:44Z dteske $ 28227825Stheraven# 29227825Stheraven############################################################ INCLUDES 30227825Stheraven 31227825StheravenBSDCFG_SHARE="/usr/share/bsdconfig" 32227825Stheraven. $BSDCFG_SHARE/common.subr || exit 1 33227825Stheravenf_dprintf "%s: loading includes..." mustberoot.subr 34227825Stheravenf_include $BSDCFG_SHARE/dialog.subr 35227825Stheraven 36227825StheravenBSDCFG_LIBE="/usr/libexec/bsdconfig" 37227825Stheravenf_include_lang $BSDCFG_LIBE/include/messages.subr 38227825Stheraven 39227825Stheraven############################################################ CONFIGURATION 40227825Stheraven# NOTE: These are not able to be overridden/inherited for security purposes. 41227825Stheraven 42227825Stheraven# 43227825Stheraven# Number of tries a user gets to enter his/her password before we log the 44227825Stheraven# sudo(8) failure and exit. 45227825Stheraven# 46227825StheravenPASSWD_TRIES=3 47227825Stheraven 48227825Stheraven# 49227825Stheraven# While in SECURE mode, should authentication as `root' be allowed? Set to 50227825Stheraven# non-NULL to enable authentication as `root', otherwise disabled. 51227825Stheraven# 52227825Stheraven# WARNING: 53227825Stheraven# Unless using a custom sudo(8) configuration, user `root' should not be 54227825Stheraven# allowed because no password is required to become `root' when already `root' 55227825Stheraven# and therefore, any value entered as password will work. 56227825Stheraven# 57227825StheravenSECURE_ALLOW_ROOT= 58227825Stheraven 59227825Stheraven# 60227825Stheraven# While in SECURE mode, should we divulge (through error message) when the 61227825Stheraven# requested authentication user does not exist? Set to non-NULL to enable, 62227825Stheraven# otherwise a non-existent user is treated like an invalid password. 63227825Stheraven# 64227825StheravenSECURE_DIVULGE_UNKNOWN_USER= 65227825Stheraven 66227825Stheraven############################################################ FUNCTIONS 67227825Stheraven 68227825Stheraven# f_become_root_via_sudo 69227825Stheraven# 70227825Stheraven# If not running as root, prompt for sudo(8) credentials to become root. 71227825Stheraven# Re-execution of the current program via sudo is automatically handled. 72227825Stheraven# 73227825Stheraven# The following environment variables effect functionality: 74227825Stheraven# 75227825Stheraven# USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate 76227825Stheraven# that Xdialog(1) should be used instead of dialog(1). 77227825Stheraven# 78227825Stheravenf_become_root_via_sudo() 79227825Stheraven{ 80227825Stheraven local msg hline height width rows 81227825Stheraven 82227825Stheraven [ "$( id -u )" = "0" ] && return $SUCCESS 83227825Stheraven 84227825Stheraven f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm" 85227825Stheraven 86227825Stheraven # 87227825Stheraven # Ask the user if it's OK to become root via sudo(8) and give them 88227825Stheraven # the option to save this preference (by touch(1)ing a file in the 89227825Stheraven # user's $HOME directory). 90227825Stheraven # 91227825Stheraven local checkpath="${HOME%/}/.bsdconfig_uses_sudo" 92227825Stheraven if [ ! -e "$checkpath" ]; then 93227825Stheraven msg=$( printf "$msg_always_try_sudo_when_run_as" "$USER" ) 94227825Stheraven local menu_list=" 95227825Stheraven 'X' '$msg_cancel_exit' 96227825Stheraven '1' '$msg' 97227825Stheraven '2' '$msg_try_sudo_only_this_once' 98227825Stheraven " # END-QUOTE 99227825Stheraven msg=$( printf "$msg_you_are_not_root_but" bsdconfig ) 100227825Stheraven hline="$hline_arrows_tab_enter" 101227825Stheraven eval f_dialog_menu_size height width rows \ 102227825Stheraven \"\$DIALOG_TITLE\" \ 103227825Stheraven \"\$DIALOG_BACKTITLE\" \ 104227825Stheraven \"\$msg\" \ 105227825Stheraven \"\$hline\" \ 106227825Stheraven $menu_list 107227825Stheraven 108227825Stheraven local mtag 109227825Stheraven mtag=$( eval $DIALOG \ 110227825Stheraven --title \"\$DIALOG_TITLE\" \ 111227825Stheraven --backtitle \"\$DIALOG_BACKTITLE\" \ 112227825Stheraven --hline \"\$hline\" \ 113227825Stheraven --ok-label \"\$msg_ok\" \ 114227825Stheraven --cancel-label \"\$msg_cancel\" \ 115227825Stheraven --menu \"\$msg\" \ 116227825Stheraven $height $width $rows \ 117227825Stheraven $menu_list \ 118227825Stheraven 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD 119227825Stheraven ) || f_die 120227825Stheraven f_dialog_data_sanitize mtag 121227825Stheraven 122227825Stheraven case "$mtag" in 123227825Stheraven X) # Cancel/Exit 124227825Stheraven f_die ;; 125227825Stheraven 1) # Always try sudo(8) when run as $user 126227825Stheraven local err 127227825Stheraven if ! err=$( touch "$checkpath" 2>&1 ); then 128227825Stheraven f_dialog_msgbox "$err" 129227825Stheraven else 130227825Stheraven f_show_msg "$msg_created_path" "$checkpath" 131227825Stheraven fi 132227825Stheraven esac 133227825Stheraven else 134227825Stheraven # 135227825Stheraven # This user has created the path signing-off on sudo(8)-use 136227825Stheraven # but let's still give them a short/quick/unobtrusive reminder 137227825Stheraven # 138227825Stheraven f_dialog_info "$msg_becoming_root_via_sudo" 139227825Stheraven [ "$USE_XDIALOG" ] || sleep 0.6 140227825Stheraven fi 141227825Stheraven 142227825Stheraven # 143227825Stheraven # Check sudo(8) access before prompting for password. 144227825Stheraven # 145227825Stheraven :| sudo -S -v 2> /dev/null 146227825Stheraven if [ $? -ne $SUCCESS ]; then 147227825Stheraven # 148227825Stheraven # sudo(8) access denied. Prompt for their password. 149227825Stheraven # 150227825Stheraven msg="$msg_please_enter_password" 151227825Stheraven hline="$hline_alnum_punc_tab_enter" 152227825Stheraven f_dialog_inputbox_size height width \ 153227825Stheraven "$DIALOG_TITLE" \ 154227825Stheraven "$DIALOG_BACKTITLE" \ 155227825Stheraven "$msg" \ 156227825Stheraven "$hline" 157227825Stheraven 158227825Stheraven # 159227825Stheraven # Continue prompting until they either Cancel, succeed 160227825Stheraven # or exceed the number of allowed failures. 161227825Stheraven # 162227825Stheraven local password nfailures=0 retval 163227825Stheraven while [ $nfailures -lt $PASSWD_TRIES ]; do 164227825Stheraven if [ "$USE_XDIALOG" ]; then 165227825Stheraven password=$( $DIALOG \ 166227825Stheraven --title "$DIALOG_TITLE" \ 167227825Stheraven --backtitle "$DIALOG_BACKTITLE" \ 168227825Stheraven --hline "$hline" \ 169227825Stheraven --ok-label "$msg_ok" \ 170227825Stheraven --cancel-label "$msg_cancel" \ 171227825Stheraven --password --inputbox "$msg" \ 172227825Stheraven $height $width \ 173227825Stheraven 2>&1 > /dev/null ) 174227825Stheraven retval=$? 175227825Stheraven 176227825Stheraven # Catch X11-related errors 177227825Stheraven [ $retval -eq 255 ] && 178227825Stheraven f_die $retval "$password" 179227825Stheraven else 180227825Stheraven local dialog_inputbox 181227825Stheraven dialog_inputbox=$( $DIALOG \ 182227825Stheraven --title "$DIALOG_TITLE" \ 183227825Stheraven --backtitle "$DIALOG_BACKTITLE" \ 184227825Stheraven --hline "$hline" \ 185227825Stheraven --ok-label "$msg_ok" \ 186227825Stheraven --cancel-label "$msg_cancel" \ 187227825Stheraven --insecure \ 188227825Stheraven --passwordbox "$msg" \ 189227825Stheraven $height $width \ 190227825Stheraven 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD 191227825Stheraven ) 192227825Stheraven retval=$? 193227825Stheraven setvar DIALOG_INPUTBOX_$$ "$dialog_inputbox" 194227825Stheraven password=$( f_dialog_inputstr ) 195227825Stheraven fi 196227825Stheraven 197227825Stheraven # Exit if the user cancelled. 198227825Stheraven [ $retval -eq $SUCCESS ] || exit $retval 199227825Stheraven 200227825Stheraven # 201227825Stheraven # Validate sudo(8) credentials 202227825Stheraven # 203227825Stheraven sudo -S -v 2> /dev/null <<-EOF 204227825Stheraven $password 205227825Stheraven EOF 206227825Stheraven retval=$? 207227825Stheraven unset password # scrub memory 208227825Stheraven if [ $retval -eq $SUCCESS ]; then 209227825Stheraven # Access granted... 210227825Stheraven break 211227825Stheraven else 212227825Stheraven # Access denied... 213227825Stheraven nfailures=$(( $nfailures + 1 )) 214227825Stheraven 215227825Stheraven # introduce a short delay 216227825Stheraven if [ $nfailures -lt $PASSWD_TRIES ]; then 217227825Stheraven f_dialog_info "$msg_sorry_try_again" 218227825Stheraven sleep 1 219227825Stheraven fi 220227825Stheraven fi 221227825Stheraven done 222227825Stheraven 223227825Stheraven # 224227825Stheraven # If user exhausted number of allowed password tries, log 225227825Stheraven # the security event and exit immediately. 226227825Stheraven # 227227825Stheraven if [ $nfailures -ge $PASSWD_TRIES ]; then 228227825Stheraven msg=$( printf "$msg_nfailed_attempts" "$nfailures" ) 229227825Stheraven logger -p auth.notice -t sudo " " \ 230227825Stheraven "$USER : $msg" \ 231227825Stheraven "; TTY=$(tty)" \ 232227825Stheraven "; PWD=$PWD" \ 233227825Stheraven "; USER=root" \ 234227825Stheraven "; COMMAND=$0" 235227825Stheraven f_die 1 "sudo: $msg" 236227825Stheraven fi 237227825Stheraven fi 238227825Stheraven 239227825Stheraven # Use xauth(1) to grant root the ability to use this X11/SSH session 240227825Stheraven if [ "$USE_XDIALOG" -a "$SSH_CONNECTION" -a "$DISPLAY" ]; then 241227825Stheraven f_have xauth || f_die 1 \ 242227825Stheraven "$msg_no_such_file_or_directory" "$pgm" "xauth" 243227825Stheraven local HOSTNAME displaynum 244227825Stheraven HOSTNAME=$(hostname) 245227825Stheraven displaynum="${DISPLAY#*:}" 246227825Stheraven xauth -f ~/.Xauthority extract - $HOSTNAME/unix:$displaynum \ 247227825Stheraven $HOSTNAME:$displaynum | sudo sh -c 'xauth -ivf \ 248227825Stheraven ~root/.Xauthority merge - > /dev/null 2>&1' 249227825Stheraven fi 250227825Stheraven 251227825Stheraven # Re-execute ourselves with sudo(8) 252227825Stheraven f_dprintf "%s: Becoming root via sudo(8)..." mustberoot.subr 253227825Stheraven if [ $ARGC -gt 0 ]; then 254227825Stheraven exec sudo "$0" $ARGV 255227825Stheraven else 256227825Stheraven exec sudo "$0" 257227825Stheraven fi 258227825Stheraven exit $? # Never reached unless error 259227825Stheraven} 260227825Stheraven 261227825Stheraven# f_authenticate_some_user 262227825Stheraven# 263227825Stheraven# Only used if running as root and requires X11 (see USE_XDIALOG below). 264227825Stheraven# Prompts the user to enter a username and password to be authenticated via 265227825Stheraven# sudo(8) to proceed. 266227825Stheraven# 267227825Stheraven# The following environment variables effect functionality: 268227825Stheraven# 269227825Stheraven# USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate 270227825Stheraven# that Xdialog(1) should be used instead of dialog(1). 271227825Stheraven# 272227825Stheravenf_authenticate_some_user() 273227825Stheraven{ 274227825Stheraven local msg hline height width 275227825Stheraven 276227825Stheraven f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm" 277227825Stheraven 278227825Stheraven # 279227825Stheraven # Secure-mode has been requested. 280227825Stheraven # 281227825Stheraven 282227825Stheraven [ "$USE_XDIALOG" ] || f_die 1 "$msg_secure_mode_requires_x11" 283227825Stheraven [ "$(id -u)" = "0" ] || f_die 1 "$msg_secure_mode_requires_root" 284227825Stheraven 285227825Stheraven # 286227825Stheraven # Prompt for sudo(8) credentials. 287227825Stheraven # 288227825Stheraven 289227825Stheraven msg="$msg_please_enter_username_password" 290227825Stheraven hline="$hline_alnum_punc_tab_enter" 291227825Stheraven f_xdialog_2inputsbox_size height width \ 292227825Stheraven "$DIALOG_TITLE" \ 293227825Stheraven "$DIALOG_BACKTITLE" \ 294227825Stheraven "$msg" \ 295227825Stheraven "$field_username" "" \ 296227825Stheraven "$field_password" "" 297227825Stheraven height=$(( $height + 2 )) # Add height for --password 298227825Stheraven 299227825Stheraven # 300227825Stheraven # Continue prompting until they either Cancel, succeed or exceed the 301227825Stheraven # number of allowed failures. 302227825Stheraven # 303227825Stheraven local user_pass nfailures=0 retval 304227825Stheraven while [ $nfailures -lt $PASSWD_TRIES ]; do 305227825Stheraven user_pass=$( $DIALOG \ 306227825Stheraven --title "$DIALOG_TITLE" \ 307227825Stheraven --backtitle "$DIALOG_BACKTITLE" \ 308227825Stheraven --hline "$hline" \ 309227825Stheraven --ok-label "$msg_ok" \ 310227825Stheraven --cancel-label "$msg_cancel" \ 311227825Stheraven --password --2inputsbox "$msg" \ 312227825Stheraven $height $width \ 313227825Stheraven "$field_username" "" \ 314227825Stheraven "$field_password" "" \ 315227825Stheraven 2>&1 > /dev/null ) 316227825Stheraven retval=$? 317227825Stheraven 318227825Stheraven # Catch X11-related errors 319227825Stheraven [ $retval -eq 255 ] && f_die $retval "$user_pass" 320227825Stheraven 321227825Stheraven # Exit if the user cancelled. 322227825Stheraven [ $retval -eq $SUCCESS ] || exit $retval 323227825Stheraven 324227825Stheraven # 325227825Stheraven # Make sure the user exists and is non-root 326227825Stheraven # 327227825Stheraven local user password 328227825Stheraven user="${user_pass%%/*}" 329227825Stheraven password="${user_pass#*/}" 330227825Stheraven unset user_pass # scrub memory 331227825Stheraven if [ ! "$user" ]; then 332227825Stheraven nfailures=$(( $nfailures + 1 )) 333227825Stheraven f_dialog_msgbox "$msg_no_username" 334227825Stheraven continue 335227825Stheraven fi 336227825Stheraven if [ ! "$SECURE_ALLOW_ROOT" ]; then 337227825Stheraven case "$user" in 338227825Stheraven root|toor) 339227825Stheraven nfailures=$(( $nfailures + 1 )) 340227825Stheraven f_show_msg "$msg_user_disallowed" "$user" 341227825Stheraven continue 342227825Stheraven esac 343227825Stheraven fi 344227825Stheraven if ! f_quietly id "$user"; then 345227825Stheraven nfailures=$(( $nfailures + 1 )) 346227825Stheraven if [ "$SECURE_DIVULGE_UNKNOWN_USER" ]; then 347227825Stheraven f_show_msg "$msg_unknown_user" "$user" 348227825Stheraven elif [ $nfailures -lt $PASSWD_TRIES ]; then 349227825Stheraven f_dialog_info "$msg_sorry_try_again" 350227825Stheraven sleep 1 351227825Stheraven fi 352227825Stheraven continue 353227825Stheraven fi 354227825Stheraven 355227825Stheraven # 356227825Stheraven # Validate sudo(8) credentials for given user 357227825Stheraven # 358227825Stheraven su -m "$user" <<-EOF 359227825Stheraven sh <<EOS 360227825Stheraven sudo -k 361227825Stheraven sudo -S -v 2> /dev/null <<EOP 362227825Stheraven $password 363227825Stheraven EOP 364227825Stheraven EOS 365227825Stheraven EOF 366227825Stheraven retval=$? 367227825Stheraven unset user 368227825Stheraven unset password # scrub memory 369227825Stheraven 370227825Stheraven if [ $retval -eq $SUCCESS ]; then 371227825Stheraven # Access granted... 372227825Stheraven break 373227825Stheraven else 374227825Stheraven # Access denied... 375227825Stheraven nfailures=$(( $nfailures + 1 )) 376227825Stheraven 377227825Stheraven # introduce a short delay 378227825Stheraven if [ $nfailures -lt $PASSWD_TRIES ]; then 379227825Stheraven f_dialog_info "$msg_sorry_try_again" 380227825Stheraven sleep 1 381227825Stheraven fi 382227825Stheraven fi 383227825Stheraven done 384227825Stheraven 385227825Stheraven # 386227825Stheraven # If user exhausted number of allowed password tries, log 387227825Stheraven # the security event and exit immediately. 388227825Stheraven # 389227825Stheraven if [ $nfailures -ge $PASSWD_TRIES ]; then 390227825Stheraven msg=$( printf "$msg_nfailed_attempts" "$nfailures" ) 391227825Stheraven logger -p auth.notice -t sudo " " \ 392227825Stheraven "${SUDO_USER:-$USER} : $msg" \ 393227825Stheraven "; TTY=$(tty)" \ 394227825Stheraven "; PWD=$PWD" \ 395227825Stheraven "; USER=root" \ 396227825Stheraven "; COMMAND=$0" 397227825Stheraven f_die 1 "sudo: $message" 398227825Stheraven fi 399227825Stheraven} 400227825Stheraven 401227825Stheraven# f_mustberoot_init 402227825Stheraven# 403227825Stheraven# If not already root, make the switch to root by re-executing ourselves via 404227825Stheraven# sudo(8) using user-supplied credentials. 405227825Stheraven# 406227825Stheraven# The following environment variables effect functionality: 407227825Stheraven# 408227825Stheraven# SECURE Either NULL or Non-NULL. If given a value will indicate 409227825Stheraven# that (while running as root) sudo(8) authentication is 410227825Stheraven# required to proceed. 411227825Stheraven# 412227825Stheravenf_mustberoot_init() 413227825Stheraven{ 414227825Stheraven if [ "$(id -u)" != "0" -a ! "$SECURE" ]; then 415227825Stheraven f_become_root_via_sudo 416227825Stheraven elif [ "$SECURE" ]; then 417227825Stheraven f_authenticate_some_user 418227825Stheraven fi 419227825Stheraven} 420227825Stheraven 421227825Stheraven############################################################ MAIN 422227825Stheraven 423227825Stheravenf_dprintf "%s: Successfully loaded." mustberoot.subr 424227825Stheraven 425227825Stheravenfi # ! $_MUSTBEROOT_SUBR 426227825Stheraven