]> granicus.if.org Git - sudo/commitdiff
Rewritten parser that converts sudoers into a set of data structures.
authorTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 26 Oct 2004 22:10:55 +0000 (22:10 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 26 Oct 2004 22:10:55 +0000 (22:10 +0000)
This eliminates ordering issues and makes it possible to apply
sudoers Defaults entries before searching for the command.

gram.c [new file with mode: 0644]
gram.h [moved from sudo.tab.h with 80% similarity]
gram.y [new file with mode: 0644]
parse.c
parse.h
parse.yacc [deleted file]
sudo.tab.c [deleted file]

diff --git a/gram.c b/gram.c
new file mode 100644 (file)
index 0000000..74b2980
--- /dev/null
+++ b/gram.c
@@ -0,0 +1,1454 @@
+#ifndef lint
+/*static char yysccsid[] = "from: @(#)yaccpar  1.9 (Berkeley) 02/21/93";*/
+static char yyrcsid[]
+#if __GNUC__ >= 2
+  __attribute__ ((unused))
+#endif /* __GNUC__ >= 2 */
+  = "$OpenBSD: skeleton.c,v 1.23 2004/03/12 13:39:50 henning Exp $";
+#endif
+#include <stdlib.h>
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define YYLEX yylex()
+#define YYEMPTY -1
+#define yyclearin (yychar=(YYEMPTY))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING() (yyerrflag!=0)
+#define YYPREFIX "yy"
+#line 2 "gram.y"
+/*
+ * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
+#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
+# include <alloca.h>
+#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
+
+#include "sudo.h"
+#include "parse.h"
+
+#ifndef lint
+static const char rcsid[] = "$Sudo$";
+#endif /* lint */
+
+/*
+ * Globals
+ */
+extern int sudolineno;
+extern char *sudoers;
+int parse_error;
+int pedantic = FALSE;
+int verbose = FALSE;
+int errorlineno = -1;
+char *errorfile = NULL;
+
+struct alias *aliases; /* XXX - use RB or binary search tree */
+struct defaults *defaults;
+struct userspec *userspecs;
+
+/*
+ * Local protoypes
+ */
+static void add_alias          __P((struct alias *));
+static void add_defaults       __P((int, struct member *, struct defaults *));
+static void add_userspec       __P((struct member *, struct privilege *));
+       void yyerror            __P((const char *));
+
+void
+yyerror(s)
+    const char *s;
+{
+    /* Save the line the first error occurred on. */
+    if (errorlineno == -1) {
+       errorlineno = sudolineno ? sudolineno - 1 : 0;
+       errorfile = estrdup(sudoers);
+    }
+    if (verbose && s != NULL) {
+#ifndef TRACELEXER
+       (void) fprintf(stderr, ">>> %s: %s near line %d <<<\n", sudoers, s,
+           sudolineno ? sudolineno - 1 : 0);
+#else
+       (void) fprintf(stderr, "<*> ");
+#endif
+    }
+    parse_error = TRUE;
+}
+#line 106 "gram.y"
+#ifndef YYSTYPE_DEFINED
+#define YYSTYPE_DEFINED
+typedef union {
+    struct alias *alias;
+    struct cmndspec *cmndspec;
+    struct defaults *defaults;
+    struct member *member;
+    struct privilege *privilege;
+    struct sudo_command command;
+    struct cmndtag tag;
+    char *string;
+    int tok;
+} YYSTYPE;
+#endif /* YYSTYPE_DEFINED */
+#line 138 "gram.c"
+#define COMMAND 257
+#define ALIAS 258
+#define DEFVAR 259
+#define NTWKADDR 260
+#define NETGROUP 261
+#define USERGROUP 262
+#define WORD 263
+#define DEFAULTS 264
+#define DEFAULTS_HOST 265
+#define DEFAULTS_USER 266
+#define DEFAULTS_RUNAS 267
+#define RUNAS 268
+#define NOPASSWD 269
+#define PASSWD 270
+#define NOEXEC 271
+#define EXEC 272
+#define MONITOR 273
+#define NOMONITOR 274
+#define ALL 275
+#define COMMENT 276
+#define HOSTALIAS 277
+#define CMNDALIAS 278
+#define USERALIAS 279
+#define RUNASALIAS 280
+#define ERROR 281
+#define YYERRCODE 256
+#if defined(__cplusplus) || defined(__STDC__)
+const short yylhs[] =
+#else
+short yylhs[] =
+#endif
+       {                                        -1,
+    0,    0,   29,   29,   30,   30,   30,   30,   30,   30,
+   30,   30,   30,   30,   30,   12,   12,   11,   11,   11,
+   11,   11,   27,   27,   26,   18,   18,   16,   16,   16,
+   16,   16,   10,   10,    9,   14,   14,   22,   22,   21,
+   21,   19,   19,   23,   23,   23,   23,   23,   28,   28,
+   28,   28,   28,   28,   28,   13,   13,   13,    4,    4,
+    3,   17,   17,    2,    2,    1,   15,   15,    6,    6,
+    5,    8,    8,    7,   25,   25,   20,   20,   24,   24,
+   24,   24,   24,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yylen[] =
+#else
+short yylen[] =
+#endif
+       {                                         2,
+    0,    1,    1,    2,    1,    2,    2,    2,    2,    2,
+    2,    2,    3,    3,    3,    1,    3,    1,    2,    3,
+    3,    3,    1,    3,    3,    1,    2,    1,    1,    1,
+    1,    1,    1,    3,    3,    1,    2,    0,    2,    1,
+    3,    1,    2,    1,    1,    1,    1,    1,    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,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yydefred[] =
+#else
+short yydefred[] =
+#endif
+       {                                      0,
+    0,   79,   81,   82,   83,    0,    0,    0,    0,   80,
+    5,    0,    0,    0,    0,    0,    0,   75,   77,    0,
+    0,    3,    6,    0,    0,   16,    0,   28,   31,   30,
+   32,   29,    0,   26,    0,   62,    0,   44,   46,   47,
+   48,   45,    0,   40,    0,   42,    0,   59,    0,    0,
+   64,    0,    0,   72,    0,    0,   69,    0,   78,    0,
+    0,   23,    0,    4,    0,    0,    0,   19,    0,   27,
+    0,    0,    0,   43,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,   76,    0,    0,   20,   21,   22,
+   17,   63,   41,    0,   60,   58,   57,   56,    0,   36,
+   67,    0,   65,    0,   73,    0,   70,    0,   33,    0,
+   49,   24,   37,    0,    0,    0,    0,   68,   34,   50,
+   51,   52,   53,   54,   55,   35,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yydgoto[] =
+#else
+short yydgoto[] =
+#endif
+       {                                      17,
+   51,   52,   48,   49,   57,   58,   54,   55,  109,  110,
+   26,   27,  100,  101,  102,   34,   61,   36,   44,   18,
+   45,  111,   46,   19,   20,   62,   63,  117,   21,   22,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yysindex[] =
+#else
+short yysindex[] =
+#endif
+       {                                    -33,
+ -270,    0,    0,    0,    0,   11,   88,  114,  140,    0,
+    0, -237, -234, -231, -226, -244,    0,    0,    0,   62,
+  -33,    0,    0,  -38, -224,    0,   -8,    0,    0,    0,
+    0,    0, -221,    0,  -24,    0,  -11,    0,    0,    0,
+    0,    0, -215,    0,   -3,    0,  -23,    0,   -9,   -5,
+    0,   -1,    2,    0,    4,    3,    0,    7,    0,  114,
+  -36,    0,    8,    0, -213, -208, -205,    0,   11,    0,
+   88,   -8,   -8,    0,  140,   -8,   88, -237,  -17, -234,
+  114, -231,  140, -226,    0, -201,   88,    0,    0,    0,
+    0,    0,    0,   24,    0,    0,    0,    0, -247,    0,
+    0,   25,    0,   27,    0,   28,    0,  140,    0,   30,
+    0,    0,    0,  -17,   28, -201,  -20,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yyrindex[] =
+#else
+short yyrindex[] =
+#endif
+       {                                     70,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+   76,    0,    0,    1,    0,    0,  156,    0,    0,    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,  236,    0,    0,  261,    0,    0,
+    0,    0,  300,    0,    0,    0,    0,    0,    0,    0,
+    0,  326,  352,    0,    0,  378,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,  274,    0,    0,    0,    0,
+    0,    0,    0,   26,    0,    0,    0,    0,    0,    0,
+    0,   52,    0,   78,    0,  104,    0,    0,    0,  130,
+    0,    0,    0,    0,  391,  274,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yygindex[] =
+#else
+short yygindex[] =
+#endif
+       {                                      0,
+    6,    0,    5,    0,   -7,    0,   -2,    0,  -37,    0,
+   12,   16,  -12, -102,    0,   49,   -4,   17,   14,   31,
+  -79,    0,   47,   77,   -6,    9,    0,    0,    0,   71,
+};
+#define YYTABLESIZE 666
+#if defined(__cplusplus) || defined(__STDC__)
+const short yytable[] =
+#else
+short yytable[] =
+#endif
+       {                                      16,
+   18,   37,   35,  106,   66,   23,   67,   71,   25,   96,
+   97,  118,   99,    2,  126,   99,    3,    4,    5,   71,
+   47,   25,   65,   50,   86,   61,   53,   98,  115,   25,
+   10,   56,   60,   18,   68,   69,   28,   77,   29,   30,
+   75,   31,   38,   25,   18,   39,   40,   41,   78,   88,
+   72,   66,   73,   32,   89,   79,   80,   90,   61,   42,
+   76,   82,   81,   83,   84,   87,  108,   71,  114,    1,
+   60,   75,   94,  116,  104,    2,  107,   74,  119,  105,
+   91,   70,   95,   61,   66,  103,  113,   92,   93,   74,
+   85,   64,   59,    0,   33,  112,    0,    0,    0,    0,
+    0,    0,    0,   71,    0,   60,    0,    0,    0,   66,
+   74,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+   33,    0,    0,    0,    0,    0,    0,    0,    0,   25,
+    0,    0,    0,    0,    0,   74,   71,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   16,    0,    0,    0,
+    0,    0,    0,    0,    0,   12,    0,    0,    0,    0,
+    0,   71,   25,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,   43,    0,    0,    0,    0,    0,    0,    0,
+    9,    0,    0,    0,    0,    0,    0,   25,   12,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   10,    0,    0,    0,    0,
+    0,    0,    0,    9,    0,    0,    0,    0,    0,    0,
+    0,    0,    1,    0,    2,    0,    0,    3,    4,    5,
+    6,    7,    8,    9,   24,    8,   96,   97,   10,   96,
+   97,   10,   11,   12,   13,   14,   15,   24,  120,  121,
+  122,  123,  124,  125,   98,   24,   18,   98,   18,    0,
+   11,   18,   18,   18,   18,   18,   18,   18,    8,   24,
+    0,    0,    0,    0,    0,   18,   18,   18,   18,   18,
+   18,   61,    0,   61,    0,    0,   61,   61,   61,   61,
+   61,   61,   61,   11,    0,    0,    0,    0,    0,    7,
+   61,   61,   61,   61,   61,   61,   38,   66,    0,   66,
+    0,    0,   66,   66,   66,   66,   66,   66,   66,   28,
+    0,   29,   30,    0,   31,   15,   66,   66,   66,   66,
+   66,   66,    7,   74,    0,   74,   32,    0,   74,   74,
+   74,   74,   74,   74,   74,   28,    0,   29,   30,    0,
+   31,   13,   74,   74,   74,   74,   74,   74,   15,   71,
+    0,   71,   32,    0,   71,   71,   71,   71,   71,   71,
+   71,    2,    0,    0,    3,    4,    5,   14,   71,   71,
+   71,   71,   71,   71,   13,   25,    0,   25,   10,    0,
+   25,   25,   25,   25,   25,   25,   25,   38,    0,    0,
+   39,   40,   41,    0,   25,   25,   25,   25,   25,   25,
+   14,   12,    0,   12,   42,    0,   12,   12,   12,   12,
+   12,   12,   12,   39,    0,    0,    0,    0,    0,    0,
+   12,   12,   12,   12,   12,   12,    9,    0,    9,    0,
+    0,    9,    9,    9,    9,    9,    9,    9,    0,    0,
+    0,    0,    0,    0,    0,    9,    9,    9,    9,    9,
+    9,   10,    0,   10,    0,    0,   10,   10,   10,   10,
+   10,   10,   10,    0,    0,    0,    0,    0,    0,    0,
+   10,   10,   10,   10,   10,   10,    0,    0,    0,    0,
+    0,    8,    0,    8,    0,    0,    8,    8,    8,    8,
+    8,    8,    8,    0,    0,    0,    0,    0,    0,    0,
+    8,    8,    8,    8,    8,    8,   11,    0,   11,    0,
+    0,   11,   11,   11,   11,   11,   11,   11,    0,    0,
+   38,   38,    0,    0,    0,   11,   11,   11,   11,   11,
+   11,    0,   38,   38,   38,   38,   38,   38,   38,    0,
+    0,    0,    0,    0,    0,    7,    0,    7,    0,    0,
+    7,    7,    7,    7,    7,    7,    7,    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,    0,    0,    0,    0,    0,    0,    0,
+   15,   15,   15,   15,   15,   15,    0,   13,    0,   13,
+    0,    0,   13,   13,   13,   13,   13,   13,   13,    0,
+    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,    0,    0,   39,   39,    0,
+    0,    0,   14,   14,   14,   14,   14,   14,    0,   39,
+   39,   39,   39,   39,   39,   39,
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const short yycheck[] =
+#else
+short yycheck[] =
+#endif
+       {                                      33,
+    0,    8,    7,   83,   43,  276,   45,   44,   33,  257,
+  258,  114,   33,  258,  117,   33,  261,  262,  263,   44,
+  258,   33,   61,  258,   61,    0,  258,  275,  108,   33,
+  275,  258,   44,   33,  259,   44,  258,   61,  260,  261,
+   44,  263,  258,   33,   44,  261,  262,  263,   58,  263,
+   35,    0,   37,  275,  263,   61,   58,  263,   33,  275,
+   45,   58,   61,   61,   58,   58,  268,   44,   44,    0,
+   44,   44,   77,   44,   81,    0,   84,    0,  116,   82,
+   69,   33,   78,   58,   33,   80,   99,   71,   75,   43,
+   60,   21,   16,   -1,   33,   87,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,    0,   -1,   44,   -1,   -1,   -1,   58,
+   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   33,   -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,   33,   -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,   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+    0,   -1,   -1,   -1,   -1,   -1,   -1,   58,   33,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   33,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,
+  264,  265,  266,  267,  259,    0,  257,  258,   33,  257,
+  258,  275,  276,  277,  278,  279,  280,  259,  269,  270,
+  271,  272,  273,  274,  275,  259,  256,  275,  258,   -1,
+    0,  261,  262,  263,  264,  265,  266,  267,   33,  259,
+   -1,   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,
+  280,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
+  265,  266,  267,   33,   -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,  258,
+   -1,  260,  261,   -1,  263,    0,  275,  276,  277,  278,
+  279,  280,   33,  256,   -1,  258,  275,   -1,  261,  262,
+  263,  264,  265,  266,  267,  258,   -1,  260,  261,   -1,
+  263,    0,  275,  276,  277,  278,  279,  280,   33,  256,
+   -1,  258,  275,   -1,  261,  262,  263,  264,  265,  266,
+  267,  258,   -1,   -1,  261,  262,  263,    0,  275,  276,
+  277,  278,  279,  280,   33,  256,   -1,  258,  275,   -1,
+  261,  262,  263,  264,  265,  266,  267,  258,   -1,   -1,
+  261,  262,  263,   -1,  275,  276,  277,  278,  279,  280,
+   33,  256,   -1,  258,  275,   -1,  261,  262,  263,  264,
+  265,  266,  267,   33,   -1,   -1,   -1,   -1,   -1,   -1,
+  275,  276,  277,  278,  279,  280,  256,   -1,  258,   -1,
+   -1,  261,  262,  263,  264,  265,  266,  267,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,
+  280,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
+  265,  266,  267,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+  275,  276,  277,  278,  279,  280,   -1,   -1,   -1,   -1,
+   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
+  265,  266,  267,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+  275,  276,  277,  278,  279,  280,  256,   -1,  258,   -1,
+   -1,  261,  262,  263,  264,  265,  266,  267,   -1,   -1,
+  257,  258,   -1,   -1,   -1,  275,  276,  277,  278,  279,
+  280,   -1,  269,  270,  271,  272,  273,  274,  275,   -1,
+   -1,   -1,   -1,   -1,   -1,  256,   -1,  258,   -1,   -1,
+  261,  262,  263,  264,  265,  266,  267,   -1,   -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,   -1,   -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,   -1,
+   -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,   -1,   -1,  257,  258,   -1,
+   -1,   -1,  275,  276,  277,  278,  279,  280,   -1,  269,
+  270,  271,  272,  273,  274,  275,
+};
+#define YYFINAL 17
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 281
+#if YYDEBUG
+#if defined(__cplusplus) || defined(__STDC__)
+const char * const yyname[] =
+#else
+char *yyname[] =
+#endif
+       {
+"end-of-file",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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,
+"COMMAND","ALIAS","DEFVAR","NTWKADDR","NETGROUP","USERGROUP","WORD","DEFAULTS",
+"DEFAULTS_HOST","DEFAULTS_USER","DEFAULTS_RUNAS","RUNAS","NOPASSWD","PASSWD",
+"NOEXEC","EXEC","MONITOR","NOMONITOR","ALL","COMMENT","HOSTALIAS","CMNDALIAS",
+"USERALIAS","RUNASALIAS","ERROR",
+};
+#if defined(__cplusplus) || defined(__STDC__)
+const char * const yyrule[] =
+#else
+char *yyrule[] =
+#endif
+       {"$accept : file",
+"file :",
+"file : line",
+"line : entry",
+"line : line entry",
+"entry : COMMENT",
+"entry : error COMMENT",
+"entry : userlist privileges",
+"entry : USERALIAS useraliases",
+"entry : HOSTALIAS hostaliases",
+"entry : CMNDALIAS cmndaliases",
+"entry : RUNASALIAS runasaliases",
+"entry : DEFAULTS defaults_list",
+"entry : DEFAULTS_USER userlist defaults_list",
+"entry : DEFAULTS_RUNAS runaslist defaults_list",
+"entry : DEFAULTS_HOST hostlist defaults_list",
+"defaults_list : defaults_entry",
+"defaults_list : defaults_list ',' defaults_entry",
+"defaults_entry : DEFVAR",
+"defaults_entry : '!' DEFVAR",
+"defaults_entry : DEFVAR '=' WORD",
+"defaults_entry : DEFVAR '+' WORD",
+"defaults_entry : DEFVAR '-' WORD",
+"privileges : privilege",
+"privileges : privileges ':' privilege",
+"privilege : hostlist '=' cmndspeclist",
+"ophost : host",
+"ophost : '!' host",
+"host : ALIAS",
+"host : ALL",
+"host : NETGROUP",
+"host : NTWKADDR",
+"host : WORD",
+"cmndspeclist : cmndspec",
+"cmndspeclist : cmndspeclist ',' cmndspec",
+"cmndspec : runasspec cmndtag opcmnd",
+"opcmnd : cmnd",
+"opcmnd : '!' cmnd",
+"runasspec :",
+"runasspec : RUNAS runaslist",
+"runaslist : oprunasuser",
+"runaslist : runaslist ',' oprunasuser",
+"oprunasuser : runasuser",
+"oprunasuser : '!' runasuser",
+"runasuser : ALIAS",
+"runasuser : ALL",
+"runasuser : NETGROUP",
+"runasuser : USERGROUP",
+"runasuser : WORD",
+"cmndtag :",
+"cmndtag : cmndtag NOPASSWD",
+"cmndtag : cmndtag PASSWD",
+"cmndtag : cmndtag NOEXEC",
+"cmndtag : cmndtag EXEC",
+"cmndtag : cmndtag MONITOR",
+"cmndtag : cmndtag NOMONITOR",
+"cmnd : ALL",
+"cmnd : ALIAS",
+"cmnd : COMMAND",
+"hostaliases : hostalias",
+"hostaliases : hostaliases ':' hostalias",
+"hostalias : ALIAS '=' hostlist",
+"hostlist : ophost",
+"hostlist : hostlist ',' ophost",
+"cmndaliases : cmndalias",
+"cmndaliases : cmndaliases ':' cmndalias",
+"cmndalias : ALIAS '=' cmndlist",
+"cmndlist : opcmnd",
+"cmndlist : cmndlist ',' opcmnd",
+"runasaliases : runasalias",
+"runasaliases : runasaliases ':' runasalias",
+"runasalias : ALIAS '=' runaslist",
+"useraliases : useralias",
+"useraliases : useraliases ':' useralias",
+"useralias : ALIAS '=' userlist",
+"userlist : opuser",
+"userlist : userlist ',' opuser",
+"opuser : user",
+"opuser : '!' user",
+"user : ALIAS",
+"user : ALL",
+"user : NETGROUP",
+"user : USERGROUP",
+"user : WORD",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 10000
+#define YYMAXDEPTH 10000
+#endif
+#endif
+#define YYINITSTACKSIZE 200
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short *yyss;
+short *yysslim;
+YYSTYPE *yyvs;
+int yystacksize;
+#line 508 "gram.y"
+
+/*
+ * Add a list of aliases to the end of the global aliases list.
+ */
+static void
+add_alias(a)
+    struct alias *a;
+{
+    if (aliases == NULL)
+       aliases = a;
+    else {
+       if (aliases->last != NULL)
+           aliases->last->next = a;
+       else /* if (aliases->next == NULL) */
+           aliases->next = a;
+       aliases->last = a->last ? a->last : a;
+    }
+}
+
+/*
+ * Add a list of defaults structures to the defaults list.
+ * The binding, if non-NULL, specifies a list of hosts, users, or
+ * runas users the entries apply to (specified by the type).
+ */
+static void
+add_defaults(type, binding, defs)
+    int type;
+    struct member *binding;
+    struct defaults *defs;
+{
+    struct defaults *d;
+
+    /*
+     * Set type and binding (who it applies to) for new entries.
+     */
+    for (d = defs; d != NULL; d = d->next) {
+       d->type = type;
+       d->binding = binding;
+    }
+    if (defaults == NULL)
+       defaults = defs;
+    else {
+       if (defaults->last != NULL)
+           defaults->last->next = defs;
+       else /* if (defaults->next == NULL) */
+           defaults->next = defs;
+       defaults->last = defs->last ? defs->last : defs;
+    }
+}
+
+/*
+ * Allocate a new struct userspec, populate it, and insert it at the
+ * and of the userspecs list.
+ */
+static void
+add_userspec(members, privs)
+    struct member *members;
+    struct privilege *privs;
+{
+    struct userspec *u;
+
+    u = emalloc(sizeof(*u));
+    u->user = members;
+    u->privileges = privs;
+    u->last = NULL;
+    u->next = NULL;
+    if (userspecs == NULL)
+       userspecs = u;
+    else {
+       if (userspecs->last != NULL)
+           userspecs->last->next = u;
+       else /* if (userspecs->next == NULL) */
+           userspecs->next = u;
+       userspecs->last = u;
+    }
+}
+
+/*
+ * Free up space used by data structures from a previous parser run and sets
+ * the current sudoers file to path.
+ */
+void
+init_parser(path, quiet)
+    char *path;
+    int quiet;
+{
+    struct alias *a;
+    struct defaults *d;
+    struct member *m, *lastbinding;
+    struct userspec *us;
+    struct privilege *priv;
+    struct cmndspec *cs;
+    VOID *next;
+
+    for (a = aliases ; a != NULL; a = a->next) {
+       for (m = a->first_member; m != NULL; m = next) {
+           next = m->next;
+           if (m->name != NULL)
+               free(m->name);
+           free(m);
+       }
+    }
+    aliases = NULL;
+
+    for (us = userspecs ; us != NULL; us = next) {
+       for (m = us->user; m != NULL; m = next) {
+           next = m->next;
+           if (m->name != NULL)
+               free(m->name);
+           free(m);
+       }
+       for (priv = us->privileges; priv != NULL; priv = next) {
+           for (m = priv->hostlist; m != NULL; m = next) {
+               next = m->next;
+               if (m->name != NULL)
+                   free(m->name);
+               free(m);
+           }
+           for (cs = priv->cmndlist; cs != NULL; cs = next) {
+               for (m = cs->runaslist; m != NULL; m = next) {
+                   next = m->next;
+                   if (m->name != NULL)
+                       free(m->name);
+                   free(m);
+               }
+               if (cs->cmnd->name != NULL)
+                   free(cs->cmnd->name);
+               free(cs->cmnd);
+               next = cs->next;
+               free(cs);
+           }
+           next = priv->next;
+           free(priv);
+       }
+       next = us->next;
+       free(us);
+    }
+    userspecs = NULL;
+
+    lastbinding = NULL;
+    for (d = defaults ; d != NULL; d = next) {
+       if (d->binding != lastbinding) {
+           for (m = d->binding; m != NULL; m = next) {
+               next = m->next;
+               if (m->name != NULL)
+                   free(m->name);
+               free(m);
+           }
+           lastbinding = d->binding;
+       }
+       next = d->next;
+       free(d->var);
+       if (d->val != NULL)
+           free(d->val);
+       free(d);
+    }
+    defaults = NULL;
+
+    if (sudoers != NULL)
+       free(sudoers);
+    sudoers = estrdup(path);
+
+    parse_error = FALSE;
+    errorlineno = -1;
+    sudolineno = 1;
+    verbose = !quiet;
+}
+#line 679 "gram.c"
+/* allocate initial stack or double stack size, up to YYMAXDEPTH */
+#if defined(__cplusplus) || defined(__STDC__)
+static int yygrowstack(void)
+#else
+static int yygrowstack()
+#endif
+{
+    int newsize, i;
+    short *newss;
+    YYSTYPE *newvs;
+
+    if ((newsize = yystacksize) == 0)
+        newsize = YYINITSTACKSIZE;
+    else if (newsize >= YYMAXDEPTH)
+        return -1;
+    else if ((newsize *= 2) > YYMAXDEPTH)
+        newsize = YYMAXDEPTH;
+    i = yyssp - yyss;
+    newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) :
+      (short *)malloc(newsize * sizeof *newss);
+    if (newss == NULL)
+        goto bail;
+    yyss = newss;
+    yyssp = newss + i;
+    newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) :
+      (YYSTYPE *)malloc(newsize * sizeof *newvs);
+    if (newvs == NULL)
+        goto bail;
+    yyvs = newvs;
+    yyvsp = newvs + i;
+    yystacksize = newsize;
+    yysslim = yyss + newsize - 1;
+    return 0;
+bail:
+    if (yyss)
+            free(yyss);
+    if (yyvs)
+            free(yyvs);
+    yyss = yyssp = NULL;
+    yyvs = yyvsp = NULL;
+    yystacksize = 0;
+    return -1;
+}
+
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+#if defined(__cplusplus) || defined(__STDC__)
+yyparse(void)
+#else
+yyparse()
+#endif
+{
+    int yym, yyn, yystate;
+#if YYDEBUG
+#if defined(__cplusplus) || defined(__STDC__)
+    const char *yys;
+#else /* !(defined(__cplusplus) || defined(__STDC__)) */
+    char *yys;
+#endif /* !(defined(__cplusplus) || defined(__STDC__)) */
+
+    if ((yys = getenv("YYDEBUG")))
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif /* YYDEBUG */
+
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = (-1);
+
+    if (yyss == NULL && yygrowstack()) goto yyoverflow;
+    yyssp = yyss;
+    yyvsp = yyvs;
+    *yyssp = yystate = 0;
+
+yyloop:
+    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
+    if (yychar < 0)
+    {
+        if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yyssp >= yysslim && yygrowstack())
+        {
+            goto yyoverflow;
+        }
+        *++yyssp = yystate = yytable[yyn];
+        *++yyvsp = yylval;
+        yychar = (-1);
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag) goto yyinrecovery;
+#if defined(lint) || defined(__GNUC__)
+    goto yynewerror;
+#endif
+yynewerror:
+    yyerror("syntax error");
+#if defined(lint) || defined(__GNUC__)
+    goto yyerrlab;
+#endif
+yyerrlab:
+    ++yynerrs;
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+                if (yyssp >= yysslim && yygrowstack())
+                {
+                    goto yyoverflow;
+                }
+                *++yyssp = yystate = yytable[yyn];
+                *++yyvsp = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yyssp);
+#endif
+                if (yyssp <= yyss) goto yyabort;
+                --yyssp;
+                --yyvsp;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == 0) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = (-1);
+        goto yyloop;
+    }
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    yyval = yyvsp[1-yym];
+    switch (yyn)
+    {
+case 1:
+#line 177 "gram.y"
+{ ; }
+break;
+case 5:
+#line 185 "gram.y"
+{
+                           ;
+                       }
+break;
+case 6:
+#line 188 "gram.y"
+{
+                           yyerrok;
+                       }
+break;
+case 7:
+#line 191 "gram.y"
+{
+                           add_userspec(yyvsp[-1].member, yyvsp[0].privilege);
+                       }
+break;
+case 8:
+#line 194 "gram.y"
+{
+                           add_alias(yyvsp[0].alias);
+                       }
+break;
+case 9:
+#line 197 "gram.y"
+{
+                           add_alias(yyvsp[0].alias);
+                       }
+break;
+case 10:
+#line 200 "gram.y"
+{
+                           add_alias(yyvsp[0].alias);
+                       }
+break;
+case 11:
+#line 203 "gram.y"
+{
+                           add_alias(yyvsp[0].alias);
+                       }
+break;
+case 12:
+#line 206 "gram.y"
+{
+                           add_defaults(DEFAULTS, NULL, yyvsp[0].defaults);
+                       }
+break;
+case 13:
+#line 209 "gram.y"
+{
+                           add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 14:
+#line 212 "gram.y"
+{
+                           add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 15:
+#line 215 "gram.y"
+{
+                           add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults);
+                       }
+break;
+case 17:
+#line 221 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].defaults, yyvsp[0].defaults);
+                           yyval.defaults = yyvsp[-2].defaults;
+                       }
+break;
+case 18:
+#line 227 "gram.y"
+{
+                           NEW_DEFAULT(yyval.defaults, yyvsp[0].string, NULL, TRUE);
+                       }
+break;
+case 19:
+#line 230 "gram.y"
+{
+                           NEW_DEFAULT(yyval.defaults, yyvsp[0].string, NULL, FALSE);
+                       }
+break;
+case 20:
+#line 233 "gram.y"
+{
+                           NEW_DEFAULT(yyval.defaults, yyvsp[-2].string, yyvsp[0].string, TRUE);
+                       }
+break;
+case 21:
+#line 236 "gram.y"
+{
+                           NEW_DEFAULT(yyval.defaults, yyvsp[-2].string, yyvsp[0].string, '+');
+                       }
+break;
+case 22:
+#line 239 "gram.y"
+{
+                           NEW_DEFAULT(yyval.defaults, yyvsp[-2].string, yyvsp[0].string, '-');
+                       }
+break;
+case 24:
+#line 245 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].privilege, yyvsp[0].privilege);
+                           yyval.privilege = yyvsp[-2].privilege;
+                       }
+break;
+case 25:
+#line 251 "gram.y"
+{
+                           struct cmndtag tags;
+                           struct privilege *p = emalloc(sizeof(*p));
+                           struct cmndspec *cs;
+                           p->hostlist = yyvsp[-2].member;
+                           p->cmndlist = yyvsp[0].cmndspec;
+                           tags.nopasswd = tags.noexec = tags.monitor = UNSPEC;
+                           /* propagate tags */
+                           for (cs = yyvsp[0].cmndspec; cs != NULL; cs = cs->next) {
+                               if (cs->tags.nopasswd == UNSPEC)
+                                   cs->tags.nopasswd = tags.nopasswd;
+                               if (cs->tags.noexec == UNSPEC)
+                                   cs->tags.noexec = tags.noexec;
+                               if (cs->tags.monitor == UNSPEC)
+                                   cs->tags.monitor = tags.monitor;
+                               memcpy(&tags, &cs->tags, sizeof(tags));
+                           }
+                           p->last = NULL;
+                           p->next = NULL;
+                           yyval.privilege = p;
+                       }
+break;
+case 26:
+#line 274 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 27:
+#line 278 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 28:
+#line 284 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, HOSTALIAS);
+                       }
+break;
+case 29:
+#line 287 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, NULL, ALL);
+                       }
+break;
+case 30:
+#line 290 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, NETGROUP);
+                       }
+break;
+case 31:
+#line 293 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, NTWKADDR);
+                       }
+break;
+case 32:
+#line 296 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, WORD);
+                       }
+break;
+case 34:
+#line 302 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].cmndspec, yyvsp[0].cmndspec);
+                           yyval.cmndspec = yyvsp[-2].cmndspec;
+                       }
+break;
+case 35:
+#line 308 "gram.y"
+{
+                           struct cmndspec *cs = emalloc(sizeof(*cs));
+                           cs->runaslist = yyvsp[-2].member;
+                           cs->tags = yyvsp[-1].tag;
+                           cs->cmnd = yyvsp[0].member;
+                           cs->last = NULL;
+                           cs->next = NULL;
+                           yyval.cmndspec = cs;
+                       }
+break;
+case 36:
+#line 319 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 37:
+#line 323 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 38:
+#line 329 "gram.y"
+{
+                           yyval.member = NULL;
+                       }
+break;
+case 39:
+#line 332 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                       }
+break;
+case 41:
+#line 338 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 42:
+#line 344 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 43:
+#line 348 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 44:
+#line 354 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, RUNASALIAS);
+                       }
+break;
+case 45:
+#line 357 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, NULL, ALL);
+                       }
+break;
+case 46:
+#line 360 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, NETGROUP);
+                       }
+break;
+case 47:
+#line 363 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, USERGROUP);
+                       }
+break;
+case 48:
+#line 366 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, WORD);
+                       }
+break;
+case 49:
+#line 371 "gram.y"
+{
+                           yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.monitor = UNSPEC;
+                       }
+break;
+case 50:
+#line 374 "gram.y"
+{
+                           yyval.tag.nopasswd = TRUE;
+                       }
+break;
+case 51:
+#line 377 "gram.y"
+{
+                           yyval.tag.nopasswd = FALSE;
+                       }
+break;
+case 52:
+#line 380 "gram.y"
+{
+                           yyval.tag.noexec = TRUE;
+                       }
+break;
+case 53:
+#line 383 "gram.y"
+{
+                           yyval.tag.noexec = FALSE;
+                       }
+break;
+case 54:
+#line 386 "gram.y"
+{
+                           yyval.tag.monitor = TRUE;
+                       }
+break;
+case 55:
+#line 389 "gram.y"
+{
+                           yyval.tag.monitor = FALSE;
+                       }
+break;
+case 56:
+#line 394 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, NULL, ALL);
+                           if (safe_cmnd)
+                               free(safe_cmnd);
+                           safe_cmnd = estrdup(user_cmnd);
+                       }
+break;
+case 57:
+#line 400 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, CMNDALIAS);
+                       }
+break;
+case 58:
+#line 403 "gram.y"
+{
+                           struct sudo_command *c = emalloc(sizeof(*c));
+                           c->cmnd = yyvsp[0].command.cmnd;
+                           c->args = yyvsp[0].command.args;
+                           NEW_MEMBER(yyval.member, (char *)c, COMMAND);
+                       }
+break;
+case 60:
+#line 412 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].alias, yyvsp[0].alias);
+                           yyval.alias = yyvsp[-2].alias;
+                       }
+break;
+case 61:
+#line 418 "gram.y"
+{
+                           NEW_ALIAS(yyval.alias, yyvsp[-2].string, HOSTALIAS, yyvsp[0].member);
+                       }
+break;
+case 63:
+#line 424 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 65:
+#line 431 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].alias, yyvsp[0].alias);
+                           yyval.alias = yyvsp[-2].alias;
+                       }
+break;
+case 66:
+#line 437 "gram.y"
+{
+                           NEW_ALIAS(yyval.alias, yyvsp[-2].string, CMNDALIAS, yyvsp[0].member);
+                       }
+break;
+case 68:
+#line 443 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 70:
+#line 450 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].alias, yyvsp[0].alias);
+                           yyval.alias = yyvsp[-2].alias;
+                       }
+break;
+case 71:
+#line 456 "gram.y"
+{
+                           NEW_ALIAS(yyval.alias, yyvsp[-2].string, RUNASALIAS, yyvsp[0].member);
+                       }
+break;
+case 73:
+#line 462 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].alias, yyvsp[0].alias);
+                           yyval.alias = yyvsp[-2].alias;
+                       }
+break;
+case 74:
+#line 468 "gram.y"
+{
+                           NEW_ALIAS(yyval.alias, yyvsp[-2].string, USERALIAS, yyvsp[0].member);
+                       }
+break;
+case 76:
+#line 474 "gram.y"
+{
+                           LIST_APPEND(yyvsp[-2].member, yyvsp[0].member);
+                           yyval.member = yyvsp[-2].member;
+                       }
+break;
+case 77:
+#line 480 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = FALSE;
+                       }
+break;
+case 78:
+#line 484 "gram.y"
+{
+                           yyval.member = yyvsp[0].member;
+                           yyval.member->negated = TRUE;
+                       }
+break;
+case 79:
+#line 490 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, USERALIAS);
+                       }
+break;
+case 80:
+#line 493 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, NULL, ALL);
+                       }
+break;
+case 81:
+#line 496 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, NETGROUP);
+                       }
+break;
+case 82:
+#line 499 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, USERGROUP);
+                       }
+break;
+case 83:
+#line 502 "gram.y"
+{
+                           NEW_MEMBER(yyval.member, yyvsp[0].string, WORD);
+                       }
+break;
+#line 1333 "gram.c"
+    }
+    yyssp -= yym;
+    yystate = *yyssp;
+    yyvsp -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yyssp = YYFINAL;
+        *++yyvsp = yyval;
+        if (yychar < 0)
+        {
+            if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+            if (yydebug)
+            {
+                yys = 0;
+                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+                if (!yys) yys = "illegal-symbol";
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == 0) goto yyaccept;
+        goto yyloop;
+    }
+    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+    if (yyssp >= yysslim && yygrowstack())
+    {
+        goto yyoverflow;
+    }
+    *++yyssp = yystate;
+    *++yyvsp = yyval;
+    goto yyloop;
+yyoverflow:
+    yyerror("yacc stack overflow");
+yyabort:
+    if (yyss)
+            free(yyss);
+    if (yyvs)
+            free(yyvs);
+    yyss = yyssp = NULL;
+    yyvs = yyvsp = NULL;
+    yystacksize = 0;
+    return (1);
+yyaccept:
+    if (yyss)
+            free(yyss);
+    if (yyvs)
+            free(yyvs);
+    yyss = yyssp = NULL;
+    yyvs = yyvsp = NULL;
+    yystacksize = 0;
+    return (0);
+}
similarity index 80%
rename from sudo.tab.h
rename to gram.h
index e4ade693ffdedab5f417a85061b00348c771a50d..95b3641305f0f1c4ab6ce2928d91925f0cfb84ee 100644 (file)
+++ b/gram.h
 #ifndef YYSTYPE_DEFINED
 #define YYSTYPE_DEFINED
 typedef union {
-    char *string;
-    int BOOLEAN;
+    struct alias *alias;
+    struct cmndspec *cmndspec;
+    struct defaults *defaults;
+    struct member *member;
+    struct privilege *privilege;
     struct sudo_command command;
+    struct cmndtag tag;
+    char *string;
     int tok;
 } YYSTYPE;
 #endif /* YYSTYPE_DEFINED */
diff --git a/gram.y b/gram.y
new file mode 100644 (file)
index 0000000..71005f3
--- /dev/null
+++ b/gram.y
@@ -0,0 +1,674 @@
+%{
+/*
+ * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif /* STDC_HEADERS */
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif /* HAVE_STRING_H */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <pwd.h>
+#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
+# include <malloc.h>
+#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
+#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
+# include <alloca.h>
+#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
+
+#include "sudo.h"
+#include "parse.h"
+
+#ifndef lint
+static const char rcsid[] = "$Sudo$";
+#endif /* lint */
+
+/*
+ * Globals
+ */
+extern int sudolineno;
+extern char *sudoers;
+int parse_error;
+int pedantic = FALSE;
+int verbose = FALSE;
+int errorlineno = -1;
+char *errorfile = NULL;
+
+struct alias *aliases; /* XXX - use RB or binary search tree */
+struct defaults *defaults;
+struct userspec *userspecs;
+
+/*
+ * Local protoypes
+ */
+static void add_alias          __P((struct alias *));
+static void add_defaults       __P((int, struct member *, struct defaults *));
+static void add_userspec       __P((struct member *, struct privilege *));
+       void yyerror            __P((const char *));
+
+void
+yyerror(s)
+    const char *s;
+{
+    /* Save the line the first error occurred on. */
+    if (errorlineno == -1) {
+       errorlineno = sudolineno ? sudolineno - 1 : 0;
+       errorfile = estrdup(sudoers);
+    }
+    if (verbose && s != NULL) {
+#ifndef TRACELEXER
+       (void) fprintf(stderr, ">>> %s: %s near line %d <<<\n", sudoers, s,
+           sudolineno ? sudolineno - 1 : 0);
+#else
+       (void) fprintf(stderr, "<*> ");
+#endif
+    }
+    parse_error = TRUE;
+}
+%}
+
+%union {
+    struct alias *alias;
+    struct cmndspec *cmndspec;
+    struct defaults *defaults;
+    struct member *member;
+    struct privilege *privilege;
+    struct sudo_command command;
+    struct cmndtag tag;
+    char *string;
+    int tok;
+}
+
+%start file                            /* special start symbol */
+%token <command> COMMAND               /* absolute pathname w/ optional args */
+%token <string>  ALIAS                 /* an UPPERCASE alias name */
+%token <string>         DEFVAR                 /* a Defaults variable name */
+%token <string>  NTWKADDR              /* w.x.y.z */
+%token <string>  NETGROUP              /* a netgroup (+NAME) */
+%token <string>  USERGROUP             /* a usergroup (%NAME) */
+%token <string>  WORD                  /* a word */
+%token <tok>    DEFAULTS               /* Defaults entry */
+%token <tok>    DEFAULTS_HOST          /* Host-specific defaults entry */
+%token <tok>    DEFAULTS_USER          /* User-specific defaults entry */
+%token <tok>    DEFAULTS_RUNAS         /* Runas-specific defaults entry */
+%token <tok>    RUNAS                  /* ( runas_list ) */
+%token <tok>    NOPASSWD               /* no passwd req for command */
+%token <tok>    PASSWD                 /* passwd req for command (default) */
+%token <tok>    NOEXEC                 /* preload dummy execve() for cmnd */
+%token <tok>    EXEC                   /* don't preload dummy execve() */
+%token <tok>    MONITOR                /* monitor children of cmnd */
+%token <tok>    NOMONITOR              /* disable monitoring of children */
+%token <tok>    ALL                    /* ALL keyword */
+%token <tok>    COMMENT                /* comment and/or carriage return */
+%token <tok>    HOSTALIAS              /* Host_Alias keyword */
+%token <tok>    CMNDALIAS              /* Cmnd_Alias keyword */
+%token <tok>    USERALIAS              /* User_Alias keyword */
+%token <tok>    RUNASALIAS             /* Runas_Alias keyword */
+%token <tok>    ':' '=' ',' '!' '+' '-' /* union member tokens */
+%token <tok>    ERROR
+
+%type <alias>    cmndalias
+%type <alias>    cmndaliases
+%type <alias>    hostalias
+%type <alias>    hostaliases
+%type <alias>    runasalias
+%type <alias>    runasaliases
+%type <alias>    useralias
+%type <alias>    useraliases
+%type <cmndspec>  cmndspec
+%type <cmndspec>  cmndspeclist
+%type <defaults>  defaults_entry
+%type <defaults>  defaults_list
+%type <member>   cmnd
+%type <member>   opcmnd
+%type <member>   cmndlist
+%type <member>   host
+%type <member>   hostlist
+%type <member>   ophost
+%type <member>   oprunasuser
+%type <member>   opuser
+%type <member>   runaslist
+%type <member>   runasspec
+%type <member>   runasuser
+%type <member>   user
+%type <member>   userlist
+%type <privilege> privilege
+%type <privilege> privileges
+%type <tag>      cmndtag
+
+%%
+
+file           :       { ; }
+               |       line
+               ;
+
+line           :       entry
+               |       line entry
+               ;
+
+entry          :       COMMENT {
+                           ;
+                       }
+                |       error COMMENT {
+                           yyerrok;
+                       }
+               |       userlist privileges {
+                           add_userspec($1, $2);
+                       }
+               |       USERALIAS useraliases {
+                           add_alias($2);
+                       }
+               |       HOSTALIAS hostaliases {
+                           add_alias($2);
+                       }
+               |       CMNDALIAS cmndaliases {
+                           add_alias($2);
+                       }
+               |       RUNASALIAS runasaliases {
+                           add_alias($2);
+                       }
+               |       DEFAULTS defaults_list {
+                           add_defaults(DEFAULTS, NULL, $2);
+                       }
+               |       DEFAULTS_USER userlist defaults_list {
+                           add_defaults(DEFAULTS_USER, $2, $3);
+                       }
+               |       DEFAULTS_RUNAS runaslist defaults_list {
+                           add_defaults(DEFAULTS_RUNAS, $2, $3);
+                       }
+               |       DEFAULTS_HOST hostlist defaults_list {
+                           add_defaults(DEFAULTS_HOST, $2, $3);
+                       }
+               ;
+
+defaults_list  :       defaults_entry
+               |       defaults_list ',' defaults_entry {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+defaults_entry :       DEFVAR {
+                           NEW_DEFAULT($$, $1, NULL, TRUE);
+                       }
+               |       '!' DEFVAR {
+                           NEW_DEFAULT($$, $2, NULL, FALSE);
+                       }
+               |       DEFVAR '=' WORD {
+                           NEW_DEFAULT($$, $1, $3, TRUE);
+                       }
+               |       DEFVAR '+' WORD {
+                           NEW_DEFAULT($$, $1, $3, '+');
+                       }
+               |       DEFVAR '-' WORD {
+                           NEW_DEFAULT($$, $1, $3, '-');
+                       }
+               ;
+
+privileges     :       privilege
+               |       privileges ':' privilege {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+privilege      :       hostlist '=' cmndspeclist {
+                           struct cmndtag tags;
+                           struct privilege *p = emalloc(sizeof(*p));
+                           struct cmndspec *cs;
+                           p->hostlist = $1;
+                           p->cmndlist = $3;
+                           tags.nopasswd = tags.noexec = tags.monitor = UNSPEC;
+                           /* propagate tags */
+                           for (cs = $3; cs != NULL; cs = cs->next) {
+                               if (cs->tags.nopasswd == UNSPEC)
+                                   cs->tags.nopasswd = tags.nopasswd;
+                               if (cs->tags.noexec == UNSPEC)
+                                   cs->tags.noexec = tags.noexec;
+                               if (cs->tags.monitor == UNSPEC)
+                                   cs->tags.monitor = tags.monitor;
+                               memcpy(&tags, &cs->tags, sizeof(tags));
+                           }
+                           p->last = NULL;
+                           p->next = NULL;
+                           $$ = p;
+                       }
+               ;
+
+ophost         :       host {
+                           $$ = $1;
+                           $$->negated = FALSE;
+                       }
+               |       '!' host {
+                           $$ = $2;
+                           $$->negated = TRUE;
+                       }
+               ;
+
+host           :       ALIAS {
+                           NEW_MEMBER($$, $1, HOSTALIAS);
+                       }
+               |       ALL {
+                           NEW_MEMBER($$, NULL, ALL);
+                       }
+               |       NETGROUP {
+                           NEW_MEMBER($$, $1, NETGROUP);
+                       }
+               |       NTWKADDR {
+                           NEW_MEMBER($$, $1, NTWKADDR);
+                       }
+               |       WORD {
+                           NEW_MEMBER($$, $1, WORD);
+                       }
+               ;
+
+cmndspeclist   :       cmndspec
+               |       cmndspeclist ',' cmndspec {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+cmndspec       :       runasspec cmndtag opcmnd {
+                           struct cmndspec *cs = emalloc(sizeof(*cs));
+                           cs->runaslist = $1;
+                           cs->tags = $2;
+                           cs->cmnd = $3;
+                           cs->last = NULL;
+                           cs->next = NULL;
+                           $$ = cs;
+                       }
+               ;
+
+opcmnd         :       cmnd {
+                           $$ = $1;
+                           $$->negated = FALSE;
+                       }
+               |       '!' cmnd {
+                           $$ = $2;
+                           $$->negated = TRUE;
+                       }
+               ;
+
+runasspec      :       /* empty */ {
+                           $$ = NULL;
+                       }
+               |       RUNAS runaslist {
+                           $$ = $2;
+                       }
+               ;
+
+runaslist      :       oprunasuser
+               |       runaslist ',' oprunasuser {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+oprunasuser    :       runasuser {
+                           $$ = $1;
+                           $$->negated = FALSE;
+                       }
+               |       '!' runasuser {
+                           $$ = $2;
+                           $$->negated = TRUE;
+                       }
+               ;
+
+runasuser      :       ALIAS {
+                           NEW_MEMBER($$, $1, RUNASALIAS);
+                       }
+               |       ALL {
+                           NEW_MEMBER($$, NULL, ALL);
+                       }
+               |       NETGROUP {
+                           NEW_MEMBER($$, $1, NETGROUP);
+                       }
+               |       USERGROUP {
+                           NEW_MEMBER($$, $1, USERGROUP);
+                       }
+               |       WORD {
+                           NEW_MEMBER($$, $1, WORD);
+                       }
+               ;
+
+cmndtag                :       /* empty */ {
+                           $$.nopasswd = $$.noexec = $$.monitor = UNSPEC;
+                       }
+               |       cmndtag NOPASSWD {
+                           $$.nopasswd = TRUE;
+                       }
+               |       cmndtag PASSWD {
+                           $$.nopasswd = FALSE;
+                       }
+               |       cmndtag NOEXEC {
+                           $$.noexec = TRUE;
+                       }
+               |       cmndtag EXEC {
+                           $$.noexec = FALSE;
+                       }
+               |       cmndtag MONITOR {
+                           $$.monitor = TRUE;
+                       }
+               |       cmndtag NOMONITOR {
+                           $$.monitor = FALSE;
+                       }
+               ;
+
+cmnd           :       ALL {
+                           NEW_MEMBER($$, NULL, ALL);
+                           if (safe_cmnd)
+                               free(safe_cmnd);
+                           safe_cmnd = estrdup(user_cmnd);
+                       }
+               |       ALIAS {
+                           NEW_MEMBER($$, $1, CMNDALIAS);
+                       }
+               |       COMMAND {
+                           struct sudo_command *c = emalloc(sizeof(*c));
+                           c->cmnd = $1.cmnd;
+                           c->args = $1.args;
+                           NEW_MEMBER($$, (char *)c, COMMAND);
+                       }
+               ;
+
+hostaliases    :       hostalias
+               |       hostaliases ':' hostalias {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+hostalias      :       ALIAS '=' hostlist {
+                           NEW_ALIAS($$, $1, HOSTALIAS, $3);
+                       }
+               ;
+
+hostlist       :       ophost
+               |       hostlist ',' ophost {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+cmndaliases    :       cmndalias
+               |       cmndaliases ':' cmndalias {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+cmndalias      :       ALIAS '=' cmndlist {
+                           NEW_ALIAS($$, $1, CMNDALIAS, $3);
+                       }
+               ;
+
+cmndlist       :       opcmnd
+               |       cmndlist ',' opcmnd {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+runasaliases   :       runasalias
+               |       runasaliases ':' runasalias {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+runasalias     :       ALIAS '=' runaslist {
+                           NEW_ALIAS($$, $1, RUNASALIAS, $3);
+                       }
+               ;
+
+useraliases    :       useralias
+               |       useraliases ':' useralias {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+useralias      :       ALIAS '=' userlist {
+                           NEW_ALIAS($$, $1, USERALIAS, $3);
+                       }
+               ;
+
+userlist       :       opuser
+               |       userlist ',' opuser {
+                           LIST_APPEND($1, $3);
+                           $$ = $1;
+                       }
+               ;
+
+opuser         :       user {
+                           $$ = $1;
+                           $$->negated = FALSE;
+                       }
+               |       '!' user {
+                           $$ = $2;
+                           $$->negated = TRUE;
+                       }
+               ;
+
+user           :       ALIAS {
+                           NEW_MEMBER($$, $1, USERALIAS);
+                       }
+               |       ALL {
+                           NEW_MEMBER($$, NULL, ALL);
+                       }
+               |       NETGROUP {
+                           NEW_MEMBER($$, $1, NETGROUP);
+                       }
+               |       USERGROUP {
+                           NEW_MEMBER($$, $1, USERGROUP);
+                       }
+               |       WORD {
+                           NEW_MEMBER($$, $1, WORD);
+                       }
+               ;
+
+%%
+
+/*
+ * Add a list of aliases to the end of the global aliases list.
+ */
+static void
+add_alias(a)
+    struct alias *a;
+{
+    if (aliases == NULL)
+       aliases = a;
+    else {
+       if (aliases->last != NULL)
+           aliases->last->next = a;
+       else /* if (aliases->next == NULL) */
+           aliases->next = a;
+       aliases->last = a->last ? a->last : a;
+    }
+}
+
+/*
+ * Add a list of defaults structures to the defaults list.
+ * The binding, if non-NULL, specifies a list of hosts, users, or
+ * runas users the entries apply to (specified by the type).
+ */
+static void
+add_defaults(type, binding, defs)
+    int type;
+    struct member *binding;
+    struct defaults *defs;
+{
+    struct defaults *d;
+
+    /*
+     * Set type and binding (who it applies to) for new entries.
+     */
+    for (d = defs; d != NULL; d = d->next) {
+       d->type = type;
+       d->binding = binding;
+    }
+    if (defaults == NULL)
+       defaults = defs;
+    else {
+       if (defaults->last != NULL)
+           defaults->last->next = defs;
+       else /* if (defaults->next == NULL) */
+           defaults->next = defs;
+       defaults->last = defs->last ? defs->last : defs;
+    }
+}
+
+/*
+ * Allocate a new struct userspec, populate it, and insert it at the
+ * and of the userspecs list.
+ */
+static void
+add_userspec(members, privs)
+    struct member *members;
+    struct privilege *privs;
+{
+    struct userspec *u;
+
+    u = emalloc(sizeof(*u));
+    u->user = members;
+    u->privileges = privs;
+    u->last = NULL;
+    u->next = NULL;
+    if (userspecs == NULL)
+       userspecs = u;
+    else {
+       if (userspecs->last != NULL)
+           userspecs->last->next = u;
+       else /* if (userspecs->next == NULL) */
+           userspecs->next = u;
+       userspecs->last = u;
+    }
+}
+
+/*
+ * Free up space used by data structures from a previous parser run and sets
+ * the current sudoers file to path.
+ */
+void
+init_parser(path, quiet)
+    char *path;
+    int quiet;
+{
+    struct alias *a;
+    struct defaults *d;
+    struct member *m, *lastbinding;
+    struct userspec *us;
+    struct privilege *priv;
+    struct cmndspec *cs;
+    VOID *next;
+
+    for (a = aliases ; a != NULL; a = a->next) {
+       for (m = a->first_member; m != NULL; m = next) {
+           next = m->next;
+           if (m->name != NULL)
+               free(m->name);
+           free(m);
+       }
+    }
+    aliases = NULL;
+
+    for (us = userspecs ; us != NULL; us = next) {
+       for (m = us->user; m != NULL; m = next) {
+           next = m->next;
+           if (m->name != NULL)
+               free(m->name);
+           free(m);
+       }
+       for (priv = us->privileges; priv != NULL; priv = next) {
+           for (m = priv->hostlist; m != NULL; m = next) {
+               next = m->next;
+               if (m->name != NULL)
+                   free(m->name);
+               free(m);
+           }
+           for (cs = priv->cmndlist; cs != NULL; cs = next) {
+               for (m = cs->runaslist; m != NULL; m = next) {
+                   next = m->next;
+                   if (m->name != NULL)
+                       free(m->name);
+                   free(m);
+               }
+               if (cs->cmnd->name != NULL)
+                   free(cs->cmnd->name);
+               free(cs->cmnd);
+               next = cs->next;
+               free(cs);
+           }
+           next = priv->next;
+           free(priv);
+       }
+       next = us->next;
+       free(us);
+    }
+    userspecs = NULL;
+
+    lastbinding = NULL;
+    for (d = defaults ; d != NULL; d = next) {
+       if (d->binding != lastbinding) {
+           for (m = d->binding; m != NULL; m = next) {
+               next = m->next;
+               if (m->name != NULL)
+                   free(m->name);
+               free(m);
+           }
+           lastbinding = d->binding;
+       }
+       next = d->next;
+       free(d->var);
+       if (d->val != NULL)
+           free(d->val);
+       free(d);
+    }
+    defaults = NULL;
+
+    if (sudoers != NULL)
+       free(sudoers);
+    sudoers = estrdup(path);
+
+    parse_error = FALSE;
+    errorlineno = -1;
+    sudolineno = 1;
+    verbose = !quiet;
+}
diff --git a/parse.c b/parse.c
index 07145a3f0ced45fa415a9c3aa9c99a72ca501792..50ccd976ec376f4a14f53381d6995a6e00016d4b 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -24,7 +24,6 @@
 
 #include <sys/types.h>
 #include <sys/param.h>
-#include <sys/stat.h>
 #include <stdio.h>
 #ifdef STDC_HEADERS
 # include <stdlib.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif /* HAVE_UNISTD_H */
-#ifdef HAVE_FNMATCH
-# include <fnmatch.h>
-#endif /* HAVE_FNMATCH */
-#ifdef HAVE_EXTENDED_GLOB
-# include <glob.h>
-#endif /* HAVE_EXTENDED_GLOB */
-#ifdef HAVE_NETGROUP_H
-# include <netgroup.h>
-#endif /* HAVE_NETGROUP_H */
 #include <ctype.h>
 #include <pwd.h>
-#include <grp.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#ifdef HAVE_DIRENT_H
-# include <dirent.h>
-# define NAMLEN(dirent) strlen((dirent)->d_name)
-#else
-# define dirent direct
-# define NAMLEN(dirent) (dirent)->d_namlen
-# ifdef HAVE_SYS_NDIR_H
-#  include <sys/ndir.h>
-# endif
-# ifdef HAVE_SYS_DIR_H
-#  include <sys/dir.h>
-# endif
-# ifdef HAVE_NDIR_H
-#  include <ndir.h>
-# endif
-#endif
 
 #include "sudo.h"
 #include "parse.h"
-#include "interfaces.h"
-
-#ifndef HAVE_FNMATCH
-# include "emul/fnmatch.h"
-#endif /* HAVE_FNMATCH */
-#ifndef HAVE_EXTENDED_GLOB
-# include "emul/glob.h"
-#endif /* HAVE_EXTENDED_GLOB */
+#include "gram.h"
 
 #ifndef lint
 static const char rcsid[] = "$Sudo$";
 #endif /* lint */
 
 /*
- * Globals
+ * Parsed sudoers info.
  */
-int parse_error = FALSE;
-extern int keepall;
-extern FILE *yyin, *yyout;
+extern struct userspec *userspecs;
 
 /*
- * Prototypes
+ * Parse the specified sudoers file.
  */
-static int has_meta    __P((char *));
+int
+parse_sudoers(path)
+    const char *path;
+{
+    extern FILE *yyin;
+
+    yyin = open_sudoers(_PATH_SUDOERS, NULL);
+    init_parser(_PATH_SUDOERS, 0);
+    return(yyparse());
+}
 
 /*
- * Look up the user in the sudoers file and check to see if they are
+ * Look up the user in the parsed sudoers file and check to see if they are
  * allowed to run the specified command on this host as the target user.
  */
 int
 sudoers_lookup(pwflag)
     int pwflag;
 {
-    int error, nopass;
-    enum def_tupple pwcheck;
-
-    yyin = sudoers_fp;
-    yyout = stdout;
-
-    /* Allocate space for data structures in the parser. */
-    init_parser(_PATH_SUDOERS);
-
-    /* If pwcheck *could* be "all" or "any", keep more state. */
-    if (pwflag > 0)
-       keepall = TRUE;
-
-    /* Need to be runas user while stat'ing things in the parser. */
-    set_perms(PERM_RUNAS);
-    error = yyparse();
-    if (error || parse_error) {
-       set_perms(PERM_ROOT);
-       return(VALIDATE_ERROR);
-    }
+    int rval, validated, matched;
+    enum def_tupple pwcheck = 0;
+    struct cmndspec *cs;
+    struct cmndtag *tags = NULL;
+    struct privilege *priv;
+    struct userspec *us;
 
     /*
-     * The pw options may have changed during sudoers parse so we
-     * wait until now to set this.
+     * We use pwflag to tell us when a password should be required
+     * for pseudo-commands.  XXX - pass in pwcheck, not pwflag
      */
     if (pwflag)
        pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple;
-    else
-       pwcheck = 0;
 
-    /*
-     * Assume the worst.  If the stack is empty the user was
-     * not mentioned at all.
-     */
-    if (def_authenticate)
-       error = VALIDATE_NOT_OK;
-    else
-       error = VALIDATE_NOT_OK | FLAG_NOPASS;
-    if (pwcheck) {
-       SET(error, FLAG_NO_CHECK);
-    } else {
-       SET(error, FLAG_NO_HOST);
-       if (!top)
-           SET(error, FLAG_NO_USER);
-    }
+    /* Assume the worst.  */
+    validated = VALIDATE_NOT_OK | FLAG_NO_HOST | FLAG_NO_USER;
+    if (pwflag)
+       SET(validated, FLAG_NO_CHECK);
+    else if (!def_authenticate)
+       validated |= FLAG_NOPASS;
 
     /*
      * Only check the actual command if pwflag is not set.
      * It is set for the "validate", "list" and "kill" pseudo-commands.
      * Always check the host and user.
      */
-    nopass = -1;
     if (pwflag) {
-       int found;
-
-       if (pwcheck == always && def_authenticate)
-           nopass = FLAG_CHECK_USER;
-       else if (pwcheck == never || !def_authenticate)
-           nopass = FLAG_NOPASS;
-       found = 0;
-       while (top) {
-           if (host_matches == TRUE) {
-               found = 1;
-               if (pwcheck == any && no_passwd == TRUE)
-                   nopass = FLAG_NOPASS;
-               else if (pwcheck == all && nopass != 0)
-                   nopass = (no_passwd == TRUE) ? FLAG_NOPASS : 0;
-           }
-           top--;
-       }
-       if (found) {
-           set_perms(PERM_ROOT);
-           if (nopass == -1)
-               nopass = 0;
-           return(VALIDATE_OK | nopass);
-       }
-    } else {
-       while (top) {
-           if (host_matches == TRUE) {
-               CLR(error, FLAG_NO_HOST);
-               if (runas_matches == TRUE && cmnd_matches == TRUE) {
-                   /*
-                    * User was granted access to cmnd on host as user.
-                    */
-                   set_perms(PERM_ROOT);
-                   return(VALIDATE_OK |
-                       (no_passwd == TRUE ? FLAG_NOPASS : 0) |
-                       (no_execve == TRUE ? FLAG_NOEXEC : 0) |
-                       (monitor_cmnd == TRUE ? FLAG_MONITOR : 0));
-               } else if ((runas_matches == TRUE && cmnd_matches == FALSE) ||
-                   (runas_matches == FALSE && cmnd_matches == TRUE)) {
-                   /*
-                    * User was explicitly denied access to cmnd on host.
-                    */
-                   set_perms(PERM_ROOT);
-                   return(VALIDATE_NOT_OK |
-                       (no_passwd == TRUE ? FLAG_NOPASS : 0) |
-                       (no_execve == TRUE ? FLAG_NOEXEC : 0) |
-                       (monitor_cmnd == TRUE ? FLAG_MONITOR : 0));
+       int nopass = UNSPEC;
+
+       CLR(validated, FLAG_NO_USER);
+       CLR(validated, FLAG_NO_HOST);
+       matched = FALSE;
+       for (us = userspecs; us != NULL; us = us->next) {
+           if (user_matches(sudo_user.pw, us->user) == TRUE) {
+               priv = us->privileges;
+               if (host_matches(user_shost, user_host, priv->hostlist) == TRUE) {
+                   matched = TRUE;
+                   for (cs = priv->cmndlist; cs != NULL; cs = cs->next) {
+                       if ((pwcheck == any && nopass != TRUE) ||
+                           (pwcheck == all && nopass == TRUE))
+                           nopass = cs->tags.nopasswd;
+                   }
                }
            }
-           top--;
        }
-    }
-    set_perms(PERM_ROOT);
-
-    /*
-     * The user was neither explicitly granted nor denied access.
-     */
-    if (nopass == -1)
-       nopass = 0;
-    return(error | nopass);
-}
-
-/*
- * If path doesn't end in /, return TRUE iff cmnd & path name the same inode;
- * otherwise, return TRUE if user_cmnd names one of the inodes in path.
- */
-int
-command_matches(sudoers_cmnd, sudoers_args)
-    char *sudoers_cmnd;
-    char *sudoers_args;
-{
-    struct stat sudoers_stat;
-    struct dirent *dent;
-    char **ap, *base, buf[PATH_MAX];
-    glob_t gl;
-    DIR *dirp;
-
-    /* Check for pseudo-commands */
-    if (strchr(user_cmnd, '/') == NULL) {
-       /*
-        * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND
-        *  a) there are no args in sudoers OR
-        *  b) there are no args on command line and none req by sudoers OR
-        *  c) there are args in sudoers and on command line and they match
-        */
-       if (strcmp(sudoers_cmnd, "sudoedit") != 0 ||
-           strcmp(user_cmnd, "sudoedit") != 0)
-           return(FALSE);
-       if (!sudoers_args ||
-           (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-           (sudoers_args &&
-            fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
-           if (safe_cmnd)
-               free(safe_cmnd);
-           safe_cmnd = estrdup(sudoers_cmnd);
-           return(TRUE);
-       } else
-           return(FALSE);
-    }
-
-    /*
-     * If sudoers_cmnd has meta characters in it, use fnmatch(3)
-     * to do the matching.
-     */
-    if (has_meta(sudoers_cmnd)) {
-       /*
-        * Return true if we find a match in the glob(3) results 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.
-        *
-        * Could optimize patterns ending in "/*" to "/user_base"
-        */
-#define GLOB_FLAGS     (GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE)
-       if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0) {
-           globfree(&gl);
-           return(FALSE);
-       }
-       /* For each glob match, compare basename, st_dev and st_ino. */
-       for (ap = gl.gl_pathv; *ap != NULL; ap++) {
-           /* only stat if basenames are the same */
-           if ((base = strrchr(*ap, '/')) != NULL)
-               base++;
-           else
-               base = *ap;
-           if (strcmp(user_base, base) != 0 ||
-               stat(*ap, &sudoers_stat) == -1)
-               continue;
-           if (user_stat->st_dev == sudoers_stat.st_dev &&
-               user_stat->st_ino == sudoers_stat.st_ino) {
-               if (safe_cmnd)
-                   free(safe_cmnd);
-               safe_cmnd = estrdup(*ap);
-               break;
-           }
-       }
-       globfree(&gl);
-       if (*ap == NULL)
-           return(FALSE);
-
-       if (!sudoers_args ||
-           (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-           (sudoers_args &&
-            fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
-           if (safe_cmnd)
-               free(safe_cmnd);
-           safe_cmnd = estrdup(user_cmnd);
-           return(TRUE);
-       } else
-           return(FALSE);
-    } else {
-       size_t dlen = strlen(sudoers_cmnd);
-
-       /*
-        * No meta characters
-        * Check to make sure this is not a directory spec (doesn't end in '/')
-        */
-       if (sudoers_cmnd[dlen - 1] != '/') {
-           /* Only proceed if user_base and basename(sudoers_cmnd) match */
-           if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
-               base = sudoers_cmnd;
-           else
-               base++;
-           if (strcmp(user_base, base) != 0 ||
-               stat(sudoers_cmnd, &sudoers_stat) == -1)
-               return(FALSE);
-
-           /*
-            * Return true if inode/device matches AND
-            *  a) there are no args in sudoers OR
-            *  b) there are no args on command line and none req by sudoers OR
-            *  c) there are args in sudoers and on command line and they match
-            */
-           if (user_stat->st_dev != sudoers_stat.st_dev ||
-               user_stat->st_ino != sudoers_stat.st_ino)
-               return(FALSE);
-           if (!sudoers_args ||
-               (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-               (sudoers_args &&
-                fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
-               if (safe_cmnd)
-                   free(safe_cmnd);
-               safe_cmnd = estrdup(sudoers_cmnd);
-               return(TRUE);
-           } else
-               return(FALSE);
+       if (matched == TRUE) {
+           /* User has an entry for this host. */
+           CLR(validated, VALIDATE_NOT_OK);
+           SET(validated, VALIDATE_OK);
+           if (pwcheck == always && def_authenticate)
+               SET(validated, FLAG_CHECK_USER);
+           else if (pwcheck == never || !def_authenticate || nopass == TRUE)
+               SET(validated, FLAG_NOPASS);
        }
+       return(validated);
+    }
 
-       /*
-        * Grot through sudoers_cmnd's directory entries, looking for user_base.
-        */
-       dirp = opendir(sudoers_cmnd);
-       if (dirp == NULL)
-           return(FALSE);
-
-       if (strlcpy(buf, sudoers_cmnd, sizeof(buf)) >= sizeof(buf))
-           return(FALSE);
-       while ((dent = readdir(dirp)) != NULL) {
-           /* ignore paths > PATH_MAX (XXX - log) */
-           buf[dlen] = '\0';
-           if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf))
-               continue;
+    /* Need to be runas user while stat'ing things. */
+    set_perms(PERM_RUNAS);
 
-           /* only stat if basenames are the same */
-           if (strcmp(user_base, dent->d_name) != 0 ||
-               stat(buf, &sudoers_stat) == -1)
-               continue;
-           if (user_stat->st_dev == sudoers_stat.st_dev &&
-               user_stat->st_ino == sudoers_stat.st_ino) {
-               if (safe_cmnd)
-                   free(safe_cmnd);
-               safe_cmnd = estrdup(buf);
-               break;
+    matched = UNSPEC;
+    for (us = userspecs; us != NULL; us = us->next) {
+       if (user_matches(sudo_user.pw, us->user) == TRUE) {
+           CLR(validated, FLAG_NO_USER);
+           priv = us->privileges;
+           if (host_matches(user_shost, user_host, priv->hostlist) == TRUE) {
+               CLR(validated, FLAG_NO_HOST);
+               for (cs = priv->cmndlist; cs != NULL; cs = cs->next) {
+                   if (runas_matches(runas_pw, cs->runaslist) == TRUE) {
+                       rval = cmnd_matches(user_cmnd, user_args, cs->cmnd);
+                       if (rval != UNSPEC) {
+                           matched = rval;
+                           tags = &cs->tags;
+                       }
+                   }
+               }
            }
        }
-
-       closedir(dirp);
-       return(dent != NULL);
     }
-}
-
-/*
- * Returns TRUE if "n" is one of our ip addresses or if
- * "n" is a network that we are on, else returns FALSE.
- */
-int
-addr_matches(n)
-    char *n;
-{
-    int i;
-    char *m;
-    struct in_addr addr, mask;
-
-    /* If there's an explicit netmask, use it. */
-    if ((m = strchr(n, '/'))) {
-       *m++ = '\0';
-       addr.s_addr = inet_addr(n);
-       if (strchr(m, '.'))
-           mask.s_addr = inet_addr(m);
-       else {
-           i = 32 - atoi(m);
-           mask.s_addr = 0xffffffff;
-           mask.s_addr >>= i;
-           mask.s_addr <<= i;
-           mask.s_addr = htonl(mask.s_addr);
+    if (matched == TRUE) {
+       CLR(validated, VALIDATE_NOT_OK);
+       SET(validated, VALIDATE_OK);
+       if (tags != NULL) {
+           if (tags->nopasswd == TRUE)
+               SET(validated, FLAG_NOPASS);
+           if (tags->noexec == TRUE)
+               SET(validated, FLAG_NOEXEC);
+           if (tags->monitor == TRUE)
+               SET(validated, FLAG_MONITOR);
        }
-       *(m - 1) = '/';
-
-       for (i = 0; i < num_interfaces; i++)
-           if ((interfaces[i].addr.s_addr & mask.s_addr) == addr.s_addr)
-               return(TRUE);
-    } else {
-       addr.s_addr = inet_addr(n);
-
-       for (i = 0; i < num_interfaces; i++)
-           if (interfaces[i].addr.s_addr == addr.s_addr ||
-               (interfaces[i].addr.s_addr & interfaces[i].netmask.s_addr)
-               == addr.s_addr)
-               return(TRUE);
-    }
-
-    return(FALSE);
-}
-
-/*
- * Returns 0 if the hostname matches the pattern and non-zero otherwise.
- */
-int
-hostname_matches(shost, lhost, pattern)
-    char *shost;
-    char *lhost;
-    char *pattern;
-{
-    if (has_meta(pattern)) {
-       if (strchr(pattern, '.'))
-           return(fnmatch(pattern, lhost, FNM_CASEFOLD));
-       else
-           return(fnmatch(pattern, shost, FNM_CASEFOLD));
-    } else {
-       if (strchr(pattern, '.'))
-           return(strcasecmp(lhost, pattern));
-       else
-           return(strcasecmp(shost, pattern));
-    }
-}
-
-/*
- *  Returns TRUE if the user/uid from sudoers matches the specified user/uid,
- *  else returns FALSE.
- */
-int
-userpw_matches(sudoers_user, user, pw)
-    char *sudoers_user;
-    char *user;
-    struct passwd *pw;
-{
-    if (pw != NULL && *sudoers_user == '#') {
-       uid_t uid = atoi(sudoers_user + 1);
-       if (uid == pw->pw_uid)
-           return(1);
     }
-    return(strcmp(sudoers_user, user) == 0);
+    set_perms(PERM_ROOT);
+    return(validated);
 }
 
 /*
- *  Returns TRUE if the given user belongs to the named group,
- *  else returns FALSE.
- *  XXX - reduce the number of passwd/group lookups
+ * Print out privileges for the specified user.
  */
-int
-usergr_matches(group, user, pw)
-    char *group;
-    char *user;
+void
+display_privs(pw)
     struct passwd *pw;
 {
-    struct group *grp;
-    gid_t pw_gid;
-    char **cur;
-
-    /* make sure we have a valid usergroup, sudo style */
-    if (*group++ != '%')
-       return(FALSE);
-
-    /* look up user's primary gid in the passwd file */
-    if (pw == NULL && (pw = getpwnam(user)) == NULL)
-       return(FALSE);
-    pw_gid = pw->pw_gid;
-
-    if ((grp = getgrnam(group)) == NULL)
-       return(FALSE);
-
-    /* check against user's primary (passwd file) gid */
-    if (grp->gr_gid == pw_gid)
-       return(TRUE);
-
-    /* check to see if user is explicitly listed in the group */
-    for (cur = grp->gr_mem; *cur; cur++) {
-       if (strcmp(*cur, user) == 0)
-           return(TRUE);
-    }
-
-    return(FALSE);
-}
-
-/*
- * Returns TRUE if "host" and "user" belong to the netgroup "netgr",
- * else return FALSE.  Either of "host", "shost" or "user" may be NULL
- * in which case that argument is not checked...
- */
-int
-netgr_matches(netgr, host, shost, user)
-    char *netgr;
-    char *host;
-    char *shost;
-    char *user;
-{
-#ifdef HAVE_GETDOMAINNAME
-    static char *domain = (char *) -1;
-#else
-    static char *domain = NULL;
-#endif /* HAVE_GETDOMAINNAME */
-
-    /* make sure we have a valid netgroup, sudo style */
-    if (*netgr++ != '+')
-       return(FALSE);
-
-#ifdef HAVE_GETDOMAINNAME
-    /* get the domain name (if any) */
-    if (domain == (char *) -1) {
-       domain = (char *) emalloc(MAXHOSTNAMELEN);
-       if (getdomainname(domain, MAXHOSTNAMELEN) == -1 || *domain == '\0') {
-           free(domain);
-           domain = NULL;
+    struct cmndspec *cs;
+    struct member *m, *runas;
+    struct privilege *priv;
+    struct userspec *us;
+
+    printf("User %s may run the following commands on this host:\n",
+       pw->pw_name);
+
+    for (us = userspecs; us != NULL; us = us->next) {
+       if (user_matches(pw, us->user) != TRUE ||
+         host_matches(user_shost, user_host, us->privileges->hostlist) != TRUE)
+           continue;
+
+       priv = us->privileges;
+       runas = NULL;
+       for (cs = priv->cmndlist; cs != NULL; cs = cs->next) {
+           fputs("    ", stdout);
+           if (cs->runaslist != NULL)
+               runas = cs->runaslist;
+           if (runas != NULL) {
+               fputs("(", stdout);
+               for (m = runas; m != NULL; m = m->next) {
+                   if (m != runas)
+                       fputs(", ", stdout);
+                   print_member(m);
+               }
+               fputs(") ", stdout);
+           }
+           if (cs->tags.monitor != UNSPEC && cs->tags.monitor != def_monitor)
+               printf("%sMONITOR: ", cs->tags.monitor ? "" : "NO");
+           if (cs->tags.noexec != UNSPEC && cs->tags.noexec != def_noexec)
+               printf("%sEXEC: ", cs->tags.noexec ? "NO" : "");
+           if (cs->tags.nopasswd != UNSPEC && cs->tags.nopasswd != !def_authenticate)
+               printf("%sPASSWD: ", cs->tags.nopasswd ? "NO" : "");
+           print_member(cs->cmnd);
+           putchar('\n');
        }
     }
-#endif /* HAVE_GETDOMAINNAME */
-
-#ifdef HAVE_INNETGR
-    if (innetgr(netgr, host, user, domain))
-       return(TRUE);
-    else if (host != shost && innetgr(netgr, shost, user, domain))
-       return(TRUE);
-#endif /* HAVE_INNETGR */
-
-    return(FALSE);
 }
 
 /*
- * Returns TRUE if "s" has shell meta characters in it,
- * else returns FALSE.
+ * Print the contents of a struct member to stdout
  */
-static int
-has_meta(s)
-    char *s;
+void
+print_member(m)
+    struct member *m;
 {
-    char *t;
-    for (t = s; *t; t++) {
-       if (*t == '\\' || *t == '?' || *t == '*' || *t == '[' || *t == ']')
-           return(TRUE);
+    struct sudo_command *c;
+
+    if (m->negated)
+       printf("!");
+    if (m->name == NULL)
+       printf("ALL");
+    else if (m->type != COMMAND)
+       printf("%s", m->name);
+    else {
+       c = (struct sudo_command *) m->name;
+       printf("%s%s%s", c->cmnd, c->args ? " " : "",
+           c->args ? c->args : "");
     }
-    return(FALSE);
 }
diff --git a/parse.h b/parse.h
index c5ad4e0a7e60cc64ab054320f54b59c936dc9b7c..6a5df80f6328972ff1a077e51c5ba709774bf3c8 100644 (file)
--- a/parse.h
+++ b/parse.h
 #ifndef _SUDO_PARSE_H
 #define _SUDO_PARSE_H
 
-/*
- * Data structure used in parsing sudoers;
- * top of stack values are the ones that
- * apply when parsing is done & can be
- * accessed by *_matches macros
- */
-#define STACKINCREMENT (32)
-struct matchstack {
-       int user;
-       int cmnd;
-       int host;
-       int runas;
-       int nopass;
-       int noexec;
-       int monitor;
-};
+#undef ALLOW
+#define ALLOW  1
+#undef DENY
+#define DENY   0
+#undef UNSPEC
+#define UNSPEC -1
+/* XXX - use NOTFOUND instead? */
 
 /*
- * Data structure describing a command in the
- * sudoers file.
+ * A command with args. XXX - merge into struct member.
  */
 struct sudo_command {
     char *cmnd;
     char *args;
 };
 
-#define user_matches   (match[top-1].user)
-#define cmnd_matches   (match[top-1].cmnd)
-#define host_matches   (match[top-1].host)
-#define runas_matches  (match[top-1].runas)
-#define no_passwd      (match[top-1].nopass)
-#define no_execve      (match[top-1].noexec)
-#define monitor_cmnd   (match[top-1].monitor)
+/*
+ * Tags associated with a command.
+ * Possible valus: TRUE, FALSE, UNSPEC.
+ */
+struct cmndtag {
+    char nopasswd;
+    char noexec;
+    char monitor;
+    char extra;
+};
 
 /*
- * Structure containing command matches if "sudo -l" is used.
+ * The parses sudoers file is stored as a collection of linked lists,
+ * modelled after the yacc grammar.
+ *
+ * There is no separate head struct, the first entry acts as the list head.
+ * Because of this, the "last" field is only valid in the first entry.
+ * The lack of a separate list head structure allows us to avoid keeping
+ * static state in the parser and makes it easy to append sublists.
  */
-struct command_match {
-    char *runas;
-    size_t runas_len;
-    size_t runas_size;
-    char *cmnd;
-    size_t cmnd_len;
-    size_t cmnd_size;
-    int nopasswd;
-    int noexecve;
-    int monitor;
+
+/*
+ * Structure describing a user specification and list thereof.
+ */
+struct userspec {
+    struct member *user;               /* list of users */
+    struct privilege *privileges;      /* list of privileges */
+    struct userspec *last, *next;
 };
 
 /*
- * Structure describing an alias match in parser.
+ * Structure describing a privilege specification.
  */
-typedef struct {
-    int type;
-    char *name;
-    int val;
-} aliasinfo;
+struct privilege {
+    struct member *hostlist;           /* list of hosts */
+    struct cmndspec *cmndlist;         /* list of Cmnd_Specs */
+    struct privilege *last, *next;
+};
 
 /*
- * Structure containing Cmnd_Alias's if "sudo -l" is used.
+ * Structure describing a linked list of Cmnd_Specs.
  */
-struct generic_alias {
-    int type;
-    char *alias;
-    char *entries;
-    size_t entries_size;
-    size_t entries_len;
+struct cmndspec {
+    struct member *runaslist;          /* list of runas users */
+    struct member *cmnd;               /* command to allow/deny */
+    struct cmndtag tags;               /* tag specificaion */
+    struct cmndspec *last, *next;
 };
 
-/* The matching stack and number of entries on it. */
-extern struct matchstack *match;
-extern int top;
+/*
+ * Generic structure to hold users, hosts, commands.
+ */
+struct member {
+    char *name;                                /* member name */
+    short type;                                /* type (see gram.h) */
+    short negated;                     /* negated via '!'? */
+    struct member *last, *next;
+};
+
+/*
+ * Generic structure to hold {User,Host,Runas,Cmnd}_Alias
+ */
+struct alias {
+    char *name;                                /* alias name */
+    int type;                          /* {USER,HOST,RUNAS,CMND}ALIAS */
+    struct member *first_member;       /* list of alias members */
+    struct alias *last, *next;
+};
+
+/*
+ * Structure describing a Defaults entry and a list thereof.
+ */
+struct defaults {
+    char *var;                         /* variable name */
+    char *val;                         /* variable value */
+    struct member *binding;            /* user/host/runas binding */
+    int type;                          /* DEFAULTS{,_USER,_RUNAS,_HOST} */
+    int op;                            /* TRUE, FALSE, '+', '-' */
+    struct defaults *last, *next;
+};
+
+/*
+ * Allocat space for a struct alias and populate it.
+ */
+#define NEW_ALIAS(r, n, t, m) do {                     \
+    (r)               = emalloc(sizeof(struct alias)); \
+    (r)->name         = (n);                           \
+    (r)->type         = (t);                           \
+    (r)->first_member = (m);                           \
+    (r)->last         = NULL;                          \
+    (r)->next         = NULL;                          \
+} while (0)
+
+/*
+ * Allocat space for a defaults entry and populate it.
+ */
+#define NEW_DEFAULT(r, v1, v2, o) do {                 \
+    (r)       = emalloc(sizeof(struct defaults));      \
+    (r)->var  = (v1);                                  \
+    (r)->val  = (v2);                                  \
+    (r)->op   = (o);                                   \
+    (r)->last = NULL;                                  \
+    (r)->next = NULL;                                  \
+} while (0)
+
+/*
+ * Allocat space for a member and populate it.
+ */
+#define NEW_MEMBER(r, n, t) do {                       \
+    (r)       = emalloc(sizeof(struct member));                \
+    (r)->name = (n);                                   \
+    (r)->type = (t);                                   \
+    (r)->last = NULL;                                  \
+    (r)->next = NULL;                                  \
+} while (0)
+
+/*
+ * Append an entry to the tail of a list.
+ */
+#define LIST_APPEND(h, e) do {                         \
+    if ((h)->last != NULL)                             \
+       (h)->last->next = (e);                          \
+    else /* if ((h)->next == NULL) */                  \
+       (h)->next = (e);                                \
+    (h)->last = (e);                                   \
+} while (0)
 
 /*
  * Prototypes
  */
 int addr_matches       __P((char *));
+int alias_matches      __P((char *, int, VOID *, VOID *));
+int cmnd_matches       __P((char *, char *, struct member *));
 int command_matches    __P((char *, char *));
+int host_matches       __P((char *, char *, struct member *));
 int hostname_matches   __P((char *, char *, char *));
 int netgr_matches      __P((char *, char *, char *, char *));
-int userpw_matches     __P((char *, char *, struct passwd *));
+int runas_matches      __P((struct passwd *, struct member *));
+int user_matches       __P((struct passwd *, struct member *));
 int usergr_matches     __P((char *, char *, struct passwd *));
-void init_parser       __P((char *));
+int userpw_matches     __P((char *, char *, struct passwd *));
+void init_parser       __P((char *, int));
+void print_member      __P((struct member *m));
 
 #endif /* _SUDO_PARSE_H */
diff --git a/parse.yacc b/parse.yacc
deleted file mode 100644 (file)
index fe465d0..0000000
+++ /dev/null
@@ -1,1285 +0,0 @@
-%{
-/*
- * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-
-/*
- * XXX - the whole opFOO naming thing is somewhat bogus.
- *
- * XXX - the way things are stored for printmatches is stupid,
- *       they should be stored as elements in an array and then
- *       list_matches() can format things the way it wants.
- */
-
-#include "config.h"
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-#  include <strings.h>
-# endif
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
-# include <malloc.h>
-#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
-#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
-# include <alloca.h>
-#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
-#ifdef HAVE_LSEARCH
-# include <search.h>
-#endif /* HAVE_LSEARCH */
-
-#include "sudo.h"
-#include "parse.h"
-
-#ifndef HAVE_LSEARCH
-#include "emul/search.h"
-#endif /* HAVE_LSEARCH */
-
-#ifndef lint
-static const char rcsid[] = "$Sudo$";
-#endif /* lint */
-
-/*
- * Globals
- */
-extern int sudolineno, parse_error;
-extern char *sudoers;
-int clearaliases = TRUE;
-int printmatches = FALSE;
-int pedantic = FALSE;
-int keepall = FALSE;
-int quiet = FALSE;
-int used_runas = FALSE;
-int errorlineno = -1;
-char *errorfile = NULL;
-
-/*
- * Alias types
- */
-#define HOST_ALIAS              1
-#define CMND_ALIAS              2
-#define USER_ALIAS              3
-#define RUNAS_ALIAS             4
-
-#define SETMATCH(_var, _val)   do { \
-       if ((_var) == UNSPEC || (_val) != NOMATCH) \
-           (_var) = (_val); \
-} while (0)
-
-#define SETNMATCH(_var, _val)  do { \
-       if ((_val) != NOMATCH) \
-           (_var) = ! (_val); \
-       else if ((_var) == UNSPEC) \
-           (_var) = NOMATCH; \
-} while (0)
-
-/*
- * The matching stack, initial space allocated in init_parser().
- */
-struct matchstack *match;
-int top = 0, stacksize = 0;
-
-#define push \
-    do { \
-       if (top >= stacksize) { \
-           while ((stacksize += STACKINCREMENT) < top); \
-           match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
-       } \
-       match[top].user   = UNSPEC; \
-       match[top].cmnd   = UNSPEC; \
-       match[top].host   = UNSPEC; \
-       match[top].runas  = UNSPEC; \
-       match[top].nopass = def_authenticate ? UNSPEC : TRUE; \
-       match[top].noexec = def_noexec ? TRUE : UNSPEC; \
-       match[top].monitor  = def_monitor ? TRUE : UNSPEC; \
-       top++; \
-    } while (0)
-
-#define pushcp \
-    do { \
-       if (top >= stacksize) { \
-           while ((stacksize += STACKINCREMENT) < top); \
-           match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
-       } \
-       match[top].user     = match[top-1].user; \
-       match[top].cmnd     = match[top-1].cmnd; \
-       match[top].host     = match[top-1].host; \
-       match[top].runas    = match[top-1].runas; \
-       match[top].nopass   = match[top-1].nopass; \
-       match[top].noexec   = match[top-1].noexec; \
-       match[top].monitor  = match[top-1].monitor; \
-       top++; \
-    } while (0)
-
-#define pop \
-    do { \
-       if (top == 0) \
-           yyerror("matching stack underflow"); \
-       else \
-           top--; \
-    } while (0)
-
-
-/*
- * For testing if foo_matches variable was set to TRUE or FALSE
- */
-#define        MATCHED(_v)     ((_v) >= 0)
-
-/*
- * Shortcuts for append()
- */
-#define append_cmnd(s, p) append(s, &cm_list[cm_list_len].cmnd, \
-       &cm_list[cm_list_len].cmnd_len, &cm_list[cm_list_len].cmnd_size, p)
-
-#define append_runas(s, p) append(s, &cm_list[cm_list_len].runas, \
-       &cm_list[cm_list_len].runas_len, &cm_list[cm_list_len].runas_size, p)
-
-#define append_entries(s, p) append(s, &ga_list[ga_list_len-1].entries, \
-       &ga_list[ga_list_len-1].entries_len, \
-       &ga_list[ga_list_len-1].entries_size, p)
-
-/*
- * The stack for printmatches.  A list of allowed commands for the user.
- */
-static struct command_match *cm_list = NULL;
-static size_t cm_list_len = 0, cm_list_size = 0;
-
-/*
- * List of Cmnd_Aliases and expansions for `sudo -l'
- */
-static int in_alias = FALSE;
-static size_t ga_list_len = 0, ga_list_size = 0;
-static struct generic_alias *ga_list = NULL;
-
-/*
- * Does this Defaults list pertain to this user?
- */
-static int defaults_matches = FALSE;
-
-/*
- * Local protoypes
- */
-static int  add_alias          __P((char *, int, int));
-static void append             __P((char *, char **, size_t *, size_t *, char *));
-static void expand_ga_list     __P((void));
-static void expand_match_list  __P((void));
-static aliasinfo *find_alias   __P((char *, int));
-static int  more_aliases       __P((void));
-       void yyerror            __P((const char *));
-
-void
-yyerror(s)
-    const char *s;
-{
-    /* Save the line the first error occurred on. */
-    if (errorlineno == -1) {
-       errorlineno = sudolineno ? sudolineno - 1 : 0;
-       errorfile = estrdup(sudoers);
-    }
-    if (s && !quiet) {
-#ifndef TRACELEXER
-       (void) fprintf(stderr, ">>> %s: %s, line %d <<<\n", sudoers, s,
-           sudolineno ? sudolineno - 1 : 0);
-#else
-       (void) fprintf(stderr, "<*> ");
-#endif
-    }
-    parse_error = TRUE;
-}
-%}
-
-%union {
-    char *string;
-    int BOOLEAN;
-    struct sudo_command command;
-    int tok;
-}
-
-%start file                            /* special start symbol */
-%token <command> COMMAND               /* absolute pathname w/ optional args */
-%token <string>  ALIAS                 /* an UPPERCASE alias name */
-%token <string>         DEFVAR                 /* a Defaults variable name */
-%token <string>  NTWKADDR              /* w.x.y.z */
-%token <string>  NETGROUP              /* a netgroup (+NAME) */
-%token <string>  USERGROUP             /* a usergroup (%NAME) */
-%token <string>  WORD                  /* a word */
-%token <tok>    DEFAULTS               /* Defaults entry */
-%token <tok>    DEFAULTS_HOST          /* Host-specific defaults entry */
-%token <tok>    DEFAULTS_USER          /* User-specific defaults entry */
-%token <tok>    DEFAULTS_RUNAS         /* Runas-specific defaults entry */
-%token <tok>    RUNAS                  /* ( runas_list ) */
-%token <tok>    NOPASSWD               /* no passwd req for command */
-%token <tok>    PASSWD                 /* passwd req for command (default) */
-%token <tok>    NOEXEC                 /* preload dummy execve() for cmnd */
-%token <tok>    EXEC                   /* don't preload dummy execve() */
-%token <tok>    MONITOR                /* monitor children of cmnd */
-%token <tok>    NOMONITOR              /* disable monitoring of children */
-%token <tok>    ALL                    /* ALL keyword */
-%token <tok>    COMMENT                /* comment and/or carriage return */
-%token <tok>    HOSTALIAS              /* Host_Alias keyword */
-%token <tok>    CMNDALIAS              /* Cmnd_Alias keyword */
-%token <tok>    USERALIAS              /* User_Alias keyword */
-%token <tok>    RUNASALIAS             /* Runas_Alias keyword */
-%token <tok>    ':' '=' ',' '!' '+' '-' /* union member tokens */
-%token <tok>    ERROR
-
-/*
- * NOTE: these are not true booleans as there are actually 4 possible values:
- *        1) TRUE (positive match)
- *        0) FALSE (negative match due to a '!' somewhere)
- *       -1) NOMATCH (don't change the value of *_matches)
- *       -2) UNSPEC (uninitialized value)
- */
-%type <BOOLEAN>         cmnd
-%type <BOOLEAN>         host
-%type <BOOLEAN>         runasuser
-%type <BOOLEAN>         oprunasuser
-%type <BOOLEAN>         runaslist
-%type <BOOLEAN>         user
-
-%%
-
-file           :       { ; }
-               |       line
-               ;
-
-line           :       entry
-               |       line entry
-               ;
-
-entry          :       COMMENT
-                           { ; }
-                |       error COMMENT
-                           { yyerrok; }
-               |       { push; } userlist privileges {
-                           while (top && user_matches != TRUE)
-                               pop;
-                       }
-               |       USERALIAS useraliases
-                           { ; }
-               |       HOSTALIAS hostaliases
-                           { ; }
-               |       CMNDALIAS cmndaliases
-                           { ; }
-               |       RUNASALIAS runasaliases
-                           { ; }
-               |       defaults_line
-                           { ; }
-               ;
-
-defaults_line  :       defaults_type defaults_list
-               ;
-
-defaults_type  :       DEFAULTS {
-                           defaults_matches = TRUE;
-                       }
-               |       DEFAULTS_USER { push; } userlist {
-                           defaults_matches = user_matches;
-                           pop;
-                       }
-               |       DEFAULTS_RUNAS { push; } runaslist {
-                           defaults_matches = $3 == TRUE;
-                           pop;
-                       }
-               |       DEFAULTS_HOST { push; } hostlist {
-                           defaults_matches = host_matches;
-                           pop;
-                       }
-               ;
-
-defaults_list  :       defaults_entry
-               |       defaults_entry ',' defaults_list
-               ;
-
-defaults_entry :       DEFVAR {
-                           if (defaults_matches == TRUE &&
-                               !set_default($1, NULL, TRUE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free($1);
-                       }
-               |       '!' DEFVAR {
-                           if (defaults_matches == TRUE &&
-                               !set_default($2, NULL, FALSE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free($2);
-                       }
-               |       DEFVAR '=' WORD {
-                           if (defaults_matches == TRUE &&
-                               !set_default($1, $3, TRUE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free($1);
-                           free($3);
-                       }
-               |       DEFVAR '+' WORD {
-                           if (defaults_matches == TRUE &&
-                               !set_default($1, $3, '+')) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free($1);
-                           free($3);
-                       }
-               |       DEFVAR '-' WORD {
-                           if (defaults_matches == TRUE &&
-                               !set_default($1, $3, '-')) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free($1);
-                           free($3);
-                       }
-               ;
-
-privileges     :       privilege
-               |       privileges ':' privilege
-               ;
-
-privilege      :       hostlist '=' cmndspeclist {
-                           /*
-                            * We already did a push if necessary in
-                            * cmndspec so just reset some values so
-                            * the next 'privilege' gets a clean slate.
-                            */
-                           host_matches = UNSPEC;
-                           runas_matches = UNSPEC;
-                           no_passwd = def_authenticate ? UNSPEC : TRUE;
-                           no_execve = def_noexec ? TRUE : UNSPEC;
-                           monitor_cmnd = def_monitor ? TRUE : UNSPEC;
-                       }
-               ;
-
-ophost         :       host {
-                           SETMATCH(host_matches, $1);
-                       }
-               |       '!' host {
-                           SETNMATCH(host_matches, $2);
-                       }
-               ;
-
-host           :       ALL {
-                           $$ = TRUE;
-                       }
-               |       NTWKADDR {
-                           if (addr_matches($1))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           free($1);
-                       }
-               |       NETGROUP {
-                           if (netgr_matches($1, user_host, user_shost, NULL))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           free($1);
-                       }
-               |       WORD {
-                           if (hostname_matches(user_shost, user_host, $1) == 0)
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           free($1);
-                       }
-               |       ALIAS {
-                           aliasinfo *aip = find_alias($1, HOST_ALIAS);
-
-                           /* could be an all-caps hostname */
-                           if (aip)
-                               $$ = aip->val;
-                           else if (strcasecmp(user_shost, $1) == 0)
-                               $$ = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Host_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               $$ = NOMATCH;
-                           }
-                           free($1);
-                       }
-               ;
-
-cmndspeclist   :       cmndspec
-               |       cmndspeclist ',' cmndspec
-               ;
-
-cmndspec       :       runasspec cmndtag opcmnd {
-                           /*
-                            * Push the entry onto the stack if it is worth
-                            * saving and reset cmnd_matches for next cmnd.
-                            *
-                            * We need to save at least one entry on
-                            * the stack so sudoers_lookup() can tell that
-                            * the user was listed in sudoers.  Also, we
-                            * need to be able to tell whether or not a
-                            * user was listed for this specific host.
-                            *
-                            * If keepall is set and the user matches then
-                            * we need to keep entries around too...
-                            */
-                           if (MATCHED(user_matches) &&
-                               MATCHED(host_matches) &&
-                               MATCHED(cmnd_matches) &&
-                               MATCHED(runas_matches))
-                               pushcp;
-                           else if (MATCHED(user_matches) && (top == 1 ||
-                               (top == 2 && MATCHED(host_matches) &&
-                               !MATCHED(match[0].host))))
-                               pushcp;
-                           else if (user_matches == TRUE && keepall)
-                               pushcp;
-                           cmnd_matches = UNSPEC;
-                       }
-               ;
-
-opcmnd         :       cmnd {
-                           SETMATCH(cmnd_matches, $1);
-                       }
-               |       '!' {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("!", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_cmnd("!", NULL);
-                           }
-                       } cmnd {
-                           SETNMATCH(cmnd_matches, $3);
-                       }
-               ;
-
-runasspec      :       /* empty */ {
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE) {
-                               if (runas_matches == UNSPEC) {
-                                   cm_list[cm_list_len].runas_len = 0;
-                               } else {
-                                   /* Inherit runas data. */
-                                   cm_list[cm_list_len].runas =
-                                       estrdup(cm_list[cm_list_len-1].runas);
-                                   cm_list[cm_list_len].runas_len =
-                                       cm_list[cm_list_len-1].runas_len;
-                                   cm_list[cm_list_len].runas_size =
-                                       cm_list[cm_list_len-1].runas_size;
-                               }
-                           }
-                           /*
-                            * If this is the first entry in a command list
-                            * then check against default runas user.
-                            */
-                           if (runas_matches == UNSPEC) {
-                               runas_matches =
-                                   userpw_matches(def_runas_default,
-                                       *user_runas, runas_pw);
-                           }
-                       }
-               |       RUNAS runaslist {
-                           runas_matches = $2;
-                       }
-               ;
-
-runaslist      :       oprunasuser { ; }
-               |       runaslist ',' oprunasuser {
-                           /* Later entries override earlier ones. */
-                           if ($3 != NOMATCH)
-                               $$ = $3;
-                           else
-                               $$ = $1;
-                       }
-               ;
-
-oprunasuser    :       runasuser { ; }
-               |       '!' {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("!", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas("!", ", ");
-                           }
-                       } runasuser {
-                           /* Set $$ to the negation of runasuser */
-                           $$ = ($3 == NOMATCH ? NOMATCH : ! $3);
-                       }
-               ;
-
-runasuser      :       WORD {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries($1, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas($1, ", ");
-                           }
-                           if (userpw_matches($1, *user_runas, runas_pw))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           free($1);
-                           used_runas = TRUE;
-                       }
-               |       USERGROUP {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries($1, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas($1, ", ");
-                           }
-                           if (usergr_matches($1, *user_runas, runas_pw))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           free($1);
-                           used_runas = TRUE;
-                       }
-               |       NETGROUP {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries($1, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas($1, ", ");
-                           }
-                           if (netgr_matches($1, NULL, NULL, *user_runas))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           free($1);
-                           used_runas = TRUE;
-                       }
-               |       ALIAS {
-                           aliasinfo *aip = find_alias($1, RUNAS_ALIAS);
-
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries($1, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas($1, ", ");
-                           }
-                           /* could be an all-caps username */
-                           if (aip)
-                               $$ = aip->val;
-                           else if (strcmp($1, *user_runas) == 0)
-                               $$ = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Runas_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               $$ = NOMATCH;
-                           }
-                           free($1);
-                           used_runas = TRUE;
-                       }
-               |       ALL {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("ALL", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas("ALL", ", ");
-                           }
-                           $$ = TRUE;
-                       }
-               ;
-
-cmndtag                :       /* empty */ {
-                           /* Inherit tags. */
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE) {
-                               if (no_passwd == TRUE)
-                                   cm_list[cm_list_len].nopasswd = TRUE;
-                               else
-                                   cm_list[cm_list_len].nopasswd = FALSE;
-                               if (no_execve == TRUE)
-                                   cm_list[cm_list_len].noexecve = TRUE;
-                               else
-                                   cm_list[cm_list_len].noexecve = FALSE;
-                               if (monitor_cmnd == TRUE)
-                                   cm_list[cm_list_len].monitor = TRUE;
-                               else
-                                   cm_list[cm_list_len].monitor = FALSE;
-                           }
-                       }
-               |       cmndtag NOPASSWD {
-                           no_passwd = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].nopasswd = TRUE;
-                       }
-               |       cmndtag PASSWD {
-                           no_passwd = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].nopasswd = FALSE;
-                       }
-               |       cmndtag NOEXEC {
-                           no_execve = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].noexecve = TRUE;
-                       }
-               |       cmndtag EXEC {
-                           no_execve = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].noexecve = FALSE;
-                       }
-               |       cmndtag MONITOR {
-                           monitor_cmnd = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].monitor = TRUE;
-                       }
-               |       cmndtag NOMONITOR {
-                           monitor_cmnd = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].monitor = FALSE;
-                       }
-               ;
-
-cmnd           :       ALL {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("ALL", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE) {
-                                   append_cmnd("ALL", NULL);
-                                   expand_match_list();
-                               }
-                           }
-
-                           $$ = TRUE;
-
-                           if (safe_cmnd)
-                               free(safe_cmnd);
-                           safe_cmnd = estrdup(user_cmnd);
-                       }
-               |       ALIAS {
-                           aliasinfo *aip;
-
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries($1, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE) {
-                                   append_cmnd($1, NULL);
-                                   expand_match_list();
-                               }
-                           }
-
-                           if ((aip = find_alias($1, CMND_ALIAS)))
-                               $$ = aip->val;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Cmnd_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               $$ = NOMATCH;
-                           }
-                           free($1);
-                       }
-               |        COMMAND {
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE) {
-                                   append_entries($1.cmnd, ", ");
-                                   if ($1.args)
-                                       append_entries($1.args, " ");
-                               }
-                               if (host_matches == TRUE &&
-                                   user_matches == TRUE)  {
-                                   append_cmnd($1.cmnd, NULL);
-                                   if ($1.args)
-                                       append_cmnd($1.args, " ");
-                                   expand_match_list();
-                               }
-                           }
-
-                           if (command_matches($1.cmnd, $1.args))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-
-                           free($1.cmnd);
-                           if ($1.args)
-                               free($1.args);
-                       }
-               ;
-
-hostaliases    :       hostalias
-               |       hostaliases ':' hostalias
-               ;
-
-hostalias      :       ALIAS { push; } '=' hostlist {
-                           if ((MATCHED(host_matches) || pedantic) &&
-                               !add_alias($1, HOST_ALIAS, host_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                       }
-               ;
-
-hostlist       :       ophost
-               |       hostlist ',' ophost
-               ;
-
-cmndaliases    :       cmndalias
-               |       cmndaliases ':' cmndalias
-               ;
-
-cmndalias      :       ALIAS {
-                           push;
-                           if (printmatches == TRUE) {
-                               in_alias = TRUE;
-                               /* Allocate space for ga_list if necessary. */
-                               expand_ga_list();
-                               ga_list[ga_list_len-1].type = CMND_ALIAS;
-                               ga_list[ga_list_len-1].alias = estrdup($1);
-                            }
-                       } '=' cmndlist {
-                           if ((MATCHED(cmnd_matches) || pedantic) &&
-                               !add_alias($1, CMND_ALIAS, cmnd_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                           free($1);
-
-                           if (printmatches == TRUE)
-                               in_alias = FALSE;
-                       }
-               ;
-
-cmndlist       :       opcmnd { ; }
-               |       cmndlist ',' opcmnd
-               ;
-
-runasaliases   :       runasalias
-               |       runasaliases ':' runasalias
-               ;
-
-runasalias     :       ALIAS {
-                           if (printmatches == TRUE) {
-                               in_alias = TRUE;
-                               /* Allocate space for ga_list if necessary. */
-                               expand_ga_list();
-                               ga_list[ga_list_len-1].type = RUNAS_ALIAS;
-                               ga_list[ga_list_len-1].alias = estrdup($1);
-                           }
-                       } '=' runaslist {
-                           if (($4 != NOMATCH || pedantic) &&
-                               !add_alias($1, RUNAS_ALIAS, $4)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free($1);
-
-                           if (printmatches == TRUE)
-                               in_alias = FALSE;
-                       }
-               ;
-
-useraliases    :       useralias
-               |       useraliases ':' useralias
-               ;
-
-useralias      :       ALIAS { push; } '=' userlist {
-                           if ((MATCHED(user_matches) || pedantic) &&
-                               !add_alias($1, USER_ALIAS, user_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                           free($1);
-                       }
-               ;
-
-userlist       :       opuser
-               |       userlist ',' opuser
-               ;
-
-opuser         :       user {
-                           SETMATCH(user_matches, $1);
-                       }
-               |       '!' user {
-                           SETNMATCH(user_matches, $2);
-                       }
-               ;
-
-user           :       WORD {
-                           if (userpw_matches($1, user_name, sudo_user.pw))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           free($1);
-                       }
-               |       USERGROUP {
-                           if (usergr_matches($1, user_name, sudo_user.pw))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           free($1);
-                       }
-               |       NETGROUP {
-                           if (netgr_matches($1, NULL, NULL, user_name))
-                               $$ = TRUE;
-                           else
-                               $$ = NOMATCH;
-                           free($1);
-                       }
-               |       ALIAS {
-                           aliasinfo *aip = find_alias($1, USER_ALIAS);
-
-                           /* could be an all-caps username */
-                           if (aip)
-                               $$ = aip->val;
-                           else if (strcmp($1, user_name) == 0)
-                               $$ = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared User_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", $1, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               $$ = NOMATCH;
-                           }
-                           free($1);
-                       }
-               |       ALL {
-                           $$ = TRUE;
-                       }
-               ;
-
-%%
-
-#define MOREALIASES (32)
-aliasinfo *aliases = NULL;
-size_t naliases = 0;
-size_t nslots = 0;
-
-
-/*
- * Compare two aliasinfo structures, strcmp() style.
- * Note that we do *not* compare their values.
- */
-static int
-aliascmp(a1, a2)
-    const VOID *a1, *a2;
-{
-    int r;
-    aliasinfo *ai1, *ai2;
-
-    ai1 = (aliasinfo *) a1;
-    ai2 = (aliasinfo *) a2;
-    if ((r = strcmp(ai1->name, ai2->name)) == 0)
-       r = ai1->type - ai2->type;
-
-    return(r);
-}
-
-/*
- * Compare two generic_alias structures, strcmp() style.
- */
-static int
-genaliascmp(entry, key)
-    const VOID *entry, *key;
-{
-    int r;
-    struct generic_alias *ga1, *ga2;
-
-    ga1 = (struct generic_alias *) key;
-    ga2 = (struct generic_alias *) entry;
-    if ((r = strcmp(ga1->alias, ga2->alias)) == 0)
-       r = ga1->type - ga2->type;
-
-    return(r);
-}
-
-
-/*
- * Adds the named alias of the specified type to the aliases list.
- */
-static int
-add_alias(alias, type, val)
-    char *alias;
-    int type;
-    int val;
-{
-    aliasinfo ai, *aip;
-    size_t onaliases;
-    char s[512];
-
-    if (naliases >= nslots && !more_aliases()) {
-       (void) snprintf(s, sizeof(s), "Out of memory defining alias `%s'",
-                       alias);
-       yyerror(s);
-       return(FALSE);
-    }
-
-    ai.type = type;
-    ai.val = val;
-    ai.name = estrdup(alias);
-    onaliases = naliases;
-
-    aip = (aliasinfo *) lsearch((VOID *)&ai, (VOID *)aliases, &naliases,
-                               sizeof(ai), aliascmp);
-    if (aip == NULL) {
-       (void) snprintf(s, sizeof(s), "Aliases corrupted defining alias `%s'",
-                       alias);
-       yyerror(s);
-       return(FALSE);
-    }
-    if (onaliases == naliases) {
-       (void) snprintf(s, sizeof(s), "Alias `%s' already defined", alias);
-       yyerror(s);
-       return(FALSE);
-    }
-
-    return(TRUE);
-}
-
-/*
- * Searches for the named alias of the specified type.
- */
-static aliasinfo *
-find_alias(alias, type)
-    char *alias;
-    int type;
-{
-    aliasinfo ai;
-
-    ai.name = alias;
-    ai.type = type;
-
-    return((aliasinfo *) lfind((VOID *)&ai, (VOID *)aliases, &naliases,
-                sizeof(ai), aliascmp));
-}
-
-/*
- * Allocates more space for the aliases list.
- */
-static int
-more_aliases()
-{
-
-    nslots += MOREALIASES;
-    if (nslots == MOREALIASES)
-       aliases = (aliasinfo *) malloc(nslots * sizeof(aliasinfo));
-    else
-       aliases = (aliasinfo *) realloc(aliases, nslots * sizeof(aliasinfo));
-
-    return(aliases != NULL);
-}
-
-/*
- * Lists the contents of the aliases list.
- */
-void
-dumpaliases()
-{
-    size_t n;
-
-    for (n = 0; n < naliases; n++) {
-       if (aliases[n].val == -1)
-           continue;
-
-       switch (aliases[n].type) {
-       case HOST_ALIAS:
-           (void) puts("HOST_ALIAS");
-           break;
-
-       case CMND_ALIAS:
-           (void) puts("CMND_ALIAS");
-           break;
-
-       case USER_ALIAS:
-           (void) puts("USER_ALIAS");
-           break;
-
-       case RUNAS_ALIAS:
-           (void) puts("RUNAS_ALIAS");
-           break;
-       }
-       (void) printf("\t%s: %d\n", aliases[n].name, aliases[n].val);
-    }
-}
-
-/*
- * Lists the contents of cm_list and ga_list for `sudo -l'.
- */
-void
-list_matches()
-{
-    size_t count;
-    char *p;
-    struct generic_alias *ga, key;
-
-    (void) printf("User %s may run the following commands on this host:\n",
-       user_name);
-    for (count = 0; count < cm_list_len; count++) {
-
-       /* Print the runas list. */
-       (void) fputs("    ", stdout);
-       if (cm_list[count].runas) {
-           (void) putchar('(');
-           p = strtok(cm_list[count].runas, ", ");
-           do {
-               if (p != cm_list[count].runas)
-                   (void) fputs(", ", stdout);
-
-               key.alias = p;
-               key.type = RUNAS_ALIAS;
-               if ((ga = (struct generic_alias *) lfind((VOID *) &key,
-                   (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
-                   (void) fputs(ga->entries, stdout);
-               else
-                   (void) fputs(p, stdout);
-           } while ((p = strtok(NULL, ", ")));
-           (void) fputs(") ", stdout);
-       } else {
-           (void) printf("(%s) ", def_runas_default);
-       }
-
-       /* Is execve(2) disabled? */
-       if (cm_list[count].noexecve == TRUE && !def_noexec)
-           (void) fputs("NOEXEC: ", stdout);
-       else if (cm_list[count].noexecve == FALSE && def_noexec)
-           (void) fputs("EXEC: ", stdout);
-
-       /* Is monitoring enabled? */
-       if (cm_list[count].monitor == TRUE && !def_monitor)
-           (void) fputs("MONITOR: ", stdout);
-       else if (cm_list[count].monitor == FALSE && def_monitor)
-           (void) fputs("NOMONITOR: ", stdout);
-
-       /* Is a password required? */
-       if (cm_list[count].nopasswd == TRUE && def_authenticate)
-           (void) fputs("NOPASSWD: ", stdout);
-       else if (cm_list[count].nopasswd == FALSE && !def_authenticate)
-           (void) fputs("PASSWD: ", stdout);
-
-       /* Print the actual command or expanded Cmnd_Alias. */
-       key.alias = cm_list[count].cmnd;
-       key.type = CMND_ALIAS;
-       if ((ga = (struct generic_alias *) lfind((VOID *) &key,
-           (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
-           (void) puts(ga->entries);
-       else
-           (void) puts(cm_list[count].cmnd);
-    }
-
-    /* Be nice and free up space now that we are done. */
-    for (count = 0; count < ga_list_len; count++) {
-       free(ga_list[count].alias);
-       free(ga_list[count].entries);
-    }
-    free(ga_list);
-    ga_list = NULL;
-
-    for (count = 0; count < cm_list_len; count++) {
-       free(cm_list[count].runas);
-       free(cm_list[count].cmnd);
-    }
-    free(cm_list);
-    cm_list = NULL;
-    cm_list_len = 0;
-    cm_list_size = 0;
-}
-
-/*
- * Appends a source string to the destination, optionally prefixing a separator.
- */
-static void
-append(src, dstp, dst_len, dst_size, separator)
-    char *src, **dstp;
-    size_t *dst_len, *dst_size;
-    char *separator;
-{
-    size_t src_len = strlen(src);
-    char *dst = *dstp;
-
-    /*
-     * Only add the separator if there is something to separate from.
-     * If the last char is a '!', don't apply the separator (XXX).
-     */
-    if (separator && dst && dst[*dst_len - 1] != '!')
-       src_len += strlen(separator);
-    else
-       separator = NULL;
-
-    /* Assumes dst will be NULL if not set. */
-    if (dst == NULL) {
-       dst = (char *) emalloc(BUFSIZ);
-       *dst = '\0';
-       *dst_size = BUFSIZ;
-       *dst_len = 0;
-       *dstp = dst;
-    }
-
-    /* Allocate more space if necessary. */
-    if (*dst_size <= *dst_len + src_len) {
-       while (*dst_size <= *dst_len + src_len)
-           *dst_size += BUFSIZ;
-
-       dst = (char *) erealloc(dst, *dst_size);
-       *dstp = dst;
-    }
-
-    /* Copy src -> dst adding a separator if appropriate and adjust len. */
-    if (separator)
-       (void) strlcat(dst, separator, *dst_size);
-    (void) strlcat(dst, src, *dst_size);
-    *dst_len += src_len;
-}
-
-/*
- * Frees up space used by the aliases list and resets the associated counters.
- */
-void
-reset_aliases()
-{
-    size_t n;
-
-    if (aliases) {
-       for (n = 0; n < naliases; n++)
-           free(aliases[n].name);
-       free(aliases);
-       aliases = NULL;
-    }
-    naliases = nslots = 0;
-}
-
-/*
- * Increments ga_list_len, allocating more space as necessary.
- */
-static void
-expand_ga_list()
-{
-
-    if (++ga_list_len >= ga_list_size) {
-       while ((ga_list_size += STACKINCREMENT) < ga_list_len)
-           ;
-       ga_list = (struct generic_alias *)
-           erealloc3(ga_list, ga_list_size, sizeof(struct generic_alias));
-    }
-
-    ga_list[ga_list_len - 1].entries = NULL;
-}
-
-/*
- * Increments cm_list_len, allocating more space as necessary.
- */
-static void
-expand_match_list()
-{
-
-    if (++cm_list_len >= cm_list_size) {
-       while ((cm_list_size += STACKINCREMENT) < cm_list_len)
-           ;
-       if (cm_list == NULL)
-           cm_list_len = 0;            /* start at 0 since it is a subscript */
-       cm_list = (struct command_match *)
-           erealloc3(cm_list, cm_list_size, sizeof(struct command_match));
-    }
-
-    cm_list[cm_list_len].runas = cm_list[cm_list_len].cmnd = NULL;
-    cm_list[cm_list_len].nopasswd = FALSE;
-    cm_list[cm_list_len].noexecve = FALSE;
-    cm_list[cm_list_len].monitor  = FALSE;
-}
-
-/*
- * Frees up spaced used by a previous parser run and allocates new space
- * for various data structures.
- */
-void
-init_parser(path)
-    char *path;
-{
-
-    /* Free up old data structures if we run the parser more than once. */
-    if (match) {
-       free(match);
-       match = NULL;
-       top = 0;
-       parse_error = FALSE;
-       used_runas = FALSE;
-       errorlineno = -1;
-       sudolineno = 1;
-       free(sudoers);
-    }
-
-    /* Allocate space for the matching stack. */
-    stacksize = STACKINCREMENT;
-    match = (struct matchstack *) emalloc2(stacksize, sizeof(struct matchstack));
-
-    /* Allocate space for the match list (for `sudo -l'). */
-    if (printmatches == TRUE)
-       expand_match_list();
-
-    sudoers = estrdup(path);
-}
diff --git a/sudo.tab.c b/sudo.tab.c
deleted file mode 100644 (file)
index dc10920..0000000
+++ /dev/null
@@ -1,2082 +0,0 @@
-#ifndef lint
-/*static char yysccsid[] = "from: @(#)yaccpar  1.9 (Berkeley) 02/21/93";*/
-static char yyrcsid[]
-#if __GNUC__ >= 2
-  __attribute__ ((unused))
-#endif /* __GNUC__ >= 2 */
-  = "$OpenBSD: skeleton.c,v 1.23 2004/03/12 13:39:50 henning Exp $";
-#endif
-#include <stdlib.h>
-#define YYBYACC 1
-#define YYMAJOR 1
-#define YYMINOR 9
-#define YYLEX yylex()
-#define YYEMPTY -1
-#define yyclearin (yychar=(YYEMPTY))
-#define yyerrok (yyerrflag=0)
-#define YYRECOVERING() (yyerrflag!=0)
-#define YYPREFIX "yy"
-#line 2 "parse.yacc"
-/*
- * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F39502-99-1-0512.
- */
-
-/*
- * XXX - the whole opFOO naming thing is somewhat bogus.
- *
- * XXX - the way things are stored for printmatches is stupid,
- *       they should be stored as elements in an array and then
- *       list_matches() can format things the way it wants.
- */
-
-#include "config.h"
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <stdio.h>
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif /* STDC_HEADERS */
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# ifdef HAVE_STRINGS_H
-#  include <strings.h>
-# endif
-#endif /* HAVE_STRING_H */
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <pwd.h>
-#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
-# include <malloc.h>
-#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
-#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
-# include <alloca.h>
-#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
-#ifdef HAVE_LSEARCH
-# include <search.h>
-#endif /* HAVE_LSEARCH */
-
-#include "sudo.h"
-#include "parse.h"
-
-#ifndef HAVE_LSEARCH
-#include "emul/search.h"
-#endif /* HAVE_LSEARCH */
-
-#ifndef lint
-static const char rcsid[] = "$Sudo$";
-#endif /* lint */
-
-/*
- * Globals
- */
-extern int sudolineno, parse_error;
-extern char *sudoers;
-int clearaliases = TRUE;
-int printmatches = FALSE;
-int pedantic = FALSE;
-int keepall = FALSE;
-int quiet = FALSE;
-int used_runas = FALSE;
-int errorlineno = -1;
-char *errorfile = NULL;
-
-/*
- * Alias types
- */
-#define HOST_ALIAS              1
-#define CMND_ALIAS              2
-#define USER_ALIAS              3
-#define RUNAS_ALIAS             4
-
-#define SETMATCH(_var, _val)   do { \
-       if ((_var) == UNSPEC || (_val) != NOMATCH) \
-           (_var) = (_val); \
-} while (0)
-
-#define SETNMATCH(_var, _val)  do { \
-       if ((_val) != NOMATCH) \
-           (_var) = ! (_val); \
-       else if ((_var) == UNSPEC) \
-           (_var) = NOMATCH; \
-} while (0)
-
-/*
- * The matching stack, initial space allocated in init_parser().
- */
-struct matchstack *match;
-int top = 0, stacksize = 0;
-
-#define push \
-    do { \
-       if (top >= stacksize) { \
-           while ((stacksize += STACKINCREMENT) < top); \
-           match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
-       } \
-       match[top].user   = UNSPEC; \
-       match[top].cmnd   = UNSPEC; \
-       match[top].host   = UNSPEC; \
-       match[top].runas  = UNSPEC; \
-       match[top].nopass = def_authenticate ? UNSPEC : TRUE; \
-       match[top].noexec = def_noexec ? TRUE : UNSPEC; \
-       match[top].monitor  = def_monitor ? TRUE : UNSPEC; \
-       top++; \
-    } while (0)
-
-#define pushcp \
-    do { \
-       if (top >= stacksize) { \
-           while ((stacksize += STACKINCREMENT) < top); \
-           match = (struct matchstack *) erealloc3(match, stacksize, sizeof(struct matchstack)); \
-       } \
-       match[top].user     = match[top-1].user; \
-       match[top].cmnd     = match[top-1].cmnd; \
-       match[top].host     = match[top-1].host; \
-       match[top].runas    = match[top-1].runas; \
-       match[top].nopass   = match[top-1].nopass; \
-       match[top].noexec   = match[top-1].noexec; \
-       match[top].monitor  = match[top-1].monitor; \
-       top++; \
-    } while (0)
-
-#define pop \
-    do { \
-       if (top == 0) \
-           yyerror("matching stack underflow"); \
-       else \
-           top--; \
-    } while (0)
-
-
-/*
- * For testing if foo_matches variable was set to TRUE or FALSE
- */
-#define        MATCHED(_v)     ((_v) >= 0)
-
-/*
- * Shortcuts for append()
- */
-#define append_cmnd(s, p) append(s, &cm_list[cm_list_len].cmnd, \
-       &cm_list[cm_list_len].cmnd_len, &cm_list[cm_list_len].cmnd_size, p)
-
-#define append_runas(s, p) append(s, &cm_list[cm_list_len].runas, \
-       &cm_list[cm_list_len].runas_len, &cm_list[cm_list_len].runas_size, p)
-
-#define append_entries(s, p) append(s, &ga_list[ga_list_len-1].entries, \
-       &ga_list[ga_list_len-1].entries_len, \
-       &ga_list[ga_list_len-1].entries_size, p)
-
-/*
- * The stack for printmatches.  A list of allowed commands for the user.
- */
-static struct command_match *cm_list = NULL;
-static size_t cm_list_len = 0, cm_list_size = 0;
-
-/*
- * List of Cmnd_Aliases and expansions for `sudo -l'
- */
-static int in_alias = FALSE;
-static size_t ga_list_len = 0, ga_list_size = 0;
-static struct generic_alias *ga_list = NULL;
-
-/*
- * Does this Defaults list pertain to this user?
- */
-static int defaults_matches = FALSE;
-
-/*
- * Local protoypes
- */
-static int  add_alias          __P((char *, int, int));
-static void append             __P((char *, char **, size_t *, size_t *, char *));
-static void expand_ga_list     __P((void));
-static void expand_match_list  __P((void));
-static aliasinfo *find_alias   __P((char *, int));
-static int  more_aliases       __P((void));
-       void yyerror            __P((const char *));
-
-void
-yyerror(s)
-    const char *s;
-{
-    /* Save the line the first error occurred on. */
-    if (errorlineno == -1) {
-       errorlineno = sudolineno ? sudolineno - 1 : 0;
-       errorfile = estrdup(sudoers);
-    }
-    if (s && !quiet) {
-#ifndef TRACELEXER
-       (void) fprintf(stderr, ">>> %s: %s, line %d <<<\n", sudoers, s,
-           sudolineno ? sudolineno - 1 : 0);
-#else
-       (void) fprintf(stderr, "<*> ");
-#endif
-    }
-    parse_error = TRUE;
-}
-#line 226 "parse.yacc"
-#ifndef YYSTYPE_DEFINED
-#define YYSTYPE_DEFINED
-typedef union {
-    char *string;
-    int BOOLEAN;
-    struct sudo_command command;
-    int tok;
-} YYSTYPE;
-#endif /* YYSTYPE_DEFINED */
-#line 253 "sudo.tab.c"
-#define COMMAND 257
-#define ALIAS 258
-#define DEFVAR 259
-#define NTWKADDR 260
-#define NETGROUP 261
-#define USERGROUP 262
-#define WORD 263
-#define DEFAULTS 264
-#define DEFAULTS_HOST 265
-#define DEFAULTS_USER 266
-#define DEFAULTS_RUNAS 267
-#define RUNAS 268
-#define NOPASSWD 269
-#define PASSWD 270
-#define NOEXEC 271
-#define EXEC 272
-#define MONITOR 273
-#define NOMONITOR 274
-#define ALL 275
-#define COMMENT 276
-#define HOSTALIAS 277
-#define CMNDALIAS 278
-#define USERALIAS 279
-#define RUNASALIAS 280
-#define ERROR 281
-#define YYERRCODE 256
-#if defined(__cplusplus) || defined(__STDC__)
-const short yylhs[] =
-#else
-short yylhs[] =
-#endif
-       {                                        -1,
-    0,    0,    7,    7,    8,    8,   10,    8,    8,    8,
-    8,    8,    8,   16,   17,   19,   17,   20,   17,   22,
-   17,   18,   18,   23,   23,   23,   23,   23,   11,   11,
-   24,   26,   26,    2,    2,    2,    2,    2,   25,   25,
-   27,   30,   31,   30,   28,   28,    5,    5,    4,   32,
-    4,    3,    3,    3,    3,    3,   29,   29,   29,   29,
-   29,   29,   29,    1,    1,    1,   13,   13,   34,   33,
-   21,   21,   14,   14,   36,   35,   37,   37,   15,   15,
-   39,   38,   12,   12,   41,   40,    9,    9,   42,   42,
-    6,    6,    6,    6,    6,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yylen[] =
-#else
-short yylen[] =
-#endif
-       {                                         2,
-    0,    1,    1,    2,    1,    2,    0,    3,    2,    2,
-    2,    2,    1,    2,    1,    0,    3,    0,    3,    0,
-    3,    1,    3,    1,    2,    3,    3,    3,    1,    3,
-    3,    1,    2,    1,    1,    1,    1,    1,    1,    3,
-    3,    1,    0,    3,    0,    2,    1,    3,    1,    0,
-    3,    1,    1,    1,    1,    1,    0,    2,    2,    2,
-    2,    2,    2,    1,    1,    1,    1,    3,    0,    4,
-    1,    3,    1,    3,    0,    4,    1,    3,    1,    3,
-    0,    4,    1,    3,    0,    4,    1,    3,    1,    2,
-    1,    1,    1,    1,    1,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yydefred[] =
-#else
-short yydefred[] =
-#endif
-       {                                      0,
-    0,   15,   20,   16,   18,    5,    0,    0,    0,    0,
-    0,    0,    3,    0,   13,    0,    6,    0,    0,    0,
-   69,    0,   67,   75,    0,   73,   85,    0,   83,   81,
-    0,   79,    4,   94,   93,   92,   91,   95,    0,   89,
-    0,   87,    0,    0,   14,    0,   38,   35,   36,   37,
-   34,    0,   32,    0,   71,    0,   55,   54,   53,   52,
-   56,   50,   49,   47,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,   90,    0,    0,    0,   29,    0,    0,
-    0,   25,    0,   33,    0,    0,    0,    0,   68,    0,
-   74,    0,   84,    0,   80,   88,    0,    0,   26,   27,
-   28,   23,   72,   51,   48,    0,   66,   65,   64,   43,
-   42,   77,    0,    0,    0,   30,    0,    0,   39,   57,
-    0,    0,    0,    0,    0,   44,   78,   40,   58,   59,
-   60,   61,   62,   63,   41,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yydgoto[] =
-#else
-short yydgoto[] =
-#endif
-       {                                      11,
-  111,   53,   63,   64,   65,   40,   12,   13,   41,   14,
-   76,   28,   22,   25,   31,   15,   16,   45,   19,   20,
-   77,   18,   46,   78,  118,   55,  119,  120,  125,  112,
-  121,   86,   23,   66,   26,   68,  113,   32,   72,   29,
-   70,   42,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yysindex[] =
-#else
-short yysindex[] =
-#endif
-       {                                   -229,
- -256,    0,    0,    0,    0,    0, -237, -234, -226, -225,
-    0, -229,    0,  114,    0,  -33,    0,  140,  114,  166,
-    0,  -12,    0,    0,   -5,    0,    0,   -4,    0,    0,
-   -1,    0,    0,    0,    0,    0,    0,    0, -244,    0,
-  -28,    0,  -36, -216,    0,   11,    0,    0,    0,    0,
-    0, -219,    0,   14,    0,   17,    0,    0,    0,    0,
-    0,    0,    0,    0,   22,    6, -237,    7, -234,    8,
- -226,    9, -225,    0,  114,   13,  -21,    0, -191, -189,
- -187,    0,  -33,    0,  140, -198,  166,  140,    0,  276,
-    0,  114,    0,  166,    0,    0,  140, -188,    0,    0,
-    0,    0,    0,    0,    0,   14,    0,    0,    0,    0,
-    0,    0,   35,   17,   22,    0,  166,   37,    0,    0,
- -247,  276,   22, -188,  -29,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yyrindex[] =
-#else
-short yyrindex[] =
-#endif
-       {                                     62,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,   88,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,  156,    0,    0,  181,    0,    0,  206,    0,    0,
-  236,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    1,    0,    0,  261,    0,    0,    0,    0,
-    0,    0,    0,  -25,    0,  -11,    0,    0,    0,    0,
-    0,    0,    0,    0,   -3,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,  300,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,    0,  -20,    0,    0,
-    0,    0,    0,    0,    0,   26,    0,    0,    0,    0,
-    0,    0,   52,   78,  104,    0,    0,  130,    0,    0,
-    0,    0,  274,  -20,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yygindex[] =
-#else
-short yygindex[] =
-#endif
-       {                                      0,
-  -39,   31,    3,    4,  -88,   47,    0,   75,  -17,    0,
-    0,    0,    0,    0,    0,    0,    0,   10,    0,    0,
-  -15,    0,    0,   -7,    0,   12,  -32,    0,    0, -110,
-    0,    0,   27,    0,   29,    0,    0,   23,    0,   28,
-    0,   25,
-};
-#define YYTABLESIZE 580
-#if defined(__cplusplus) || defined(__STDC__)
-const short yytable[] =
-#else
-short yytable[] =
-#endif
-       {                                      44,
-   24,   56,   54,  110,   52,  115,   80,   21,   81,  107,
-  108,  127,   45,   34,  135,   75,   35,   36,   37,   17,
-   21,   17,   85,   24,   79,   70,    1,  109,  123,   19,
-   38,   27,   30,   24,    2,    3,    4,    5,   47,   98,
-   48,   49,   82,   50,   24,   67,    6,    7,    8,    9,
-   10,   76,   69,   71,   83,   51,   73,   85,   70,   57,
-   75,    1,   58,   59,   60,   87,   88,   90,   92,   94,
-   97,   99,  106,  100,  114,  101,   61,   86,  122,  117,
-  124,  126,   84,   70,   76,   74,   33,    2,  104,  116,
-  105,  128,  102,   89,    7,   95,  103,   91,   93,   96,
-    0,    0,    0,   82,    0,    0,    0,    0,    0,   76,
-   86,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-    7,    0,    0,    0,    0,    0,    0,    0,    0,   31,
-    0,    0,    0,    0,    0,   86,   82,    0,    0,    0,
-    0,    0,    0,    0,    0,    0,   39,    0,    0,    0,
-    0,    0,    0,    0,    0,   10,    0,    0,    0,    0,
-    0,   82,   31,    0,    0,    0,    0,    0,    0,    0,
-    0,    0,   52,    0,    0,    0,    0,    0,    0,    0,
-   11,    0,    0,    0,    0,    0,    0,   31,   10,    0,
-    0,    0,    0,    0,    0,    0,    0,    0,   62,    0,
-    0,    0,    0,    0,    0,    9,    0,    0,    0,    0,
-    0,    0,    0,   11,    0,    0,    0,    0,    0,    0,
-    0,    0,    0,    0,    0,   43,    0,  107,  108,   47,
-    0,   48,   49,   21,   50,   12,   45,   45,    9,  129,
-  130,  131,  132,  133,  134,  109,   51,   17,   45,   45,
-   45,   45,   45,   45,   45,   19,   24,    0,   24,    0,
-   22,   24,   24,   24,   24,   24,   24,   24,   12,    0,
-    0,    0,    0,    0,    0,   24,   24,   24,   24,   24,
-   24,   70,    0,   70,    0,    0,   70,   70,   70,   70,
-   70,   70,   70,   22,    0,    0,    0,    0,    0,    8,
-   70,   70,   70,   70,   70,   70,   46,   76,  110,   76,
-    0,    0,   76,   76,   76,   76,   76,   76,   76,    7,
-    0,    0,    7,    7,    7,    0,   76,   76,   76,   76,
-   76,   76,    8,   86,    0,   86,    7,    0,   86,   86,
-   86,   86,   86,   86,   86,    7,    0,    0,    7,    7,
-    7,    0,   86,   86,   86,   86,   86,   86,    0,   82,
-    0,   82,    7,    0,   82,   82,   82,   82,   82,   82,
-   82,   34,    0,    0,   35,   36,   37,    0,   82,   82,
-   82,   82,   82,   82,    0,   31,    0,   31,   38,    0,
-   31,   31,   31,   31,   31,   31,   31,   47,    0,   48,
-   49,    0,   50,    0,   31,   31,   31,   31,   31,   31,
-    0,   10,    0,   10,   51,    0,   10,   10,   10,   10,
-   10,   10,   10,   57,    0,    0,   58,   59,   60,    0,
-   10,   10,   10,   10,   10,   10,   11,    0,   11,    0,
-   61,   11,   11,   11,   11,   11,   11,   11,    0,    0,
-    0,    0,    0,    0,    0,   11,   11,   11,   11,   11,
-   11,    9,    0,    9,    0,    0,    9,    9,    9,    9,
-    9,    9,    9,    0,    0,    0,    0,    0,    0,    0,
-    9,    9,    9,    9,    9,    9,    0,    0,    0,    0,
-    0,   12,    0,   12,    0,    0,   12,   12,   12,   12,
-   12,   12,   12,    0,    0,    0,    0,    0,    0,    0,
-   12,   12,   12,   12,   12,   12,   22,    0,   22,    0,
-    0,   22,   22,   22,   22,   22,   22,   22,    0,    0,
-   46,   46,  107,  108,    0,   22,   22,   22,   22,   22,
-   22,    0,   46,   46,   46,   46,   46,   46,   46,    0,
-  109,    0,    0,    0,    0,    8,    0,    8,    0,    0,
-    8,    8,    8,    8,    8,    8,    8,    0,    0,    0,
-    0,    0,    0,    0,    8,    8,    8,    8,    8,    8,
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const short yycheck[] =
-#else
-short yycheck[] =
-#endif
-       {                                      33,
-    0,   19,   18,   33,   33,   94,   43,   33,   45,  257,
-  258,  122,   33,  258,  125,   44,  261,  262,  263,  276,
-  258,   33,   44,  258,   61,    0,  256,  275,  117,   33,
-  275,  258,  258,   33,  264,  265,  266,  267,  258,   61,
-  260,  261,  259,  263,   44,   58,  276,  277,  278,  279,
-  280,    0,   58,   58,   44,  275,   58,   44,   33,  258,
-   44,    0,  261,  262,  263,   44,   61,   61,   61,   61,
-   58,  263,   88,  263,   92,  263,  275,    0,   44,  268,
-   44,  121,   52,   58,   33,   39,   12,    0,   86,   97,
-   87,  124,   83,   67,   33,   73,   85,   69,   71,   75,
-   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,   -1,   58,
-   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-   33,   -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,   33,   -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,   33,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-    0,   -1,   -1,   -1,   -1,   -1,   -1,   58,   33,   -1,
-   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   33,   -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,
-   -1,  260,  261,  259,  263,    0,  257,  258,   33,  269,
-  270,  271,  272,  273,  274,  275,  275,  259,  269,  270,
-  271,  272,  273,  274,  275,  259,  256,   -1,  258,   -1,
-    0,  261,  262,  263,  264,  265,  266,  267,   33,   -1,
-   -1,   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,
-  280,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
-  265,  266,  267,   33,   -1,   -1,   -1,   -1,   -1,    0,
-  275,  276,  277,  278,  279,  280,   33,  256,   33,  258,
-   -1,   -1,  261,  262,  263,  264,  265,  266,  267,  258,
-   -1,   -1,  261,  262,  263,   -1,  275,  276,  277,  278,
-  279,  280,   33,  256,   -1,  258,  275,   -1,  261,  262,
-  263,  264,  265,  266,  267,  258,   -1,   -1,  261,  262,
-  263,   -1,  275,  276,  277,  278,  279,  280,   -1,  256,
-   -1,  258,  275,   -1,  261,  262,  263,  264,  265,  266,
-  267,  258,   -1,   -1,  261,  262,  263,   -1,  275,  276,
-  277,  278,  279,  280,   -1,  256,   -1,  258,  275,   -1,
-  261,  262,  263,  264,  265,  266,  267,  258,   -1,  260,
-  261,   -1,  263,   -1,  275,  276,  277,  278,  279,  280,
-   -1,  256,   -1,  258,  275,   -1,  261,  262,  263,  264,
-  265,  266,  267,  258,   -1,   -1,  261,  262,  263,   -1,
-  275,  276,  277,  278,  279,  280,  256,   -1,  258,   -1,
-  275,  261,  262,  263,  264,  265,  266,  267,   -1,   -1,
-   -1,   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,
-  280,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
-  265,  266,  267,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-  275,  276,  277,  278,  279,  280,   -1,   -1,   -1,   -1,
-   -1,  256,   -1,  258,   -1,   -1,  261,  262,  263,  264,
-  265,  266,  267,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
-  275,  276,  277,  278,  279,  280,  256,   -1,  258,   -1,
-   -1,  261,  262,  263,  264,  265,  266,  267,   -1,   -1,
-  257,  258,  257,  258,   -1,  275,  276,  277,  278,  279,
-  280,   -1,  269,  270,  271,  272,  273,  274,  275,   -1,
-  275,   -1,   -1,   -1,   -1,  256,   -1,  258,   -1,   -1,
-  261,  262,  263,  264,  265,  266,  267,   -1,   -1,   -1,
-   -1,   -1,   -1,   -1,  275,  276,  277,  278,  279,  280,
-};
-#define YYFINAL 11
-#ifndef YYDEBUG
-#define YYDEBUG 0
-#endif
-#define YYMAXTOKEN 281
-#if YYDEBUG
-#if defined(__cplusplus) || defined(__STDC__)
-const char * const yyname[] =
-#else
-char *yyname[] =
-#endif
-       {
-"end-of-file",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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,0,
-"COMMAND","ALIAS","DEFVAR","NTWKADDR","NETGROUP","USERGROUP","WORD","DEFAULTS",
-"DEFAULTS_HOST","DEFAULTS_USER","DEFAULTS_RUNAS","RUNAS","NOPASSWD","PASSWD",
-"NOEXEC","EXEC","MONITOR","NOMONITOR","ALL","COMMENT","HOSTALIAS","CMNDALIAS",
-"USERALIAS","RUNASALIAS","ERROR",
-};
-#if defined(__cplusplus) || defined(__STDC__)
-const char * const yyrule[] =
-#else
-char *yyrule[] =
-#endif
-       {"$accept : file",
-"file :",
-"file : line",
-"line : entry",
-"line : line entry",
-"entry : COMMENT",
-"entry : error COMMENT",
-"$$1 :",
-"entry : $$1 userlist privileges",
-"entry : USERALIAS useraliases",
-"entry : HOSTALIAS hostaliases",
-"entry : CMNDALIAS cmndaliases",
-"entry : RUNASALIAS runasaliases",
-"entry : defaults_line",
-"defaults_line : defaults_type defaults_list",
-"defaults_type : DEFAULTS",
-"$$2 :",
-"defaults_type : DEFAULTS_USER $$2 userlist",
-"$$3 :",
-"defaults_type : DEFAULTS_RUNAS $$3 runaslist",
-"$$4 :",
-"defaults_type : DEFAULTS_HOST $$4 hostlist",
-"defaults_list : defaults_entry",
-"defaults_list : defaults_entry ',' defaults_list",
-"defaults_entry : DEFVAR",
-"defaults_entry : '!' DEFVAR",
-"defaults_entry : DEFVAR '=' WORD",
-"defaults_entry : DEFVAR '+' WORD",
-"defaults_entry : DEFVAR '-' WORD",
-"privileges : privilege",
-"privileges : privileges ':' privilege",
-"privilege : hostlist '=' cmndspeclist",
-"ophost : host",
-"ophost : '!' host",
-"host : ALL",
-"host : NTWKADDR",
-"host : NETGROUP",
-"host : WORD",
-"host : ALIAS",
-"cmndspeclist : cmndspec",
-"cmndspeclist : cmndspeclist ',' cmndspec",
-"cmndspec : runasspec cmndtag opcmnd",
-"opcmnd : cmnd",
-"$$5 :",
-"opcmnd : '!' $$5 cmnd",
-"runasspec :",
-"runasspec : RUNAS runaslist",
-"runaslist : oprunasuser",
-"runaslist : runaslist ',' oprunasuser",
-"oprunasuser : runasuser",
-"$$6 :",
-"oprunasuser : '!' $$6 runasuser",
-"runasuser : WORD",
-"runasuser : USERGROUP",
-"runasuser : NETGROUP",
-"runasuser : ALIAS",
-"runasuser : ALL",
-"cmndtag :",
-"cmndtag : cmndtag NOPASSWD",
-"cmndtag : cmndtag PASSWD",
-"cmndtag : cmndtag NOEXEC",
-"cmndtag : cmndtag EXEC",
-"cmndtag : cmndtag MONITOR",
-"cmndtag : cmndtag NOMONITOR",
-"cmnd : ALL",
-"cmnd : ALIAS",
-"cmnd : COMMAND",
-"hostaliases : hostalias",
-"hostaliases : hostaliases ':' hostalias",
-"$$7 :",
-"hostalias : ALIAS $$7 '=' hostlist",
-"hostlist : ophost",
-"hostlist : hostlist ',' ophost",
-"cmndaliases : cmndalias",
-"cmndaliases : cmndaliases ':' cmndalias",
-"$$8 :",
-"cmndalias : ALIAS $$8 '=' cmndlist",
-"cmndlist : opcmnd",
-"cmndlist : cmndlist ',' opcmnd",
-"runasaliases : runasalias",
-"runasaliases : runasaliases ':' runasalias",
-"$$9 :",
-"runasalias : ALIAS $$9 '=' runaslist",
-"useraliases : useralias",
-"useraliases : useraliases ':' useralias",
-"$$10 :",
-"useralias : ALIAS $$10 '=' userlist",
-"userlist : opuser",
-"userlist : userlist ',' opuser",
-"opuser : user",
-"opuser : '!' user",
-"user : WORD",
-"user : USERGROUP",
-"user : NETGROUP",
-"user : ALIAS",
-"user : ALL",
-};
-#endif
-#ifdef YYSTACKSIZE
-#undef YYMAXDEPTH
-#define YYMAXDEPTH YYSTACKSIZE
-#else
-#ifdef YYMAXDEPTH
-#define YYSTACKSIZE YYMAXDEPTH
-#else
-#define YYSTACKSIZE 10000
-#define YYMAXDEPTH 10000
-#endif
-#endif
-#define YYINITSTACKSIZE 200
-int yydebug;
-int yynerrs;
-int yyerrflag;
-int yychar;
-short *yyssp;
-YYSTYPE *yyvsp;
-YYSTYPE yyval;
-YYSTYPE yylval;
-short *yyss;
-short *yysslim;
-YYSTYPE *yyvs;
-int yystacksize;
-#line 918 "parse.yacc"
-
-#define MOREALIASES (32)
-aliasinfo *aliases = NULL;
-size_t naliases = 0;
-size_t nslots = 0;
-
-
-/*
- * Compare two aliasinfo structures, strcmp() style.
- * Note that we do *not* compare their values.
- */
-static int
-aliascmp(a1, a2)
-    const VOID *a1, *a2;
-{
-    int r;
-    aliasinfo *ai1, *ai2;
-
-    ai1 = (aliasinfo *) a1;
-    ai2 = (aliasinfo *) a2;
-    if ((r = strcmp(ai1->name, ai2->name)) == 0)
-       r = ai1->type - ai2->type;
-
-    return(r);
-}
-
-/*
- * Compare two generic_alias structures, strcmp() style.
- */
-static int
-genaliascmp(entry, key)
-    const VOID *entry, *key;
-{
-    int r;
-    struct generic_alias *ga1, *ga2;
-
-    ga1 = (struct generic_alias *) key;
-    ga2 = (struct generic_alias *) entry;
-    if ((r = strcmp(ga1->alias, ga2->alias)) == 0)
-       r = ga1->type - ga2->type;
-
-    return(r);
-}
-
-
-/*
- * Adds the named alias of the specified type to the aliases list.
- */
-static int
-add_alias(alias, type, val)
-    char *alias;
-    int type;
-    int val;
-{
-    aliasinfo ai, *aip;
-    size_t onaliases;
-    char s[512];
-
-    if (naliases >= nslots && !more_aliases()) {
-       (void) snprintf(s, sizeof(s), "Out of memory defining alias `%s'",
-                       alias);
-       yyerror(s);
-       return(FALSE);
-    }
-
-    ai.type = type;
-    ai.val = val;
-    ai.name = estrdup(alias);
-    onaliases = naliases;
-
-    aip = (aliasinfo *) lsearch((VOID *)&ai, (VOID *)aliases, &naliases,
-                               sizeof(ai), aliascmp);
-    if (aip == NULL) {
-       (void) snprintf(s, sizeof(s), "Aliases corrupted defining alias `%s'",
-                       alias);
-       yyerror(s);
-       return(FALSE);
-    }
-    if (onaliases == naliases) {
-       (void) snprintf(s, sizeof(s), "Alias `%s' already defined", alias);
-       yyerror(s);
-       return(FALSE);
-    }
-
-    return(TRUE);
-}
-
-/*
- * Searches for the named alias of the specified type.
- */
-static aliasinfo *
-find_alias(alias, type)
-    char *alias;
-    int type;
-{
-    aliasinfo ai;
-
-    ai.name = alias;
-    ai.type = type;
-
-    return((aliasinfo *) lfind((VOID *)&ai, (VOID *)aliases, &naliases,
-                sizeof(ai), aliascmp));
-}
-
-/*
- * Allocates more space for the aliases list.
- */
-static int
-more_aliases()
-{
-
-    nslots += MOREALIASES;
-    if (nslots == MOREALIASES)
-       aliases = (aliasinfo *) malloc(nslots * sizeof(aliasinfo));
-    else
-       aliases = (aliasinfo *) realloc(aliases, nslots * sizeof(aliasinfo));
-
-    return(aliases != NULL);
-}
-
-/*
- * Lists the contents of the aliases list.
- */
-void
-dumpaliases()
-{
-    size_t n;
-
-    for (n = 0; n < naliases; n++) {
-       if (aliases[n].val == -1)
-           continue;
-
-       switch (aliases[n].type) {
-       case HOST_ALIAS:
-           (void) puts("HOST_ALIAS");
-           break;
-
-       case CMND_ALIAS:
-           (void) puts("CMND_ALIAS");
-           break;
-
-       case USER_ALIAS:
-           (void) puts("USER_ALIAS");
-           break;
-
-       case RUNAS_ALIAS:
-           (void) puts("RUNAS_ALIAS");
-           break;
-       }
-       (void) printf("\t%s: %d\n", aliases[n].name, aliases[n].val);
-    }
-}
-
-/*
- * Lists the contents of cm_list and ga_list for `sudo -l'.
- */
-void
-list_matches()
-{
-    size_t count;
-    char *p;
-    struct generic_alias *ga, key;
-
-    (void) printf("User %s may run the following commands on this host:\n",
-       user_name);
-    for (count = 0; count < cm_list_len; count++) {
-
-       /* Print the runas list. */
-       (void) fputs("    ", stdout);
-       if (cm_list[count].runas) {
-           (void) putchar('(');
-           p = strtok(cm_list[count].runas, ", ");
-           do {
-               if (p != cm_list[count].runas)
-                   (void) fputs(", ", stdout);
-
-               key.alias = p;
-               key.type = RUNAS_ALIAS;
-               if ((ga = (struct generic_alias *) lfind((VOID *) &key,
-                   (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
-                   (void) fputs(ga->entries, stdout);
-               else
-                   (void) fputs(p, stdout);
-           } while ((p = strtok(NULL, ", ")));
-           (void) fputs(") ", stdout);
-       } else {
-           (void) printf("(%s) ", def_runas_default);
-       }
-
-       /* Is execve(2) disabled? */
-       if (cm_list[count].noexecve == TRUE && !def_noexec)
-           (void) fputs("NOEXEC: ", stdout);
-       else if (cm_list[count].noexecve == FALSE && def_noexec)
-           (void) fputs("EXEC: ", stdout);
-
-       /* Is monitoring enabled? */
-       if (cm_list[count].monitor == TRUE && !def_monitor)
-           (void) fputs("MONITOR: ", stdout);
-       else if (cm_list[count].monitor == FALSE && def_monitor)
-           (void) fputs("NOMONITOR: ", stdout);
-
-       /* Is a password required? */
-       if (cm_list[count].nopasswd == TRUE && def_authenticate)
-           (void) fputs("NOPASSWD: ", stdout);
-       else if (cm_list[count].nopasswd == FALSE && !def_authenticate)
-           (void) fputs("PASSWD: ", stdout);
-
-       /* Print the actual command or expanded Cmnd_Alias. */
-       key.alias = cm_list[count].cmnd;
-       key.type = CMND_ALIAS;
-       if ((ga = (struct generic_alias *) lfind((VOID *) &key,
-           (VOID *) &ga_list[0], &ga_list_len, sizeof(key), genaliascmp)))
-           (void) puts(ga->entries);
-       else
-           (void) puts(cm_list[count].cmnd);
-    }
-
-    /* Be nice and free up space now that we are done. */
-    for (count = 0; count < ga_list_len; count++) {
-       free(ga_list[count].alias);
-       free(ga_list[count].entries);
-    }
-    free(ga_list);
-    ga_list = NULL;
-
-    for (count = 0; count < cm_list_len; count++) {
-       free(cm_list[count].runas);
-       free(cm_list[count].cmnd);
-    }
-    free(cm_list);
-    cm_list = NULL;
-    cm_list_len = 0;
-    cm_list_size = 0;
-}
-
-/*
- * Appends a source string to the destination, optionally prefixing a separator.
- */
-static void
-append(src, dstp, dst_len, dst_size, separator)
-    char *src, **dstp;
-    size_t *dst_len, *dst_size;
-    char *separator;
-{
-    size_t src_len = strlen(src);
-    char *dst = *dstp;
-
-    /*
-     * Only add the separator if there is something to separate from.
-     * If the last char is a '!', don't apply the separator (XXX).
-     */
-    if (separator && dst && dst[*dst_len - 1] != '!')
-       src_len += strlen(separator);
-    else
-       separator = NULL;
-
-    /* Assumes dst will be NULL if not set. */
-    if (dst == NULL) {
-       dst = (char *) emalloc(BUFSIZ);
-       *dst = '\0';
-       *dst_size = BUFSIZ;
-       *dst_len = 0;
-       *dstp = dst;
-    }
-
-    /* Allocate more space if necessary. */
-    if (*dst_size <= *dst_len + src_len) {
-       while (*dst_size <= *dst_len + src_len)
-           *dst_size += BUFSIZ;
-
-       dst = (char *) erealloc(dst, *dst_size);
-       *dstp = dst;
-    }
-
-    /* Copy src -> dst adding a separator if appropriate and adjust len. */
-    if (separator)
-       (void) strlcat(dst, separator, *dst_size);
-    (void) strlcat(dst, src, *dst_size);
-    *dst_len += src_len;
-}
-
-/*
- * Frees up space used by the aliases list and resets the associated counters.
- */
-void
-reset_aliases()
-{
-    size_t n;
-
-    if (aliases) {
-       for (n = 0; n < naliases; n++)
-           free(aliases[n].name);
-       free(aliases);
-       aliases = NULL;
-    }
-    naliases = nslots = 0;
-}
-
-/*
- * Increments ga_list_len, allocating more space as necessary.
- */
-static void
-expand_ga_list()
-{
-
-    if (++ga_list_len >= ga_list_size) {
-       while ((ga_list_size += STACKINCREMENT) < ga_list_len)
-           ;
-       ga_list = (struct generic_alias *)
-           erealloc3(ga_list, ga_list_size, sizeof(struct generic_alias));
-    }
-
-    ga_list[ga_list_len - 1].entries = NULL;
-}
-
-/*
- * Increments cm_list_len, allocating more space as necessary.
- */
-static void
-expand_match_list()
-{
-
-    if (++cm_list_len >= cm_list_size) {
-       while ((cm_list_size += STACKINCREMENT) < cm_list_len)
-           ;
-       if (cm_list == NULL)
-           cm_list_len = 0;            /* start at 0 since it is a subscript */
-       cm_list = (struct command_match *)
-           erealloc3(cm_list, cm_list_size, sizeof(struct command_match));
-    }
-
-    cm_list[cm_list_len].runas = cm_list[cm_list_len].cmnd = NULL;
-    cm_list[cm_list_len].nopasswd = FALSE;
-    cm_list[cm_list_len].noexecve = FALSE;
-    cm_list[cm_list_len].monitor  = FALSE;
-}
-
-/*
- * Frees up spaced used by a previous parser run and allocates new space
- * for various data structures.
- */
-void
-init_parser(path)
-    char *path;
-{
-
-    /* Free up old data structures if we run the parser more than once. */
-    if (match) {
-       free(match);
-       match = NULL;
-       top = 0;
-       parse_error = FALSE;
-       used_runas = FALSE;
-       errorlineno = -1;
-       sudolineno = 1;
-       free(sudoers);
-    }
-
-    /* Allocate space for the matching stack. */
-    stacksize = STACKINCREMENT;
-    match = (struct matchstack *) emalloc2(stacksize, sizeof(struct matchstack));
-
-    /* Allocate space for the match list (for `sudo -l'). */
-    if (printmatches == TRUE)
-       expand_match_list();
-
-    sudoers = estrdup(path);
-}
-#line 998 "sudo.tab.c"
-/* allocate initial stack or double stack size, up to YYMAXDEPTH */
-#if defined(__cplusplus) || defined(__STDC__)
-static int yygrowstack(void)
-#else
-static int yygrowstack()
-#endif
-{
-    int newsize, i;
-    short *newss;
-    YYSTYPE *newvs;
-
-    if ((newsize = yystacksize) == 0)
-        newsize = YYINITSTACKSIZE;
-    else if (newsize >= YYMAXDEPTH)
-        return -1;
-    else if ((newsize *= 2) > YYMAXDEPTH)
-        newsize = YYMAXDEPTH;
-    i = yyssp - yyss;
-    newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) :
-      (short *)malloc(newsize * sizeof *newss);
-    if (newss == NULL)
-        goto bail;
-    yyss = newss;
-    yyssp = newss + i;
-    newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) :
-      (YYSTYPE *)malloc(newsize * sizeof *newvs);
-    if (newvs == NULL)
-        goto bail;
-    yyvs = newvs;
-    yyvsp = newvs + i;
-    yystacksize = newsize;
-    yysslim = yyss + newsize - 1;
-    return 0;
-bail:
-    if (yyss)
-            free(yyss);
-    if (yyvs)
-            free(yyvs);
-    yyss = yyssp = NULL;
-    yyvs = yyvsp = NULL;
-    yystacksize = 0;
-    return -1;
-}
-
-#define YYABORT goto yyabort
-#define YYREJECT goto yyabort
-#define YYACCEPT goto yyaccept
-#define YYERROR goto yyerrlab
-int
-#if defined(__cplusplus) || defined(__STDC__)
-yyparse(void)
-#else
-yyparse()
-#endif
-{
-    int yym, yyn, yystate;
-#if YYDEBUG
-#if defined(__cplusplus) || defined(__STDC__)
-    const char *yys;
-#else /* !(defined(__cplusplus) || defined(__STDC__)) */
-    char *yys;
-#endif /* !(defined(__cplusplus) || defined(__STDC__)) */
-
-    if ((yys = getenv("YYDEBUG")))
-    {
-        yyn = *yys;
-        if (yyn >= '0' && yyn <= '9')
-            yydebug = yyn - '0';
-    }
-#endif /* YYDEBUG */
-
-    yynerrs = 0;
-    yyerrflag = 0;
-    yychar = (-1);
-
-    if (yyss == NULL && yygrowstack()) goto yyoverflow;
-    yyssp = yyss;
-    yyvsp = yyvs;
-    *yyssp = yystate = 0;
-
-yyloop:
-    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
-    if (yychar < 0)
-    {
-        if ((yychar = yylex()) < 0) yychar = 0;
-#if YYDEBUG
-        if (yydebug)
-        {
-            yys = 0;
-            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
-            if (!yys) yys = "illegal-symbol";
-            printf("%sdebug: state %d, reading %d (%s)\n",
-                    YYPREFIX, yystate, yychar, yys);
-        }
-#endif
-    }
-    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
-            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
-    {
-#if YYDEBUG
-        if (yydebug)
-            printf("%sdebug: state %d, shifting to state %d\n",
-                    YYPREFIX, yystate, yytable[yyn]);
-#endif
-        if (yyssp >= yysslim && yygrowstack())
-        {
-            goto yyoverflow;
-        }
-        *++yyssp = yystate = yytable[yyn];
-        *++yyvsp = yylval;
-        yychar = (-1);
-        if (yyerrflag > 0)  --yyerrflag;
-        goto yyloop;
-    }
-    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
-            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
-    {
-        yyn = yytable[yyn];
-        goto yyreduce;
-    }
-    if (yyerrflag) goto yyinrecovery;
-#if defined(lint) || defined(__GNUC__)
-    goto yynewerror;
-#endif
-yynewerror:
-    yyerror("syntax error");
-#if defined(lint) || defined(__GNUC__)
-    goto yyerrlab;
-#endif
-yyerrlab:
-    ++yynerrs;
-yyinrecovery:
-    if (yyerrflag < 3)
-    {
-        yyerrflag = 3;
-        for (;;)
-        {
-            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
-                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
-            {
-#if YYDEBUG
-                if (yydebug)
-                    printf("%sdebug: state %d, error recovery shifting\
- to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
-#endif
-                if (yyssp >= yysslim && yygrowstack())
-                {
-                    goto yyoverflow;
-                }
-                *++yyssp = yystate = yytable[yyn];
-                *++yyvsp = yylval;
-                goto yyloop;
-            }
-            else
-            {
-#if YYDEBUG
-                if (yydebug)
-                    printf("%sdebug: error recovery discarding state %d\n",
-                            YYPREFIX, *yyssp);
-#endif
-                if (yyssp <= yyss) goto yyabort;
-                --yyssp;
-                --yyvsp;
-            }
-        }
-    }
-    else
-    {
-        if (yychar == 0) goto yyabort;
-#if YYDEBUG
-        if (yydebug)
-        {
-            yys = 0;
-            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
-            if (!yys) yys = "illegal-symbol";
-            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
-                    YYPREFIX, yystate, yychar, yys);
-        }
-#endif
-        yychar = (-1);
-        goto yyloop;
-    }
-yyreduce:
-#if YYDEBUG
-    if (yydebug)
-        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
-                YYPREFIX, yystate, yyn, yyrule[yyn]);
-#endif
-    yym = yylen[yyn];
-    yyval = yyvsp[1-yym];
-    switch (yyn)
-    {
-case 1:
-#line 277 "parse.yacc"
-{ ; }
-break;
-case 5:
-#line 286 "parse.yacc"
-{ ; }
-break;
-case 6:
-#line 288 "parse.yacc"
-{ yyerrok; }
-break;
-case 7:
-#line 289 "parse.yacc"
-{ push; }
-break;
-case 8:
-#line 289 "parse.yacc"
-{
-                           while (top && user_matches != TRUE)
-                               pop;
-                       }
-break;
-case 9:
-#line 294 "parse.yacc"
-{ ; }
-break;
-case 10:
-#line 296 "parse.yacc"
-{ ; }
-break;
-case 11:
-#line 298 "parse.yacc"
-{ ; }
-break;
-case 12:
-#line 300 "parse.yacc"
-{ ; }
-break;
-case 13:
-#line 302 "parse.yacc"
-{ ; }
-break;
-case 15:
-#line 308 "parse.yacc"
-{
-                           defaults_matches = TRUE;
-                       }
-break;
-case 16:
-#line 311 "parse.yacc"
-{ push; }
-break;
-case 17:
-#line 311 "parse.yacc"
-{
-                           defaults_matches = user_matches;
-                           pop;
-                       }
-break;
-case 18:
-#line 315 "parse.yacc"
-{ push; }
-break;
-case 19:
-#line 315 "parse.yacc"
-{
-                           defaults_matches = yyvsp[0].BOOLEAN == TRUE;
-                           pop;
-                       }
-break;
-case 20:
-#line 319 "parse.yacc"
-{ push; }
-break;
-case 21:
-#line 319 "parse.yacc"
-{
-                           defaults_matches = host_matches;
-                           pop;
-                       }
-break;
-case 24:
-#line 329 "parse.yacc"
-{
-                           if (defaults_matches == TRUE &&
-                               !set_default(yyvsp[0].string, NULL, TRUE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free(yyvsp[0].string);
-                       }
-break;
-case 25:
-#line 337 "parse.yacc"
-{
-                           if (defaults_matches == TRUE &&
-                               !set_default(yyvsp[0].string, NULL, FALSE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free(yyvsp[0].string);
-                       }
-break;
-case 26:
-#line 345 "parse.yacc"
-{
-                           if (defaults_matches == TRUE &&
-                               !set_default(yyvsp[-2].string, yyvsp[0].string, TRUE)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free(yyvsp[-2].string);
-                           free(yyvsp[0].string);
-                       }
-break;
-case 27:
-#line 354 "parse.yacc"
-{
-                           if (defaults_matches == TRUE &&
-                               !set_default(yyvsp[-2].string, yyvsp[0].string, '+')) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free(yyvsp[-2].string);
-                           free(yyvsp[0].string);
-                       }
-break;
-case 28:
-#line 363 "parse.yacc"
-{
-                           if (defaults_matches == TRUE &&
-                               !set_default(yyvsp[-2].string, yyvsp[0].string, '-')) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free(yyvsp[-2].string);
-                           free(yyvsp[0].string);
-                       }
-break;
-case 31:
-#line 378 "parse.yacc"
-{
-                           /*
-                            * We already did a push if necessary in
-                            * cmndspec so just reset some values so
-                            * the next 'privilege' gets a clean slate.
-                            */
-                           host_matches = UNSPEC;
-                           runas_matches = UNSPEC;
-                           no_passwd = def_authenticate ? UNSPEC : TRUE;
-                           no_execve = def_noexec ? TRUE : UNSPEC;
-                           monitor_cmnd = def_monitor ? TRUE : UNSPEC;
-                       }
-break;
-case 32:
-#line 392 "parse.yacc"
-{
-                           SETMATCH(host_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 33:
-#line 395 "parse.yacc"
-{
-                           SETNMATCH(host_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 34:
-#line 400 "parse.yacc"
-{
-                           yyval.BOOLEAN = TRUE;
-                       }
-break;
-case 35:
-#line 403 "parse.yacc"
-{
-                           if (addr_matches(yyvsp[0].string))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           free(yyvsp[0].string);
-                       }
-break;
-case 36:
-#line 410 "parse.yacc"
-{
-                           if (netgr_matches(yyvsp[0].string, user_host, user_shost, NULL))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           free(yyvsp[0].string);
-                       }
-break;
-case 37:
-#line 417 "parse.yacc"
-{
-                           if (hostname_matches(user_shost, user_host, yyvsp[0].string) == 0)
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           free(yyvsp[0].string);
-                       }
-break;
-case 38:
-#line 424 "parse.yacc"
-{
-                           aliasinfo *aip = find_alias(yyvsp[0].string, HOST_ALIAS);
-
-                           /* could be an all-caps hostname */
-                           if (aip)
-                               yyval.BOOLEAN = aip->val;
-                           else if (strcasecmp(user_shost, yyvsp[0].string) == 0)
-                               yyval.BOOLEAN = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Host_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", yyvsp[0].string, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               yyval.BOOLEAN = NOMATCH;
-                           }
-                           free(yyvsp[0].string);
-                       }
-break;
-case 41:
-#line 452 "parse.yacc"
-{
-                           /*
-                            * Push the entry onto the stack if it is worth
-                            * saving and reset cmnd_matches for next cmnd.
-                            *
-                            * We need to save at least one entry on
-                            * the stack so sudoers_lookup() can tell that
-                            * the user was listed in sudoers.  Also, we
-                            * need to be able to tell whether or not a
-                            * user was listed for this specific host.
-                            *
-                            * If keepall is set and the user matches then
-                            * we need to keep entries around too...
-                            */
-                           if (MATCHED(user_matches) &&
-                               MATCHED(host_matches) &&
-                               MATCHED(cmnd_matches) &&
-                               MATCHED(runas_matches))
-                               pushcp;
-                           else if (MATCHED(user_matches) && (top == 1 ||
-                               (top == 2 && MATCHED(host_matches) &&
-                               !MATCHED(match[0].host))))
-                               pushcp;
-                           else if (user_matches == TRUE && keepall)
-                               pushcp;
-                           cmnd_matches = UNSPEC;
-                       }
-break;
-case 42:
-#line 481 "parse.yacc"
-{
-                           SETMATCH(cmnd_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 43:
-#line 484 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("!", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_cmnd("!", NULL);
-                           }
-                       }
-break;
-case 44:
-#line 492 "parse.yacc"
-{
-                           SETNMATCH(cmnd_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 45:
-#line 497 "parse.yacc"
-{
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE) {
-                               if (runas_matches == UNSPEC) {
-                                   cm_list[cm_list_len].runas_len = 0;
-                               } else {
-                                   /* Inherit runas data. */
-                                   cm_list[cm_list_len].runas =
-                                       estrdup(cm_list[cm_list_len-1].runas);
-                                   cm_list[cm_list_len].runas_len =
-                                       cm_list[cm_list_len-1].runas_len;
-                                   cm_list[cm_list_len].runas_size =
-                                       cm_list[cm_list_len-1].runas_size;
-                               }
-                           }
-                           /*
-                            * If this is the first entry in a command list
-                            * then check against default runas user.
-                            */
-                           if (runas_matches == UNSPEC) {
-                               runas_matches =
-                                   userpw_matches(def_runas_default,
-                                       *user_runas, runas_pw);
-                           }
-                       }
-break;
-case 46:
-#line 522 "parse.yacc"
-{
-                           runas_matches = yyvsp[0].BOOLEAN;
-                       }
-break;
-case 47:
-#line 527 "parse.yacc"
-{ ; }
-break;
-case 48:
-#line 528 "parse.yacc"
-{
-                           /* Later entries override earlier ones. */
-                           if (yyvsp[0].BOOLEAN != NOMATCH)
-                               yyval.BOOLEAN = yyvsp[0].BOOLEAN;
-                           else
-                               yyval.BOOLEAN = yyvsp[-2].BOOLEAN;
-                       }
-break;
-case 49:
-#line 537 "parse.yacc"
-{ ; }
-break;
-case 50:
-#line 538 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("!", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas("!", ", ");
-                           }
-                       }
-break;
-case 51:
-#line 546 "parse.yacc"
-{
-                           /* Set $$ to the negation of runasuser */
-                           yyval.BOOLEAN = (yyvsp[0].BOOLEAN == NOMATCH ? NOMATCH : ! yyvsp[0].BOOLEAN);
-                       }
-break;
-case 52:
-#line 552 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries(yyvsp[0].string, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas(yyvsp[0].string, ", ");
-                           }
-                           if (userpw_matches(yyvsp[0].string, *user_runas, runas_pw))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           free(yyvsp[0].string);
-                           used_runas = TRUE;
-                       }
-break;
-case 53:
-#line 567 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries(yyvsp[0].string, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas(yyvsp[0].string, ", ");
-                           }
-                           if (usergr_matches(yyvsp[0].string, *user_runas, runas_pw))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           free(yyvsp[0].string);
-                           used_runas = TRUE;
-                       }
-break;
-case 54:
-#line 582 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries(yyvsp[0].string, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas(yyvsp[0].string, ", ");
-                           }
-                           if (netgr_matches(yyvsp[0].string, NULL, NULL, *user_runas))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           free(yyvsp[0].string);
-                           used_runas = TRUE;
-                       }
-break;
-case 55:
-#line 597 "parse.yacc"
-{
-                           aliasinfo *aip = find_alias(yyvsp[0].string, RUNAS_ALIAS);
-
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries(yyvsp[0].string, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas(yyvsp[0].string, ", ");
-                           }
-                           /* could be an all-caps username */
-                           if (aip)
-                               yyval.BOOLEAN = aip->val;
-                           else if (strcmp(yyvsp[0].string, *user_runas) == 0)
-                               yyval.BOOLEAN = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Runas_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", yyvsp[0].string, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               yyval.BOOLEAN = NOMATCH;
-                           }
-                           free(yyvsp[0].string);
-                           used_runas = TRUE;
-                       }
-break;
-case 56:
-#line 627 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("ALL", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE)
-                                   append_runas("ALL", ", ");
-                           }
-                           yyval.BOOLEAN = TRUE;
-                       }
-break;
-case 57:
-#line 639 "parse.yacc"
-{
-                           /* Inherit tags. */
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE) {
-                               if (no_passwd == TRUE)
-                                   cm_list[cm_list_len].nopasswd = TRUE;
-                               else
-                                   cm_list[cm_list_len].nopasswd = FALSE;
-                               if (no_execve == TRUE)
-                                   cm_list[cm_list_len].noexecve = TRUE;
-                               else
-                                   cm_list[cm_list_len].noexecve = FALSE;
-                               if (monitor_cmnd == TRUE)
-                                   cm_list[cm_list_len].monitor = TRUE;
-                               else
-                                   cm_list[cm_list_len].monitor = FALSE;
-                           }
-                       }
-break;
-case 58:
-#line 657 "parse.yacc"
-{
-                           no_passwd = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].nopasswd = TRUE;
-                       }
-break;
-case 59:
-#line 663 "parse.yacc"
-{
-                           no_passwd = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].nopasswd = FALSE;
-                       }
-break;
-case 60:
-#line 669 "parse.yacc"
-{
-                           no_execve = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].noexecve = TRUE;
-                       }
-break;
-case 61:
-#line 675 "parse.yacc"
-{
-                           no_execve = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].noexecve = FALSE;
-                       }
-break;
-case 62:
-#line 681 "parse.yacc"
-{
-                           monitor_cmnd = TRUE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].monitor = TRUE;
-                       }
-break;
-case 63:
-#line 687 "parse.yacc"
-{
-                           monitor_cmnd = FALSE;
-                           if (printmatches == TRUE && host_matches == TRUE &&
-                               user_matches == TRUE)
-                               cm_list[cm_list_len].monitor = FALSE;
-                       }
-break;
-case 64:
-#line 695 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries("ALL", ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE) {
-                                   append_cmnd("ALL", NULL);
-                                   expand_match_list();
-                               }
-                           }
-
-                           yyval.BOOLEAN = TRUE;
-
-                           if (safe_cmnd)
-                               free(safe_cmnd);
-                           safe_cmnd = estrdup(user_cmnd);
-                       }
-break;
-case 65:
-#line 712 "parse.yacc"
-{
-                           aliasinfo *aip;
-
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE)
-                                   append_entries(yyvsp[0].string, ", ");
-                               else if (host_matches == TRUE &&
-                                   user_matches == TRUE) {
-                                   append_cmnd(yyvsp[0].string, NULL);
-                                   expand_match_list();
-                               }
-                           }
-
-                           if ((aip = find_alias(yyvsp[0].string, CMND_ALIAS)))
-                               yyval.BOOLEAN = aip->val;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared Cmnd_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", yyvsp[0].string, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               yyval.BOOLEAN = NOMATCH;
-                           }
-                           free(yyvsp[0].string);
-                       }
-break;
-case 66:
-#line 741 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               if (in_alias == TRUE) {
-                                   append_entries(yyvsp[0].command.cmnd, ", ");
-                                   if (yyvsp[0].command.args)
-                                       append_entries(yyvsp[0].command.args, " ");
-                               }
-                               if (host_matches == TRUE &&
-                                   user_matches == TRUE)  {
-                                   append_cmnd(yyvsp[0].command.cmnd, NULL);
-                                   if (yyvsp[0].command.args)
-                                       append_cmnd(yyvsp[0].command.args, " ");
-                                   expand_match_list();
-                               }
-                           }
-
-                           if (command_matches(yyvsp[0].command.cmnd, yyvsp[0].command.args))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-
-                           free(yyvsp[0].command.cmnd);
-                           if (yyvsp[0].command.args)
-                               free(yyvsp[0].command.args);
-                       }
-break;
-case 69:
-#line 772 "parse.yacc"
-{ push; }
-break;
-case 70:
-#line 772 "parse.yacc"
-{
-                           if ((MATCHED(host_matches) || pedantic) &&
-                               !add_alias(yyvsp[-3].string, HOST_ALIAS, host_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                       }
-break;
-case 75:
-#line 790 "parse.yacc"
-{
-                           push;
-                           if (printmatches == TRUE) {
-                               in_alias = TRUE;
-                               /* Allocate space for ga_list if necessary. */
-                               expand_ga_list();
-                               ga_list[ga_list_len-1].type = CMND_ALIAS;
-                               ga_list[ga_list_len-1].alias = estrdup(yyvsp[0].string);
-                            }
-                       }
-break;
-case 76:
-#line 799 "parse.yacc"
-{
-                           if ((MATCHED(cmnd_matches) || pedantic) &&
-                               !add_alias(yyvsp[-3].string, CMND_ALIAS, cmnd_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                           free(yyvsp[-3].string);
-
-                           if (printmatches == TRUE)
-                               in_alias = FALSE;
-                       }
-break;
-case 77:
-#line 813 "parse.yacc"
-{ ; }
-break;
-case 81:
-#line 821 "parse.yacc"
-{
-                           if (printmatches == TRUE) {
-                               in_alias = TRUE;
-                               /* Allocate space for ga_list if necessary. */
-                               expand_ga_list();
-                               ga_list[ga_list_len-1].type = RUNAS_ALIAS;
-                               ga_list[ga_list_len-1].alias = estrdup(yyvsp[0].string);
-                           }
-                       }
-break;
-case 82:
-#line 829 "parse.yacc"
-{
-                           if ((yyvsp[0].BOOLEAN != NOMATCH || pedantic) &&
-                               !add_alias(yyvsp[-3].string, RUNAS_ALIAS, yyvsp[0].BOOLEAN)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           free(yyvsp[-3].string);
-
-                           if (printmatches == TRUE)
-                               in_alias = FALSE;
-                       }
-break;
-case 85:
-#line 846 "parse.yacc"
-{ push; }
-break;
-case 86:
-#line 846 "parse.yacc"
-{
-                           if ((MATCHED(user_matches) || pedantic) &&
-                               !add_alias(yyvsp[-3].string, USER_ALIAS, user_matches)) {
-                               yyerror(NULL);
-                               YYERROR;
-                           }
-                           pop;
-                           free(yyvsp[-3].string);
-                       }
-break;
-case 89:
-#line 861 "parse.yacc"
-{
-                           SETMATCH(user_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 90:
-#line 864 "parse.yacc"
-{
-                           SETNMATCH(user_matches, yyvsp[0].BOOLEAN);
-                       }
-break;
-case 91:
-#line 869 "parse.yacc"
-{
-                           if (userpw_matches(yyvsp[0].string, user_name, sudo_user.pw))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           free(yyvsp[0].string);
-                       }
-break;
-case 92:
-#line 876 "parse.yacc"
-{
-                           if (usergr_matches(yyvsp[0].string, user_name, sudo_user.pw))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           free(yyvsp[0].string);
-                       }
-break;
-case 93:
-#line 883 "parse.yacc"
-{
-                           if (netgr_matches(yyvsp[0].string, NULL, NULL, user_name))
-                               yyval.BOOLEAN = TRUE;
-                           else
-                               yyval.BOOLEAN = NOMATCH;
-                           free(yyvsp[0].string);
-                       }
-break;
-case 94:
-#line 890 "parse.yacc"
-{
-                           aliasinfo *aip = find_alias(yyvsp[0].string, USER_ALIAS);
-
-                           /* could be an all-caps username */
-                           if (aip)
-                               yyval.BOOLEAN = aip->val;
-                           else if (strcmp(yyvsp[0].string, user_name) == 0)
-                               yyval.BOOLEAN = TRUE;
-                           else {
-                               if (pedantic) {
-                                   (void) fprintf(stderr,
-                                       "%s: undeclared User_Alias `%s' referenced near line %d\n",
-                                       (pedantic == 1) ? "Warning" : "Error", yyvsp[0].string, sudolineno);
-                                   if (pedantic > 1) {
-                                       yyerror(NULL);
-                                       YYERROR;
-                                   }
-                               }
-                               yyval.BOOLEAN = NOMATCH;
-                           }
-                           free(yyvsp[0].string);
-                       }
-break;
-case 95:
-#line 912 "parse.yacc"
-{
-                           yyval.BOOLEAN = TRUE;
-                       }
-break;
-#line 1961 "sudo.tab.c"
-    }
-    yyssp -= yym;
-    yystate = *yyssp;
-    yyvsp -= yym;
-    yym = yylhs[yyn];
-    if (yystate == 0 && yym == 0)
-    {
-#if YYDEBUG
-        if (yydebug)
-            printf("%sdebug: after reduction, shifting from state 0 to\
- state %d\n", YYPREFIX, YYFINAL);
-#endif
-        yystate = YYFINAL;
-        *++yyssp = YYFINAL;
-        *++yyvsp = yyval;
-        if (yychar < 0)
-        {
-            if ((yychar = yylex()) < 0) yychar = 0;
-#if YYDEBUG
-            if (yydebug)
-            {
-                yys = 0;
-                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
-                if (!yys) yys = "illegal-symbol";
-                printf("%sdebug: state %d, reading %d (%s)\n",
-                        YYPREFIX, YYFINAL, yychar, yys);
-            }
-#endif
-        }
-        if (yychar == 0) goto yyaccept;
-        goto yyloop;
-    }
-    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
-            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
-        yystate = yytable[yyn];
-    else
-        yystate = yydgoto[yym];
-#if YYDEBUG
-    if (yydebug)
-        printf("%sdebug: after reduction, shifting from state %d \
-to state %d\n", YYPREFIX, *yyssp, yystate);
-#endif
-    if (yyssp >= yysslim && yygrowstack())
-    {
-        goto yyoverflow;
-    }
-    *++yyssp = yystate;
-    *++yyvsp = yyval;
-    goto yyloop;
-yyoverflow:
-    yyerror("yacc stack overflow");
-yyabort:
-    if (yyss)
-            free(yyss);
-    if (yyvs)
-            free(yyvs);
-    yyss = yyssp = NULL;
-    yyvs = yyvsp = NULL;
-    yystacksize = 0;
-    return (1);
-yyaccept:
-    if (yyss)
-            free(yyss);
-    if (yyvs)
-            free(yyvs);
-    yyss = yyssp = NULL;
-    yyvs = yyvsp = NULL;
-    yystacksize = 0;
-    return (0);
-}