Annotation of embedaddon/sudo/plugins/sudoers/toke.l, revision 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>