From 5becc03851b88caadb507a6c334c97997c33c7e3 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 26 Oct 2004 22:10:55 +0000 Subject: [PATCH] Rewritten parser that converts sudoers into a set of data structures. This eliminates ordering issues and makes it possible to apply sudoers Defaults entries before searching for the command. --- gram.c | 1454 +++++++++++++++++++++++++++++ sudo.tab.h => gram.h | 9 +- gram.y | 674 ++++++++++++++ parse.c | 601 +++--------- parse.h | 184 ++-- parse.yacc | 1285 -------------------------- sudo.tab.c | 2082 ------------------------------------------ 7 files changed, 2404 insertions(+), 3885 deletions(-) create mode 100644 gram.c rename sudo.tab.h => gram.h (80%) create mode 100644 gram.y delete mode 100644 parse.yacc delete mode 100644 sudo.tab.c diff --git a/gram.c b/gram.c new file mode 100644 index 000000000..74b2980b2 --- /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 +#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 + * + * 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 +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif /* HAVE_STRING_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ +#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) +# include +#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); +} diff --git a/sudo.tab.h b/gram.h similarity index 80% rename from sudo.tab.h rename to gram.h index e4ade693f..95b364130 100644 --- a/sudo.tab.h +++ b/gram.h @@ -26,9 +26,14 @@ #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 index 000000000..71005f3a1 --- /dev/null +++ b/gram.y @@ -0,0 +1,674 @@ +%{ +/* + * Copyright (c) 1996, 1998-2004 Todd C. Miller + * + * 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 +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif /* HAVE_STRING_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ +#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) +# include +#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 /* absolute pathname w/ optional args */ +%token ALIAS /* an UPPERCASE alias name */ +%token DEFVAR /* a Defaults variable name */ +%token NTWKADDR /* w.x.y.z */ +%token NETGROUP /* a netgroup (+NAME) */ +%token USERGROUP /* a usergroup (%NAME) */ +%token WORD /* a word */ +%token DEFAULTS /* Defaults entry */ +%token DEFAULTS_HOST /* Host-specific defaults entry */ +%token DEFAULTS_USER /* User-specific defaults entry */ +%token DEFAULTS_RUNAS /* Runas-specific defaults entry */ +%token RUNAS /* ( runas_list ) */ +%token NOPASSWD /* no passwd req for command */ +%token PASSWD /* passwd req for command (default) */ +%token NOEXEC /* preload dummy execve() for cmnd */ +%token EXEC /* don't preload dummy execve() */ +%token MONITOR /* monitor children of cmnd */ +%token NOMONITOR /* disable monitoring of children */ +%token ALL /* ALL keyword */ +%token COMMENT /* comment and/or carriage return */ +%token HOSTALIAS /* Host_Alias keyword */ +%token CMNDALIAS /* Cmnd_Alias keyword */ +%token USERALIAS /* User_Alias keyword */ +%token RUNASALIAS /* Runas_Alias keyword */ +%token ':' '=' ',' '!' '+' '-' /* union member tokens */ +%token ERROR + +%type cmndalias +%type cmndaliases +%type hostalias +%type hostaliases +%type runasalias +%type runasaliases +%type useralias +%type useraliases +%type cmndspec +%type cmndspeclist +%type defaults_entry +%type defaults_list +%type cmnd +%type opcmnd +%type cmndlist +%type host +%type hostlist +%type ophost +%type oprunasuser +%type opuser +%type runaslist +%type runasspec +%type runasuser +%type user +%type userlist +%type privilege +%type privileges +%type 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 07145a3f0..50ccd976e 100644 --- a/parse.c +++ b/parse.c @@ -24,7 +24,6 @@ #include #include -#include #include #ifdef STDC_HEADERS # include @@ -44,526 +43,204 @@ #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ -#ifdef HAVE_FNMATCH -# include -#endif /* HAVE_FNMATCH */ -#ifdef HAVE_EXTENDED_GLOB -# include -#endif /* HAVE_EXTENDED_GLOB */ -#ifdef HAVE_NETGROUP_H -# include -#endif /* HAVE_NETGROUP_H */ #include #include -#include -#include -#include -#include -#ifdef HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# 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 c5ad4e0a7..6a5df80f6 100644 --- a/parse.h +++ b/parse.h @@ -19,88 +19,164 @@ #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 index fe465d0e1..000000000 --- a/parse.yacc +++ /dev/null @@ -1,1285 +0,0 @@ -%{ -/* - * Copyright (c) 1996, 1998-2004 Todd C. Miller - * - * 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 -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ -#ifdef HAVE_STRING_H -# include -#else -# ifdef HAVE_STRINGS_H -# include -# endif -#endif /* HAVE_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) -# include -#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ -#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) -# include -#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */ -#ifdef HAVE_LSEARCH -# include -#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 /* absolute pathname w/ optional args */ -%token ALIAS /* an UPPERCASE alias name */ -%token DEFVAR /* a Defaults variable name */ -%token NTWKADDR /* w.x.y.z */ -%token NETGROUP /* a netgroup (+NAME) */ -%token USERGROUP /* a usergroup (%NAME) */ -%token WORD /* a word */ -%token DEFAULTS /* Defaults entry */ -%token DEFAULTS_HOST /* Host-specific defaults entry */ -%token DEFAULTS_USER /* User-specific defaults entry */ -%token DEFAULTS_RUNAS /* Runas-specific defaults entry */ -%token RUNAS /* ( runas_list ) */ -%token NOPASSWD /* no passwd req for command */ -%token PASSWD /* passwd req for command (default) */ -%token NOEXEC /* preload dummy execve() for cmnd */ -%token EXEC /* don't preload dummy execve() */ -%token MONITOR /* monitor children of cmnd */ -%token NOMONITOR /* disable monitoring of children */ -%token ALL /* ALL keyword */ -%token COMMENT /* comment and/or carriage return */ -%token HOSTALIAS /* Host_Alias keyword */ -%token CMNDALIAS /* Cmnd_Alias keyword */ -%token USERALIAS /* User_Alias keyword */ -%token RUNASALIAS /* Runas_Alias keyword */ -%token ':' '=' ',' '!' '+' '-' /* union member tokens */ -%token 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 cmnd -%type host -%type runasuser -%type oprunasuser -%type runaslist -%type 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 index dc1092010..000000000 --- a/sudo.tab.c +++ /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 -#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 - * - * 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 -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ -#ifdef HAVE_STRING_H -# include -#else -# ifdef HAVE_STRINGS_H -# include -# endif -#endif /* HAVE_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) -# include -#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ -#if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) -# include -#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */ -#ifdef HAVE_LSEARCH -# include -#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); -} -- 2.50.1