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