update control to reflect move of primary repo to collab-maint
[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 #if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
48 # include <alloca.h>
49 #endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
50 #include <limits.h>
51
52 #include "sudoers.h" /* XXX */
53 #include "parse.h"
54 #include "toke.h"
55 #include "gram.h"
56
57 /*
58  * We must define SIZE_MAX for yacc's skeleton.c.
59  * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
60  * could be signed (as it is on SunOS 4.x).
61  */
62 #ifndef SIZE_MAX
63 # ifdef SIZE_T_MAX
64 #  define SIZE_MAX      SIZE_T_MAX
65 # else
66 #  define SIZE_MAX      INT_MAX
67 # endif /* SIZE_T_MAX */
68 #endif /* SIZE_MAX */
69
70 /*
71  * Globals
72  */
73 extern int sudolineno;
74 extern int last_token;
75 extern char *sudoers;
76 bool sudoers_warnings = true;
77 bool parse_error = false;
78 int errorlineno = -1;
79 char *errorfile = NULL;
80
81 struct defaults_list defaults;
82 struct userspec_list userspecs;
83
84 /*
85  * Local protoypes
86  */
87 static void  add_defaults(int, struct member *, struct defaults *);
88 static void  add_userspec(struct member *, struct privilege *);
89 static struct defaults *new_default(char *, char *, int);
90 static struct member *new_member(char *, int);
91        void  yyerror(const char *);
92
93 void
94 yyerror(const char *s)
95 {
96     debug_decl(yyerror, SUDO_DEBUG_PARSER)
97
98     /* If we last saw a newline the error is on the preceding line. */
99     if (last_token == COMMENT)
100         sudolineno--;
101
102     /* Save the line the first error occurred on. */
103     if (errorlineno == -1) {
104         errorlineno = sudolineno;
105         errorfile = estrdup(sudoers);
106     }
107     if (trace_print != NULL) {
108         LEXTRACE("<*> ");
109     } else if (sudoers_warnings && s != NULL) {
110         warningx(_(">>> %s: %s near line %d <<<"), sudoers, s, sudolineno);
111     }
112     parse_error = true;
113     debug_return;
114 }
115 %}
116
117 %union {
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;
124     struct cmndtag tag;
125     struct selinux_info seinfo;
126     char *string;
127     int tok;
128 }
129
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>     LOG_INPUT              /* log user's cmnd input */
150 %token <tok>     NOLOG_INPUT            /* don't log user's cmnd input */
151 %token <tok>     LOG_OUTPUT             /* log cmnd output */
152 %token <tok>     NOLOG_OUTPUT           /* don't log cmnd output */
153 %token <tok>     ALL                    /* ALL keyword */
154 %token <tok>     COMMENT                /* comment and/or carriage return */
155 %token <tok>     HOSTALIAS              /* Host_Alias keyword */
156 %token <tok>     CMNDALIAS              /* Cmnd_Alias keyword */
157 %token <tok>     USERALIAS              /* User_Alias keyword */
158 %token <tok>     RUNASALIAS             /* Runas_Alias keyword */
159 %token <tok>     ':' '=' ',' '!' '+' '-' /* union member tokens */
160 %token <tok>     '(' ')'                /* runas tokens */
161 %token <tok>     ERROR
162 %token <tok>     TYPE                   /* SELinux type */
163 %token <tok>     ROLE                   /* SELinux role */
164
165 %type <cmndspec>  cmndspec
166 %type <cmndspec>  cmndspeclist
167 %type <defaults>  defaults_entry
168 %type <defaults>  defaults_list
169 %type <member>    cmnd
170 %type <member>    opcmnd
171 %type <member>    cmndlist
172 %type <member>    host
173 %type <member>    hostlist
174 %type <member>    ophost
175 %type <member>    opuser
176 %type <member>    user
177 %type <member>    userlist
178 %type <member>    opgroup
179 %type <member>    group
180 %type <member>    grouplist
181 %type <runas>     runasspec
182 %type <runas>     runaslist
183 %type <privilege> privilege
184 %type <privilege> privileges
185 %type <tag>       cmndtag
186 %type <seinfo>    selinux
187 %type <string>    rolespec
188 %type <string>    typespec
189
190 %%
191
192 file            :       { ; }
193                 |       line
194                 ;
195
196 line            :       entry
197                 |       line entry
198                 ;
199
200 entry           :       COMMENT {
201                             ;
202                         }
203                 |       error COMMENT {
204                             yyerrok;
205                         }
206                 |       userlist privileges {
207                             add_userspec($1, $2);
208                         }
209                 |       USERALIAS useraliases {
210                             ;
211                         }
212                 |       HOSTALIAS hostaliases {
213                             ;
214                         }
215                 |       CMNDALIAS cmndaliases {
216                             ;
217                         }
218                 |       RUNASALIAS runasaliases {
219                             ;
220                         }
221                 |       DEFAULTS defaults_list {
222                             add_defaults(DEFAULTS, NULL, $2);
223                         }
224                 |       DEFAULTS_USER userlist defaults_list {
225                             add_defaults(DEFAULTS_USER, $2, $3);
226                         }
227                 |       DEFAULTS_RUNAS userlist defaults_list {
228                             add_defaults(DEFAULTS_RUNAS, $2, $3);
229                         }
230                 |       DEFAULTS_HOST hostlist defaults_list {
231                             add_defaults(DEFAULTS_HOST, $2, $3);
232                         }
233                 |       DEFAULTS_CMND cmndlist defaults_list {
234                             add_defaults(DEFAULTS_CMND, $2, $3);
235                         }
236                 ;
237
238 defaults_list   :       defaults_entry
239                 |       defaults_list ',' defaults_entry {
240                             list_append($1, $3);
241                             $$ = $1;
242                         }
243                 ;
244
245 defaults_entry  :       DEFVAR {
246                             $$ = new_default($1, NULL, true);
247                         }
248                 |       '!' DEFVAR {
249                             $$ = new_default($2, NULL, false);
250                         }
251                 |       DEFVAR '=' WORD {
252                             $$ = new_default($1, $3, true);
253                         }
254                 |       DEFVAR '+' WORD {
255                             $$ = new_default($1, $3, '+');
256                         }
257                 |       DEFVAR '-' WORD {
258                             $$ = new_default($1, $3, '-');
259                         }
260                 ;
261
262 privileges      :       privilege
263                 |       privileges ':' privilege {
264                             list_append($1, $3);
265                             $$ = $1;
266                         }
267                 ;
268
269 privilege       :       hostlist '=' cmndspeclist {
270                             struct privilege *p = ecalloc(1, sizeof(*p));
271                             list2tq(&p->hostlist, $1);
272                             list2tq(&p->cmndlist, $3);
273                             p->prev = p;
274                             /* p->next = NULL; */
275                             $$ = p;
276                         }
277                 ;
278
279 ophost          :       host {
280                             $$ = $1;
281                             $$->negated = false;
282                         }
283                 |       '!' host {
284                             $$ = $2;
285                             $$->negated = true;
286                         }
287                 ;
288
289 host            :       ALIAS {
290                             $$ = new_member($1, ALIAS);
291                         }
292                 |       ALL {
293                             $$ = new_member(NULL, ALL);
294                         }
295                 |       NETGROUP {
296                             $$ = new_member($1, NETGROUP);
297                         }
298                 |       NTWKADDR {
299                             $$ = new_member($1, NTWKADDR);
300                         }
301                 |       WORD {
302                             $$ = new_member($1, WORD);
303                         }
304                 ;
305
306 cmndspeclist    :       cmndspec
307                 |       cmndspeclist ',' cmndspec {
308                             list_append($1, $3);
309 #ifdef HAVE_SELINUX
310                             /* propagate role and type */
311                             if ($3->role == NULL)
312                                 $3->role = $3->prev->role;
313                             if ($3->type == NULL)
314                                 $3->type = $3->prev->type;
315 #endif /* HAVE_SELINUX */
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 cmndtag opcmnd {
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                             cs->tags = $3;
354                             cs->cmnd = $4;
355                             cs->prev = cs;
356                             cs->next = NULL;
357                             /* sudo "ALL" implies the SETENV tag */
358                             if (cs->cmnd->type == ALL && !cs->cmnd->negated &&
359                                 cs->tags.setenv == UNSPEC)
360                                 cs->tags.setenv = IMPLIED;
361                             $$ = cs;
362                         }
363                 ;
364
365 opcmnd          :       cmnd {
366                             $$ = $1;
367                             $$->negated = false;
368                         }
369                 |       '!' cmnd {
370                             $$ = $2;
371                             $$->negated = true;
372                         }
373                 ;
374
375 rolespec        :       ROLE '=' WORD {
376                             $$ = $3;
377                         }
378                 ;
379
380 typespec        :       TYPE '=' WORD {
381                             $$ = $3;
382                         }
383                 ;
384
385 selinux         :       /* empty */ {
386                             $$.role = NULL;
387                             $$.type = NULL;
388                         }
389                 |       rolespec {
390                             $$.role = $1;
391                             $$.type = NULL;
392                         }
393                 |       typespec {
394                             $$.type = $1;
395                             $$.role = NULL;
396                         }
397                 |       rolespec typespec {
398                             $$.role = $1;
399                             $$.type = $2;
400                         }
401                 |       typespec rolespec {
402                             $$.type = $1;
403                             $$.role = $2;
404                         }
405                 ;
406
407 runasspec       :       /* empty */ {
408                             $$ = NULL;
409                         }
410                 |       '(' runaslist ')' {
411                             $$ = $2;
412                         }
413                 ;
414
415 runaslist       :       userlist {
416                             $$ = ecalloc(1, sizeof(struct runascontainer));
417                             $$->runasusers = $1;
418                             /* $$->runasgroups = NULL; */
419                         }
420                 |       userlist ':' grouplist {
421                             $$ = ecalloc(1, sizeof(struct runascontainer));
422                             $$->runasusers = $1;
423                             $$->runasgroups = $3;
424                         }
425                 |       ':' grouplist {
426                             $$ = ecalloc(1, sizeof(struct runascontainer));
427                             /* $$->runasusers = NULL; */
428                             $$->runasgroups = $2;
429                         }
430                 ;
431
432 cmndtag         :       /* empty */ {
433                             $$.nopasswd = $$.noexec = $$.setenv =
434                                 $$.log_input = $$.log_output = UNSPEC;
435                         }
436                 |       cmndtag NOPASSWD {
437                             $$.nopasswd = true;
438                         }
439                 |       cmndtag PASSWD {
440                             $$.nopasswd = false;
441                         }
442                 |       cmndtag NOEXEC {
443                             $$.noexec = true;
444                         }
445                 |       cmndtag EXEC {
446                             $$.noexec = false;
447                         }
448                 |       cmndtag SETENV {
449                             $$.setenv = true;
450                         }
451                 |       cmndtag NOSETENV {
452                             $$.setenv = false;
453                         }
454                 |       cmndtag LOG_INPUT {
455                             $$.log_input = true;
456                         }
457                 |       cmndtag NOLOG_INPUT {
458                             $$.log_input = false;
459                         }
460                 |       cmndtag LOG_OUTPUT {
461                             $$.log_output = true;
462                         }
463                 |       cmndtag NOLOG_OUTPUT {
464                             $$.log_output = false;
465                         }
466                 ;
467
468 cmnd            :       ALL {
469                             $$ = new_member(NULL, ALL);
470                         }
471                 |       ALIAS {
472                             $$ = new_member($1, ALIAS);
473                         }
474                 |       COMMAND {
475                             struct sudo_command *c = ecalloc(1, sizeof(*c));
476                             c->cmnd = $1.cmnd;
477                             c->args = $1.args;
478                             $$ = new_member((char *)c, COMMAND);
479                         }
480                 ;
481
482 hostaliases     :       hostalias
483                 |       hostaliases ':' hostalias
484                 ;
485
486 hostalias       :       ALIAS '=' hostlist {
487                             char *s;
488                             if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) {
489                                 yyerror(s);
490                                 YYERROR;
491                             }
492                         }
493                 ;
494
495 hostlist        :       ophost
496                 |       hostlist ',' ophost {
497                             list_append($1, $3);
498                             $$ = $1;
499                         }
500                 ;
501
502 cmndaliases     :       cmndalias
503                 |       cmndaliases ':' cmndalias
504                 ;
505
506 cmndalias       :       ALIAS '=' cmndlist {
507                             char *s;
508                             if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) {
509                                 yyerror(s);
510                                 YYERROR;
511                             }
512                         }
513                 ;
514
515 cmndlist        :       opcmnd
516                 |       cmndlist ',' opcmnd {
517                             list_append($1, $3);
518                             $$ = $1;
519                         }
520                 ;
521
522 runasaliases    :       runasalias
523                 |       runasaliases ':' runasalias
524                 ;
525
526 runasalias      :       ALIAS '=' userlist {
527                             char *s;
528                             if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) {
529                                 yyerror(s);
530                                 YYERROR;
531                             }
532                         }
533                 ;
534
535 useraliases     :       useralias
536                 |       useraliases ':' useralias
537                 ;
538
539 useralias       :       ALIAS '=' userlist {
540                             char *s;
541                             if ((s = alias_add($1, USERALIAS, $3)) != NULL) {
542                                 yyerror(s);
543                                 YYERROR;
544                             }
545                         }
546                 ;
547
548 userlist        :       opuser
549                 |       userlist ',' opuser {
550                             list_append($1, $3);
551                             $$ = $1;
552                         }
553                 ;
554
555 opuser          :       user {
556                             $$ = $1;
557                             $$->negated = false;
558                         }
559                 |       '!' user {
560                             $$ = $2;
561                             $$->negated = true;
562                         }
563                 ;
564
565 user            :       ALIAS {
566                             $$ = new_member($1, ALIAS);
567                         }
568                 |       ALL {
569                             $$ = new_member(NULL, ALL);
570                         }
571                 |       NETGROUP {
572                             $$ = new_member($1, NETGROUP);
573                         }
574                 |       USERGROUP {
575                             $$ = new_member($1, USERGROUP);
576                         }
577                 |       WORD {
578                             $$ = new_member($1, WORD);
579                         }
580                 ;
581
582 grouplist       :       opgroup
583                 |       grouplist ',' opgroup {
584                             list_append($1, $3);
585                             $$ = $1;
586                         }
587                 ;
588
589 opgroup         :       group {
590                             $$ = $1;
591                             $$->negated = false;
592                         }
593                 |       '!' group {
594                             $$ = $2;
595                             $$->negated = true;
596                         }
597                 ;
598
599 group           :       ALIAS {
600                             $$ = new_member($1, ALIAS);
601                         }
602                 |       ALL {
603                             $$ = new_member(NULL, ALL);
604                         }
605                 |       WORD {
606                             $$ = new_member($1, WORD);
607                         }
608                 ;
609
610 %%
611 static struct defaults *
612 new_default(char *var, char *val, int op)
613 {
614     struct defaults *d;
615     debug_decl(new_default, SUDO_DEBUG_PARSER)
616
617     d = ecalloc(1, sizeof(struct defaults));
618     d->var = var;
619     d->val = val;
620     tq_init(&d->binding);
621     /* d->type = 0; */
622     d->op = op;
623     d->prev = d;
624     /* d->next = NULL; */
625
626     debug_return_ptr(d);
627 }
628
629 static struct member *
630 new_member(char *name, int type)
631 {
632     struct member *m;
633     debug_decl(new_member, SUDO_DEBUG_PARSER)
634
635     m = ecalloc(1, sizeof(struct member));
636     m->name = name;
637     m->type = type;
638     m->prev = m;
639     /* m->next = NULL; */
640
641     debug_return_ptr(m);
642 }
643
644 /*
645  * Add a list of defaults structures to the defaults list.
646  * The binding, if non-NULL, specifies a list of hosts, users, or
647  * runas users the entries apply to (specified by the type).
648  */
649 static void
650 add_defaults(int type, struct member *bmem, struct defaults *defs)
651 {
652     struct defaults *d;
653     struct member_list binding;
654     debug_decl(add_defaults, SUDO_DEBUG_PARSER)
655
656     /*
657      * We can only call list2tq once on bmem as it will zero
658      * out the prev pointer when it consumes bmem.
659      */
660     list2tq(&binding, bmem);
661
662     /*
663      * Set type and binding (who it applies to) for new entries.
664      */
665     for (d = defs; d != NULL; d = d->next) {
666         d->type = type;
667         d->binding = binding;
668     }
669     tq_append(&defaults, defs);
670
671     debug_return;
672 }
673
674 /*
675  * Allocate a new struct userspec, populate it, and insert it at the
676  * and of the userspecs list.
677  */
678 static void
679 add_userspec(struct member *members, struct privilege *privs)
680 {
681     struct userspec *u;
682     debug_decl(add_userspec, SUDO_DEBUG_PARSER)
683
684     u = ecalloc(1, sizeof(*u));
685     list2tq(&u->users, members);
686     list2tq(&u->privileges, privs);
687     u->prev = u;
688     /* u->next = NULL; */
689     tq_append(&userspecs, u);
690
691     debug_return;
692 }
693
694 /*
695  * Free up space used by data structures from a previous parser run and sets
696  * the current sudoers file to path.
697  */
698 void
699 init_parser(const char *path, int quiet)
700 {
701     struct defaults *d;
702     struct member *m, *binding;
703     struct userspec *us;
704     struct privilege *priv;
705     struct cmndspec *cs;
706     struct sudo_command *c;
707     debug_decl(init_parser, SUDO_DEBUG_PARSER)
708
709     while ((us = tq_pop(&userspecs)) != NULL) {
710         while ((m = tq_pop(&us->users)) != NULL) {
711             efree(m->name);
712             efree(m);
713         }
714         while ((priv = tq_pop(&us->privileges)) != NULL) {
715             struct member *runasuser = NULL, *runasgroup = NULL;
716 #ifdef HAVE_SELINUX
717             char *role = NULL, *type = NULL;
718 #endif /* HAVE_SELINUX */
719
720             while ((m = tq_pop(&priv->hostlist)) != NULL) {
721                 efree(m->name);
722                 efree(m);
723             }
724             while ((cs = tq_pop(&priv->cmndlist)) != NULL) {
725 #ifdef HAVE_SELINUX
726                 /* Only free the first instance of a role/type. */
727                 if (cs->role != role) {
728                     role = cs->role;
729                     efree(cs->role);
730                 }
731                 if (cs->type != type) {
732                     type = cs->type;
733                     efree(cs->type);
734                 }
735 #endif /* HAVE_SELINUX */
736                 if (tq_last(&cs->runasuserlist) != runasuser) {
737                     runasuser = tq_last(&cs->runasuserlist);
738                     while ((m = tq_pop(&cs->runasuserlist)) != NULL) {
739                         efree(m->name);
740                         efree(m);
741                     }
742                 }
743                 if (tq_last(&cs->runasgrouplist) != runasgroup) {
744                     runasgroup = tq_last(&cs->runasgrouplist);
745                     while ((m = tq_pop(&cs->runasgrouplist)) != NULL) {
746                         efree(m->name);
747                         efree(m);
748                     }
749                 }
750                 if (cs->cmnd->type == COMMAND) {
751                         c = (struct sudo_command *) cs->cmnd->name;
752                         efree(c->cmnd);
753                         efree(c->args);
754                 }
755                 efree(cs->cmnd->name);
756                 efree(cs->cmnd);
757                 efree(cs);
758             }
759             efree(priv);
760         }
761         efree(us);
762     }
763     tq_init(&userspecs);
764
765     binding = NULL;
766     while ((d = tq_pop(&defaults)) != NULL) {
767         if (tq_last(&d->binding) != binding) {
768             binding = tq_last(&d->binding);
769             while ((m = tq_pop(&d->binding)) != NULL) {
770                 if (m->type == COMMAND) {
771                         c = (struct sudo_command *) m->name;
772                         efree(c->cmnd);
773                         efree(c->args);
774                 }
775                 efree(m->name);
776                 efree(m);
777             }
778         }
779         efree(d->var);
780         efree(d->val);
781         efree(d);
782     }
783     tq_init(&defaults);
784
785     init_aliases();
786
787     init_lexer();
788
789     efree(sudoers);
790     sudoers = path ? estrdup(path) : NULL;
791
792     parse_error = false;
793     errorlineno = -1;
794     errorfile = sudoers;
795     sudoers_warnings = !quiet;
796
797     debug_return;
798 }