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