1 if [ ! "$_MUSTBEROOT_SUBR" ]; then _MUSTBEROOT_SUBR=1
3 # Copyright (c) 2006-2013 Devin Teske
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
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.
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
29 ############################################################ INCLUDES
31 BSDCFG_SHARE="/usr/share/bsdconfig"
32 . $BSDCFG_SHARE/common.subr || exit 1
33 f_dprintf "%s: loading includes..." mustberoot.subr
34 f_include $BSDCFG_SHARE/dialog.subr
36 BSDCFG_LIBE="/usr/libexec/bsdconfig"
37 f_include_lang $BSDCFG_LIBE/include/messages.subr
39 ############################################################ CONFIGURATION
40 # NOTE: These are not able to be overridden/inherited for security purposes.
43 # Number of tries a user gets to enter his/her password before we log the
44 # sudo(8) failure and exit.
49 # While in SECURE mode, should authentication as `root' be allowed? Set to
50 # non-NULL to enable authentication as `root', otherwise disabled.
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.
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.
64 SECURE_DIVULGE_UNKNOWN_USER=
66 ############################################################ FUNCTIONS
68 # f_become_root_via_sudo
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.
73 # The following environment variables effect functionality:
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).
78 f_become_root_via_sudo()
80 local prompt hline height width rows msg
82 [ "$( id -u )" = "0" ] && return $SUCCESS
84 f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm"
87 # Ask the user if it's OK to become root via sudo(8) and give them
88 # the option to save this preference (by touch(1)ing a file in the
89 # user's $HOME directory).
91 local checkpath="${HOME%/}/.bsdconfig_uses_sudo"
92 if [ ! -e "$checkpath" ]; then
93 prompt=$( printf "$msg_you_are_not_root_but" bsdconfig )
94 msg=$( printf "$msg_always_try_sudo_when_run_as" "$USER" )
96 'X' '$msg_cancel_exit'
98 '2' '$msg_try_sudo_only_this_once'
100 hline="$hline_arrows_tab_enter"
102 eval f_dialog_menu_size height width rows \
104 \"\$DIALOG_BACKTITLE\" \
110 mtag=$( eval $DIALOG \
111 --title \"\$DIALOG_TITLE\" \
112 --backtitle \"\$DIALOG_BACKTITLE\" \
113 --hline \"\$hline\" \
114 --ok-label \"\$msg_ok\" \
115 --cancel-label \"\$msg_cancel\" \
116 --menu \"\$prompt\" \
117 $height $width $rows \
119 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
121 f_dialog_data_sanitize mtag
126 1) # Always try sudo(8) when run as $user
128 if ! err=$( touch "$checkpath" 2>&1 ); then
129 f_dialog_msgbox "$err"
131 f_show_msg "$msg_created_path" "$checkpath"
136 # This user has created the path signing-off on sudo(8)-use
137 # but let's still give them a short/quick/unobtrusive reminder
139 f_dialog_info "$msg_becoming_root_via_sudo"
140 [ "$USE_XDIALOG" ] || sleep 0.6
144 # Check sudo(8) access before prompting for password.
146 :| sudo -S -v 2> /dev/null
147 if [ $? -ne $SUCCESS ]; then
149 # sudo(8) access denied. Prompt for their password.
151 prompt="$msg_please_enter_password"
152 hline="$hline_alnum_punc_tab_enter"
153 f_dialog_inputbox_size height width \
155 "$DIALOG_BACKTITLE" \
160 # Continue prompting until they either Cancel, succeed
161 # or exceed the number of allowed failures.
163 local password nfailures=0 retval
164 while [ $nfailures -lt $PASSWD_TRIES ]; do
165 if [ "$USE_XDIALOG" ]; then
166 password=$( $DIALOG \
167 --title "$DIALOG_TITLE" \
168 --backtitle "$DIALOG_BACKTITLE" \
170 --ok-label "$msg_ok" \
171 --cancel-label "$msg_cancel" \
172 --password --inputbox "$prompt" \
178 # Catch X11-related errors
179 if [ $retval -eq $DIALOG_ESC ]; then
180 f_die $retval "$password"
181 elif [ $retval -ne $DIALOG_OK ]; then
186 password=$( $DIALOG \
187 --title "$DIALOG_TITLE" \
188 --backtitle "$DIALOG_BACKTITLE" \
190 --ok-label "$msg_ok" \
191 --cancel-label "$msg_cancel" \
193 --passwordbox "$prompt" \
195 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
198 debug= f_dialog_line_sanitize password
201 # Validate sudo(8) credentials
203 sudo -S -v 2> /dev/null <<-EOF
207 unset password # scrub memory
208 if [ $retval -eq $SUCCESS ]; then
213 nfailures=$(( $nfailures + 1 ))
215 # introduce a short delay
216 if [ $nfailures -lt $PASSWD_TRIES ]; then
217 f_dialog_info "$msg_sorry_try_again"
224 # If user exhausted number of allowed password tries, log
225 # the security event and exit immediately.
227 if [ $nfailures -ge $PASSWD_TRIES ]; then
228 msg=$( printf "$msg_nfailed_attempts" "$nfailures" )
229 logger -p auth.notice -t sudo " " \
239 # Use xauth(1) to grant root the ability to use this X11/SSH session
240 if [ "$USE_XDIALOG" -a "$SSH_CONNECTION" -a "$DISPLAY" ]; then
241 f_have xauth || f_die 1 \
242 "$msg_no_such_file_or_directory" "$pgm" "xauth"
243 local HOSTNAME displaynum
245 displaynum="${DISPLAY#*:}"
246 xauth -f ~/.Xauthority extract - $HOSTNAME/unix:$displaynum \
247 $HOSTNAME:$displaynum | sudo sh -c 'xauth -ivf \
248 ~root/.Xauthority merge - > /dev/null 2>&1'
251 # Re-execute ourselves with sudo(8)
252 f_dprintf "%s: Becoming root via sudo(8)..." mustberoot.subr
253 if [ $ARGC -gt 0 ]; then
258 exit $? # Never reached unless error
261 # f_authenticate_some_user
263 # Only used if running as root and requires X11 (see USE_XDIALOG below).
264 # Prompts the user to enter a username and password to be authenticated via
265 # sudo(8) to proceed.
267 # The following environment variables effect functionality:
269 # USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate
270 # that Xdialog(1) should be used instead of dialog(1).
272 f_authenticate_some_user()
274 local msg hline height width
276 f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm"
279 # Secure-mode has been requested.
282 [ "$USE_XDIALOG" ] || f_die 1 "$msg_secure_mode_requires_x11"
283 [ "$(id -u)" = "0" ] || f_die 1 "$msg_secure_mode_requires_root"
286 # Prompt for sudo(8) credentials.
289 msg="$msg_please_enter_username_password"
290 hline="$hline_alnum_punc_tab_enter"
291 f_xdialog_2inputsbox_size height width \
293 "$DIALOG_BACKTITLE" \
295 "$field_username" "" \
297 height=$(( $height + 2 )) # Add height for --password
300 # Continue prompting until they either Cancel, succeed or exceed the
301 # number of allowed failures.
303 local user_pass nfailures=0 retval
304 while [ $nfailures -lt $PASSWD_TRIES ]; do
305 user_pass=$( $DIALOG \
306 --title "$DIALOG_TITLE" \
307 --backtitle "$DIALOG_BACKTITLE" \
309 --ok-label "$msg_ok" \
310 --cancel-label "$msg_cancel" \
311 --password --2inputsbox "$msg" \
313 "$field_username" "" \
314 "$field_password" "" \
318 # Catch X11-related errors
319 [ $retval -eq $DIALOG_ESC ] && f_die $retval "$user_pass"
321 # Exit if the user cancelled.
322 [ $retval -eq $DIALOG_OK ] || exit $retval
325 # Make sure the user exists and is non-root
328 user="${user_pass%%/*}"
329 password="${user_pass#*/}"
330 unset user_pass # scrub memory
331 if [ ! "$user" ]; then
332 nfailures=$(( $nfailures + 1 ))
333 f_show_msg "$msg_no_username"
336 if [ ! "$SECURE_ALLOW_ROOT" ]; then
339 nfailures=$(( $nfailures + 1 ))
340 f_show_msg "$msg_user_disallowed" "$user"
344 if ! f_quietly id "$user"; then
345 nfailures=$(( $nfailures + 1 ))
346 if [ "$SECURE_DIVULGE_UNKNOWN_USER" ]; then
347 f_show_msg "$msg_unknown_user" "$user"
348 elif [ $nfailures -lt $PASSWD_TRIES ]; then
349 f_dialog_info "$msg_sorry_try_again"
356 # Validate sudo(8) credentials for given user
361 sudo -S -v 2> /dev/null <<EOP
368 unset password # scrub memory
370 if [ $retval -eq $SUCCESS ]; then
375 nfailures=$(( $nfailures + 1 ))
377 # introduce a short delay
378 if [ $nfailures -lt $PASSWD_TRIES ]; then
379 f_dialog_info "$msg_sorry_try_again"
386 # If user exhausted number of allowed password tries, log
387 # the security event and exit immediately.
389 if [ $nfailures -ge $PASSWD_TRIES ]; then
390 msg=$( printf "$msg_nfailed_attempts" "$nfailures" )
391 logger -p auth.notice -t sudo " " \
392 "${SUDO_USER:-$USER} : $msg" \
397 f_die 1 "sudo: $message"
403 # If not already root, make the switch to root by re-executing ourselves via
404 # sudo(8) using user-supplied credentials.
406 # The following environment variables effect functionality:
408 # SECURE Either NULL or Non-NULL. If given a value will indicate
409 # that (while running as root) sudo(8) authentication is
410 # required to proceed.
414 if [ "$(id -u)" != "0" -a ! "$SECURE" ]; then
415 f_become_root_via_sudo
416 elif [ "$SECURE" ]; then
417 f_authenticate_some_user
421 ############################################################ MAIN
423 f_dprintf "%s: Successfully loaded." mustberoot.subr
425 fi # ! $_MUSTBEROOT_SUBR