if [ ! "$_MUSTBEROOT_SUBR" ]; then _MUSTBEROOT_SUBR=1 # # Copyright (c) 2006-2013 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # ############################################################ INCLUDES BSDCFG_SHARE="/usr/share/bsdconfig" . $BSDCFG_SHARE/common.subr || exit 1 f_dprintf "%s: loading includes..." mustberoot.subr f_include $BSDCFG_SHARE/dialog.subr f_include $BSDCFG_SHARE/strings.subr BSDCFG_LIBE="/usr/libexec/bsdconfig" f_include_lang $BSDCFG_LIBE/include/messages.subr ############################################################ CONFIGURATION # NOTE: These are not able to be overridden/inherited for security purposes. # # Number of tries a user gets to enter his/her password before we log the # sudo(8) failure and exit. # PASSWD_TRIES=3 # # While in SECURE mode, should authentication as `root' be allowed? Set to # non-NULL to enable authentication as `root', otherwise disabled. # # WARNING: # Unless using a custom sudo(8) configuration, user `root' should not be # allowed because no password is required to become `root' when already `root' # and therefore, any value entered as password will work. # SECURE_ALLOW_ROOT= # # While in SECURE mode, should we divulge (through error message) when the # requested authentication user does not exist? Set to non-NULL to enable, # otherwise a non-existent user is treated like an invalid password. # SECURE_DIVULGE_UNKNOWN_USER= ############################################################ FUNCTIONS # f_become_root_via_sudo # # If not running as root, prompt for sudo(8) credentials to become root. # Re-execution of the current program via sudo is automatically handled. # # The following environment variables effect functionality: # # USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate # that Xdialog(1) should be used instead of dialog(1). # f_become_root_via_sudo() { local funcname=f_become_root_via_sudo local prompt hline height width rows msg [ "$( id -u )" = "0" ] && return $SUCCESS f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm" # # Ask the user if it's OK to become root via sudo(8) and give them # the option to save this preference (by touch(1)ing a file in the # user's $HOME directory). # local checkpath="${HOME%/}/.bsdconfig_uses_sudo" if [ ! -e "$checkpath" ]; then f_sprintf prompt "$msg_you_are_not_root_but" bsdconfig f_sprintf msg "$msg_always_try_sudo_when_run_as" "$USER" local menu_list=" 'X' '$msg_cancel_exit' '1' '$msg' '2' '$msg_try_sudo_only_this_once' " # END-QUOTE hline="$hline_arrows_tab_enter" eval f_dialog_menu_size height width rows \ \"\$DIALOG_TITLE\" \ \"\$DIALOG_BACKTITLE\" \ \"\$prompt\" \ \"\$hline\" \ $menu_list local mtag mtag=$( eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --hline \"\$hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_cancel\" \ --menu \"\$prompt\" \ $height $width $rows \ $menu_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) || f_die f_dialog_data_sanitize mtag case "$mtag" in X) # Cancel/Exit f_die ;; 1) # Always try sudo(8) when run as $user f_eval_catch $funcname touch \ 'touch "%s"' "$checkpath" && f_show_msg "$msg_created_path" "$checkpath" esac else # # This user has created the path signing-off on sudo(8)-use # but let's still give them a short/quick/unobtrusive reminder # f_dialog_info "$msg_becoming_root_via_sudo" [ "$USE_XDIALOG" ] || sleep 0.6 fi # # Check sudo(8) access before prompting for password. # :| sudo -S -v 2> /dev/null if [ $? -ne $SUCCESS ]; then # # sudo(8) access denied. Prompt for their password. # prompt="$msg_please_enter_password" hline="$hline_alnum_punc_tab_enter" f_dialog_inputbox_size height width \ "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$prompt" \ "$hline" # # Continue prompting until they either Cancel, succeed # or exceed the number of allowed failures. # local password nfailures=0 retval while [ $nfailures -lt $PASSWD_TRIES ]; do if [ "$USE_XDIALOG" ]; then password=$( $DIALOG \ --title "$DIALOG_TITLE" \ --backtitle "$DIALOG_BACKTITLE" \ --hline "$hline" \ --ok-label "$msg_ok" \ --cancel-label "$msg_cancel" \ --password --inputbox "$prompt" \ $height $width \ 2>&1 > /dev/null ) retval=$? # Catch X11-related errors if [ $retval -eq $DIALOG_ESC ]; then f_die $retval "$password" elif [ $retval -ne $DIALOG_OK ]; then # User cancelled exit $retval fi else password=$( $DIALOG \ --title "$DIALOG_TITLE" \ --backtitle "$DIALOG_BACKTITLE" \ --hline "$hline" \ --ok-label "$msg_ok" \ --cancel-label "$msg_cancel" \ --insecure \ --passwordbox "$prompt" \ $height $width \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) || exit $? fi debug= f_dialog_line_sanitize password # # Validate sudo(8) credentials # sudo -S -v 2> /dev/null <<-EOF $password EOF retval=$? unset password # scrub memory if [ $retval -eq $SUCCESS ]; then # Access granted... break else # Access denied... nfailures=$(( $nfailures + 1 )) # introduce a short delay if [ $nfailures -lt $PASSWD_TRIES ]; then f_dialog_info "$msg_sorry_try_again" sleep 1 fi fi done # # If user exhausted number of allowed password tries, log # the security event and exit immediately. # if [ $nfailures -ge $PASSWD_TRIES ]; then f_sprintf msg "$msg_nfailed_attempts" "$nfailures" logger -p auth.notice -t sudo " " \ "$USER : $msg" \ "; TTY=$(tty)" \ "; PWD=$PWD" \ "; USER=root" \ "; COMMAND=$0" f_die 1 "sudo: $msg" fi fi # Use xauth(1) to grant root the ability to use this X11/SSH session if [ "$USE_XDIALOG" -a "$SSH_CONNECTION" -a "$DISPLAY" ]; then f_have xauth || f_die 1 \ "$msg_no_such_file_or_directory" "$pgm" "xauth" local HOSTNAME displaynum HOSTNAME=$(hostname) displaynum="${DISPLAY#*:}" xauth -f ~/.Xauthority extract - $HOSTNAME/unix:$displaynum \ $HOSTNAME:$displaynum | sudo sh -c 'xauth -ivf \ ~root/.Xauthority merge - > /dev/null 2>&1' fi # Re-execute ourselves with sudo(8) f_dprintf "%s: Becoming root via sudo(8)..." mustberoot.subr if [ $ARGC -gt 0 ]; then exec sudo "$0" $ARGV else exec sudo "$0" fi exit $? # Never reached unless error } # f_authenticate_some_user # # Only used if running as root and requires X11 (see USE_XDIALOG below). # Prompts the user to enter a username and password to be authenticated via # sudo(8) to proceed. # # The following environment variables effect functionality: # # USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate # that Xdialog(1) should be used instead of dialog(1). # f_authenticate_some_user() { local msg hline height width f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm" # # Secure-mode has been requested. # [ "$USE_XDIALOG" ] || f_die 1 "$msg_secure_mode_requires_x11" [ "$(id -u)" = "0" ] || f_die 1 "$msg_secure_mode_requires_root" # # Prompt for sudo(8) credentials. # msg="$msg_please_enter_username_password" hline="$hline_alnum_punc_tab_enter" f_xdialog_2inputsbox_size height width \ "$DIALOG_TITLE" \ "$DIALOG_BACKTITLE" \ "$msg" \ "$field_username" "" \ "$field_password" "" height=$(( $height + 2 )) # Add height for --password # # Continue prompting until they either Cancel, succeed or exceed the # number of allowed failures. # local user_pass nfailures=0 retval while [ $nfailures -lt $PASSWD_TRIES ]; do user_pass=$( $DIALOG \ --title "$DIALOG_TITLE" \ --backtitle "$DIALOG_BACKTITLE" \ --hline "$hline" \ --ok-label "$msg_ok" \ --cancel-label "$msg_cancel" \ --password --2inputsbox "$msg" \ $height $width \ "$field_username" "" \ "$field_password" "" \ 2>&1 > /dev/null ) retval=$? # Catch X11-related errors [ $retval -eq $DIALOG_ESC ] && f_die $retval "$user_pass" # Exit if the user cancelled. [ $retval -eq $DIALOG_OK ] || exit $retval # # Make sure the user exists and is non-root # local user password user="${user_pass%%/*}" password="${user_pass#*/}" unset user_pass # scrub memory if [ ! "$user" ]; then nfailures=$(( $nfailures + 1 )) f_show_msg "$msg_no_username" continue fi if [ ! "$SECURE_ALLOW_ROOT" ]; then case "$user" in root|toor) nfailures=$(( $nfailures + 1 )) f_show_msg "$msg_user_disallowed" "$user" continue esac fi if ! f_quietly id "$user"; then nfailures=$(( $nfailures + 1 )) if [ "$SECURE_DIVULGE_UNKNOWN_USER" ]; then f_show_msg "$msg_unknown_user" "$user" elif [ $nfailures -lt $PASSWD_TRIES ]; then f_dialog_info "$msg_sorry_try_again" sleep 1 fi continue fi # # Validate sudo(8) credentials for given user # su -m "$user" <<-EOF sh < /dev/null <