]> granicus.if.org Git - sudo/commitdiff
First cut at session logging for sudo. Still need to write get_pty()
authorTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 6 Aug 2009 00:04:14 +0000 (00:04 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 6 Aug 2009 00:04:14 +0000 (00:04 +0000)
for Unix 98 and old-style BSD ptys.  Also needs documentation and
general cleanup.

19 files changed:
Makefile.in
aclocal.m4
compat.h
config.h.in
configure
configure.in
def_data.c
def_data.h
def_data.in
gram.c
gram.h
gram.y
parse.c
parse.h
pathnames.h.in
sudo.c
sudo.h
term.c
tgetpass.c

index f665b2cb6cd173d6eebcba9a375304085035b3fa..f0eed2a8e3e91083aafaafed7e7051de9dde57dc 100644 (file)
@@ -106,7 +106,7 @@ SRCS = aix.c alias.c alloc.c audit.c bsm_audit.c check.c closefrom.c \
        def_data.c defaults.c env.c error.c fileops.c find_path.c fnmatch.c \
        getcwd.c getprogname.c getspwuid.c gettime.c glob.c goodpath.c gram.c \
        gram.y interfaces.c isblank.c lbuf.c ldap.c list.c logging.c match.c \
-       mkstemp.c memrchr.c parse.c pwutil.c  set_perms.c sigaction.c \
+       mkstemp.c memrchr.c parse.c pwutil.c script.c  set_perms.c sigaction.c \
        snprintf.c strcasecmp.c strerror.c strlcat.c strlcpy.c sudo.c \
        sudo_noexec.c sudo_edit.c sudo_nss.c term.c testsudoers.c tgetpass.c \
        toke.c toke.l tsgetgrpw.c utimes.c vasgroups.c visudo.c zero_bytes.c \
@@ -131,8 +131,8 @@ COMMON_OBJS = gram.o alias.o alloc.o defaults.o error.o list.o match.o \
 
 SUDO_OBJS = $(COMMON_OBJS) $(AUTH_OBJS) @SUDO_OBJS@ audit.o check.o env.o \
            getspwuid.o gettime.o goodpath.o fileops.o find_path.o \
-           interfaces.o lbuf.o logging.o parse.o pwutil.o set_perms.o \
-           sudo.o sudo_edit.o sudo_nss.o term.o tgetpass.o
+           interfaces.o lbuf.o logging.o parse.o pwutil.o script.o \
+           set_perms.o sudo.o sudo_edit.o sudo_nss.o term.o tgetpass.o
 
 VISUDO_OBJS = $(COMMON_OBJS) visudo.o fileops.o gettime.o goodpath.o \
              find_path.o pwutil.o
@@ -285,6 +285,8 @@ pwutil.o: $(srcdir)/pwutil.c $(SUDODEP)
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/pwutil.c
 redblack.o: $(srcdir)/redblack.c $(SUDODEP) $(srcdir)/redblack.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/redblack.c
+script.o: $(srcdir)/script.c $(SUDODEP)
+       $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/script.c
 set_perms.o: $(srcdir)/set_perms.c $(SUDODEP)
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/set_perms.c
 sigaction.o: $(srcdir)/sigaction.c $(srcdir)/compat.h
index 1a6d9904931fa66f450f84d43fa17b448c99ec50..f333ed30ef984f5b6819f5c3862dea29018b0adb 100644 (file)
@@ -134,7 +134,8 @@ fi
 ])dnl
 
 dnl
-dnl Where the log file goes, use /var/log if it exists, else /{var,usr}/adm
+dnl Where the timestamp files go, use /var/run/sudo if /var/run exists,
+dnl else /{var,usr}/adm/sudo
 dnl
 AC_DEFUN(SUDO_TIMEDIR, [AC_MSG_CHECKING(for timestamp file location)
 if test -n "$with_timedir"; then
@@ -156,6 +157,30 @@ else
 fi
 ])dnl
 
+dnl
+dnl Where the session files go, use /var/log/sudo-session if /var/log exists,
+dnl else /{var,usr}/adm/sudo-session
+dnl
+AC_DEFUN(SUDO_SESSDIR, [AC_MSG_CHECKING(for session file location)
+if test -n "$with_sessdir"; then
+    AC_MSG_RESULT($with_sessdir)
+    SUDO_DEFINE_UNQUOTED(_PATH_SUDO_SESSDIR, "$with_sessdir")
+    sessdir="$with_sessdir"
+elif test -d "/var/log"; then
+    AC_MSG_RESULT(/var/log/sudo-session)
+    SUDO_DEFINE(_PATH_SUDO_SESSDIR, "/var/log/sudo-session")
+    sessdir="/var/log/sudo-session"
+elif test -d "/var/adm"; then
+    AC_MSG_RESULT(/var/adm/sudo-session)
+    SUDO_DEFINE(_PATH_SUDO_SESSDIR, "/var/adm/sudo-session")
+    sessdir="/var/adm/sudo-session"
+else
+    AC_MSG_RESULT(/usr/adm/sudo-session)
+    SUDO_DEFINE(_PATH_SUDO_SESSDIR, "/usr/adm/sudo-session")
+    sessdir="/usr/adm/sudo-session"
+fi
+])dnl
+
 dnl
 dnl SUDO_CHECK_TYPE(TYPE, DEFAULT)
 dnl XXX - should require the check for unistd.h...
index 6851bde88603c04e493f75dedb2559e1672b3176..7cededc65de874d09416422da082531f35ee2fb2 100644 (file)
--- a/compat.h
+++ b/compat.h
@@ -198,6 +198,7 @@ int isblank __P((int));
 # define SA_ONSTACK    SV_ONSTACK
 # define SA_RESTART    SV_INTERRUPT            /* opposite effect */
 # define SA_RESETHAND  SV_RESETHAND
+# define SA_NOCLDSTOP  SV_NOCLDSTOP
 # define sa_handler    sv_handler
 # define sa_mask       sv_mask
 # define sa_flags      sv_flags
index 18698f4f92bc34840a8cb75d9d1ce252b89c96c2..62f2a3902a6f5edaca1fea344432fa6268f94a05 100644 (file)
 /* Define to 1 if you have the <netgroup.h> header file. */
 #undef HAVE_NETGROUP_H
 
+/* Define to 1 if you have the `openpty' function. */
+#undef HAVE_OPENPTY
+
 /* Define to 1 if you use NRL OPIE. */
 #undef HAVE_OPIE
 
index 1d45b2118a18c1df9b8d3c9375a433ed3e81f674..cb4dd8a823a0945595995130be12bf81dfb9eac0 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for sudo 1.7.2.
+# Generated by GNU Autoconf 2.61 for sudo 1.7.3.
 #
 # Report bugs to <http://www.sudo.ws/bugs/>.
 #
@@ -724,8 +724,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='sudo'
 PACKAGE_TARNAME='sudo'
-PACKAGE_VERSION='1.7.2'
-PACKAGE_STRING='sudo 1.7.2'
+PACKAGE_VERSION='1.7.3'
+PACKAGE_STRING='sudo 1.7.3'
 PACKAGE_BUGREPORT='http://www.sudo.ws/bugs/'
 
 # Factoring default headers for most tests.
@@ -1416,7 +1416,7 @@ if test "$ac_init_help" = "long"; then
   # 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.
   cat <<_ACEOF
-\`configure' configures sudo 1.7.2 to adapt to many kinds of systems.
+\`configure' configures sudo 1.7.3 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1481,7 +1481,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of sudo 1.7.2:";;
+     short | recursive ) echo "Configuration of sudo 1.7.3:";;
    esac
   cat <<\_ACEOF
 
@@ -1683,7 +1683,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-sudo configure 1.7.2
+sudo configure 1.7.3
 generated by GNU Autoconf 2.61
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1697,7 +1697,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by sudo $as_me 1.7.2, which was
+It was created by sudo $as_me 1.7.3, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   $ $0 $@
 done
 
 
+for ac_func in openpty
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  { echo "$as_me:$LINENO: checking for openpty in -lutil" >&5
+echo $ECHO_N "checking for openpty in -lutil... $ECHO_C" >&6; }
+if test "${ac_cv_lib_util_openpty+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lutil  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char openpty ();
+int
+main ()
+{
+return openpty ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_util_openpty=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_util_openpty=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_util_openpty" >&5
+echo "${ECHO_T}$ac_cv_lib_util_openpty" >&6; }
+if test $ac_cv_lib_util_openpty = yes; then
+
+    SUDO_LIBS="${SUDO_LIBS} -lutil"
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPENPTY 1
+_ACEOF
+
+
+fi
+
+fi
+done
+
+
 for ac_func in unsetenv
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -23997,6 +24163,42 @@ EOF
     timedir="/usr/adm/sudo"
 fi
 
+{ echo "$as_me:$LINENO: checking for session file location" >&5
+echo $ECHO_N "checking for session file location... $ECHO_C" >&6; }
+if test -n "$with_sessdir"; then
+    { echo "$as_me:$LINENO: result: $with_sessdir" >&5
+echo "${ECHO_T}$with_sessdir" >&6; }
+    cat >>confdefs.h <<EOF
+#define _PATH_SUDO_SESSDIR "$with_sessdir"
+EOF
+
+    sessdir="$with_sessdir"
+elif test -d "/var/log"; then
+    { echo "$as_me:$LINENO: result: /var/log/sudo-session" >&5
+echo "${ECHO_T}/var/log/sudo-session" >&6; }
+    cat >>confdefs.h <<\EOF
+#define _PATH_SUDO_SESSDIR "/var/log/sudo-session"
+EOF
+
+    sessdir="/var/log/sudo-session"
+elif test -d "/var/adm"; then
+    { echo "$as_me:$LINENO: result: /var/adm/sudo-session" >&5
+echo "${ECHO_T}/var/adm/sudo-session" >&6; }
+    cat >>confdefs.h <<\EOF
+#define _PATH_SUDO_SESSDIR "/var/adm/sudo-session"
+EOF
+
+    sessdir="/var/adm/sudo-session"
+else
+    { echo "$as_me:$LINENO: result: /usr/adm/sudo-session" >&5
+echo "${ECHO_T}/usr/adm/sudo-session" >&6; }
+    cat >>confdefs.h <<\EOF
+#define _PATH_SUDO_SESSDIR "/usr/adm/sudo-session"
+EOF
+
+    sessdir="/usr/adm/sudo-session"
+fi
+
 
 case "$with_passwd" in
 yes|maybe)
@@ -24462,7 +24664,7 @@ exec 6>&1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by sudo $as_me 1.7.2, which was
+This file was extended by sudo $as_me 1.7.3, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -24511,7 +24713,7 @@ Report bugs to <bug-autoconf@gnu.org>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-sudo config.status 1.7.2
+sudo config.status 1.7.3
 configured by $0, generated by GNU Autoconf 2.61,
   with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
index e33e343b0890d3346c7382f55ae3abb06edea744..a1d35bf2a3ed056b3f5f6fc0543348025a5a3d96 100644 (file)
@@ -4,7 +4,7 @@ dnl $Sudo$
 dnl
 dnl Copyright (c) 1994-1996,1998-2009 Todd C. Miller <Todd.Miller@courtesan.com>
 dnl
-AC_INIT([sudo], [1.7.2], [http://www.sudo.ws/bugs/], [sudo])
+AC_INIT([sudo], [1.7.3], [http://www.sudo.ws/bugs/], [sudo])
 AC_CONFIG_HEADER(config.h pathnames.h)
 dnl
 dnl This won't work before AC_INIT
@@ -1837,6 +1837,10 @@ AC_FUNC_GETGROUPS
 AC_CHECK_FUNCS(strchr strrchr memchr memcpy memset sysconf tzset \
               strftime setrlimit initgroups getgroups fstat gettimeofday \
               setlocale getaddrinfo setsid setenv)
+AC_CHECK_FUNCS(openpty, [], [AC_CHECK_LIB(util, openpty, [
+    SUDO_LIBS="${SUDO_LIBS} -lutil"
+    AC_DEFINE(HAVE_OPENPTY)
+])])
 AC_CHECK_FUNCS(unsetenv, SUDO_FUNC_UNSETENV_VOID)
 SUDO_FUNC_PUTENV_CONST
 if test -z "$SKIP_SETRESUID"; then
@@ -2543,6 +2547,7 @@ dnl Check for log file and timestamp locations
 dnl
 SUDO_LOGFILE
 SUDO_TIMEDIR
+SUDO_SESSDIR
 
 dnl
 dnl Use passwd (and secureware) auth modules?
index 8498464dbe1e32250589ead5ae1eb9bb973fe3c9..2ba2be773eb9a1076e353bbb0d16198b8dac125a 100644 (file)
@@ -314,6 +314,10 @@ struct sudo_defs_types sudo_defs_table[] = {
        "umask_override", T_FLAG,
        "The umask specified in sudoers will override the user's, even if it is more permissive",
        NULL,
+    }, {
+       "script", T_FLAG,
+       "Log a transcript of the command being run",
+       NULL,
     }, {
        NULL, 0, NULL
     }
index bccfd160b8cebf6f6ee8a148ecfb1ecbee588431..a8dadb4f8b8a11f135ce29d27bc2adb2244112b4 100644 (file)
 #define I_FAST_GLOB             71
 #define def_umask_override      (sudo_defs_table[72].sd_un.flag)
 #define I_UMASK_OVERRIDE        72
+#define def_script              (sudo_defs_table[73].sd_un.flag)
+#define I_SCRIPT                73
 
 enum def_tupple {
        never,
index 625c1409729d61ebcc34958626899bef7e23ccaf..cb31693e1e0b4ec50113c5bca0342fa3a6b7ec32 100644 (file)
@@ -232,3 +232,6 @@ fast_glob
 umask_override
        T_FLAG
        "The umask specified in sudoers will override the user's, even if it is more permissive"
+script
+       T_FLAG
+       "Log a transcript of the command being run"
diff --git a/gram.c b/gram.c
index 1f0117e2bea94660c0fff339b1f9ef0cc644d7d5..e10c43dde3a44731b8f1b209eeaa80a6b2c96fe0 100644 (file)
--- a/gram.c
+++ b/gram.c
@@ -19,7 +19,7 @@ static char yyrcsid[]
 #define YYPREFIX "yy"
 #line 2 "gram.y"
 /*
- * Copyright (c) 1996, 1998-2005, 2007-2008
+ * Copyright (c) 1996, 1998-2005, 2007-2009
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -166,15 +166,17 @@ typedef union {
 #define EXEC 272
 #define SETENV 273
 #define NOSETENV 274
-#define ALL 275
-#define COMMENT 276
-#define HOSTALIAS 277
-#define CMNDALIAS 278
-#define USERALIAS 279
-#define RUNASALIAS 280
-#define ERROR 281
-#define TYPE 282
-#define ROLE 283
+#define SCRIPT 275
+#define NOSCRIPT 276
+#define ALL 277
+#define COMMENT 278
+#define HOSTALIAS 279
+#define CMNDALIAS 280
+#define USERALIAS 281
+#define RUNASALIAS 282
+#define ERROR 283
+#define TYPE 284
+#define ROLE 285
 #define YYERRCODE 256
 #if defined(__cplusplus) || defined(__STDC__)
 const short yylhs[] =
@@ -187,11 +189,11 @@ short yylhs[] =
     3,    3,    3,   20,   20,   19,   10,   10,    8,    8,
     8,    8,    8,    2,    2,    1,    6,    6,   23,   24,
    22,   22,   22,   22,   22,   17,   17,   18,   18,   18,
-   21,   21,   21,   21,   21,   21,   21,    5,    5,    5,
-   28,   28,   31,    9,    9,   29,   29,   32,    7,    7,
-   30,   30,   33,   27,   27,   34,   13,   13,   11,   11,
-   12,   12,   12,   12,   12,   16,   16,   14,   14,   15,
-   15,   15,
+   21,   21,   21,   21,   21,   21,   21,   21,   21,    5,
+    5,    5,   28,   28,   31,    9,    9,   29,   29,   32,
+    7,    7,   30,   30,   33,   27,   27,   34,   13,   13,
+   11,   11,   12,   12,   12,   12,   12,   16,   16,   14,
+   14,   15,   15,   15,
 };
 #if defined(__cplusplus) || defined(__STDC__)
 const short yylen[] =
@@ -204,11 +206,11 @@ short yylen[] =
     3,    3,    3,    1,    3,    3,    1,    2,    1,    1,
     1,    1,    1,    1,    3,    4,    1,    2,    3,    3,
     0,    1,    1,    2,    2,    0,    3,    1,    3,    2,
-    0,    2,    2,    2,    2,    2,    2,    1,    1,    1,
-    1,    3,    3,    1,    3,    1,    3,    3,    1,    3,
-    1,    3,    3,    1,    3,    3,    1,    3,    1,    2,
-    1,    1,    1,    1,    1,    1,    3,    1,    2,    1,
-    1,    1,
+    0,    2,    2,    2,    2,    2,    2,    2,    2,    1,
+    1,    1,    1,    3,    3,    1,    3,    1,    3,    3,
+    1,    3,    1,    3,    3,    1,    3,    3,    1,    3,
+    1,    2,    1,    1,    1,    1,    1,    1,    3,    1,
+    2,    1,    1,    1,
 };
 #if defined(__cplusplus) || defined(__STDC__)
 const short yydefred[] =
@@ -216,21 +218,21 @@ const short yydefred[] =
 short yydefred[] =
 #endif
        {                                      0,
-    0,   81,   83,   84,   85,    0,    0,    0,    0,    0,
-   82,    5,    0,    0,    0,    0,    0,    0,   77,   79,
+    0,   83,   85,   86,   87,    0,    0,    0,    0,    0,
+   84,    5,    0,    0,    0,    0,    0,    0,   79,   81,
     0,    0,    3,    6,    0,    0,   17,    0,   29,   32,
-   31,   33,   30,    0,   27,    0,   64,    0,    0,   60,
-   59,   58,    0,   37,   69,    0,    0,    0,   61,    0,
-    0,   66,    0,    0,   74,    0,    0,   71,   80,    0,
+   31,   33,   30,    0,   27,    0,   66,    0,    0,   62,
+   61,   60,    0,   37,   71,    0,    0,    0,   63,    0,
+    0,   68,    0,    0,   76,    0,    0,   73,   82,    0,
     0,   24,    0,    4,    0,    0,    0,   20,    0,   28,
     0,    0,    0,    0,   38,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,   78,    0,    0,   21,   22,
-   23,   18,   65,   70,    0,   62,    0,   67,    0,   75,
-    0,   72,    0,   34,    0,    0,   25,    0,    0,    0,
-    0,    0,    0,   51,    0,    0,   90,   92,   91,    0,
-   86,   88,    0,    0,   47,   35,    0,    0,    0,   44,
-   45,   89,    0,    0,   40,   39,   52,   53,   54,   55,
-   56,   57,   36,   87,
+    0,    0,    0,    0,    0,   80,    0,    0,   21,   22,
+   23,   18,   67,   72,    0,   64,    0,   69,    0,   77,
+    0,   74,    0,   34,    0,    0,   25,    0,    0,    0,
+    0,    0,    0,   51,    0,    0,   92,   94,   93,    0,
+   88,   90,    0,    0,   47,   35,    0,    0,    0,   44,
+   45,   91,    0,    0,   40,   39,   52,   53,   54,   55,
+   56,   57,   58,   59,   36,   89,
 };
 #if defined(__cplusplus) || defined(__STDC__)
 const short yydgoto[] =
@@ -248,232 +250,238 @@ const short yysindex[] =
 #else
 short yysindex[] =
 #endif
-       {                                    405,
- -266,    0,    0,    0,    0,   -9,  463,  510,  510,   -2,
-    0,    0, -243, -218, -215, -211, -225,    0,    0,    0,
-  -28,  405,    0,    0,  -36, -210,    0,    4,    0,    0,
-    0,    0,    0, -231,    0,  -33,    0,  -25,  -25,    0,
-    0,    0, -240,    0,    0,  -21,   -6,   -1,    0,    2,
-    6,    0,    7,    8,    0,    9,   11,    0,    0,  510,
-  -22,    0,   13,    0, -203, -201, -198,    0,   -9,    0,
-  463,    4,    4,    4,    0,   -2,    4,  463, -243,   -2,
- -218,  510, -215,  510, -211,    0,   27,  463,    0,    0,
-    0,    0,    0,    0,   28,    0,   30,    0,   31,    0,
-   31,    0,  141,    0,   32, -262,    0,  -27,  -16,   36,
-   27,   18,   19,    0, -200, -202,    0,    0,    0, -217,
-    0,    0,   39,  -27,    0,    0, -177, -175,  250,    0,
-    0,    0,  -27,   39,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,};
+       {                                    -26,
+ -272,    0,    0,    0,    0,  -16,  481,  485,  485,  -31,
+    0,    0, -237, -232, -228, -227, -238,    0,    0,    0,
+  417,  -26,    0,    0,   -2, -217,    0,    7,    0,    0,
+    0,    0,    0, -223,    0,  -28,    0,  -25,  -25,    0,
+    0,    0, -248,    0,    0,  -11,  -14,   -6,    0,   -3,
+   -5,    0,   -1,    4,    0,    2,    6,    0,    0,  485,
+  -17,    0,    8,    0, -198, -196, -195,    0,  -16,    0,
+  481,    7,    7,    7,    0,  -31,    7,  481, -237,  -31,
+ -232,  485, -228,  485, -227,    0,   29,  481,    0,    0,
+    0,    0,    0,    0,   26,    0,   30,    0,   31,    0,
+   31,    0,  457,    0,   32, -270,    0,  -30,   -8,   36,
+   29,   11,   12,    0, -206, -205,    0,    0,    0, -245,
+    0,    0,   35,  -30,    0,    0, -182, -180,  453,    0,
+    0,    0,  -30,   35,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,};
 #if defined(__cplusplus) || defined(__STDC__)
 const short yyrindex[] =
 #else
 short yyrindex[] =
 #endif
-       {                                     90,
+       {                                     84,
     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,   91,    0,    0,    1,    0,    0,  156,    0,    0,
+    0,   89,    0,    0,    1,    0,    0,  163,    0,    0,
     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,  181,    0,    0,
-  206,    0,    0,  237,    0,    0,  274,    0,    0,    0,
-    0,    0,  300,    0,    0,    0,    0,    0,    0,    0,
-    0,  326,  352,  378,    0,    0,  430,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,  -29,    0,    0,    0,
-    0,    0,    0,    0,   26,    0,   52,    0,   78,    0,
-  104,    0,    0,    0,  130,  442,    0,    0,   51,    0,
-  -29,    0,    0,    0,  461,  485,    0,    0,    0,    0,
-    0,    0,   53,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,   54,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,};
+    0,    0,    0,    0,    0,    0,    0,  190,    0,    0,
+  217,    0,    0,  244,    0,    0,  271,    0,    0,    0,
+    0,    0,  298,    0,    0,    0,    0,    0,    0,    0,
+    0,  325,  352,  379,    0,    0,  406,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,  432,    0,    0,    0,
+    0,    0,    0,    0,   28,    0,   55,    0,   82,    0,
+  109,    0,    0,    0,  136,  480,    0,    0,   49,    0,
+  432,    0,    0,    0,  507,  534,    0,    0,    0,    0,
+    0,    0,   50,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,   51,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,};
 #if defined(__cplusplus) || defined(__STDC__)
 const short yygindex[] =
 #else
 short yygindex[] =
 #endif
        {                                      0,
-  -18,    0,   29,   15,   56,  -73,   16,   63,   -5,   34,
-   40,   84,    5,  -31,  -17,  -15,    0,    0,   24,    0,
-    0,    0,  -10,   -8,    0,   92,    0,    0,    0,    0,
-   37,   38,   33,   41,
+  -18,    0,   25,   10,   52,  -72,   16,   63,   -7,   27,
+   39,   83,    3,  -32,  -15,  -22,    0,    0,   15,    0,
+    0,    0,  -12,   -4,    0,   85,    0,    0,    0,    0,
+   33,   37,   23,   34,
 };
-#define YYTABLESIZE 785
+#define YYTABLESIZE 811
 #if defined(__cplusplus) || defined(__STDC__)
 const short yytable[] =
 #else
 short yytable[] =
 #endif
-       {                                      26,
-   19,   36,   94,   46,   34,  120,   66,   26,   67,   24,
-   71,   26,   38,   39,   47,   60,   40,   41,   60,  112,
-  113,   71,   76,   26,   65,   63,   29,   60,   30,   31,
-   43,   32,    2,   19,   42,    3,    4,    5,   87,   50,
-  117,  124,   53,   33,   19,  118,   56,   69,   68,   11,
-   72,   68,   73,   74,   78,  143,   79,  119,   63,   89,
-   77,   90,   80,   81,   91,   83,  103,   82,   85,   84,
-   88,   71,   95,   76,   60,  111,  125,   76,  127,  128,
-  113,  112,  133,   63,   68,  135,   99,  136,  101,    1,
-    2,   48,  126,   50,   49,   97,   70,   92,   75,   86,
-   59,  144,  132,   73,   93,  131,  130,  109,  134,   68,
-   76,  107,    0,   64,    0,   96,    0,  102,   98,    0,
-    0,    0,    0,  100,    0,    0,    0,    0,    0,   26,
-    0,    0,    0,    0,    0,   76,   73,    0,    0,    0,
+       {                                      36,
+   19,   43,  120,   94,   26,   24,   17,   26,   40,   41,
+   38,   39,  117,  112,  113,   71,   26,  118,   60,    2,
+   47,   26,    3,    4,    5,   50,   71,   65,   42,   53,
+   56,  119,   76,   19,   29,   60,   30,   31,   11,   32,
+   66,   68,   67,   87,   19,   72,   78,   73,   74,  124,
+   69,   79,   81,   33,   70,   77,  145,   80,   65,   82,
+   65,   83,   84,   85,   89,   88,   90,   91,  103,   71,
+   95,  127,  128,   76,   60,  111,  125,  112,  133,  113,
+  135,   78,  136,    1,   99,   65,  101,   70,    2,   48,
+   50,   49,  126,   92,   75,   97,   70,   93,   86,   59,
+  146,  134,  107,  131,  132,  109,   64,  102,   75,    0,
+  130,   96,   70,    0,   78,    0,  100,   98,    0,    0,
     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,   12,    0,    0,    0,    0,
-    0,   73,   26,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,   17,    0,    0,    0,    0,    0,    0,
-    9,    0,    0,    0,    0,    0,    0,   26,   12,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,  108,    0,
-    0,    0,    0,    0,    0,   10,    0,    0,    0,    0,
-    0,    0,    0,    9,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,   25,    0,   46,   46,   29,
-  117,   30,   31,   25,   32,  118,    8,   25,   10,   46,
-   46,   46,   46,   46,   46,   46,   33,  119,    0,   25,
-    0,    0,   46,   46,   40,   41,   19,    0,   19,    0,
-    0,   19,   19,   19,   19,   19,   19,   19,   19,    8,
-    0,    0,   42,   11,    0,   19,   19,   19,   19,   19,
-   19,   63,   43,   63,    0,    0,   63,   63,   63,   63,
-   63,   63,   63,   63,    0,    0,    0,    0,    0,    7,
-   63,   63,   63,   63,   63,   63,   11,   68,    0,   68,
-    0,    0,   68,   68,   68,   68,   68,   68,   68,   68,
-    0,    0,    0,    0,    0,   15,   68,   68,   68,   68,
-   68,   68,    7,   76,    0,   76,    0,    0,   76,   76,
-   76,   76,   76,   76,   76,   76,    0,    0,    0,    0,
-    0,   13,   76,   76,   76,   76,   76,   76,   15,   73,
-    0,   73,    0,    0,   73,   73,   73,   73,   73,   73,
-   73,   73,    0,    0,    0,    0,    0,   14,   73,   73,
-   73,   73,   73,   73,   13,   26,    0,   26,    0,    0,
-   26,   26,   26,   26,   26,   26,   26,   26,    2,    0,
-    0,    3,    4,    5,   26,   26,   26,   26,   26,   26,
-   14,   12,    0,   12,    0,   11,   12,   12,   12,   12,
-   12,   12,   12,   12,    0,    0,    0,    0,    0,   16,
-   12,   12,   12,   12,   12,   12,    9,   17,    9,    0,
-    0,    9,    9,    9,    9,    9,    9,    9,    9,    0,
-    0,    0,    0,    0,    0,    9,    9,    9,    9,    9,
-    9,   10,   16,   10,    0,    0,   10,   10,   10,   10,
-   10,   10,   10,   10,   41,    0,    0,    0,    0,    0,
-   10,   10,   10,   10,   10,   10,    0,    0,    0,    0,
-    0,    0,    8,   42,    8,   34,    0,    8,    8,    8,
-    8,    8,    8,    8,    8,    0,   40,   41,    0,    0,
-    0,    8,    8,    8,    8,    8,    8,   43,  137,  138,
-  139,  140,  141,  142,   42,    0,    0,    0,    0,   11,
-    0,   11,    0,    0,   11,   11,   11,   11,   11,   11,
-   11,   11,   17,    0,    0,    0,    0,    0,   11,   11,
-   11,   11,   11,   11,    0,    7,    0,    7,    0,    0,
-    7,    7,    7,    7,    7,    7,    7,    7,    0,    0,
+    0,    0,    0,    0,    0,   26,    0,    0,    0,   78,
+    0,   75,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,   12,    0,    0,    0,   75,    0,   26,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    9,
+    0,    0,    0,   26,    0,   12,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   10,    0,    0,    0,
+    0,    0,    9,    0,    0,   40,   41,  117,    0,    1,
+   25,    2,  118,   25,    3,    4,    5,    6,    7,    8,
+    9,   10,   25,    8,    0,   42,  119,   25,    0,   10,
+   11,   12,   13,   14,   15,   16,   19,    0,   19,    0,
+    0,   19,   19,   19,   19,   19,   19,   19,   19,    0,
+   11,    0,    0,    0,    0,    0,    8,   19,   19,   19,
+   19,   19,   19,   65,    0,   65,    0,    0,   65,   65,
+   65,   65,   65,   65,   65,   65,    0,    7,    0,    0,
+    0,    0,    0,   11,   65,   65,   65,   65,   65,   65,
+   70,    0,   70,    0,    0,   70,   70,   70,   70,   70,
+   70,   70,   70,    0,   15,    0,    0,    0,    0,    0,
+    7,   70,   70,   70,   70,   70,   70,   78,    0,   78,
+    0,    0,   78,   78,   78,   78,   78,   78,   78,   78,
+    0,   13,    0,    0,    0,    0,    0,   15,   78,   78,
+   78,   78,   78,   78,   75,    0,   75,    0,    0,   75,
+   75,   75,   75,   75,   75,   75,   75,    0,   14,    0,
+    0,    0,    0,    0,   13,   75,   75,   75,   75,   75,
+   75,   26,    0,   26,    0,    0,   26,   26,   26,   26,
+   26,   26,   26,   26,    0,   16,    0,    0,    0,    0,
+    0,   14,   26,   26,   26,   26,   26,   26,   12,    0,
+   12,    0,    0,   12,   12,   12,   12,   12,   12,   12,
+   12,    0,    0,    0,    0,    0,    0,    0,   16,   12,
+   12,   12,   12,   12,   12,    9,    0,    9,    0,   34,
+    9,    9,    9,    9,    9,    9,    9,    9,    0,    0,
+   60,    0,    0,    0,   46,    0,    9,    9,    9,    9,
+    9,    9,   10,    0,   10,    0,    0,   10,   10,   10,
+   10,   10,   10,   10,   10,   43,    0,    0,    0,   17,
+    0,    0,    0,   10,   10,   10,   10,   10,   10,    8,
+    0,    8,    0,    0,    8,    8,    8,    8,    8,    8,
+    8,    8,   41,   34,  108,    0,    0,   17,    0,    0,
+    8,    8,    8,    8,    8,    8,   11,    0,   11,    0,
+    0,   11,   11,   11,   11,   11,   11,   11,   11,   42,
+    0,    0,    0,    0,    0,    0,    0,   11,   11,   11,
+   11,   11,   11,    7,    0,    7,    0,    0,    7,    7,
+    7,    7,    7,    7,    7,    7,   43,    0,    0,    0,
     0,    0,    0,    0,    7,    7,    7,    7,    7,    7,
-    0,   15,    0,   15,    0,    0,   15,   15,   15,   15,
-   15,   15,   15,   15,    0,    0,    0,    0,    0,    0,
-   15,   15,   15,   15,   15,   15,    0,   13,    0,   13,
+   15,    0,   15,    0,    0,   15,   15,   15,   15,   15,
+   15,   15,   15,    0,    0,    0,    0,    0,    0,    0,
+    0,   15,   15,   15,   15,   15,   15,   13,    0,   13,
     0,    0,   13,   13,   13,   13,   13,   13,   13,   13,
-    0,    0,    0,    0,    0,    0,   13,   13,   13,   13,
-   13,   13,    0,   14,    0,   14,    0,    0,   14,   14,
-   14,   14,   14,   14,   14,   14,    0,    0,    0,    0,
-    0,    0,   14,   14,   14,   14,   14,   14,    0,    0,
-    1,    0,    2,    0,    0,    3,    4,    5,    6,    7,
-    8,    9,   10,    0,    0,    0,    0,    0,    0,   11,
-   12,   13,   14,   15,   16,   16,    0,   16,    0,    0,
-   16,   16,   16,   16,   16,   16,   16,   16,   41,   41,
-    0,    0,    0,    0,   16,   16,   16,   16,   16,   16,
-   41,   41,   41,   41,   41,   41,   41,   42,   42,    0,
-   29,    0,   30,   31,    0,   32,    0,    0,    0,   42,
-   42,   42,   42,   42,   42,   42,    0,   33,    0,    0,
-    0,   43,   43,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,   43,   43,   43,   43,   43,   43,   43,
-    0,    0,    0,    0,    0,    0,    0,    2,    0,    0,
-    3,    4,    5,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,   11,
+    0,    0,    0,    0,    0,    0,    0,    0,   13,   13,
+   13,   13,   13,   13,   14,    0,   14,    0,    0,   14,
+   14,   14,   14,   14,   14,   14,   14,    0,    0,    0,
+    0,    0,    0,    0,    0,   14,   14,   14,   14,   14,
+   14,   16,    0,   16,    0,    0,   16,   16,   16,   16,
+   16,   16,   16,   16,   29,    0,   30,   31,    0,   32,
+    0,    0,   16,   16,   16,   16,   16,   16,   46,   46,
+    0,    0,    0,   33,    0,    0,    0,    0,    0,    0,
+   46,   46,   46,   46,   46,   46,   46,   46,   46,   40,
+   41,    0,    0,    0,    2,   46,   46,    3,    4,    5,
+    0,  137,  138,  139,  140,  141,  142,  143,  144,   42,
+    0,    0,    0,   11,    0,    0,   41,   41,   29,    0,
+   30,   31,    2,   32,    0,    3,    4,    5,   41,   41,
+   41,   41,   41,   41,   41,   41,   41,   33,    0,    0,
+    0,   11,    0,   42,   42,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   42,   42,   42,   42,   42,
+   42,   42,   42,   42,    0,    0,    0,    0,    0,    0,
+   43,   43,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,   43,   43,   43,   43,   43,   43,   43,   43,
+   43,
 };
 #if defined(__cplusplus) || defined(__STDC__)
 const short yycheck[] =
 #else
 short yycheck[] =
 #endif
-       {                                      33,
-    0,    7,   76,   33,   33,   33,   43,   33,   45,  276,
-   44,   33,    8,    9,  258,   44,  257,  258,   44,  282,
-  283,   44,   44,   33,   61,    0,  258,   44,  260,  261,
-   33,  263,  258,   33,  275,  261,  262,  263,   61,  258,
-  258,   58,  258,  275,   44,  263,  258,   44,  259,  275,
-   36,    0,   38,   39,   61,  129,   58,  275,   33,  263,
-   46,  263,   61,   58,  263,   58,   40,   61,   58,   61,
-   58,   44,   78,   44,   44,   44,   41,    0,   61,   61,
-  283,  282,   44,   58,   33,  263,   82,  263,   84,    0,
-    0,   41,  111,   41,   41,   80,   34,   69,   43,   60,
-   17,  133,  120,    0,   71,  116,  115,  103,  124,   58,
-   33,   88,   -1,   22,   -1,   79,   -1,   85,   81,   -1,
-   -1,   -1,   -1,   83,   -1,   -1,   -1,   -1,   -1,    0,
-   -1,   -1,   -1,   -1,   -1,   58,   33,   -1,   -1,   -1,
+       {                                       7,
+    0,   33,   33,   76,   33,  278,   33,   33,  257,  258,
+    8,    9,  258,  284,  285,   44,   33,  263,   44,  258,
+  258,   33,  261,  262,  263,  258,   44,    0,  277,  258,
+  258,  277,   44,   33,  258,   44,  260,  261,  277,  263,
+   43,  259,   45,   61,   44,   36,   61,   38,   39,   58,
+   44,   58,   58,  277,    0,   46,  129,   61,   61,   61,
+   33,   58,   61,   58,  263,   58,  263,  263,   40,   44,
+   78,   61,   61,   44,   44,   44,   41,  284,   44,  285,
+  263,    0,  263,    0,   82,   58,   84,   33,    0,   41,
+   41,   41,  111,   69,   43,   80,   34,   71,   60,   17,
+  133,  124,   88,  116,  120,  103,   22,   85,    0,   -1,
+  115,   79,   58,   -1,   33,   -1,   83,   81,   -1,   -1,
    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,
-   -1,   58,   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,   -1,   -1,
-    0,   -1,   -1,   -1,   -1,   -1,   -1,   58,   33,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   58,   -1,
-   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,  259,   -1,  257,  258,  258,
-  258,  260,  261,  259,  263,  263,    0,  259,   33,  269,
-  270,  271,  272,  273,  274,  275,  275,  275,   -1,  259,
-   -1,   -1,  282,  283,  257,  258,  256,   -1,  258,   -1,
-   -1,  261,  262,  263,  264,  265,  266,  267,  268,   33,
-   -1,   -1,  275,    0,   -1,  275,  276,  277,  278,  279,
-  280,  256,   33,  258,   -1,   -1,  261,  262,  263,  264,
-  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,    0,
-  275,  276,  277,  278,  279,  280,   33,  256,   -1,  258,
-   -1,   -1,  261,  262,  263,  264,  265,  266,  267,  268,
-   -1,   -1,   -1,   -1,   -1,    0,  275,  276,  277,  278,
-  279,  280,   33,  256,   -1,  258,   -1,   -1,  261,  262,
-  263,  264,  265,  266,  267,  268,   -1,   -1,   -1,   -1,
-   -1,    0,  275,  276,  277,  278,  279,  280,   33,  256,
-   -1,  258,   -1,   -1,  261,  262,  263,  264,  265,  266,
-  267,  268,   -1,   -1,   -1,   -1,   -1,    0,  275,  276,
-  277,  278,  279,  280,   33,  256,   -1,  258,   -1,   -1,
-  261,  262,  263,  264,  265,  266,  267,  268,  258,   -1,
-   -1,  261,  262,  263,  275,  276,  277,  278,  279,  280,
-   33,  256,   -1,  258,   -1,  275,  261,  262,  263,  264,
-  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,    0,
-  275,  276,  277,  278,  279,  280,  256,   33,  258,   -1,
+   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   58,
+   -1,   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,    0,   -1,   -1,   -1,   58,   -1,   33,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,    0,
+   -1,   -1,   -1,   58,   -1,   33,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,
+   -1,   -1,   33,   -1,   -1,  257,  258,  258,   -1,  256,
+  259,  258,  263,  259,  261,  262,  263,  264,  265,  266,
+  267,  268,  259,    0,   -1,  277,  277,  259,   -1,   33,
+  277,  278,  279,  280,  281,  282,  256,   -1,  258,   -1,
    -1,  261,  262,  263,  264,  265,  266,  267,  268,   -1,
-   -1,   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,
-  280,  256,   33,  258,   -1,   -1,  261,  262,  263,  264,
-  265,  266,  267,  268,   33,   -1,   -1,   -1,   -1,   -1,
-  275,  276,  277,  278,  279,  280,   -1,   -1,   -1,   -1,
-   -1,   -1,  256,   33,  258,   33,   -1,  261,  262,  263,
-  264,  265,  266,  267,  268,   -1,  257,  258,   -1,   -1,
-   -1,  275,  276,  277,  278,  279,  280,   33,  269,  270,
-  271,  272,  273,  274,  275,   -1,   -1,   -1,   -1,  256,
-   -1,  258,   -1,   -1,  261,  262,  263,  264,  265,  266,
-  267,  268,   33,   -1,   -1,   -1,   -1,   -1,  275,  276,
-  277,  278,  279,  280,   -1,  256,   -1,  258,   -1,   -1,
-  261,  262,  263,  264,  265,  266,  267,  268,   -1,   -1,
-   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,  280,
-   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
-  265,  266,  267,  268,   -1,   -1,   -1,   -1,   -1,   -1,
-  275,  276,  277,  278,  279,  280,   -1,  256,   -1,  258,
+    0,   -1,   -1,   -1,   -1,   -1,   33,  277,  278,  279,
+  280,  281,  282,  256,   -1,  258,   -1,   -1,  261,  262,
+  263,  264,  265,  266,  267,  268,   -1,    0,   -1,   -1,
+   -1,   -1,   -1,   33,  277,  278,  279,  280,  281,  282,
+  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,  265,
+  266,  267,  268,   -1,    0,   -1,   -1,   -1,   -1,   -1,
+   33,  277,  278,  279,  280,  281,  282,  256,   -1,  258,
    -1,   -1,  261,  262,  263,  264,  265,  266,  267,  268,
-   -1,   -1,   -1,   -1,   -1,   -1,  275,  276,  277,  278,
-  279,  280,   -1,  256,   -1,  258,   -1,   -1,  261,  262,
-  263,  264,  265,  266,  267,  268,   -1,   -1,   -1,   -1,
-   -1,   -1,  275,  276,  277,  278,  279,  280,   -1,   -1,
+   -1,    0,   -1,   -1,   -1,   -1,   -1,   33,  277,  278,
+  279,  280,  281,  282,  256,   -1,  258,   -1,   -1,  261,
+  262,  263,  264,  265,  266,  267,  268,   -1,    0,   -1,
+   -1,   -1,   -1,   -1,   33,  277,  278,  279,  280,  281,
+  282,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
+  265,  266,  267,  268,   -1,    0,   -1,   -1,   -1,   -1,
+   -1,   33,  277,  278,  279,  280,  281,  282,  256,   -1,
+  258,   -1,   -1,  261,  262,  263,  264,  265,  266,  267,
+  268,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   33,  277,
+  278,  279,  280,  281,  282,  256,   -1,  258,   -1,   33,
+  261,  262,  263,  264,  265,  266,  267,  268,   -1,   -1,
+   44,   -1,   -1,   -1,   33,   -1,  277,  278,  279,  280,
+  281,  282,  256,   -1,  258,   -1,   -1,  261,  262,  263,
+  264,  265,  266,  267,  268,   33,   -1,   -1,   -1,   33,
+   -1,   -1,   -1,  277,  278,  279,  280,  281,  282,  256,
+   -1,  258,   -1,   -1,  261,  262,  263,  264,  265,  266,
+  267,  268,   33,   33,   58,   -1,   -1,   33,   -1,   -1,
+  277,  278,  279,  280,  281,  282,  256,   -1,  258,   -1,
+   -1,  261,  262,  263,  264,  265,  266,  267,  268,   33,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,  277,  278,  279,
+  280,  281,  282,  256,   -1,  258,   -1,   -1,  261,  262,
+  263,  264,  265,  266,  267,  268,   33,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,  277,  278,  279,  280,  281,  282,
   256,   -1,  258,   -1,   -1,  261,  262,  263,  264,  265,
-  266,  267,  268,   -1,   -1,   -1,   -1,   -1,   -1,  275,
-  276,  277,  278,  279,  280,  256,   -1,  258,   -1,   -1,
-  261,  262,  263,  264,  265,  266,  267,  268,  257,  258,
-   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,  280,
-  269,  270,  271,  272,  273,  274,  275,  257,  258,   -1,
-  258,   -1,  260,  261,   -1,  263,   -1,   -1,   -1,  269,
-  270,  271,  272,  273,  274,  275,   -1,  275,   -1,   -1,
-   -1,  257,  258,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,  269,  270,  271,  272,  273,  274,  275,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,  258,   -1,   -1,
-  261,  262,  263,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,  275,
+  266,  267,  268,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,  277,  278,  279,  280,  281,  282,  256,   -1,  258,
+   -1,   -1,  261,  262,  263,  264,  265,  266,  267,  268,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  277,  278,
+  279,  280,  281,  282,  256,   -1,  258,   -1,   -1,  261,
+  262,  263,  264,  265,  266,  267,  268,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  277,  278,  279,  280,  281,
+  282,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
+  265,  266,  267,  268,  258,   -1,  260,  261,   -1,  263,
+   -1,   -1,  277,  278,  279,  280,  281,  282,  257,  258,
+   -1,   -1,   -1,  277,   -1,   -1,   -1,   -1,   -1,   -1,
+  269,  270,  271,  272,  273,  274,  275,  276,  277,  257,
+  258,   -1,   -1,   -1,  258,  284,  285,  261,  262,  263,
+   -1,  269,  270,  271,  272,  273,  274,  275,  276,  277,
+   -1,   -1,   -1,  277,   -1,   -1,  257,  258,  258,   -1,
+  260,  261,  258,  263,   -1,  261,  262,  263,  269,  270,
+  271,  272,  273,  274,  275,  276,  277,  277,   -1,   -1,
+   -1,  277,   -1,  257,  258,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  269,  270,  271,  272,  273,
+  274,  275,  276,  277,   -1,   -1,   -1,   -1,   -1,   -1,
+  257,  258,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,  269,  270,  271,  272,  273,  274,  275,  276,
+  277,
 };
 #define YYFINAL 18
 #ifndef YYDEBUG
 #define YYDEBUG 0
 #endif
-#define YYMAXTOKEN 283
+#define YYMAXTOKEN 285
 #if YYDEBUG
 #if defined(__cplusplus) || defined(__STDC__)
 const char * const yyname[] =
@@ -490,8 +498,9 @@ char *yyname[] =
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 "COMMAND","ALIAS","DEFVAR","NTWKADDR","NETGROUP","USERGROUP","WORD","DEFAULTS",
 "DEFAULTS_HOST","DEFAULTS_USER","DEFAULTS_RUNAS","DEFAULTS_CMND","NOPASSWD",
-"PASSWD","NOEXEC","EXEC","SETENV","NOSETENV","ALL","COMMENT","HOSTALIAS",
-"CMNDALIAS","USERALIAS","RUNASALIAS","ERROR","TYPE","ROLE",
+"PASSWD","NOEXEC","EXEC","SETENV","NOSETENV","SCRIPT","NOSCRIPT","ALL",
+"COMMENT","HOSTALIAS","CMNDALIAS","USERALIAS","RUNASALIAS","ERROR","TYPE",
+"ROLE",
 };
 #if defined(__cplusplus) || defined(__STDC__)
 const char * const yyrule[] =
@@ -556,6 +565,8 @@ char *yyrule[] =
 "cmndtag : cmndtag EXEC",
 "cmndtag : cmndtag SETENV",
 "cmndtag : cmndtag NOSETENV",
+"cmndtag : cmndtag SCRIPT",
+"cmndtag : cmndtag NOSCRIPT",
 "cmnd : ALL",
 "cmnd : ALIAS",
 "cmnd : COMMAND",
@@ -618,7 +629,7 @@ short *yyss;
 short *yysslim;
 YYSTYPE *yyvs;
 int yystacksize;
-#line 590 "gram.y"
+#line 600 "gram.y"
 static struct defaults *
 new_default(var, val, op)
     char *var;
@@ -809,7 +820,7 @@ init_parser(path, quiet)
     sudolineno = 1;
     verbose = !quiet;
 }
-#line 761 "y.tab.c"
+#line 772 "y.tab.c"
 /* allocate initial stack or double stack size, up to YYMAXDEPTH */
 #if defined(__cplusplus) || defined(__STDC__)
 static int yygrowstack(void)
@@ -1015,127 +1026,127 @@ yyreduce:
     switch (yyn)
     {
 case 1:
-#line 188 "gram.y"
+#line 190 "gram.y"
 { ; }
 break;
 case 5:
-#line 196 "gram.y"
+#line 198 "gram.y"
 {
                            ;
                        }
 break;
 case 6:
-#line 199 "gram.y"
+#line 201 "gram.y"
 {
                            yyerrok;
                        }
 break;
 case 7:
-#line 202 "gram.y"
+#line 204 "gram.y"
 {
                            add_userspec(yyvsp[-1].member, yyvsp[0].privilege);
                        }
 break;
 case 8:
-#line 205 "gram.y"
+#line 207 "gram.y"
 {
                            ;
                        }
 break;
 case 9:
-#line 208 "gram.y"
+#line 210 "gram.y"
 {
                            ;
                        }
 break;
 case 10:
-#line 211 "gram.y"
+#line 213 "gram.y"
 {
                            ;
                        }
 break;
 case 11:
-#line 214 "gram.y"
+#line 216 "gram.y"
 {
                            ;
                        }
 break;
 case 12:
-#line 217 "gram.y"
+#line 219 "gram.y"
 {
                            add_defaults(DEFAULTS, NULL, yyvsp[0].defaults);
                        }
 break;
 case 13:
-#line 220 "gram.y"
+#line 222 "gram.y"
 {
                            add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults);
                        }
 break;
 case 14:
-#line 223 "gram.y"
+#line 225 "gram.y"
 {
                            add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults);
                        }
 break;
 case 15:
-#line 226 "gram.y"
+#line 228 "gram.y"
 {
                            add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults);
                        }
 break;
 case 16:
-#line 229 "gram.y"
+#line 231 "gram.y"
 {
                            add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults);
                        }
 break;
 case 18:
-#line 235 "gram.y"
+#line 237 "gram.y"
 {
                            list_append(yyvsp[-2].defaults, yyvsp[0].defaults);
                            yyval.defaults = yyvsp[-2].defaults;
                        }
 break;
 case 19:
-#line 241 "gram.y"
+#line 243 "gram.y"
 {
                            yyval.defaults = new_default(yyvsp[0].string, NULL, TRUE);
                        }
 break;
 case 20:
-#line 244 "gram.y"
+#line 246 "gram.y"
 {
                            yyval.defaults = new_default(yyvsp[0].string, NULL, FALSE);
                        }
 break;
 case 21:
-#line 247 "gram.y"
+#line 249 "gram.y"
 {
                            yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, TRUE);
                        }
 break;
 case 22:
-#line 250 "gram.y"
+#line 252 "gram.y"
 {
                            yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+');
                        }
 break;
 case 23:
-#line 253 "gram.y"
+#line 255 "gram.y"
 {
                            yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-');
                        }
 break;
 case 25:
-#line 259 "gram.y"
+#line 261 "gram.y"
 {
                            list_append(yyvsp[-2].privilege, yyvsp[0].privilege);
                            yyval.privilege = yyvsp[-2].privilege;
                        }
 break;
 case 26:
-#line 265 "gram.y"
+#line 267 "gram.y"
 {
                            struct privilege *p = emalloc(sizeof(*p));
                            list2tq(&p->hostlist, yyvsp[-2].member);
@@ -1146,51 +1157,51 @@ case 26:
                        }
 break;
 case 27:
-#line 275 "gram.y"
+#line 277 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = FALSE;
                        }
 break;
 case 28:
-#line 279 "gram.y"
+#line 281 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = TRUE;
                        }
 break;
 case 29:
-#line 285 "gram.y"
+#line 287 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, ALIAS);
                        }
 break;
 case 30:
-#line 288 "gram.y"
+#line 290 "gram.y"
 {
                            yyval.member = new_member(NULL, ALL);
                        }
 break;
 case 31:
-#line 291 "gram.y"
+#line 293 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, NETGROUP);
                        }
 break;
 case 32:
-#line 294 "gram.y"
+#line 296 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, NTWKADDR);
                        }
 break;
 case 33:
-#line 297 "gram.y"
+#line 299 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, WORD);
                        }
 break;
 case 35:
-#line 303 "gram.y"
+#line 305 "gram.y"
 {
                            list_append(yyvsp[-2].cmndspec, yyvsp[0].cmndspec);
 #ifdef HAVE_SELINUX
@@ -1208,6 +1219,8 @@ case 35:
                            if (yyvsp[0].cmndspec->tags.setenv == UNSPEC &&
                                yyvsp[0].cmndspec->prev->tags.setenv != IMPLIED)
                                yyvsp[0].cmndspec->tags.setenv = yyvsp[0].cmndspec->prev->tags.setenv;
+                           if (yyvsp[0].cmndspec->tags.script == UNSPEC)
+                               yyvsp[0].cmndspec->tags.script = yyvsp[0].cmndspec->prev->tags.script;
                            if ((tq_empty(&yyvsp[0].cmndspec->runasuserlist) &&
                                 tq_empty(&yyvsp[0].cmndspec->runasgrouplist)) &&
                                (!tq_empty(&yyvsp[0].cmndspec->prev->runasuserlist) ||
@@ -1219,7 +1232,7 @@ case 35:
                        }
 break;
 case 36:
-#line 331 "gram.y"
+#line 335 "gram.y"
 {
                            struct cmndspec *cs = emalloc(sizeof(*cs));
                            if (yyvsp[-3].runas != NULL) {
@@ -1246,80 +1259,80 @@ case 36:
                        }
 break;
 case 37:
-#line 357 "gram.y"
+#line 361 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = FALSE;
                        }
 break;
 case 38:
-#line 361 "gram.y"
+#line 365 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = TRUE;
                        }
 break;
 case 39:
-#line 367 "gram.y"
+#line 371 "gram.y"
 {
                            yyval.string = yyvsp[0].string;
                        }
 break;
 case 40:
-#line 372 "gram.y"
+#line 376 "gram.y"
 {
                            yyval.string = yyvsp[0].string;
                        }
 break;
 case 41:
-#line 377 "gram.y"
+#line 381 "gram.y"
 {
                            yyval.seinfo.role = NULL;
                            yyval.seinfo.type = NULL;
                        }
 break;
 case 42:
-#line 381 "gram.y"
+#line 385 "gram.y"
 {
                            yyval.seinfo.role = yyvsp[0].string;
                            yyval.seinfo.type = NULL;
                        }
 break;
 case 43:
-#line 385 "gram.y"
+#line 389 "gram.y"
 {
                            yyval.seinfo.type = yyvsp[0].string;
                            yyval.seinfo.role = NULL;
                        }
 break;
 case 44:
-#line 389 "gram.y"
+#line 393 "gram.y"
 {
                            yyval.seinfo.role = yyvsp[-1].string;
                            yyval.seinfo.type = yyvsp[0].string;
                        }
 break;
 case 45:
-#line 393 "gram.y"
+#line 397 "gram.y"
 {
                            yyval.seinfo.type = yyvsp[-1].string;
                            yyval.seinfo.role = yyvsp[0].string;
                        }
 break;
 case 46:
-#line 399 "gram.y"
+#line 403 "gram.y"
 {
                            yyval.runas = NULL;
                        }
 break;
 case 47:
-#line 402 "gram.y"
+#line 406 "gram.y"
 {
                            yyval.runas = yyvsp[-1].runas;
                        }
 break;
 case 48:
-#line 407 "gram.y"
+#line 411 "gram.y"
 {
                            yyval.runas = emalloc(sizeof(struct runascontainer));
                            yyval.runas->runasusers = yyvsp[0].member;
@@ -1327,7 +1340,7 @@ case 48:
                        }
 break;
 case 49:
-#line 412 "gram.y"
+#line 416 "gram.y"
 {
                            yyval.runas = emalloc(sizeof(struct runascontainer));
                            yyval.runas->runasusers = yyvsp[-2].member;
@@ -1335,7 +1348,7 @@ case 49:
                        }
 break;
 case 50:
-#line 417 "gram.y"
+#line 421 "gram.y"
 {
                            yyval.runas = emalloc(sizeof(struct runascontainer));
                            yyval.runas->runasusers = NULL;
@@ -1343,61 +1356,73 @@ case 50:
                        }
 break;
 case 51:
-#line 424 "gram.y"
+#line 428 "gram.y"
 {
-                           yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.setenv = UNSPEC;
+                           yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.setenv = yyval.tag.script = UNSPEC;
                        }
 break;
 case 52:
-#line 427 "gram.y"
+#line 431 "gram.y"
 {
                            yyval.tag.nopasswd = TRUE;
                        }
 break;
 case 53:
-#line 430 "gram.y"
+#line 434 "gram.y"
 {
                            yyval.tag.nopasswd = FALSE;
                        }
 break;
 case 54:
-#line 433 "gram.y"
+#line 437 "gram.y"
 {
                            yyval.tag.noexec = TRUE;
                        }
 break;
 case 55:
-#line 436 "gram.y"
+#line 440 "gram.y"
 {
                            yyval.tag.noexec = FALSE;
                        }
 break;
 case 56:
-#line 439 "gram.y"
+#line 443 "gram.y"
 {
                            yyval.tag.setenv = TRUE;
                        }
 break;
 case 57:
-#line 442 "gram.y"
+#line 446 "gram.y"
 {
                            yyval.tag.setenv = FALSE;
                        }
 break;
 case 58:
-#line 447 "gram.y"
+#line 449 "gram.y"
 {
-                           yyval.member = new_member(NULL, ALL);
+                           yyval.tag.script = TRUE;
                        }
 break;
 case 59:
-#line 450 "gram.y"
+#line 452 "gram.y"
 {
-                           yyval.member = new_member(yyvsp[0].string, ALIAS);
+                           yyval.tag.script = FALSE;
                        }
 break;
 case 60:
-#line 453 "gram.y"
+#line 457 "gram.y"
+{
+                           yyval.member = new_member(NULL, ALL);
+                       }
+break;
+case 61:
+#line 460 "gram.y"
+{
+                           yyval.member = new_member(yyvsp[0].string, ALIAS);
+                       }
+break;
+case 62:
+#line 463 "gram.y"
 {
                            struct sudo_command *c = emalloc(sizeof(*c));
                            c->cmnd = yyvsp[0].command.cmnd;
@@ -1405,8 +1430,8 @@ case 60:
                            yyval.member = new_member((char *)c, COMMAND);
                        }
 break;
-case 63:
-#line 465 "gram.y"
+case 65:
+#line 475 "gram.y"
 {
                            char *s;
                            if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) {
@@ -1415,15 +1440,15 @@ case 63:
                            }
                        }
 break;
-case 65:
-#line 475 "gram.y"
+case 67:
+#line 485 "gram.y"
 {
                            list_append(yyvsp[-2].member, yyvsp[0].member);
                            yyval.member = yyvsp[-2].member;
                        }
 break;
-case 68:
-#line 485 "gram.y"
+case 70:
+#line 495 "gram.y"
 {
                            char *s;
                            if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) {
@@ -1432,15 +1457,15 @@ case 68:
                            }
                        }
 break;
-case 70:
-#line 495 "gram.y"
+case 72:
+#line 505 "gram.y"
 {
                            list_append(yyvsp[-2].member, yyvsp[0].member);
                            yyval.member = yyvsp[-2].member;
                        }
 break;
-case 73:
-#line 505 "gram.y"
+case 75:
+#line 515 "gram.y"
 {
                            char *s;
                            if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) {
@@ -1449,8 +1474,8 @@ case 73:
                            }
                        }
 break;
-case 76:
-#line 518 "gram.y"
+case 78:
+#line 528 "gram.y"
 {
                            char *s;
                            if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) {
@@ -1459,97 +1484,97 @@ case 76:
                            }
                        }
 break;
-case 78:
-#line 528 "gram.y"
+case 80:
+#line 538 "gram.y"
 {
                            list_append(yyvsp[-2].member, yyvsp[0].member);
                            yyval.member = yyvsp[-2].member;
                        }
 break;
-case 79:
-#line 534 "gram.y"
+case 81:
+#line 544 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = FALSE;
                        }
 break;
-case 80:
-#line 538 "gram.y"
+case 82:
+#line 548 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = TRUE;
                        }
 break;
-case 81:
-#line 544 "gram.y"
+case 83:
+#line 554 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, ALIAS);
                        }
 break;
-case 82:
-#line 547 "gram.y"
+case 84:
+#line 557 "gram.y"
 {
                            yyval.member = new_member(NULL, ALL);
                        }
 break;
-case 83:
-#line 550 "gram.y"
+case 85:
+#line 560 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, NETGROUP);
                        }
 break;
-case 84:
-#line 553 "gram.y"
+case 86:
+#line 563 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, USERGROUP);
                        }
 break;
-case 85:
-#line 556 "gram.y"
+case 87:
+#line 566 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, WORD);
                        }
 break;
-case 87:
-#line 562 "gram.y"
+case 89:
+#line 572 "gram.y"
 {
                            list_append(yyvsp[-2].member, yyvsp[0].member);
                            yyval.member = yyvsp[-2].member;
                        }
 break;
-case 88:
-#line 568 "gram.y"
+case 90:
+#line 578 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = FALSE;
                        }
 break;
-case 89:
-#line 572 "gram.y"
+case 91:
+#line 582 "gram.y"
 {
                            yyval.member = yyvsp[0].member;
                            yyval.member->negated = TRUE;
                        }
 break;
-case 90:
-#line 578 "gram.y"
+case 92:
+#line 588 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, ALIAS);
                        }
 break;
-case 91:
-#line 581 "gram.y"
+case 93:
+#line 591 "gram.y"
 {
                            yyval.member = new_member(NULL, ALL);
                        }
 break;
-case 92:
-#line 584 "gram.y"
+case 94:
+#line 594 "gram.y"
 {
                            yyval.member = new_member(yyvsp[0].string, WORD);
                        }
 break;
-#line 1501 "y.tab.c"
+#line 1526 "y.tab.c"
     }
     yyssp -= yym;
     yystate = *yyssp;
diff --git a/gram.h b/gram.h
index 8f054916ae7263fb5e9e0697c568ae7691121cd2..c71c897e62ba9b4394acb50f7a57372af7ead3be 100644 (file)
--- a/gram.h
+++ b/gram.h
 #define EXEC 272
 #define SETENV 273
 #define NOSETENV 274
-#define ALL 275
-#define COMMENT 276
-#define HOSTALIAS 277
-#define CMNDALIAS 278
-#define USERALIAS 279
-#define RUNASALIAS 280
-#define ERROR 281
-#define TYPE 282
-#define ROLE 283
+#define SCRIPT 275
+#define NOSCRIPT 276
+#define ALL 277
+#define COMMENT 278
+#define HOSTALIAS 279
+#define CMNDALIAS 280
+#define USERALIAS 281
+#define RUNASALIAS 282
+#define ERROR 283
+#define TYPE 284
+#define ROLE 285
 #ifndef YYSTYPE_DEFINED
 #define YYSTYPE_DEFINED
 typedef union {
diff --git a/gram.y b/gram.y
index 628ae01a63c9832457b27cd4c52510499c915cb1..8d7eeef14060ed45804c4edc510d98ef02e7ce26 100644 (file)
--- a/gram.y
+++ b/gram.y
@@ -146,6 +146,8 @@ yyerror(s)
 %token <tok>    EXEC                   /* don't preload dummy execve() */
 %token <tok>    SETENV                 /* user may set environment for cmnd */
 %token <tok>    NOSETENV               /* user may not set environment */
+%token <tok>    SCRIPT                 /* log a transcript of the cmnd */
+%token <tok>    NOSCRIPT               /* don't log a transcript of the cmnd */
 %token <tok>    ALL                    /* ALL keyword */
 %token <tok>    COMMENT                /* comment and/or carriage return */
 %token <tok>    HOSTALIAS              /* Host_Alias keyword */
@@ -317,6 +319,8 @@ cmndspeclist        :       cmndspec
                            if ($3->tags.setenv == UNSPEC &&
                                $3->prev->tags.setenv != IMPLIED)
                                $3->tags.setenv = $3->prev->tags.setenv;
+                           if ($3->tags.script == UNSPEC)
+                               $3->tags.script = $3->prev->tags.script;
                            if ((tq_empty(&$3->runasuserlist) &&
                                 tq_empty(&$3->runasgrouplist)) &&
                                (!tq_empty(&$3->prev->runasuserlist) ||
@@ -422,7 +426,7 @@ runaslist   :       userlist {
                ;
 
 cmndtag                :       /* empty */ {
-                           $$.nopasswd = $$.noexec = $$.setenv = UNSPEC;
+                           $$.nopasswd = $$.noexec = $$.setenv = $$.script = UNSPEC;
                        }
                |       cmndtag NOPASSWD {
                            $$.nopasswd = TRUE;
@@ -442,6 +446,12 @@ cmndtag            :       /* empty */ {
                |       cmndtag NOSETENV {
                            $$.setenv = FALSE;
                        }
+               |       cmndtag SCRIPT {
+                           $$.script = TRUE;
+                       }
+               |       cmndtag NOSCRIPT {
+                           $$.script = FALSE;
+                       }
                ;
 
 cmnd           :       ALL {
diff --git a/parse.c b/parse.c
index 5e8ac2fc0ceed19ca29deec70b61f3a77d8a1b2b..0b9b23510d6545fba59736afa66821ff5d37d723 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -254,6 +254,8 @@ sudo_file_lookup(nss, validated, pwflag)
                def_noexec = tags->noexec;
            if (tags->setenv != UNSPEC)
                def_setenv = tags->setenv;
+           if (tags->script != UNSPEC)
+               def_script = tags->script;
        }
     } else if (match == DENY) {
        SET(validated, VALIDATE_NOT_OK);
@@ -295,6 +297,11 @@ sudo_file_append_cmnd(cs, tags, lbuf)
            "PASSWD: ", NULL);
        tags->nopasswd = cs->tags.nopasswd;
     }
+    if (TAG_CHANGED(script)) {
+       lbuf_append(lbuf, cs->tags.script ? "SCRIPT: " :
+           "NOSCRIPT: ", NULL);
+       tags->script = cs->tags.script;
+    }
     m = cs->cmnd;
     print_member(lbuf, m->name, m->type, m->negated,
        CMNDALIAS);
@@ -316,6 +323,7 @@ sudo_file_display_priv_short(pw, us, lbuf)
        tags.noexec = UNSPEC;
        tags.setenv = UNSPEC;
        tags.nopasswd = UNSPEC;
+       tags.script = UNSPEC;
        lbuf_append(lbuf, "    ", NULL);
        tq_foreach_fwd(&priv->cmndlist, cs) {
            if (cs != tq_first(&priv->cmndlist))
@@ -367,6 +375,7 @@ sudo_file_display_priv_long(pw, us, lbuf)
        tags.noexec = UNSPEC;
        tags.setenv = UNSPEC;
        tags.nopasswd = UNSPEC;
+       tags.script = UNSPEC;
        lbuf_print(lbuf);       /* force a newline */
        lbuf_append(lbuf, "Sudoers entry:", NULL);
        lbuf_print(lbuf);
diff --git a/parse.h b/parse.h
index e0049e245ae55b6eade7d5f40a099c48524d0dfa..a33b7904378766104b5d6528331b197d18f22cac 100644 (file)
--- a/parse.h
+++ b/parse.h
@@ -45,7 +45,7 @@ struct cmndtag {
     __signed char nopasswd;
     __signed char noexec;
     __signed char setenv;
-    __signed char extra;
+    __signed char script;
 };
 
 /*
index 6cc18b787d49c3d943325d58fe92a3698e21814c..4166c7f9c6bfaa13c5123ba932f1c426c804b856 100644 (file)
 #undef _PATH_SUDO_TIMEDIR
 #endif /* _PATH_SUDO_TIMEDIR */
 
+/*
+ * Where to put the session files.  Defaults to /var/log/sudo-session,
+ * /var/adm/sudo-session or /usr/adm/sudo-session depending on what exists.
+ */
+#ifndef _PATH_SUDO_SESSDIR
+#undef _PATH_SUDO_SESSDIR
+#endif /* _PATH_SUDO_SESSDIR */
+
 /*
  * Where to put the sudo log file when logging to a file.  Defaults to
  * /var/log/sudo.log if /var/log exists, else /var/adm/sudo.log.
diff --git a/sudo.c b/sudo.c
index e32146729919c37225b729e8e001549013bf2a8a..ebe947d77396dce22e7fcb1661129caf08adf15e 100644 (file)
--- a/sudo.c
+++ b/sudo.c
@@ -165,6 +165,10 @@ static struct sudo_nss_list *snl;
 extern char *optarg;
 extern int optind;
 
+/* XXX - script.c */
+extern int script_fds[5];
+extern void term_restore __P((int));
+
 int
 main(argc, argv, envp)
     int argc;
@@ -498,6 +502,10 @@ main(argc, argv, envp)
        /* Must audit before uid change. */
        audit_success(NewArgv);
 
+       /* Open tty as needed */
+       if (def_script)
+           script_setup();
+
        /* Become specified user or root if executing a command. */
        if (ISSET(sudo_mode, MODE_RUN))
            set_perms(PERM_FULL_RUNAS);
@@ -540,7 +548,16 @@ main(argc, argv, envp)
        sudo_endpwent();
        sudo_endgrent();
 
-       closefrom(def_closefrom);
+       /* Move pty master/slave to low numbered fd and close the rest. */
+       fd = def_closefrom;
+       if (def_script) {
+           int i;
+           for (i = 0; i < 5; i++) {
+               dup2(script_fds[i], fd);
+               script_fds[i] = fd++;
+           }
+       }
+       closefrom(fd);
 
 #ifndef PROFILING
        if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0) {
@@ -548,11 +565,15 @@ main(argc, argv, envp)
            exit(0);
        } else {
 #ifdef HAVE_SELINUX
+           /* XXX - script support */
            if (is_selinux_enabled() > 0 && user_role != NULL)
                selinux_exec(user_role, user_type, NewArgv,
                    ISSET(sudo_mode, MODE_LOGIN_SHELL));
 #endif
-           execv(safe_cmnd, NewArgv);
+           if (def_script)
+               script_execv(safe_cmnd, NewArgv);
+           else
+               execv(safe_cmnd, NewArgv);
        }
 #else
        exit(0);
@@ -1446,6 +1467,8 @@ cleanup(gotsignal)
        sudo_endpwent();
        sudo_endgrent();
     }
+    if (def_script)
+       term_restore(STDIN_FILENO);
 }
 
 static void
diff --git a/sudo.h b/sudo.h
index 30537c0cc32fad8d11752c3abb910fa03c969a7e..4557f7f129b74be978d915b96523c59199cf11f0 100644 (file)
--- a/sudo.h
+++ b/sudo.h
@@ -324,6 +324,8 @@ void selinux_exec __P((char *, char *, char **, int));
 #ifdef HAVE_GETUSERATTR
 void aix_setlimits __P((char *));
 #endif
+int script_execv __P((const char *, char * const *));
+void script_setup __P((void));
 YY_DECL;
 
 /* Only provide extern declarations outside of sudo.c. */
diff --git a/term.c b/term.c
index 234c9dec36626edb572e2bfe45ec33dd8b5b62f8..301b396b6cbccd45cd1d83c79231448f1ab8c76a 100644 (file)
--- a/term.c
+++ b/term.c
@@ -132,9 +132,32 @@ term_noecho(fd)
 }
 
 #if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
+
 int
 term_raw(fd)
     int fd;
+{
+    struct termios term;
+
+    if (!changed && tcgetattr(fd, &oterm) != 0)
+       return(0);
+    (void) memcpy(&term, &oterm, sizeof(term));
+    /* Set terminal to raw mode */
+    term.c_iflag &= ~(BRKINT|ICRNL|IGNCR|INLCR|IXON|PARMRK);
+    term.c_oflag &= ~OPOST;
+    term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+    term.c_cc[VMIN] = 1;
+    term.c_cc[VTIME] = 0;
+    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) == 0) {
+       changed = 1;
+       return(1);
+    }
+    return(0);
+}
+
+int
+term_cbreak(fd)
+    int fd;
 {
     if (!changed && tcgetattr(fd, &oterm) != 0)
        return(0);
@@ -156,11 +179,42 @@ term_raw(fd)
     return(0);
 }
 
+int
+term_copy(src, dst)
+    int src;
+    int dst;
+{
+    struct termios tt;
+
+    if (tcgetattr(src, &tt) != 0)
+       return(0);
+    if (tcsetattr(dst, TCSAFLUSH, &tt) != 0)
+       return(0);
+    return(1);
+}
+
 #else /* SGTTY */
 
 int
 term_raw(fd)
     int fd;
+{
+    if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0)
+       return(0);
+    (void) memcpy(&term, &oterm, sizeof(term));
+    /* Set terminal to raw mode */
+    CLR(term.c_lflag, ECHO);
+    SET(term.sg_flags, RAW);
+    if (ioctl(fd, TIOCSETP, &term) == 0) {
+       changed = 1;
+       return(1);
+    }
+    return(0);
+}
+
+int
+term_cbreak(fd)
+    int fd;
 {
     if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0)
        return(0);
@@ -177,4 +231,27 @@ term_raw(fd)
     return(0);
 }
 
+int
+term_copy(src, dst)
+    int src;
+    int dst;
+{
+    struct sgttyb b;
+    struct tchars tc;
+    struct ltchars lc;
+    int l, lb;
+
+    if (ioctl(src, TIOCGETP, &b) != 0 || ioctl(src, TIOCGETC, &tc) != 0 ||
+       ioctl(src, TIOCGETD, &l) != 0 || ioctl(src, TIOCGLTC, &lc) != 0 ||
+       ioctl(src, TIOCLGET, &lb)) {
+       return(0);
+    }
+    if (ioctl(dst, TIOCSETP, &b) != 0 || ioctl(dst, TIOCSETC, &tc) != 0 ||
+       ioctl(dst, TIOCSLTC, &lc) != 0 || ioctl(dst, TIOCLSET, &lb) != 0 ||
+       ioctl(dst, TIOCSETD, &l) != 0) {
+       return(0);
+    }
+    return(1);
+}
+
 #endif
index 3d0b7359859b980cc1797b66f0fa68ab003a20d9..8ebc8f198d2aedabebfb4bee9d898e9fe16f1888 100644 (file)
@@ -68,7 +68,7 @@ static char *sudo_askpass __P((const char *));
 
 extern int term_restore __P((int));
 extern int term_noecho __P((int));
-extern int term_raw __P((int));
+extern int term_cbreak __P((int));
 
 /*
  * Like getpass(3) but with timeout and echo flags.
@@ -120,7 +120,7 @@ restart:
     (void) sigaction(SIGTTOU, &sa, &savettou);
 
     if (def_pwfeedback)
-       neednl = term_raw(input);
+       neednl = term_cbreak(input);
     else
        neednl = term_noecho(input);