Modular sudo front-end which loads policy and I/O plugins that do
most the actual work. Currently relies on dynamic loading using dlopen(). See doc/plugin.pod for the plugin API.
This commit is contained in:
26
Makefile
Normal file
26
Makefile
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
# XXX - add sudoers, doc, compat?
|
||||||
|
SUBDIRS = src plugins/sample
|
||||||
|
|
||||||
|
all install:
|
||||||
|
@if [ ! -s config.status ]; then \
|
||||||
|
echo "Please run configure first"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
for d in $(SUBDIRS); do (cd $$d && $(MAKE) $@); done
|
76
configure
vendored
76
configure
vendored
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# Guess values for system-dependent variables and create Makefiles.
|
||||||
# Generated by GNU Autoconf 2.61 for sudo 1.7.3b2.
|
# Generated by GNU Autoconf 2.61 for sudo 1.8.0a1.
|
||||||
#
|
#
|
||||||
# Report bugs to <http://www.sudo.ws/bugs/>.
|
# Report bugs to <http://www.sudo.ws/bugs/>.
|
||||||
#
|
#
|
||||||
@@ -724,10 +724,11 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
|||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='sudo'
|
PACKAGE_NAME='sudo'
|
||||||
PACKAGE_TARNAME='sudo'
|
PACKAGE_TARNAME='sudo'
|
||||||
PACKAGE_VERSION='1.7.3b2'
|
PACKAGE_VERSION='1.8.0a1'
|
||||||
PACKAGE_STRING='sudo 1.7.3b2'
|
PACKAGE_STRING='sudo 1.8.0a1'
|
||||||
PACKAGE_BUGREPORT='http://www.sudo.ws/bugs/'
|
PACKAGE_BUGREPORT='http://www.sudo.ws/bugs/'
|
||||||
|
|
||||||
|
ac_config_libobj_dir=compat
|
||||||
# Factoring default headers for most tests.
|
# Factoring default headers for most tests.
|
||||||
ac_includes_default="\
|
ac_includes_default="\
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -830,6 +831,7 @@ mansectform
|
|||||||
mansrcdir
|
mansrcdir
|
||||||
NOEXECFILE
|
NOEXECFILE
|
||||||
NOEXECDIR
|
NOEXECDIR
|
||||||
|
PLUGINDIR
|
||||||
noexec_file
|
noexec_file
|
||||||
INSTALL_NOEXEC
|
INSTALL_NOEXEC
|
||||||
DONT_LEAK_PATH_INFO
|
DONT_LEAK_PATH_INFO
|
||||||
@@ -1418,7 +1420,7 @@ if test "$ac_init_help" = "long"; then
|
|||||||
# Omit some internal or obsolete options to make the list less imposing.
|
# Omit some internal or obsolete options to make the list less imposing.
|
||||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures sudo 1.7.3b2 to adapt to many kinds of systems.
|
\`configure' configures sudo 1.8.0a1 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@@ -1483,7 +1485,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of sudo 1.7.3b2:";;
|
short | recursive ) echo "Configuration of sudo 1.8.0a1:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@@ -1602,6 +1604,7 @@ Optional Packages:
|
|||||||
(default=libvas.so)
|
(default=libvas.so)
|
||||||
--with-libvas-rpath=PATH
|
--with-libvas-rpath=PATH
|
||||||
Path to look for libvas in [default=/opt/quest/lib]
|
Path to look for libvas in [default=/opt/quest/lib]
|
||||||
|
--with-plugin_dir set directory to load plugins from
|
||||||
--with-selinux enable SELinux support
|
--with-selinux enable SELinux support
|
||||||
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
|
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
|
||||||
--with-pic try to use only PIC/non-PIC objects [default=use
|
--with-pic try to use only PIC/non-PIC objects [default=use
|
||||||
@@ -1688,7 +1691,7 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
sudo configure 1.7.3b2
|
sudo configure 1.8.0a1
|
||||||
generated by GNU Autoconf 2.61
|
generated by GNU Autoconf 2.61
|
||||||
|
|
||||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||||
@@ -1702,7 +1705,7 @@ cat >config.log <<_ACEOF
|
|||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by sudo $as_me 1.7.3b2, which was
|
It was created by sudo $as_me 1.8.0a1, which was
|
||||||
generated by GNU Autoconf 2.61. Invocation command line was
|
generated by GNU Autoconf 2.61. Invocation command line was
|
||||||
|
|
||||||
$ $0 $@
|
$ $0 $@
|
||||||
@@ -2127,6 +2130,7 @@ echo "$as_me: Configuring Sudo version $PACKAGE_VERSION" >&6;}
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
timeout=5
|
timeout=5
|
||||||
@@ -2193,6 +2197,8 @@ test "$sysconfdir" = '${prefix}/etc' -a X"$with_stow" != X"yes" && sysconfdir='/
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Check whether --with-otp-only was given.
|
# Check whether --with-otp-only was given.
|
||||||
if test "${with_otp_only+set}" = set; then
|
if test "${with_otp_only+set}" = set; then
|
||||||
withval=$with_otp_only; case $with_otp_only in
|
withval=$with_otp_only; case $with_otp_only in
|
||||||
@@ -3847,6 +3853,23 @@ fi
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
PLUGINDIR="$libexecdir"
|
||||||
|
|
||||||
|
# Check whether --with-plugin_dir was given.
|
||||||
|
if test "${with_plugin_dir+set}" = set; then
|
||||||
|
withval=$with_plugin_dir; case $with_plugin_dir in
|
||||||
|
yes) ;;
|
||||||
|
no) ;;
|
||||||
|
*) PLUGINDIR="$with_plugin_dir"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat >>confdefs.h <<EOF
|
||||||
|
#define _PATH_SUDO_PLUGIN_DIR "$PLUGINDIR"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ echo "$as_me:$LINENO: checking whether to do user authentication by default" >&5
|
{ echo "$as_me:$LINENO: checking whether to do user authentication by default" >&5
|
||||||
echo $ECHO_N "checking whether to do user authentication by default... $ECHO_C" >&6; }
|
echo $ECHO_N "checking whether to do user authentication by default... $ECHO_C" >&6; }
|
||||||
@@ -6471,7 +6494,7 @@ ia64-*-hpux*)
|
|||||||
;;
|
;;
|
||||||
*-*-irix6*)
|
*-*-irix6*)
|
||||||
# Find out which ABI we are using.
|
# Find out which ABI we are using.
|
||||||
echo '#line 6474 "configure"' > conftest.$ac_ext
|
echo '#line 6497 "configure"' > conftest.$ac_ext
|
||||||
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
||||||
(eval $ac_compile) 2>&5
|
(eval $ac_compile) 2>&5
|
||||||
ac_status=$?
|
ac_status=$?
|
||||||
@@ -8335,11 +8358,11 @@ else
|
|||||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||||
-e 's:$: $lt_compiler_flag:'`
|
-e 's:$: $lt_compiler_flag:'`
|
||||||
(eval echo "\"\$as_me:8338: $lt_compile\"" >&5)
|
(eval echo "\"\$as_me:8361: $lt_compile\"" >&5)
|
||||||
(eval "$lt_compile" 2>conftest.err)
|
(eval "$lt_compile" 2>conftest.err)
|
||||||
ac_status=$?
|
ac_status=$?
|
||||||
cat conftest.err >&5
|
cat conftest.err >&5
|
||||||
echo "$as_me:8342: \$? = $ac_status" >&5
|
echo "$as_me:8365: \$? = $ac_status" >&5
|
||||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||||
# The compiler can only warn and ignore the option if not recognized
|
# The compiler can only warn and ignore the option if not recognized
|
||||||
# So say no if there are warnings other than the usual output.
|
# So say no if there are warnings other than the usual output.
|
||||||
@@ -8625,11 +8648,11 @@ else
|
|||||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||||
-e 's:$: $lt_compiler_flag:'`
|
-e 's:$: $lt_compiler_flag:'`
|
||||||
(eval echo "\"\$as_me:8628: $lt_compile\"" >&5)
|
(eval echo "\"\$as_me:8651: $lt_compile\"" >&5)
|
||||||
(eval "$lt_compile" 2>conftest.err)
|
(eval "$lt_compile" 2>conftest.err)
|
||||||
ac_status=$?
|
ac_status=$?
|
||||||
cat conftest.err >&5
|
cat conftest.err >&5
|
||||||
echo "$as_me:8632: \$? = $ac_status" >&5
|
echo "$as_me:8655: \$? = $ac_status" >&5
|
||||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||||
# The compiler can only warn and ignore the option if not recognized
|
# The compiler can only warn and ignore the option if not recognized
|
||||||
# So say no if there are warnings other than the usual output.
|
# So say no if there are warnings other than the usual output.
|
||||||
@@ -8729,11 +8752,11 @@ else
|
|||||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||||
-e 's:$: $lt_compiler_flag:'`
|
-e 's:$: $lt_compiler_flag:'`
|
||||||
(eval echo "\"\$as_me:8732: $lt_compile\"" >&5)
|
(eval echo "\"\$as_me:8755: $lt_compile\"" >&5)
|
||||||
(eval "$lt_compile" 2>out/conftest.err)
|
(eval "$lt_compile" 2>out/conftest.err)
|
||||||
ac_status=$?
|
ac_status=$?
|
||||||
cat out/conftest.err >&5
|
cat out/conftest.err >&5
|
||||||
echo "$as_me:8736: \$? = $ac_status" >&5
|
echo "$as_me:8759: \$? = $ac_status" >&5
|
||||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||||
then
|
then
|
||||||
# The compiler can only warn and ignore the option if not recognized
|
# The compiler can only warn and ignore the option if not recognized
|
||||||
@@ -11089,7 +11112,7 @@ else
|
|||||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||||
lt_status=$lt_dlunknown
|
lt_status=$lt_dlunknown
|
||||||
cat > conftest.$ac_ext <<EOF
|
cat > conftest.$ac_ext <<EOF
|
||||||
#line 11092 "configure"
|
#line 11115 "configure"
|
||||||
#include "confdefs.h"
|
#include "confdefs.h"
|
||||||
|
|
||||||
#if HAVE_DLFCN_H
|
#if HAVE_DLFCN_H
|
||||||
@@ -11189,7 +11212,7 @@ else
|
|||||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||||
lt_status=$lt_dlunknown
|
lt_status=$lt_dlunknown
|
||||||
cat > conftest.$ac_ext <<EOF
|
cat > conftest.$ac_ext <<EOF
|
||||||
#line 11192 "configure"
|
#line 11215 "configure"
|
||||||
#include "confdefs.h"
|
#include "confdefs.h"
|
||||||
|
|
||||||
#if HAVE_DLFCN_H
|
#if HAVE_DLFCN_H
|
||||||
@@ -26182,7 +26205,7 @@ _ACEOF
|
|||||||
exec_prefix="$oexec_prefix"
|
exec_prefix="$oexec_prefix"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ac_config_files="$ac_config_files Makefile sudo.man visudo.man sudoers.man sudoers.ldap.man sudoreplay.man sudo_usage.h"
|
ac_config_files="$ac_config_files src/sudo_usage.h src/Makefile plugins/sample/Makefile"
|
||||||
|
|
||||||
cat >confcache <<\_ACEOF
|
cat >confcache <<\_ACEOF
|
||||||
# This file is a shell script that caches the results of configure
|
# This file is a shell script that caches the results of configure
|
||||||
@@ -26580,7 +26603,7 @@ exec 6>&1
|
|||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by sudo $as_me 1.7.3b2, which was
|
This file was extended by sudo $as_me 1.8.0a1, which was
|
||||||
generated by GNU Autoconf 2.61. Invocation command line was
|
generated by GNU Autoconf 2.61. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
@@ -26629,7 +26652,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
|||||||
_ACEOF
|
_ACEOF
|
||||||
cat >>$CONFIG_STATUS <<_ACEOF
|
cat >>$CONFIG_STATUS <<_ACEOF
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
sudo config.status 1.7.3b2
|
sudo config.status 1.8.0a1
|
||||||
configured by $0, generated by GNU Autoconf 2.61,
|
configured by $0, generated by GNU Autoconf 2.61,
|
||||||
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||||
|
|
||||||
@@ -26738,13 +26761,9 @@ do
|
|||||||
case $ac_config_target in
|
case $ac_config_target in
|
||||||
"config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
|
"config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
|
||||||
"pathnames.h") CONFIG_HEADERS="$CONFIG_HEADERS pathnames.h" ;;
|
"pathnames.h") CONFIG_HEADERS="$CONFIG_HEADERS pathnames.h" ;;
|
||||||
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
|
"src/sudo_usage.h") CONFIG_FILES="$CONFIG_FILES src/sudo_usage.h" ;;
|
||||||
"sudo.man") CONFIG_FILES="$CONFIG_FILES sudo.man" ;;
|
"src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
|
||||||
"visudo.man") CONFIG_FILES="$CONFIG_FILES visudo.man" ;;
|
"plugins/sample/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sample/Makefile" ;;
|
||||||
"sudoers.man") CONFIG_FILES="$CONFIG_FILES sudoers.man" ;;
|
|
||||||
"sudoers.ldap.man") CONFIG_FILES="$CONFIG_FILES sudoers.ldap.man" ;;
|
|
||||||
"sudoreplay.man") CONFIG_FILES="$CONFIG_FILES sudoreplay.man" ;;
|
|
||||||
"sudo_usage.h") CONFIG_FILES="$CONFIG_FILES sudo_usage.h" ;;
|
|
||||||
|
|
||||||
*) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
|
*) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
|
||||||
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
|
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
|
||||||
@@ -26872,6 +26891,7 @@ mansectform!$mansectform$ac_delim
|
|||||||
mansrcdir!$mansrcdir$ac_delim
|
mansrcdir!$mansrcdir$ac_delim
|
||||||
NOEXECFILE!$NOEXECFILE$ac_delim
|
NOEXECFILE!$NOEXECFILE$ac_delim
|
||||||
NOEXECDIR!$NOEXECDIR$ac_delim
|
NOEXECDIR!$NOEXECDIR$ac_delim
|
||||||
|
PLUGINDIR!$PLUGINDIR$ac_delim
|
||||||
noexec_file!$noexec_file$ac_delim
|
noexec_file!$noexec_file$ac_delim
|
||||||
INSTALL_NOEXEC!$INSTALL_NOEXEC$ac_delim
|
INSTALL_NOEXEC!$INSTALL_NOEXEC$ac_delim
|
||||||
DONT_LEAK_PATH_INFO!$DONT_LEAK_PATH_INFO$ac_delim
|
DONT_LEAK_PATH_INFO!$DONT_LEAK_PATH_INFO$ac_delim
|
||||||
@@ -26902,7 +26922,6 @@ mailsub!$mailsub$ac_delim
|
|||||||
badpass_message!$badpass_message$ac_delim
|
badpass_message!$badpass_message$ac_delim
|
||||||
fqdn!$fqdn$ac_delim
|
fqdn!$fqdn$ac_delim
|
||||||
runas_default!$runas_default$ac_delim
|
runas_default!$runas_default$ac_delim
|
||||||
env_editor!$env_editor$ac_delim
|
|
||||||
_ACEOF
|
_ACEOF
|
||||||
|
|
||||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
|
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
|
||||||
@@ -26944,6 +26963,7 @@ _ACEOF
|
|||||||
ac_delim='%!_!# '
|
ac_delim='%!_!# '
|
||||||
for ac_last_try in false false false false false :; do
|
for ac_last_try in false false false false false :; do
|
||||||
cat >conf$$subs.sed <<_ACEOF
|
cat >conf$$subs.sed <<_ACEOF
|
||||||
|
env_editor!$env_editor$ac_delim
|
||||||
passwd_tries!$passwd_tries$ac_delim
|
passwd_tries!$passwd_tries$ac_delim
|
||||||
tty_tickets!$tty_tickets$ac_delim
|
tty_tickets!$tty_tickets$ac_delim
|
||||||
insults!$insults$ac_delim
|
insults!$insults$ac_delim
|
||||||
@@ -26989,7 +27009,7 @@ KRB5CONFIG!$KRB5CONFIG$ac_delim
|
|||||||
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
||||||
_ACEOF
|
_ACEOF
|
||||||
|
|
||||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 43; then
|
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 44; then
|
||||||
break
|
break
|
||||||
elif $ac_last_try; then
|
elif $ac_last_try; then
|
||||||
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
||||||
|
21
configure.in
21
configure.in
@@ -3,7 +3,7 @@ dnl Process this file with GNU autoconf to produce a configure script.
|
|||||||
dnl
|
dnl
|
||||||
dnl Copyright (c) 1994-1996,1998-2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
dnl Copyright (c) 1994-1996,1998-2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
dnl
|
dnl
|
||||||
AC_INIT([sudo], [1.7.3b2], [http://www.sudo.ws/bugs/], [sudo])
|
AC_INIT([sudo], [1.8.0a1], [http://www.sudo.ws/bugs/], [sudo])
|
||||||
AC_CONFIG_HEADER(config.h pathnames.h)
|
AC_CONFIG_HEADER(config.h pathnames.h)
|
||||||
dnl
|
dnl
|
||||||
dnl This won't work before AC_INIT
|
dnl This won't work before AC_INIT
|
||||||
@@ -42,6 +42,7 @@ AC_SUBST(mansectform)
|
|||||||
AC_SUBST(mansrcdir)
|
AC_SUBST(mansrcdir)
|
||||||
AC_SUBST(NOEXECFILE)
|
AC_SUBST(NOEXECFILE)
|
||||||
AC_SUBST(NOEXECDIR)
|
AC_SUBST(NOEXECDIR)
|
||||||
|
AC_SUBST(PLUGINDIR)
|
||||||
AC_SUBST(noexec_file)
|
AC_SUBST(noexec_file)
|
||||||
AC_SUBST(INSTALL_NOEXEC)
|
AC_SUBST(INSTALL_NOEXEC)
|
||||||
AC_SUBST(DONT_LEAK_PATH_INFO)
|
AC_SUBST(DONT_LEAK_PATH_INFO)
|
||||||
@@ -161,6 +162,11 @@ test "$bindir" = '${exec_prefix}/bin' && bindir='$(exec_prefix)/bin'
|
|||||||
test "$sbindir" = '${exec_prefix}/sbin' && sbindir='$(exec_prefix)/sbin'
|
test "$sbindir" = '${exec_prefix}/sbin' && sbindir='$(exec_prefix)/sbin'
|
||||||
test "$sysconfdir" = '${prefix}/etc' -a X"$with_stow" != X"yes" && sysconfdir='/etc'
|
test "$sysconfdir" = '${prefix}/etc' -a X"$with_stow" != X"yes" && sysconfdir='/etc'
|
||||||
|
|
||||||
|
dnl
|
||||||
|
dnl libc replacement functions live in compat
|
||||||
|
dnl
|
||||||
|
AC_CONFIG_LIBOBJ_DIR(compat)
|
||||||
|
|
||||||
dnl
|
dnl
|
||||||
dnl Deprecated --with options (these all warn or generate an error)
|
dnl Deprecated --with options (these all warn or generate an error)
|
||||||
dnl
|
dnl
|
||||||
@@ -1061,6 +1067,16 @@ if test X"$with_libvas" != X"no"; then
|
|||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
|
|
||||||
|
PLUGINDIR="$libexecdir"
|
||||||
|
AC_ARG_WITH(plugin_dir, [AS_HELP_STRING([--with-plugin_dir], [set directory to load plugins from])],
|
||||||
|
[case $with_plugin_dir in
|
||||||
|
yes) ;;
|
||||||
|
no) ;;
|
||||||
|
*) PLUGINDIR="$with_plugin_dir"
|
||||||
|
;;
|
||||||
|
esac])
|
||||||
|
SUDO_DEFINE_UNQUOTED(_PATH_SUDO_PLUGIN_DIR, "$PLUGINDIR")
|
||||||
|
|
||||||
dnl
|
dnl
|
||||||
dnl Options for --enable
|
dnl Options for --enable
|
||||||
dnl
|
dnl
|
||||||
@@ -2701,7 +2717,8 @@ fi
|
|||||||
dnl
|
dnl
|
||||||
dnl Substitute into the Makefile and man pages
|
dnl Substitute into the Makefile and man pages
|
||||||
dnl
|
dnl
|
||||||
AC_CONFIG_FILES([Makefile sudo.man visudo.man sudoers.man sudoers.ldap.man sudoreplay.man sudo_usage.h])
|
dnl AC_CONFIG_FILES([doc/sudo.man doc/visudo.man doc/sudoers.man doc/sudoers.ldap.man doc/sudoreplay.man src/Makefile src/sudo_usage.h])
|
||||||
|
AC_CONFIG_FILES([src/sudo_usage.h src/Makefile plugins/sample/Makefile])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
dnl
|
dnl
|
||||||
|
@@ -47,6 +47,13 @@
|
|||||||
#define _PATH_ENVIRONMENT "/etc/environment"
|
#define _PATH_ENVIRONMENT "/etc/environment"
|
||||||
#endif /* _PATH_ENVIRONMENT */
|
#endif /* _PATH_ENVIRONMENT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: _PATH_SUDO_CONF is usually overridden by the Makefile.
|
||||||
|
*/
|
||||||
|
#ifndef _PATH_SUDO_CONF
|
||||||
|
#define _PATH_SUDO_CONF "/etc/sudo.conf"
|
||||||
|
#endif /* _PATH_SUDO_CONF */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: _PATH_SUDOERS is usually overridden by the Makefile.
|
* NOTE: _PATH_SUDOERS is usually overridden by the Makefile.
|
||||||
*/
|
*/
|
||||||
@@ -94,6 +101,10 @@
|
|||||||
#undef _PATH_SUDO_ASKPASS
|
#undef _PATH_SUDO_ASKPASS
|
||||||
#endif /* _PATH_SUDO_ASKPASS */
|
#endif /* _PATH_SUDO_ASKPASS */
|
||||||
|
|
||||||
|
#ifndef _PATH_SUDO_PLUGIN_DIR
|
||||||
|
#undef _PATH_SUDO_PLUGIN_DIR
|
||||||
|
#endif /* _PATH_SUDO_PLUGIN_DIR */
|
||||||
|
|
||||||
#ifndef _PATH_VI
|
#ifndef _PATH_VI
|
||||||
#undef _PATH_VI
|
#undef _PATH_VI
|
||||||
#endif /* _PATH_VI */
|
#endif /* _PATH_VI */
|
||||||
|
208
src/Makefile.in
Normal file
208
src/Makefile.in
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# @configure_input@
|
||||||
|
#
|
||||||
|
|
||||||
|
#### Start of system configuration section. ####
|
||||||
|
|
||||||
|
srcdir = @srcdir@
|
||||||
|
devdir = @devdir@
|
||||||
|
top_builddir = @top_builddir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
incdir = $(top_srcdir)/include
|
||||||
|
|
||||||
|
# Compiler & tools to use
|
||||||
|
CC = @CC@
|
||||||
|
NROFF = nroff -Tascii
|
||||||
|
|
||||||
|
# Our install program supports extra flags...
|
||||||
|
INSTALL = $(SHELL) $(top_srcdir)/install-sh -c
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
LIBS = @LIBS@ @SUDO_LIBS@ @GETGROUPS_LIB@ @NET_LIBS@
|
||||||
|
|
||||||
|
# C preprocessor flags
|
||||||
|
CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(srcdir) -I. @CPPFLAGS@
|
||||||
|
|
||||||
|
# Usually -O and/or -g
|
||||||
|
CFLAGS = @CFLAGS@
|
||||||
|
|
||||||
|
# Flags to pass to the link stage
|
||||||
|
LDFLAGS = @LDFLAGS@
|
||||||
|
|
||||||
|
# Where to install things...
|
||||||
|
prefix = @prefix@
|
||||||
|
exec_prefix = @exec_prefix@
|
||||||
|
bindir = @bindir@
|
||||||
|
sbindir = @sbindir@
|
||||||
|
sysconfdir = @sysconfdir@
|
||||||
|
libexecdir = @libexecdir@
|
||||||
|
datarootdir = @datarootdir@
|
||||||
|
noexecfile = @NOEXECFILE@
|
||||||
|
noexecdir = @NOEXECDIR@
|
||||||
|
|
||||||
|
# User and group ids the installed files should be "owned" by
|
||||||
|
install_uid = 0
|
||||||
|
install_gid = 0
|
||||||
|
|
||||||
|
# Pass in paths and OS dependent defines
|
||||||
|
DEFS = @OSDEFS@
|
||||||
|
|
||||||
|
#### End of system configuration section. ####
|
||||||
|
|
||||||
|
SHELL = /bin/sh
|
||||||
|
|
||||||
|
PROGS = sudo
|
||||||
|
|
||||||
|
# XXX - add back missing ones:
|
||||||
|
# sudo_edit.c selinux.c
|
||||||
|
OBJS = sudo.o parse_args.o lbuf.o alloc.o error.o zero_bytes.o \
|
||||||
|
load_plugins.o conversation.o list.o fmt_string.o tgetpass.o \
|
||||||
|
fileops.o term.o atobool.o script.o pty.o
|
||||||
|
|
||||||
|
LIB_OBJS = @LIBOBJS@
|
||||||
|
|
||||||
|
VERSION = @PACKAGE_VERSION@
|
||||||
|
|
||||||
|
# XXX - update
|
||||||
|
SUDODEP = $(srcdir)/sudo.h $(incdir)/alloc.h \
|
||||||
|
$(incdir)/compat.h $(incdir)/error.h \
|
||||||
|
$(incdir)/list.h $(incdir)/missing.h \
|
||||||
|
$(top_builddir)/pathnames.h $(top_builddir)/config.h
|
||||||
|
|
||||||
|
all: $(PROGS)
|
||||||
|
|
||||||
|
.SUFFIXES: .o .c .h .l .y .man .cat .lo
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $<
|
||||||
|
|
||||||
|
.c.lo:
|
||||||
|
$(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $<
|
||||||
|
|
||||||
|
sudo: $(OBJS)
|
||||||
|
$(CC) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
sudo_noexec.lo: $(srcdir)/sudo_noexec.c
|
||||||
|
$(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c
|
||||||
|
|
||||||
|
sudo_noexec.la: sudo_noexec.lo
|
||||||
|
$(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ sudo_noexec.lo -avoid-version -rpath $(noexecdir)
|
||||||
|
|
||||||
|
# Dependencies (not counting auth functions)
|
||||||
|
aix.o: $(srcdir)/aix.c
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/aix.c
|
||||||
|
alloc.o: $(srcdir)/alloc.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alloc.c
|
||||||
|
audit.o: $(srcdir)/audit.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/audit.c
|
||||||
|
bsm_audit.o: $(srcdir)/bsm_audit.c $(SUDODEP) bsm_audit.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/bsm_audit.c
|
||||||
|
closefrom.o: $(srcdir)/closefrom.c $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/closefrom.c
|
||||||
|
error.o: $(srcdir)/error.c $(incdir)/compat.h $(incdir)/error.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/error.c
|
||||||
|
fileops.o: $(srcdir)/fileops.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/fileops.c
|
||||||
|
getcwd.o: $(srcdir)/getcwd.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getcwd.c
|
||||||
|
getline.o: $(srcdir)/getline.c $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getline.c
|
||||||
|
getprogname.o: $(srcdir)/getprogname.c $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getprogname.c
|
||||||
|
isblank.o: $(srcdir)/isblank.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/isblank.c
|
||||||
|
lbuf.o: $(srcdir)/lbuf.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/lbuf.c
|
||||||
|
list.o: $(srcdir)/list.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/list.c
|
||||||
|
memrchr.o: $(srcdir)/memrchr.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/memrchr.c
|
||||||
|
mkstemp.o: $(srcdir)/mkstemp.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/mkstemp.c
|
||||||
|
nanosleep.o: $(srcdir)/nanosleep.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/nanosleep.c
|
||||||
|
pty.o: $(srcdir)/pty.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/pty.c
|
||||||
|
script.o: $(srcdir)/script.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/script.c
|
||||||
|
sigaction.o: $(srcdir)/sigaction.c $(incdir)/compat.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sigaction.c
|
||||||
|
snprintf.o: $(srcdir)/snprintf.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/snprintf.c
|
||||||
|
strcasecmp.o: $(srcdir)/strcasecmp.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strcasecmp.c
|
||||||
|
strerror.o: $(srcdir)/strerror.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strerror.c
|
||||||
|
strlcat.o: $(srcdir)/strlcat.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strlcat.c
|
||||||
|
strlcpy.o: $(srcdir)/strlcpy.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strlcpy.c
|
||||||
|
strsignal.o: $(srcdir)/strsignal.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strsignal.c
|
||||||
|
selinux.o: $(srcdir)/selinux.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/selinux.c
|
||||||
|
sudo.o: $(srcdir)/sudo.c $(SUDODEP) sudo_usage.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo.c
|
||||||
|
sudo_edit.o: $(srcdir)/sudo_edit.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_edit.c
|
||||||
|
sudo_noexec.o: $(srcdir)/sudo_noexec.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c
|
||||||
|
term.o: $(srcdir)/term.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/term.c
|
||||||
|
tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP)
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tgetpass.c
|
||||||
|
utimes.o: $(srcdir)/utimes.c $(incdir)/compat.h $(srcdir)/emul/utime.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/utimes.c
|
||||||
|
zero_bytes.o: $(srcdir)/zero_bytes.c $(incdir)/compat.h $(top_builddir)/config.h
|
||||||
|
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/zero_bytes.c
|
||||||
|
|
||||||
|
install: install-dirs install-binaries @INSTALL_NOEXEC@
|
||||||
|
|
||||||
|
install-dirs:
|
||||||
|
$(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(sudodir) \
|
||||||
|
$(DESTDIR)$(noexecdir)
|
||||||
|
|
||||||
|
install-binaries: install-dirs $(PROGS)
|
||||||
|
$(INSTALL) -O $(install_uid) -G $(install_gid) -M 4111 -s sudo $(DESTDIR)$(sudodir)/sudo
|
||||||
|
rm -f $(DESTDIR)$(sudodir)/sudoedit
|
||||||
|
ln $(DESTDIR)$(sudodir)/sudo $(DESTDIR)$(sudodir)/sudoedit
|
||||||
|
if [ -f sesh ]; then $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0111 -s sesh $(DESTDIR)$(libexecdir)/sesh; fi
|
||||||
|
|
||||||
|
install-noexec: install-dirs sudo_noexec.la
|
||||||
|
if [ -f .libs/$(noexecfile) ]; then $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0755 .libs/$(noexecfile) $(DESTDIR)$(noexecdir); fi
|
||||||
|
|
||||||
|
check:
|
||||||
|
@echo nothing to check
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -f *.a *.o *.lo stamp-* $(PROGS) core *.core core.*
|
||||||
|
|
||||||
|
mostlyclean: clean
|
||||||
|
|
||||||
|
# XXX - remove some
|
||||||
|
distclean: clean
|
||||||
|
-rm -rf Makefile pathnames.h config.h config.status config.cache \
|
||||||
|
config.log libtool sudo_noexec.lo .libs $(GENERATED) \
|
||||||
|
sudo_usage.h
|
||||||
|
|
||||||
|
clobber: distclean
|
||||||
|
|
||||||
|
realclean: distclean
|
||||||
|
rm -f TAGS tags
|
||||||
|
|
||||||
|
cleandir: realclean
|
109
src/conversation.c
Normal file
109
src/conversation.c
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1999-2005, 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* Sponsored in part by the Defense Advanced Research Projects
|
||||||
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||||
|
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef STDC_HEADERS
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <stddef.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STDLIB_H
|
||||||
|
# include <stdlib.h>
|
||||||
|
# endif
|
||||||
|
#endif /* STDC_HEADERS */
|
||||||
|
#ifdef HAVE_STRING_H
|
||||||
|
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
|
||||||
|
# include <memory.h>
|
||||||
|
# endif
|
||||||
|
# include <string.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STRINGS_H
|
||||||
|
# include <strings.h>
|
||||||
|
# endif
|
||||||
|
#endif /* HAVE_STRING_H */
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif /* HAVE_UNISTD_H */
|
||||||
|
|
||||||
|
#include "sudo.h"
|
||||||
|
#include "sudo_plugin.h"
|
||||||
|
|
||||||
|
extern int tgetpass_flags; /* XXX */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sudo conversation function.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
|
||||||
|
struct sudo_conv_reply replies[])
|
||||||
|
{
|
||||||
|
struct sudo_conv_reply *repl;
|
||||||
|
const struct sudo_conv_message *msg;
|
||||||
|
char *pass;
|
||||||
|
int n, flags = tgetpass_flags;
|
||||||
|
|
||||||
|
for (n = 0; n < num_msgs; n++) {
|
||||||
|
msg = &msgs[n];
|
||||||
|
repl = &replies[n];
|
||||||
|
switch (msg->msg_type) {
|
||||||
|
case SUDO_CONV_PROMPT_ECHO_ON:
|
||||||
|
SET(flags, TGP_ECHO);
|
||||||
|
case SUDO_CONV_PROMPT_ECHO_OFF:
|
||||||
|
/* Read the password unless interrupted. */
|
||||||
|
/* XXX - look up passwd timeout and pass in XXX */
|
||||||
|
pass = tgetpass(msg->msg, 0, flags);
|
||||||
|
if (pass == NULL)
|
||||||
|
goto err;
|
||||||
|
repl->reply = estrdup(pass);
|
||||||
|
zero_bytes(pass, strlen(pass));
|
||||||
|
break;
|
||||||
|
case SUDO_CONV_INFO_MSG:
|
||||||
|
if (msg->msg)
|
||||||
|
(void) puts(msg->msg);
|
||||||
|
break;
|
||||||
|
case SUDO_CONV_ERROR_MSG:
|
||||||
|
if (msg->msg) {
|
||||||
|
(void) fputs(msg->msg, stderr);
|
||||||
|
(void) fputc('\n', stderr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
err:
|
||||||
|
/* Zero and free allocated memory and return an error. */
|
||||||
|
do {
|
||||||
|
repl = &replies[n];
|
||||||
|
if (repl->reply != NULL) {
|
||||||
|
zero_bytes(repl->reply, strlen(repl->reply));
|
||||||
|
free(repl->reply);
|
||||||
|
repl->reply = NULL;
|
||||||
|
}
|
||||||
|
} while (n--);
|
||||||
|
|
||||||
|
return(-1);
|
||||||
|
}
|
@@ -44,7 +44,7 @@
|
|||||||
# include <time.h>
|
# include <time.h>
|
||||||
#endif
|
#endif
|
||||||
#ifndef HAVE_TIMESPEC
|
#ifndef HAVE_TIMESPEC
|
||||||
# include <compat/timespec.h>
|
# include <emul/timespec.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "sudo.h"
|
#include "sudo.h"
|
||||||
|
63
src/fmt_string.c
Normal file
63
src/fmt_string.c
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef STDC_HEADERS
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <stddef.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STDLIB_H
|
||||||
|
# include <stdlib.h>
|
||||||
|
# endif
|
||||||
|
#endif /* STDC_HEADERS */
|
||||||
|
#ifdef HAVE_STRING_H
|
||||||
|
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
|
||||||
|
# include <memory.h>
|
||||||
|
# endif
|
||||||
|
# include <string.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STRINGS_H
|
||||||
|
# include <strings.h>
|
||||||
|
# endif
|
||||||
|
#endif /* HAVE_STRING_H */
|
||||||
|
|
||||||
|
#include "sudo.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate storage for a name=value string and return it.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
fmt_string(const char *var, const char *val)
|
||||||
|
{
|
||||||
|
size_t var_len = strlen(var);
|
||||||
|
size_t val_len = strlen(val);
|
||||||
|
char *cp, *str;
|
||||||
|
|
||||||
|
cp = str = emalloc(var_len + 1 + val_len + 1);
|
||||||
|
memcpy(cp, var, var_len);
|
||||||
|
cp += var_len;
|
||||||
|
*cp++ = '=';
|
||||||
|
memcpy(cp, val, val_len);
|
||||||
|
cp += val_len;
|
||||||
|
*cp = '\0';
|
||||||
|
|
||||||
|
return(str);
|
||||||
|
}
|
176
src/load_plugins.c
Normal file
176
src/load_plugins.c
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef STDC_HEADERS
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <stddef.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STDLIB_H
|
||||||
|
# include <stdlib.h>
|
||||||
|
# endif
|
||||||
|
#endif /* STDC_HEADERS */
|
||||||
|
#ifdef HAVE_STRING_H
|
||||||
|
# include <string.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STRINGS_H
|
||||||
|
# include <strings.h>
|
||||||
|
# endif
|
||||||
|
#endif /* HAVE_STRING_H */
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif /* HAVE_UNISTD_H */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include "sudo.h"
|
||||||
|
#include "sudo_plugin.h"
|
||||||
|
#include "sudo_plugin_int.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read in /etc/sudo.conf
|
||||||
|
* Returns a list of plugins.
|
||||||
|
*/
|
||||||
|
static struct plugin_info_list *
|
||||||
|
sudo_read_conf(const char *conf_file)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char *cp, *name, *path;
|
||||||
|
struct plugin_info *info;
|
||||||
|
static struct plugin_info_list pil; /* XXX */
|
||||||
|
|
||||||
|
if ((fp = fopen(conf_file, "r")) == NULL) {
|
||||||
|
/* Default values */
|
||||||
|
info = emalloc(sizeof(*info));
|
||||||
|
info->symbol_name = "sudoers";
|
||||||
|
info->path = "sudoers_policy";
|
||||||
|
info->prev = info;
|
||||||
|
info->next = NULL;
|
||||||
|
tq_append(&pil, info);
|
||||||
|
/* XXX - io plugin too */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((cp = sudo_parseln(fp)) != NULL) {
|
||||||
|
/* Skip blank or comment lines */
|
||||||
|
if (*cp == '\0')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Look for a line starting with "Plugin" */
|
||||||
|
if (strncasecmp(cp, "Plugin", 6) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Parse line */
|
||||||
|
if ((name = strtok(cp + 6, " \t")) == NULL ||
|
||||||
|
(path = strtok(NULL, " \t")) == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
info = emalloc(sizeof(*info));
|
||||||
|
info->symbol_name = estrdup(name);
|
||||||
|
info->path = estrdup(path);
|
||||||
|
info->prev = info;
|
||||||
|
info->next = NULL;
|
||||||
|
tq_append(&pil, info);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
return(&pil);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the plugins listed in conf_file.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
sudo_load_plugins(const char *conf_file,
|
||||||
|
struct plugin_container *policy_plugin,
|
||||||
|
struct plugin_container_list *io_plugins)
|
||||||
|
{
|
||||||
|
struct generic_plugin *plugin;
|
||||||
|
struct plugin_container *container;
|
||||||
|
struct plugin_info *info;
|
||||||
|
struct plugin_info_list *plugin_list;
|
||||||
|
struct stat sb;
|
||||||
|
void *handle;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
/* Parse sudo.conf */
|
||||||
|
plugin_list = sudo_read_conf(conf_file);
|
||||||
|
if (tq_empty(plugin_list))
|
||||||
|
errorx(1, "no plugins defined in %s", conf_file);
|
||||||
|
|
||||||
|
tq_foreach_fwd(plugin_list, info) {
|
||||||
|
if (info->path[0] == '/') {
|
||||||
|
if (strlcpy(path, info->path, sizeof(path) >= sizeof(path)))
|
||||||
|
errorx(1, "%s: %s", info->path, strerror(ENAMETOOLONG));
|
||||||
|
} else {
|
||||||
|
if (snprintf(path, sizeof(path), "%s/%s", _PATH_SUDO_PLUGIN_DIR,
|
||||||
|
info->path) >= sizeof(path)) {
|
||||||
|
errorx(1, "%s/%s: %s", _PATH_SUDO_PLUGIN_DIR, info->path,
|
||||||
|
strerror(ENAMETOOLONG));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stat(path, &sb) != 0)
|
||||||
|
error(1, "%s", path);
|
||||||
|
if (sb.st_uid != ROOT_UID)
|
||||||
|
errorx(1, "%s must be owned by uid %d", path, ROOT_UID);
|
||||||
|
if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0)
|
||||||
|
errorx(1, "%s must be only be writable by owner", path);
|
||||||
|
|
||||||
|
/* Open plugin and map in symbol */
|
||||||
|
handle = dlopen(path, RTLD_NOW);
|
||||||
|
if (!handle)
|
||||||
|
errorx(1, "unable to dlopen %s: %s", path, dlerror());
|
||||||
|
plugin = dlsym(handle, info->symbol_name);
|
||||||
|
if (!plugin)
|
||||||
|
errorx(1, "unable to find symbol %s in %s", info->symbol_name, path);
|
||||||
|
|
||||||
|
if (plugin->type != SUDO_POLICY_PLUGIN && plugin->type != SUDO_IO_PLUGIN) {
|
||||||
|
errorx(1, "%s: unknown policy type %d", path, plugin->type);
|
||||||
|
}
|
||||||
|
if (SUDO_API_VERSION_GET_MAJOR(plugin->version) != SUDO_API_VERSION_MAJOR) {
|
||||||
|
errorx(1, "%s: incompatible policy major version %d, expected %d",
|
||||||
|
path, SUDO_API_VERSION_GET_MAJOR(plugin->version),
|
||||||
|
SUDO_API_VERSION_MAJOR);
|
||||||
|
}
|
||||||
|
if (plugin->type == SUDO_POLICY_PLUGIN) {
|
||||||
|
if (policy_plugin->handle)
|
||||||
|
errorx(1, "only a single policy plugin may be loaded");
|
||||||
|
policy_plugin->handle = handle;
|
||||||
|
policy_plugin->name = info->symbol_name;
|
||||||
|
policy_plugin->u.generic = plugin;
|
||||||
|
} else if (plugin->type == SUDO_IO_PLUGIN) {
|
||||||
|
container = emalloc(sizeof(*container));
|
||||||
|
container->prev = container;
|
||||||
|
container->next = NULL;
|
||||||
|
container->handle = handle;
|
||||||
|
container->name = info->symbol_name;
|
||||||
|
container->u.generic = plugin;
|
||||||
|
tq_append(io_plugins, container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (policy_plugin->handle == NULL)
|
||||||
|
errorx(1, "%s: at least one policy plugin must be specified", conf_file);
|
||||||
|
if (policy_plugin->u.policy->check_policy == NULL)
|
||||||
|
errorx(1, "policy plugin %s does not include a check_policy method");
|
||||||
|
}
|
431
src/parse_args.c
Normal file
431
src/parse_args.c
Normal file
@@ -0,0 +1,431 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1993-1996, 1998-2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* Sponsored in part by the Defense Advanced Research Projects
|
||||||
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||||
|
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
/* XXX - prune this */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef STDC_HEADERS
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <stddef.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STDLIB_H
|
||||||
|
# include <stdlib.h>
|
||||||
|
# endif
|
||||||
|
#endif /* STDC_HEADERS */
|
||||||
|
#ifdef HAVE_STRING_H
|
||||||
|
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
|
||||||
|
# include <memory.h>
|
||||||
|
# endif
|
||||||
|
# include <string.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STRINGS_H
|
||||||
|
# include <strings.h>
|
||||||
|
# endif
|
||||||
|
#endif /* HAVE_STRING_H */
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif /* HAVE_UNISTD_H */
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
|
#include <sudo_usage.h>
|
||||||
|
#include "sudo.h"
|
||||||
|
#include "lbuf.h" /* XXX */
|
||||||
|
|
||||||
|
/* For getopt(3) */
|
||||||
|
extern char *optarg;
|
||||||
|
extern int optind;
|
||||||
|
|
||||||
|
/* XXX - better home for these and extern in header file */
|
||||||
|
int tgetpass_flags;
|
||||||
|
int user_closefrom = -1;
|
||||||
|
const char *list_user, *runas_user, *runas_group;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local functions.
|
||||||
|
*/
|
||||||
|
static void usage(int) __attribute__((__noreturn__));
|
||||||
|
static void usage_excl(int) __attribute__((__noreturn__));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mapping of command line flags to name/value settings.
|
||||||
|
*/
|
||||||
|
struct name_value_pair {
|
||||||
|
const char *name;
|
||||||
|
const char *value;
|
||||||
|
};
|
||||||
|
static struct sudo_settings {
|
||||||
|
struct name_value_pair a;
|
||||||
|
struct name_value_pair c;
|
||||||
|
struct name_value_pair D;
|
||||||
|
struct name_value_pair E;
|
||||||
|
struct name_value_pair g;
|
||||||
|
struct name_value_pair H;
|
||||||
|
struct name_value_pair i;
|
||||||
|
struct name_value_pair k;
|
||||||
|
struct name_value_pair p;
|
||||||
|
struct name_value_pair r;
|
||||||
|
struct name_value_pair t;
|
||||||
|
struct name_value_pair U;
|
||||||
|
struct name_value_pair u;
|
||||||
|
} sudo_settings = {
|
||||||
|
{ "bsdauth_type" },
|
||||||
|
{ "login_class" },
|
||||||
|
{ "debug_level" },
|
||||||
|
{ "preserve_environment" },
|
||||||
|
{ "runas_group" },
|
||||||
|
{ "set_home" },
|
||||||
|
{ "login_shell" },
|
||||||
|
{ "ignore_ticket" },
|
||||||
|
{ "prompt" },
|
||||||
|
{ "selinux_role" },
|
||||||
|
{ "selinux_type" },
|
||||||
|
{ "runas_user" }
|
||||||
|
};
|
||||||
|
static struct name_value_pair *setting_pairs[] = {
|
||||||
|
&sudo_settings.a,
|
||||||
|
&sudo_settings.c,
|
||||||
|
&sudo_settings.D,
|
||||||
|
&sudo_settings.E,
|
||||||
|
&sudo_settings.g,
|
||||||
|
&sudo_settings.H,
|
||||||
|
&sudo_settings.i,
|
||||||
|
&sudo_settings.p,
|
||||||
|
&sudo_settings.r,
|
||||||
|
&sudo_settings.t,
|
||||||
|
&sudo_settings.u
|
||||||
|
};
|
||||||
|
#define settings_size (sizeof(setting_pairs) / sizeof(struct name_value_pair))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command line argument parsing.
|
||||||
|
* Sets nargc and nargv which corresponds to the argc/argv we'll use
|
||||||
|
* for the command to be run (if we are running one).
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
|
||||||
|
char ***env_addp)
|
||||||
|
{
|
||||||
|
int mode = 0; /* what mode is sudo to be run in? */
|
||||||
|
int flags = 0; /* mode flags */
|
||||||
|
int valid_flags, ch;
|
||||||
|
int i, j;
|
||||||
|
char **settings;
|
||||||
|
char **env_add;
|
||||||
|
int nenv = 0;
|
||||||
|
int env_size = 32;
|
||||||
|
|
||||||
|
env_add = emalloc2(env_size, sizeof(char *));
|
||||||
|
env_add[0] = NULL;
|
||||||
|
|
||||||
|
/* First, check to see if we were invoked as "sudoedit". */
|
||||||
|
if (strcmp(getprogname(), "sudoedit") == 0)
|
||||||
|
mode = MODE_EDIT;
|
||||||
|
|
||||||
|
/* Returns true if the last option string was "--" */
|
||||||
|
#define got_end_of_args (optind > 1 && argv[optind - 1][0] == '-' && \
|
||||||
|
argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')
|
||||||
|
|
||||||
|
/* Returns true if next option is an environment variable */
|
||||||
|
#define is_envar (optind < argc && argv[optind][0] != '/' && \
|
||||||
|
strchr(argv[optind], '=') != NULL)
|
||||||
|
|
||||||
|
/* Flags allowed when running a command */
|
||||||
|
valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
|
||||||
|
MODE_LOGIN_SHELL|MODE_INVALIDATE|MODE_NONINTERACTIVE|
|
||||||
|
MODE_PRESERVE_GROUPS|MODE_SHELL;
|
||||||
|
/* XXX - should fill in settings at the end to avoid dupes */
|
||||||
|
for (;;) {
|
||||||
|
/*
|
||||||
|
* We disable arg permutation for GNU getopt().
|
||||||
|
* Some trickiness is required to allow environment variables
|
||||||
|
* to be interspersed with command line options.
|
||||||
|
*/
|
||||||
|
if ((ch = getopt(argc, argv, "+Aa:bC:c:D:Eeg:HhiKkLlnPp:r:Sst:U:u:Vv")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'A':
|
||||||
|
SET(tgetpass_flags, TGP_ASKPASS);
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_BSD_AUTH_H
|
||||||
|
case 'a':
|
||||||
|
sudo_settings.a.value = optarg;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'b':
|
||||||
|
SET(flags, MODE_BACKGROUND);
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
if ((user_closefrom = atoi(optarg)) < 3) {
|
||||||
|
warningx("the argument to -C must be at least 3");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_LOGIN_CAP_H
|
||||||
|
case 'c':
|
||||||
|
sudo_settings.c.value = optarg;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'D':
|
||||||
|
sudo_settings.D.value = optarg;
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
sudo_settings.c.value = "true";
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
if (mode && mode != MODE_EDIT)
|
||||||
|
usage_excl(1);
|
||||||
|
mode = MODE_EDIT;
|
||||||
|
valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
runas_group = optarg;
|
||||||
|
sudo_settings.g.value = optarg;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
sudo_settings.H.value = optarg;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
if (mode && mode != MODE_HELP) {
|
||||||
|
if (strcmp(getprogname(), "sudoedit") != 0)
|
||||||
|
usage_excl(1);
|
||||||
|
}
|
||||||
|
mode = MODE_HELP;
|
||||||
|
valid_flags = 0;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
sudo_settings.i.value = "true";
|
||||||
|
SET(flags, MODE_LOGIN_SHELL);
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
sudo_settings.k.value = "true";
|
||||||
|
SET(flags, MODE_INVALIDATE);
|
||||||
|
break;
|
||||||
|
case 'K':
|
||||||
|
sudo_settings.k.value = "true";
|
||||||
|
if (mode && mode != MODE_KILL)
|
||||||
|
usage_excl(1);
|
||||||
|
mode = MODE_KILL;
|
||||||
|
valid_flags = 0;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
if (mode) {
|
||||||
|
if (mode == MODE_LIST)
|
||||||
|
SET(flags, MODE_LONG_LIST);
|
||||||
|
else
|
||||||
|
usage_excl(1);
|
||||||
|
}
|
||||||
|
mode = MODE_LIST;
|
||||||
|
valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE|MODE_LONG_LIST;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
SET(flags, MODE_NONINTERACTIVE);
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
SET(flags, MODE_PRESERVE_GROUPS);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
sudo_settings.i.value = optarg;
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
case 'r':
|
||||||
|
sudo_settings.r.value = optarg;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
sudo_settings.t.value = optarg;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'S':
|
||||||
|
SET(tgetpass_flags, TGP_STDIN);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
SET(flags, MODE_SHELL);
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
/* XXX - sudo_getpwnam */
|
||||||
|
if ((getpwnam(optarg)) == NULL)
|
||||||
|
errorx(1, "unknown user: %s", optarg);
|
||||||
|
list_user = optarg;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
runas_user = optarg;
|
||||||
|
sudo_settings.u.value = optarg;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
if (mode && mode != MODE_VALIDATE)
|
||||||
|
usage_excl(1);
|
||||||
|
mode = MODE_VALIDATE;
|
||||||
|
valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
if (mode && mode != MODE_VERSION)
|
||||||
|
usage_excl(1);
|
||||||
|
mode = MODE_VERSION;
|
||||||
|
valid_flags = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
} else if (!got_end_of_args && is_envar) {
|
||||||
|
if (nenv == env_size - 2) {
|
||||||
|
env_size *= 2;
|
||||||
|
env_add = erealloc3(env_add, env_size, sizeof(char *));
|
||||||
|
}
|
||||||
|
env_add[nenv++] = argv[optind];
|
||||||
|
|
||||||
|
/* Crank optind and resume getopt. */
|
||||||
|
optind++;
|
||||||
|
} else {
|
||||||
|
/* Not an option or an environment variable -- we're done. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*nargc = argc - optind;
|
||||||
|
*nargv = argv + optind;
|
||||||
|
|
||||||
|
if (!mode) {
|
||||||
|
/* Defer -k mode setting until we know whether it is a flag or not */
|
||||||
|
if (ISSET(flags, MODE_INVALIDATE) && *nargc == 0) {
|
||||||
|
mode = MODE_INVALIDATE; /* -k by itself */
|
||||||
|
CLR(flags, MODE_INVALIDATE);
|
||||||
|
sudo_settings.k.value = NULL;
|
||||||
|
valid_flags = 0;
|
||||||
|
} else {
|
||||||
|
mode = MODE_RUN; /* running a command */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*nargc > 0 && mode == MODE_LIST)
|
||||||
|
mode = MODE_CHECK;
|
||||||
|
|
||||||
|
if (ISSET(flags, MODE_LOGIN_SHELL)) {
|
||||||
|
if (ISSET(flags, MODE_SHELL)) {
|
||||||
|
warningx("you may not specify both the `-i' and `-s' options");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
if (ISSET(flags, MODE_PRESERVE_ENV)) {
|
||||||
|
warningx("you may not specify both the `-i' and `-E' options");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
SET(flags, MODE_SHELL);
|
||||||
|
}
|
||||||
|
if ((flags & valid_flags) != flags)
|
||||||
|
usage(1);
|
||||||
|
if (mode == MODE_EDIT &&
|
||||||
|
(ISSET(flags, MODE_PRESERVE_ENV) || env_add[0] != NULL)) {
|
||||||
|
if (ISSET(mode, MODE_PRESERVE_ENV))
|
||||||
|
warningx("the `-E' option is not valid in edit mode");
|
||||||
|
if (env_add[0] != NULL)
|
||||||
|
warningx("you may not specify environment variables in edit mode");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
if ((runas_user != NULL || runas_group != NULL) &&
|
||||||
|
!ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK | MODE_VALIDATE)) {
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
if (list_user != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
|
||||||
|
warningx("the `-U' option may only be used with the `-l' option");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
|
||||||
|
warningx("the `-A' and `-S' options may not be used together");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
if ((*nargc == 0 && mode == MODE_EDIT) ||
|
||||||
|
(*nargc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
|
||||||
|
usage(1);
|
||||||
|
if (*nargc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL))
|
||||||
|
SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
|
||||||
|
|
||||||
|
if (mode == MODE_HELP)
|
||||||
|
usage(0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format setting_pairs into settings array.
|
||||||
|
*/
|
||||||
|
settings = emalloc2(settings_size + 1, sizeof (char *));
|
||||||
|
for (i = 0, j = 0; i < settings_size; i++) {
|
||||||
|
if (setting_pairs[i]->value) {
|
||||||
|
settings[j++] = fmt_string(setting_pairs[i]->name,
|
||||||
|
setting_pairs[i]->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings[j] = NULL;
|
||||||
|
|
||||||
|
*settingsp = settings;
|
||||||
|
*env_addp = env_add;
|
||||||
|
return(mode | flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Give usage message and exit.
|
||||||
|
* The actual usage strings are in sudo_usage.h for configure substitution.
|
||||||
|
* XXX - avoid lbuf usage
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
usage(int exit_val)
|
||||||
|
{
|
||||||
|
struct lbuf lbuf;
|
||||||
|
char *uvec[6];
|
||||||
|
int i, ulen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use usage vectors appropriate to the progname.
|
||||||
|
*/
|
||||||
|
if (strcmp(getprogname(), "sudoedit") == 0) {
|
||||||
|
uvec[0] = SUDO_USAGE5 + 3;
|
||||||
|
uvec[1] = NULL;
|
||||||
|
} else {
|
||||||
|
uvec[0] = SUDO_USAGE1;
|
||||||
|
uvec[1] = SUDO_USAGE2;
|
||||||
|
uvec[2] = SUDO_USAGE3;
|
||||||
|
uvec[3] = SUDO_USAGE4;
|
||||||
|
uvec[4] = SUDO_USAGE5;
|
||||||
|
uvec[5] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print usage and wrap lines as needed, depending on the
|
||||||
|
* tty width.
|
||||||
|
*/
|
||||||
|
ulen = (int)strlen(getprogname()) + 8;
|
||||||
|
lbuf_init(&lbuf, NULL, ulen, 0);
|
||||||
|
for (i = 0; uvec[i] != NULL; i++) {
|
||||||
|
lbuf_append(&lbuf, "usage: ", getprogname(), uvec[i], NULL);
|
||||||
|
lbuf_print(&lbuf);
|
||||||
|
}
|
||||||
|
lbuf_destroy(&lbuf);
|
||||||
|
exit(exit_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tell which options are mutually exclusive and exit.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
usage_excl(int exit_val)
|
||||||
|
{
|
||||||
|
warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified");
|
||||||
|
usage(exit_val);
|
||||||
|
}
|
38
src/pty.c
38
src/pty.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
* Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -58,31 +58,23 @@
|
|||||||
|
|
||||||
#if defined(HAVE_OPENPTY)
|
#if defined(HAVE_OPENPTY)
|
||||||
int
|
int
|
||||||
get_pty(master, slave, name, namesz)
|
get_pty(int *master, int *slave, char *name, size_t namesz, uid_t uid)
|
||||||
int *master;
|
|
||||||
int *slave;
|
|
||||||
char *name;
|
|
||||||
size_t namesz;
|
|
||||||
{
|
{
|
||||||
struct group *gr;
|
struct group *gr;
|
||||||
gid_t ttygid = -1;
|
gid_t ttygid = -1;
|
||||||
|
|
||||||
if ((gr = sudo_getgrnam("tty")) != NULL)
|
if ((gr = getgrnam("tty")) != NULL)
|
||||||
ttygid = gr->gr_gid;
|
ttygid = gr->gr_gid;
|
||||||
|
|
||||||
if (openpty(master, slave, name, NULL, NULL) != 0)
|
if (openpty(master, slave, name, NULL, NULL) != 0)
|
||||||
return(0);
|
return(0);
|
||||||
(void) chown(name, runas_pw->pw_uid, ttygid);
|
(void) chown(name, uid, ttygid);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(HAVE__GETPTY)
|
#elif defined(HAVE__GETPTY)
|
||||||
int
|
int
|
||||||
get_pty(master, slave, name, namesz)
|
get_pty(int *master, int *slave, char *name, size_t namesz, uid_t uid)
|
||||||
int *master;
|
|
||||||
int *slave;
|
|
||||||
char *name;
|
|
||||||
size_t namesz;
|
|
||||||
{
|
{
|
||||||
char *line;
|
char *line;
|
||||||
|
|
||||||
@@ -95,7 +87,7 @@ get_pty(master, slave, name, namesz)
|
|||||||
close(*master);
|
close(*master);
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
(void) chown(line, runas_pw->pw_uid, -1);
|
(void) chown(line, uid, -1);
|
||||||
strlcpy(name, line, namesz);
|
strlcpy(name, line, namesz);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
@@ -117,11 +109,7 @@ posix_openpt(oflag)
|
|||||||
# endif /* HAVE_POSIX_OPENPT */
|
# endif /* HAVE_POSIX_OPENPT */
|
||||||
|
|
||||||
int
|
int
|
||||||
get_pty(master, slave, name, namesz)
|
get_pty(int *master, int *slave, char *name, size_t namesz, uid_t uid)
|
||||||
int *master;
|
|
||||||
int *slave;
|
|
||||||
char *name;
|
|
||||||
size_t namesz;
|
|
||||||
{
|
{
|
||||||
char *line;
|
char *line;
|
||||||
|
|
||||||
@@ -148,7 +136,7 @@ get_pty(master, slave, name, namesz)
|
|||||||
ioctl(*slave, I_PUSH, "ptem"); /* pseudo tty emulation module */
|
ioctl(*slave, I_PUSH, "ptem"); /* pseudo tty emulation module */
|
||||||
ioctl(*slave, I_PUSH, "ldterm"); /* line discipline module */
|
ioctl(*slave, I_PUSH, "ldterm"); /* line discipline module */
|
||||||
# endif
|
# endif
|
||||||
(void) chown(line, runas_pw->pw_uid, -1);
|
(void) chown(line, uid, -1);
|
||||||
strlcpy(name, line, namesz);
|
strlcpy(name, line, namesz);
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
@@ -158,17 +146,13 @@ get_pty(master, slave, name, namesz)
|
|||||||
static char line[] = "/dev/ptyXX";
|
static char line[] = "/dev/ptyXX";
|
||||||
|
|
||||||
int
|
int
|
||||||
get_pty(master, slave, name, namesz)
|
get_pty(int *master, int *slave, char *name, size_t namesz, uid_t uid)
|
||||||
int *master;
|
|
||||||
int *slave;
|
|
||||||
char *name;
|
|
||||||
size_t namesz;
|
|
||||||
{
|
{
|
||||||
char *bank, *cp;
|
char *bank, *cp;
|
||||||
struct group *gr;
|
struct group *gr;
|
||||||
gid_t ttygid = -1;
|
gid_t ttygid = -1;
|
||||||
|
|
||||||
if ((gr = sudo_getgrnam("tty")) != NULL)
|
if ((gr = getgrnam("tty")) != NULL)
|
||||||
ttygid = gr->gr_gid;
|
ttygid = gr->gr_gid;
|
||||||
|
|
||||||
for (bank = "pqrs"; *bank != '\0'; bank++) {
|
for (bank = "pqrs"; *bank != '\0'; bank++) {
|
||||||
@@ -182,7 +166,7 @@ get_pty(master, slave, name, namesz)
|
|||||||
continue; /* already in use */
|
continue; /* already in use */
|
||||||
}
|
}
|
||||||
line[sizeof("/dev/p") - 2] = 't';
|
line[sizeof("/dev/p") - 2] = 't';
|
||||||
(void) chown(line, runas_pw->pw_uid, ttygid);
|
(void) chown(line, uid, ttygid);
|
||||||
(void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
|
(void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
|
||||||
# ifdef HAVE_REVOKE
|
# ifdef HAVE_REVOKE
|
||||||
(void) revoke(line);
|
(void) revoke(line);
|
||||||
|
544
src/script.c
544
src/script.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
* Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -68,39 +68,29 @@
|
|||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
# include <selinux/selinux.h>
|
# include <selinux/selinux.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_ZLIB
|
|
||||||
# include <zlib.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "sudo.h"
|
#include "sudo.h" /* XXX? */
|
||||||
|
#include "sudo_plugin.h"
|
||||||
|
#include "sudo_plugin_int.h"
|
||||||
|
|
||||||
#define SFD_MASTER 0
|
#define SFD_MASTER 0
|
||||||
#define SFD_SLAVE 1
|
#define SFD_SLAVE 1
|
||||||
#define SFD_LOG 2
|
#define SFD_USERTTY 2
|
||||||
#define SFD_OUTPUT 3
|
|
||||||
#define SFD_TIMING 4
|
|
||||||
#define SFD_USERTTY 5
|
|
||||||
|
|
||||||
#define TERM_COOKED 0
|
#define TERM_COOKED 0
|
||||||
#define TERM_CBREAK 1
|
#define TERM_CBREAK 1
|
||||||
#define TERM_RAW 2
|
#define TERM_RAW 2
|
||||||
|
|
||||||
union script_fd {
|
|
||||||
FILE *f;
|
|
||||||
#ifdef HAVE_ZLIB
|
|
||||||
gzFile g;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct script_buf {
|
struct script_buf {
|
||||||
int len; /* buffer length (how much read in) */
|
int len; /* buffer length (how much read in) */
|
||||||
int off; /* write position (how much already consumed) */
|
int off; /* write position (how much already consumed) */
|
||||||
char buf[16 * 1024];
|
char buf[16 * 1024];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int script_fds[6];
|
static int script_fds[3];
|
||||||
static int ttyout;
|
static int ttyout;
|
||||||
|
|
||||||
|
/* XXX - use an array of signals instead of just a single variable */
|
||||||
static sig_atomic_t alive = 1;
|
static sig_atomic_t alive = 1;
|
||||||
static sig_atomic_t recvsig = 0;
|
static sig_atomic_t recvsig = 0;
|
||||||
static sig_atomic_t ttymode = TERM_COOKED;
|
static sig_atomic_t ttymode = TERM_COOKED;
|
||||||
@@ -114,247 +104,68 @@ static int foreground;
|
|||||||
|
|
||||||
static char slavename[PATH_MAX];
|
static char slavename[PATH_MAX];
|
||||||
|
|
||||||
static int suspend_parent __P((int signo, struct script_buf *output,
|
static int suspend_parent(int signo, struct script_buf *output);
|
||||||
struct timeval *then, struct timeval *now, union script_fd ofile,
|
static void flush_output(struct script_buf *output);
|
||||||
union script_fd tfile));
|
static void handler(int s);
|
||||||
static void flush_output __P((struct script_buf *output, struct timeval *then,
|
static int script_child(const char *path, char *argv[], char *envp[], int, int);
|
||||||
struct timeval *now, union script_fd ofile, union script_fd tfile));
|
static void script_run(const char *path, char *argv[], char *envp[], int);
|
||||||
static void handler __P((int s));
|
static void sigchild(int s);
|
||||||
static void script_child __P((char *path, char *argv[], int, int));
|
static void sigwinch(int s);
|
||||||
static void script_run __P((char *path, char *argv[], int));
|
static void sync_winsize(int src, int dst);
|
||||||
static void sigchild __P((int s));
|
|
||||||
static void sigwinch __P((int s));
|
|
||||||
static void sync_winsize __P((int src, int dst));
|
|
||||||
|
|
||||||
extern int get_pty __P((int *master, int *slave, char *name, size_t namesz));
|
/* sudo.c */
|
||||||
|
extern struct plugin_container_list io_plugins;
|
||||||
/*
|
|
||||||
* TODO: run monitor as root?
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
fdcompar(v1, v2)
|
|
||||||
const void *v1;
|
|
||||||
const void *v2;
|
|
||||||
{
|
|
||||||
int i = *(int *)v1;
|
|
||||||
int j = *(int *)v2;
|
|
||||||
|
|
||||||
return(script_fds[i] - script_fds[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
script_nextid()
|
script_setup(uid_t uid)
|
||||||
{
|
{
|
||||||
struct stat sb;
|
|
||||||
char buf[32], *ep;
|
|
||||||
int fd, i, ch;
|
|
||||||
unsigned long id = 0;
|
|
||||||
int len;
|
|
||||||
ssize_t nread;
|
|
||||||
char pathbuf[PATH_MAX];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create _PATH_SUDO_TRANSCRIPT if it doesn't already exist.
|
|
||||||
*/
|
|
||||||
if (stat(_PATH_SUDO_TRANSCRIPT, &sb) != 0) {
|
|
||||||
if (mkdir(_PATH_SUDO_TRANSCRIPT, S_IRWXU) != 0)
|
|
||||||
log_error(USE_ERRNO, "Can't mkdir %s", _PATH_SUDO_TRANSCRIPT);
|
|
||||||
} else if (!S_ISDIR(sb.st_mode)) {
|
|
||||||
log_error(0, "%s exists but is not a directory (0%o)",
|
|
||||||
_PATH_SUDO_TRANSCRIPT, (unsigned int) sb.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open sequence file
|
|
||||||
*/
|
|
||||||
len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", _PATH_SUDO_TRANSCRIPT);
|
|
||||||
if (len <= 0 || len >= sizeof(pathbuf)) {
|
|
||||||
errno = ENAMETOOLONG;
|
|
||||||
log_error(USE_ERRNO, "%s/seq", pathbuf);
|
|
||||||
}
|
|
||||||
fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
|
|
||||||
if (fd == -1)
|
|
||||||
log_error(USE_ERRNO, "cannot open %s", pathbuf);
|
|
||||||
lock_file(fd, SUDO_LOCK);
|
|
||||||
|
|
||||||
/* Read seq number (base 36). */
|
|
||||||
nread = read(fd, buf, sizeof(buf));
|
|
||||||
if (nread != 0) {
|
|
||||||
if (nread == -1)
|
|
||||||
log_error(USE_ERRNO, "cannot read %s", pathbuf);
|
|
||||||
id = strtoul(buf, &ep, 36);
|
|
||||||
if (buf == ep || id >= 2176782336U)
|
|
||||||
log_error(0, "invalid sequence number %s", pathbuf);
|
|
||||||
}
|
|
||||||
id++;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert id to a string and stash in sudo_user.sessid.
|
|
||||||
* Note that that least significant digits go at the end of the string.
|
|
||||||
*/
|
|
||||||
for (i = 5; i >= 0; i--) {
|
|
||||||
ch = id % 36;
|
|
||||||
id /= 36;
|
|
||||||
buf[i] = ch < 10 ? ch + '0' : ch - 10 + 'A';
|
|
||||||
}
|
|
||||||
buf[6] = '\n';
|
|
||||||
|
|
||||||
/* Stash id logging purposes */
|
|
||||||
memcpy(sudo_user.sessid, buf, 6);
|
|
||||||
sudo_user.sessid[6] = '\0';
|
|
||||||
|
|
||||||
/* Rewind and overwrite old seq file. */
|
|
||||||
if (lseek(fd, 0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7)
|
|
||||||
log_error(USE_ERRNO, "Can't write to %s", pathbuf);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
build_idpath(pathbuf)
|
|
||||||
char *pathbuf;
|
|
||||||
{
|
|
||||||
struct stat sb;
|
|
||||||
int i, len;
|
|
||||||
|
|
||||||
if (sudo_user.sessid[0] == '\0')
|
|
||||||
log_error(0, "tried to build a session id path without a session id");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Path is of the form /var/log/sudo-session/00/00/01.
|
|
||||||
*/
|
|
||||||
len = snprintf(pathbuf, PATH_MAX, "%s/%c%c/%c%c/%c%c", _PATH_SUDO_TRANSCRIPT,
|
|
||||||
sudo_user.sessid[0], sudo_user.sessid[1], sudo_user.sessid[2],
|
|
||||||
sudo_user.sessid[3], sudo_user.sessid[4], sudo_user.sessid[5]);
|
|
||||||
if (len <= 0 && len >= PATH_MAX) {
|
|
||||||
errno = ENAMETOOLONG;
|
|
||||||
log_error(USE_ERRNO, "%s/%s", _PATH_SUDO_TRANSCRIPT, sudo_user.sessid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create the intermediate subdirs as needed.
|
|
||||||
*/
|
|
||||||
for (i = 6; i > 0; i -= 3) {
|
|
||||||
pathbuf[len - i] = '\0';
|
|
||||||
if (stat(pathbuf, &sb) != 0) {
|
|
||||||
if (mkdir(pathbuf, S_IRWXU) != 0)
|
|
||||||
log_error(USE_ERRNO, "Can't mkdir %s", pathbuf);
|
|
||||||
} else if (!S_ISDIR(sb.st_mode)) {
|
|
||||||
log_error(0, "%s: %s", pathbuf, strerror(ENOTDIR));
|
|
||||||
}
|
|
||||||
pathbuf[len - i] = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
return(len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
script_setup()
|
|
||||||
{
|
|
||||||
char pathbuf[PATH_MAX];
|
|
||||||
int len;
|
|
||||||
|
|
||||||
script_fds[SFD_USERTTY] = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
|
script_fds[SFD_USERTTY] = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
|
||||||
if (script_fds[SFD_USERTTY] == -1)
|
if (script_fds[SFD_USERTTY] == -1)
|
||||||
log_error(0, "tty required for transcript support"); /* XXX */
|
errorx(1, "tty required for transcript support");
|
||||||
|
|
||||||
if (!get_pty(&script_fds[SFD_MASTER], &script_fds[SFD_SLAVE],
|
if (!get_pty(&script_fds[SFD_MASTER], &script_fds[SFD_SLAVE],
|
||||||
slavename, sizeof(slavename)))
|
slavename, sizeof(slavename), uid))
|
||||||
log_error(USE_ERRNO, "Can't get pty");
|
error(1, "Can't get pty");
|
||||||
|
|
||||||
/*
|
|
||||||
* Build a path containing the session id split into two-digit subdirs,
|
|
||||||
* so ID 000001 becomes /var/log/sudo-session/00/00/01.
|
|
||||||
*/
|
|
||||||
len = build_idpath(pathbuf);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We create 3 files: a log file, one for the raw session data,
|
|
||||||
* and one for the timing info.
|
|
||||||
*/
|
|
||||||
script_fds[SFD_LOG] = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
|
|
||||||
if (script_fds[SFD_LOG] == -1)
|
|
||||||
log_error(USE_ERRNO, "Can't create %s", pathbuf);
|
|
||||||
|
|
||||||
strlcat(pathbuf, ".scr", sizeof(pathbuf));
|
|
||||||
script_fds[SFD_OUTPUT] = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY,
|
|
||||||
S_IRUSR|S_IWUSR);
|
|
||||||
if (script_fds[SFD_OUTPUT] == -1)
|
|
||||||
log_error(USE_ERRNO, "Can't create %s", pathbuf);
|
|
||||||
|
|
||||||
pathbuf[len] = '\0';
|
|
||||||
strlcat(pathbuf, ".tim", sizeof(pathbuf));
|
|
||||||
script_fds[SFD_TIMING] = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
|
|
||||||
if (script_fds[SFD_TIMING] == -1)
|
|
||||||
log_error(USE_ERRNO, "Can't create %s", pathbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
/* Call I/O plugin input method. */
|
||||||
script_duplow(fd)
|
|
||||||
int fd;
|
|
||||||
{
|
|
||||||
int i, j, indices[6];
|
|
||||||
|
|
||||||
/* sort fds so we can dup them safely */
|
|
||||||
for (i = 0; i < 6; i++)
|
|
||||||
indices[i] = i;
|
|
||||||
qsort(indices, 6, sizeof(int), fdcompar);
|
|
||||||
|
|
||||||
/* Move pty master/slave and session fds to low numbered fds. */
|
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
j = indices[i];
|
|
||||||
if (script_fds[j] != fd) {
|
|
||||||
#ifdef HAVE_DUP2
|
|
||||||
dup2(script_fds[j], fd);
|
|
||||||
#else
|
|
||||||
close(fd);
|
|
||||||
dup(script_fds[j]);
|
|
||||||
close(script_fds[j]);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
script_fds[j] = fd++;
|
|
||||||
}
|
|
||||||
return(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update output and timing files. */
|
|
||||||
static void
|
static void
|
||||||
log_output(buf, n, then, now, ofile, tfile)
|
log_input(char *buf, unsigned int n)
|
||||||
char *buf;
|
|
||||||
int n;
|
|
||||||
struct timeval *then;
|
|
||||||
struct timeval *now;
|
|
||||||
union script_fd ofile;
|
|
||||||
union script_fd tfile;
|
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct plugin_container *plugin;
|
||||||
sigset_t omask;
|
sigset_t omask;
|
||||||
|
|
||||||
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
|
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
|
||||||
|
|
||||||
#ifdef HAVE_ZLIB
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
if (def_compress_transcript)
|
/* XXX - die if return != TRUE */
|
||||||
gzwrite(ofile.g, buf, n);
|
if (plugin->u.io->log_input)
|
||||||
else
|
plugin->u.io->log_input(buf, n);
|
||||||
#endif
|
}
|
||||||
fwrite(buf, 1, n, ofile.f);
|
|
||||||
timersub(now, then, &tv);
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
#ifdef HAVE_ZLIB
|
}
|
||||||
if (def_compress_transcript)
|
|
||||||
gzprintf(tfile.g, "%f %d\n",
|
/* Call I/O plugin output method. */
|
||||||
tv.tv_sec + ((double)tv.tv_usec / 1000000), n);
|
static void
|
||||||
else
|
log_output(char *buf, unsigned int n)
|
||||||
#endif
|
{
|
||||||
fprintf(tfile.f, "%f %d\n",
|
struct plugin_container *plugin;
|
||||||
tv.tv_sec + ((double)tv.tv_usec / 1000000), n);
|
sigset_t omask;
|
||||||
then->tv_sec = now->tv_sec;
|
|
||||||
then->tv_usec = now->tv_usec;
|
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
|
||||||
|
|
||||||
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
|
/* XXX - die if return != TRUE */
|
||||||
|
if (plugin->u.io->log_output)
|
||||||
|
plugin->u.io->log_output(buf, n);
|
||||||
|
}
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &omask, NULL);
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
check_foreground()
|
check_foreground(void)
|
||||||
{
|
{
|
||||||
foreground = tcgetpgrp(script_fds[SFD_USERTTY]) == parent;
|
foreground = tcgetpgrp(script_fds[SFD_USERTTY]) == parent;
|
||||||
if (foreground && !tty_initialized) {
|
if (foreground && !tty_initialized) {
|
||||||
@@ -370,13 +181,7 @@ check_foreground()
|
|||||||
* Returns SIGUSR1 if the child should be resume in foreground else SIGUSR2.
|
* Returns SIGUSR1 if the child should be resume in foreground else SIGUSR2.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
suspend_parent(signo, output, then, now, ofile, tfile)
|
suspend_parent(int signo, struct script_buf *output)
|
||||||
int signo;
|
|
||||||
struct script_buf *output;
|
|
||||||
struct timeval *then;
|
|
||||||
struct timeval *now;
|
|
||||||
union script_fd ofile;
|
|
||||||
union script_fd tfile;
|
|
||||||
{
|
{
|
||||||
sigaction_t sa, osa;
|
sigaction_t sa, osa;
|
||||||
int n, oldmode = ttymode, rval = 0;
|
int n, oldmode = ttymode, rval = 0;
|
||||||
@@ -404,7 +209,7 @@ suspend_parent(signo, output, then, now, ofile, tfile)
|
|||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case SIGTSTP:
|
case SIGTSTP:
|
||||||
/* Flush any remaining output to master tty. */
|
/* Flush any remaining output to master tty. */
|
||||||
flush_output(output, then, now, ofile, tfile);
|
flush_output(output);
|
||||||
|
|
||||||
/* Restore original tty mode before suspending. */
|
/* Restore original tty mode before suspending. */
|
||||||
if (oldmode != TERM_COOKED) {
|
if (oldmode != TERM_COOKED) {
|
||||||
@@ -469,19 +274,18 @@ suspend_parent(signo, output, then, now, ofile, tfile)
|
|||||||
* controlling tty, belongs to child's session but has its own pgrp.
|
* controlling tty, belongs to child's session but has its own pgrp.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
script_execv(path, argv)
|
script_execve(struct command_details *details, char *argv[], char *envp[],
|
||||||
char *path;
|
struct command_status *cstat)
|
||||||
char *argv[];
|
|
||||||
{
|
{
|
||||||
sigaction_t sa;
|
sigaction_t sa;
|
||||||
struct script_buf input, output;
|
struct script_buf input, output;
|
||||||
struct timeval now, then;
|
int n, nready;
|
||||||
int n, nready, exitcode = 1;
|
|
||||||
int relaysig, sv[2];
|
int relaysig, sv[2];
|
||||||
fd_set *fdsr, *fdsw;
|
fd_set *fdsr, *fdsw;
|
||||||
FILE *idfile;
|
|
||||||
union script_fd ofile, tfile;
|
|
||||||
int rbac_enabled = 0;
|
int rbac_enabled = 0;
|
||||||
|
int maxfd;
|
||||||
|
|
||||||
|
cstat->type = 0; /* XXX */
|
||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
rbac_enabled = is_selinux_enabled() > 0 && user_role != NULL;
|
rbac_enabled = is_selinux_enabled() > 0 && user_role != NULL;
|
||||||
@@ -491,7 +295,7 @@ script_execv(path, argv)
|
|||||||
close(script_fds[SFD_SLAVE]);
|
close(script_fds[SFD_SLAVE]);
|
||||||
script_fds[SFD_SLAVE] = open(slavename, O_RDWR|O_NOCTTY, 0);
|
script_fds[SFD_SLAVE] = open(slavename, O_RDWR|O_NOCTTY, 0);
|
||||||
if (script_fds[SFD_SLAVE] == -1)
|
if (script_fds[SFD_SLAVE] == -1)
|
||||||
log_error(USE_ERRNO, "cannot open %s", slavename);
|
error(1, "cannot open %s", slavename);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -542,8 +346,8 @@ script_execv(path, argv)
|
|||||||
* We communicate with the child over a bi-directional pipe.
|
* We communicate with the child over a bi-directional pipe.
|
||||||
* Parent sends signal info to child and child sends back wait status.
|
* Parent sends signal info to child and child sends back wait status.
|
||||||
*/
|
*/
|
||||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) != 0)
|
if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) != 0)
|
||||||
log_error(USE_ERRNO, "cannot create sockets");
|
error(1, "cannot create sockets");
|
||||||
|
|
||||||
if (foreground) {
|
if (foreground) {
|
||||||
/* Copy terminal attrs from user tty -> pty slave. */
|
/* Copy terminal attrs from user tty -> pty slave. */
|
||||||
@@ -559,7 +363,7 @@ script_execv(path, argv)
|
|||||||
ttymode == TERM_CBREAK);
|
ttymode == TERM_CBREAK);
|
||||||
} while (!n && errno == EINTR);
|
} while (!n && errno == EINTR);
|
||||||
if (!n)
|
if (!n)
|
||||||
log_error(USE_ERRNO, "Can't set terminal to raw mode");
|
error(1, "Can't set terminal to raw mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -569,43 +373,22 @@ script_execv(path, argv)
|
|||||||
child = fork();
|
child = fork();
|
||||||
switch (child) {
|
switch (child) {
|
||||||
case -1:
|
case -1:
|
||||||
log_error(USE_ERRNO, "fork");
|
error(1, "fork");
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
|
/* child */
|
||||||
close(sv[0]);
|
close(sv[0]);
|
||||||
script_child(path, argv, sv[1], rbac_enabled);
|
if (exec_setup(details) == 0) {
|
||||||
/* NOTREACHED */
|
/* headed for execve() */
|
||||||
break;
|
script_child(details->command, argv, envp, sv[1], rbac_enabled);
|
||||||
|
}
|
||||||
|
cstat->type = CMD_ERRNO;
|
||||||
|
cstat->val = errno;
|
||||||
|
send(sv[1], cstat, sizeof(*cstat), 0);
|
||||||
|
_exit(1);
|
||||||
}
|
}
|
||||||
close(sv[1]);
|
close(sv[1]);
|
||||||
|
|
||||||
if ((idfile = fdopen(script_fds[SFD_LOG], "w")) == NULL)
|
|
||||||
log_error(USE_ERRNO, "fdopen");
|
|
||||||
#ifdef HAVE_ZLIB
|
|
||||||
if (def_compress_transcript) {
|
|
||||||
if ((ofile.g = gzdopen(script_fds[SFD_OUTPUT], "w")) == NULL)
|
|
||||||
log_error(USE_ERRNO, "gzdopen");
|
|
||||||
if ((tfile.g = gzdopen(script_fds[SFD_TIMING], "w")) == NULL)
|
|
||||||
log_error(USE_ERRNO, "gzdopen");
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if ((ofile.f = fdopen(script_fds[SFD_OUTPUT], "w")) == NULL)
|
|
||||||
log_error(USE_ERRNO, "fdopen");
|
|
||||||
if ((tfile.f = fdopen(script_fds[SFD_TIMING], "w")) == NULL)
|
|
||||||
log_error(USE_ERRNO, "fdopen");
|
|
||||||
}
|
|
||||||
|
|
||||||
gettimeofday(&then, NULL);
|
|
||||||
|
|
||||||
/* XXX - log more stuff? window size? environment? */
|
|
||||||
fprintf(idfile, "%ld:%s:%s:%s:%s\n", then.tv_sec, user_name,
|
|
||||||
runas_pw->pw_name, runas_gr ? runas_gr->gr_name : "", user_tty);
|
|
||||||
fprintf(idfile, "%s\n", user_cwd);
|
|
||||||
fprintf(idfile, "%s%s%s\n", user_cmnd, user_args ? " " : "",
|
|
||||||
user_args ? user_args : "");
|
|
||||||
fclose(idfile);
|
|
||||||
|
|
||||||
n = fcntl(script_fds[SFD_MASTER], F_GETFL, 0);
|
n = fcntl(script_fds[SFD_MASTER], F_GETFL, 0);
|
||||||
if (n != -1) {
|
if (n != -1) {
|
||||||
n |= O_NONBLOCK;
|
n |= O_NONBLOCK;
|
||||||
@@ -622,13 +405,19 @@ script_execv(path, argv)
|
|||||||
(void) fcntl(STDOUT_FILENO, F_SETFL, n);
|
(void) fcntl(STDOUT_FILENO, F_SETFL, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Max fd we will be selecting on. */
|
||||||
|
maxfd = sv[0];
|
||||||
|
if (maxfd < script_fds[SFD_MASTER])
|
||||||
|
maxfd = script_fds[SFD_MASTER];
|
||||||
|
if (maxfd < script_fds[SFD_USERTTY])
|
||||||
|
maxfd = script_fds[SFD_USERTTY];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the event loop we pass input from user tty to master
|
* In the event loop we pass input from user tty to master
|
||||||
* and pass output from master to stdout and ofile. Note that
|
* and pass output from master to stdout and IO plugin.
|
||||||
* we've set things up such that master is > 3 (see sudo.c).
|
|
||||||
*/
|
*/
|
||||||
fdsr = (fd_set *)emalloc2(howmany(sv[0] + 1, NFDBITS), sizeof(fd_mask));
|
fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
|
||||||
fdsw = (fd_set *)emalloc2(howmany(sv[0] + 1, NFDBITS), sizeof(fd_mask));
|
fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
|
||||||
zero_bytes(&input, sizeof(input));
|
zero_bytes(&input, sizeof(input));
|
||||||
zero_bytes(&output, sizeof(output));
|
zero_bytes(&output, sizeof(output));
|
||||||
while (alive) {
|
while (alive) {
|
||||||
@@ -643,8 +432,8 @@ script_execv(path, argv)
|
|||||||
if (output.off == output.len)
|
if (output.off == output.len)
|
||||||
output.off = output.len = 0;
|
output.off = output.len = 0;
|
||||||
|
|
||||||
zero_bytes(fdsw, howmany(sv[0] + 1, NFDBITS) * sizeof(fd_mask));
|
zero_bytes(fdsw, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
|
||||||
zero_bytes(fdsr, howmany(sv[0] + 1, NFDBITS) * sizeof(fd_mask));
|
zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
|
||||||
|
|
||||||
if (ttymode == TERM_RAW && input.len != sizeof(input.buf))
|
if (ttymode == TERM_RAW && input.len != sizeof(input.buf))
|
||||||
FD_SET(script_fds[SFD_USERTTY], fdsr);
|
FD_SET(script_fds[SFD_USERTTY], fdsr);
|
||||||
@@ -658,51 +447,50 @@ script_execv(path, argv)
|
|||||||
if (relaysig)
|
if (relaysig)
|
||||||
FD_SET(sv[0], fdsw);
|
FD_SET(sv[0], fdsw);
|
||||||
|
|
||||||
nready = select(sv[0] + 1, fdsr, fdsw, NULL, NULL);
|
nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL);
|
||||||
if (nready == -1) {
|
if (nready == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
log_error(USE_ERRNO, "select failed");
|
error(1, "select failed");
|
||||||
}
|
}
|
||||||
if (FD_ISSET(sv[0], fdsr)) {
|
if (FD_ISSET(sv[0], fdsr)) {
|
||||||
/* read child status */
|
/* read child status */
|
||||||
n = read(sv[0], &child_status, sizeof(child_status));
|
n = recv(sv[0], cstat, sizeof(*cstat), 0);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
if (errno != EAGAIN)
|
if (errno != EAGAIN)
|
||||||
break;
|
break;
|
||||||
} else if (n != sizeof(child_status)) {
|
} else if (n != sizeof(*cstat)) {
|
||||||
break; /* EOF? */
|
break; /* EOF? */
|
||||||
}
|
}
|
||||||
if (WIFSTOPPED(child_status)) {
|
if (cstat->type == CMD_WSTATUS) {
|
||||||
|
if (WIFSTOPPED(cstat->val)) {
|
||||||
/* Suspend parent and tell child how to resume on return. */
|
/* Suspend parent and tell child how to resume on return. */
|
||||||
#ifdef SCRIPT_DEBUG
|
#ifdef SCRIPT_DEBUG
|
||||||
warningx("child stopped, suspending parent");
|
warningx("child stopped, suspending parent");
|
||||||
#endif
|
#endif
|
||||||
relaysig = suspend_parent(WSTOPSIG(child_status),
|
relaysig = suspend_parent(WSTOPSIG(cstat->val), &output);
|
||||||
&output, &then, &now, ofile, tfile);
|
|
||||||
/* XXX - write relaysig immediately? */
|
/* XXX - write relaysig immediately? */
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
/* Child exited or was killed, either way we are done. */
|
/* Child exited or was killed, either way we are done. */
|
||||||
if (WIFEXITED(child_status))
|
break;
|
||||||
exitcode = WEXITSTATUS(child_status);
|
}
|
||||||
else if (WIFSIGNALED(child_status))
|
} else if (cstat->type == CMD_ERRNO) {
|
||||||
exitcode = WTERMSIG(child_status) | 128;
|
/* Child was unable to execute command. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (FD_ISSET(sv[0], fdsw)) {
|
if (FD_ISSET(sv[0], fdsw)) {
|
||||||
/* XXX - we rely on child to be suspended before we suspend us */
|
/* XXX - we rely on child to be suspended before we suspend us */
|
||||||
n = write(sv[0], &relaysig, sizeof(relaysig));
|
cstat->type = CMD_SIGNO;
|
||||||
|
cstat->val = relaysig;
|
||||||
relaysig = 0;
|
relaysig = 0;
|
||||||
if (n == -1) {
|
do {
|
||||||
if (errno == EINTR)
|
n = send(sv[0], cstat, sizeof(*cstat), 0);
|
||||||
continue;
|
} while (n == -1 && errno == EINTR);
|
||||||
if (errno != EAGAIN)
|
if (n != sizeof(relaysig)) {
|
||||||
break;
|
|
||||||
} else if (n != sizeof(relaysig)) {
|
|
||||||
break; /* should not happen */
|
break; /* should not happen */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -717,6 +505,7 @@ script_execv(path, argv)
|
|||||||
} else {
|
} else {
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
break; /* got EOF */
|
break; /* got EOF */
|
||||||
|
log_input(input.buf + input.len, n);
|
||||||
input.len += n;
|
input.len += n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -733,7 +522,6 @@ script_execv(path, argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (FD_ISSET(script_fds[SFD_MASTER], fdsr)) {
|
if (FD_ISSET(script_fds[SFD_MASTER], fdsr)) {
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
n = read(script_fds[SFD_MASTER], output.buf + output.len,
|
n = read(script_fds[SFD_MASTER], output.buf + output.len,
|
||||||
sizeof(output.buf) - output.len);
|
sizeof(output.buf) - output.len);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
@@ -744,9 +532,7 @@ script_execv(path, argv)
|
|||||||
} else {
|
} else {
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
break; /* got EOF */
|
break; /* got EOF */
|
||||||
|
log_output(output.buf + output.len, n);
|
||||||
/* Update output and timing files. */
|
|
||||||
log_output(output.buf + output.len, n, &then, &now, ofile, tfile);
|
|
||||||
output.len += n;
|
output.len += n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -770,26 +556,15 @@ script_execv(path, argv)
|
|||||||
n &= ~O_NONBLOCK;
|
n &= ~O_NONBLOCK;
|
||||||
(void) fcntl(STDOUT_FILENO, F_SETFL, n);
|
(void) fcntl(STDOUT_FILENO, F_SETFL, n);
|
||||||
}
|
}
|
||||||
flush_output(&output, &then, &now, ofile, tfile);
|
flush_output(&output);
|
||||||
|
|
||||||
#ifdef HAVE_ZLIB
|
|
||||||
if (def_compress_transcript) {
|
|
||||||
gzclose(ofile.g);
|
|
||||||
gzclose(tfile.g);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
fclose(ofile.f);
|
|
||||||
fclose(tfile.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_STRSIGNAL
|
#ifdef HAVE_STRSIGNAL
|
||||||
if (WIFSIGNALED(child_status)) {
|
if (cstat->type == CMD_WSTATUS && WIFSIGNALED(cstat->val)) {
|
||||||
int signo = WTERMSIG(child_status);
|
int signo = WTERMSIG(cstat->val);
|
||||||
if (signo && signo != SIGINT && signo != SIGPIPE) {
|
if (signo && signo != SIGINT && signo != SIGPIPE) {
|
||||||
char *reason = strsignal(signo);
|
char *reason = strsignal(signo);
|
||||||
write(STDOUT_FILENO, reason, strlen(reason));
|
write(STDOUT_FILENO, reason, strlen(reason));
|
||||||
if (WCOREDUMP(child_status))
|
if (WCOREDUMP(cstat->val))
|
||||||
write(STDOUT_FILENO, " (core dumped)", 14);
|
write(STDOUT_FILENO, " (core dumped)", 14);
|
||||||
write(STDOUT_FILENO, "\n", 1);
|
write(STDOUT_FILENO, "\n", 1);
|
||||||
}
|
}
|
||||||
@@ -800,30 +575,22 @@ script_execv(path, argv)
|
|||||||
n = term_restore(script_fds[SFD_USERTTY], 0);
|
n = term_restore(script_fds[SFD_USERTTY], 0);
|
||||||
} while (!n && errno == EINTR);
|
} while (!n && errno == EINTR);
|
||||||
|
|
||||||
exit(exitcode);
|
return cstat->type == CMD_ERRNO ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
script_child(path, argv, backchannel, rbac_enabled)
|
script_child(const char *path, char *argv[], char *envp[], int backchannel, int rbac)
|
||||||
char *path;
|
|
||||||
char *argv[];
|
|
||||||
int backchannel;
|
|
||||||
int rbac_enabled;
|
|
||||||
{
|
{
|
||||||
|
struct command_status cstat;
|
||||||
|
fd_set *fdsr;
|
||||||
sigaction_t sa;
|
sigaction_t sa;
|
||||||
pid_t pid, self = getpid();
|
pid_t pid, self = getpid();
|
||||||
int nread, signo, status;
|
int n, signo, status;
|
||||||
#ifndef TIOCSCTTY
|
|
||||||
int n;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
recvsig = 0;
|
recvsig = 0;
|
||||||
|
|
||||||
/* Close unused fds. */
|
/* Close unused fds. */
|
||||||
close(script_fds[SFD_MASTER]);
|
close(script_fds[SFD_MASTER]);
|
||||||
close(script_fds[SFD_LOG]);
|
|
||||||
close(script_fds[SFD_OUTPUT]);
|
|
||||||
close(script_fds[SFD_TIMING]);
|
|
||||||
close(script_fds[SFD_USERTTY]);
|
close(script_fds[SFD_USERTTY]);
|
||||||
|
|
||||||
/* Reset signal handlers. */
|
/* Reset signal handlers. */
|
||||||
@@ -840,8 +607,7 @@ script_child(path, argv, backchannel, rbac_enabled)
|
|||||||
sigaction(SIGTTIN, &sa, NULL);
|
sigaction(SIGTTIN, &sa, NULL);
|
||||||
sigaction(SIGTTOU, &sa, NULL);
|
sigaction(SIGTTOU, &sa, NULL);
|
||||||
|
|
||||||
/* We want SIGCHLD to interrupt us. */
|
/* SIGCHLD will interrupt select. */
|
||||||
sa.sa_flags = 0; /* do not restart syscalls for these signals. */
|
|
||||||
sa.sa_handler = handler;
|
sa.sa_handler = handler;
|
||||||
sigaction(SIGCHLD, &sa, NULL);
|
sigaction(SIGCHLD, &sa, NULL);
|
||||||
|
|
||||||
@@ -853,7 +619,7 @@ script_child(path, argv, backchannel, rbac_enabled)
|
|||||||
#ifdef HAVE_SETSID
|
#ifdef HAVE_SETSID
|
||||||
if (setsid() == -1) {
|
if (setsid() == -1) {
|
||||||
warning("setsid");
|
warning("setsid");
|
||||||
_exit(1);
|
goto bad;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# ifdef TIOCNOTTY
|
# ifdef TIOCNOTTY
|
||||||
@@ -869,7 +635,7 @@ script_child(path, argv, backchannel, rbac_enabled)
|
|||||||
#endif
|
#endif
|
||||||
#ifdef TIOCSCTTY
|
#ifdef TIOCSCTTY
|
||||||
if (ioctl(script_fds[SFD_SLAVE], TIOCSCTTY, NULL) != 0)
|
if (ioctl(script_fds[SFD_SLAVE], TIOCSCTTY, NULL) != 0)
|
||||||
log_error(USE_ERRNO, "unable to set controlling tty");
|
error(1, "unable to set controlling tty");
|
||||||
#else
|
#else
|
||||||
/* Set controlling tty by reopening slave. */
|
/* Set controlling tty by reopening slave. */
|
||||||
if ((n = open(slavename, O_RDWR)) >= 0)
|
if ((n = open(slavename, O_RDWR)) >= 0)
|
||||||
@@ -880,10 +646,11 @@ script_child(path, argv, backchannel, rbac_enabled)
|
|||||||
foreground = 0;
|
foreground = 0;
|
||||||
|
|
||||||
/* Start command and wait for it to stop or exit */
|
/* Start command and wait for it to stop or exit */
|
||||||
|
/* XXX - use details->timeout */
|
||||||
child = fork();
|
child = fork();
|
||||||
if (child == -1) {
|
if (child == -1) {
|
||||||
warning("Can't fork");
|
warning("Can't fork");
|
||||||
_exit(1);
|
goto bad;
|
||||||
}
|
}
|
||||||
if (child == 0) {
|
if (child == 0) {
|
||||||
/* Reset signal handlers. */
|
/* Reset signal handlers. */
|
||||||
@@ -900,9 +667,9 @@ script_child(path, argv, backchannel, rbac_enabled)
|
|||||||
sigaction(SIGUSR2, &sa, NULL);
|
sigaction(SIGUSR2, &sa, NULL);
|
||||||
|
|
||||||
/* setup tty and exec command */
|
/* setup tty and exec command */
|
||||||
script_run(path, argv, rbac_enabled);
|
script_run(path, argv, envp, rbac);
|
||||||
warning("unable to execute %s", path);
|
warning("unable to execute %s", path); /* XXX - leave this to plugin? */
|
||||||
_exit(127);
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -917,6 +684,9 @@ script_child(path, argv, backchannel, rbac_enabled)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for signal on backchannel or for SIGCHLD */
|
/* Wait for signal on backchannel or for SIGCHLD */
|
||||||
|
fdsr = (fd_set *)emalloc2(howmany(backchannel + 1, NFDBITS), sizeof(fd_mask));
|
||||||
|
zero_bytes(fdsr, howmany(backchannel + 1, NFDBITS) * sizeof(fd_mask));
|
||||||
|
FD_SET(backchannel, fdsr);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Read child status, assumes recvsig can only be SIGCHLD */
|
/* Read child status, assumes recvsig can only be SIGCHLD */
|
||||||
while (recvsig) {
|
while (recvsig) {
|
||||||
@@ -934,26 +704,43 @@ script_child(path, argv, backchannel, rbac_enabled)
|
|||||||
else
|
else
|
||||||
warningx("command exited?");
|
warningx("command exited?");
|
||||||
#endif
|
#endif
|
||||||
if (write(backchannel, &status, sizeof(status)) != sizeof(status))
|
cstat.type = CMD_WSTATUS;
|
||||||
|
cstat.val = status;
|
||||||
|
do {
|
||||||
|
n = send(backchannel, &cstat, sizeof(cstat), 0);
|
||||||
|
} while (n == -1 && errno == EINTR);
|
||||||
|
if (n != sizeof(cstat))
|
||||||
break; /* XXX - error, kill child and exit */
|
break; /* XXX - error, kill child and exit */
|
||||||
#ifdef SCRIPT_DEBUG
|
#ifdef SCRIPT_DEBUG
|
||||||
warningx("sent signo to parent");
|
warningx("sent signo to parent");
|
||||||
#endif
|
#endif
|
||||||
if (!WIFSTOPPED(status)) {
|
if (!WIFSTOPPED(status)) {
|
||||||
|
/* XXX */
|
||||||
_exit(1); /* child dead */
|
_exit(1); /* child dead */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nread = read(backchannel, &signo, sizeof(signo));
|
n = select(backchannel + 1, fdsr, NULL, NULL, NULL);
|
||||||
if (nread == -1) {
|
if (n == -1) {
|
||||||
if (errno != EINTR)
|
if (errno == EINTR)
|
||||||
break; /* XXX - error, kill child and exit */
|
|
||||||
continue;
|
continue;
|
||||||
|
error(1, "select failed");
|
||||||
}
|
}
|
||||||
if (nread != sizeof(signo)) {
|
|
||||||
/* EOF? */
|
/* read child status */
|
||||||
|
n = recv(backchannel, &cstat, sizeof(cstat), 0);
|
||||||
|
if (n == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
} else if (n != sizeof(cstat)) {
|
||||||
|
warningx("error reading command status");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (cstat.type != CMD_SIGNO) {
|
||||||
|
warningx("unexpected reply type on backchannel: %d", cstat.type);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
signo = cstat.val;
|
||||||
|
|
||||||
/* Handle signal from parent. */
|
/* Handle signal from parent. */
|
||||||
#ifdef SCRIPT_DEBUG
|
#ifdef SCRIPT_DEBUG
|
||||||
@@ -961,7 +748,7 @@ script_child(path, argv, backchannel, rbac_enabled)
|
|||||||
#endif
|
#endif
|
||||||
switch (signo) {
|
switch (signo) {
|
||||||
case SIGKILL:
|
case SIGKILL:
|
||||||
_exit(1);
|
_exit(1); /* XXX */
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
case SIGHUP:
|
case SIGHUP:
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
@@ -991,16 +778,14 @@ script_child(path, argv, backchannel, rbac_enabled)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_exit(1);
|
_exit(1); /* XXX */
|
||||||
|
|
||||||
|
bad:
|
||||||
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
flush_output(output, then, now, ofile, tfile)
|
flush_output(struct script_buf *output)
|
||||||
struct script_buf *output;
|
|
||||||
struct timeval *then;
|
|
||||||
struct timeval *now;
|
|
||||||
union script_fd ofile;
|
|
||||||
union script_fd tfile;
|
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
@@ -1017,7 +802,8 @@ flush_output(output, then, now, ofile, tfile)
|
|||||||
n = read(script_fds[SFD_MASTER], output->buf, sizeof(output->buf));
|
n = read(script_fds[SFD_MASTER], output->buf, sizeof(output->buf));
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
break;
|
break;
|
||||||
log_output(output->buf, n, &then, &now, ofile, tfile);
|
/* XXX */
|
||||||
|
log_output(output->buf, n);
|
||||||
output->off = 0;
|
output->off = 0;
|
||||||
output->len = n;
|
output->len = n;
|
||||||
do {
|
do {
|
||||||
@@ -1031,10 +817,7 @@ flush_output(output, then, now, ofile, tfile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
script_run(path, argv, rbac_enabled)
|
script_run(const char *path, char *argv[], char *envp[], int rbac_enabled)
|
||||||
char *path;
|
|
||||||
char *argv[];
|
|
||||||
int rbac_enabled;
|
|
||||||
{
|
{
|
||||||
pid_t self = getpid();
|
pid_t self = getpid();
|
||||||
|
|
||||||
@@ -1058,16 +841,14 @@ script_run(path, argv, rbac_enabled)
|
|||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
if (rbac_enabled)
|
if (rbac_enabled)
|
||||||
selinux_execv(path, argv);
|
selinux_execve(path, argv, envp);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
execv(path, argv);
|
execve(path, argv, envp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sync_winsize(src, dst)
|
sync_winsize(int src, int dst)
|
||||||
int src;
|
|
||||||
int dst;
|
|
||||||
{
|
{
|
||||||
#ifdef TIOCGWINSZ
|
#ifdef TIOCGWINSZ
|
||||||
struct winsize win;
|
struct winsize win;
|
||||||
@@ -1087,8 +868,7 @@ sync_winsize(src, dst)
|
|||||||
* Handler for SIGCHLD in parent
|
* Handler for SIGCHLD in parent
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
sigchild(s)
|
sigchild(int s)
|
||||||
int s;
|
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int serrno = errno;
|
int serrno = errno;
|
||||||
@@ -1110,8 +890,7 @@ sigchild(s)
|
|||||||
* Generic handler for signals passed from parent -> child
|
* Generic handler for signals passed from parent -> child
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
handler(s)
|
handler(int s)
|
||||||
int s;
|
|
||||||
{
|
{
|
||||||
recvsig = s;
|
recvsig = s;
|
||||||
}
|
}
|
||||||
@@ -1120,8 +899,7 @@ handler(s)
|
|||||||
* Handler for SIGWINCH in parent
|
* Handler for SIGWINCH in parent
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
sigwinch(s)
|
sigwinch(int s)
|
||||||
int s;
|
|
||||||
{
|
{
|
||||||
int serrno = errno;
|
int serrno = errno;
|
||||||
|
|
||||||
|
893
src/sudo.c
Normal file
893
src/sudo.c
Normal file
@@ -0,0 +1,893 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __TANDEM
|
||||||
|
# include <floss.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#ifdef HAVE_SYS_SELECT_H
|
||||||
|
# include <sys/select.h>
|
||||||
|
#endif /* HAVE_SYS_SELECT_H */
|
||||||
|
#ifdef HAVE_SETRLIMIT
|
||||||
|
# include <sys/time.h>
|
||||||
|
# include <sys/resource.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef STDC_HEADERS
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <stddef.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STDLIB_H
|
||||||
|
# include <stdlib.h>
|
||||||
|
# endif
|
||||||
|
#endif /* STDC_HEADERS */
|
||||||
|
#ifdef HAVE_STRING_H
|
||||||
|
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
|
||||||
|
# include <memory.h>
|
||||||
|
# endif
|
||||||
|
# include <string.h>
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_STRINGS_H
|
||||||
|
# include <strings.h>
|
||||||
|
# endif
|
||||||
|
#endif /* HAVE_STRING_H */
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif /* HAVE_UNISTD_H */
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#if TIME_WITH_SYS_TIME
|
||||||
|
# include <time.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SETLOCALE
|
||||||
|
# include <locale.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_LOGIN_CAP_H
|
||||||
|
# include <login_cap.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sudo_usage.h>
|
||||||
|
#include "sudo.h"
|
||||||
|
#include "sudo_plugin.h"
|
||||||
|
#include "sudo_plugin_int.h"
|
||||||
|
|
||||||
|
#ifdef USING_NONUNIX_GROUPS
|
||||||
|
# include "nonunix.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables
|
||||||
|
*/
|
||||||
|
struct plugin_container policy_plugin;
|
||||||
|
struct plugin_container_list io_plugins;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local functions
|
||||||
|
*/
|
||||||
|
static void fix_fds(void);
|
||||||
|
static void disable_coredumps(void);
|
||||||
|
static char **get_user_info(struct user_details *);
|
||||||
|
static void command_info_to_details(char * const info[],
|
||||||
|
struct command_details *details);
|
||||||
|
static int run_command(struct command_details *details, char *argv[],
|
||||||
|
char *envp[]);
|
||||||
|
|
||||||
|
/* XXX - header file */
|
||||||
|
extern const char *list_user, *runas_user, *runas_group;
|
||||||
|
|
||||||
|
/* Used by getprogname() unless crt0 supports getting program name. */
|
||||||
|
int Argc;
|
||||||
|
char **Argv;
|
||||||
|
|
||||||
|
#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
|
||||||
|
static struct rlimit corelimit;
|
||||||
|
#endif /* RLIMIT_CORE && !SUDO_DEVEL */
|
||||||
|
sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[], char *envp[])
|
||||||
|
{
|
||||||
|
sigaction_t sa;
|
||||||
|
int nargc, sudo_mode;
|
||||||
|
char **nargv, **settings, **env_add;
|
||||||
|
char **user_info, **command_info, **argv_out, **user_env_out;
|
||||||
|
struct plugin_container *plugin;
|
||||||
|
struct user_details user_details;
|
||||||
|
struct command_details command_details;
|
||||||
|
int ok;
|
||||||
|
#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
|
||||||
|
extern char *malloc_options;
|
||||||
|
malloc_options = "AFGJPR";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Argc = argc;
|
||||||
|
Argv = argv;
|
||||||
|
|
||||||
|
#ifdef HAVE_SETLOCALE
|
||||||
|
setlocale(LC_ALL, "");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (geteuid() != 0)
|
||||||
|
errorx(1, "must be setuid root");
|
||||||
|
|
||||||
|
/* XXX - Must be done before shadow file lookups... */
|
||||||
|
#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS)
|
||||||
|
(void) set_auth_parameters(Argc, Argv);
|
||||||
|
# ifdef HAVE_INITPRIVS
|
||||||
|
initprivs();
|
||||||
|
# endif
|
||||||
|
#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Signal setup:
|
||||||
|
* Ignore keyboard-generated signals so the user cannot interrupt
|
||||||
|
* us at some point and avoid the logging.
|
||||||
|
* XXX - leave this to the plugin?
|
||||||
|
*/
|
||||||
|
zero_bytes(&sa, sizeof(sa));
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
sa.sa_handler = SIG_IGN;
|
||||||
|
(void) sigaction(SIGINT, &sa, &saved_sa_int);
|
||||||
|
(void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
|
||||||
|
(void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
|
||||||
|
|
||||||
|
/* Turn off core dumps and make sure fds 0-2 are open. */
|
||||||
|
disable_coredumps();
|
||||||
|
fix_fds();
|
||||||
|
|
||||||
|
/* Parse command line arguments. */
|
||||||
|
sudo_mode = parse_args(Argc, Argv, &nargc, &nargv, &settings, &env_add);
|
||||||
|
|
||||||
|
/* Read sudo.conf and load plugins. */
|
||||||
|
sudo_load_plugins(_PATH_SUDO_CONF, &policy_plugin, &io_plugins);
|
||||||
|
|
||||||
|
/* Fill in user_info with user name, uid, cwd, etc. */
|
||||||
|
memset(&user_details, 0, sizeof(user_details));
|
||||||
|
user_info = get_user_info(&user_details);
|
||||||
|
|
||||||
|
/* Open each plugin (XXX - check for errors). */
|
||||||
|
policy_plugin.u.policy->open(SUDO_API_VERSION, sudo_conversation,
|
||||||
|
settings, user_info, envp);
|
||||||
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
|
/* XXX - remove from list if open returns 0 */
|
||||||
|
plugin->u.io->open(SUDO_API_VERSION, sudo_conversation, settings,
|
||||||
|
user_info, envp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX - should not need to check for MODE_INVALIDATE ORed in */
|
||||||
|
warningx("sudo_mode %d", sudo_mode); /* XXX */
|
||||||
|
switch (sudo_mode & MODE_MASK) {
|
||||||
|
case MODE_VERSION:
|
||||||
|
policy_plugin.u.policy->show_version(!user_details.uid);
|
||||||
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
|
plugin->u.io->show_version(!user_details.uid);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MODE_VALIDATE:
|
||||||
|
case MODE_VALIDATE|MODE_INVALIDATE:
|
||||||
|
if (policy_plugin.u.policy->validate == NULL) {
|
||||||
|
warningx("policy plugin %s does not support the -v flag",
|
||||||
|
policy_plugin.name);
|
||||||
|
ok = FALSE;
|
||||||
|
} else {
|
||||||
|
ok = policy_plugin.u.policy->validate();
|
||||||
|
}
|
||||||
|
exit(ok != TRUE);
|
||||||
|
case MODE_KILL:
|
||||||
|
case MODE_INVALIDATE:
|
||||||
|
if (policy_plugin.u.policy->validate == NULL) {
|
||||||
|
warningx("policy plugin %s does not support the -k/-K flags",
|
||||||
|
policy_plugin.name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
policy_plugin.u.policy->invalidate(sudo_mode == MODE_KILL);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
case MODE_CHECK:
|
||||||
|
case MODE_CHECK|MODE_INVALIDATE:
|
||||||
|
case MODE_LIST:
|
||||||
|
case MODE_LIST|MODE_INVALIDATE:
|
||||||
|
if (policy_plugin.u.policy->list == NULL) {
|
||||||
|
warningx("policy plugin %s does not support listing privileges",
|
||||||
|
policy_plugin.name);
|
||||||
|
ok = FALSE;
|
||||||
|
} else {
|
||||||
|
ok = policy_plugin.u.policy->list(nargc, nargv,
|
||||||
|
ISSET(sudo_mode, MODE_LONG_LIST), list_user);
|
||||||
|
}
|
||||||
|
exit(ok != TRUE);
|
||||||
|
case MODE_RUN:
|
||||||
|
ok = policy_plugin.u.policy->check_policy(nargc, nargv, env_add,
|
||||||
|
&command_info, &argv_out, &user_env_out);
|
||||||
|
warningx("policy plugin returns %d", ok); /* XXX */
|
||||||
|
if (ok != TRUE)
|
||||||
|
exit(ok); /* plugin printed error message */
|
||||||
|
command_info_to_details(command_info, &command_details);
|
||||||
|
/* Restore coredumpsize resource limit before running. */
|
||||||
|
#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
|
||||||
|
(void) setrlimit(RLIMIT_CORE, &corelimit);
|
||||||
|
#endif /* RLIMIT_CORE && !SUDO_DEVEL */
|
||||||
|
/* run_command will call close for us */
|
||||||
|
run_command(&command_details, argv_out, user_env_out);
|
||||||
|
break;
|
||||||
|
case MODE_EDIT:
|
||||||
|
/* XXX - fill in */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorx(1, "unexpected sudo mode 0x%x", sudo_mode);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure that stdin, stdout and stderr are open; set to /dev/null if not.
|
||||||
|
* Some operating systems do this automatically in the kernel or libc.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
fix_fds(void)
|
||||||
|
{
|
||||||
|
int miss[3], devnull = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* stdin, stdout and stderr must be open; set them to /dev/null
|
||||||
|
* if they are closed.
|
||||||
|
*/
|
||||||
|
miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1;
|
||||||
|
miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1;
|
||||||
|
miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1;
|
||||||
|
if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) {
|
||||||
|
if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
|
||||||
|
if (miss[STDIN_FILENO])
|
||||||
|
(void) dup2(devnull, STDIN_FILENO);
|
||||||
|
if (miss[STDOUT_FILENO])
|
||||||
|
(void) dup2(devnull, STDOUT_FILENO);
|
||||||
|
if (miss[STDERR_FILENO])
|
||||||
|
(void) dup2(devnull, STDERR_FILENO);
|
||||||
|
if (devnull > STDERR_FILENO)
|
||||||
|
close(devnull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_user_groups(struct user_details *ud)
|
||||||
|
{
|
||||||
|
char *gid_list = NULL;
|
||||||
|
#ifdef HAVE_GETGROUPS
|
||||||
|
size_t glsize;
|
||||||
|
char *cp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((ud->ngroups = getgroups(0, NULL)) <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T));
|
||||||
|
if (getgroups(ud->ngroups, ud->groups) < 0)
|
||||||
|
error(1, "can't get group vector");
|
||||||
|
glsize = sizeof("groups=") - 1 + (ud->ngroups * (MAX_UID_T_LEN + 1));
|
||||||
|
gid_list = emalloc(glsize);
|
||||||
|
memcpy(gid_list, "groups=", sizeof("groups=") - 1);
|
||||||
|
cp = gid_list + sizeof("groups=") - 1;
|
||||||
|
for (i = 0; i < ud->ngroups; i++) {
|
||||||
|
snprintf(cp, glsize - (cp - gid_list), "%lu%s",
|
||||||
|
(unsigned long)ud->groups[i], i ? "," : "");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return gid_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return user information as an array of name=value pairs.
|
||||||
|
* and fill in struct user_details (which shares the same strings).
|
||||||
|
*/
|
||||||
|
static char **
|
||||||
|
get_user_info(struct user_details *ud)
|
||||||
|
{
|
||||||
|
char cwd[PATH_MAX];
|
||||||
|
char host[MAXHOSTNAMELEN];
|
||||||
|
char **user_info, *cp;
|
||||||
|
struct passwd *pw;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
/* XXX - bound check number of entries */
|
||||||
|
user_info = emalloc2(32, sizeof(char *));
|
||||||
|
|
||||||
|
ud->uid = getuid();
|
||||||
|
ud->euid = geteuid();
|
||||||
|
ud->gid = getgid();
|
||||||
|
ud->egid = getegid();
|
||||||
|
|
||||||
|
pw = getpwuid(ud->uid);
|
||||||
|
if (pw == NULL)
|
||||||
|
errorx(1, "unknown uid %lu: who are you?", (unsigned long)ud->uid);
|
||||||
|
|
||||||
|
user_info[i] = fmt_string("user", pw->pw_name);
|
||||||
|
ud->username = user_info[i] + sizeof("user=") - 1;
|
||||||
|
|
||||||
|
easprintf(&user_info[++i], "uid=%lu", (unsigned long)ud->uid);
|
||||||
|
easprintf(&user_info[++i], "euid=%lu", (unsigned long)ud->euid);
|
||||||
|
easprintf(&user_info[++i], "gid=%lu", (unsigned long)ud->gid);
|
||||||
|
easprintf(&user_info[++i], "egid=%lu", (unsigned long)ud->egid);
|
||||||
|
|
||||||
|
if ((cp = get_user_groups(ud)) != NULL)
|
||||||
|
user_info[++i] = cp;
|
||||||
|
|
||||||
|
if (getcwd(cwd, sizeof(cwd)) != NULL) {
|
||||||
|
user_info[++i] = fmt_string("cwd", cwd);
|
||||||
|
ud->cwd = user_info[i] + sizeof("cwd=") - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cp = ttyname(STDIN_FILENO)) || (cp = ttyname(STDOUT_FILENO)) ||
|
||||||
|
(cp = ttyname(STDERR_FILENO))) {
|
||||||
|
user_info[++i] = fmt_string("tty", cp);
|
||||||
|
ud->tty = user_info[i] + sizeof("tty=") - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gethostname(host, sizeof(host)) == 0)
|
||||||
|
host[sizeof(host) - 1] = '\0';
|
||||||
|
else
|
||||||
|
strlcpy(host, "localhost", sizeof(host));
|
||||||
|
user_info[++i] = fmt_string("host", host);
|
||||||
|
ud->host = user_info[i] + sizeof("host=") - 1;
|
||||||
|
|
||||||
|
user_info[++i] = NULL;
|
||||||
|
|
||||||
|
return user_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a command_info array into a command_details structure.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
command_info_to_details(char * const info[], struct command_details *details)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
long lval;
|
||||||
|
unsigned long ulval;
|
||||||
|
char *cp, *ep;
|
||||||
|
|
||||||
|
memset(details, 0, sizeof(*details));
|
||||||
|
|
||||||
|
for (i = 0; info[i] != NULL; i++) {
|
||||||
|
/* XXX - should ignore empty entries */
|
||||||
|
switch (info[i][0]) {
|
||||||
|
case 'c':
|
||||||
|
if (strncmp("chroot=", info[i], sizeof("chroot=") - 1) == 0) {
|
||||||
|
details->chroot = info[i] + sizeof("chroot=") - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strncmp("command=", info[i], sizeof("command=") - 1) == 0) {
|
||||||
|
details->command = info[i] + sizeof("command=") - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strncmp("cwd=", info[i], sizeof("cwd=") - 1) == 0) {
|
||||||
|
details->cwd = info[i] + sizeof("cwd=") - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
if (strncmp("login_class=", info[i], sizeof("login_class=") - 1) == 0) {
|
||||||
|
details->login_class = info[i] + sizeof("login_class=") - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
/* XXX - bounds check -NZERO to NZERO (inclusive). */
|
||||||
|
if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) {
|
||||||
|
cp = info[i] + sizeof("nice=") - 1;
|
||||||
|
errno = 0;
|
||||||
|
lval = strtol(cp, &ep, 0);
|
||||||
|
if (*cp != '\0' && *ep == '\0' &&
|
||||||
|
!(errno == ERANGE &&
|
||||||
|
(lval == LONG_MAX || lval == LONG_MIN)) &&
|
||||||
|
lval < INT_MAX && lval > INT_MIN) {
|
||||||
|
details->priority = (int)lval;
|
||||||
|
SET(details->flags, CD_SET_PRIORITY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) {
|
||||||
|
if (atobool(info[i] + sizeof("noexec=") - 1))
|
||||||
|
SET(details->flags, CD_NOEXEC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (strncmp("preserve_groups=", info[i], sizeof("preserve_groups=") - 1) == 0) {
|
||||||
|
if (atobool(info[i] + sizeof("preserve_groups=") - 1))
|
||||||
|
SET(details->flags, CD_PRESERVE_GROUPS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) {
|
||||||
|
cp = info[i] + sizeof("runas_egid=") - 1;
|
||||||
|
errno = 0;
|
||||||
|
ulval = strtoul(cp, &ep, 0);
|
||||||
|
if (*cp != '\0' && *ep == '\0' &&
|
||||||
|
(errno != ERANGE || ulval != ULONG_MAX)) {
|
||||||
|
details->egid = (gid_t)ulval;
|
||||||
|
SET(details->flags, CD_SET_EGID);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) {
|
||||||
|
cp = info[i] + sizeof("runas_euid=") - 1;
|
||||||
|
errno = 0;
|
||||||
|
ulval = strtoul(cp, &ep, 0);
|
||||||
|
if (*cp != '\0' && *ep == '\0' &&
|
||||||
|
(errno != ERANGE || ulval != ULONG_MAX)) {
|
||||||
|
details->euid = (uid_t)ulval;
|
||||||
|
SET(details->flags, CD_SET_EUID);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) {
|
||||||
|
cp = info[i] + sizeof("runas_gid=") - 1;
|
||||||
|
errno = 0;
|
||||||
|
ulval = strtoul(cp, &ep, 0);
|
||||||
|
if (*cp != '\0' && *ep == '\0' &&
|
||||||
|
(errno != ERANGE || ulval != ULONG_MAX)) {
|
||||||
|
details->gid = (gid_t)ulval;
|
||||||
|
SET(details->flags, CD_SET_GID);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/* count groups, alloc and fill in */
|
||||||
|
cp = info[i] + sizeof("runas_groups=") - 1;
|
||||||
|
for (;;) {
|
||||||
|
details->ngroups++;
|
||||||
|
if ((cp = strchr(cp, ',')) == NULL)
|
||||||
|
break;
|
||||||
|
cp++;
|
||||||
|
}
|
||||||
|
details->groups = emalloc2(details->ngroups, sizeof(GETGROUPS_T));
|
||||||
|
cp = info[i] + sizeof("runas_groups=") - 1;
|
||||||
|
for (j = 0; j < details->ngroups;) {
|
||||||
|
errno = 0;
|
||||||
|
ulval = strtoul(cp, &ep, 0);
|
||||||
|
if (*cp != '\0' && (*ep == ',' || *ep == '\0') &&
|
||||||
|
(errno != ERANGE || ulval != ULONG_MAX)) {
|
||||||
|
details->groups[j++] = (gid_t)ulval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
details->ngroups = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) {
|
||||||
|
cp = info[i] + sizeof("runas_uid=") - 1;
|
||||||
|
errno = 0;
|
||||||
|
ulval = strtoul(cp, &ep, 0);
|
||||||
|
if (*cp != '\0' && *ep == '\0' &&
|
||||||
|
(errno != ERANGE || ulval != ULONG_MAX)) {
|
||||||
|
details->uid = (uid_t)ulval;
|
||||||
|
SET(details->flags, CD_SET_UID);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if (strncmp("selinux_role=", info[i], sizeof("selinux_role=") - 1) == 0) {
|
||||||
|
details->selinux_role = info[i] + sizeof("selinux_role=") - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strncmp("selinux_type=", info[i], sizeof("selinux_type=") - 1) == 0) {
|
||||||
|
details->selinux_type = info[i] + sizeof("selinux_type=") - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) {
|
||||||
|
cp = info[i] + sizeof("timeout=") - 1;
|
||||||
|
errno = 0;
|
||||||
|
lval = strtol(cp, &ep, 0);
|
||||||
|
if (*cp != '\0' && *ep == '\0' &&
|
||||||
|
!(errno == ERANGE &&
|
||||||
|
(lval == LONG_MAX || lval == LONG_MIN)) &&
|
||||||
|
lval <= INT_MAX && lval >= 0) {
|
||||||
|
details->timeout = (int)lval;
|
||||||
|
SET(details->flags, CD_SET_TIMEOUT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) {
|
||||||
|
cp = info[i] + sizeof("umask=") - 1;
|
||||||
|
errno = 0;
|
||||||
|
ulval = strtoul(cp, &ep, 8);
|
||||||
|
if (*cp != '\0' && *ep == '\0' &&
|
||||||
|
(errno != ERANGE || ulval != ULONG_MAX)) {
|
||||||
|
details->umask = (uid_t)ulval;
|
||||||
|
SET(details->flags, CD_SET_UMASK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ISSET(details->flags, CD_SET_EUID))
|
||||||
|
details->euid = details->uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable core dumps to avoid dropping a core with user password in it.
|
||||||
|
* We will reset this limit before executing the command.
|
||||||
|
* Not all operating systems disable core dumps for setuid processes.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
disable_coredumps(void)
|
||||||
|
{
|
||||||
|
#if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL))
|
||||||
|
struct rlimit rl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
/*
|
||||||
|
* Unlimit the number of processes since Linux's setuid() will
|
||||||
|
* apply resource limits when changing uid and return EAGAIN if
|
||||||
|
* nproc would be violated by the uid switch.
|
||||||
|
*/
|
||||||
|
rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
|
||||||
|
if (setrlimit(RLIMIT_NPROC, &rl)) {
|
||||||
|
if (getrlimit(RLIMIT_NPROC, &rl) == 0) {
|
||||||
|
rl.rlim_cur = rl.rlim_max;
|
||||||
|
(void)setrlimit(RLIMIT_NPROC, &rl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* __linux__ */
|
||||||
|
#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)
|
||||||
|
/*
|
||||||
|
* Turn off core dumps.
|
||||||
|
*/
|
||||||
|
(void) getrlimit(RLIMIT_CORE, &corelimit);
|
||||||
|
memcpy(&rl, &corelimit, sizeof(struct rlimit));
|
||||||
|
rl.rlim_cur = 0;
|
||||||
|
(void) setrlimit(RLIMIT_CORE, &rl);
|
||||||
|
#endif /* RLIMIT_CORE && !SUDO_DEVEL */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cleanup hook for error()/errorx()
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cleanup(gotsignal)
|
||||||
|
int gotsignal;
|
||||||
|
{
|
||||||
|
#if 0 /* XXX */
|
||||||
|
struct sudo_nss *nss;
|
||||||
|
|
||||||
|
if (!gotsignal) {
|
||||||
|
if (snl != NULL) {
|
||||||
|
tq_foreach_fwd(snl, nss)
|
||||||
|
nss->close(nss);
|
||||||
|
}
|
||||||
|
sudo_endpwent();
|
||||||
|
sudo_endgrent();
|
||||||
|
}
|
||||||
|
#ifdef _PATH_SUDO_TRANSCRIPT
|
||||||
|
if (def_transcript)
|
||||||
|
term_restore(STDIN_FILENO, 0);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup the execution environment immediately prior to the call to execve()
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
exec_setup(struct command_details *details)
|
||||||
|
{
|
||||||
|
struct passwd *pw;
|
||||||
|
|
||||||
|
pw = getpwuid(details->euid);
|
||||||
|
if (pw != NULL) {
|
||||||
|
#ifdef HAVE_GETUSERATTR
|
||||||
|
aix_setlimits(pw->pw_name);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_LOGIN_CAP_H
|
||||||
|
if (details->login_class) {
|
||||||
|
int flags;
|
||||||
|
login_cap_t *lc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only use setusercontext() to set the nice value and rlimits.
|
||||||
|
*/
|
||||||
|
lc = login_getclass((char *)details->login_class);
|
||||||
|
if (!lc) {
|
||||||
|
warningx("unknown login class %s", details->login_class);
|
||||||
|
errno = ENOENT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
|
||||||
|
if (setusercontext(lc, pw, pw->pw_uid, flags)) {
|
||||||
|
if (pw->pw_uid != ROOT_UID) {
|
||||||
|
warning("unable to set user context");
|
||||||
|
goto done;
|
||||||
|
} else
|
||||||
|
warning("unable to set user context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* HAVE_LOGIN_CAP_H */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set groups, including supplementary group vector.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_SETEUID
|
||||||
|
if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) {
|
||||||
|
warning("unable to set egid to runas gid");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (ISSET(details->flags, CD_SET_GID) && setgid(details->gid)) {
|
||||||
|
warning("unable to set gid to runas gid");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) {
|
||||||
|
/* XXX - may need to initgroups anyway--plugin may not have list */
|
||||||
|
#ifdef HAVE_GETGROUPS
|
||||||
|
if (details->ngroups >= 0) {
|
||||||
|
if (setgroups(details->ngroups, details->groups) < 0) {
|
||||||
|
warning("unable to set supplementary group IDs");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (pw && initgroups(pw->pw_name, pw->pw_gid) < 0) {
|
||||||
|
warning("unable to set supplementary group IDs");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ISSET(details->flags, CD_SET_PRIORITY)) {
|
||||||
|
if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) {
|
||||||
|
warning("unable to set process priority");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ISSET(details->flags, CD_SET_UMASK))
|
||||||
|
(void) umask(details->umask);
|
||||||
|
if (ISSET(details->flags, CD_SET_TIMEOUT))
|
||||||
|
alarm(details->timeout);
|
||||||
|
if (details->chroot) {
|
||||||
|
if (chroot(details->chroot) != 0 || chdir("/") != 0) {
|
||||||
|
warning("unable to change root to %s", details->chroot);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (details->cwd) {
|
||||||
|
/* cwd is relative to the new root, if any */
|
||||||
|
if (chdir(details->cwd) != 0) {
|
||||||
|
warning("unable to change directory to %s", details->cwd);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must set uids last */
|
||||||
|
#ifdef HAVE_SETRESUID
|
||||||
|
if (setresuid(details->uid, details->euid, details->euid) != 0) {
|
||||||
|
warning("unable to change to runas uid");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#elif HAVE_SETREUID
|
||||||
|
if (setreuid(details->uid, details->euid) != 0) {
|
||||||
|
warning("unable to change to runas uid");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (seteuid(details->euid) != 0 || setuid(details->euid) != 0) {
|
||||||
|
warning("unable to change to runas uid");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static sig_atomic_t sigchld;
|
||||||
|
|
||||||
|
static void
|
||||||
|
sigchild(int s)
|
||||||
|
{
|
||||||
|
sigchld = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run the command and wait for it to complete.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
run_command(struct command_details *details, char *argv[], char *envp[])
|
||||||
|
{
|
||||||
|
struct plugin_container *plugin;
|
||||||
|
struct command_status cstat;
|
||||||
|
int exitcode = 1;
|
||||||
|
|
||||||
|
cstat.type = CMD_INVALID;
|
||||||
|
cstat.val = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX - missing closefrom(), may not be possible in new scheme
|
||||||
|
* also no background support
|
||||||
|
* or selinux...
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* If there are I/O plugins, allocate a pty and exec */
|
||||||
|
if (!tq_empty(&io_plugins)) {
|
||||||
|
warningx("script mode"); /* XXX */
|
||||||
|
script_setup(details->euid);
|
||||||
|
script_execve(details, argv, envp, &cstat);
|
||||||
|
} else {
|
||||||
|
pid_t child, pid;
|
||||||
|
int nready, sv[2];
|
||||||
|
ssize_t nread;
|
||||||
|
sigaction_t sa;
|
||||||
|
fd_set *fdsr;
|
||||||
|
|
||||||
|
zero_bytes(&sa, sizeof(sa));
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
|
||||||
|
/* Want select() to be interrupted when child dies. */
|
||||||
|
sa.sa_handler = sigchild;
|
||||||
|
sigaction(SIGCHLD, &sa, NULL);
|
||||||
|
|
||||||
|
/* Ignore SIGPIPE from other end of socketpair. */
|
||||||
|
sa.sa_handler = SIG_IGN;
|
||||||
|
sigaction(SIGPIPE, &sa, NULL);
|
||||||
|
|
||||||
|
if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) != 0)
|
||||||
|
error(1, "cannot create sockets");
|
||||||
|
|
||||||
|
child = fork();
|
||||||
|
if (child == -1)
|
||||||
|
error(1, "unable to fork");
|
||||||
|
|
||||||
|
if (child == 0) {
|
||||||
|
/* child */
|
||||||
|
close(sv[0]);
|
||||||
|
if (exec_setup(details) == 0) {
|
||||||
|
/* XXX - fallback via /bin/sh */
|
||||||
|
execve(details->command, argv, envp);
|
||||||
|
}
|
||||||
|
cstat.type = CMD_ERRNO;
|
||||||
|
cstat.val = errno;
|
||||||
|
write(sv[1], &cstat, sizeof(cstat));
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
close(sv[1]);
|
||||||
|
warningx("waiting for child"); /* XXX */
|
||||||
|
|
||||||
|
/* wait for child to complete or for data on sv[0] */
|
||||||
|
fdsr = (fd_set *)emalloc2(howmany(sv[0] + 1, NFDBITS), sizeof(fd_mask));
|
||||||
|
zero_bytes(fdsr, howmany(sv[0] + 1, NFDBITS) * sizeof(fd_mask));
|
||||||
|
FD_SET(sv[0], fdsr);
|
||||||
|
for (;;) {
|
||||||
|
if (sigchld) {
|
||||||
|
sigchld = 0;
|
||||||
|
do {
|
||||||
|
pid = waitpid(child, &cstat.val, WNOHANG);
|
||||||
|
if (pid == child)
|
||||||
|
cstat.type = CMD_WSTATUS;
|
||||||
|
} while (pid == -1 && errno == EINTR);
|
||||||
|
if (cstat.type == CMD_WSTATUS) {
|
||||||
|
/* command terminated, we're done */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nready = select(sv[0] + 1, fdsr, NULL, NULL, NULL);
|
||||||
|
if (nready == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
error(1, "select failed");
|
||||||
|
}
|
||||||
|
if (FD_ISSET(sv[0], fdsr)) {
|
||||||
|
/* read child status */
|
||||||
|
nread = recv(sv[0], &cstat, sizeof(cstat), 0);
|
||||||
|
if (nread == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
} else if (nread != sizeof(cstat)) {
|
||||||
|
warningx("error reading command status");
|
||||||
|
}
|
||||||
|
break; /* XXX */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cstat.type) {
|
||||||
|
case CMD_ERRNO:
|
||||||
|
/* exec_setup() or execve() returned an error. */
|
||||||
|
policy_plugin.u.policy->close(0, cstat.val);
|
||||||
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
|
plugin->u.io->close(0, cstat.val);
|
||||||
|
}
|
||||||
|
exitcode = 1;
|
||||||
|
break;
|
||||||
|
case CMD_WSTATUS:
|
||||||
|
/* Command ran, exited or was killed. */
|
||||||
|
policy_plugin.u.policy->close(cstat.val, 0);
|
||||||
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
|
plugin->u.io->close(0, cstat.val);
|
||||||
|
}
|
||||||
|
if (WIFEXITED(cstat.val))
|
||||||
|
exitcode = WEXITSTATUS(cstat.val);
|
||||||
|
else if (WIFSIGNALED(cstat.val))
|
||||||
|
exitcode = WTERMSIG(cstat.val) | 128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warningx("unexpected child termination condition: %d", cstat.type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
exit(exitcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 /* XXX - convert warning/error to something log this */
|
||||||
|
/*
|
||||||
|
* Simple debugging/logging.
|
||||||
|
* XXX - use askpass if configured?
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
sudo_log(int level, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case SUDO_LOG_INFO:
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stdout, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
break;
|
||||||
|
case SUDO_LOG_DEBUG1:
|
||||||
|
case SUDO_LOG_DEBUG2:
|
||||||
|
case SUDO_LOG_DEBUG3:
|
||||||
|
case SUDO_LOG_DEBUG4:
|
||||||
|
case SUDO_LOG_DEBUG5:
|
||||||
|
case SUDO_LOG_DEBUG6:
|
||||||
|
case SUDO_LOG_DEBUG7:
|
||||||
|
case SUDO_LOG_DEBUG8:
|
||||||
|
case SUDO_LOG_DEBUG9:
|
||||||
|
if (level > debug_level)
|
||||||
|
return;
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case SUDO_LOG_WARN:
|
||||||
|
case SUDO_LOG_ERROR:
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
234
src/sudo.h
Normal file
234
src/sudo.h
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1993-1996, 1998-2005, 2007-2009
|
||||||
|
* Todd C. Miller <Todd.Miller@courtesan.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* Sponsored in part by the Defense Advanced Research Projects
|
||||||
|
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||||
|
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||||
|
*
|
||||||
|
* $Sudo: sudo.h,v 1.290 2009/12/12 16:12:26 millert Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SUDO_SUDO_H
|
||||||
|
#define _SUDO_SUDO_H
|
||||||
|
|
||||||
|
#include <pathnames.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include "compat.h"
|
||||||
|
#include "alloc.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "missing.h"
|
||||||
|
|
||||||
|
#ifdef __TANDEM
|
||||||
|
# define ROOT_UID 65535
|
||||||
|
#else
|
||||||
|
# define ROOT_UID 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pseudo-boolean values
|
||||||
|
*/
|
||||||
|
#undef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#undef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Various modes sudo can be in (based on arguments) in hex
|
||||||
|
*/
|
||||||
|
#define MODE_RUN 0x00000001
|
||||||
|
#define MODE_EDIT 0x00000002
|
||||||
|
#define MODE_VALIDATE 0x00000004
|
||||||
|
#define MODE_INVALIDATE 0x00000008
|
||||||
|
#define MODE_KILL 0x00000010
|
||||||
|
#define MODE_VERSION 0x00000020
|
||||||
|
#define MODE_HELP 0x00000040
|
||||||
|
#define MODE_LIST 0x00000080
|
||||||
|
#define MODE_CHECK 0x00000100
|
||||||
|
#define MODE_MASK 0x0000ffff
|
||||||
|
|
||||||
|
/* Mode flags */
|
||||||
|
/* XXX - prune this */
|
||||||
|
#define MODE_BACKGROUND 0x00010000
|
||||||
|
#define MODE_SHELL 0x00020000
|
||||||
|
#define MODE_LOGIN_SHELL 0x00040000
|
||||||
|
#define MODE_IMPLIED_SHELL 0x00080000
|
||||||
|
#define MODE_RESET_HOME 0x00100000
|
||||||
|
#define MODE_PRESERVE_GROUPS 0x00200000
|
||||||
|
#define MODE_PRESERVE_ENV 0x00400000
|
||||||
|
#define MODE_NONINTERACTIVE 0x00800000
|
||||||
|
#define MODE_LONG_LIST 0x01000000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used with set_perms()
|
||||||
|
*/
|
||||||
|
#define PERM_ROOT 0x00
|
||||||
|
#define PERM_USER 0x01
|
||||||
|
#define PERM_FULL_USER 0x02
|
||||||
|
#define PERM_SUDOERS 0x03
|
||||||
|
#define PERM_RUNAS 0x04
|
||||||
|
#define PERM_FULL_RUNAS 0x05
|
||||||
|
#define PERM_TIMESTAMP 0x06
|
||||||
|
#define PERM_NOEXIT 0x10 /* flag */
|
||||||
|
#define PERM_MASK 0xf0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We used to use the system definition of PASS_MAX or _PASSWD_LEN,
|
||||||
|
* but that caused problems with various alternate authentication
|
||||||
|
* methods. So, we just define our own and assume that it is >= the
|
||||||
|
* system max.
|
||||||
|
*/
|
||||||
|
#define SUDO_PASS_MAX 256
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags for lock_file()
|
||||||
|
*/
|
||||||
|
#define SUDO_LOCK 1 /* lock a file */
|
||||||
|
#define SUDO_TLOCK 2 /* test & lock a file (non-blocking) */
|
||||||
|
#define SUDO_UNLOCK 4 /* unlock a file */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags for tgetpass()
|
||||||
|
*/
|
||||||
|
#define TGP_ECHO 0x01 /* leave echo on when reading passwd */
|
||||||
|
#define TGP_STDIN 0x02 /* read from stdin, not /dev/tty */
|
||||||
|
#define TGP_ASKPASS 0x04 /* read from askpass helper program */
|
||||||
|
#define TGP_FEEDBACK 0x08 /* visual feedback during input */
|
||||||
|
|
||||||
|
struct user_details {
|
||||||
|
uid_t uid;
|
||||||
|
uid_t euid;
|
||||||
|
uid_t gid;
|
||||||
|
uid_t egid;
|
||||||
|
const char *username;
|
||||||
|
const char *cwd;
|
||||||
|
const char *tty;
|
||||||
|
const char *host;
|
||||||
|
GETGROUPS_T *groups;
|
||||||
|
int ngroups;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CD_SET_UID 0x0001
|
||||||
|
#define CD_SET_EUID 0x0002
|
||||||
|
#define CD_SET_GID 0x0004
|
||||||
|
#define CD_SET_EGID 0x0008
|
||||||
|
#define CD_PRESERVE_GROUPS 0x0010
|
||||||
|
#define CD_NOEXEC 0x0020
|
||||||
|
#define CD_SET_PRIORITY 0x0040
|
||||||
|
#define CD_SET_UMASK 0x0080
|
||||||
|
#define CD_SET_TIMEOUT 0x0100
|
||||||
|
|
||||||
|
struct command_details {
|
||||||
|
uid_t uid;
|
||||||
|
uid_t euid;
|
||||||
|
gid_t gid;
|
||||||
|
gid_t egid;
|
||||||
|
mode_t umask;
|
||||||
|
int flags;
|
||||||
|
int priority;
|
||||||
|
int timeout;
|
||||||
|
int ngroups;
|
||||||
|
GETGROUPS_T *groups;
|
||||||
|
const char *command;
|
||||||
|
const char *cwd;
|
||||||
|
const char *login_class;
|
||||||
|
const char *chroot;
|
||||||
|
const char *selinux_role;
|
||||||
|
const char *selinux_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Status passed between parent and child via socketpair */
|
||||||
|
struct command_status {
|
||||||
|
#define CMD_INVALID 0
|
||||||
|
#define CMD_ERRNO 1
|
||||||
|
#define CMD_WSTATUS 2
|
||||||
|
#define CMD_SIGNO 3
|
||||||
|
int type;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* For error() and errorx() (XXX - needed?) */
|
||||||
|
void cleanup(int);
|
||||||
|
|
||||||
|
/* tgetpass.c */
|
||||||
|
char *tgetpass(const char *, int, int);
|
||||||
|
int tty_present(void);
|
||||||
|
|
||||||
|
/* zero_bytes.c */
|
||||||
|
void zero_bytes(volatile void *, size_t);
|
||||||
|
|
||||||
|
/* fileops.c */
|
||||||
|
int lock_file(int, int);
|
||||||
|
char *sudo_parseln(FILE *);
|
||||||
|
|
||||||
|
/* script.c */
|
||||||
|
int script_duplow(int);
|
||||||
|
int script_execve(struct command_details *details, char *argv[], char *envp[],
|
||||||
|
struct command_status *cstat);
|
||||||
|
void script_setup(uid_t);
|
||||||
|
|
||||||
|
/* term.c */
|
||||||
|
int term_cbreak(int);
|
||||||
|
int term_copy(int, int, int);
|
||||||
|
int term_noecho(int);
|
||||||
|
int term_raw(int, int, int);
|
||||||
|
int term_restore(int, int);
|
||||||
|
|
||||||
|
/* fmt_string.h */
|
||||||
|
char *fmt_string(const char *var, const char *value);
|
||||||
|
|
||||||
|
/* atobool.c */
|
||||||
|
int atobool(const char *str);
|
||||||
|
|
||||||
|
/* parse_args.c */
|
||||||
|
int parse_args(int argc, char **argv, int *nargc, char ***nargv,
|
||||||
|
char ***settingsp, char ***env_addp);
|
||||||
|
|
||||||
|
/* pty.c */
|
||||||
|
int get_pty(int *master, int *slave, char *name, size_t namesz, uid_t uid);
|
||||||
|
|
||||||
|
/* sudo.c */
|
||||||
|
int exec_setup(struct command_details *details);
|
||||||
|
extern int debug_level;
|
||||||
|
extern struct plugin_container_list io_plugins;
|
||||||
|
|
||||||
|
#ifndef errno
|
||||||
|
extern int errno;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ntoyet
|
||||||
|
/*
|
||||||
|
* Sudo logging/debugging, printf-style.
|
||||||
|
* XXX - not hooked up yet
|
||||||
|
* The debug level may be set on the command line via the -D flag.
|
||||||
|
* A higher debug level yields more verbose debugging.
|
||||||
|
*/
|
||||||
|
#define SUDO_LOG_DEBUG1 1
|
||||||
|
#define SUDO_LOG_DEBUG2 2
|
||||||
|
#define SUDO_LOG_DEBUG3 3
|
||||||
|
#define SUDO_LOG_DEBUG4 4
|
||||||
|
#define SUDO_LOG_DEBUG5 5
|
||||||
|
#define SUDO_LOG_DEBUG6 6
|
||||||
|
#define SUDO_LOG_DEBUG7 7
|
||||||
|
#define SUDO_LOG_DEBUG8 8
|
||||||
|
#define SUDO_LOG_DEBUG9 9
|
||||||
|
#define SUDO_LOG_INFO 10
|
||||||
|
#define SUDO_LOG_WARN 11
|
||||||
|
#define SUDO_LOG_ERROR 12
|
||||||
|
void sudo_log(int level, const char *format, ...) __printflike(2, 3);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _SUDO_SUDO_H */
|
39
src/sudo_plugin_int.h
Normal file
39
src/sudo_plugin_int.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef _SUDO_PLUGIN_INT_H
|
||||||
|
#define _SUDO_PLUGIN_INT_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sudo plugin internals.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct plugin_info {
|
||||||
|
struct plugin_info *prev; /* required */
|
||||||
|
struct plugin_info *next; /* required */
|
||||||
|
const char *path;
|
||||||
|
const char *symbol_name;
|
||||||
|
};
|
||||||
|
TQ_DECLARE(plugin_info)
|
||||||
|
|
||||||
|
struct plugin_container {
|
||||||
|
struct plugin_container *prev; /* required */
|
||||||
|
struct plugin_container *next; /* required */
|
||||||
|
const char *name;
|
||||||
|
void *handle;
|
||||||
|
union {
|
||||||
|
struct generic_plugin *generic;
|
||||||
|
struct policy_plugin *policy;
|
||||||
|
struct io_plugin *io;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
TQ_DECLARE(plugin_container)
|
||||||
|
|
||||||
|
extern struct plugin_container_list policy_plugins;
|
||||||
|
extern struct plugin_container_list io_plugins;
|
||||||
|
|
||||||
|
int sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
|
||||||
|
struct sudo_conv_reply replies[]);
|
||||||
|
|
||||||
|
void sudo_load_plugins(const char *conf_file,
|
||||||
|
struct plugin_container *policy_plugin,
|
||||||
|
struct plugin_container_list *io_plugins);
|
||||||
|
|
||||||
|
#endif /* _SUDO_PLUGIN_INT_H */
|
@@ -56,6 +56,9 @@
|
|||||||
|
|
||||||
#include "sudo.h"
|
#include "sudo.h"
|
||||||
|
|
||||||
|
/* XXX */
|
||||||
|
char *user_askpass = NULL;
|
||||||
|
|
||||||
static volatile sig_atomic_t signo;
|
static volatile sig_atomic_t signo;
|
||||||
|
|
||||||
static void handler __P((int));
|
static void handler __P((int));
|
||||||
@@ -111,7 +114,7 @@ restart:
|
|||||||
(void) sigaction(SIGTTIN, &sa, &savettin);
|
(void) sigaction(SIGTTIN, &sa, &savettin);
|
||||||
(void) sigaction(SIGTTOU, &sa, &savettou);
|
(void) sigaction(SIGTTOU, &sa, &savettou);
|
||||||
|
|
||||||
if (def_pwfeedback)
|
if (ISSET(flags, TGP_FEEDBACK))
|
||||||
neednl = term_cbreak(input);
|
neednl = term_cbreak(input);
|
||||||
else
|
else
|
||||||
neednl = term_noecho(input);
|
neednl = term_noecho(input);
|
||||||
@@ -123,7 +126,7 @@ restart:
|
|||||||
|
|
||||||
if (timeout > 0)
|
if (timeout > 0)
|
||||||
alarm(timeout);
|
alarm(timeout);
|
||||||
pass = getln(input, buf, sizeof(buf), def_pwfeedback);
|
pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_FEEDBACK));
|
||||||
alarm(0);
|
alarm(0);
|
||||||
save_errno = errno;
|
save_errno = errno;
|
||||||
|
|
||||||
@@ -184,7 +187,8 @@ sudo_askpass(prompt)
|
|||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
/* child, point stdout to output side of the pipe and exec askpass */
|
/* child, point stdout to output side of the pipe and exec askpass */
|
||||||
(void) dup2(pfd[1], STDOUT_FILENO);
|
(void) dup2(pfd[1], STDOUT_FILENO);
|
||||||
set_perms(PERM_FULL_USER);
|
//XXX - set real and effective uid to user
|
||||||
|
//set_perms(PERM_FULL_USER);
|
||||||
closefrom(STDERR_FILENO + 1);
|
closefrom(STDERR_FILENO + 1);
|
||||||
execl(user_askpass, user_askpass, prompt, (char *)NULL);
|
execl(user_askpass, user_askpass, prompt, (char *)NULL);
|
||||||
warning("unable to run %s", user_askpass);
|
warning("unable to run %s", user_askpass);
|
||||||
|
Reference in New Issue
Block a user