File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers / gram.y
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 10:46:12 2013 UTC (10 years, 11 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_8p0, v1_8_8, v1_8_7p0, v1_8_7, HEAD
1.8.7

    1: %{
    2: /*
    3:  * Copyright (c) 1996, 1998-2005, 2007-2013
    4:  *	Todd C. Miller <Todd.Miller@courtesan.com>
    5:  *
    6:  * Permission to use, copy, modify, and distribute this software for any
    7:  * purpose with or without fee is hereby granted, provided that the above
    8:  * copyright notice and this permission notice appear in all copies.
    9:  *
   10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   18:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   19:  *
   20:  * Sponsored in part by the Defense Advanced Research Projects
   21:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
   22:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
   23:  */
   24: 
   25: #include <config.h>
   26: 
   27: #include <sys/types.h>
   28: #include <stdio.h>
   29: #ifdef STDC_HEADERS
   30: # include <stdlib.h>
   31: # include <stddef.h>
   32: #else
   33: # ifdef HAVE_STDLIB_H
   34: #  include <stdlib.h>
   35: # endif
   36: #endif /* STDC_HEADERS */
   37: #ifdef HAVE_STRING_H
   38: # include <string.h>
   39: #endif /* HAVE_STRING_H */
   40: #ifdef HAVE_STRINGS_H
   41: # include <strings.h>
   42: #endif /* HAVE_STRINGS_H */
   43: #ifdef HAVE_UNISTD_H
   44: # include <unistd.h>
   45: #endif /* HAVE_UNISTD_H */
   46: #ifdef HAVE_INTTYPES_H
   47: # include <inttypes.h>
   48: #endif
   49: #if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
   50: # include <alloca.h>
   51: #endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
   52: #include <limits.h>
   53: 
   54: #include "sudoers.h" /* XXX */
   55: #include "parse.h"
   56: #include "toke.h"
   57: 
   58: /*
   59:  * We must define SIZE_MAX for yacc's skeleton.c.
   60:  * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
   61:  * could be signed (as it is on SunOS 4.x).
   62:  */
   63: #ifndef SIZE_MAX
   64: # ifdef SIZE_T_MAX
   65: #  define SIZE_MAX	SIZE_T_MAX
   66: # else
   67: #  define SIZE_MAX	INT_MAX
   68: # endif /* SIZE_T_MAX */
   69: #endif /* SIZE_MAX */
   70: 
   71: /*
   72:  * Globals
   73:  */
   74: extern int sudolineno;
   75: extern int last_token;
   76: extern char *sudoers;
   77: bool sudoers_warnings = true;
   78: bool parse_error = false;
   79: int errorlineno = -1;
   80: char *errorfile = NULL;
   81: 
   82: struct defaults_list defaults;
   83: struct userspec_list userspecs;
   84: 
   85: /*
   86:  * Local protoypes
   87:  */
   88: static void  add_defaults(int, struct member *, struct defaults *);
   89: static void  add_userspec(struct member *, struct privilege *);
   90: static struct defaults *new_default(char *, char *, int);
   91: static struct member *new_member(char *, int);
   92: static struct sudo_digest *new_digest(int, const char *);
   93: %}
   94: 
   95: %union {
   96:     struct cmndspec *cmndspec;
   97:     struct defaults *defaults;
   98:     struct member *member;
   99:     struct runascontainer *runas;
  100:     struct privilege *privilege;
  101:     struct sudo_digest *digest;
  102:     struct sudo_command command;
  103:     struct cmndtag tag;
  104:     struct selinux_info seinfo;
  105:     struct solaris_privs_info privinfo;
  106:     char *string;
  107:     int tok;
  108: }
  109: 
  110: %start file				/* special start symbol */
  111: %token <command> COMMAND		/* absolute pathname w/ optional args */
  112: %token <string>  ALIAS			/* an UPPERCASE alias name */
  113: %token <string>	 DEFVAR			/* a Defaults variable name */
  114: %token <string>  NTWKADDR		/* ipv4 or ipv6 address */
  115: %token <string>  NETGROUP		/* a netgroup (+NAME) */
  116: %token <string>  USERGROUP		/* a usergroup (%NAME) */
  117: %token <string>  WORD			/* a word */
  118: %token <string>  DIGEST			/* a SHA-2 digest */
  119: %token <tok>	 DEFAULTS		/* Defaults entry */
  120: %token <tok>	 DEFAULTS_HOST		/* Host-specific defaults entry */
  121: %token <tok>	 DEFAULTS_USER		/* User-specific defaults entry */
  122: %token <tok>	 DEFAULTS_RUNAS		/* Runas-specific defaults entry */
  123: %token <tok>	 DEFAULTS_CMND		/* Command-specific defaults entry */
  124: %token <tok> 	 NOPASSWD		/* no passwd req for command */
  125: %token <tok> 	 PASSWD			/* passwd req for command (default) */
  126: %token <tok> 	 NOEXEC			/* preload dummy execve() for cmnd */
  127: %token <tok> 	 EXEC			/* don't preload dummy execve() */
  128: %token <tok>	 SETENV			/* user may set environment for cmnd */
  129: %token <tok>	 NOSETENV		/* user may not set environment */
  130: %token <tok>	 LOG_INPUT		/* log user's cmnd input */
  131: %token <tok>	 NOLOG_INPUT		/* don't log user's cmnd input */
  132: %token <tok>	 LOG_OUTPUT		/* log cmnd output */
  133: %token <tok>	 NOLOG_OUTPUT		/* don't log cmnd output */
  134: %token <tok>	 ALL			/* ALL keyword */
  135: %token <tok>	 COMMENT		/* comment and/or carriage return */
  136: %token <tok>	 HOSTALIAS		/* Host_Alias keyword */
  137: %token <tok>	 CMNDALIAS		/* Cmnd_Alias keyword */
  138: %token <tok>	 USERALIAS		/* User_Alias keyword */
  139: %token <tok>	 RUNASALIAS		/* Runas_Alias keyword */
  140: %token <tok>	 ':' '=' ',' '!' '+' '-' /* union member tokens */
  141: %token <tok>	 '(' ')'		/* runas tokens */
  142: %token <tok>	 ERROR
  143: %token <tok>	 TYPE			/* SELinux type */
  144: %token <tok>	 ROLE			/* SELinux role */
  145: %token <tok>	 PRIVS			/* Solaris privileges */
  146: %token <tok>	 LIMITPRIVS		/* Solaris limit privileges */
  147: %token <tok>	 MYSELF			/* run as myself, not another user */
  148: %token <tok>	 SHA224			/* sha224 digest */
  149: %token <tok>	 SHA256			/* sha256 digest */
  150: %token <tok>	 SHA384			/* sha384 digest */
  151: %token <tok>	 SHA512			/* sha512 digest */
  152: 
  153: %type <cmndspec>  cmndspec
  154: %type <cmndspec>  cmndspeclist
  155: %type <defaults>  defaults_entry
  156: %type <defaults>  defaults_list
  157: %type <member>	  cmnd
  158: %type <member>	  opcmnd
  159: %type <member>	  digcmnd
  160: %type <member>	  cmndlist
  161: %type <member>	  host
  162: %type <member>	  hostlist
  163: %type <member>	  ophost
  164: %type <member>	  opuser
  165: %type <member>	  user
  166: %type <member>	  userlist
  167: %type <member>	  opgroup
  168: %type <member>	  group
  169: %type <member>	  grouplist
  170: %type <runas>	  runasspec
  171: %type <runas>	  runaslist
  172: %type <privilege> privilege
  173: %type <privilege> privileges
  174: %type <tag>	  cmndtag
  175: %type <seinfo>	  selinux
  176: %type <string>	  rolespec
  177: %type <string>	  typespec
  178: %type <privinfo>  solarisprivs
  179: %type <string>	  privsspec
  180: %type <string>	  limitprivsspec
  181: %type <digest>	  digest
  182: 
  183: %%
  184: 
  185: file		:	{ ; }
  186: 		|	line
  187: 		;
  188: 
  189: line		:	entry
  190: 		|	line entry
  191: 		;
  192: 
  193: entry		:	COMMENT {
  194: 			    ;
  195: 			}
  196:                 |       error COMMENT {
  197: 			    yyerrok;
  198: 			}
  199: 		|	userlist privileges {
  200: 			    add_userspec($1, $2);
  201: 			}
  202: 		|	USERALIAS useraliases {
  203: 			    ;
  204: 			}
  205: 		|	HOSTALIAS hostaliases {
  206: 			    ;
  207: 			}
  208: 		|	CMNDALIAS cmndaliases {
  209: 			    ;
  210: 			}
  211: 		|	RUNASALIAS runasaliases {
  212: 			    ;
  213: 			}
  214: 		|	DEFAULTS defaults_list {
  215: 			    add_defaults(DEFAULTS, NULL, $2);
  216: 			}
  217: 		|	DEFAULTS_USER userlist defaults_list {
  218: 			    add_defaults(DEFAULTS_USER, $2, $3);
  219: 			}
  220: 		|	DEFAULTS_RUNAS userlist defaults_list {
  221: 			    add_defaults(DEFAULTS_RUNAS, $2, $3);
  222: 			}
  223: 		|	DEFAULTS_HOST hostlist defaults_list {
  224: 			    add_defaults(DEFAULTS_HOST, $2, $3);
  225: 			}
  226: 		|	DEFAULTS_CMND cmndlist defaults_list {
  227: 			    add_defaults(DEFAULTS_CMND, $2, $3);
  228: 			}
  229: 		;
  230: 
  231: defaults_list	:	defaults_entry
  232: 		|	defaults_list ',' defaults_entry {
  233: 			    list_append($1, $3);
  234: 			    $$ = $1;
  235: 			}
  236: 		;
  237: 
  238: defaults_entry	:	DEFVAR {
  239: 			    $$ = new_default($1, NULL, true);
  240: 			}
  241: 		|	'!' DEFVAR {
  242: 			    $$ = new_default($2, NULL, false);
  243: 			}
  244: 		|	DEFVAR '=' WORD {
  245: 			    $$ = new_default($1, $3, true);
  246: 			}
  247: 		|	DEFVAR '+' WORD {
  248: 			    $$ = new_default($1, $3, '+');
  249: 			}
  250: 		|	DEFVAR '-' WORD {
  251: 			    $$ = new_default($1, $3, '-');
  252: 			}
  253: 		;
  254: 
  255: privileges	:	privilege
  256: 		|	privileges ':' privilege {
  257: 			    list_append($1, $3);
  258: 			    $$ = $1;
  259: 			}
  260: 		;
  261: 
  262: privilege	:	hostlist '=' cmndspeclist {
  263: 			    struct privilege *p = ecalloc(1, sizeof(*p));
  264: 			    list2tq(&p->hostlist, $1);
  265: 			    list2tq(&p->cmndlist, $3);
  266: 			    p->prev = p;
  267: 			    /* p->next = NULL; */
  268: 			    $$ = p;
  269: 			}
  270: 		;
  271: 
  272: ophost		:	host {
  273: 			    $$ = $1;
  274: 			    $$->negated = false;
  275: 			}
  276: 		|	'!' host {
  277: 			    $$ = $2;
  278: 			    $$->negated = true;
  279: 			}
  280: 		;
  281: 
  282: host		:	ALIAS {
  283: 			    $$ = new_member($1, ALIAS);
  284: 			}
  285: 		|	ALL {
  286: 			    $$ = new_member(NULL, ALL);
  287: 			}
  288: 		|	NETGROUP {
  289: 			    $$ = new_member($1, NETGROUP);
  290: 			}
  291: 		|	NTWKADDR {
  292: 			    $$ = new_member($1, NTWKADDR);
  293: 			}
  294: 		|	WORD {
  295: 			    $$ = new_member($1, WORD);
  296: 			}
  297: 		;
  298: 
  299: cmndspeclist	:	cmndspec
  300: 		|	cmndspeclist ',' cmndspec {
  301: 			    list_append($1, $3);
  302: #ifdef HAVE_SELINUX
  303: 			    /* propagate role and type */
  304: 			    if ($3->role == NULL)
  305: 				$3->role = $3->prev->role;
  306: 			    if ($3->type == NULL)
  307: 				$3->type = $3->prev->type;
  308: #endif /* HAVE_SELINUX */
  309: #ifdef HAVE_PRIV_SET
  310: 			    /* propagate privs & limitprivs */
  311: 			    if ($3->privs == NULL)
  312: 			        $3->privs = $3->prev->privs;
  313: 			    if ($3->limitprivs == NULL)
  314: 			        $3->limitprivs = $3->prev->limitprivs;
  315: #endif /* HAVE_PRIV_SET */
  316: 			    /* propagate tags and runas list */
  317: 			    if ($3->tags.nopasswd == UNSPEC)
  318: 				$3->tags.nopasswd = $3->prev->tags.nopasswd;
  319: 			    if ($3->tags.noexec == UNSPEC)
  320: 				$3->tags.noexec = $3->prev->tags.noexec;
  321: 			    if ($3->tags.setenv == UNSPEC &&
  322: 				$3->prev->tags.setenv != IMPLIED)
  323: 				$3->tags.setenv = $3->prev->tags.setenv;
  324: 			    if ($3->tags.log_input == UNSPEC)
  325: 				$3->tags.log_input = $3->prev->tags.log_input;
  326: 			    if ($3->tags.log_output == UNSPEC)
  327: 				$3->tags.log_output = $3->prev->tags.log_output;
  328: 			    if ((tq_empty(&$3->runasuserlist) &&
  329: 				 tq_empty(&$3->runasgrouplist)) &&
  330: 				(!tq_empty(&$3->prev->runasuserlist) ||
  331: 				 !tq_empty(&$3->prev->runasgrouplist))) {
  332: 				$3->runasuserlist = $3->prev->runasuserlist;
  333: 				$3->runasgrouplist = $3->prev->runasgrouplist;
  334: 			    }
  335: 			    $$ = $1;
  336: 			}
  337: 		;
  338: 
  339: cmndspec	:	runasspec selinux solarisprivs cmndtag digcmnd {
  340: 			    struct cmndspec *cs = ecalloc(1, sizeof(*cs));
  341: 			    if ($1 != NULL) {
  342: 				list2tq(&cs->runasuserlist, $1->runasusers);
  343: 				list2tq(&cs->runasgrouplist, $1->runasgroups);
  344: 				efree($1);
  345: 			    } else {
  346: 				tq_init(&cs->runasuserlist);
  347: 				tq_init(&cs->runasgrouplist);
  348: 			    }
  349: #ifdef HAVE_SELINUX
  350: 			    cs->role = $2.role;
  351: 			    cs->type = $2.type;
  352: #endif
  353: #ifdef HAVE_PRIV_SET
  354: 			    cs->privs = $3.privs;
  355: 			    cs->limitprivs = $3.limitprivs;
  356: #endif
  357: 			    cs->tags = $4;
  358: 			    cs->cmnd = $5;
  359: 			    cs->prev = cs;
  360: 			    cs->next = NULL;
  361: 			    /* sudo "ALL" implies the SETENV tag */
  362: 			    if (cs->cmnd->type == ALL && !cs->cmnd->negated &&
  363: 				cs->tags.setenv == UNSPEC)
  364: 				cs->tags.setenv = IMPLIED;
  365: 			    $$ = cs;
  366: 			}
  367: 		;
  368: 
  369: digest		:	SHA224 ':' DIGEST {
  370: 			    $$ = new_digest(SUDO_DIGEST_SHA224, $3);
  371: 			}
  372: 		|	SHA256 ':' DIGEST {
  373: 			    $$ = new_digest(SUDO_DIGEST_SHA256, $3);
  374: 			}
  375: 		|	SHA384 ':' DIGEST {
  376: 			    $$ = new_digest(SUDO_DIGEST_SHA384, $3);
  377: 			}
  378: 		|	SHA512 ':' DIGEST {
  379: 			    $$ = new_digest(SUDO_DIGEST_SHA512, $3);
  380: 			}
  381: 		;
  382: 
  383: digcmnd		:	opcmnd {
  384: 			    $$ = $1;
  385: 			}
  386: 		|	digest opcmnd {
  387: 			    /* XXX - yuck */
  388: 			    struct sudo_command *c = (struct sudo_command *)($2->name);
  389: 			    c->digest = $1;
  390: 			    $$ = $2;
  391: 			}
  392: 		;
  393: 
  394: opcmnd		:	cmnd {
  395: 			    $$ = $1;
  396: 			    $$->negated = false;
  397: 			}
  398: 		|	'!' cmnd {
  399: 			    $$ = $2;
  400: 			    $$->negated = true;
  401: 			}
  402: 		;
  403: 
  404: rolespec	:	ROLE '=' WORD {
  405: 			    $$ = $3;
  406: 			}
  407: 		;
  408: 
  409: typespec	:	TYPE '=' WORD {
  410: 			    $$ = $3;
  411: 			}
  412: 		;
  413: 
  414: selinux		:	/* empty */ {
  415: 			    $$.role = NULL;
  416: 			    $$.type = NULL;
  417: 			}
  418: 		|	rolespec {
  419: 			    $$.role = $1;
  420: 			    $$.type = NULL;
  421: 			}
  422: 		|	typespec {
  423: 			    $$.type = $1;
  424: 			    $$.role = NULL;
  425: 			}
  426: 		|	rolespec typespec {
  427: 			    $$.role = $1;
  428: 			    $$.type = $2;
  429: 			}
  430: 		|	typespec rolespec {
  431: 			    $$.type = $1;
  432: 			    $$.role = $2;
  433: 			}
  434: 		;
  435: 
  436: privsspec	:	PRIVS '=' WORD {
  437: 			    $$ = $3;
  438: 			}
  439: 		;
  440: limitprivsspec	:	LIMITPRIVS '=' WORD {
  441: 			    $$ = $3;
  442: 			}
  443: 		;
  444: 
  445: solarisprivs	:	/* empty */ {
  446: 			    $$.privs = NULL;
  447: 			    $$.limitprivs = NULL;
  448: 			}
  449: 		|	privsspec {
  450: 			    $$.privs = $1;
  451: 			    $$.limitprivs = NULL;
  452: 			}
  453: 		|	limitprivsspec {
  454: 			    $$.privs = NULL;
  455: 			    $$.limitprivs = $1;
  456: 			}
  457: 		|	privsspec limitprivsspec {
  458: 			    $$.privs = $1;
  459: 			    $$.limitprivs = $2;
  460: 			}
  461: 		|	limitprivsspec privsspec {
  462: 			    $$.limitprivs = $1;
  463: 			    $$.privs = $2;
  464: 			}
  465: 		;
  466: 
  467: runasspec	:	/* empty */ {
  468: 			    $$ = NULL;
  469: 			}
  470: 		|	'(' runaslist ')' {
  471: 			    $$ = $2;
  472: 			}
  473: 		;
  474: 
  475: runaslist	:	/* empty */ {
  476: 			    $$ = ecalloc(1, sizeof(struct runascontainer));
  477: 			    $$->runasusers = new_member(NULL, MYSELF);
  478: 			    /* $$->runasgroups = NULL; */
  479: 			}
  480: 		|	userlist {
  481: 			    $$ = ecalloc(1, sizeof(struct runascontainer));
  482: 			    $$->runasusers = $1;
  483: 			    /* $$->runasgroups = NULL; */
  484: 			}
  485: 		|	userlist ':' grouplist {
  486: 			    $$ = ecalloc(1, sizeof(struct runascontainer));
  487: 			    $$->runasusers = $1;
  488: 			    $$->runasgroups = $3;
  489: 			}
  490: 		|	':' grouplist {
  491: 			    $$ = ecalloc(1, sizeof(struct runascontainer));
  492: 			    /* $$->runasusers = NULL; */
  493: 			    $$->runasgroups = $2;
  494: 			}
  495: 		|	':' {
  496: 			    $$ = ecalloc(1, sizeof(struct runascontainer));
  497: 			    $$->runasusers = new_member(NULL, MYSELF);
  498: 			    /* $$->runasgroups = NULL; */
  499: 			}
  500: 		;
  501: 
  502: cmndtag		:	/* empty */ {
  503: 			    $$.nopasswd = $$.noexec = $$.setenv =
  504: 				$$.log_input = $$.log_output = UNSPEC;
  505: 			}
  506: 		|	cmndtag NOPASSWD {
  507: 			    $$.nopasswd = true;
  508: 			}
  509: 		|	cmndtag PASSWD {
  510: 			    $$.nopasswd = false;
  511: 			}
  512: 		|	cmndtag NOEXEC {
  513: 			    $$.noexec = true;
  514: 			}
  515: 		|	cmndtag EXEC {
  516: 			    $$.noexec = false;
  517: 			}
  518: 		|	cmndtag SETENV {
  519: 			    $$.setenv = true;
  520: 			}
  521: 		|	cmndtag NOSETENV {
  522: 			    $$.setenv = false;
  523: 			}
  524: 		|	cmndtag LOG_INPUT {
  525: 			    $$.log_input = true;
  526: 			}
  527: 		|	cmndtag NOLOG_INPUT {
  528: 			    $$.log_input = false;
  529: 			}
  530: 		|	cmndtag LOG_OUTPUT {
  531: 			    $$.log_output = true;
  532: 			}
  533: 		|	cmndtag NOLOG_OUTPUT {
  534: 			    $$.log_output = false;
  535: 			}
  536: 		;
  537: 
  538: cmnd		:	ALL {
  539: 			    $$ = new_member(NULL, ALL);
  540: 			}
  541: 		|	ALIAS {
  542: 			    $$ = new_member($1, ALIAS);
  543: 			}
  544: 		|	COMMAND {
  545: 			    struct sudo_command *c = ecalloc(1, sizeof(*c));
  546: 			    c->cmnd = $1.cmnd;
  547: 			    c->args = $1.args;
  548: 			    $$ = new_member((char *)c, COMMAND);
  549: 			}
  550: 		;
  551: 
  552: hostaliases	:	hostalias
  553: 		|	hostaliases ':' hostalias
  554: 		;
  555: 
  556: hostalias	:	ALIAS '=' hostlist {
  557: 			    char *s;
  558: 			    if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) {
  559: 				sudoerserror(s);
  560: 				YYERROR;
  561: 			    }
  562: 			}
  563: 		;
  564: 
  565: hostlist	:	ophost
  566: 		|	hostlist ',' ophost {
  567: 			    list_append($1, $3);
  568: 			    $$ = $1;
  569: 			}
  570: 		;
  571: 
  572: cmndaliases	:	cmndalias
  573: 		|	cmndaliases ':' cmndalias
  574: 		;
  575: 
  576: cmndalias	:	ALIAS '=' cmndlist {
  577: 			    char *s;
  578: 			    if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) {
  579: 				sudoerserror(s);
  580: 				YYERROR;
  581: 			    }
  582: 			}
  583: 		;
  584: 
  585: cmndlist	:	digcmnd
  586: 		|	cmndlist ',' digcmnd {
  587: 			    list_append($1, $3);
  588: 			    $$ = $1;
  589: 			}
  590: 		;
  591: 
  592: runasaliases	:	runasalias
  593: 		|	runasaliases ':' runasalias
  594: 		;
  595: 
  596: runasalias	:	ALIAS '=' userlist {
  597: 			    char *s;
  598: 			    if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) {
  599: 				sudoerserror(s);
  600: 				YYERROR;
  601: 			    }
  602: 			}
  603: 		;
  604: 
  605: useraliases	:	useralias
  606: 		|	useraliases ':' useralias
  607: 		;
  608: 
  609: useralias	:	ALIAS '=' userlist {
  610: 			    char *s;
  611: 			    if ((s = alias_add($1, USERALIAS, $3)) != NULL) {
  612: 				sudoerserror(s);
  613: 				YYERROR;
  614: 			    }
  615: 			}
  616: 		;
  617: 
  618: userlist	:	opuser
  619: 		|	userlist ',' opuser {
  620: 			    list_append($1, $3);
  621: 			    $$ = $1;
  622: 			}
  623: 		;
  624: 
  625: opuser		:	user {
  626: 			    $$ = $1;
  627: 			    $$->negated = false;
  628: 			}
  629: 		|	'!' user {
  630: 			    $$ = $2;
  631: 			    $$->negated = true;
  632: 			}
  633: 		;
  634: 
  635: user		:	ALIAS {
  636: 			    $$ = new_member($1, ALIAS);
  637: 			}
  638: 		|	ALL {
  639: 			    $$ = new_member(NULL, ALL);
  640: 			}
  641: 		|	NETGROUP {
  642: 			    $$ = new_member($1, NETGROUP);
  643: 			}
  644: 		|	USERGROUP {
  645: 			    $$ = new_member($1, USERGROUP);
  646: 			}
  647: 		|	WORD {
  648: 			    $$ = new_member($1, WORD);
  649: 			}
  650: 		;
  651: 
  652: grouplist	:	opgroup
  653: 		|	grouplist ',' opgroup {
  654: 			    list_append($1, $3);
  655: 			    $$ = $1;
  656: 			}
  657: 		;
  658: 
  659: opgroup		:	group {
  660: 			    $$ = $1;
  661: 			    $$->negated = false;
  662: 			}
  663: 		|	'!' group {
  664: 			    $$ = $2;
  665: 			    $$->negated = true;
  666: 			}
  667: 		;
  668: 
  669: group		:	ALIAS {
  670: 			    $$ = new_member($1, ALIAS);
  671: 			}
  672: 		|	ALL {
  673: 			    $$ = new_member(NULL, ALL);
  674: 			}
  675: 		|	WORD {
  676: 			    $$ = new_member($1, WORD);
  677: 			}
  678: 		;
  679: 
  680: %%
  681: void
  682: sudoerserror(const char *s)
  683: {
  684:     debug_decl(sudoerserror, SUDO_DEBUG_PARSER)
  685: 
  686:     /* If we last saw a newline the error is on the preceding line. */
  687:     if (last_token == COMMENT)
  688: 	sudolineno--;
  689: 
  690:     /* Save the line the first error occurred on. */
  691:     if (errorlineno == -1) {
  692: 	errorlineno = sudolineno;
  693: 	errorfile = estrdup(sudoers);
  694:     }
  695:     if (sudoers_warnings && s != NULL) {
  696: 	LEXTRACE("<*> ");
  697: #ifndef TRACELEXER
  698: 	if (trace_print == NULL || trace_print == sudoers_trace_print) {
  699: 	    const char fmt[] = ">>> %s: %s near line %d <<<\n";
  700: 	    int oldlocale;
  701: 
  702: 	    /* Warnings are displayed in the user's locale. */
  703: 	    sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale);
  704: 	    sudo_printf(SUDO_CONV_ERROR_MSG, _(fmt), sudoers, _(s), sudolineno);
  705: 	    sudoers_setlocale(oldlocale, NULL);
  706: 	}
  707: #endif
  708:     }
  709:     parse_error = true;
  710:     debug_return;
  711: }
  712: 
  713: static struct defaults *
  714: new_default(char *var, char *val, int op)
  715: {
  716:     struct defaults *d;
  717:     debug_decl(new_default, SUDO_DEBUG_PARSER)
  718: 
  719:     d = ecalloc(1, sizeof(struct defaults));
  720:     d->var = var;
  721:     d->val = val;
  722:     tq_init(&d->binding);
  723:     /* d->type = 0; */
  724:     d->op = op;
  725:     d->prev = d;
  726:     /* d->next = NULL; */
  727: 
  728:     debug_return_ptr(d);
  729: }
  730: 
  731: static struct member *
  732: new_member(char *name, int type)
  733: {
  734:     struct member *m;
  735:     debug_decl(new_member, SUDO_DEBUG_PARSER)
  736: 
  737:     m = ecalloc(1, sizeof(struct member));
  738:     m->name = name;
  739:     m->type = type;
  740:     m->prev = m;
  741:     /* m->next = NULL; */
  742: 
  743:     debug_return_ptr(m);
  744: }
  745: 
  746: struct sudo_digest *
  747: new_digest(int digest_type, const char *digest_str)
  748: {
  749:     struct sudo_digest *dig;
  750:     debug_decl(new_digest, SUDO_DEBUG_PARSER)
  751: 
  752:     dig = emalloc(sizeof(*dig));
  753:     dig->digest_type = digest_type;
  754:     dig->digest_str = estrdup(digest_str);
  755: 
  756:     debug_return_ptr(dig);
  757: }
  758: 
  759: /*
  760:  * Add a list of defaults structures to the defaults list.
  761:  * The binding, if non-NULL, specifies a list of hosts, users, or
  762:  * runas users the entries apply to (specified by the type).
  763:  */
  764: static void
  765: add_defaults(int type, struct member *bmem, struct defaults *defs)
  766: {
  767:     struct defaults *d;
  768:     struct member_list binding;
  769:     debug_decl(add_defaults, SUDO_DEBUG_PARSER)
  770: 
  771:     /*
  772:      * We can only call list2tq once on bmem as it will zero
  773:      * out the prev pointer when it consumes bmem.
  774:      */
  775:     list2tq(&binding, bmem);
  776: 
  777:     /*
  778:      * Set type and binding (who it applies to) for new entries.
  779:      */
  780:     for (d = defs; d != NULL; d = d->next) {
  781: 	d->type = type;
  782: 	d->binding = binding;
  783:     }
  784:     tq_append(&defaults, defs);
  785: 
  786:     debug_return;
  787: }
  788: 
  789: /*
  790:  * Allocate a new struct userspec, populate it, and insert it at the
  791:  * and of the userspecs list.
  792:  */
  793: static void
  794: add_userspec(struct member *members, struct privilege *privs)
  795: {
  796:     struct userspec *u;
  797:     debug_decl(add_userspec, SUDO_DEBUG_PARSER)
  798: 
  799:     u = ecalloc(1, sizeof(*u));
  800:     list2tq(&u->users, members);
  801:     list2tq(&u->privileges, privs);
  802:     u->prev = u;
  803:     /* u->next = NULL; */
  804:     tq_append(&userspecs, u);
  805: 
  806:     debug_return;
  807: }
  808: 
  809: /*
  810:  * Free up space used by data structures from a previous parser run and sets
  811:  * the current sudoers file to path.
  812:  */
  813: void
  814: init_parser(const char *path, bool quiet)
  815: {
  816:     struct defaults *d;
  817:     struct member *m, *binding;
  818:     struct userspec *us;
  819:     struct privilege *priv;
  820:     struct cmndspec *cs;
  821:     struct sudo_command *c;
  822:     debug_decl(init_parser, SUDO_DEBUG_PARSER)
  823: 
  824:     while ((us = tq_pop(&userspecs)) != NULL) {
  825: 	while ((m = tq_pop(&us->users)) != NULL) {
  826: 	    efree(m->name);
  827: 	    efree(m);
  828: 	}
  829: 	while ((priv = tq_pop(&us->privileges)) != NULL) {
  830: 	    struct member *runasuser = NULL, *runasgroup = NULL;
  831: #ifdef HAVE_SELINUX
  832: 	    char *role = NULL, *type = NULL;
  833: #endif /* HAVE_SELINUX */
  834: #ifdef HAVE_PRIV_SET
  835: 	    char *privs = NULL, *limitprivs = NULL;
  836: #endif /* HAVE_PRIV_SET */
  837: 
  838: 	    while ((m = tq_pop(&priv->hostlist)) != NULL) {
  839: 		efree(m->name);
  840: 		efree(m);
  841: 	    }
  842: 	    while ((cs = tq_pop(&priv->cmndlist)) != NULL) {
  843: #ifdef HAVE_SELINUX
  844: 		/* Only free the first instance of a role/type. */
  845: 		if (cs->role != role) {
  846: 		    role = cs->role;
  847: 		    efree(cs->role);
  848: 		}
  849: 		if (cs->type != type) {
  850: 		    type = cs->type;
  851: 		    efree(cs->type);
  852: 		}
  853: #endif /* HAVE_SELINUX */
  854: #ifdef HAVE_PRIV_SET
  855: 		/* Only free the first instance of privs/limitprivs. */
  856: 		if (cs->privs != privs) {
  857: 		    privs = cs->privs;
  858: 		    efree(cs->privs);
  859: 		}
  860: 		if (cs->limitprivs != limitprivs) {
  861: 		    limitprivs = cs->limitprivs;
  862: 		    efree(cs->limitprivs);
  863: 		}
  864: #endif /* HAVE_PRIV_SET */
  865: 		if (tq_last(&cs->runasuserlist) != runasuser) {
  866: 		    runasuser = tq_last(&cs->runasuserlist);
  867: 		    while ((m = tq_pop(&cs->runasuserlist)) != NULL) {
  868: 			efree(m->name);
  869: 			efree(m);
  870: 		    }
  871: 		}
  872: 		if (tq_last(&cs->runasgrouplist) != runasgroup) {
  873: 		    runasgroup = tq_last(&cs->runasgrouplist);
  874: 		    while ((m = tq_pop(&cs->runasgrouplist)) != NULL) {
  875: 			efree(m->name);
  876: 			efree(m);
  877: 		    }
  878: 		}
  879: 		if (cs->cmnd->type == COMMAND) {
  880: 			c = (struct sudo_command *) cs->cmnd->name;
  881: 			efree(c->cmnd);
  882: 			efree(c->args);
  883: 		}
  884: 		efree(cs->cmnd->name);
  885: 		efree(cs->cmnd);
  886: 		efree(cs);
  887: 	    }
  888: 	    efree(priv);
  889: 	}
  890: 	efree(us);
  891:     }
  892:     tq_init(&userspecs);
  893: 
  894:     binding = NULL;
  895:     while ((d = tq_pop(&defaults)) != NULL) {
  896: 	if (tq_last(&d->binding) != binding) {
  897: 	    binding = tq_last(&d->binding);
  898: 	    while ((m = tq_pop(&d->binding)) != NULL) {
  899: 		if (m->type == COMMAND) {
  900: 			c = (struct sudo_command *) m->name;
  901: 			efree(c->cmnd);
  902: 			efree(c->args);
  903: 		}
  904: 		efree(m->name);
  905: 		efree(m);
  906: 	    }
  907: 	}
  908: 	efree(d->var);
  909: 	efree(d->val);
  910: 	efree(d);
  911:     }
  912:     tq_init(&defaults);
  913: 
  914:     init_aliases();
  915: 
  916:     init_lexer();
  917: 
  918:     efree(sudoers);
  919:     sudoers = path ? estrdup(path) : NULL;
  920: 
  921:     parse_error = false;
  922:     errorlineno = -1;
  923:     errorfile = sudoers;
  924:     sudoers_warnings = !quiet;
  925: 
  926:     debug_return;
  927: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>