1 %{
2 /*
3 * SPDX-License-Identifier: ISC
4 *
5 * Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2021
6 * Todd C. Miller <Todd.Miller@sudo.ws>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
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 <stdio.h>
28 #include <stdlib.h>
29 #include <stddef.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <errno.h>
33
34 #include "sudoers.h"
35 #include "sudo_digest.h"
36 #include "toke.h"
37
38 #ifdef YYBISON
39 # define YYERROR_VERBOSE
40 #endif
41
42 /* If we last saw a newline the entry is on the preceding line. */
43 #define this_lineno (sudoerschar == '\n' ? sudolineno - 1 : sudolineno)
44
45 // PVS Studio suppression
46 // -V::1037, 1042
47
48 /*
49 * Globals
50 */
51 bool sudoers_warnings = true;
52 bool sudoers_strict = false;
53 bool parse_error = false;
54 int errorlineno = -1;
55 char *errorfile = NULL;
56
57 static int alias_line, alias_column;
58
59 #ifdef NO_LEAKS
60 static struct parser_leak_list parser_leak_list =
61 SLIST_HEAD_INITIALIZER(parser_leak_list);
62 #endif
63
64 struct sudoers_parse_tree parsed_policy = {
65 TAILQ_HEAD_INITIALIZER(parsed_policy.userspecs),
66 TAILQ_HEAD_INITIALIZER(parsed_policy.defaults),
67 NULL, /* aliases */
68 NULL, /* lhost */
69 NULL /* shost */
70 };
71
72 /*
73 * Local prototypes
74 */
75 static void init_options(struct command_options *opts);
76 static bool add_defaults(int, struct member *, struct defaults *);
77 static bool add_userspec(struct member *, struct privilege *);
78 static struct defaults *new_default(char *, char *, short);
79 static struct member *new_member(char *, int);
80 static struct sudo_command *new_command(char *, char *);
81 static struct command_digest *new_digest(int, char *);
82 static void alias_error(const char *name, int errnum);
83 %}
84
85 %union {
86 struct cmndspec *cmndspec;
87 struct defaults *defaults;
88 struct member *member;
89 struct runascontainer *runas;
90 struct privilege *privilege;
91 struct command_digest *digest;
92 struct sudo_command command;
93 struct command_options options;
94 struct cmndtag tag;
95 char *string;
96 int tok;
97 }
98
99 %start file /* special start symbol */
100 %token <command> COMMAND /* absolute pathname w/ optional args */
101 %token <string> ALIAS /* an UPPERCASE alias name */
102 %token <string> DEFVAR /* a Defaults variable name */
103 %token <string> NTWKADDR /* ipv4 or ipv6 address */
104 %token <string> NETGROUP /* a netgroup (+NAME) */
105 %token <string> USERGROUP /* a usergroup (%NAME) */
106 %token <string> WORD /* a word */
107 %token <string> DIGEST /* a SHA-2 digest */
108 %token <tok> INCLUDE /* @include */
109 %token <tok> INCLUDEDIR /* @includedir */
110 %token <tok> DEFAULTS /* Defaults entry */
111 %token <tok> DEFAULTS_HOST /* Host-specific defaults entry */
112 %token <tok> DEFAULTS_USER /* User-specific defaults entry */
113 %token <tok> DEFAULTS_RUNAS /* Runas-specific defaults entry */
114 %token <tok> DEFAULTS_CMND /* Command-specific defaults entry */
115 %token <tok> NOPASSWD /* no passwd req for command */
116 %token <tok> PASSWD /* passwd req for command (default) */
117 %token <tok> NOEXEC /* preload fake execve() for cmnd */
118 %token <tok> EXEC /* don't preload fake execve() */
119 %token <tok> SETENV /* user may set environment for cmnd */
120 %token <tok> NOSETENV /* user may not set environment */
121 %token <tok> LOG_INPUT /* log user's cmnd input */
122 %token <tok> NOLOG_INPUT /* don't log user's cmnd input */
123 %token <tok> LOG_OUTPUT /* log cmnd output */
124 %token <tok> NOLOG_OUTPUT /* don't log cmnd output */
125 %token <tok> MAIL /* mail log message */
126 %token <tok> NOMAIL /* don't mail log message */
127 %token <tok> FOLLOWLNK /* follow symbolic links */
128 %token <tok> NOFOLLOWLNK /* don't follow symbolic links */
129 %token <tok> INTERCEPT /* intercept children of command */
130 %token <tok> NOINTERCEPT /* disable intercepting of children */
131 %token <tok> ALL /* ALL keyword */
132 %token <tok> HOSTALIAS /* Host_Alias keyword */
133 %token <tok> CMNDALIAS /* Cmnd_Alias keyword */
134 %token <tok> USERALIAS /* User_Alias keyword */
135 %token <tok> RUNASALIAS /* Runas_Alias keyword */
136 %token <tok> ':' '=' ',' '!' '+' '-' /* union member tokens */
137 %token <tok> '(' ')' /* runas tokens */
138 %token <tok> '\n' /* newline (with optional comment) */
139 %token <tok> ERROR /* error from lexer */
140 %token <tok> NOMATCH /* no match from lexer */
141 %token <tok> CHROOT /* root directory for command */
142 %token <tok> CWD /* working directory for command */
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> CMND_TIMEOUT /* command timeout */
148 %token <tok> NOTBEFORE /* time restriction */
149 %token <tok> NOTAFTER /* time restriction */
150 %token <tok> MYSELF /* run as myself, not another user */
151 %token <tok> SHA224_TOK /* sha224 token */
152 %token <tok> SHA256_TOK /* sha256 token */
153 %token <tok> SHA384_TOK /* sha384 token */
154 %token <tok> SHA512_TOK /* sha512 token */
155
156 %type <cmndspec> cmndspec
157 %type <cmndspec> cmndspeclist
158 %type <defaults> defaults_entry
159 %type <defaults> defaults_list
160 %type <member> cmnd
161 %type <member> opcmnd
162 %type <member> digcmnd
163 %type <member> cmndlist
164 %type <member> host
165 %type <member> hostlist
166 %type <member> ophost
167 %type <member> opuser
168 %type <member> user
169 %type <member> userlist
170 %type <member> opgroup
171 %type <member> group
172 %type <member> grouplist
173 %type <runas> runasspec
174 %type <runas> runaslist
175 %type <privilege> privilege
176 %type <privilege> privileges
177 %type <tag> cmndtag
178 %type <options> options
179 %type <string> chdirspec
180 %type <string> chrootspec
181 %type <string> rolespec
182 %type <string> typespec
183 %type <string> privsspec
184 %type <string> limitprivsspec
185 %type <string> timeoutspec
186 %type <string> notbeforespec
187 %type <string> notafterspec
188 %type <string> include
189 %type <string> includedir
190 %type <digest> digestspec
191 %type <digest> digestlist
192 %type <string> reserved_word
193
194 %%
195
196 file : {
197 ; /* empty file */
198 }
199 | line
200 ;
201
202 line : entry
203 | line entry
204 ;
205
206 entry : '\n' {
207 ; /* blank line */
208 }
209 | error '\n' {
210 yyerrok;
211 }
212 | include {
213 if (!push_include($1, false)) {
214 parser_leak_remove(LEAK_PTR, $1);
215 free($1);
216 YYERROR;
217 }
218 parser_leak_remove(LEAK_PTR, $1);
219 free($1);
220 }
221 | includedir {
222 if (!push_include($1, true)) {
223 parser_leak_remove(LEAK_PTR, $1);
224 free($1);
225 YYERROR;
226 }
227 parser_leak_remove(LEAK_PTR, $1);
228 free($1);
229 }
230 | userlist privileges '\n' {
231 if (!add_userspec($1, $2)) {
232 sudoerserror(N_("unable to allocate memory"));
233 YYERROR;
234 }
235 }
236 | USERALIAS useraliases '\n' {
237 ;
238 }
239 | HOSTALIAS hostaliases '\n' {
240 ;
241 }
242 | CMNDALIAS cmndaliases '\n' {
243 ;
244 }
245 | RUNASALIAS runasaliases '\n' {
246 ;
247 }
248 | DEFAULTS defaults_list '\n' {
249 if (!add_defaults(DEFAULTS, NULL, $2))
250 YYERROR;
251 }
252 | DEFAULTS_USER userlist defaults_list '\n' {
253 if (!add_defaults(DEFAULTS_USER, $2, $3))
254 YYERROR;
255 }
256 | DEFAULTS_RUNAS userlist defaults_list '\n' {
257 if (!add_defaults(DEFAULTS_RUNAS, $2, $3))
258 YYERROR;
259 }
260 | DEFAULTS_HOST hostlist defaults_list '\n' {
261 if (!add_defaults(DEFAULTS_HOST, $2, $3))
262 YYERROR;
263 }
264 | DEFAULTS_CMND cmndlist defaults_list '\n' {
265 if (!add_defaults(DEFAULTS_CMND, $2, $3))
266 YYERROR;
267 }
268 ;
269
270 include : INCLUDE WORD '\n' {
271 $$ = $2;
272 }
273 | INCLUDE WORD error '\n' {
274 yyerrok;
275 $$ = $2;
276 }
277 ;
278
279 includedir : INCLUDEDIR WORD '\n' {
280 $$ = $2;
281 }
282 | INCLUDEDIR WORD error '\n' {
283 yyerrok;
284 $$ = $2;
285 }
286 ;
287
288 defaults_list : defaults_entry
289 | defaults_list ',' defaults_entry {
290 parser_leak_remove(LEAK_DEFAULTS, $3);
291 HLTQ_CONCAT($1, $3, entries);
292 $$ = $1;
293 }
294 ;
295
296 defaults_entry : DEFVAR {
297 $$ = new_default($1, NULL, true);
298 if ($$ == NULL) {
299 sudoerserror(N_("unable to allocate memory"));
300 YYERROR;
301 }
302 parser_leak_remove(LEAK_PTR, $1);
303 parser_leak_add(LEAK_DEFAULTS, $$);
304 }
305 | '!' DEFVAR {
306 $$ = new_default($2, NULL, false);
307 if ($$ == NULL) {
308 sudoerserror(N_("unable to allocate memory"));
309 YYERROR;
310 }
311 parser_leak_remove(LEAK_PTR, $2);
312 parser_leak_add(LEAK_DEFAULTS, $$);
313 }
314 | DEFVAR '=' WORD {
315 $$ = new_default($1, $3, true);
316 if ($$ == NULL) {
317 sudoerserror(N_("unable to allocate memory"));
318 YYERROR;
319 }
320 parser_leak_remove(LEAK_PTR, $1);
321 parser_leak_remove(LEAK_PTR, $3);
322 parser_leak_add(LEAK_DEFAULTS, $$);
323 }
324 | DEFVAR '+' WORD {
325 $$ = new_default($1, $3, '+');
326 if ($$ == NULL) {
327 sudoerserror(N_("unable to allocate memory"));
328 YYERROR;
329 }
330 parser_leak_remove(LEAK_PTR, $1);
331 parser_leak_remove(LEAK_PTR, $3);
332 parser_leak_add(LEAK_DEFAULTS, $$);
333 }
334 | DEFVAR '-' WORD {
335 $$ = new_default($1, $3, '-');
336 if ($$ == NULL) {
337 sudoerserror(N_("unable to allocate memory"));
338 YYERROR;
339 }
340 parser_leak_remove(LEAK_PTR, $1);
341 parser_leak_remove(LEAK_PTR, $3);
342 parser_leak_add(LEAK_DEFAULTS, $$);
343 }
344 ;
345
346 privileges : privilege
347 | privileges ':' privilege {
348 parser_leak_remove(LEAK_PRIVILEGE, $3);
349 HLTQ_CONCAT($1, $3, entries);
350 $$ = $1;
351 }
352 | privileges ':' error {
353 yyerrok;
354 $$ = $1;
355 }
356 ;
357
358 privilege : hostlist '=' cmndspeclist {
359 struct privilege *p = calloc(1, sizeof(*p));
360 if (p == NULL) {
361 sudoerserror(N_("unable to allocate memory"));
362 YYERROR;
363 }
364 parser_leak_add(LEAK_PRIVILEGE, p);
365 TAILQ_INIT(&p->defaults);
366 parser_leak_remove(LEAK_MEMBER, $1);
367 HLTQ_TO_TAILQ(&p->hostlist, $1, entries);
368 parser_leak_remove(LEAK_CMNDSPEC, $3);
369 HLTQ_TO_TAILQ(&p->cmndlist, $3, entries);
370 HLTQ_INIT(p, entries);
371 $$ = p;
372 }
373 ;
374
375 ophost : host {
376 $$ = $1;
377 $$->negated = false;
378 }
379 | '!' host {
380 $$ = $2;
381 $$->negated = true;
382 }
383 ;
384
385 host : ALIAS {
386 $$ = new_member($1, ALIAS);
387 if ($$ == NULL) {
388 sudoerserror(N_("unable to allocate memory"));
389 YYERROR;
390 }
391 parser_leak_remove(LEAK_PTR, $1);
392 parser_leak_add(LEAK_MEMBER, $$);
393 }
394 | ALL {
395 $$ = new_member(NULL, ALL);
396 if ($$ == NULL) {
397 sudoerserror(N_("unable to allocate memory"));
398 YYERROR;
399 }
400 parser_leak_add(LEAK_MEMBER, $$);
401 }
402 | NETGROUP {
403 $$ = new_member($1, NETGROUP);
404 if ($$ == NULL) {
405 sudoerserror(N_("unable to allocate memory"));
406 YYERROR;
407 }
408 parser_leak_remove(LEAK_PTR, $1);
409 parser_leak_add(LEAK_MEMBER, $$);
410 }
411 | NTWKADDR {
412 $$ = new_member($1, NTWKADDR);
413 if ($$ == NULL) {
414 sudoerserror(N_("unable to allocate memory"));
415 YYERROR;
416 }
417 parser_leak_remove(LEAK_PTR, $1);
418 parser_leak_add(LEAK_MEMBER, $$);
419 }
420 | WORD {
421 $$ = new_member($1, WORD);
422 if ($$ == NULL) {
423 sudoerserror(N_("unable to allocate memory"));
424 YYERROR;
425 }
426 parser_leak_remove(LEAK_PTR, $1);
427 parser_leak_add(LEAK_MEMBER, $$);
428 }
429 ;
430
431 cmndspeclist : cmndspec
432 | cmndspeclist ',' cmndspec {
433 struct cmndspec *prev;
434 prev = HLTQ_LAST($1, cmndspec, entries);
435 parser_leak_remove(LEAK_CMNDSPEC, $3);
436 HLTQ_CONCAT($1, $3, entries);
437
438 /* propagate runcwd and runchroot */
439 if ($3->runcwd == NULL)
440 $3->runcwd = prev->runcwd;
441 if ($3->runchroot == NULL)
442 $3->runchroot = prev->runchroot;
443 #ifdef HAVE_SELINUX
444 /* propagate role and type */
445 if ($3->role == NULL && $3->type == NULL) {
446 $3->role = prev->role;
447 $3->type = prev->type;
448 }
449 #endif /* HAVE_SELINUX */
450 #ifdef HAVE_PRIV_SET
451 /* propagate privs & limitprivs */
452 if ($3->privs == NULL && $3->limitprivs == NULL) {
453 $3->privs = prev->privs;
454 $3->limitprivs = prev->limitprivs;
455 }
456 #endif /* HAVE_PRIV_SET */
457 /* propagate command time restrictions */
458 if ($3->notbefore == UNSPEC)
459 $3->notbefore = prev->notbefore;
460 if ($3->notafter == UNSPEC)
461 $3->notafter = prev->notafter;
462 /* propagate command timeout */
463 if ($3->timeout == UNSPEC)
464 $3->timeout = prev->timeout;
465 /* propagate tags and runas list */
466 if ($3->tags.nopasswd == UNSPEC)
467 $3->tags.nopasswd = prev->tags.nopasswd;
468 if ($3->tags.noexec == UNSPEC)
469 $3->tags.noexec = prev->tags.noexec;
470 if ($3->tags.intercept == UNSPEC)
471 $3->tags.intercept = prev->tags.intercept;
472 if ($3->tags.setenv == UNSPEC &&
473 prev->tags.setenv != IMPLIED)
474 $3->tags.setenv = prev->tags.setenv;
475 if ($3->tags.log_input == UNSPEC)
476 $3->tags.log_input = prev->tags.log_input;
477 if ($3->tags.log_output == UNSPEC)
478 $3->tags.log_output = prev->tags.log_output;
479 if ($3->tags.send_mail == UNSPEC)
480 $3->tags.send_mail = prev->tags.send_mail;
481 if ($3->tags.follow == UNSPEC)
482 $3->tags.follow = prev->tags.follow;
483 if (($3->runasuserlist == NULL &&
484 $3->runasgrouplist == NULL) &&
485 (prev->runasuserlist != NULL ||
486 prev->runasgrouplist != NULL)) {
487 $3->runasuserlist = prev->runasuserlist;
488 $3->runasgrouplist = prev->runasgrouplist;
489 }
490 $$ = $1;
491 }
492 ;
493
494 cmndspec : runasspec options cmndtag digcmnd {
495 struct cmndspec *cs = calloc(1, sizeof(*cs));
496 if (cs == NULL) {
497 sudoerserror(N_("unable to allocate memory"));
498 YYERROR;
499 }
500 parser_leak_add(LEAK_CMNDSPEC, cs);
501 if ($1 != NULL) {
502 if ($1->runasusers != NULL) {
503 cs->runasuserlist =
504 malloc(sizeof(*cs->runasuserlist));
505 if (cs->runasuserlist == NULL) {
506 free(cs);
507 sudoerserror(N_("unable to allocate memory"));
508 YYERROR;
509 }
510 /* g/c done via runas container */
511 HLTQ_TO_TAILQ(cs->runasuserlist,
512 $1->runasusers, entries);
513 }
514 if ($1->runasgroups != NULL) {
515 cs->runasgrouplist =
516 malloc(sizeof(*cs->runasgrouplist));
517 if (cs->runasgrouplist == NULL) {
518 free(cs);
519 sudoerserror(N_("unable to allocate memory"));
520 YYERROR;
521 }
522 /* g/c done via runas container */
523 HLTQ_TO_TAILQ(cs->runasgrouplist,
524 $1->runasgroups, entries);
525 }
526 parser_leak_remove(LEAK_RUNAS, $1);
527 free($1);
528 }
529 #ifdef HAVE_SELINUX
530 cs->role = $2.role;
531 parser_leak_remove(LEAK_PTR, $2.role);
532 cs->type = $2.type;
533 parser_leak_remove(LEAK_PTR, $2.type);
534 #endif
535 #ifdef HAVE_PRIV_SET
536 cs->privs = $2.privs;
537 parser_leak_remove(LEAK_PTR, $2.privs);
538 cs->limitprivs = $2.limitprivs;
539 parser_leak_remove(LEAK_PTR, $2.limitprivs);
540 #endif
541 cs->notbefore = $2.notbefore;
542 cs->notafter = $2.notafter;
543 cs->timeout = $2.timeout;
544 cs->runcwd = $2.runcwd;
545 parser_leak_remove(LEAK_PTR, $2.runcwd);
546 cs->runchroot = $2.runchroot;
547 parser_leak_remove(LEAK_PTR, $2.runchroot);
548 cs->tags = $3;
549 cs->cmnd = $4;
550 parser_leak_remove(LEAK_MEMBER, $4);
551 HLTQ_INIT(cs, entries);
552 /* sudo "ALL" implies the SETENV tag */
553 if (cs->cmnd->type == ALL && !cs->cmnd->negated &&
554 cs->tags.setenv == UNSPEC)
555 cs->tags.setenv = IMPLIED;
556 $$ = cs;
557 }
558 ;
559
560 digestspec : SHA224_TOK ':' DIGEST {
561 $$ = new_digest(SUDO_DIGEST_SHA224, $3);
562 if ($$ == NULL) {
563 sudoerserror(N_("unable to allocate memory"));
564 YYERROR;
565 }
566 parser_leak_remove(LEAK_PTR, $3);
567 parser_leak_add(LEAK_DIGEST, $$);
568 }
569 | SHA256_TOK ':' DIGEST {
570 $$ = new_digest(SUDO_DIGEST_SHA256, $3);
571 if ($$ == NULL) {
572 sudoerserror(N_("unable to allocate memory"));
573 YYERROR;
574 }
575 parser_leak_remove(LEAK_PTR, $3);
576 parser_leak_add(LEAK_DIGEST, $$);
577 }
578 | SHA384_TOK ':' DIGEST {
579 $$ = new_digest(SUDO_DIGEST_SHA384, $3);
580 if ($$ == NULL) {
581 sudoerserror(N_("unable to allocate memory"));
582 YYERROR;
583 }
584 parser_leak_remove(LEAK_PTR, $3);
585 parser_leak_add(LEAK_DIGEST, $$);
586 }
587 | SHA512_TOK ':' DIGEST {
588 $$ = new_digest(SUDO_DIGEST_SHA512, $3);
589 if ($$ == NULL) {
590 sudoerserror(N_("unable to allocate memory"));
591 YYERROR;
592 }
593 parser_leak_remove(LEAK_PTR, $3);
594 parser_leak_add(LEAK_DIGEST, $$);
595 }
596 ;
597
598 digestlist : digestspec
599 | digestlist ',' digestspec {
600 parser_leak_remove(LEAK_DIGEST, $3);
601 HLTQ_CONCAT($1, $3, entries);
602 $$ = $1;
603 }
604 ;
605
606 digcmnd : opcmnd {
607 $$ = $1;
608 }
609 | digestlist opcmnd {
610 struct sudo_command *c =
611 (struct sudo_command *) $2->name;
612
613 if ($2->type != COMMAND && $2->type != ALL) {
614 sudoerserror(N_("a digest requires a path name"));
615 YYERROR;
616 }
617 parser_leak_remove(LEAK_DIGEST, $1);
618 HLTQ_TO_TAILQ(&c->digests, $1, entries);
619 $$ = $2;
620 }
621 ;
622
623 opcmnd : cmnd {
624 $$ = $1;
625 $$->negated = false;
626 }
627 | '!' cmnd {
628 $$ = $2;
629 $$->negated = true;
630 }
631 ;
632
633 chdirspec : CWD '=' WORD {
634 if ($3[0] != '/' && $3[0] != '~') {
635 if (strcmp($3, "*") != 0) {
636 sudoerserror(N_("values for \"CWD\" must"
637 " start with a '/', '~', or '*'"));
638 YYERROR;
639 }
640 }
641 $$ = $3;
642 }
643 ;
644
645 chrootspec : CHROOT '=' WORD {
646 if ($3[0] != '/' && $3[0] != '~') {
647 if (strcmp($3, "*") != 0) {
648 sudoerserror(N_("values for \"CHROOT\" must"
649 " start with a '/', '~', or '*'"));
650 YYERROR;
651 }
652 }
653 $$ = $3;
654 }
655 ;
656
657 timeoutspec : CMND_TIMEOUT '=' WORD {
658 $$ = $3;
659 }
660 ;
661
662 notbeforespec : NOTBEFORE '=' WORD {
663 $$ = $3;
664 }
665
666 notafterspec : NOTAFTER '=' WORD {
667 $$ = $3;
668 }
669 ;
670
671 rolespec : ROLE '=' WORD {
672 $$ = $3;
673 }
674 ;
675
676 typespec : TYPE '=' WORD {
677 $$ = $3;
678 }
679 ;
680
681 privsspec : PRIVS '=' WORD {
682 $$ = $3;
683 }
684 ;
685 limitprivsspec : LIMITPRIVS '=' WORD {
686 $$ = $3;
687 }
688 ;
689
690 runasspec : /* empty */ {
691 $$ = NULL;
692 }
693 | '(' runaslist ')' {
694 $$ = $2;
695 }
696 ;
697
698 runaslist : /* empty */ {
699 $$ = calloc(1, sizeof(struct runascontainer));
700 if ($$ != NULL) {
701 $$->runasusers = new_member(NULL, MYSELF);
702 /* $$->runasgroups = NULL; */
703 if ($$->runasusers == NULL) {
704 free($$);
705 $$ = NULL;
706 }
707 }
708 if ($$ == NULL) {
709 sudoerserror(N_("unable to allocate memory"));
710 YYERROR;
711 }
712 parser_leak_add(LEAK_RUNAS, $$);
713 }
714 | userlist {
715 $$ = calloc(1, sizeof(struct runascontainer));
716 if ($$ == NULL) {
717 sudoerserror(N_("unable to allocate memory"));
718 YYERROR;
719 }
720 parser_leak_add(LEAK_RUNAS, $$);
721 parser_leak_remove(LEAK_MEMBER, $1);
722 $$->runasusers = $1;
723 /* $$->runasgroups = NULL; */
724 }
725 | userlist ':' grouplist {
726 $$ = calloc(1, sizeof(struct runascontainer));
727 if ($$ == NULL) {
728 sudoerserror(N_("unable to allocate memory"));
729 YYERROR;
730 }
731 parser_leak_add(LEAK_RUNAS, $$);
732 parser_leak_remove(LEAK_MEMBER, $1);
733 parser_leak_remove(LEAK_MEMBER, $3);
734 $$->runasusers = $1;
735 $$->runasgroups = $3;
736 }
737 | ':' grouplist {
738 $$ = calloc(1, sizeof(struct runascontainer));
739 if ($$ == NULL) {
740 sudoerserror(N_("unable to allocate memory"));
741 YYERROR;
742 }
743 parser_leak_add(LEAK_RUNAS, $$);
744 parser_leak_remove(LEAK_MEMBER, $2);
745 /* $$->runasusers = NULL; */
746 $$->runasgroups = $2;
747 }
748 | ':' {
749 $$ = calloc(1, sizeof(struct runascontainer));
750 if ($$ != NULL) {
751 $$->runasusers = new_member(NULL, MYSELF);
752 /* $$->runasgroups = NULL; */
753 if ($$->runasusers == NULL) {
754 free($$);
755 $$ = NULL;
756 }
757 }
758 if ($$ == NULL) {
759 sudoerserror(N_("unable to allocate memory"));
760 YYERROR;
761 }
762 parser_leak_add(LEAK_RUNAS, $$);
763 }
764 ;
765
766 reserved_word : ALL { $$ = "ALL"; }
767 | CHROOT { $$ = "CHROOT"; }
768 | CWD { $$ = "CWD"; }
769 | CMND_TIMEOUT { $$ = "CMND_TIMEOUT"; }
770 | NOTBEFORE { $$ = "NOTBEFORE"; }
771 | NOTAFTER { $$ = "NOTAFTER"; }
772 | ROLE { $$ = "ROLE"; }
773 | TYPE { $$ = "TYPE"; }
774 | PRIVS { $$ = "PRIVS"; }
775 | LIMITPRIVS { $$ = "LIMITPRIVS"; }
776 ;
777
778 reserved_alias : reserved_word {
779 sudoerserrorf(U_("syntax error, reserved word %s used as an alias name"), $1);
780 YYERROR;
781 }
782 ;
783
784 options : /* empty */ {
785 init_options(&$$);
786 }
787 | options chdirspec {
788 parser_leak_remove(LEAK_PTR, $$.runcwd);
789 free($$.runcwd);
790 $$.runcwd = $2;
791 }
792 | options chrootspec {
793 parser_leak_remove(LEAK_PTR, $$.runchroot);
794 free($$.runchroot);
795 $$.runchroot = $2;
796 }
797 | options notbeforespec {
798 $$.notbefore = parse_gentime($2);
799 parser_leak_remove(LEAK_PTR, $2);
800 free($2);
801 if ($$.notbefore == -1) {
802 sudoerserror(N_("invalid notbefore value"));
803 YYERROR;
804 }
805 }
806 | options notafterspec {
807 $$.notafter = parse_gentime($2);
808 parser_leak_remove(LEAK_PTR, $2);
809 free($2);
810 if ($$.notafter == -1) {
811 sudoerserror(N_("invalid notafter value"));
812 YYERROR;
813 }
814 }
815 | options timeoutspec {
816 $$.timeout = parse_timeout($2);
817 parser_leak_remove(LEAK_PTR, $2);
818 free($2);
819 if ($$.timeout == -1) {
820 if (errno == ERANGE)
821 sudoerserror(N_("timeout value too large"));
822 else
823 sudoerserror(N_("invalid timeout value"));
824 YYERROR;
825 }
826 }
827 | options rolespec {
828 #ifdef HAVE_SELINUX
829 parser_leak_remove(LEAK_PTR, $$.role);
830 free($$.role);
831 $$.role = $2;
832 #endif
833 }
834 | options typespec {
835 #ifdef HAVE_SELINUX
836 parser_leak_remove(LEAK_PTR, $$.type);
837 free($$.type);
838 $$.type = $2;
839 #endif
840 }
841 | options privsspec {
842 #ifdef HAVE_PRIV_SET
843 parser_leak_remove(LEAK_PTR, $$.privs);
844 free($$.privs);
845 $$.privs = $2;
846 #endif
847 }
848 | options limitprivsspec {
849 #ifdef HAVE_PRIV_SET
850 parser_leak_remove(LEAK_PTR, $$.limitprivs);
851 free($$.limitprivs);
852 $$.limitprivs = $2;
853 #endif
854 }
855 ;
856
857 cmndtag : /* empty */ {
858 TAGS_INIT(&$$);
859 }
860 | cmndtag NOPASSWD {
861 $$.nopasswd = true;
862 }
863 | cmndtag PASSWD {
864 $$.nopasswd = false;
865 }
866 | cmndtag NOEXEC {
867 $$.noexec = true;
868 }
869 | cmndtag EXEC {
870 $$.noexec = false;
871 }
872 | cmndtag INTERCEPT {
873 $$.intercept = true;
874 }
875 | cmndtag NOINTERCEPT {
876 $$.intercept = false;
877 }
878 | cmndtag SETENV {
879 $$.setenv = true;
880 }
881 | cmndtag NOSETENV {
882 $$.setenv = false;
883 }
884 | cmndtag LOG_INPUT {
885 $$.log_input = true;
886 }
887 | cmndtag NOLOG_INPUT {
888 $$.log_input = false;
889 }
890 | cmndtag LOG_OUTPUT {
891 $$.log_output = true;
892 }
893 | cmndtag NOLOG_OUTPUT {
894 $$.log_output = false;
895 }
896 | cmndtag FOLLOWLNK {
897 $$.follow = true;
898 }
899 | cmndtag NOFOLLOWLNK {
900 $$.follow = false;
901 }
902 | cmndtag MAIL {
903 $$.send_mail = true;
904 }
905 | cmndtag NOMAIL {
906 $$.send_mail = false;
907 }
908 ;
909
910 cmnd : ALL {
911 struct sudo_command *c;
912
913 if ((c = new_command(NULL, NULL)) == NULL) {
914 sudoerserror(N_("unable to allocate memory"));
915 YYERROR;
916 }
917 $$ = new_member((char *)c, ALL);
918 if ($$ == NULL) {
919 sudoerserror(N_("unable to allocate memory"));
920 YYERROR;
921 }
922 parser_leak_add(LEAK_MEMBER, $$);
923 }
924 | ALIAS {
925 $$ = new_member($1, ALIAS);
926 if ($$ == NULL) {
927 sudoerserror(N_("unable to allocate memory"));
928 YYERROR;
929 }
930 parser_leak_remove(LEAK_PTR, $1);
931 parser_leak_add(LEAK_MEMBER, $$);
932 }
933 | COMMAND {
934 struct sudo_command *c;
935
936 if ((c = new_command($1.cmnd, $1.args)) == NULL) {
937 sudoerserror(N_("unable to allocate memory"));
938 YYERROR;
939 }
940 $$ = new_member((char *)c, COMMAND);
941 if ($$ == NULL) {
942 free(c);
943 sudoerserror(N_("unable to allocate memory"));
944 YYERROR;
945 }
946 parser_leak_remove(LEAK_PTR, $1.cmnd);
947 parser_leak_remove(LEAK_PTR, $1.args);
948 parser_leak_add(LEAK_MEMBER, $$);
949 }
950 ;
951
952 hostaliases : hostalias
953 | hostaliases ':' hostalias
954 ;
955
956 hostalias : ALIAS {
957 alias_line = this_lineno;
958 alias_column = sudolinebuf.toke_start + 1;
959 } '=' hostlist {
960 if (!alias_add(&parsed_policy, $1, HOSTALIAS,
961 sudoers, alias_line, alias_column, $4)) {
962 alias_error($1, errno);
963 YYERROR;
964 }
965 parser_leak_remove(LEAK_PTR, $1);
966 parser_leak_remove(LEAK_MEMBER, $4);
967 }
968 | reserved_alias '=' hostlist
969 ;
970
971 hostlist : ophost
972 | hostlist ',' ophost {
973 parser_leak_remove(LEAK_MEMBER, $3);
974 HLTQ_CONCAT($1, $3, entries);
975 $$ = $1;
976 }
977 ;
978
979 cmndaliases : cmndalias
980 | cmndaliases ':' cmndalias
981 ;
982
983 cmndalias : ALIAS {
984 alias_line = this_lineno;
985 alias_column = sudolinebuf.toke_start + 1;
986 } '=' cmndlist {
987 if (!alias_add(&parsed_policy, $1, CMNDALIAS,
988 sudoers, alias_line, alias_column, $4)) {
989 alias_error($1, errno);
990 YYERROR;
991 }
992 parser_leak_remove(LEAK_PTR, $1);
993 parser_leak_remove(LEAK_MEMBER, $4);
994 }
995 | reserved_alias '=' cmndlist
996 ;
997
998 cmndlist : digcmnd
999 | cmndlist ',' digcmnd {
1000 parser_leak_remove(LEAK_MEMBER, $3);
1001 HLTQ_CONCAT($1, $3, entries);
1002 $$ = $1;
1003 }
1004 ;
1005
1006 runasaliases : runasalias
1007 | runasaliases ':' runasalias
1008 ;
1009
1010 runasalias : ALIAS {
1011 alias_line = this_lineno;
1012 alias_column = sudolinebuf.toke_start + 1;
1013 } '=' userlist {
1014 if (!alias_add(&parsed_policy, $1, RUNASALIAS,
1015 sudoers, alias_line, alias_column, $4)) {
1016 alias_error($1, errno);
1017 YYERROR;
1018 }
1019 parser_leak_remove(LEAK_PTR, $1);
1020 parser_leak_remove(LEAK_MEMBER, $4);
1021 }
1022 | reserved_alias '=' userlist
1023 ;
1024
1025 useraliases : useralias
1026 | useraliases ':' useralias
1027 ;
1028
1029 useralias : ALIAS {
1030 alias_line = this_lineno;
1031 alias_column = sudolinebuf.toke_start + 1;
1032 } '=' userlist {
1033 if (!alias_add(&parsed_policy, $1, USERALIAS,
1034 sudoers, alias_line, alias_column, $4)) {
1035 alias_error($1, errno);
1036 YYERROR;
1037 }
1038 parser_leak_remove(LEAK_PTR, $1);
1039 parser_leak_remove(LEAK_MEMBER, $4);
1040 }
1041 | reserved_alias '=' userlist
1042 ;
1043
1044 userlist : opuser
1045 | userlist ',' opuser {
1046 parser_leak_remove(LEAK_MEMBER, $3);
1047 HLTQ_CONCAT($1, $3, entries);
1048 $$ = $1;
1049 }
1050 ;
1051
1052 opuser : user {
1053 $$ = $1;
1054 $$->negated = false;
1055 }
1056 | '!' user {
1057 $$ = $2;
1058 $$->negated = true;
1059 }
1060 ;
1061
1062 user : ALIAS {
1063 $$ = new_member($1, ALIAS);
1064 if ($$ == NULL) {
1065 sudoerserror(N_("unable to allocate memory"));
1066 YYERROR;
1067 }
1068 parser_leak_remove(LEAK_PTR, $1);
1069 parser_leak_add(LEAK_MEMBER, $$);
1070 }
1071 | ALL {
1072 $$ = new_member(NULL, ALL);
1073 if ($$ == NULL) {
1074 sudoerserror(N_("unable to allocate memory"));
1075 YYERROR;
1076 }
1077 parser_leak_add(LEAK_MEMBER, $$);
1078 }
1079 | NETGROUP {
1080 $$ = new_member($1, NETGROUP);
1081 if ($$ == NULL) {
1082 sudoerserror(N_("unable to allocate memory"));
1083 YYERROR;
1084 }
1085 parser_leak_remove(LEAK_PTR, $1);
1086 parser_leak_add(LEAK_MEMBER, $$);
1087 }
1088 | USERGROUP {
1089 $$ = new_member($1, USERGROUP);
1090 if ($$ == NULL) {
1091 sudoerserror(N_("unable to allocate memory"));
1092 YYERROR;
1093 }
1094 parser_leak_remove(LEAK_PTR, $1);
1095 parser_leak_add(LEAK_MEMBER, $$);
1096 }
1097 | WORD {
1098 $$ = new_member($1, WORD);
1099 if ($$ == NULL) {
1100 sudoerserror(N_("unable to allocate memory"));
1101 YYERROR;
1102 }
1103 parser_leak_remove(LEAK_PTR, $1);
1104 parser_leak_add(LEAK_MEMBER, $$);
1105 }
1106 ;
1107
1108 grouplist : opgroup
1109 | grouplist ',' opgroup {
1110 parser_leak_remove(LEAK_MEMBER, $3);
1111 HLTQ_CONCAT($1, $3, entries);
1112 $$ = $1;
1113 }
1114 ;
1115
1116 opgroup : group {
1117 $$ = $1;
1118 $$->negated = false;
1119 }
1120 | '!' group {
1121 $$ = $2;
1122 $$->negated = true;
1123 }
1124 ;
1125
1126 group : ALIAS {
1127 $$ = new_member($1, ALIAS);
1128 if ($$ == NULL) {
1129 sudoerserror(N_("unable to allocate memory"));
1130 YYERROR;
1131 }
1132 parser_leak_remove(LEAK_PTR, $1);
1133 parser_leak_add(LEAK_MEMBER, $$);
1134 }
1135 | ALL {
1136 $$ = new_member(NULL, ALL);
1137 if ($$ == NULL) {
1138 sudoerserror(N_("unable to allocate memory"));
1139 YYERROR;
1140 }
1141 parser_leak_add(LEAK_MEMBER, $$);
1142 }
1143 | WORD {
1144 $$ = new_member($1, WORD);
1145 if ($$ == NULL) {
1146 sudoerserror(N_("unable to allocate memory"));
1147 YYERROR;
1148 }
1149 parser_leak_remove(LEAK_PTR, $1);
1150 parser_leak_add(LEAK_MEMBER, $$);
1151 }
1152 ;
1153 %%
1154 /* Like yyerror() but takes a printf-style format string. */
1155 void
1156 sudoerserrorf(const char *fmt, ...)
1157 {
1158 debug_decl(sudoerserrorf, SUDOERS_DEBUG_PARSER);
1159
1160 /* Save the line the first error occurred on. */
1161 if (errorlineno == -1) {
1162 errorlineno = this_lineno;
1163 sudo_rcstr_delref(errorfile);
1164 errorfile = sudo_rcstr_addref(sudoers);
1165 }
1166 if (sudoers_warnings && fmt != NULL) {
1167 LEXTRACE("<*> ");
1168 #ifndef TRACELEXER
1169 if (trace_print == NULL || trace_print == sudoers_trace_print) {
1170 char *s, *tofree = NULL;
1171 int oldlocale;
1172 va_list ap;
1173
1174 /* Warnings are displayed in the user's locale. */
1175 sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale);
1176
1177 va_start(ap, fmt);
1178 if (sudoerschar == ERROR) {
1179 /* Use error string from lexer. */
1180 s = _(sudoers_errstr);
1181 } else if (strcmp(fmt, "%s") == 0) {
1182 /* Optimize common case, a single string. */
1183 s = _(va_arg(ap, char *));
1184 } else {
1185 if (vasprintf(&s, fmt, ap) != -1)
1186 tofree = s;
1187 else
1188 s = _("syntax error");
1189 }
1190 sudo_printf(SUDO_CONV_ERROR_MSG, _("%s:%d:%d: %s\n"), sudoers,
1191 this_lineno, (int)sudolinebuf.toke_start + 1, s);
1192 free(tofree);
1193 va_end(ap);
1194 sudoers_setlocale(oldlocale, NULL);
1195
1196 /* Display the offending line and token if possible. */
1197 if (sudolinebuf.len != 0) {
1198 char tildes[128];
1199 size_t tlen = 0;
1200
1201 sudo_printf(SUDO_CONV_ERROR_MSG, "%s%s", sudolinebuf.buf,
1202 sudolinebuf.buf[sudolinebuf.len - 1] == '\n' ? "" : "\n");
1203 if (sudolinebuf.toke_end > sudolinebuf.toke_start) {
1204 tlen = sudolinebuf.toke_end - sudolinebuf.toke_start - 1;
1205 if (tlen >= sizeof(tildes))
1206 tlen = sizeof(tildes) - 1;
1207 memset(tildes, '~', tlen);
1208 }
1209 tildes[tlen] = '\0';
1210 sudo_printf(SUDO_CONV_ERROR_MSG, "%*s^%s\n",
1211 (int)sudolinebuf.toke_start, "", tildes);
1212 }
1213 }
1214 #endif
1215 }
1216 parse_error = true;
1217 debug_return;
1218 }
1219
1220 void
sudoerserror(const char * s)1221 sudoerserror(const char *s)
1222 {
1223 // -V:sudoerserror:575, 618
1224 if (s == NULL)
1225 sudoerserrorf(NULL);
1226 else
1227 sudoerserrorf("%s", s);
1228 }
1229
1230 static void
alias_error(const char * name,int errnum)1231 alias_error(const char *name, int errnum)
1232 {
1233 if (errnum == EEXIST)
1234 sudoerserrorf(U_("Alias \"%s\" already defined"), name);
1235 else
1236 sudoerserror(N_("unable to allocate memory"));
1237 }
1238
1239 static struct defaults *
new_default(char * var,char * val,short op)1240 new_default(char *var, char *val, short op)
1241 {
1242 struct defaults *d;
1243 debug_decl(new_default, SUDOERS_DEBUG_PARSER);
1244
1245 if ((d = calloc(1, sizeof(struct defaults))) == NULL) {
1246 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1247 "unable to allocate memory");
1248 debug_return_ptr(NULL);
1249 }
1250
1251 d->var = var;
1252 d->val = val;
1253 /* d->type = 0; */
1254 d->op = op;
1255 /* d->binding = NULL */
1256 d->line = this_lineno;
1257 d->column = sudolinebuf.toke_start + 1;
1258 d->file = sudo_rcstr_addref(sudoers);
1259 HLTQ_INIT(d, entries);
1260
1261 debug_return_ptr(d);
1262 }
1263
1264 static struct member *
new_member(char * name,int type)1265 new_member(char *name, int type)
1266 {
1267 struct member *m;
1268 debug_decl(new_member, SUDOERS_DEBUG_PARSER);
1269
1270 if ((m = calloc(1, sizeof(struct member))) == NULL) {
1271 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1272 "unable to allocate memory");
1273 debug_return_ptr(NULL);
1274 }
1275
1276 m->name = name;
1277 m->type = type;
1278 HLTQ_INIT(m, entries);
1279
1280 debug_return_ptr(m);
1281 }
1282
1283 static struct sudo_command *
new_command(char * cmnd,char * args)1284 new_command(char *cmnd, char *args)
1285 {
1286 struct sudo_command *c;
1287 debug_decl(new_command, SUDOERS_DEBUG_PARSER);
1288
1289 if ((c = calloc(1, sizeof(*c))) == NULL) {
1290 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1291 "unable to allocate memory");
1292 debug_return_ptr(NULL);
1293 }
1294 /* garbage collected as part of struct member */
1295
1296 c->cmnd = cmnd;
1297 c->args = args;
1298 TAILQ_INIT(&c->digests);
1299
1300 debug_return_ptr(c);
1301 }
1302
1303 static struct command_digest *
new_digest(int digest_type,char * digest_str)1304 new_digest(int digest_type, char *digest_str)
1305 {
1306 struct command_digest *digest;
1307 debug_decl(new_digest, SUDOERS_DEBUG_PARSER);
1308
1309 if ((digest = malloc(sizeof(*digest))) == NULL) {
1310 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1311 "unable to allocate memory");
1312 debug_return_ptr(NULL);
1313 }
1314
1315 HLTQ_INIT(digest, entries);
1316 digest->digest_type = digest_type;
1317 digest->digest_str = digest_str;
1318 if (digest->digest_str == NULL) {
1319 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1320 "unable to allocate memory");
1321 free(digest);
1322 digest = NULL;
1323 }
1324
1325 debug_return_ptr(digest);
1326 }
1327
1328 /*
1329 * Add a list of defaults structures to the defaults list.
1330 * The binding, if non-NULL, specifies a list of hosts, users, or
1331 * runas users the entries apply to (specified by the type).
1332 */
1333 static bool
add_defaults(int type,struct member * bmem,struct defaults * defs)1334 add_defaults(int type, struct member *bmem, struct defaults *defs)
1335 {
1336 struct defaults *d, *next;
1337 struct member_list *binding;
1338 bool ret = true;
1339 debug_decl(add_defaults, SUDOERS_DEBUG_PARSER);
1340
1341 if (defs != NULL) {
1342 /*
1343 * We use a single binding for each entry in defs.
1344 */
1345 if ((binding = malloc(sizeof(*binding))) == NULL) {
1346 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1347 "unable to allocate memory");
1348 sudoerserror(N_("unable to allocate memory"));
1349 debug_return_bool(false);
1350 }
1351 if (bmem != NULL) {
1352 parser_leak_remove(LEAK_MEMBER, bmem);
1353 HLTQ_TO_TAILQ(binding, bmem, entries);
1354 } else {
1355 TAILQ_INIT(binding);
1356 }
1357
1358 /*
1359 * Set type and binding (who it applies to) for new entries.
1360 * Then add to the global defaults list.
1361 */
1362 parser_leak_remove(LEAK_DEFAULTS, defs);
1363 HLTQ_FOREACH_SAFE(d, defs, entries, next) {
1364 d->type = type;
1365 d->binding = binding;
1366 TAILQ_INSERT_TAIL(&parsed_policy.defaults, d, entries);
1367 }
1368 }
1369
1370 debug_return_bool(ret);
1371 }
1372
1373 /*
1374 * Allocate a new struct userspec, populate it, and insert it at the
1375 * end of the userspecs list.
1376 */
1377 static bool
add_userspec(struct member * members,struct privilege * privs)1378 add_userspec(struct member *members, struct privilege *privs)
1379 {
1380 struct userspec *u;
1381 debug_decl(add_userspec, SUDOERS_DEBUG_PARSER);
1382
1383 if ((u = calloc(1, sizeof(*u))) == NULL) {
1384 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
1385 "unable to allocate memory");
1386 debug_return_bool(false);
1387 }
1388 u->line = this_lineno;
1389 u->column = sudolinebuf.toke_start + 1;
1390 u->file = sudo_rcstr_addref(sudoers);
1391 parser_leak_remove(LEAK_MEMBER, members);
1392 HLTQ_TO_TAILQ(&u->users, members, entries);
1393 parser_leak_remove(LEAK_PRIVILEGE, privs);
1394 HLTQ_TO_TAILQ(&u->privileges, privs, entries);
1395 STAILQ_INIT(&u->comments);
1396 TAILQ_INSERT_TAIL(&parsed_policy.userspecs, u, entries);
1397
1398 debug_return_bool(true);
1399 }
1400
1401 /*
1402 * Free a member struct and its contents.
1403 */
1404 void
free_member(struct member * m)1405 free_member(struct member *m)
1406 {
1407 debug_decl(free_member, SUDOERS_DEBUG_PARSER);
1408
1409 if (m->type == COMMAND || (m->type == ALL && m->name != NULL)) {
1410 struct command_digest *digest;
1411 struct sudo_command *c = (struct sudo_command *)m->name;
1412 free(c->cmnd);
1413 free(c->args);
1414 while ((digest = TAILQ_FIRST(&c->digests)) != NULL) {
1415 TAILQ_REMOVE(&c->digests, digest, entries);
1416 free(digest->digest_str);
1417 free(digest);
1418 }
1419 }
1420 free(m->name);
1421 free(m);
1422
1423 debug_return;
1424 }
1425
1426 /*
1427 * Free a tailq of members but not the struct member_list container itself.
1428 */
1429 void
free_members(struct member_list * members)1430 free_members(struct member_list *members)
1431 {
1432 struct member *m;
1433 debug_decl(free_members, SUDOERS_DEBUG_PARSER);
1434
1435 while ((m = TAILQ_FIRST(members)) != NULL) {
1436 TAILQ_REMOVE(members, m, entries);
1437 free_member(m);
1438 }
1439
1440 debug_return;
1441 }
1442
1443 void
free_defaults(struct defaults_list * defs)1444 free_defaults(struct defaults_list *defs)
1445 {
1446 struct member_list *prev_binding = NULL;
1447 struct defaults *def;
1448 debug_decl(free_defaults, SUDOERS_DEBUG_PARSER);
1449
1450 while ((def = TAILQ_FIRST(defs)) != NULL) {
1451 TAILQ_REMOVE(defs, def, entries);
1452 free_default(def, &prev_binding);
1453 }
1454
1455 debug_return;
1456 }
1457
1458 void
free_default(struct defaults * def,struct member_list ** binding)1459 free_default(struct defaults *def, struct member_list **binding)
1460 {
1461 debug_decl(free_default, SUDOERS_DEBUG_PARSER);
1462
1463 if (def->binding != *binding) {
1464 *binding = def->binding;
1465 if (def->binding != NULL) {
1466 free_members(def->binding);
1467 free(def->binding);
1468 }
1469 }
1470 sudo_rcstr_delref(def->file);
1471 free(def->var);
1472 free(def->val);
1473 free(def);
1474
1475 debug_return;
1476 }
1477
1478 void
free_cmndspecs(struct cmndspec_list * csl)1479 free_cmndspecs(struct cmndspec_list *csl)
1480 {
1481 struct member_list *runasuserlist = NULL, *runasgrouplist = NULL;
1482 char *runcwd = NULL, *runchroot = NULL;
1483 #ifdef HAVE_SELINUX
1484 char *role = NULL, *type = NULL;
1485 #endif /* HAVE_SELINUX */
1486 #ifdef HAVE_PRIV_SET
1487 char *privs = NULL, *limitprivs = NULL;
1488 #endif /* HAVE_PRIV_SET */
1489 struct cmndspec *cs;
1490 debug_decl(free_cmndspecs, SUDOERS_DEBUG_PARSER);
1491
1492 while ((cs = TAILQ_FIRST(csl)) != NULL) {
1493 TAILQ_REMOVE(csl, cs, entries);
1494
1495 /* Only free the first instance of runcwd/runchroot. */
1496 if (cs->runcwd != runcwd) {
1497 runcwd = cs->runcwd;
1498 free(cs->runcwd);
1499 }
1500 if (cs->runchroot != runchroot) {
1501 runchroot = cs->runchroot;
1502 free(cs->runchroot);
1503 }
1504 #ifdef HAVE_SELINUX
1505 /* Only free the first instance of a role/type. */
1506 if (cs->role != role) {
1507 role = cs->role;
1508 free(cs->role);
1509 }
1510 if (cs->type != type) {
1511 type = cs->type;
1512 free(cs->type);
1513 }
1514 #endif /* HAVE_SELINUX */
1515 #ifdef HAVE_PRIV_SET
1516 /* Only free the first instance of privs/limitprivs. */
1517 if (cs->privs != privs) {
1518 privs = cs->privs;
1519 free(cs->privs);
1520 }
1521 if (cs->limitprivs != limitprivs) {
1522 limitprivs = cs->limitprivs;
1523 free(cs->limitprivs);
1524 }
1525 #endif /* HAVE_PRIV_SET */
1526 /* Only free the first instance of runas user/group lists. */
1527 if (cs->runasuserlist && cs->runasuserlist != runasuserlist) {
1528 runasuserlist = cs->runasuserlist;
1529 free_members(runasuserlist);
1530 free(runasuserlist);
1531 }
1532 if (cs->runasgrouplist && cs->runasgrouplist != runasgrouplist) {
1533 runasgrouplist = cs->runasgrouplist;
1534 free_members(runasgrouplist);
1535 free(runasgrouplist);
1536 }
1537 free_member(cs->cmnd);
1538 free(cs);
1539 }
1540
1541 debug_return;
1542 }
1543
1544 void
free_privilege(struct privilege * priv)1545 free_privilege(struct privilege *priv)
1546 {
1547 struct member_list *prev_binding = NULL;
1548 struct defaults *def;
1549 debug_decl(free_privilege, SUDOERS_DEBUG_PARSER);
1550
1551 free(priv->ldap_role);
1552 free_members(&priv->hostlist);
1553 free_cmndspecs(&priv->cmndlist);
1554 while ((def = TAILQ_FIRST(&priv->defaults)) != NULL) {
1555 TAILQ_REMOVE(&priv->defaults, def, entries);
1556 free_default(def, &prev_binding);
1557 }
1558 free(priv);
1559
1560 debug_return;
1561 }
1562
1563 void
free_userspecs(struct userspec_list * usl)1564 free_userspecs(struct userspec_list *usl)
1565 {
1566 struct userspec *us;
1567 debug_decl(free_userspecs, SUDOERS_DEBUG_PARSER);
1568
1569 while ((us = TAILQ_FIRST(usl)) != NULL) {
1570 TAILQ_REMOVE(usl, us, entries);
1571 free_userspec(us);
1572 }
1573
1574 debug_return;
1575 }
1576
1577 void
free_userspec(struct userspec * us)1578 free_userspec(struct userspec *us)
1579 {
1580 struct privilege *priv;
1581 struct sudoers_comment *comment;
1582 debug_decl(free_userspec, SUDOERS_DEBUG_PARSER);
1583
1584 free_members(&us->users);
1585 while ((priv = TAILQ_FIRST(&us->privileges)) != NULL) {
1586 TAILQ_REMOVE(&us->privileges, priv, entries);
1587 free_privilege(priv);
1588 }
1589 while ((comment = STAILQ_FIRST(&us->comments)) != NULL) {
1590 STAILQ_REMOVE_HEAD(&us->comments, entries);
1591 free(comment->str);
1592 free(comment);
1593 }
1594 sudo_rcstr_delref(us->file);
1595 free(us);
1596
1597 debug_return;
1598 }
1599
1600 /*
1601 * Initialized a sudoers parse tree.
1602 */
1603 void
init_parse_tree(struct sudoers_parse_tree * parse_tree,const char * lhost,const char * shost)1604 init_parse_tree(struct sudoers_parse_tree *parse_tree, const char *lhost,
1605 const char *shost)
1606 {
1607 TAILQ_INIT(&parse_tree->userspecs);
1608 TAILQ_INIT(&parse_tree->defaults);
1609 parse_tree->aliases = NULL;
1610 parse_tree->shost = shost;
1611 parse_tree->lhost = lhost;
1612 }
1613
1614 /*
1615 * Move the contents of parsed_policy to new_tree.
1616 */
1617 void
reparent_parse_tree(struct sudoers_parse_tree * new_tree)1618 reparent_parse_tree(struct sudoers_parse_tree *new_tree)
1619 {
1620 TAILQ_CONCAT(&new_tree->userspecs, &parsed_policy.userspecs, entries);
1621 TAILQ_CONCAT(&new_tree->defaults, &parsed_policy.defaults, entries);
1622 new_tree->aliases = parsed_policy.aliases;
1623 parsed_policy.aliases = NULL;
1624 }
1625
1626 /*
1627 * Free the contents of a sudoers parse tree and initialize it.
1628 */
1629 void
free_parse_tree(struct sudoers_parse_tree * parse_tree)1630 free_parse_tree(struct sudoers_parse_tree *parse_tree)
1631 {
1632 free_userspecs(&parse_tree->userspecs);
1633 free_defaults(&parse_tree->defaults);
1634 free_aliases(parse_tree->aliases);
1635 parse_tree->aliases = NULL;
1636 }
1637
1638 /*
1639 * Free up space used by data structures from a previous parser run and sets
1640 * the current sudoers file to path.
1641 */
1642 bool
init_parser(const char * path,bool quiet,bool strict)1643 init_parser(const char *path, bool quiet, bool strict)
1644 {
1645 bool ret = true;
1646 debug_decl(init_parser, SUDOERS_DEBUG_PARSER);
1647
1648 free_parse_tree(&parsed_policy);
1649 parser_leak_init();
1650 init_lexer();
1651
1652 sudo_rcstr_delref(sudoers);
1653 if (path != NULL) {
1654 if ((sudoers = sudo_rcstr_dup(path)) == NULL) {
1655 sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1656 ret = false;
1657 }
1658 } else {
1659 sudoers = NULL;
1660 }
1661
1662 parse_error = false;
1663 errorlineno = -1;
1664 sudo_rcstr_delref(errorfile);
1665 errorfile = NULL;
1666 sudoers_warnings = !quiet;
1667 sudoers_strict = strict;
1668
1669 debug_return_bool(ret);
1670 }
1671
1672 /*
1673 * Initialize all options in a cmndspec.
1674 */
1675 static void
init_options(struct command_options * opts)1676 init_options(struct command_options *opts)
1677 {
1678 opts->notbefore = UNSPEC;
1679 opts->notafter = UNSPEC;
1680 opts->timeout = UNSPEC;
1681 opts->runchroot = NULL;
1682 opts->runcwd = NULL;
1683 #ifdef HAVE_SELINUX
1684 opts->role = NULL;
1685 opts->type = NULL;
1686 #endif
1687 #ifdef HAVE_PRIV_SET
1688 opts->privs = NULL;
1689 opts->limitprivs = NULL;
1690 #endif
1691 }
1692
1693 bool
parser_leak_add(enum parser_leak_types type,void * v)1694 parser_leak_add(enum parser_leak_types type, void *v)
1695 {
1696 #ifdef NO_LEAKS
1697 struct parser_leak_entry *entry;
1698 debug_decl(parser_leak_add, SUDOERS_DEBUG_PARSER);
1699
1700 if (v == NULL)
1701 debug_return_bool(false);
1702
1703 entry = calloc(1, sizeof(*entry));
1704 if (entry == NULL) {
1705 sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1706 debug_return_bool(false);
1707 }
1708 switch (type) {
1709 case LEAK_PRIVILEGE:
1710 entry->u.p = v;
1711 break;
1712 case LEAK_CMNDSPEC:
1713 entry->u.cs = v;
1714 break;
1715 case LEAK_DEFAULTS:
1716 entry->u.d = v;
1717 break;
1718 case LEAK_MEMBER:
1719 entry->u.m = v;
1720 break;
1721 case LEAK_DIGEST:
1722 entry->u.dig = v;
1723 break;
1724 case LEAK_RUNAS:
1725 entry->u.rc = v;
1726 break;
1727 case LEAK_PTR:
1728 entry->u.ptr = v;
1729 break;
1730 default:
1731 free(entry);
1732 sudo_warnx("unexpected leak type %d", type);
1733 debug_return_bool(false);
1734 }
1735 entry->type = type;
1736 SLIST_INSERT_HEAD(&parser_leak_list, entry, entries);
1737 debug_return_bool(true);
1738 #else
1739 return true;
1740 #endif /* NO_LEAKS */
1741 }
1742
1743 bool
parser_leak_remove(enum parser_leak_types type,void * v)1744 parser_leak_remove(enum parser_leak_types type, void *v)
1745 {
1746 #ifdef NO_LEAKS
1747 struct parser_leak_entry *entry, *prev = NULL;
1748 debug_decl(parser_leak_remove, SUDOERS_DEBUG_PARSER);
1749
1750 if (v == NULL)
1751 debug_return_bool(false);
1752
1753 SLIST_FOREACH(entry, &parser_leak_list, entries) {
1754 switch (entry->type) {
1755 case LEAK_PRIVILEGE:
1756 if (entry->u.p == v)
1757 goto found;
1758 break;
1759 case LEAK_CMNDSPEC:
1760 if (entry->u.cs == v)
1761 goto found;
1762 break;
1763 case LEAK_DEFAULTS:
1764 if (entry->u.d == v)
1765 goto found;
1766 break;
1767 case LEAK_MEMBER:
1768 if (entry->u.m == v)
1769 goto found;
1770 break;
1771 case LEAK_DIGEST:
1772 if (entry->u.dig == v)
1773 goto found;
1774 break;
1775 case LEAK_RUNAS:
1776 if (entry->u.rc == v)
1777 goto found;
1778 break;
1779 case LEAK_PTR:
1780 if (entry->u.ptr == v)
1781 goto found;
1782 break;
1783 default:
1784 sudo_warnx("unexpected leak type %d in %p", entry->type, entry);
1785 }
1786 prev = entry;
1787 }
1788 /* If this happens, there is a bug in the leak tracking code. */
1789 sudo_warnx("%s: unable to find %p, type %d", __func__, v, type);
1790 debug_return_bool(false);
1791 found:
1792 if (prev == NULL)
1793 SLIST_REMOVE_HEAD(&parser_leak_list, entries);
1794 else
1795 SLIST_REMOVE_AFTER(prev, entries);
1796 free(entry);
1797 debug_return_bool(true);
1798 #else
1799 return true;
1800 #endif /* NO_LEAKS */
1801 }
1802
1803 void
parser_leak_free(void)1804 parser_leak_free(void)
1805 {
1806 #ifdef NO_LEAKS
1807 struct parser_leak_entry *entry;
1808 void *next;
1809 debug_decl(parser_leak_run, SUDOERS_DEBUG_PARSER);
1810
1811 /* Free the leaks. */
1812 while ((entry = SLIST_FIRST(&parser_leak_list))) {
1813 SLIST_REMOVE_HEAD(&parser_leak_list, entries);
1814 switch (entry->type) {
1815 case LEAK_PRIVILEGE:
1816 {
1817 struct privilege *priv;
1818
1819 HLTQ_FOREACH_SAFE(priv, entry->u.p, entries, next)
1820 free_privilege(priv);
1821 free(entry);
1822 }
1823 break;
1824 case LEAK_CMNDSPEC:
1825 {
1826 struct cmndspec_list specs;
1827
1828 HLTQ_TO_TAILQ(&specs, entry->u.cs, entries);
1829 free_cmndspecs(&specs);
1830 free(entry);
1831 }
1832 break;
1833 case LEAK_DEFAULTS:
1834 {
1835 struct defaults_list defs;
1836
1837 HLTQ_TO_TAILQ(&defs, entry->u.d, entries);
1838 free_defaults(&defs);
1839 free(entry);
1840 }
1841 break;
1842 case LEAK_MEMBER:
1843 {
1844 struct member *m;
1845
1846 HLTQ_FOREACH_SAFE(m, entry->u.m, entries, next)
1847 free_member(m);
1848 free(entry);
1849 }
1850 break;
1851 case LEAK_DIGEST:
1852 {
1853 struct command_digest *dig;
1854
1855 HLTQ_FOREACH_SAFE(dig, entry->u.dig, entries, next) {
1856 free(dig->digest_str);
1857 free(dig);
1858 }
1859 free(entry);
1860 }
1861 break;
1862 case LEAK_RUNAS:
1863 {
1864 struct member *m;
1865
1866 if (entry->u.rc->runasusers != NULL) {
1867 HLTQ_FOREACH_SAFE(m, entry->u.rc->runasusers, entries, next)
1868 free_member(m);
1869 }
1870 if (entry->u.rc->runasgroups != NULL) {
1871 HLTQ_FOREACH_SAFE(m, entry->u.rc->runasgroups, entries, next)
1872 free_member(m);
1873 }
1874 free(entry->u.rc);
1875 free(entry);
1876 break;
1877 }
1878 case LEAK_PTR:
1879 free(entry->u.ptr);
1880 free(entry);
1881 break;
1882 default:
1883 sudo_warnx("unexpected garbage type %d", entry->type);
1884 }
1885 }
1886
1887 debug_return;
1888 #endif /* NO_LEAKS */
1889 }
1890
1891 void
parser_leak_init(void)1892 parser_leak_init(void)
1893 {
1894 #ifdef NO_LEAKS
1895 static bool initialized;
1896 debug_decl(parser_leak_init, SUDOERS_DEBUG_PARSER);
1897
1898 if (!initialized) {
1899 atexit(parser_leak_free);
1900 initialized = true;
1901 debug_return;
1902 }
1903
1904 /* Already initialized, free existing leaks. */
1905 parser_leak_free();
1906 debug_return;
1907 #endif /* NO_LEAKS */
1908 }
1909