Add support for matching command and args using regular expressions.
Either the command, its arguments or both may be (separate) regular expressions.
This commit is contained in:
13
MANIFEST
13
MANIFEST
@@ -921,6 +921,17 @@ plugins/sudoers/regress/sudoers/test27.ldif.ok
|
|||||||
plugins/sudoers/regress/sudoers/test27.ldif2sudo.ok
|
plugins/sudoers/regress/sudoers/test27.ldif2sudo.ok
|
||||||
plugins/sudoers/regress/sudoers/test27.out.ok
|
plugins/sudoers/regress/sudoers/test27.out.ok
|
||||||
plugins/sudoers/regress/sudoers/test27.toke.ok
|
plugins/sudoers/regress/sudoers/test27.toke.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test28.in
|
||||||
|
plugins/sudoers/regress/sudoers/test28.json.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test28.ldif.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test28.ldif2sudo.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test28.out.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test28.toke.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test29.in
|
||||||
|
plugins/sudoers/regress/sudoers/test29.json.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test29.ldif.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test29.out.ok
|
||||||
|
plugins/sudoers/regress/sudoers/test29.toke.ok
|
||||||
plugins/sudoers/regress/sudoers/test3.in
|
plugins/sudoers/regress/sudoers/test3.in
|
||||||
plugins/sudoers/regress/sudoers/test3.json.ok
|
plugins/sudoers/regress/sudoers/test3.json.ok
|
||||||
plugins/sudoers/regress/sudoers/test3.ldif.ok
|
plugins/sudoers/regress/sudoers/test3.ldif.ok
|
||||||
@@ -977,6 +988,8 @@ plugins/sudoers/regress/testsudoers/test16.out.ok
|
|||||||
plugins/sudoers/regress/testsudoers/test16.sh
|
plugins/sudoers/regress/testsudoers/test16.sh
|
||||||
plugins/sudoers/regress/testsudoers/test17.out.ok
|
plugins/sudoers/regress/testsudoers/test17.out.ok
|
||||||
plugins/sudoers/regress/testsudoers/test17.sh
|
plugins/sudoers/regress/testsudoers/test17.sh
|
||||||
|
plugins/sudoers/regress/testsudoers/test18.out.ok
|
||||||
|
plugins/sudoers/regress/testsudoers/test18.sh
|
||||||
plugins/sudoers/regress/testsudoers/test2.inc
|
plugins/sudoers/regress/testsudoers/test2.inc
|
||||||
plugins/sudoers/regress/testsudoers/test2.out.ok
|
plugins/sudoers/regress/testsudoers/test2.out.ok
|
||||||
plugins/sudoers/regress/testsudoers/test2.sh
|
plugins/sudoers/regress/testsudoers/test2.sh
|
||||||
|
18
configure
vendored
18
configure
vendored
@@ -830,6 +830,7 @@ NOEXECFILE
|
|||||||
intercept_file
|
intercept_file
|
||||||
INTERCEPTDIR
|
INTERCEPTDIR
|
||||||
INTERCEPTFILE
|
INTERCEPTFILE
|
||||||
|
mansectmisc
|
||||||
mansectform
|
mansectform
|
||||||
mansectsu
|
mansectsu
|
||||||
devdir
|
devdir
|
||||||
@@ -3567,6 +3568,7 @@ ac_config_headers="$ac_config_headers config.h pathnames.h"
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -5209,6 +5211,7 @@ printf "%s\n" "$as_me: adding CSOps standard options" >&6;}
|
|||||||
with_env_editor=yes
|
with_env_editor=yes
|
||||||
: ${mansectsu='8'}
|
: ${mansectsu='8'}
|
||||||
: ${mansectform='5'}
|
: ${mansectform='5'}
|
||||||
|
: ${mansectmisc='7'}
|
||||||
;;
|
;;
|
||||||
no) ;;
|
no) ;;
|
||||||
*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ignoring unknown argument to --with-csops: $with_csops" >&5
|
*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ignoring unknown argument to --with-csops: $with_csops" >&5
|
||||||
@@ -17094,6 +17097,7 @@ case "$host" in
|
|||||||
fi
|
fi
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
|
test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
|
||||||
|
|
||||||
for ac_func in priv_set
|
for ac_func in priv_set
|
||||||
@@ -17339,6 +17343,7 @@ printf "%s\n" "#define HAVE_DECL_SETAUTHDB $ac_have_decl" >>confdefs.h
|
|||||||
|
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
|
|
||||||
# HP-UX does not clear /var/run so we need to do it
|
# HP-UX does not clear /var/run so we need to do it
|
||||||
INIT_SCRIPT=hpux.sh
|
INIT_SCRIPT=hpux.sh
|
||||||
@@ -17376,6 +17381,7 @@ fi
|
|||||||
fi
|
fi
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
|
|
||||||
# HP-UX does not clear /var/run so we need to do it
|
# HP-UX does not clear /var/run so we need to do it
|
||||||
INIT_SCRIPT=hpux.sh
|
INIT_SCRIPT=hpux.sh
|
||||||
@@ -17587,6 +17593,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
|||||||
RTLD_PRELOAD_DEFAULT="DEFAULT"
|
RTLD_PRELOAD_DEFAULT="DEFAULT"
|
||||||
: ${mansectsu='8'}
|
: ${mansectsu='8'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-*-irix*)
|
*-*-irix*)
|
||||||
printf "%s\n" "#define _BSD_TYPES 1" >>confdefs.h
|
printf "%s\n" "#define _BSD_TYPES 1" >>confdefs.h
|
||||||
@@ -17646,6 +17653,7 @@ fi
|
|||||||
RTLD_PRELOAD_DEFAULT="DEFAULT"
|
RTLD_PRELOAD_DEFAULT="DEFAULT"
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-*-linux*|*-*-k*bsd*-gnu)
|
*-*-linux*|*-*-k*bsd*-gnu)
|
||||||
shadow_funcs="getspnam"
|
shadow_funcs="getspnam"
|
||||||
@@ -17689,18 +17697,21 @@ fi
|
|||||||
shadow_libs="-lprot -lx"
|
shadow_libs="-lprot -lx"
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
m88k-motorola-sysv*)
|
m88k-motorola-sysv*)
|
||||||
# motorolla's cc (a variant of gcc) does -O but not -O2
|
# motorolla's cc (a variant of gcc) does -O but not -O2
|
||||||
CFLAGS=`echo $CFLAGS | sed 's/-O2/-O/g'`
|
CFLAGS=`echo $CFLAGS | sed 's/-O2/-O/g'`
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-sequent-sysv*)
|
*-sequent-sysv*)
|
||||||
shadow_funcs="getspnam"
|
shadow_funcs="getspnam"
|
||||||
shadow_libs="-lsec"
|
shadow_libs="-lsec"
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-ncr-sysv4*|*-ncr-sysvr4*)
|
*-ncr-sysv4*|*-ncr-sysvr4*)
|
||||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for strcasecmp in -lc89" >&5
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for strcasecmp in -lc89" >&5
|
||||||
@@ -17745,11 +17756,13 @@ fi
|
|||||||
|
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-ccur-sysv4*|*-ccur-sysvr4*)
|
*-ccur-sysv4*|*-ccur-sysvr4*)
|
||||||
LIBS="${LIBS} -lgen"
|
LIBS="${LIBS} -lgen"
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-*-bsdi*)
|
*-*-bsdi*)
|
||||||
SKIP_SETREUID=yes
|
SKIP_SETREUID=yes
|
||||||
@@ -18022,10 +18035,12 @@ fi
|
|||||||
*-*-*sysv4*)
|
*-*-*sysv4*)
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-*-*sco3.2*) # SCO OpenServer 5
|
*-*-*sco3.2*) # SCO OpenServer 5
|
||||||
: ${mansectsu='1'}
|
: ${mansectsu='1'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
shadow_funcs="getprpwnam"
|
shadow_funcs="getprpwnam"
|
||||||
shadow_libs="-lprot"
|
shadow_libs="-lprot"
|
||||||
;;
|
;;
|
||||||
@@ -18033,6 +18048,7 @@ fi
|
|||||||
*-*-*sysv5*)
|
*-*-*sysv5*)
|
||||||
: ${mansectsu='1'}
|
: ${mansectsu='1'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
case "$host" in
|
case "$host" in
|
||||||
*-*-sysv5SCO_SV*) # SCO OpenServer 6.x
|
*-*-sysv5SCO_SV*) # SCO OpenServer 6.x
|
||||||
shadow_funcs="getprpwnam"
|
shadow_funcs="getprpwnam"
|
||||||
@@ -18046,6 +18062,7 @@ fi
|
|||||||
*-*-sysv*)
|
*-*-sysv*)
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -18122,6 +18139,7 @@ fi
|
|||||||
|
|
||||||
: ${mansectsu='8'}
|
: ${mansectsu='8'}
|
||||||
: ${mansectform='5'}
|
: ${mansectform='5'}
|
||||||
|
: ${mansectmisc='7'}
|
||||||
|
|
||||||
if test -n "$with_libpath"; then
|
if test -n "$with_libpath"; then
|
||||||
for i in ${with_libpath}; do
|
for i in ${with_libpath}; do
|
||||||
|
17
configure.ac
17
configure.ac
@@ -70,6 +70,7 @@ AC_SUBST([SEMAN])
|
|||||||
AC_SUBST([devdir])
|
AC_SUBST([devdir])
|
||||||
AC_SUBST([mansectsu])
|
AC_SUBST([mansectsu])
|
||||||
AC_SUBST([mansectform])
|
AC_SUBST([mansectform])
|
||||||
|
AC_SUBST([mansectmisc])
|
||||||
AC_SUBST([INTERCEPTFILE])
|
AC_SUBST([INTERCEPTFILE])
|
||||||
AC_SUBST([INTERCEPTDIR])
|
AC_SUBST([INTERCEPTDIR])
|
||||||
AC_SUBST([intercept_file])
|
AC_SUBST([intercept_file])
|
||||||
@@ -495,6 +496,7 @@ AC_ARG_WITH(csops, [AS_HELP_STRING([--with-csops], [add CSOps standard options])
|
|||||||
with_env_editor=yes
|
with_env_editor=yes
|
||||||
: ${mansectsu='8'}
|
: ${mansectsu='8'}
|
||||||
: ${mansectform='5'}
|
: ${mansectform='5'}
|
||||||
|
: ${mansectmisc='7'}
|
||||||
;;
|
;;
|
||||||
no) ;;
|
no) ;;
|
||||||
*) AC_MSG_WARN([ignoring unknown argument to --with-csops: $with_csops])
|
*) AC_MSG_WARN([ignoring unknown argument to --with-csops: $with_csops])
|
||||||
@@ -1790,6 +1792,7 @@ case "$host" in
|
|||||||
fi
|
fi
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
|
test -z "$with_pam" && AUTH_EXCL_DEF="PAM"
|
||||||
AC_CHECK_FUNCS([priv_set], [PSMAN=1])
|
AC_CHECK_FUNCS([priv_set], [PSMAN=1])
|
||||||
;;
|
;;
|
||||||
@@ -1884,6 +1887,7 @@ case "$host" in
|
|||||||
|
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
|
|
||||||
# HP-UX does not clear /var/run so we need to do it
|
# HP-UX does not clear /var/run so we need to do it
|
||||||
INIT_SCRIPT=hpux.sh
|
INIT_SCRIPT=hpux.sh
|
||||||
@@ -1908,6 +1912,7 @@ case "$host" in
|
|||||||
fi
|
fi
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
|
|
||||||
# HP-UX does not clear /var/run so we need to do it
|
# HP-UX does not clear /var/run so we need to do it
|
||||||
INIT_SCRIPT=hpux.sh
|
INIT_SCRIPT=hpux.sh
|
||||||
@@ -2022,6 +2027,7 @@ case "$host" in
|
|||||||
RTLD_PRELOAD_DEFAULT="DEFAULT"
|
RTLD_PRELOAD_DEFAULT="DEFAULT"
|
||||||
: ${mansectsu='8'}
|
: ${mansectsu='8'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-*-irix*)
|
*-*-irix*)
|
||||||
AC_DEFINE([_BSD_TYPES])
|
AC_DEFINE([_BSD_TYPES])
|
||||||
@@ -2041,6 +2047,7 @@ case "$host" in
|
|||||||
RTLD_PRELOAD_DEFAULT="DEFAULT"
|
RTLD_PRELOAD_DEFAULT="DEFAULT"
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-*-linux*|*-*-k*bsd*-gnu)
|
*-*-linux*|*-*-k*bsd*-gnu)
|
||||||
shadow_funcs="getspnam"
|
shadow_funcs="getspnam"
|
||||||
@@ -2069,28 +2076,33 @@ case "$host" in
|
|||||||
shadow_libs="-lprot -lx"
|
shadow_libs="-lprot -lx"
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
m88k-motorola-sysv*)
|
m88k-motorola-sysv*)
|
||||||
# motorolla's cc (a variant of gcc) does -O but not -O2
|
# motorolla's cc (a variant of gcc) does -O but not -O2
|
||||||
CFLAGS=`echo $CFLAGS | sed 's/-O2/-O/g'`
|
CFLAGS=`echo $CFLAGS | sed 's/-O2/-O/g'`
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-sequent-sysv*)
|
*-sequent-sysv*)
|
||||||
shadow_funcs="getspnam"
|
shadow_funcs="getspnam"
|
||||||
shadow_libs="-lsec"
|
shadow_libs="-lsec"
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-ncr-sysv4*|*-ncr-sysvr4*)
|
*-ncr-sysv4*|*-ncr-sysvr4*)
|
||||||
AC_CHECK_LIB(c89, strcasecmp, [LIBS="${LIBS} -lc89"])
|
AC_CHECK_LIB(c89, strcasecmp, [LIBS="${LIBS} -lc89"])
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-ccur-sysv4*|*-ccur-sysvr4*)
|
*-ccur-sysv4*|*-ccur-sysvr4*)
|
||||||
LIBS="${LIBS} -lgen"
|
LIBS="${LIBS} -lgen"
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-*-bsdi*)
|
*-*-bsdi*)
|
||||||
SKIP_SETREUID=yes
|
SKIP_SETREUID=yes
|
||||||
@@ -2239,10 +2251,12 @@ case "$host" in
|
|||||||
*-*-*sysv4*)
|
*-*-*sysv4*)
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
*-*-*sco3.2*) # SCO OpenServer 5
|
*-*-*sco3.2*) # SCO OpenServer 5
|
||||||
: ${mansectsu='1'}
|
: ${mansectsu='1'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
shadow_funcs="getprpwnam"
|
shadow_funcs="getprpwnam"
|
||||||
shadow_libs="-lprot"
|
shadow_libs="-lprot"
|
||||||
;;
|
;;
|
||||||
@@ -2250,6 +2264,7 @@ case "$host" in
|
|||||||
*-*-*sysv5*)
|
*-*-*sysv5*)
|
||||||
: ${mansectsu='1'}
|
: ${mansectsu='1'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
case "$host" in
|
case "$host" in
|
||||||
*-*-sysv5SCO_SV*) # SCO OpenServer 6.x
|
*-*-sysv5SCO_SV*) # SCO OpenServer 6.x
|
||||||
shadow_funcs="getprpwnam"
|
shadow_funcs="getprpwnam"
|
||||||
@@ -2263,6 +2278,7 @@ case "$host" in
|
|||||||
*-*-sysv*)
|
*-*-sysv*)
|
||||||
: ${mansectsu='1m'}
|
: ${mansectsu='1m'}
|
||||||
: ${mansectform='4'}
|
: ${mansectform='4'}
|
||||||
|
: ${mansectmisc='5'}
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -2339,6 +2355,7 @@ dnl Use BSD-style man sections by default
|
|||||||
dnl
|
dnl
|
||||||
: ${mansectsu='8'}
|
: ${mansectsu='8'}
|
||||||
: ${mansectform='5'}
|
: ${mansectform='5'}
|
||||||
|
: ${mansectmisc='7'}
|
||||||
|
|
||||||
dnl
|
dnl
|
||||||
dnl Add in any libpaths or libraries specified via configure
|
dnl Add in any libpaths or libraries specified via configure
|
||||||
|
@@ -1008,13 +1008,20 @@ Digest_List ::= Digest_Spec |
|
|||||||
Cmnd_List ::= Cmnd |
|
Cmnd_List ::= Cmnd |
|
||||||
Cmnd ',' Cmnd_List
|
Cmnd ',' Cmnd_List
|
||||||
|
|
||||||
command name ::= file name |
|
command name ::= regex |
|
||||||
file name args |
|
file name
|
||||||
file name '""'
|
|
||||||
|
|
||||||
Edit_Spec ::= "sudoedit" file name+
|
command ::= command name |
|
||||||
|
command name args |
|
||||||
|
command name regex |
|
||||||
|
command name '""' |
|
||||||
|
ALL
|
||||||
|
|
||||||
Cmnd ::= Digest_List? '!'* command name |
|
Edit_Spec ::= "sudoedit" file name+ |
|
||||||
|
"sudoedit" regex |
|
||||||
|
"sudoedit"
|
||||||
|
|
||||||
|
Cmnd ::= Digest_List? '!'* command |
|
||||||
'!'* directory |
|
'!'* directory |
|
||||||
'!'* Edit_Spec |
|
'!'* Edit_Spec |
|
||||||
'!'* Cmnd_Alias
|
'!'* Cmnd_Alias
|
||||||
@@ -1023,21 +1030,18 @@ Cmnd ::= Digest_List? '!'* command name |
|
|||||||
.PP
|
.PP
|
||||||
A
|
A
|
||||||
\fRCmnd_List\fR
|
\fRCmnd_List\fR
|
||||||
is a list of one or more command names, directories, and other aliases.
|
is a list of one or more commands, directories, or aliases.
|
||||||
A command name is a fully qualified file name which may include
|
A command is a fully qualified file name, which may include
|
||||||
shell-style wildcards (see the
|
shell-style wildcards (see the
|
||||||
\fIWildcards\fR
|
\fIWildcards\fR
|
||||||
|
section below),
|
||||||
|
or a regular expression that starts with
|
||||||
|
\(oq^\(cq
|
||||||
|
and ends with
|
||||||
|
\(oq$\(cq
|
||||||
|
(see the
|
||||||
|
\fIRegular expressions\fR
|
||||||
section below).
|
section below).
|
||||||
A simple file name allows the user to run the command with any
|
|
||||||
arguments they wish.
|
|
||||||
However, you may also specify command line arguments (including
|
|
||||||
wildcards).
|
|
||||||
Alternately, you can specify
|
|
||||||
\fR\&""\fR
|
|
||||||
to indicate that the command
|
|
||||||
may only be run
|
|
||||||
\fBwithout\fR
|
|
||||||
command line arguments.
|
|
||||||
A directory is a
|
A directory is a
|
||||||
fully qualified path name ending in a
|
fully qualified path name ending in a
|
||||||
\(oq/\(cq.
|
\(oq/\(cq.
|
||||||
@@ -1045,21 +1049,49 @@ When you specify a directory in a
|
|||||||
\fRCmnd_List\fR,
|
\fRCmnd_List\fR,
|
||||||
the user will be able to run any file within that directory
|
the user will be able to run any file within that directory
|
||||||
(but not in any sub-directories therein).
|
(but not in any sub-directories therein).
|
||||||
|
If no command line arguments are specified, the user may run the
|
||||||
|
command with any arguments they choose.
|
||||||
|
Command line arguments can include wildcards or be a regular
|
||||||
|
expression that starts with
|
||||||
|
\(oq^\(cq
|
||||||
|
and ends with
|
||||||
|
\(oq$\(cq.
|
||||||
|
If the command line arguments consist of
|
||||||
|
\fR\&""\fR,
|
||||||
|
the command may only be run with
|
||||||
|
\fIno\fR
|
||||||
|
arguments.
|
||||||
.PP
|
.PP
|
||||||
If a
|
If a
|
||||||
\fRCmnd\fR
|
\fRCmnd\fR
|
||||||
has associated command line arguments, then the arguments
|
has associated command line arguments, the arguments
|
||||||
in the
|
in the
|
||||||
\fRCmnd\fR
|
\fRCmnd\fR
|
||||||
must match exactly those given by the user on the command line
|
must match those given by the user on the command line.
|
||||||
(or match the wildcards if there are any).
|
If the arguments in a
|
||||||
Note that the following characters must be escaped with a
|
\fRCmnd\fR
|
||||||
|
begin with the
|
||||||
|
\(oq^\(cq
|
||||||
|
character, they will be interpreted as a regular expression
|
||||||
|
and matched accordingly.
|
||||||
|
Otherwise, shell-style wildcards are used when matching.
|
||||||
|
Unless a regular expression is specified, the following characters must
|
||||||
|
be escaped with a
|
||||||
\(oq\e\(cq
|
\(oq\e\(cq
|
||||||
if they are used in command arguments:
|
if they are used in command arguments:
|
||||||
\(oq,\&\(cq,
|
\(oq,\&\(cq,
|
||||||
\(oq:\&\(cq,
|
\(oq:\&\(cq,
|
||||||
\(oq=\&\(cq,
|
\(oq=\&\(cq,
|
||||||
\(oq\e\(cq.
|
\(oq\e\(cq.
|
||||||
|
To prevent arguments in a
|
||||||
|
\fRCmnd\fR
|
||||||
|
that begin with a
|
||||||
|
\(oq^\(cq
|
||||||
|
character from being interpreted as a regular expression, the
|
||||||
|
\(oq^\(cq
|
||||||
|
must be escaped with a
|
||||||
|
\(oq\e\(cq.
|
||||||
|
.PP
|
||||||
The built-in command
|
The built-in command
|
||||||
\(lq\fRsudoedit\fR\(rq
|
\(lq\fRsudoedit\fR\(rq
|
||||||
is used to permit a user to run
|
is used to permit a user to run
|
||||||
@@ -1076,7 +1108,7 @@ is a command built into
|
|||||||
itself and must be specified in the
|
itself and must be specified in the
|
||||||
\fIsudoers\fR
|
\fIsudoers\fR
|
||||||
file
|
file
|
||||||
\fBwithout\fR
|
\fIwithout\fR
|
||||||
a leading path.
|
a leading path.
|
||||||
If a leading path is present, for example
|
If a leading path is present, for example
|
||||||
\fI/usr/bin/sudoedit\fR,
|
\fI/usr/bin/sudoedit\fR,
|
||||||
@@ -1088,7 +1120,7 @@ is treated as an error by
|
|||||||
\fBvisudo\fR.
|
\fBvisudo\fR.
|
||||||
.PP
|
.PP
|
||||||
A
|
A
|
||||||
\fRcommand name\fR
|
\fRcommand\fR
|
||||||
may be preceded by a
|
may be preceded by a
|
||||||
\fRDigest_List\fR,
|
\fRDigest_List\fR,
|
||||||
a comma-separated list of one or more
|
a comma-separated list of one or more
|
||||||
@@ -1206,6 +1238,8 @@ This is due to there being two levels of escaping, one in the
|
|||||||
\fIsudoers\fR
|
\fIsudoers\fR
|
||||||
parser itself and another when command line arguments are matched by the
|
parser itself and another when command line arguments are matched by the
|
||||||
fnmatch(3)
|
fnmatch(3)
|
||||||
|
or
|
||||||
|
regexec(3)
|
||||||
function.
|
function.
|
||||||
.PP
|
.PP
|
||||||
Lists have two additional assignment operators,
|
Lists have two additional assignment operators,
|
||||||
@@ -2101,6 +2135,75 @@ Command line arguments to the
|
|||||||
built-in command should always be path names, so a forward slash
|
built-in command should always be path names, so a forward slash
|
||||||
(\(oq/\(cq)
|
(\(oq/\(cq)
|
||||||
will not be matched by a wildcard.
|
will not be matched by a wildcard.
|
||||||
|
.SS "Regular expressions"
|
||||||
|
Starting with version 1.9.10, it is possible to use
|
||||||
|
regular expressions for path names and command line arguments.
|
||||||
|
Regular expressions are more expressive than shell-style
|
||||||
|
\fIwildcards\fR
|
||||||
|
and are usually safer because they provide a greater degree of
|
||||||
|
control when matching.
|
||||||
|
The type of regular expressions supported by
|
||||||
|
\fBsudoers\fR
|
||||||
|
are POSIX extended regular expressions, similar to those used by the
|
||||||
|
egrep(1)
|
||||||
|
utility.
|
||||||
|
They are usually documented in the
|
||||||
|
regex(@mansectmisc@)
|
||||||
|
or
|
||||||
|
re_format(@mansectmisc@)
|
||||||
|
manual, depending on the system.
|
||||||
|
As an extension, if the regular expression begins with
|
||||||
|
\(lq(?i)\(rq,
|
||||||
|
it will be matched in a case-insensitive manner.
|
||||||
|
.PP
|
||||||
|
In
|
||||||
|
\fIsudoers\fR,
|
||||||
|
regular expressions must start with a
|
||||||
|
\(oq^\(cq
|
||||||
|
character and end with a
|
||||||
|
\(oq$\(cq.
|
||||||
|
This makes it explicit what is, or is not, a regular expression.
|
||||||
|
Either the path name, the command line arguments or both may
|
||||||
|
be regular expressions.
|
||||||
|
Because the path name and arguments are matched separately, it is
|
||||||
|
even possible to use wildcards for the path name and regular
|
||||||
|
expressions for the arguments.
|
||||||
|
It is not possible to use a single regular expression to match
|
||||||
|
both the command and its arguments.
|
||||||
|
.PP
|
||||||
|
There is no need to escape
|
||||||
|
\fIsudoers\fR
|
||||||
|
special characters in a regular expression other than the pound sign
|
||||||
|
(\(oq#\(cq).
|
||||||
|
.PP
|
||||||
|
In the following example, user
|
||||||
|
\fBjohn\fR
|
||||||
|
can run the passwd, chsh and chfn commands as root on any host but
|
||||||
|
is not allowed to change root's password database entry.
|
||||||
|
This kind of rule is impossible to express safely using wildcards.
|
||||||
|
.nf
|
||||||
|
.sp
|
||||||
|
.RS 4n
|
||||||
|
john ALL = ^/usr/bin/(passwd|chsh|chfn)$ ^[a-zA-Z0-9_]+$,\e
|
||||||
|
!^/usr/bin/(passwd|chsh|chfn)$ root
|
||||||
|
.RE
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
It is also possible to use a regular expression in conjunction with
|
||||||
|
\fBsudoedit\fR
|
||||||
|
rules.
|
||||||
|
The following rule would give user bob the ability to edit the
|
||||||
|
\fI/etc/motd\fR,
|
||||||
|
\fI/etc/issue\fR,
|
||||||
|
and
|
||||||
|
\fI/etc/hosts\fR
|
||||||
|
files only.
|
||||||
|
.nf
|
||||||
|
.sp
|
||||||
|
.RS 4n
|
||||||
|
bob ALL = sudoedit ^/etc/(motd|issue|hosts)$
|
||||||
|
.RE
|
||||||
|
.fi
|
||||||
.SS "Including other files from within sudoers"
|
.SS "Including other files from within sudoers"
|
||||||
It is possible to include other
|
It is possible to include other
|
||||||
\fIsudoers\fR
|
\fIsudoers\fR
|
||||||
|
@@ -968,13 +968,20 @@ Digest_List ::= Digest_Spec |
|
|||||||
Cmnd_List ::= Cmnd |
|
Cmnd_List ::= Cmnd |
|
||||||
Cmnd ',' Cmnd_List
|
Cmnd ',' Cmnd_List
|
||||||
|
|
||||||
command name ::= file name |
|
command name ::= regex |
|
||||||
file name args |
|
file name
|
||||||
file name '""'
|
|
||||||
|
|
||||||
Edit_Spec ::= "sudoedit" file name+
|
command ::= command name |
|
||||||
|
command name args |
|
||||||
|
command name regex |
|
||||||
|
command name '""' |
|
||||||
|
ALL
|
||||||
|
|
||||||
Cmnd ::= Digest_List? '!'* command name |
|
Edit_Spec ::= "sudoedit" file name+ |
|
||||||
|
"sudoedit" regex |
|
||||||
|
"sudoedit"
|
||||||
|
|
||||||
|
Cmnd ::= Digest_List? '!'* command |
|
||||||
'!'* directory |
|
'!'* directory |
|
||||||
'!'* Edit_Spec |
|
'!'* Edit_Spec |
|
||||||
'!'* Cmnd_Alias
|
'!'* Cmnd_Alias
|
||||||
@@ -982,21 +989,18 @@ Cmnd ::= Digest_List? '!'* command name |
|
|||||||
.Pp
|
.Pp
|
||||||
A
|
A
|
||||||
.Li Cmnd_List
|
.Li Cmnd_List
|
||||||
is a list of one or more command names, directories, and other aliases.
|
is a list of one or more commands, directories, or aliases.
|
||||||
A command name is a fully qualified file name which may include
|
A command is a fully qualified file name, which may include
|
||||||
shell-style wildcards (see the
|
shell-style wildcards (see the
|
||||||
.Sx Wildcards
|
.Sx Wildcards
|
||||||
|
section below),
|
||||||
|
or a regular expression that starts with
|
||||||
|
.Ql ^
|
||||||
|
and ends with
|
||||||
|
.Ql $
|
||||||
|
(see the
|
||||||
|
.Sx Regular expressions
|
||||||
section below).
|
section below).
|
||||||
A simple file name allows the user to run the command with any
|
|
||||||
arguments they wish.
|
|
||||||
However, you may also specify command line arguments (including
|
|
||||||
wildcards).
|
|
||||||
Alternately, you can specify
|
|
||||||
.Li \&""
|
|
||||||
to indicate that the command
|
|
||||||
may only be run
|
|
||||||
.Sy without
|
|
||||||
command line arguments.
|
|
||||||
A directory is a
|
A directory is a
|
||||||
fully qualified path name ending in a
|
fully qualified path name ending in a
|
||||||
.Ql / .
|
.Ql / .
|
||||||
@@ -1004,21 +1008,49 @@ When you specify a directory in a
|
|||||||
.Li Cmnd_List ,
|
.Li Cmnd_List ,
|
||||||
the user will be able to run any file within that directory
|
the user will be able to run any file within that directory
|
||||||
(but not in any sub-directories therein).
|
(but not in any sub-directories therein).
|
||||||
|
If no command line arguments are specified, the user may run the
|
||||||
|
command with any arguments they choose.
|
||||||
|
Command line arguments can include wildcards or be a regular
|
||||||
|
expression that starts with
|
||||||
|
.Ql ^
|
||||||
|
and ends with
|
||||||
|
.Ql $ .
|
||||||
|
If the command line arguments consist of
|
||||||
|
.Li \&"" ,
|
||||||
|
the command may only be run with
|
||||||
|
.Em no
|
||||||
|
arguments.
|
||||||
.Pp
|
.Pp
|
||||||
If a
|
If a
|
||||||
.Li Cmnd
|
.Li Cmnd
|
||||||
has associated command line arguments, then the arguments
|
has associated command line arguments, the arguments
|
||||||
in the
|
in the
|
||||||
.Li Cmnd
|
.Li Cmnd
|
||||||
must match exactly those given by the user on the command line
|
must match those given by the user on the command line.
|
||||||
(or match the wildcards if there are any).
|
If the arguments in a
|
||||||
Note that the following characters must be escaped with a
|
.Li Cmnd
|
||||||
|
begin with the
|
||||||
|
.Ql ^
|
||||||
|
character, they will be interpreted as a regular expression
|
||||||
|
and matched accordingly.
|
||||||
|
Otherwise, shell-style wildcards are used when matching.
|
||||||
|
Unless a regular expression is specified, the following characters must
|
||||||
|
be escaped with a
|
||||||
.Ql \e
|
.Ql \e
|
||||||
if they are used in command arguments:
|
if they are used in command arguments:
|
||||||
.Ql ,\& ,
|
.Ql ,\& ,
|
||||||
.Ql :\& ,
|
.Ql :\& ,
|
||||||
.Ql =\& ,
|
.Ql =\& ,
|
||||||
.Ql \e .
|
.Ql \e .
|
||||||
|
To prevent arguments in a
|
||||||
|
.Li Cmnd
|
||||||
|
that begin with a
|
||||||
|
.Ql ^
|
||||||
|
character from being interpreted as a regular expression, the
|
||||||
|
.Ql ^
|
||||||
|
must be escaped with a
|
||||||
|
.Ql \e .
|
||||||
|
.Pp
|
||||||
The built-in command
|
The built-in command
|
||||||
.Dq Li sudoedit
|
.Dq Li sudoedit
|
||||||
is used to permit a user to run
|
is used to permit a user to run
|
||||||
@@ -1035,7 +1067,7 @@ is a command built into
|
|||||||
itself and must be specified in the
|
itself and must be specified in the
|
||||||
.Em sudoers
|
.Em sudoers
|
||||||
file
|
file
|
||||||
.Sy without
|
.Em without
|
||||||
a leading path.
|
a leading path.
|
||||||
If a leading path is present, for example
|
If a leading path is present, for example
|
||||||
.Pa /usr/bin/sudoedit ,
|
.Pa /usr/bin/sudoedit ,
|
||||||
@@ -1047,7 +1079,7 @@ is treated as an error by
|
|||||||
.Nm visudo .
|
.Nm visudo .
|
||||||
.Pp
|
.Pp
|
||||||
A
|
A
|
||||||
.Li command name
|
.Li command
|
||||||
may be preceded by a
|
may be preceded by a
|
||||||
.Li Digest_List ,
|
.Li Digest_List ,
|
||||||
a comma-separated list of one or more
|
a comma-separated list of one or more
|
||||||
@@ -1156,6 +1188,8 @@ This is due to there being two levels of escaping, one in the
|
|||||||
.Em sudoers
|
.Em sudoers
|
||||||
parser itself and another when command line arguments are matched by the
|
parser itself and another when command line arguments are matched by the
|
||||||
.Xr fnmatch 3
|
.Xr fnmatch 3
|
||||||
|
or
|
||||||
|
.Xr regexec 3
|
||||||
function.
|
function.
|
||||||
.Pp
|
.Pp
|
||||||
Lists have two additional assignment operators,
|
Lists have two additional assignment operators,
|
||||||
@@ -1979,6 +2013,69 @@ built-in command should always be path names, so a forward slash
|
|||||||
.Pq Ql /
|
.Pq Ql /
|
||||||
will not be matched by a wildcard.
|
will not be matched by a wildcard.
|
||||||
.El
|
.El
|
||||||
|
.Ss Regular expressions
|
||||||
|
Starting with version 1.9.10, it is possible to use
|
||||||
|
regular expressions for path names and command line arguments.
|
||||||
|
Regular expressions are more expressive than shell-style
|
||||||
|
.Em wildcards
|
||||||
|
and are usually safer because they provide a greater degree of
|
||||||
|
control when matching.
|
||||||
|
The type of regular expressions supported by
|
||||||
|
.Nm
|
||||||
|
are POSIX extended regular expressions, similar to those used by the
|
||||||
|
.Xr egrep 1
|
||||||
|
utility.
|
||||||
|
They are usually documented in the
|
||||||
|
.Xr regex @mansectmisc@
|
||||||
|
or
|
||||||
|
.Xr re_format @mansectmisc@
|
||||||
|
manual, depending on the system.
|
||||||
|
As an extension, if the regular expression begins with
|
||||||
|
.Dq (?i) ,
|
||||||
|
it will be matched in a case-insensitive manner.
|
||||||
|
.Pp
|
||||||
|
In
|
||||||
|
.Em sudoers ,
|
||||||
|
regular expressions must start with a
|
||||||
|
.Ql ^
|
||||||
|
character and end with a
|
||||||
|
.Ql $ .
|
||||||
|
This makes it explicit what is, or is not, a regular expression.
|
||||||
|
Either the path name, the command line arguments or both may
|
||||||
|
be regular expressions.
|
||||||
|
Because the path name and arguments are matched separately, it is
|
||||||
|
even possible to use wildcards for the path name and regular
|
||||||
|
expressions for the arguments.
|
||||||
|
It is not possible to use a single regular expression to match
|
||||||
|
both the command and its arguments.
|
||||||
|
.Pp
|
||||||
|
There is no need to escape
|
||||||
|
.Em sudoers
|
||||||
|
special characters in a regular expression other than the pound sign
|
||||||
|
.Pq Ql # .
|
||||||
|
.Pp
|
||||||
|
In the following example, user
|
||||||
|
.Sy john
|
||||||
|
can run the passwd, chsh and chfn commands as root on any host but
|
||||||
|
is not allowed to change root's password database entry.
|
||||||
|
This kind of rule is impossible to express safely using wildcards.
|
||||||
|
.Bd -literal -offset 4n
|
||||||
|
john ALL = ^/usr/bin/(passwd|chsh|chfn)$ ^[a-zA-Z0-9_]+$,\e
|
||||||
|
!^/usr/bin/(passwd|chsh|chfn)$ root
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
It is also possible to use a regular expression in conjunction with
|
||||||
|
.Nm sudoedit
|
||||||
|
rules.
|
||||||
|
The following rule would give user bob the ability to edit the
|
||||||
|
.Pa /etc/motd ,
|
||||||
|
.Pa /etc/issue ,
|
||||||
|
and
|
||||||
|
.Pa /etc/hosts
|
||||||
|
files only.
|
||||||
|
.Bd -literal -offset 4n
|
||||||
|
bob ALL = sudoedit ^/etc/(motd|issue|hosts)$
|
||||||
|
.Ed
|
||||||
.Ss Including other files from within sudoers
|
.Ss Including other files from within sudoers
|
||||||
It is possible to include other
|
It is possible to include other
|
||||||
.Em sudoers
|
.Em sudoers
|
||||||
|
@@ -69,9 +69,9 @@ root ALL = (ALL:ALL) ALL
|
|||||||
%wheel ALL = (ALL:ALL) ALL
|
%wheel ALL = (ALL:ALL) ALL
|
||||||
|
|
||||||
# full time sysadmins can run anything on any machine without a password
|
# full time sysadmins can run anything on any machine without a password
|
||||||
FULLTIMERS ALL = NOPASSWD: ALL
|
FULLTIMERS ALL = (ALL:ALL) NOPASSWD: ALL
|
||||||
|
|
||||||
# part time sysadmins may run anything but need a password
|
# part time sysadmins may run anything as root but need a password
|
||||||
PARTTIMERS ALL = ALL
|
PARTTIMERS ALL = ALL
|
||||||
|
|
||||||
# jack may run anything on machines in CSNETS
|
# jack may run anything on machines in CSNETS
|
||||||
@@ -88,7 +88,7 @@ operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\
|
|||||||
joe ALL = /usr/bin/su operator
|
joe ALL = /usr/bin/su operator
|
||||||
|
|
||||||
# pete may change passwords for anyone but root on the hp snakes
|
# pete may change passwords for anyone but root on the hp snakes
|
||||||
pete HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd *root*
|
pete HPPA = /usr/bin/passwd ^[a-zA-Z0-9_]+$, !/usr/bin/passwd root
|
||||||
|
|
||||||
# bob may run anything on the sparc and sgi machines as any user
|
# bob may run anything on the sparc and sgi machines as any user
|
||||||
# listed in the Runas_Alias "OP" (ie: root and operator)
|
# listed in the Runas_Alias "OP" (ie: root and operator)
|
||||||
@@ -104,8 +104,8 @@ jim +biglab = ALL
|
|||||||
# fred can run commands as oracle or sybase without a password
|
# fred can run commands as oracle or sybase without a password
|
||||||
fred ALL = (DB) NOPASSWD: ALL
|
fred ALL = (DB) NOPASSWD: ALL
|
||||||
|
|
||||||
# on the alphas, john may su to anyone but root and flags are not allowed
|
# on the alphas, john may su to anyone except root, no flags are allowed.
|
||||||
john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
|
john ALPHA = /usr/bin/su ^[a-zA-Z0-9_]+$, !/usr/bin/su root
|
||||||
|
|
||||||
# jen can run anything on all machines except the ones
|
# jen can run anything on all machines except the ones
|
||||||
# in the "SERVERS" Host_Alias
|
# in the "SERVERS" Host_Alias
|
||||||
|
@@ -68,11 +68,22 @@ sudoers_format_member_int(struct sudo_lbuf *lbuf,
|
|||||||
}
|
}
|
||||||
if (negated)
|
if (negated)
|
||||||
sudo_lbuf_append(lbuf, "!");
|
sudo_lbuf_append(lbuf, "!");
|
||||||
|
if (c->cmnd == NULL || c->cmnd[0] == '^') {
|
||||||
|
/* No additional quoting of characters inside a regex. */
|
||||||
|
sudo_lbuf_append(lbuf, "%s", c->cmnd ? c->cmnd : "ALL");
|
||||||
|
} else {
|
||||||
sudo_lbuf_append_quoted(lbuf, SUDOERS_QUOTED_CMD, "%s",
|
sudo_lbuf_append_quoted(lbuf, SUDOERS_QUOTED_CMD, "%s",
|
||||||
c->cmnd ? c->cmnd : "ALL");
|
c->cmnd);
|
||||||
if (c->args) {
|
}
|
||||||
|
if (c->args != NULL) {
|
||||||
sudo_lbuf_append(lbuf, " ");
|
sudo_lbuf_append(lbuf, " ");
|
||||||
sudo_lbuf_append_quoted(lbuf, SUDOERS_QUOTED_ARG, "%s", c->args);
|
if (c->args[0] == '^') {
|
||||||
|
/* No additional quoting of characters inside a regex. */
|
||||||
|
sudo_lbuf_append(lbuf, "%s", c->args);
|
||||||
|
} else {
|
||||||
|
sudo_lbuf_append_quoted(lbuf, SUDOERS_QUOTED_ARG, "%s",
|
||||||
|
c->args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case USERGROUP:
|
case USERGROUP:
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: ISC
|
* SPDX-License-Identifier: ISC
|
||||||
*
|
*
|
||||||
* Copyright (c) 1996, 1998-2005, 2007-2019
|
* Copyright (c) 1996, 1998-2005, 2007-2022
|
||||||
* Todd C. Miller <Todd.Miller@sudo.ws>
|
* Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
@@ -48,6 +48,7 @@
|
|||||||
#else
|
#else
|
||||||
# include "compat/fnmatch.h"
|
# include "compat/fnmatch.h"
|
||||||
#endif /* HAVE_FNMATCH */
|
#endif /* HAVE_FNMATCH */
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#include "sudoers.h"
|
#include "sudoers.h"
|
||||||
#include <gram.h>
|
#include <gram.h>
|
||||||
@@ -56,9 +57,47 @@
|
|||||||
# define O_EXEC O_PATH
|
# define O_EXEC O_PATH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static bool
|
||||||
|
regex_matches(const char *pattern, const char *str)
|
||||||
|
{
|
||||||
|
int errcode, cflags = REG_EXTENDED|REG_NOSUB;
|
||||||
|
char *copy = NULL;
|
||||||
|
regex_t re;
|
||||||
|
debug_decl(regex_matches, SUDOERS_DEBUG_MATCH);
|
||||||
|
|
||||||
|
/* Check for (?i) to enable case-insensitive matching. */
|
||||||
|
if (strncmp(pattern, "^(?i)", 5) == 0) {
|
||||||
|
cflags |= REG_ICASE;
|
||||||
|
copy = strdup(pattern + 4);
|
||||||
|
if (copy == NULL) {
|
||||||
|
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
copy[0] = '^';
|
||||||
|
pattern = copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
errcode = regcomp(&re, pattern, cflags);
|
||||||
|
if (errcode == 0) {
|
||||||
|
errcode = regexec(&re, str, 0, NULL, 0);
|
||||||
|
regfree(&re);
|
||||||
|
} else {
|
||||||
|
char errbuf[1024];
|
||||||
|
|
||||||
|
regerror(errcode, &re, errbuf, sizeof(errbuf));
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"unable to compile regular expression \"%s\": %s",
|
||||||
|
pattern, errbuf);
|
||||||
|
}
|
||||||
|
free(copy);
|
||||||
|
|
||||||
|
debug_return_bool(errcode == 0);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
command_args_match(const char *sudoers_cmnd, const char *sudoers_args)
|
command_args_match(const char *sudoers_cmnd, const char *sudoers_args)
|
||||||
{
|
{
|
||||||
|
const char *args = user_args ? user_args : "";
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
debug_decl(command_args_match, SUDOERS_DEBUG_MATCH);
|
debug_decl(command_args_match, SUDOERS_DEBUG_MATCH);
|
||||||
|
|
||||||
@@ -71,14 +110,18 @@ command_args_match(const char *sudoers_cmnd, const char *sudoers_args)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If args are specified in sudoers, they must match the user args.
|
* If args are specified in sudoers, they must match the user args.
|
||||||
* If running as sudoedit, all args are assumed to be paths.
|
* Args are matched either as a regular expression or glob pattern.
|
||||||
*/
|
*/
|
||||||
|
if (sudoers_args[0] == '^') {
|
||||||
|
size_t len = strlen(sudoers_args);
|
||||||
|
if (len > 0 && sudoers_args[len - 1] == '$')
|
||||||
|
debug_return_bool(regex_matches(sudoers_args, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If running as sudoedit, all args are assumed to be paths. */
|
||||||
if (strcmp(sudoers_cmnd, "sudoedit") == 0)
|
if (strcmp(sudoers_cmnd, "sudoedit") == 0)
|
||||||
flags = FNM_PATHNAME;
|
flags = FNM_PATHNAME;
|
||||||
if (fnmatch(sudoers_args, user_args ? user_args : "", flags) == 0)
|
debug_return_bool(fnmatch(sudoers_args, args, flags) == 0);
|
||||||
debug_return_bool(true);
|
|
||||||
|
|
||||||
debug_return_bool(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SUDOERS_NAME_MATCH
|
#ifndef SUDOERS_NAME_MATCH
|
||||||
@@ -416,6 +459,49 @@ bad:
|
|||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
command_matches_regex(const char *sudoers_cmnd, const char *sudoers_args,
|
||||||
|
const char *runchroot, bool intercepted,
|
||||||
|
const struct command_digest_list *digests)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
debug_decl(command_matches_regex, SUDOERS_DEBUG_MATCH);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true if sudoers_cmnd regex matches user_cmnd AND
|
||||||
|
* a) there are no args in sudoers OR
|
||||||
|
* b) there are no args on command line and none required by sudoers OR
|
||||||
|
* c) there are args in sudoers and on command line and they match
|
||||||
|
* else return false.
|
||||||
|
*
|
||||||
|
* Neither sudoers_cmnd nor user_cmnd are relative to runchroot.
|
||||||
|
*/
|
||||||
|
if (!regex_matches(sudoers_cmnd, user_cmnd))
|
||||||
|
debug_return_bool(false);
|
||||||
|
|
||||||
|
if (command_args_match(sudoers_cmnd, sudoers_args)) {
|
||||||
|
/* Open the file for fdexec or for digest matching. */
|
||||||
|
if (!open_cmnd(user_cmnd, runchroot, digests, &fd))
|
||||||
|
goto bad;
|
||||||
|
#ifndef SUDOERS_NAME_MATCH
|
||||||
|
if (!do_stat(fd, user_cmnd, runchroot, intercepted, NULL))
|
||||||
|
goto bad;
|
||||||
|
#endif
|
||||||
|
/* Check digest of user_cmnd since sudoers_cmnd is a pattern. */
|
||||||
|
if (!digest_matches(fd, user_cmnd, runchroot, digests))
|
||||||
|
goto bad;
|
||||||
|
set_cmnd_fd(fd);
|
||||||
|
|
||||||
|
/* No need to set safe_cmnd since user_cmnd matches sudoers_cmnd */
|
||||||
|
debug_return_bool(true);
|
||||||
|
bad:
|
||||||
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SUDOERS_NAME_MATCH
|
#ifndef SUDOERS_NAME_MATCH
|
||||||
static bool
|
static bool
|
||||||
command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
|
command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args,
|
||||||
@@ -724,6 +810,13 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for regular expressions first. */
|
||||||
|
if (sudoers_cmnd[0] == '^') {
|
||||||
|
rc = command_matches_regex(sudoers_cmnd, sudoers_args, runchroot,
|
||||||
|
intercepted, digests);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for pseudo-commands */
|
/* Check for pseudo-commands */
|
||||||
if (sudoers_cmnd[0] != '/') {
|
if (sudoers_cmnd[0] != '/') {
|
||||||
/*
|
/*
|
||||||
|
@@ -24,9 +24,9 @@
|
|||||||
#include "sudo_queue.h"
|
#include "sudo_queue.h"
|
||||||
|
|
||||||
/* Characters that must be quoted in sudoers. */
|
/* Characters that must be quoted in sudoers. */
|
||||||
#define SUDOERS_QUOTED ":\\,=#\""
|
#define SUDOERS_QUOTED ":,=#\""
|
||||||
#define SUDOERS_QUOTED_CMD ":\\,= \t#"
|
#define SUDOERS_QUOTED_CMD ":,= \t#"
|
||||||
#define SUDOERS_QUOTED_ARG ":\\,=#"
|
#define SUDOERS_QUOTED_ARG ":,=#"
|
||||||
|
|
||||||
/* Returns true if string 's' contains meta characters. */
|
/* Returns true if string 's' contains meta characters. */
|
||||||
#define has_meta(s) (strpbrk(s, "\\?*[]") != NULL)
|
#define has_meta(s) (strpbrk(s, "\\?*[]") != NULL)
|
||||||
|
33
plugins/sudoers/regress/sudoers/test28.in
Normal file
33
plugins/sudoers/regress/sudoers/test28.in
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Test simple command with regex args
|
||||||
|
user ALL = /bin/ls ^/etc/(hosts|motd|issue)$
|
||||||
|
|
||||||
|
# Test wildcard command with regex args
|
||||||
|
user ALL = /usr/bin/c* ^/etc/(hosts|motd|issue)$
|
||||||
|
|
||||||
|
# Test regex command with no args
|
||||||
|
user ALL = ^/usr/bin/(who|w|id|whoami)$
|
||||||
|
|
||||||
|
# Test regex command with empty args
|
||||||
|
user ALL = ^/usr/bin/(who|w|id|whoami)$ ""
|
||||||
|
|
||||||
|
# Test regex command with simple args
|
||||||
|
user ALL = ^/usr/bin/(who|w|id|whoami)$ root
|
||||||
|
|
||||||
|
# Test regex command with wildcard args
|
||||||
|
user ALL = ^/usr/bin/(who|w|id|whoami)$ -*
|
||||||
|
|
||||||
|
# Test regex command with regex args
|
||||||
|
user ALL = ^/usr/bin/(who|w|id|whoami)$ ^(-[ahi] ?)+$
|
||||||
|
|
||||||
|
# Test sudoedit with regex args
|
||||||
|
user ALL = sudoedit ^/etc/(hosts|motd|issue)$
|
||||||
|
|
||||||
|
# Test regex command with escapted '$', no args
|
||||||
|
user ALL = ^/usr/bin/\$tree$
|
||||||
|
|
||||||
|
# Combined entry
|
||||||
|
user host1 = /bin/ls ^/etc/(hosts|motd|issue)$, \
|
||||||
|
/usr/bin/c* ^/etc/(hosts|motd|issue)$ : \
|
||||||
|
host2 = ^/usr/bin/(who|w|id|whoami)$ "", \
|
||||||
|
^/usr/bin/(who|w|id|whoami)$ root : \
|
||||||
|
host3 = /bin/echo ^\$foo$
|
186
plugins/sudoers/regress/sudoers/test28.json.ok
Normal file
186
plugins/sudoers/regress/sudoers/test28.json.ok
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
{
|
||||||
|
"User_Specs": [
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/bin/ls ^/etc/(hosts|motd|issue)$" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/usr/bin/c* ^/etc/(hosts|motd|issue)$" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "^/usr/bin/(who|w|id|whoami)$" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "^/usr/bin/(who|w|id|whoami)$ \"\"" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "^/usr/bin/(who|w|id|whoami)$ root" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "^/usr/bin/(who|w|id|whoami)$ -*" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "^/usr/bin/(who|w|id|whoami)$ ^(-[ahi] ?)+$" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "sudoedit ^/etc/(hosts|motd|issue)$" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "ALL" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "^/usr/bin/\\$tree$" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "host1" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/bin/ls ^/etc/(hosts|motd|issue)$" },
|
||||||
|
{ "command": "/usr/bin/c* ^/etc/(hosts|motd|issue)$" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "host2" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "^/usr/bin/(who|w|id|whoami)$ \"\"" },
|
||||||
|
{ "command": "^/usr/bin/(who|w|id|whoami)$ root" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"User_List": [
|
||||||
|
{ "username": "user" }
|
||||||
|
],
|
||||||
|
"Host_List": [
|
||||||
|
{ "hostname": "host3" }
|
||||||
|
],
|
||||||
|
"Cmnd_Specs": [
|
||||||
|
{
|
||||||
|
"Commands": [
|
||||||
|
{ "command": "/bin/echo ^\\$foo$" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
110
plugins/sudoers/regress/sudoers/test28.ldif.ok
Normal file
110
plugins/sudoers/regress/sudoers/test28.ldif.ok
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
dn: cn=user,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: ALL
|
||||||
|
sudoCommand: /bin/ls ^/etc/(hosts|motd|issue)$
|
||||||
|
sudoOrder: 1
|
||||||
|
|
||||||
|
dn: cn=user_1,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_1
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: ALL
|
||||||
|
sudoCommand: /usr/bin/c* ^/etc/(hosts|motd|issue)$
|
||||||
|
sudoOrder: 2
|
||||||
|
|
||||||
|
dn: cn=user_2,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_2
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: ALL
|
||||||
|
sudoCommand: ^/usr/bin/(who|w|id|whoami)$
|
||||||
|
sudoOrder: 3
|
||||||
|
|
||||||
|
dn: cn=user_3,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_3
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: ALL
|
||||||
|
sudoCommand: ^/usr/bin/(who|w|id|whoami)$ ""
|
||||||
|
sudoOrder: 4
|
||||||
|
|
||||||
|
dn: cn=user_4,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_4
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: ALL
|
||||||
|
sudoCommand: ^/usr/bin/(who|w|id|whoami)$ root
|
||||||
|
sudoOrder: 5
|
||||||
|
|
||||||
|
dn: cn=user_5,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_5
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: ALL
|
||||||
|
sudoCommand: ^/usr/bin/(who|w|id|whoami)$ -*
|
||||||
|
sudoOrder: 6
|
||||||
|
|
||||||
|
dn: cn=user_6,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_6
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: ALL
|
||||||
|
sudoCommand: ^/usr/bin/(who|w|id|whoami)$ ^(-[ahi] ?)+$
|
||||||
|
sudoOrder: 7
|
||||||
|
|
||||||
|
dn: cn=user_7,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_7
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: ALL
|
||||||
|
sudoCommand: sudoedit ^/etc/(hosts|motd|issue)$
|
||||||
|
sudoOrder: 8
|
||||||
|
|
||||||
|
dn: cn=user_8,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_8
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: ALL
|
||||||
|
sudoCommand: ^/usr/bin/\$tree$
|
||||||
|
sudoOrder: 9
|
||||||
|
|
||||||
|
dn: cn=user_9,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_9
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: host1
|
||||||
|
sudoCommand: /bin/ls ^/etc/(hosts|motd|issue)$
|
||||||
|
sudoCommand: /usr/bin/c* ^/etc/(hosts|motd|issue)$
|
||||||
|
sudoOrder: 10
|
||||||
|
|
||||||
|
dn: cn=user_10,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_10
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: host2
|
||||||
|
sudoCommand: ^/usr/bin/(who|w|id|whoami)$ ""
|
||||||
|
sudoCommand: ^/usr/bin/(who|w|id|whoami)$ root
|
||||||
|
sudoOrder: 11
|
||||||
|
|
||||||
|
dn: cn=user_11,ou=SUDOers,dc=sudo,dc=ws
|
||||||
|
objectClass: top
|
||||||
|
objectClass: sudoRole
|
||||||
|
cn: user_11
|
||||||
|
sudoUser: user
|
||||||
|
sudoHost: host3
|
||||||
|
sudoCommand: /bin/echo ^\$foo$
|
||||||
|
sudoOrder: 12
|
||||||
|
|
10
plugins/sudoers/regress/sudoers/test28.ldif2sudo.ok
Normal file
10
plugins/sudoers/regress/sudoers/test28.ldif2sudo.ok
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# sudoRole user, user_1, user_2, user_3, user_4, user_5, user_6, user_7,
|
||||||
|
# user_8, user_9, user_10, user_11
|
||||||
|
user ALL = /bin/ls ^/etc/(hosts|motd|issue)$, /usr/bin/c*\
|
||||||
|
^/etc/(hosts|motd|issue)$, ^/usr/bin/(who|w|id|whoami)$,\
|
||||||
|
^/usr/bin/(who|w|id|whoami)$ "", ^/usr/bin/(who|w|id|whoami)$ root,\
|
||||||
|
^/usr/bin/(who|w|id|whoami)$ -*, ^/usr/bin/(who|w|id|whoami)$ ^(-[ahi]\
|
||||||
|
?)+$, sudoedit ^/etc/(hosts|motd|issue)$, ^/usr/bin/\$tree$ : host1 =\
|
||||||
|
/bin/ls ^/etc/(hosts|motd|issue)$, /usr/bin/c* ^/etc/(hosts|motd|issue)$ :\
|
||||||
|
host2 = ^/usr/bin/(who|w|id|whoami)$ "", ^/usr/bin/(who|w|id|whoami)$ root\
|
||||||
|
: host3 = /bin/echo ^\$foo$
|
12
plugins/sudoers/regress/sudoers/test28.out.ok
Normal file
12
plugins/sudoers/regress/sudoers/test28.out.ok
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Parses OK
|
||||||
|
|
||||||
|
user ALL = /bin/ls ^/etc/(hosts|motd|issue)$
|
||||||
|
user ALL = /usr/bin/c* ^/etc/(hosts|motd|issue)$
|
||||||
|
user ALL = ^/usr/bin/(who|w|id|whoami)$
|
||||||
|
user ALL = ^/usr/bin/(who|w|id|whoami)$ ""
|
||||||
|
user ALL = ^/usr/bin/(who|w|id|whoami)$ root
|
||||||
|
user ALL = ^/usr/bin/(who|w|id|whoami)$ -*
|
||||||
|
user ALL = ^/usr/bin/(who|w|id|whoami)$ ^(-[ahi] ?)+$
|
||||||
|
user ALL = sudoedit ^/etc/(hosts|motd|issue)$
|
||||||
|
user ALL = ^/usr/bin/\$tree$
|
||||||
|
user host1 = /bin/ls ^/etc/(hosts|motd|issue)$, /usr/bin/c* ^/etc/(hosts|motd|issue)$ : host2 = ^/usr/bin/(who|w|id|whoami)$ "", ^/usr/bin/(who|w|id|whoami)$ root : host3 = /bin/echo ^\$foo$
|
29
plugins/sudoers/regress/sudoers/test28.toke.ok
Normal file
29
plugins/sudoers/regress/sudoers/test28.toke.ok
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#
|
||||||
|
WORD(6) ALL = COMMAND ARG REGEX
|
||||||
|
|
||||||
|
#
|
||||||
|
WORD(6) ALL = COMMAND ARG REGEX
|
||||||
|
|
||||||
|
#
|
||||||
|
WORD(6) ALL = COMMAND
|
||||||
|
|
||||||
|
#
|
||||||
|
WORD(6) ALL = COMMAND ARG
|
||||||
|
|
||||||
|
#
|
||||||
|
WORD(6) ALL = COMMAND ARG
|
||||||
|
|
||||||
|
#
|
||||||
|
WORD(6) ALL = COMMAND ARG
|
||||||
|
|
||||||
|
#
|
||||||
|
WORD(6) ALL = COMMAND ARG REGEX
|
||||||
|
|
||||||
|
#
|
||||||
|
WORD(6) ALL = COMMAND ARG REGEX
|
||||||
|
|
||||||
|
#
|
||||||
|
WORD(6) ALL = COMMAND
|
||||||
|
|
||||||
|
#
|
||||||
|
WORD(6) WORD(6) = COMMAND ARG REGEX , COMMAND ARG REGEX : WORD(6) = COMMAND ARG , COMMAND ARG : WORD(6) = COMMAND ARG REGEX QUOTEDCHAR
|
11
plugins/sudoers/regress/sudoers/test29.in
Normal file
11
plugins/sudoers/regress/sudoers/test29.in
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Test lexer regex syntax errors
|
||||||
|
# We don't test regcomp() errors since regerror() strings are not
|
||||||
|
# standardized.
|
||||||
|
|
||||||
|
user ALL = /bin/ls ^/etc/(hosts|motd|issue
|
||||||
|
|
||||||
|
user ALL = ^/bin/ls
|
||||||
|
|
||||||
|
user ALL = ^/bin/ls$ ^error
|
||||||
|
|
||||||
|
user ALL = ^/bin/ls$ ^error # comment
|
0
plugins/sudoers/regress/sudoers/test29.json.ok
Normal file
0
plugins/sudoers/regress/sudoers/test29.json.ok
Normal file
0
plugins/sudoers/regress/sudoers/test29.ldif.ok
Normal file
0
plugins/sudoers/regress/sudoers/test29.ldif.ok
Normal file
1
plugins/sudoers/regress/sudoers/test29.out.ok
Normal file
1
plugins/sudoers/regress/sudoers/test29.out.ok
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
11
plugins/sudoers/regress/sudoers/test29.toke.ok
Normal file
11
plugins/sudoers/regress/sudoers/test29.toke.ok
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
WORD(6) ALL = COMMAND ARG REGEX ERROR <*>
|
||||||
|
|
||||||
|
WORD(6) ALL = WORD(6) <*>
|
||||||
|
|
||||||
|
WORD(6) ALL = COMMAND ARG REGEX ERROR <*>
|
||||||
|
|
||||||
|
WORD(6) ALL = COMMAND ARG REGEX ERROR <*> #
|
60
plugins/sudoers/regress/testsudoers/test18.out.ok
Normal file
60
plugins/sudoers/regress/testsudoers/test18.out.ok
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
Parses OK
|
||||||
|
|
||||||
|
Entries for user root:
|
||||||
|
|
||||||
|
ALL = ^/usr/bin/w$ ^-[abc]$
|
||||||
|
host matched
|
||||||
|
runas matched
|
||||||
|
cmnd allowed
|
||||||
|
|
||||||
|
Command allowed
|
||||||
|
Parses OK
|
||||||
|
|
||||||
|
Entries for user root:
|
||||||
|
|
||||||
|
ALL = ^/bin/cat$ /var/log/*
|
||||||
|
host matched
|
||||||
|
runas matched
|
||||||
|
cmnd allowed
|
||||||
|
|
||||||
|
Command allowed
|
||||||
|
Parses OK
|
||||||
|
|
||||||
|
Entries for user root:
|
||||||
|
|
||||||
|
ALL = /bin/cat ^/var/log/[^/]+$
|
||||||
|
host matched
|
||||||
|
runas matched
|
||||||
|
cmnd allowed
|
||||||
|
|
||||||
|
Command allowed
|
||||||
|
Parses OK
|
||||||
|
|
||||||
|
Entries for user root:
|
||||||
|
|
||||||
|
ALL = /bin/*at ^/var/log/[^/]+$
|
||||||
|
host matched
|
||||||
|
runas matched
|
||||||
|
cmnd allowed
|
||||||
|
|
||||||
|
Command allowed
|
||||||
|
Parses OK
|
||||||
|
|
||||||
|
Entries for user root:
|
||||||
|
|
||||||
|
ALL = /usr/bin/grep \^foo$
|
||||||
|
host matched
|
||||||
|
runas matched
|
||||||
|
cmnd allowed
|
||||||
|
|
||||||
|
Command allowed
|
||||||
|
Parses OK
|
||||||
|
|
||||||
|
Entries for user root:
|
||||||
|
|
||||||
|
ALL = sudoedit ^/etc/(motd|issue|hosts)$
|
||||||
|
host matched
|
||||||
|
runas matched
|
||||||
|
cmnd allowed
|
||||||
|
|
||||||
|
Command allowed
|
40
plugins/sudoers/regress/testsudoers/test18.sh
Executable file
40
plugins/sudoers/regress/testsudoers/test18.sh
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Test regular expressions
|
||||||
|
#
|
||||||
|
|
||||||
|
: ${TESTSUDOERS=testsudoers}
|
||||||
|
|
||||||
|
exec 2>&1
|
||||||
|
|
||||||
|
# Command and args: regex
|
||||||
|
$TESTSUDOERS root /usr/bin/w -a <<'EOF'
|
||||||
|
root ALL = ^/usr/bin/w$ ^-[abc]$
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Command: regex, args: wildcard
|
||||||
|
$TESTSUDOERS root /bin/cat /var/log/syslog <<'EOF'
|
||||||
|
root ALL = ^/bin/cat$ /var/log/*
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Command: path, args: regex
|
||||||
|
$TESTSUDOERS root /bin/cat /var/log/authlog <<'EOF'
|
||||||
|
root ALL = /bin/cat ^/var/log/[^/]+$
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Command: wildcard, args: regex
|
||||||
|
$TESTSUDOERS root /bin/cat /var/log/mail <<'EOF'
|
||||||
|
root ALL = /bin/*at ^/var/log/[^/]+$
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Command: path, args: args start with escaped ^
|
||||||
|
$TESTSUDOERS root /usr/bin/grep ^foo$ <<'EOF'
|
||||||
|
root ALL = /usr/bin/grep \^foo$
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Command: sudoedit, args: regex
|
||||||
|
$TESTSUDOERS root sudoedit /etc/motd <<'EOF'
|
||||||
|
root ALL = sudoedit ^/etc/(motd|issue|hosts)$
|
||||||
|
EOF
|
||||||
|
|
||||||
|
exit 0
|
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@ bool fill_args(const char *, size_t, int);
|
|||||||
bool fill_cmnd(const char *, size_t);
|
bool fill_cmnd(const char *, size_t);
|
||||||
bool fill(const char *, size_t);
|
bool fill(const char *, size_t);
|
||||||
bool ipv6_valid(const char *s);
|
bool ipv6_valid(const char *s);
|
||||||
|
bool regex_valid(const char *pattern, char **errstr);
|
||||||
int sudoers_trace_print(const char *);
|
int sudoers_trace_print(const char *);
|
||||||
void sudoerserrorf(const char *, ...) __printf0like(1, 2);
|
void sudoerserrorf(const char *, ...) __printf0like(1, 2);
|
||||||
void sudoerserror(const char *);
|
void sudoerserror(const char *);
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: ISC
|
* SPDX-License-Identifier: ISC
|
||||||
*
|
*
|
||||||
* Copyright (c) 1996, 1998-2005, 2007-2021
|
* Copyright (c) 1996, 1998-2005, 2007-2022
|
||||||
* Todd C. Miller <Todd.Miller@sudo.ws>
|
* Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
@@ -102,6 +102,7 @@ HOSTNAME [[:alnum:]_-]+
|
|||||||
WORD ([^#>!=:,\(\) \t\r\n\\\"]|\\[^\t\n])+
|
WORD ([^#>!=:,\(\) \t\r\n\\\"]|\\[^\t\n])+
|
||||||
ID #-?[0-9]+
|
ID #-?[0-9]+
|
||||||
PATH \/(\\[\,:= \t#]|[^\,:=\\ \t\r\n#])+
|
PATH \/(\\[\,:= \t#]|[^\,:=\\ \t\r\n#])+
|
||||||
|
REGEX \^([^#\r\n\$]|\\[#\$])*\$
|
||||||
ENVAR ([^#!=, \t\r\n\\\"]|\\[^\r\n])([^#=, \t\r\n\\\"]|\\[^\r\n])*
|
ENVAR ([^#!=, \t\r\n\\\"]|\\[^\r\n])([^#=, \t\r\n\\\"]|\\[^\r\n])*
|
||||||
DEFVAR [a-z_]+
|
DEFVAR [a-z_]+
|
||||||
|
|
||||||
@@ -112,6 +113,7 @@ DEFVAR [a-z_]+
|
|||||||
|
|
||||||
%s GOTDEFS
|
%s GOTDEFS
|
||||||
%x GOTCMND
|
%x GOTCMND
|
||||||
|
%x GOTREGEX
|
||||||
%x STARTDEFS
|
%x STARTDEFS
|
||||||
%x INDEFS
|
%x INDEFS
|
||||||
%x INSTR
|
%x INSTR
|
||||||
@@ -232,7 +234,7 @@ DEFVAR [a-z_]+
|
|||||||
}
|
}
|
||||||
|
|
||||||
<GOTCMND>{
|
<GOTCMND>{
|
||||||
\\[\*\?\[\]\!] {
|
\\[\*\?\[\]\!^] {
|
||||||
/* quoted fnmatch glob char, pass verbatim */
|
/* quoted fnmatch glob char, pass verbatim */
|
||||||
LEXTRACE("QUOTEDCHAR ");
|
LEXTRACE("QUOTEDCHAR ");
|
||||||
if (!fill_args(sudoerstext, 2, sawspace))
|
if (!fill_args(sudoerstext, 2, sawspace))
|
||||||
@@ -256,13 +258,69 @@ DEFVAR [a-z_]+
|
|||||||
} /* end of command line args */
|
} /* end of command line args */
|
||||||
|
|
||||||
[^#\\:, \t\r\n]+ {
|
[^#\\:, \t\r\n]+ {
|
||||||
|
if (sudoerslval.command.args == NULL && sudoerstext[0] == '^') {
|
||||||
|
LEXTRACE("ARG REGEX ");
|
||||||
|
BEGIN GOTREGEX;
|
||||||
|
sudoersless(0);
|
||||||
|
yy_set_bol(0);
|
||||||
|
} else {
|
||||||
LEXTRACE("ARG ");
|
LEXTRACE("ARG ");
|
||||||
if (!fill_args(sudoerstext, sudoersleng, sawspace))
|
if (!fill_args(sudoerstext, sudoersleng, sawspace))
|
||||||
yyterminate();
|
yyterminate();
|
||||||
sawspace = false;
|
sawspace = false;
|
||||||
|
}
|
||||||
} /* a command line arg */
|
} /* a command line arg */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<GOTREGEX>{
|
||||||
|
\\[^\r\n] {
|
||||||
|
/* quoted character, pass verbatim */
|
||||||
|
LEXTRACE("QUOTEDCHAR ");
|
||||||
|
if (!fill_args(sudoerstext, 2, false))
|
||||||
|
yyterminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
[#\r\n] {
|
||||||
|
/* Let the parser attempt to recover. */
|
||||||
|
sudoersless(0);
|
||||||
|
yy_set_bol(0);
|
||||||
|
BEGIN INITIAL;
|
||||||
|
|
||||||
|
sudoers_errstr = N_("unterminated regular expression");
|
||||||
|
LEXTRACE("ERROR ");
|
||||||
|
return ERROR;
|
||||||
|
} /* illegal inside regex */
|
||||||
|
|
||||||
|
\$ {
|
||||||
|
if (!fill_args("$", 1, false))
|
||||||
|
yyterminate();
|
||||||
|
BEGIN INITIAL;
|
||||||
|
continued = false;
|
||||||
|
if (sudoers_strict) {
|
||||||
|
if (!regex_valid(sudoerstext, &sudoers_errstr)) {
|
||||||
|
LEXTRACE("ERROR ");
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
[^#\\\r\n$]+ {
|
||||||
|
if (continued) {
|
||||||
|
/* remove whitespace after line continuation */
|
||||||
|
while (isblank((unsigned char)*sudoerstext)) {
|
||||||
|
sudoerstext++;
|
||||||
|
sudoersleng--;
|
||||||
|
}
|
||||||
|
continued = false;
|
||||||
|
}
|
||||||
|
if (sudoersleng != 0) {
|
||||||
|
if (!fill_args(sudoerstext, sudoersleng, false))
|
||||||
|
yyterminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
<WANTDIGEST>[[:xdigit:]]+ {
|
<WANTDIGEST>[[:xdigit:]]+ {
|
||||||
/* Only return DIGEST if the length is correct. */
|
/* Only return DIGEST if the length is correct. */
|
||||||
yy_size_t digest_len =
|
yy_size_t digest_len =
|
||||||
@@ -647,7 +705,7 @@ ALL {
|
|||||||
return ALIAS;
|
return ALIAS;
|
||||||
}
|
}
|
||||||
|
|
||||||
<GOTDEFS>({PATH}|sudoedit) {
|
<GOTDEFS>({PATH}|{REGEX}|sudoedit) {
|
||||||
/* XXX - no way to specify digest for command */
|
/* XXX - no way to specify digest for command */
|
||||||
/* no command args allowed for Defaults!/path */
|
/* no command args allowed for Defaults!/path */
|
||||||
if (!fill_cmnd(sudoerstext, sudoersleng))
|
if (!fill_cmnd(sudoerstext, sudoersleng))
|
||||||
@@ -713,6 +771,19 @@ sudoedit {
|
|||||||
yyterminate();
|
yyterminate();
|
||||||
} /* a pathname */
|
} /* a pathname */
|
||||||
|
|
||||||
|
{REGEX} {
|
||||||
|
if (sudoers_strict) {
|
||||||
|
if (!regex_valid(sudoerstext, &sudoers_errstr)) {
|
||||||
|
LEXTRACE("ERROR ");
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BEGIN GOTCMND;
|
||||||
|
LEXTRACE("COMMAND ");
|
||||||
|
if (!fill_cmnd(sudoerstext, sudoersleng))
|
||||||
|
yyterminate();
|
||||||
|
} /* a regex */
|
||||||
|
|
||||||
<INITIAL,GOTDEFS>\" {
|
<INITIAL,GOTDEFS>\" {
|
||||||
LEXTRACE("BEGINSTR ");
|
LEXTRACE("BEGINSTR ");
|
||||||
sudoerslval.string = NULL;
|
sudoerslval.string = NULL;
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#include "sudoers.h"
|
#include "sudoers.h"
|
||||||
#include "toke.h"
|
#include "toke.h"
|
||||||
@@ -38,6 +39,7 @@
|
|||||||
|
|
||||||
static unsigned int arg_len = 0;
|
static unsigned int arg_len = 0;
|
||||||
static unsigned int arg_size = 0;
|
static unsigned int arg_size = 0;
|
||||||
|
static char errbuf[1024];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy the string and collapse any escaped characters.
|
* Copy the string and collapse any escaped characters.
|
||||||
@@ -133,6 +135,11 @@ fill_cmnd(const char *src, size_t len)
|
|||||||
}
|
}
|
||||||
sudoerslval.command.args = NULL;
|
sudoerslval.command.args = NULL;
|
||||||
|
|
||||||
|
if (src[0] == '^') {
|
||||||
|
/* Copy the regular expression, no escaped sudo-specific characters. */
|
||||||
|
memcpy(dst, src, len);
|
||||||
|
dst[len] = '\0';
|
||||||
|
} else {
|
||||||
/* Copy the string and collapse any escaped sudo-specific characters. */
|
/* Copy the string and collapse any escaped sudo-specific characters. */
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
if (src[i] == '\\' && i != len - 1 && SPECIAL(src[i + 1]))
|
if (src[i] == '\\' && i != len - 1 && SPECIAL(src[i + 1]))
|
||||||
@@ -157,6 +164,7 @@ fill_cmnd(const char *src, size_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parser_leak_add(LEAK_PTR, sudoerslval.command.cmnd);
|
parser_leak_add(LEAK_PTR, sudoerslval.command.cmnd);
|
||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
@@ -239,3 +247,36 @@ ipv6_valid(const char *s)
|
|||||||
|
|
||||||
debug_return_bool(nmatch <= 1);
|
debug_return_bool(nmatch <= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
regex_valid(const char *pattern, char **errstr)
|
||||||
|
{
|
||||||
|
int errcode, cflags = REG_EXTENDED|REG_NOSUB;
|
||||||
|
char *copy = NULL;
|
||||||
|
regex_t re;
|
||||||
|
debug_decl(regex_valid, SUDOERS_DEBUG_PARSER);
|
||||||
|
|
||||||
|
/* Check for (?i) to enable case-insensitive matching. */
|
||||||
|
if (strncmp(pattern, "^(?i)", 5) == 0) {
|
||||||
|
cflags |= REG_ICASE;
|
||||||
|
copy = strdup(pattern + 4);
|
||||||
|
if (copy == NULL) {
|
||||||
|
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
|
||||||
|
sudoerserror(NULL);
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
copy[0] = '^';
|
||||||
|
pattern = copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
errcode = regcomp(&re, pattern, cflags);
|
||||||
|
if (errcode == 0) {
|
||||||
|
regfree(&re);
|
||||||
|
} else {
|
||||||
|
regerror(errcode, &re, errbuf, sizeof(errbuf));
|
||||||
|
*errstr = errbuf;
|
||||||
|
}
|
||||||
|
free(copy);
|
||||||
|
|
||||||
|
debug_return_bool(errcode == 0);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user