1if [ ! "$_MUSTBEROOT_SUBR" ]; then _MUSTBEROOT_SUBR=1 2# 3# Copyright (c) 2006-2013 Devin Teske 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25# SUCH DAMAGE. 26# 27# 28############################################################ INCLUDES 29 30BSDCFG_SHARE="/usr/share/bsdconfig" 31. $BSDCFG_SHARE/common.subr || exit 1 32f_dprintf "%s: loading includes..." mustberoot.subr 33f_include $BSDCFG_SHARE/dialog.subr 34f_include $BSDCFG_SHARE/strings.subr 35 36BSDCFG_LIBE="/usr/libexec/bsdconfig" 37f_include_lang $BSDCFG_LIBE/include/messages.subr 38 39############################################################ CONFIGURATION 40# NOTE: These are not able to be overridden/inherited for security purposes. 41 42# 43# Number of tries a user gets to enter his/her password before we log the 44# sudo(8) failure and exit. 45# 46PASSWD_TRIES=3 47 48# 49# While in SECURE mode, should authentication as `root' be allowed? Set to 50# non-NULL to enable authentication as `root', otherwise disabled. 51# 52# WARNING: 53# Unless using a custom sudo(8) configuration, user `root' should not be 54# allowed because no password is required to become `root' when already `root' 55# and therefore, any value entered as password will work. 56# 57SECURE_ALLOW_ROOT= 58 59# 60# While in SECURE mode, should we divulge (through error message) when the 61# requested authentication user does not exist? Set to non-NULL to enable, 62# otherwise a non-existent user is treated like an invalid password. 63# 64SECURE_DIVULGE_UNKNOWN_USER= 65 66############################################################ FUNCTIONS 67 68# f_become_root_via_sudo 69# 70# If not running as root, prompt for sudo(8) credentials to become root. 71# Re-execution of the current program via sudo is automatically handled. 72# 73# The following environment variables effect functionality: 74# 75# USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate 76# that Xdialog(1) should be used instead of dialog(1). 77# 78f_become_root_via_sudo() 79{ 80 local funcname=f_become_root_via_sudo 81 local prompt hline height width rows msg 82 83 [ "$( id -u )" = "0" ] && return $SUCCESS 84 85 f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm" 86 87 # 88 # Ask the user if it's OK to become root via sudo(8) and give them 89 # the option to save this preference (by touch(1)ing a file in the 90 # user's $HOME directory). 91 # 92 local checkpath="${HOME%/}/.bsdconfig_uses_sudo" 93 if [ ! -e "$checkpath" ]; then 94 f_sprintf prompt "$msg_you_are_not_root_but" bsdconfig 95 f_sprintf msg "$msg_always_try_sudo_when_run_as" "$USER" 96 local menu_list=" 97 'X' '$msg_cancel_exit' 98 '1' '$msg' 99 '2' '$msg_try_sudo_only_this_once' 100 " # END-QUOTE 101 hline="$hline_arrows_tab_enter" 102 103 eval f_dialog_menu_size height width rows \ 104 \"\$DIALOG_TITLE\" \ 105 \"\$DIALOG_BACKTITLE\" \ 106 \"\$prompt\" \ 107 \"\$hline\" \ 108 $menu_list 109 110 local mtag 111 mtag=$( eval $DIALOG \ 112 --title \"\$DIALOG_TITLE\" \ 113 --backtitle \"\$DIALOG_BACKTITLE\" \ 114 --hline \"\$hline\" \ 115 --ok-label \"\$msg_ok\" \ 116 --cancel-label \"\$msg_cancel\" \ 117 --menu \"\$prompt\" \ 118 $height $width $rows \ 119 $menu_list \ 120 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD 121 ) || f_die 122 f_dialog_data_sanitize mtag 123 124 case "$mtag" in 125 X) # Cancel/Exit 126 f_die ;; 127 1) # Always try sudo(8) when run as $user 128 f_eval_catch $funcname touch \ 129 'touch "%s"' "$checkpath" && 130 f_show_msg "$msg_created_path" "$checkpath" 131 esac 132 else 133 # 134 # This user has created the path signing-off on sudo(8)-use 135 # but let's still give them a short/quick/unobtrusive reminder 136 # 137 f_dialog_info "$msg_becoming_root_via_sudo" 138 [ "$USE_XDIALOG" ] || sleep 0.6 139 fi 140 141 # 142 # Check sudo(8) access before prompting for password. 143 # 144 :| sudo -S -v 2> /dev/null 145 if [ $? -ne $SUCCESS ]; then 146 # 147 # sudo(8) access denied. Prompt for their password. 148 # 149 prompt="$msg_please_enter_password" 150 hline="$hline_alnum_punc_tab_enter" 151 f_dialog_inputbox_size height width \ 152 "$DIALOG_TITLE" \ 153 "$DIALOG_BACKTITLE" \ 154 "$prompt" \ 155 "$hline" 156 157 # 158 # Continue prompting until they either Cancel, succeed 159 # or exceed the number of allowed failures. 160 # 161 local password nfailures=0 retval 162 while [ $nfailures -lt $PASSWD_TRIES ]; do 163 if [ "$USE_XDIALOG" ]; then 164 password=$( $DIALOG \ 165 --title "$DIALOG_TITLE" \ 166 --backtitle "$DIALOG_BACKTITLE" \ 167 --hline "$hline" \ 168 --ok-label "$msg_ok" \ 169 --cancel-label "$msg_cancel" \ 170 --password --inputbox "$prompt" \ 171 $height $width \ 172 2>&1 > /dev/null 173 ) 174 retval=$? 175 176 # Catch X11-related errors 177 if [ $retval -eq $DIALOG_ESC ]; then 178 f_die $retval "$password" 179 elif [ $retval -ne $DIALOG_OK ]; then 180 # User cancelled 181 exit $retval 182 fi 183 else 184 password=$( $DIALOG \ 185 --title "$DIALOG_TITLE" \ 186 --backtitle "$DIALOG_BACKTITLE" \ 187 --hline "$hline" \ 188 --ok-label "$msg_ok" \ 189 --cancel-label "$msg_cancel" \ 190 --insecure \ 191 --passwordbox "$prompt" \ 192 $height $width \ 193 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD 194 ) || exit $? 195 fi 196 debug= f_dialog_line_sanitize password 197 198 # 199 # Validate sudo(8) credentials 200 # 201 sudo -S -v 2> /dev/null <<-EOF 202 $password 203 EOF 204 retval=$? 205 unset password # scrub memory 206 if [ $retval -eq $SUCCESS ]; then 207 # Access granted... 208 break 209 else 210 # Access denied... 211 nfailures=$(( $nfailures + 1 )) 212 213 # introduce a short delay 214 if [ $nfailures -lt $PASSWD_TRIES ]; then 215 f_dialog_info "$msg_sorry_try_again" 216 sleep 1 217 fi 218 fi 219 done 220 221 # 222 # If user exhausted number of allowed password tries, log 223 # the security event and exit immediately. 224 # 225 if [ $nfailures -ge $PASSWD_TRIES ]; then 226 f_sprintf msg "$msg_nfailed_attempts" "$nfailures" 227 logger -p auth.notice -t sudo " " \ 228 "$USER : $msg" \ 229 "; TTY=$(tty)" \ 230 "; PWD=$PWD" \ 231 "; USER=root" \ 232 "; COMMAND=$0" 233 f_die 1 "sudo: $msg" 234 fi 235 fi 236 237 # Use xauth(1) to grant root the ability to use this X11/SSH session 238 if [ "$USE_XDIALOG" -a "$SSH_CONNECTION" -a "$DISPLAY" ]; then 239 f_have xauth || f_die 1 \ 240 "$msg_no_such_file_or_directory" "$pgm" "xauth" 241 local HOSTNAME displaynum 242 HOSTNAME=$(hostname) 243 displaynum="${DISPLAY#*:}" 244 xauth -f ~/.Xauthority extract - $HOSTNAME/unix:$displaynum \ 245 $HOSTNAME:$displaynum | sudo sh -c 'xauth -ivf \ 246 ~root/.Xauthority merge - > /dev/null 2>&1' 247 fi 248 249 # Re-execute ourselves with sudo(8) 250 f_dprintf "%s: Becoming root via sudo(8)..." mustberoot.subr 251 if [ $ARGC -gt 0 ]; then 252 exec sudo "$0" $ARGV 253 else 254 exec sudo "$0" 255 fi 256 exit $? # Never reached unless error 257} 258 259# f_authenticate_some_user 260# 261# Only used if running as root and requires X11 (see USE_XDIALOG below). 262# Prompts the user to enter a username and password to be authenticated via 263# sudo(8) to proceed. 264# 265# The following environment variables effect functionality: 266# 267# USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate 268# that Xdialog(1) should be used instead of dialog(1). 269# 270f_authenticate_some_user() 271{ 272 local msg hline height width 273 274 f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm" 275 276 # 277 # Secure-mode has been requested. 278 # 279 280 [ "$USE_XDIALOG" ] || f_die 1 "$msg_secure_mode_requires_x11" 281 [ "$(id -u)" = "0" ] || f_die 1 "$msg_secure_mode_requires_root" 282 283 # 284 # Prompt for sudo(8) credentials. 285 # 286 287 msg="$msg_please_enter_username_password" 288 hline="$hline_alnum_punc_tab_enter" 289 f_xdialog_2inputsbox_size height width \ 290 "$DIALOG_TITLE" \ 291 "$DIALOG_BACKTITLE" \ 292 "$msg" \ 293 "$field_username" "" \ 294 "$field_password" "" 295 height=$(( $height + 2 )) # Add height for --password 296 297 # 298 # Continue prompting until they either Cancel, succeed or exceed the 299 # number of allowed failures. 300 # 301 local user_pass nfailures=0 retval 302 while [ $nfailures -lt $PASSWD_TRIES ]; do 303 user_pass=$( $DIALOG \ 304 --title "$DIALOG_TITLE" \ 305 --backtitle "$DIALOG_BACKTITLE" \ 306 --hline "$hline" \ 307 --ok-label "$msg_ok" \ 308 --cancel-label "$msg_cancel" \ 309 --password --2inputsbox "$msg" \ 310 $height $width \ 311 "$field_username" "" \ 312 "$field_password" "" \ 313 2>&1 > /dev/null ) 314 retval=$? 315 316 # Catch X11-related errors 317 [ $retval -eq $DIALOG_ESC ] && f_die $retval "$user_pass" 318 319 # Exit if the user cancelled. 320 [ $retval -eq $DIALOG_OK ] || exit $retval 321 322 # 323 # Make sure the user exists and is non-root 324 # 325 local user password 326 user="${user_pass%%/*}" 327 password="${user_pass#*/}" 328 unset user_pass # scrub memory 329 if [ ! "$user" ]; then 330 nfailures=$(( $nfailures + 1 )) 331 f_show_msg "$msg_no_username" 332 continue 333 fi 334 if [ ! "$SECURE_ALLOW_ROOT" ]; then 335 case "$user" in 336 root|toor) 337 nfailures=$(( $nfailures + 1 )) 338 f_show_msg "$msg_user_disallowed" "$user" 339 continue 340 esac 341 fi 342 if ! f_quietly id "$user"; then 343 nfailures=$(( $nfailures + 1 )) 344 if [ "$SECURE_DIVULGE_UNKNOWN_USER" ]; then 345 f_show_msg "$msg_unknown_user" "$user" 346 elif [ $nfailures -lt $PASSWD_TRIES ]; then 347 f_dialog_info "$msg_sorry_try_again" 348 sleep 1 349 fi 350 continue 351 fi 352 353 # 354 # Validate sudo(8) credentials for given user 355 # 356 su -m "$user" <<-EOF 357 sh <<EOS 358 sudo -k 359 sudo -S -v 2> /dev/null <<EOP 360 $password 361 EOP 362 EOS 363 EOF 364 retval=$? 365 unset user 366 unset password # scrub memory 367 368 if [ $retval -eq $SUCCESS ]; then 369 # Access granted... 370 break 371 else 372 # Access denied... 373 nfailures=$(( $nfailures + 1 )) 374 375 # introduce a short delay 376 if [ $nfailures -lt $PASSWD_TRIES ]; then 377 f_dialog_info "$msg_sorry_try_again" 378 sleep 1 379 fi 380 fi 381 done 382 383 # 384 # If user exhausted number of allowed password tries, log 385 # the security event and exit immediately. 386 # 387 if [ $nfailures -ge $PASSWD_TRIES ]; then 388 f_sprintf msg "$msg_nfailed_attempts" "$nfailures" 389 logger -p auth.notice -t sudo " " \ 390 "${SUDO_USER:-$USER} : $msg" \ 391 "; TTY=$(tty)" \ 392 "; PWD=$PWD" \ 393 "; USER=root" \ 394 "; COMMAND=$0" 395 f_die 1 "sudo: $message" 396 fi 397} 398 399# f_mustberoot_init 400# 401# If not already root, make the switch to root by re-executing ourselves via 402# sudo(8) using user-supplied credentials. 403# 404# The following environment variables effect functionality: 405# 406# SECURE Either NULL or Non-NULL. If given a value will indicate 407# that (while running as root) sudo(8) authentication is 408# required to proceed. 409# 410f_mustberoot_init() 411{ 412 if [ "$(id -u)" != "0" -a ! "$SECURE" ]; then 413 f_become_root_via_sudo 414 elif [ "$SECURE" ]; then 415 f_authenticate_some_user 416 fi 417} 418 419############################################################ MAIN 420 421f_dprintf "%s: Successfully loaded." mustberoot.subr 422 423fi # ! $_MUSTBEROOT_SUBR 424