3 * Copyright (c) 1996, 1998-2005, 2007-2009
4 * Todd C. Miller <Todd.Miller@courtesan.com>
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.
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.
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.
27 #include <sys/types.h>
28 #include <sys/param.h>
37 #endif /* STDC_HEADERS */
41 # ifdef HAVE_STRINGS_H
44 #endif /* HAVE_STRING_H */
47 #endif /* HAVE_UNISTD_H */
48 #if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
50 #endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
57 __unused static const char rcsid[] = "$Sudo: gram.y,v 1.36 2009/05/25 12:02:41 millert Exp $";
61 * We must define SIZE_MAX for yacc's skeleton.c.
62 * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
63 * could be signed (as it is on SunOS 4.x).
67 # define SIZE_MAX SIZE_T_MAX
69 # define SIZE_MAX INT_MAX
70 # endif /* SIZE_T_MAX */
76 extern int sudolineno;
82 char *errorfile = NULL;
84 struct defaults_list defaults;
85 struct userspec_list userspecs;
90 static void add_defaults __P((int, struct member *, struct defaults *));
91 static void add_userspec __P((struct member *, struct privilege *));
92 static struct defaults *new_default __P((char *, char *, int));
93 static struct member *new_member __P((char *, int));
94 void yyerror __P((const char *));
100 /* Save the line the first error occurred on. */
101 if (errorlineno == -1) {
102 errorlineno = sudolineno ? sudolineno - 1 : 0;
103 errorfile = estrdup(sudoers);
105 if (verbose && s != NULL) {
107 (void) fprintf(stderr, ">>> %s: %s near line %d <<<\n", sudoers, s,
108 sudolineno ? sudolineno - 1 : 0);
110 (void) fprintf(stderr, "<*> ");
118 struct cmndspec *cmndspec;
119 struct defaults *defaults;
120 struct member *member;
121 struct runascontainer *runas;
122 struct privilege *privilege;
123 struct sudo_command command;
125 struct selinux_info seinfo;
130 %start file /* special start symbol */
131 %token <command> COMMAND /* absolute pathname w/ optional args */
132 %token <string> ALIAS /* an UPPERCASE alias name */
133 %token <string> DEFVAR /* a Defaults variable name */
134 %token <string> NTWKADDR /* ipv4 or ipv6 address */
135 %token <string> NETGROUP /* a netgroup (+NAME) */
136 %token <string> USERGROUP /* a usergroup (%NAME) */
137 %token <string> WORD /* a word */
138 %token <tok> DEFAULTS /* Defaults entry */
139 %token <tok> DEFAULTS_HOST /* Host-specific defaults entry */
140 %token <tok> DEFAULTS_USER /* User-specific defaults entry */
141 %token <tok> DEFAULTS_RUNAS /* Runas-specific defaults entry */
142 %token <tok> DEFAULTS_CMND /* Command-specific defaults entry */
143 %token <tok> NOPASSWD /* no passwd req for command */
144 %token <tok> PASSWD /* passwd req for command (default) */
145 %token <tok> NOEXEC /* preload dummy execve() for cmnd */
146 %token <tok> EXEC /* don't preload dummy execve() */
147 %token <tok> SETENV /* user may set environment for cmnd */
148 %token <tok> NOSETENV /* user may not set environment */
149 %token <tok> ALL /* ALL keyword */
150 %token <tok> COMMENT /* comment and/or carriage return */
151 %token <tok> HOSTALIAS /* Host_Alias keyword */
152 %token <tok> CMNDALIAS /* Cmnd_Alias keyword */
153 %token <tok> USERALIAS /* User_Alias keyword */
154 %token <tok> RUNASALIAS /* Runas_Alias keyword */
155 %token <tok> ':' '=' ',' '!' '+' '-' /* union member tokens */
156 %token <tok> '(' ')' /* runas tokens */
158 %token <tok> TYPE /* SELinux type */
159 %token <tok> ROLE /* SELinux role */
161 %type <cmndspec> cmndspec
162 %type <cmndspec> cmndspeclist
163 %type <defaults> defaults_entry
164 %type <defaults> defaults_list
166 %type <member> opcmnd
167 %type <member> cmndlist
169 %type <member> hostlist
170 %type <member> ophost
171 %type <member> opuser
173 %type <member> userlist
174 %type <member> opgroup
176 %type <member> grouplist
177 %type <runas> runasspec
178 %type <runas> runaslist
179 %type <privilege> privilege
180 %type <privilege> privileges
182 %type <seinfo> selinux
183 %type <string> rolespec
184 %type <string> typespec
202 | userlist privileges {
203 add_userspec($1, $2);
205 | USERALIAS useraliases {
208 | HOSTALIAS hostaliases {
211 | CMNDALIAS cmndaliases {
214 | RUNASALIAS runasaliases {
217 | DEFAULTS defaults_list {
218 add_defaults(DEFAULTS, NULL, $2);
220 | DEFAULTS_USER userlist defaults_list {
221 add_defaults(DEFAULTS_USER, $2, $3);
223 | DEFAULTS_RUNAS userlist defaults_list {
224 add_defaults(DEFAULTS_RUNAS, $2, $3);
226 | DEFAULTS_HOST hostlist defaults_list {
227 add_defaults(DEFAULTS_HOST, $2, $3);
229 | DEFAULTS_CMND cmndlist defaults_list {
230 add_defaults(DEFAULTS_CMND, $2, $3);
234 defaults_list : defaults_entry
235 | defaults_list ',' defaults_entry {
241 defaults_entry : DEFVAR {
242 $$ = new_default($1, NULL, TRUE);
245 $$ = new_default($2, NULL, FALSE);
248 $$ = new_default($1, $3, TRUE);
251 $$ = new_default($1, $3, '+');
254 $$ = new_default($1, $3, '-');
258 privileges : privilege
259 | privileges ':' privilege {
265 privilege : hostlist '=' cmndspeclist {
266 struct privilege *p = emalloc(sizeof(*p));
267 list2tq(&p->hostlist, $1);
268 list2tq(&p->cmndlist, $3);
286 $$ = new_member($1, ALIAS);
289 $$ = new_member(NULL, ALL);
292 $$ = new_member($1, NETGROUP);
295 $$ = new_member($1, NTWKADDR);
298 $$ = new_member($1, WORD);
302 cmndspeclist : cmndspec
303 | cmndspeclist ',' cmndspec {
306 /* propagate role and type */
307 if ($3->role == NULL)
308 $3->role = $3->prev->role;
309 if ($3->type == NULL)
310 $3->type = $3->prev->type;
311 #endif /* HAVE_SELINUX */
312 /* propagate tags and runas list */
313 if ($3->tags.nopasswd == UNSPEC)
314 $3->tags.nopasswd = $3->prev->tags.nopasswd;
315 if ($3->tags.noexec == UNSPEC)
316 $3->tags.noexec = $3->prev->tags.noexec;
317 if ($3->tags.setenv == UNSPEC &&
318 $3->prev->tags.setenv != IMPLIED)
319 $3->tags.setenv = $3->prev->tags.setenv;
320 if ((tq_empty(&$3->runasuserlist) &&
321 tq_empty(&$3->runasgrouplist)) &&
322 (!tq_empty(&$3->prev->runasuserlist) ||
323 !tq_empty(&$3->prev->runasgrouplist))) {
324 $3->runasuserlist = $3->prev->runasuserlist;
325 $3->runasgrouplist = $3->prev->runasgrouplist;
331 cmndspec : runasspec selinux cmndtag opcmnd {
332 struct cmndspec *cs = emalloc(sizeof(*cs));
334 list2tq(&cs->runasuserlist, $1->runasusers);
335 list2tq(&cs->runasgrouplist, $1->runasgroups);
338 tq_init(&cs->runasuserlist);
339 tq_init(&cs->runasgrouplist);
349 /* sudo "ALL" implies the SETENV tag */
350 if (cs->cmnd->type == ALL && !cs->cmnd->negated &&
351 cs->tags.setenv == UNSPEC)
352 cs->tags.setenv = IMPLIED;
367 rolespec : ROLE '=' WORD {
372 typespec : TYPE '=' WORD {
377 selinux : /* empty */ {
389 | rolespec typespec {
393 | typespec rolespec {
399 runasspec : /* empty */ {
402 | '(' runaslist ')' {
407 runaslist : userlist {
408 $$ = emalloc(sizeof(struct runascontainer));
410 $$->runasgroups = NULL;
412 | userlist ':' grouplist {
413 $$ = emalloc(sizeof(struct runascontainer));
415 $$->runasgroups = $3;
418 $$ = emalloc(sizeof(struct runascontainer));
419 $$->runasusers = NULL;
420 $$->runasgroups = $2;
424 cmndtag : /* empty */ {
425 $$.nopasswd = $$.noexec = $$.setenv = UNSPEC;
448 $$ = new_member(NULL, ALL);
451 $$ = new_member($1, ALIAS);
454 struct sudo_command *c = emalloc(sizeof(*c));
457 $$ = new_member((char *)c, COMMAND);
461 hostaliases : hostalias
462 | hostaliases ':' hostalias
465 hostalias : ALIAS '=' hostlist {
467 if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) {
475 | hostlist ',' ophost {
481 cmndaliases : cmndalias
482 | cmndaliases ':' cmndalias
485 cmndalias : ALIAS '=' cmndlist {
487 if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) {
495 | cmndlist ',' opcmnd {
501 runasaliases : runasalias
502 | runasaliases ':' runasalias
505 runasalias : ALIAS '=' userlist {
507 if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) {
514 useraliases : useralias
515 | useraliases ':' useralias
518 useralias : ALIAS '=' userlist {
520 if ((s = alias_add($1, USERALIAS, $3)) != NULL) {
528 | userlist ',' opuser {
545 $$ = new_member($1, ALIAS);
548 $$ = new_member(NULL, ALL);
551 $$ = new_member($1, NETGROUP);
554 $$ = new_member($1, USERGROUP);
557 $$ = new_member($1, WORD);
562 | grouplist ',' opgroup {
579 $$ = new_member($1, ALIAS);
582 $$ = new_member(NULL, ALL);
585 $$ = new_member($1, WORD);
590 static struct defaults *
591 new_default(var, val, op)
598 d = emalloc(sizeof(struct defaults));
601 tq_init(&d->binding);
610 static struct member *
611 new_member(name, type)
617 m = emalloc(sizeof(struct member));
627 * Add a list of defaults structures to the defaults list.
628 * The binding, if non-NULL, specifies a list of hosts, users, or
629 * runas users the entries apply to (specified by the type).
632 add_defaults(type, bmem, defs)
635 struct defaults *defs;
638 struct member_list binding;
641 * We can only call list2tq once on bmem as it will zero
642 * out the prev pointer when it consumes bmem.
644 list2tq(&binding, bmem);
647 * Set type and binding (who it applies to) for new entries.
649 for (d = defs; d != NULL; d = d->next) {
651 d->binding = binding;
653 tq_append(&defaults, defs);
657 * Allocate a new struct userspec, populate it, and insert it at the
658 * and of the userspecs list.
661 add_userspec(members, privs)
662 struct member *members;
663 struct privilege *privs;
667 u = emalloc(sizeof(*u));
668 list2tq(&u->users, members);
669 list2tq(&u->privileges, privs);
672 tq_append(&userspecs, u);
676 * Free up space used by data structures from a previous parser run and sets
677 * the current sudoers file to path.
680 init_parser(path, quiet)
685 struct member *m, *binding;
687 struct privilege *priv;
689 struct sudo_command *c;
691 while ((us = tq_pop(&userspecs)) != NULL) {
692 while ((m = tq_pop(&us->users)) != NULL) {
696 while ((priv = tq_pop(&us->privileges)) != NULL) {
697 struct member *runasuser = NULL, *runasgroup = NULL;
699 char *role = NULL, *type = NULL;
700 #endif /* HAVE_SELINUX */
702 while ((m = tq_pop(&priv->hostlist)) != NULL) {
706 while ((cs = tq_pop(&priv->cmndlist)) != NULL) {
708 /* Only free the first instance of a role/type. */
709 if (cs->role != role) {
713 if (cs->type != type) {
717 #endif /* HAVE_SELINUX */
718 if (tq_last(&cs->runasuserlist) != runasuser) {
719 runasuser = tq_last(&cs->runasuserlist);
720 while ((m = tq_pop(&cs->runasuserlist)) != NULL) {
725 if (tq_last(&cs->runasgrouplist) != runasgroup) {
726 runasgroup = tq_last(&cs->runasgrouplist);
727 while ((m = tq_pop(&cs->runasgrouplist)) != NULL) {
732 if (cs->cmnd->type == COMMAND) {
733 c = (struct sudo_command *) cs->cmnd->name;
737 efree(cs->cmnd->name);
748 while ((d = tq_pop(&defaults)) != NULL) {
749 if (tq_last(&d->binding) != binding) {
750 binding = tq_last(&d->binding);
751 while ((m = tq_pop(&d->binding)) != NULL) {
752 if (m->type == COMMAND) {
753 c = (struct sudo_command *) m->name;
772 sudoers = path ? estrdup(path) : NULL;