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