f3f0aace351b2ab4c4d253ca30c08a58e0cb8a0b
[debian/sudo] / plugins / sudoers / gram.y
1 %{
2 /*
3  * Copyright (c) 1996, 1998-2005, 2007-2011
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
56 /*
57  * We must define SIZE_MAX for yacc's skeleton.c.
58  * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
59  * could be signed (as it is on SunOS 4.x).
60  */
61 #ifndef SIZE_MAX
62 # ifdef SIZE_T_MAX
63 #  define SIZE_MAX      SIZE_T_MAX
64 # else
65 #  define SIZE_MAX      INT_MAX
66 # endif /* SIZE_T_MAX */
67 #endif /* SIZE_MAX */
68
69 /*
70  * Globals
71  */
72 extern int sudolineno;
73 extern char *sudoers;
74 static int verbose = FALSE;
75 int parse_error = FALSE;
76 int pedantic = FALSE;
77 int errorlineno = -1;
78 char *errorfile = NULL;
79
80 struct defaults_list defaults;
81 struct userspec_list userspecs;
82
83 /*
84  * Local protoypes
85  */
86 static void  add_defaults(int, struct member *, struct defaults *);
87 static void  add_userspec(struct member *, struct privilege *);
88 static struct defaults *new_default(char *, char *, int);
89 static struct member *new_member(char *, int);
90        void  yyerror(const char *);
91
92 void
93 yyerror(const char *s)
94 {
95     /* Save the line the first error occurred on. */
96     if (errorlineno == -1) {
97         errorlineno = sudolineno ? sudolineno - 1 : 0;
98         errorfile = estrdup(sudoers);
99     }
100     if (trace_print != NULL) {
101         LEXTRACE("<*> ");
102     } else if (verbose && s != NULL) {
103         warningx(_(">>> %s: %s near line %d <<<"), sudoers, s,
104             sudolineno ? sudolineno - 1 : 0);
105     }
106     parse_error = TRUE;
107 }
108 %}
109
110 %union {
111     struct cmndspec *cmndspec;
112     struct defaults *defaults;
113     struct member *member;
114     struct runascontainer *runas;
115     struct privilege *privilege;
116     struct sudo_command command;
117     struct cmndtag tag;
118     struct selinux_info seinfo;
119     char *string;
120     int tok;
121 }
122
123 %start file                             /* special start symbol */
124 %token <command> COMMAND                /* absolute pathname w/ optional args */
125 %token <string>  ALIAS                  /* an UPPERCASE alias name */
126 %token <string>  DEFVAR                 /* a Defaults variable name */
127 %token <string>  NTWKADDR               /* ipv4 or ipv6 address */
128 %token <string>  NETGROUP               /* a netgroup (+NAME) */
129 %token <string>  USERGROUP              /* a usergroup (%NAME) */
130 %token <string>  WORD                   /* a word */
131 %token <tok>     DEFAULTS               /* Defaults entry */
132 %token <tok>     DEFAULTS_HOST          /* Host-specific defaults entry */
133 %token <tok>     DEFAULTS_USER          /* User-specific defaults entry */
134 %token <tok>     DEFAULTS_RUNAS         /* Runas-specific defaults entry */
135 %token <tok>     DEFAULTS_CMND          /* Command-specific defaults entry */
136 %token <tok>     NOPASSWD               /* no passwd req for command */
137 %token <tok>     PASSWD                 /* passwd req for command (default) */
138 %token <tok>     NOEXEC                 /* preload dummy execve() for cmnd */
139 %token <tok>     EXEC                   /* don't preload dummy execve() */
140 %token <tok>     SETENV                 /* user may set environment for cmnd */
141 %token <tok>     NOSETENV               /* user may not set environment */
142 %token <tok>     LOG_INPUT              /* log user's cmnd input */
143 %token <tok>     NOLOG_INPUT            /* don't log user's cmnd input */
144 %token <tok>     LOG_OUTPUT             /* log cmnd output */
145 %token <tok>     NOLOG_OUTPUT           /* don't log cmnd output */
146 %token <tok>     ALL                    /* ALL keyword */
147 %token <tok>     COMMENT                /* comment and/or carriage return */
148 %token <tok>     HOSTALIAS              /* Host_Alias keyword */
149 %token <tok>     CMNDALIAS              /* Cmnd_Alias keyword */
150 %token <tok>     USERALIAS              /* User_Alias keyword */
151 %token <tok>     RUNASALIAS             /* Runas_Alias keyword */
152 %token <tok>     ':' '=' ',' '!' '+' '-' /* union member tokens */
153 %token <tok>     '(' ')'                /* runas tokens */
154 %token <tok>     ERROR
155 %token <tok>     TYPE                   /* SELinux type */
156 %token <tok>     ROLE                   /* SELinux role */
157
158 %type <cmndspec>  cmndspec
159 %type <cmndspec>  cmndspeclist
160 %type <defaults>  defaults_entry
161 %type <defaults>  defaults_list
162 %type <member>    cmnd
163 %type <member>    opcmnd
164 %type <member>    cmndlist
165 %type <member>    host
166 %type <member>    hostlist
167 %type <member>    ophost
168 %type <member>    opuser
169 %type <member>    user
170 %type <member>    userlist
171 %type <member>    opgroup
172 %type <member>    group
173 %type <member>    grouplist
174 %type <runas>     runasspec
175 %type <runas>     runaslist
176 %type <privilege> privilege
177 %type <privilege> privileges
178 %type <tag>       cmndtag
179 %type <seinfo>    selinux
180 %type <string>    rolespec
181 %type <string>    typespec
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 = emalloc(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                             /* propagate tags and runas list */
310                             if ($3->tags.nopasswd == UNSPEC)
311                                 $3->tags.nopasswd = $3->prev->tags.nopasswd;
312                             if ($3->tags.noexec == UNSPEC)
313                                 $3->tags.noexec = $3->prev->tags.noexec;
314                             if ($3->tags.setenv == UNSPEC &&
315                                 $3->prev->tags.setenv != IMPLIED)
316                                 $3->tags.setenv = $3->prev->tags.setenv;
317                             if ($3->tags.log_input == UNSPEC)
318                                 $3->tags.log_input = $3->prev->tags.log_input;
319                             if ($3->tags.log_output == UNSPEC)
320                                 $3->tags.log_output = $3->prev->tags.log_output;
321                             if ((tq_empty(&$3->runasuserlist) &&
322                                  tq_empty(&$3->runasgrouplist)) &&
323                                 (!tq_empty(&$3->prev->runasuserlist) ||
324                                  !tq_empty(&$3->prev->runasgrouplist))) {
325                                 $3->runasuserlist = $3->prev->runasuserlist;
326                                 $3->runasgrouplist = $3->prev->runasgrouplist;
327                             }
328                             $$ = $1;
329                         }
330                 ;
331
332 cmndspec        :       runasspec selinux cmndtag opcmnd {
333                             struct cmndspec *cs = emalloc(sizeof(*cs));
334                             if ($1 != NULL) {
335                                 list2tq(&cs->runasuserlist, $1->runasusers);
336                                 list2tq(&cs->runasgrouplist, $1->runasgroups);
337                                 efree($1);
338                             } else {
339                                 tq_init(&cs->runasuserlist);
340                                 tq_init(&cs->runasgrouplist);
341                             }
342 #ifdef HAVE_SELINUX
343                             cs->role = $2.role;
344                             cs->type = $2.type;
345 #endif
346                             cs->tags = $3;
347                             cs->cmnd = $4;
348                             cs->prev = cs;
349                             cs->next = NULL;
350                             /* sudo "ALL" implies the SETENV tag */
351                             if (cs->cmnd->type == ALL && !cs->cmnd->negated &&
352                                 cs->tags.setenv == UNSPEC)
353                                 cs->tags.setenv = IMPLIED;
354                             $$ = cs;
355                         }
356                 ;
357
358 opcmnd          :       cmnd {
359                             $$ = $1;
360                             $$->negated = FALSE;
361                         }
362                 |       '!' cmnd {
363                             $$ = $2;
364                             $$->negated = TRUE;
365                         }
366                 ;
367
368 rolespec        :       ROLE '=' WORD {
369                             $$ = $3;
370                         }
371                 ;
372
373 typespec        :       TYPE '=' WORD {
374                             $$ = $3;
375                         }
376                 ;
377
378 selinux         :       /* empty */ {
379                             $$.role = NULL;
380                             $$.type = NULL;
381                         }
382                 |       rolespec {
383                             $$.role = $1;
384                             $$.type = NULL;
385                         }
386                 |       typespec {
387                             $$.type = $1;
388                             $$.role = NULL;
389                         }
390                 |       rolespec typespec {
391                             $$.role = $1;
392                             $$.type = $2;
393                         }
394                 |       typespec rolespec {
395                             $$.type = $1;
396                             $$.role = $2;
397                         }
398                 ;
399
400 runasspec       :       /* empty */ {
401                             $$ = NULL;
402                         }
403                 |       '(' runaslist ')' {
404                             $$ = $2;
405                         }
406                 ;
407
408 runaslist       :       userlist {
409                             $$ = emalloc(sizeof(struct runascontainer));
410                             $$->runasusers = $1;
411                             $$->runasgroups = NULL;
412                         }
413                 |       userlist ':' grouplist {
414                             $$ = emalloc(sizeof(struct runascontainer));
415                             $$->runasusers = $1;
416                             $$->runasgroups = $3;
417                         }
418                 |       ':' grouplist {
419                             $$ = emalloc(sizeof(struct runascontainer));
420                             $$->runasusers = NULL;
421                             $$->runasgroups = $2;
422                         }
423                 ;
424
425 cmndtag         :       /* empty */ {
426                             $$.nopasswd = $$.noexec = $$.setenv =
427                                 $$.log_input = $$.log_output = UNSPEC;
428                         }
429                 |       cmndtag NOPASSWD {
430                             $$.nopasswd = TRUE;
431                         }
432                 |       cmndtag PASSWD {
433                             $$.nopasswd = FALSE;
434                         }
435                 |       cmndtag NOEXEC {
436                             $$.noexec = TRUE;
437                         }
438                 |       cmndtag EXEC {
439                             $$.noexec = FALSE;
440                         }
441                 |       cmndtag SETENV {
442                             $$.setenv = TRUE;
443                         }
444                 |       cmndtag NOSETENV {
445                             $$.setenv = FALSE;
446                         }
447                 |       cmndtag LOG_INPUT {
448                             $$.log_input = TRUE;
449                         }
450                 |       cmndtag NOLOG_INPUT {
451                             $$.log_input = FALSE;
452                         }
453                 |       cmndtag LOG_OUTPUT {
454                             $$.log_output = TRUE;
455                         }
456                 |       cmndtag NOLOG_OUTPUT {
457                             $$.log_output = FALSE;
458                         }
459                 ;
460
461 cmnd            :       ALL {
462                             $$ = new_member(NULL, ALL);
463                         }
464                 |       ALIAS {
465                             $$ = new_member($1, ALIAS);
466                         }
467                 |       COMMAND {
468                             struct sudo_command *c = emalloc(sizeof(*c));
469                             c->cmnd = $1.cmnd;
470                             c->args = $1.args;
471                             $$ = new_member((char *)c, COMMAND);
472                         }
473                 ;
474
475 hostaliases     :       hostalias
476                 |       hostaliases ':' hostalias
477                 ;
478
479 hostalias       :       ALIAS '=' hostlist {
480                             char *s;
481                             if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) {
482                                 yyerror(s);
483                                 YYERROR;
484                             }
485                         }
486                 ;
487
488 hostlist        :       ophost
489                 |       hostlist ',' ophost {
490                             list_append($1, $3);
491                             $$ = $1;
492                         }
493                 ;
494
495 cmndaliases     :       cmndalias
496                 |       cmndaliases ':' cmndalias
497                 ;
498
499 cmndalias       :       ALIAS '=' cmndlist {
500                             char *s;
501                             if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) {
502                                 yyerror(s);
503                                 YYERROR;
504                             }
505                         }
506                 ;
507
508 cmndlist        :       opcmnd
509                 |       cmndlist ',' opcmnd {
510                             list_append($1, $3);
511                             $$ = $1;
512                         }
513                 ;
514
515 runasaliases    :       runasalias
516                 |       runasaliases ':' runasalias
517                 ;
518
519 runasalias      :       ALIAS '=' userlist {
520                             char *s;
521                             if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) {
522                                 yyerror(s);
523                                 YYERROR;
524                             }
525                         }
526                 ;
527
528 useraliases     :       useralias
529                 |       useraliases ':' useralias
530                 ;
531
532 useralias       :       ALIAS '=' userlist {
533                             char *s;
534                             if ((s = alias_add($1, USERALIAS, $3)) != NULL) {
535                                 yyerror(s);
536                                 YYERROR;
537                             }
538                         }
539                 ;
540
541 userlist        :       opuser
542                 |       userlist ',' opuser {
543                             list_append($1, $3);
544                             $$ = $1;
545                         }
546                 ;
547
548 opuser          :       user {
549                             $$ = $1;
550                             $$->negated = FALSE;
551                         }
552                 |       '!' user {
553                             $$ = $2;
554                             $$->negated = TRUE;
555                         }
556                 ;
557
558 user            :       ALIAS {
559                             $$ = new_member($1, ALIAS);
560                         }
561                 |       ALL {
562                             $$ = new_member(NULL, ALL);
563                         }
564                 |       NETGROUP {
565                             $$ = new_member($1, NETGROUP);
566                         }
567                 |       USERGROUP {
568                             $$ = new_member($1, USERGROUP);
569                         }
570                 |       WORD {
571                             $$ = new_member($1, WORD);
572                         }
573                 ;
574
575 grouplist       :       opgroup
576                 |       grouplist ',' opgroup {
577                             list_append($1, $3);
578                             $$ = $1;
579                         }
580                 ;
581
582 opgroup         :       group {
583                             $$ = $1;
584                             $$->negated = FALSE;
585                         }
586                 |       '!' group {
587                             $$ = $2;
588                             $$->negated = TRUE;
589                         }
590                 ;
591
592 group           :       ALIAS {
593                             $$ = new_member($1, ALIAS);
594                         }
595                 |       ALL {
596                             $$ = new_member(NULL, ALL);
597                         }
598                 |       WORD {
599                             $$ = new_member($1, WORD);
600                         }
601                 ;
602
603 %%
604 static struct defaults *
605 new_default(char *var, char *val, int op)
606 {
607     struct defaults *d;
608
609     d = emalloc(sizeof(struct defaults));
610     d->var = var;
611     d->val = val;
612     tq_init(&d->binding);
613     d->type = 0;
614     d->op = op;
615     d->prev = d;
616     d->next = NULL;
617
618     return d;
619 }
620
621 static struct member *
622 new_member(char *name, int type)
623 {
624     struct member *m;
625
626     m = emalloc(sizeof(struct member));
627     m->name = name;
628     m->type = type;
629     m->prev = m;
630     m->next = NULL;
631
632     return m;
633 }
634
635 /*
636  * Add a list of defaults structures to the defaults list.
637  * The binding, if non-NULL, specifies a list of hosts, users, or
638  * runas users the entries apply to (specified by the type).
639  */
640 static void
641 add_defaults(int type, struct member *bmem, struct defaults *defs)
642 {
643     struct defaults *d;
644     struct member_list binding;
645
646     /*
647      * We can only call list2tq once on bmem as it will zero
648      * out the prev pointer when it consumes bmem.
649      */
650     list2tq(&binding, bmem);
651
652     /*
653      * Set type and binding (who it applies to) for new entries.
654      */
655     for (d = defs; d != NULL; d = d->next) {
656         d->type = type;
657         d->binding = binding;
658     }
659     tq_append(&defaults, defs);
660 }
661
662 /*
663  * Allocate a new struct userspec, populate it, and insert it at the
664  * and of the userspecs list.
665  */
666 static void
667 add_userspec(struct member *members, struct privilege *privs)
668 {
669     struct userspec *u;
670
671     u = emalloc(sizeof(*u));
672     list2tq(&u->users, members);
673     list2tq(&u->privileges, privs);
674     u->prev = u;
675     u->next = NULL;
676     tq_append(&userspecs, u);
677 }
678
679 /*
680  * Free up space used by data structures from a previous parser run and sets
681  * the current sudoers file to path.
682  */
683 void
684 init_parser(const char *path, int quiet)
685 {
686     struct defaults *d;
687     struct member *m, *binding;
688     struct userspec *us;
689     struct privilege *priv;
690     struct cmndspec *cs;
691     struct sudo_command *c;
692
693     while ((us = tq_pop(&userspecs)) != NULL) {
694         while ((m = tq_pop(&us->users)) != NULL) {
695             efree(m->name);
696             efree(m);
697         }
698         while ((priv = tq_pop(&us->privileges)) != NULL) {
699             struct member *runasuser = NULL, *runasgroup = NULL;
700 #ifdef HAVE_SELINUX
701             char *role = NULL, *type = NULL;
702 #endif /* HAVE_SELINUX */
703
704             while ((m = tq_pop(&priv->hostlist)) != NULL) {
705                 efree(m->name);
706                 efree(m);
707             }
708             while ((cs = tq_pop(&priv->cmndlist)) != NULL) {
709 #ifdef HAVE_SELINUX
710                 /* Only free the first instance of a role/type. */
711                 if (cs->role != role) {
712                     role = cs->role;
713                     efree(cs->role);
714                 }
715                 if (cs->type != type) {
716                     type = cs->type;
717                     efree(cs->type);
718                 }
719 #endif /* HAVE_SELINUX */
720                 if (tq_last(&cs->runasuserlist) != runasuser) {
721                     runasuser = tq_last(&cs->runasuserlist);
722                     while ((m = tq_pop(&cs->runasuserlist)) != NULL) {
723                         efree(m->name);
724                         efree(m);
725                     }
726                 }
727                 if (tq_last(&cs->runasgrouplist) != runasgroup) {
728                     runasgroup = tq_last(&cs->runasgrouplist);
729                     while ((m = tq_pop(&cs->runasgrouplist)) != NULL) {
730                         efree(m->name);
731                         efree(m);
732                     }
733                 }
734                 if (cs->cmnd->type == COMMAND) {
735                         c = (struct sudo_command *) cs->cmnd->name;
736                         efree(c->cmnd);
737                         efree(c->args);
738                 }
739                 efree(cs->cmnd->name);
740                 efree(cs->cmnd);
741                 efree(cs);
742             }
743             efree(priv);
744         }
745         efree(us);
746     }
747     tq_init(&userspecs);
748
749     binding = NULL;
750     while ((d = tq_pop(&defaults)) != NULL) {
751         if (tq_last(&d->binding) != binding) {
752             binding = tq_last(&d->binding);
753             while ((m = tq_pop(&d->binding)) != NULL) {
754                 if (m->type == COMMAND) {
755                         c = (struct sudo_command *) m->name;
756                         efree(c->cmnd);
757                         efree(c->args);
758                 }
759                 efree(m->name);
760                 efree(m);
761             }
762         }
763         efree(d->var);
764         efree(d->val);
765         efree(d);
766     }
767     tq_init(&defaults);
768
769     init_aliases();
770
771     init_lexer();
772
773     efree(sudoers);
774     sudoers = path ? estrdup(path) : NULL;
775
776     parse_error = FALSE;
777     errorlineno = -1;
778     errorfile = NULL;
779     verbose = !quiet;
780 }