Annotation of embedaddon/sudo/plugins/sudoers/toke.l, revision 1.1.1.1
1.1 misho 1: %{
2: /*
3: * Copyright (c) 1996, 1998-2005, 2007-2011
4: * Todd C. Miller <Todd.Miller@courtesan.com>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
18: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
19: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20: *
21: * Sponsored in part by the Defense Advanced Research Projects
22: * Agency (DARPA) and Air Force Research Laboratory, Air Force
23: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
24: */
25:
26: #include <config.h>
27:
28: #include <sys/types.h>
29: #include <sys/param.h>
30: #include <sys/stat.h>
31: #include <stdio.h>
32: #ifdef STDC_HEADERS
33: # include <stdlib.h>
34: # include <stddef.h>
35: #else
36: # ifdef HAVE_STDLIB_H
37: # include <stdlib.h>
38: # endif
39: #endif /* STDC_HEADERS */
40: #ifdef HAVE_STRING_H
41: # include <string.h>
42: #endif /* HAVE_STRING_H */
43: #ifdef HAVE_STRINGS_H
44: # include <strings.h>
45: #endif /* HAVE_STRINGS_H */
46: #ifdef HAVE_UNISTD_H
47: # include <unistd.h>
48: #endif /* HAVE_UNISTD_H */
49: #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
50: # include <malloc.h>
51: #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
52: #ifdef HAVE_DIRENT_H
53: # include <dirent.h>
54: # define NAMLEN(dirent) strlen((dirent)->d_name)
55: #else
56: # define dirent direct
57: # define NAMLEN(dirent) (dirent)->d_namlen
58: # ifdef HAVE_SYS_NDIR_H
59: # include <sys/ndir.h>
60: # endif
61: # ifdef HAVE_SYS_DIR_H
62: # include <sys/dir.h>
63: # endif
64: # ifdef HAVE_NDIR_H
65: # include <ndir.h>
66: # endif
67: #endif
68: #include <errno.h>
69: #include <ctype.h>
70: #include "sudoers.h"
71: #include "parse.h"
72: #include "toke.h"
73: #include <gram.h>
74:
75: extern YYSTYPE yylval;
76: extern int parse_error;
77: int sudolineno;
78: char *sudoers;
79:
80: static int continued, prev_state, sawspace;
81:
82: static int _push_include(char *, int);
83: static int pop_include(void);
84: static char *parse_include(char *);
85:
86: #ifdef TRACELEXER
87: static int sudoers_trace_print(const char *msg);
88: #else
89: # define sudoers_trace_print NULL
90: #endif
91: int (*trace_print)(const char *msg) = sudoers_trace_print;
92:
93: #define push_include(_p) (_push_include((_p), FALSE))
94: #define push_includedir(_p) (_push_include((_p), TRUE))
95: %}
96:
97: HEX16 [0-9A-Fa-f]{1,4}
98: OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
99: IPV4ADDR {OCTET}(\.{OCTET}){3}
100: IPV6ADDR ({HEX16}?:){2,7}{HEX16}?|({HEX16}?:){2,6}:{IPV4ADDR}
101:
102: HOSTNAME [[:alnum:]_-]+
103: WORD ([^#>!=:,\(\) \t\n\\\"]|\\[^\n])+
104: ID #-?[0-9]+
105: PATH \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+
106: ENVAR ([^#!=, \t\n\\\"]|\\[^\n])([^#=, \t\n\\\"]|\\[^\n])*
107: DEFVAR [a-z_]+
108:
109: %option noinput
110: %option nounput
111: %option noyywrap
112:
113: %s GOTDEFS
114: %x GOTCMND
115: %x STARTDEFS
116: %x INDEFS
117: %x INSTR
118:
119: %%
120: <GOTDEFS>[[:blank:]]*,[[:blank:]]* {
121: LEXTRACE(", ");
122: return ',';
123: } /* return ',' */
124:
125: <GOTDEFS>[[:blank:]]+ BEGIN STARTDEFS;
126:
127: <STARTDEFS>{DEFVAR} {
128: BEGIN INDEFS;
129: LEXTRACE("DEFVAR ");
130: if (!fill(yytext, yyleng))
131: yyterminate();
132: return DEFVAR;
133: }
134:
135: <INDEFS>{
136: , {
137: BEGIN STARTDEFS;
138: LEXTRACE(", ");
139: return ',';
140: } /* return ',' */
141:
142: = {
143: LEXTRACE("= ");
144: return '=';
145: } /* return '=' */
146:
147: \+= {
148: LEXTRACE("+= ");
149: return '+';
150: } /* return '+' */
151:
152: -= {
153: LEXTRACE("-= ");
154: return '-';
155: } /* return '-' */
156:
157: \" {
158: LEXTRACE("BEGINSTR ");
159: yylval.string = NULL;
160: prev_state = YY_START;
161: BEGIN INSTR;
162: }
163:
164: {ENVAR} {
165: LEXTRACE("WORD(2) ");
166: if (!fill(yytext, yyleng))
167: yyterminate();
168: return WORD;
169: }
170: }
171:
172: <INSTR>{
173: \\[[:blank:]]*\n[[:blank:]]* {
174: /* Line continuation char followed by newline. */
175: ++sudolineno;
176: continued = TRUE;
177: }
178:
179: \" {
180: LEXTRACE("ENDSTR ");
181: BEGIN prev_state;
182:
183: if (yylval.string == NULL) {
184: LEXTRACE("ERROR "); /* empty string */
185: return ERROR;
186: }
187: if (prev_state == INITIAL) {
188: switch (yylval.string[0]) {
189: case '%':
190: if (yylval.string[1] == '\0' ||
191: (yylval.string[1] == ':' &&
192: yylval.string[2] == '\0')) {
193: LEXTRACE("ERROR "); /* empty group */
194: return ERROR;
195: }
196: LEXTRACE("USERGROUP ");
197: return USERGROUP;
198: case '+':
199: if (yylval.string[1] == '\0') {
200: LEXTRACE("ERROR "); /* empty netgroup */
201: return ERROR;
202: }
203: LEXTRACE("NETGROUP ");
204: return NETGROUP;
205: }
206: }
207: LEXTRACE("WORD(4) ");
208: return WORD;
209: }
210:
211: \\ {
212: LEXTRACE("BACKSLASH ");
213: if (!append(yytext, yyleng))
214: yyterminate();
215: }
216:
217: ([^\"\n\\]|\\\")+ {
218: LEXTRACE("STRBODY ");
219: if (!append(yytext, yyleng))
220: yyterminate();
221: }
222: }
223:
224: <GOTCMND>{
225: \\[\*\?\[\]\!] {
226: /* quoted fnmatch glob char, pass verbatim */
227: LEXTRACE("QUOTEDCHAR ");
228: if (!fill_args(yytext, 2, sawspace))
229: yyterminate();
230: sawspace = FALSE;
231: }
232:
233: \\[:\\,= \t#] {
234: /* quoted sudoers special char, strip backslash */
235: LEXTRACE("QUOTEDCHAR ");
236: if (!fill_args(yytext + 1, 1, sawspace))
237: yyterminate();
238: sawspace = FALSE;
239: }
240:
241: [#:\,=\n] {
242: BEGIN INITIAL;
243: yyless(0);
244: return COMMAND;
245: } /* end of command line args */
246:
247: [^#\\:, \t\n]+ {
248: LEXTRACE("ARG ");
249: if (!fill_args(yytext, yyleng, sawspace))
250: yyterminate();
251: sawspace = FALSE;
252: } /* a command line arg */
253: }
254:
255: <INITIAL>^#include[[:blank:]]+\/.*\n {
256: char *path;
257:
258: if (continued) {
259: LEXTRACE("ERROR ");
260: return ERROR;
261: }
262:
263: if ((path = parse_include(yytext)) == NULL)
264: yyterminate();
265:
266: LEXTRACE("INCLUDE\n");
267:
268: /* Push current buffer and switch to include file */
269: if (!push_include(path))
270: yyterminate();
271: }
272:
273: <INITIAL>^#includedir[[:blank:]]+\/.*\n {
274: char *path;
275:
276: if (continued) {
277: LEXTRACE("ERROR ");
278: return ERROR;
279: }
280:
281: if ((path = parse_include(yytext)) == NULL)
282: yyterminate();
283:
284: LEXTRACE("INCLUDEDIR\n");
285:
286: /*
287: * Push current buffer and switch to include file.
288: * We simply ignore empty directories.
289: */
290: if (!push_includedir(path) && parse_error)
291: yyterminate();
292: }
293:
294: <INITIAL>^[[:blank:]]*Defaults([:@>\!][[:blank:]]*\!*\"?({ID}|{WORD}))? {
295: char deftype;
296: int n;
297:
298: if (continued) {
299: LEXTRACE("ERROR ");
300: return ERROR;
301: }
302:
303: for (n = 0; isblank((unsigned char)yytext[n]); n++)
304: continue;
305: n += sizeof("Defaults") - 1;
306: if ((deftype = yytext[n++]) != '\0') {
307: while (isblank((unsigned char)yytext[n]))
308: n++;
309: }
310: BEGIN GOTDEFS;
311: switch (deftype) {
312: case ':':
313: yyless(n);
314: LEXTRACE("DEFAULTS_USER ");
315: return DEFAULTS_USER;
316: case '>':
317: yyless(n);
318: LEXTRACE("DEFAULTS_RUNAS ");
319: return DEFAULTS_RUNAS;
320: case '@':
321: yyless(n);
322: LEXTRACE("DEFAULTS_HOST ");
323: return DEFAULTS_HOST;
324: case '!':
325: yyless(n);
326: LEXTRACE("DEFAULTS_CMND ");
327: return DEFAULTS_CMND;
328: default:
329: LEXTRACE("DEFAULTS ");
330: return DEFAULTS;
331: }
332: }
333:
334: <INITIAL>^[[:blank:]]*(Host|Cmnd|User|Runas)_Alias {
335: int n;
336:
337: if (continued) {
338: LEXTRACE("ERROR ");
339: return ERROR;
340: }
341:
342: for (n = 0; isblank((unsigned char)yytext[n]); n++)
343: continue;
344: switch (yytext[n]) {
345: case 'H':
346: LEXTRACE("HOSTALIAS ");
347: return HOSTALIAS;
348: case 'C':
349: LEXTRACE("CMNDALIAS ");
350: return CMNDALIAS;
351: case 'U':
352: LEXTRACE("USERALIAS ");
353: return USERALIAS;
354: case 'R':
355: LEXTRACE("RUNASALIAS ");
356: return RUNASALIAS;
357: }
358: }
359:
360: NOPASSWD[[:blank:]]*: {
361: /* cmnd does not require passwd for this user */
362: LEXTRACE("NOPASSWD ");
363: return NOPASSWD;
364: }
365:
366: PASSWD[[:blank:]]*: {
367: /* cmnd requires passwd for this user */
368: LEXTRACE("PASSWD ");
369: return PASSWD;
370: }
371:
372: NOEXEC[[:blank:]]*: {
373: LEXTRACE("NOEXEC ");
374: return NOEXEC;
375: }
376:
377: EXEC[[:blank:]]*: {
378: LEXTRACE("EXEC ");
379: return EXEC;
380: }
381:
382: SETENV[[:blank:]]*: {
383: LEXTRACE("SETENV ");
384: return SETENV;
385: }
386:
387: NOSETENV[[:blank:]]*: {
388: LEXTRACE("NOSETENV ");
389: return NOSETENV;
390: }
391:
392: LOG_OUTPUT[[:blank:]]*: {
393: LEXTRACE("LOG_OUTPUT ");
394: return LOG_OUTPUT;
395: }
396:
397: NOLOG_OUTPUT[[:blank:]]*: {
398: LEXTRACE("NOLOG_OUTPUT ");
399: return NOLOG_OUTPUT;
400: }
401:
402: LOG_INPUT[[:blank:]]*: {
403: LEXTRACE("LOG_INPUT ");
404: return LOG_INPUT;
405: }
406:
407: NOLOG_INPUT[[:blank:]]*: {
408: LEXTRACE("NOLOG_INPUT ");
409: return NOLOG_INPUT;
410: }
411:
412: <INITIAL,GOTDEFS>(\+|\%|\%:) {
413: /* empty group or netgroup */
414: LEXTRACE("ERROR ");
415: return ERROR;
416: }
417:
418: \+{WORD} {
419: /* netgroup */
420: if (!fill(yytext, yyleng))
421: yyterminate();
422: LEXTRACE("NETGROUP ");
423: return NETGROUP;
424: }
425:
426: \%:?({WORD}|{ID}) {
427: /* group */
428: if (!fill(yytext, yyleng))
429: yyterminate();
430: LEXTRACE("USERGROUP ");
431: return USERGROUP;
432: }
433:
434: {IPV4ADDR}(\/{IPV4ADDR})? {
435: if (!fill(yytext, yyleng))
436: yyterminate();
437: LEXTRACE("NTWKADDR ");
438: return NTWKADDR;
439: }
440:
441: {IPV4ADDR}\/([12]?[0-9]|3[0-2]) {
442: if (!fill(yytext, yyleng))
443: yyterminate();
444: LEXTRACE("NTWKADDR ");
445: return NTWKADDR;
446: }
447:
448: {IPV6ADDR}(\/{IPV6ADDR})? {
449: if (!ipv6_valid(yytext)) {
450: LEXTRACE("ERROR ");
451: return ERROR;
452: }
453: if (!fill(yytext, yyleng))
454: yyterminate();
455: LEXTRACE("NTWKADDR ");
456: return NTWKADDR;
457: }
458:
459: {IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
460: if (!ipv6_valid(yytext)) {
461: LEXTRACE("ERROR ");
462: return ERROR;
463: }
464: if (!fill(yytext, yyleng))
465: yyterminate();
466: LEXTRACE("NTWKADDR ");
467: return NTWKADDR;
468: }
469:
470: ALL {
471: LEXTRACE("ALL ");
472: return ALL;
473:
474: }
475:
476: <INITIAL>ROLE {
477: #ifdef HAVE_SELINUX
478: LEXTRACE("ROLE ");
479: return ROLE;
480: #else
481: goto got_alias;
482: #endif
483: }
484:
485: <INITIAL>TYPE {
486: #ifdef HAVE_SELINUX
487: LEXTRACE("TYPE ");
488: return TYPE;
489: #else
490: goto got_alias;
491: #endif
492: }
493:
494: [[:upper:]][[:upper:][:digit:]_]* {
495: #ifndef HAVE_SELINUX
496: got_alias:
497: #endif
498: if (!fill(yytext, yyleng))
499: yyterminate();
500: LEXTRACE("ALIAS ");
501: return ALIAS;
502: }
503:
504: <GOTDEFS>({PATH}|sudoedit) {
505: /* no command args allowed for Defaults!/path */
506: if (!fill_cmnd(yytext, yyleng))
507: yyterminate();
508: LEXTRACE("COMMAND ");
509: return COMMAND;
510: }
511:
512: sudoedit {
513: BEGIN GOTCMND;
514: LEXTRACE("COMMAND ");
515: if (!fill_cmnd(yytext, yyleng))
516: yyterminate();
517: } /* sudo -e */
518:
519: {PATH} {
520: /* directories can't have args... */
521: if (yytext[yyleng - 1] == '/') {
522: LEXTRACE("COMMAND ");
523: if (!fill_cmnd(yytext, yyleng))
524: yyterminate();
525: return COMMAND;
526: } else {
527: BEGIN GOTCMND;
528: LEXTRACE("COMMAND ");
529: if (!fill_cmnd(yytext, yyleng))
530: yyterminate();
531: }
532: } /* a pathname */
533:
534: <INITIAL,GOTDEFS>\" {
535: LEXTRACE("BEGINSTR ");
536: yylval.string = NULL;
537: prev_state = YY_START;
538: BEGIN INSTR;
539: }
540:
541: <INITIAL,GOTDEFS>({ID}|{WORD}) {
542: /* a word */
543: if (!fill(yytext, yyleng))
544: yyterminate();
545: LEXTRACE("WORD(5) ");
546: return WORD;
547: }
548:
549: \( {
550: LEXTRACE("( ");
551: return '(';
552: }
553:
554: \) {
555: LEXTRACE(") ");
556: return ')';
557: }
558:
559: , {
560: LEXTRACE(", ");
561: return ',';
562: } /* return ',' */
563:
564: = {
565: LEXTRACE("= ");
566: return '=';
567: } /* return '=' */
568:
569: : {
570: LEXTRACE(": ");
571: return ':';
572: } /* return ':' */
573:
574: <*>!+ {
575: if (yyleng & 1) {
576: LEXTRACE("!");
577: return '!'; /* return '!' */
578: }
579: }
580:
581: <*>\n {
582: if (YY_START == INSTR) {
583: LEXTRACE("ERROR ");
584: return ERROR; /* line break in string */
585: }
586: BEGIN INITIAL;
587: ++sudolineno;
588: continued = FALSE;
589: LEXTRACE("\n");
590: return COMMENT;
591: } /* return newline */
592:
593: <*>[[:blank:]]+ { /* throw away space/tabs */
594: sawspace = TRUE; /* but remember for fill_args */
595: }
596:
597: <*>\\[[:blank:]]*\n {
598: sawspace = TRUE; /* remember for fill_args */
599: ++sudolineno;
600: continued = TRUE;
601: } /* throw away EOL after \ */
602:
603: <INITIAL,STARTDEFS,INDEFS>#(-[^\n0-9].*|[^\n0-9-].*)?\n {
604: BEGIN INITIAL;
605: ++sudolineno;
606: continued = FALSE;
607: LEXTRACE("#\n");
608: return COMMENT;
609: } /* comment, not uid/gid */
610:
611: <*>. {
612: LEXTRACE("ERROR ");
613: return ERROR;
614: } /* parse error */
615:
616: <*><<EOF>> {
617: if (YY_START != INITIAL) {
618: BEGIN INITIAL;
619: LEXTRACE("ERROR ");
620: return ERROR;
621: }
622: if (!pop_include())
623: yyterminate();
624: }
625:
626: %%
627: struct path_list {
628: char *path;
629: struct path_list *next;
630: };
631:
632: struct include_stack {
633: YY_BUFFER_STATE bs;
634: char *path;
635: struct path_list *more; /* more files in case of includedir */
636: int lineno;
637: int keepopen;
638: };
639:
640: static int
641: pl_compare(const void *v1, const void *v2)
642: {
643: const struct path_list * const *p1 = v1;
644: const struct path_list * const *p2 = v2;
645:
646: return strcmp((*p1)->path, (*p2)->path);
647: }
648:
649: static char *
650: switch_dir(struct include_stack *stack, char *dirpath)
651: {
652: DIR *dir;
653: int i, count = 0;
654: char *path = NULL;
655: struct dirent *dent;
656: struct stat sb;
657: struct path_list *pl, *first = NULL;
658: struct path_list **sorted = NULL;
659:
660: if (!(dir = opendir(dirpath))) {
661: if (errno != ENOENT) {
662: char *errbuf;
663: if (asprintf(&errbuf, _("%s: %s"), dirpath, strerror(errno)) != -1) {
664: yyerror(errbuf);
665: free(errbuf);
666: } else {
667: yyerror(_("unable to allocate memory"));
668: }
669: }
670: goto done;
671: }
672: while ((dent = readdir(dir))) {
673: /* Ignore files that end in '~' or have a '.' in them. */
674: if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~'
675: || strchr(dent->d_name, '.') != NULL) {
676: continue;
677: }
678: if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) {
679: closedir(dir);
680: goto bad;
681: }
682: if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) {
683: efree(path);
684: path = NULL;
685: continue;
686: }
687: pl = malloc(sizeof(*pl));
688: if (pl == NULL)
689: goto bad;
690: pl->path = path;
691: pl->next = first;
692: first = pl;
693: count++;
694: }
695: closedir(dir);
696:
697: if (count == 0)
698: goto done;
699:
700: /* Sort the list as an array. */
701: sorted = malloc(sizeof(*sorted) * count);
702: if (sorted == NULL)
703: goto bad;
704: pl = first;
705: for (i = 0; i < count; i++) {
706: sorted[i] = pl;
707: pl = pl->next;
708: }
709: qsort(sorted, count, sizeof(*sorted), pl_compare);
710:
711: /* Apply sorting to the list. */
712: first = sorted[0];
713: sorted[count - 1]->next = NULL;
714: for (i = 1; i < count; i++)
715: sorted[i - 1]->next = sorted[i];
716: efree(sorted);
717:
718: /* Pull out the first element for parsing, leave the rest for later. */
719: if (count) {
720: path = first->path;
721: pl = first->next;
722: efree(first);
723: stack->more = pl;
724: } else {
725: path = NULL;
726: }
727: done:
728: efree(dirpath);
729: return path;
730: bad:
731: while (first != NULL) {
732: pl = first;
733: first = pl->next;
734: free(pl->path);
735: free(pl);
736: }
737: efree(sorted);
738: efree(dirpath);
739: efree(path);
740: return NULL;
741: }
742:
743: #define MAX_SUDOERS_DEPTH 128
744: #define SUDOERS_STACK_INCREMENT 16
745:
746: static size_t istacksize, idepth;
747: static struct include_stack *istack;
748: static int keepopen;
749:
750: void
751: init_lexer(void)
752: {
753: struct path_list *pl;
754:
755: while (idepth) {
756: idepth--;
757: while ((pl = istack[idepth].more) != NULL) {
758: istack[idepth].more = pl->next;
759: efree(pl->path);
760: efree(pl);
761: }
762: efree(istack[idepth].path);
763: if (idepth && !istack[idepth].keepopen)
764: fclose(istack[idepth].bs->yy_input_file);
765: yy_delete_buffer(istack[idepth].bs);
766: }
767: efree(istack);
768: istack = NULL;
769: istacksize = idepth = 0;
770: sudolineno = 1;
771: keepopen = FALSE;
772: sawspace = FALSE;
773: continued = FALSE;
774: prev_state = INITIAL;
775: }
776:
777: static int
778: _push_include(char *path, int isdir)
779: {
780: struct path_list *pl;
781: FILE *fp;
782:
783: /* push current state onto stack */
784: if (idepth >= istacksize) {
785: if (idepth > MAX_SUDOERS_DEPTH) {
786: yyerror(_("too many levels of includes"));
787: return FALSE;
788: }
789: istacksize += SUDOERS_STACK_INCREMENT;
790: istack = (struct include_stack *) realloc(istack,
791: sizeof(*istack) * istacksize);
792: if (istack == NULL) {
793: yyerror(_("unable to allocate memory"));
794: return FALSE;
795: }
796: }
797: if (isdir) {
798: if (!(path = switch_dir(&istack[idepth], path))) {
799: /* switch_dir() called yyerror() for us */
800: return FALSE;
801: }
802: while ((fp = open_sudoers(path, FALSE, &keepopen)) == NULL) {
803: /* Unable to open path in includedir, go to next one, if any. */
804: efree(path);
805: if ((pl = istack[idepth].more) == NULL)
806: return FALSE;
807: path = pl->path;
808: istack[idepth].more = pl->next;
809: efree(pl);
810: }
811: } else {
812: if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) {
813: char *errbuf;
814: if (asprintf(&errbuf, _("%s: %s"), path, strerror(errno)) != -1) {
815: yyerror(errbuf);
816: free(errbuf);
817: } else {
818: yyerror(_("unable to allocate memory"));
819: }
820: return FALSE;
821: }
822: istack[idepth].more = NULL;
823: }
824: /* Push the old (current) file and open the new one. */
825: istack[idepth].path = sudoers; /* push old path */
826: istack[idepth].bs = YY_CURRENT_BUFFER;
827: istack[idepth].lineno = sudolineno;
828: istack[idepth].keepopen = keepopen;
829: idepth++;
830: sudolineno = 1;
831: sudoers = path;
832: yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
833:
834: return TRUE;
835: }
836:
837: static int
838: pop_include(void)
839: {
840: struct path_list *pl;
841: FILE *fp;
842:
843: if (idepth == 0)
844: return FALSE;
845:
846: if (!keepopen)
847: fclose(YY_CURRENT_BUFFER->yy_input_file);
848: yy_delete_buffer(YY_CURRENT_BUFFER);
849: /* If we are in an include dir, move to the next file. */
850: while ((pl = istack[idepth - 1].more) != NULL) {
851: fp = open_sudoers(pl->path, FALSE, &keepopen);
852: if (fp != NULL) {
853: istack[idepth - 1].more = pl->next;
854: efree(sudoers);
855: sudoers = pl->path;
856: sudolineno = 1;
857: yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
858: efree(pl);
859: break;
860: }
861: /* Unable to open path in include dir, go to next one. */
862: istack[idepth - 1].more = pl->next;
863: efree(pl->path);
864: efree(pl);
865: }
866: /* If no path list, just pop the last dir on the stack. */
867: if (pl == NULL) {
868: idepth--;
869: yy_switch_to_buffer(istack[idepth].bs);
870: efree(sudoers);
871: sudoers = istack[idepth].path;
872: sudolineno = istack[idepth].lineno;
873: keepopen = istack[idepth].keepopen;
874: }
875: return TRUE;
876: }
877:
878: static char *
879: parse_include(char *base)
880: {
881: char *cp, *ep, *path;
882: int len = 0, subst = 0;
883: size_t shost_len = 0;
884:
885: /* Pull out path from #include line. */
886: cp = base + sizeof("#include");
887: if (*cp == 'i')
888: cp += 3; /* includedir */
889: while (isblank((unsigned char) *cp))
890: cp++;
891: ep = cp;
892: while (*ep != '\0' && !isspace((unsigned char) *ep)) {
893: if (ep[0] == '%' && ep[1] == 'h') {
894: shost_len = strlen(user_shost);
895: len += shost_len - 2;
896: subst = 1;
897: }
898: ep++;
899: }
900:
901: /* Make a copy of path and return it. */
902: len += (int)(ep - cp);
903: if ((path = malloc(len + 1)) == NULL) {
904: yyerror(_("unable to allocate memory"));
905: return NULL;
906: }
907: if (subst) {
908: /* substitute for %h */
909: char *pp = path;
910: while (cp < ep) {
911: if (cp[0] == '%' && cp[1] == 'h') {
912: memcpy(pp, user_shost, shost_len);
913: pp += shost_len;
914: cp += 2;
915: continue;
916: }
917: *pp++ = *cp++;
918: }
919: *pp = '\0';
920: } else {
921: memcpy(path, cp, len);
922: path[len] = '\0';
923: }
924:
925: /* Push any excess characters (e.g. comment, newline) back to the lexer */
926: if (*ep != '\0')
927: yyless((int)(ep - base));
928:
929: return path;
930: }
931:
932: #ifdef TRACELEXER
933: static int
934: sudoers_trace_print(const char *msg)
935: {
936: return fputs(msg, stderr);
937: }
938: #endif /* TRACELEXER */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>