Return to toke.l CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / plugins / sudoers |
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 */