Imported Upstream version 1.8.7
[debian/sudo] / plugins / sudoers / gram.y
1 %{
2 /*
3  * Copyright (c) 1996, 1998-2005, 2007-2013
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 <stdio.h>
29 #ifdef STDC_HEADERS
30 # include <stdlib.h>
31 # include <stddef.h>
32 #else
33 # ifdef HAVE_STDLIB_H
34 #  include <stdlib.h>
35 # endif
36 #endif /* STDC_HEADERS */
37 #ifdef HAVE_STRING_H
38 # include <string.h>
39 #endif /* HAVE_STRING_H */
40 #ifdef HAVE_STRINGS_H
41 # include <strings.h>
42 #endif /* HAVE_STRINGS_H */
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif /* HAVE_UNISTD_H */
46 #ifdef HAVE_INTTYPES_H
47 # include <inttypes.h>
48 #endif
49 #if defined(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
50 # include <alloca.h>
51 #endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */
52 #include <limits.h>
53
54 #include "sudoers.h" /* XXX */
55 #include "parse.h"
56 #include "toke.h"
57
58 /*
59  * We must define SIZE_MAX for yacc's skeleton.c.
60  * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
61  * could be signed (as it is on SunOS 4.x).
62  */
63 #ifndef SIZE_MAX
64 # ifdef SIZE_T_MAX
65 #  define SIZE_MAX      SIZE_T_MAX
66 # else
67 #  define SIZE_MAX      INT_MAX
68 # endif /* SIZE_T_MAX */
69 #endif /* SIZE_MAX */
70
71 /*
72  * Globals
73  */
74 extern int sudolineno;
75 extern int last_token;
76 extern char *sudoers;
77 bool sudoers_warnings = true;
78 bool parse_error = false;
79 int errorlineno = -1;
80 char *errorfile = NULL;
81
82 struct defaults_list defaults;
83 struct userspec_list userspecs;
84
85 /*
86  * Local protoypes
87  */
88 static void  add_defaults(int, struct member *, struct defaults *);
89 static void  add_userspec(struct member *, struct privilege *);
90 static struct defaults *new_default(char *, char *, int);
91 static struct member *new_member(char *, int);
92 static struct sudo_digest *new_digest(int, const char *);
93 %}
94
95 %union {
96     struct cmndspec *cmndspec;
97     struct defaults *defaults;
98     struct member *member;
99     struct runascontainer *runas;
100     struct privilege *privilege;
101     struct sudo_digest *digest;
102     struct sudo_command command;
103     struct cmndtag tag;
104     struct selinux_info seinfo;
105     struct solaris_privs_info privinfo;
106     char *string;
107     int tok;
108 }
109
110 %start file                             /* special start symbol */
111 %token <command> COMMAND                /* absolute pathname w/ optional args */
112 %token <string>  ALIAS                  /* an UPPERCASE alias name */
113 %token <string>  DEFVAR                 /* a Defaults variable name */
114 %token <string>  NTWKADDR               /* ipv4 or ipv6 address */
115 %token <string>  NETGROUP               /* a netgroup (+NAME) */
116 %token <string>  USERGROUP              /* a usergroup (%NAME) */
117 %token <string>  WORD                   /* a word */
118 %token <string>  DIGEST                 /* a SHA-2 digest */
119 %token <tok>     DEFAULTS               /* Defaults entry */
120 %token <tok>     DEFAULTS_HOST          /* Host-specific defaults entry */
121 %token <tok>     DEFAULTS_USER          /* User-specific defaults entry */
122 %token <tok>     DEFAULTS_RUNAS         /* Runas-specific defaults entry */
123 %token <tok>     DEFAULTS_CMND          /* Command-specific defaults entry */
124 %token <tok>     NOPASSWD               /* no passwd req for command */
125 %token <tok>     PASSWD                 /* passwd req for command (default) */
126 %token <tok>     NOEXEC                 /* preload dummy execve() for cmnd */
127 %token <tok>     EXEC                   /* don't preload dummy execve() */
128 %token <tok>     SETENV                 /* user may set environment for cmnd */
129 %token <tok>     NOSETENV               /* user may not set environment */
130 %token <tok>     LOG_INPUT              /* log user's cmnd input */
131 %token <tok>     NOLOG_INPUT            /* don't log user's cmnd input */
132 %token <tok>     LOG_OUTPUT             /* log cmnd output */
133 %token <tok>     NOLOG_OUTPUT           /* don't log cmnd output */
134 %token <tok>     ALL                    /* ALL keyword */
135 %token <tok>     COMMENT                /* comment and/or carriage return */
136 %token <tok>     HOSTALIAS              /* Host_Alias keyword */
137 %token <tok>     CMNDALIAS              /* Cmnd_Alias keyword */
138 %token <tok>     USERALIAS              /* User_Alias keyword */
139 %token <tok>     RUNASALIAS             /* Runas_Alias keyword */
140 %token <tok>     ':' '=' ',' '!' '+' '-' /* union member tokens */
141 %token <tok>     '(' ')'                /* runas tokens */
142 %token <tok>     ERROR
143 %token <tok>     TYPE                   /* SELinux type */
144 %token <tok>     ROLE                   /* SELinux role */
145 %token <tok>     PRIVS                  /* Solaris privileges */
146 %token <tok>     LIMITPRIVS             /* Solaris limit privileges */
147 %token <tok>     MYSELF                 /* run as myself, not another user */
148 %token <tok>     SHA224                 /* sha224 digest */
149 %token <tok>     SHA256                 /* sha256 digest */
150 %token <tok>     SHA384                 /* sha384 digest */
151 %token <tok>     SHA512                 /* sha512 digest */
152
153 %type <cmndspec>  cmndspec
154 %type <cmndspec>  cmndspeclist
155 %type <defaults>  defaults_entry
156 %type <defaults>  defaults_list
157 %type <member>    cmnd
158 %type <member>    opcmnd
159 %type <member>    digcmnd
160 %type <member>    cmndlist
161 %type <member>    host
162 %type <member>    hostlist
163 %type <member>    ophost
164 %type <member>    opuser
165 %type <member>    user
166 %type <member>    userlist
167 %type <member>    opgroup
168 %type <member>    group
169 %type <member>    grouplist
170 %type <runas>     runasspec
171 %type <runas>     runaslist
172 %type <privilege> privilege
173 %type <privilege> privileges
174 %type <tag>       cmndtag
175 %type <seinfo>    selinux
176 %type <string>    rolespec
177 %type <string>    typespec
178 %type <privinfo>  solarisprivs
179 %type <string>    privsspec
180 %type <string>    limitprivsspec
181 %type <digest>    digest
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 = ecalloc(1, 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 #ifdef HAVE_PRIV_SET
310                             /* propagate privs & limitprivs */
311                             if ($3->privs == NULL)
312                                 $3->privs = $3->prev->privs;
313                             if ($3->limitprivs == NULL)
314                                 $3->limitprivs = $3->prev->limitprivs;
315 #endif /* HAVE_PRIV_SET */
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 solarisprivs cmndtag digcmnd {
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 #ifdef HAVE_PRIV_SET
354                             cs->privs = $3.privs;
355                             cs->limitprivs = $3.limitprivs;
356 #endif
357                             cs->tags = $4;
358                             cs->cmnd = $5;
359                             cs->prev = cs;
360                             cs->next = NULL;
361                             /* sudo "ALL" implies the SETENV tag */
362                             if (cs->cmnd->type == ALL && !cs->cmnd->negated &&
363                                 cs->tags.setenv == UNSPEC)
364                                 cs->tags.setenv = IMPLIED;
365                             $$ = cs;
366                         }
367                 ;
368
369 digest          :       SHA224 ':' DIGEST {
370                             $$ = new_digest(SUDO_DIGEST_SHA224, $3);
371                         }
372                 |       SHA256 ':' DIGEST {
373                             $$ = new_digest(SUDO_DIGEST_SHA256, $3);
374                         }
375                 |       SHA384 ':' DIGEST {
376                             $$ = new_digest(SUDO_DIGEST_SHA384, $3);
377                         }
378                 |       SHA512 ':' DIGEST {
379                             $$ = new_digest(SUDO_DIGEST_SHA512, $3);
380                         }
381                 ;
382
383 digcmnd         :       opcmnd {
384                             $$ = $1;
385                         }
386                 |       digest opcmnd {
387                             /* XXX - yuck */
388                             struct sudo_command *c = (struct sudo_command *)($2->name);
389                             c->digest = $1;
390                             $$ = $2;
391                         }
392                 ;
393
394 opcmnd          :       cmnd {
395                             $$ = $1;
396                             $$->negated = false;
397                         }
398                 |       '!' cmnd {
399                             $$ = $2;
400                             $$->negated = true;
401                         }
402                 ;
403
404 rolespec        :       ROLE '=' WORD {
405                             $$ = $3;
406                         }
407                 ;
408
409 typespec        :       TYPE '=' WORD {
410                             $$ = $3;
411                         }
412                 ;
413
414 selinux         :       /* empty */ {
415                             $$.role = NULL;
416                             $$.type = NULL;
417                         }
418                 |       rolespec {
419                             $$.role = $1;
420                             $$.type = NULL;
421                         }
422                 |       typespec {
423                             $$.type = $1;
424                             $$.role = NULL;
425                         }
426                 |       rolespec typespec {
427                             $$.role = $1;
428                             $$.type = $2;
429                         }
430                 |       typespec rolespec {
431                             $$.type = $1;
432                             $$.role = $2;
433                         }
434                 ;
435
436 privsspec       :       PRIVS '=' WORD {
437                             $$ = $3;
438                         }
439                 ;
440 limitprivsspec  :       LIMITPRIVS '=' WORD {
441                             $$ = $3;
442                         }
443                 ;
444
445 solarisprivs    :       /* empty */ {
446                             $$.privs = NULL;
447                             $$.limitprivs = NULL;
448                         }
449                 |       privsspec {
450                             $$.privs = $1;
451                             $$.limitprivs = NULL;
452                         }
453                 |       limitprivsspec {
454                             $$.privs = NULL;
455                             $$.limitprivs = $1;
456                         }
457                 |       privsspec limitprivsspec {
458                             $$.privs = $1;
459                             $$.limitprivs = $2;
460                         }
461                 |       limitprivsspec privsspec {
462                             $$.limitprivs = $1;
463                             $$.privs = $2;
464                         }
465                 ;
466
467 runasspec       :       /* empty */ {
468                             $$ = NULL;
469                         }
470                 |       '(' runaslist ')' {
471                             $$ = $2;
472                         }
473                 ;
474
475 runaslist       :       /* empty */ {
476                             $$ = ecalloc(1, sizeof(struct runascontainer));
477                             $$->runasusers = new_member(NULL, MYSELF);
478                             /* $$->runasgroups = NULL; */
479                         }
480                 |       userlist {
481                             $$ = ecalloc(1, sizeof(struct runascontainer));
482                             $$->runasusers = $1;
483                             /* $$->runasgroups = NULL; */
484                         }
485                 |       userlist ':' grouplist {
486                             $$ = ecalloc(1, sizeof(struct runascontainer));
487                             $$->runasusers = $1;
488                             $$->runasgroups = $3;
489                         }
490                 |       ':' grouplist {
491                             $$ = ecalloc(1, sizeof(struct runascontainer));
492                             /* $$->runasusers = NULL; */
493                             $$->runasgroups = $2;
494                         }
495                 |       ':' {
496                             $$ = ecalloc(1, sizeof(struct runascontainer));
497                             $$->runasusers = new_member(NULL, MYSELF);
498                             /* $$->runasgroups = NULL; */
499                         }
500                 ;
501
502 cmndtag         :       /* empty */ {
503                             $$.nopasswd = $$.noexec = $$.setenv =
504                                 $$.log_input = $$.log_output = UNSPEC;
505                         }
506                 |       cmndtag NOPASSWD {
507                             $$.nopasswd = true;
508                         }
509                 |       cmndtag PASSWD {
510                             $$.nopasswd = false;
511                         }
512                 |       cmndtag NOEXEC {
513                             $$.noexec = true;
514                         }
515                 |       cmndtag EXEC {
516                             $$.noexec = false;
517                         }
518                 |       cmndtag SETENV {
519                             $$.setenv = true;
520                         }
521                 |       cmndtag NOSETENV {
522                             $$.setenv = false;
523                         }
524                 |       cmndtag LOG_INPUT {
525                             $$.log_input = true;
526                         }
527                 |       cmndtag NOLOG_INPUT {
528                             $$.log_input = false;
529                         }
530                 |       cmndtag LOG_OUTPUT {
531                             $$.log_output = true;
532                         }
533                 |       cmndtag NOLOG_OUTPUT {
534                             $$.log_output = false;
535                         }
536                 ;
537
538 cmnd            :       ALL {
539                             $$ = new_member(NULL, ALL);
540                         }
541                 |       ALIAS {
542                             $$ = new_member($1, ALIAS);
543                         }
544                 |       COMMAND {
545                             struct sudo_command *c = ecalloc(1, sizeof(*c));
546                             c->cmnd = $1.cmnd;
547                             c->args = $1.args;
548                             $$ = new_member((char *)c, COMMAND);
549                         }
550                 ;
551
552 hostaliases     :       hostalias
553                 |       hostaliases ':' hostalias
554                 ;
555
556 hostalias       :       ALIAS '=' hostlist {
557                             char *s;
558                             if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) {
559                                 sudoerserror(s);
560                                 YYERROR;
561                             }
562                         }
563                 ;
564
565 hostlist        :       ophost
566                 |       hostlist ',' ophost {
567                             list_append($1, $3);
568                             $$ = $1;
569                         }
570                 ;
571
572 cmndaliases     :       cmndalias
573                 |       cmndaliases ':' cmndalias
574                 ;
575
576 cmndalias       :       ALIAS '=' cmndlist {
577                             char *s;
578                             if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) {
579                                 sudoerserror(s);
580                                 YYERROR;
581                             }
582                         }
583                 ;
584
585 cmndlist        :       digcmnd
586                 |       cmndlist ',' digcmnd {
587                             list_append($1, $3);
588                             $$ = $1;
589                         }
590                 ;
591
592 runasaliases    :       runasalias
593                 |       runasaliases ':' runasalias
594                 ;
595
596 runasalias      :       ALIAS '=' userlist {
597                             char *s;
598                             if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) {
599                                 sudoerserror(s);
600                                 YYERROR;
601                             }
602                         }
603                 ;
604
605 useraliases     :       useralias
606                 |       useraliases ':' useralias
607                 ;
608
609 useralias       :       ALIAS '=' userlist {
610                             char *s;
611                             if ((s = alias_add($1, USERALIAS, $3)) != NULL) {
612                                 sudoerserror(s);
613                                 YYERROR;
614                             }
615                         }
616                 ;
617
618 userlist        :       opuser
619                 |       userlist ',' opuser {
620                             list_append($1, $3);
621                             $$ = $1;
622                         }
623                 ;
624
625 opuser          :       user {
626                             $$ = $1;
627                             $$->negated = false;
628                         }
629                 |       '!' user {
630                             $$ = $2;
631                             $$->negated = true;
632                         }
633                 ;
634
635 user            :       ALIAS {
636                             $$ = new_member($1, ALIAS);
637                         }
638                 |       ALL {
639                             $$ = new_member(NULL, ALL);
640                         }
641                 |       NETGROUP {
642                             $$ = new_member($1, NETGROUP);
643                         }
644                 |       USERGROUP {
645                             $$ = new_member($1, USERGROUP);
646                         }
647                 |       WORD {
648                             $$ = new_member($1, WORD);
649                         }
650                 ;
651
652 grouplist       :       opgroup
653                 |       grouplist ',' opgroup {
654                             list_append($1, $3);
655                             $$ = $1;
656                         }
657                 ;
658
659 opgroup         :       group {
660                             $$ = $1;
661                             $$->negated = false;
662                         }
663                 |       '!' group {
664                             $$ = $2;
665                             $$->negated = true;
666                         }
667                 ;
668
669 group           :       ALIAS {
670                             $$ = new_member($1, ALIAS);
671                         }
672                 |       ALL {
673                             $$ = new_member(NULL, ALL);
674                         }
675                 |       WORD {
676                             $$ = new_member($1, WORD);
677                         }
678                 ;
679
680 %%
681 void
682 sudoerserror(const char *s)
683 {
684     debug_decl(sudoerserror, SUDO_DEBUG_PARSER)
685
686     /* If we last saw a newline the error is on the preceding line. */
687     if (last_token == COMMENT)
688         sudolineno--;
689
690     /* Save the line the first error occurred on. */
691     if (errorlineno == -1) {
692         errorlineno = sudolineno;
693         errorfile = estrdup(sudoers);
694     }
695     if (sudoers_warnings && s != NULL) {
696         LEXTRACE("<*> ");
697 #ifndef TRACELEXER
698         if (trace_print == NULL || trace_print == sudoers_trace_print) {
699             const char fmt[] = ">>> %s: %s near line %d <<<\n";
700             int oldlocale;
701
702             /* Warnings are displayed in the user's locale. */
703             sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale);
704             sudo_printf(SUDO_CONV_ERROR_MSG, _(fmt), sudoers, _(s), sudolineno);
705             sudoers_setlocale(oldlocale, NULL);
706         }
707 #endif
708     }
709     parse_error = true;
710     debug_return;
711 }
712
713 static struct defaults *
714 new_default(char *var, char *val, int op)
715 {
716     struct defaults *d;
717     debug_decl(new_default, SUDO_DEBUG_PARSER)
718
719     d = ecalloc(1, sizeof(struct defaults));
720     d->var = var;
721     d->val = val;
722     tq_init(&d->binding);
723     /* d->type = 0; */
724     d->op = op;
725     d->prev = d;
726     /* d->next = NULL; */
727
728     debug_return_ptr(d);
729 }
730
731 static struct member *
732 new_member(char *name, int type)
733 {
734     struct member *m;
735     debug_decl(new_member, SUDO_DEBUG_PARSER)
736
737     m = ecalloc(1, sizeof(struct member));
738     m->name = name;
739     m->type = type;
740     m->prev = m;
741     /* m->next = NULL; */
742
743     debug_return_ptr(m);
744 }
745
746 struct sudo_digest *
747 new_digest(int digest_type, const char *digest_str)
748 {
749     struct sudo_digest *dig;
750     debug_decl(new_digest, SUDO_DEBUG_PARSER)
751
752     dig = emalloc(sizeof(*dig));
753     dig->digest_type = digest_type;
754     dig->digest_str = estrdup(digest_str);
755
756     debug_return_ptr(dig);
757 }
758
759 /*
760  * Add a list of defaults structures to the defaults list.
761  * The binding, if non-NULL, specifies a list of hosts, users, or
762  * runas users the entries apply to (specified by the type).
763  */
764 static void
765 add_defaults(int type, struct member *bmem, struct defaults *defs)
766 {
767     struct defaults *d;
768     struct member_list binding;
769     debug_decl(add_defaults, SUDO_DEBUG_PARSER)
770
771     /*
772      * We can only call list2tq once on bmem as it will zero
773      * out the prev pointer when it consumes bmem.
774      */
775     list2tq(&binding, bmem);
776
777     /*
778      * Set type and binding (who it applies to) for new entries.
779      */
780     for (d = defs; d != NULL; d = d->next) {
781         d->type = type;
782         d->binding = binding;
783     }
784     tq_append(&defaults, defs);
785
786     debug_return;
787 }
788
789 /*
790  * Allocate a new struct userspec, populate it, and insert it at the
791  * and of the userspecs list.
792  */
793 static void
794 add_userspec(struct member *members, struct privilege *privs)
795 {
796     struct userspec *u;
797     debug_decl(add_userspec, SUDO_DEBUG_PARSER)
798
799     u = ecalloc(1, sizeof(*u));
800     list2tq(&u->users, members);
801     list2tq(&u->privileges, privs);
802     u->prev = u;
803     /* u->next = NULL; */
804     tq_append(&userspecs, u);
805
806     debug_return;
807 }
808
809 /*
810  * Free up space used by data structures from a previous parser run and sets
811  * the current sudoers file to path.
812  */
813 void
814 init_parser(const char *path, bool quiet)
815 {
816     struct defaults *d;
817     struct member *m, *binding;
818     struct userspec *us;
819     struct privilege *priv;
820     struct cmndspec *cs;
821     struct sudo_command *c;
822     debug_decl(init_parser, SUDO_DEBUG_PARSER)
823
824     while ((us = tq_pop(&userspecs)) != NULL) {
825         while ((m = tq_pop(&us->users)) != NULL) {
826             efree(m->name);
827             efree(m);
828         }
829         while ((priv = tq_pop(&us->privileges)) != NULL) {
830             struct member *runasuser = NULL, *runasgroup = NULL;
831 #ifdef HAVE_SELINUX
832             char *role = NULL, *type = NULL;
833 #endif /* HAVE_SELINUX */
834 #ifdef HAVE_PRIV_SET
835             char *privs = NULL, *limitprivs = NULL;
836 #endif /* HAVE_PRIV_SET */
837
838             while ((m = tq_pop(&priv->hostlist)) != NULL) {
839                 efree(m->name);
840                 efree(m);
841             }
842             while ((cs = tq_pop(&priv->cmndlist)) != NULL) {
843 #ifdef HAVE_SELINUX
844                 /* Only free the first instance of a role/type. */
845                 if (cs->role != role) {
846                     role = cs->role;
847                     efree(cs->role);
848                 }
849                 if (cs->type != type) {
850                     type = cs->type;
851                     efree(cs->type);
852                 }
853 #endif /* HAVE_SELINUX */
854 #ifdef HAVE_PRIV_SET
855                 /* Only free the first instance of privs/limitprivs. */
856                 if (cs->privs != privs) {
857                     privs = cs->privs;
858                     efree(cs->privs);
859                 }
860                 if (cs->limitprivs != limitprivs) {
861                     limitprivs = cs->limitprivs;
862                     efree(cs->limitprivs);
863                 }
864 #endif /* HAVE_PRIV_SET */
865                 if (tq_last(&cs->runasuserlist) != runasuser) {
866                     runasuser = tq_last(&cs->runasuserlist);
867                     while ((m = tq_pop(&cs->runasuserlist)) != NULL) {
868                         efree(m->name);
869                         efree(m);
870                     }
871                 }
872                 if (tq_last(&cs->runasgrouplist) != runasgroup) {
873                     runasgroup = tq_last(&cs->runasgrouplist);
874                     while ((m = tq_pop(&cs->runasgrouplist)) != NULL) {
875                         efree(m->name);
876                         efree(m);
877                     }
878                 }
879                 if (cs->cmnd->type == COMMAND) {
880                         c = (struct sudo_command *) cs->cmnd->name;
881                         efree(c->cmnd);
882                         efree(c->args);
883                 }
884                 efree(cs->cmnd->name);
885                 efree(cs->cmnd);
886                 efree(cs);
887             }
888             efree(priv);
889         }
890         efree(us);
891     }
892     tq_init(&userspecs);
893
894     binding = NULL;
895     while ((d = tq_pop(&defaults)) != NULL) {
896         if (tq_last(&d->binding) != binding) {
897             binding = tq_last(&d->binding);
898             while ((m = tq_pop(&d->binding)) != NULL) {
899                 if (m->type == COMMAND) {
900                         c = (struct sudo_command *) m->name;
901                         efree(c->cmnd);
902                         efree(c->args);
903                 }
904                 efree(m->name);
905                 efree(m);
906             }
907         }
908         efree(d->var);
909         efree(d->val);
910         efree(d);
911     }
912     tq_init(&defaults);
913
914     init_aliases();
915
916     init_lexer();
917
918     efree(sudoers);
919     sudoers = path ? estrdup(path) : NULL;
920
921     parse_error = false;
922     errorlineno = -1;
923     errorfile = sudoers;
924     sudoers_warnings = !quiet;
925
926     debug_return;
927 }