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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>