Annotation of src/usr.bin/sudo/parse.lex, Revision 1.1
1.1 ! millert 1: %{
! 2: /*
! 3: * Copyright (c) 1996, 1998, 1999 Todd C. Miller <Todd.Miller@courtesan.com>
! 4: * All rights reserved.
! 5: *
! 6: * This code is derived from software contributed by Chris Jepeway
! 7: * <jepeway@cs.utk.edu>
! 8: *
! 9: * This code is derived from software contributed by Chris Jepeway
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: *
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: *
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: *
! 21: * 3. The name of the author may not be used to endorse or promote products
! 22: * derived from this software without specific prior written permission.
! 23: *
! 24: * 4. Products derived from this software may not be called "Sudo" nor
! 25: * may "Sudo" appear in their names without specific prior written
! 26: * permission from the author.
! 27: *
! 28: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
! 29: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
! 30: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
! 31: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 32: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 33: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! 34: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 35: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! 36: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! 37: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include "config.h"
! 41:
! 42: #ifdef STDC_HEADERS
! 43: #include <stdlib.h>
! 44: #endif /* STDC_HEADERS */
! 45: #ifdef HAVE_UNISTD_H
! 46: #include <unistd.h>
! 47: #endif /* HAVE_UNISTD_H */
! 48: #ifdef HAVE_STRING_H
! 49: #include <string.h>
! 50: #endif /* HAVE_STRING_H */
! 51: #ifdef HAVE_STRINGS_H
! 52: #include <strings.h>
! 53: #endif /* HAVE_STRINGS_H */
! 54: #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
! 55: #include <malloc.h>
! 56: #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
! 57: #include <ctype.h>
! 58: #include <sys/types.h>
! 59: #include <sys/param.h>
! 60: #include "sudo.h"
! 61: #include "parse.h"
! 62: #include "sudo.tab.h"
! 63:
! 64: #ifndef lint
! 65: static const char rcsid[] = "$Sudo: parse.lex,v 1.109 1999/11/09 20:06:52 millert Exp $";
! 66: #endif /* lint */
! 67:
! 68: #undef yywrap /* guard against a yywrap macro */
! 69:
! 70: extern YYSTYPE yylval;
! 71: extern int clearaliases;
! 72: int sudolineno = 1;
! 73: static int sawspace = 0;
! 74: static int arg_len = 0;
! 75: static int arg_size = 0;
! 76:
! 77: static void fill __P((char *, int));
! 78: static void fill_cmnd __P((char *, int));
! 79: static void fill_args __P((char *, int, int));
! 80: extern void reset_aliases __P((void));
! 81: extern void yyerror __P((char *));
! 82:
! 83: /* realloc() to size + COMMANDARGINC to make room for command args */
! 84: #define COMMANDARGINC 64
! 85:
! 86: #ifdef TRACELEXER
! 87: #define LEXTRACE(msg) fputs(msg, stderr)
! 88: #else
! 89: #define LEXTRACE(msg)
! 90: #endif
! 91: %}
! 92:
! 93: OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
! 94: DOTTEDQUAD {OCTET}(\.{OCTET}){3}
! 95: HOSTNAME [[:alnum:]_-]+
! 96: WORD ([^@!=:,\(\) \t\n\\]|\\[^\n])+
! 97:
! 98: %s GOTCMND
! 99: %s GOTRUNAS
! 100: %s GOTDEFS
! 101:
! 102: %%
! 103: [ \t]+ { /* throw away space/tabs */
! 104: sawspace = TRUE; /* but remember for fill_args */
! 105: }
! 106:
! 107: \\[ \t]*\n {
! 108: sawspace = TRUE; /* remember for fill_args */
! 109: ++sudolineno;
! 110: LEXTRACE("\n\t");
! 111: } /* throw away EOL after \ */
! 112:
! 113: <GOTCMND>\\[:\,=\\ \t] {
! 114: LEXTRACE("QUOTEDCHAR ");
! 115: fill_args(yytext + 1, 1, sawspace);
! 116: sawspace = FALSE;
! 117: }
! 118:
! 119: <GOTDEFS>\"([^\"]|\\\")+\" {
! 120: LEXTRACE("WORD(1) ");
! 121: fill(yytext + 1, yyleng - 2);
! 122: return(WORD);
! 123: }
! 124:
! 125: <GOTDEFS>(#.*)?\n {
! 126: BEGIN INITIAL;
! 127: ++sudolineno;
! 128: LEXTRACE("\n");
! 129: return(COMMENT);
! 130: }
! 131:
! 132: <GOTCMND>[:\,=\n] {
! 133: BEGIN INITIAL;
! 134: unput(*yytext);
! 135: return(COMMAND);
! 136: } /* end of command line args */
! 137:
! 138: \n {
! 139: ++sudolineno;
! 140: LEXTRACE("\n");
! 141: return(COMMENT);
! 142: } /* return newline */
! 143:
! 144: <INITIAL>#.*\n {
! 145: ++sudolineno;
! 146: LEXTRACE("\n");
! 147: return(COMMENT);
! 148: } /* return comments */
! 149:
! 150: <GOTCMND>[^\\:, \t\n]+ {
! 151: LEXTRACE("ARG ");
! 152: fill_args(yytext, yyleng, sawspace);
! 153: sawspace = FALSE;
! 154: } /* a command line arg */
! 155:
! 156: , {
! 157: LEXTRACE(", ");
! 158: return(',');
! 159: } /* return ',' */
! 160:
! 161: !+ {
! 162: if (yyleng % 2 == 1)
! 163: return('!'); /* return '!' */
! 164: }
! 165:
! 166: = {
! 167: LEXTRACE("= ");
! 168: return('=');
! 169: } /* return '=' */
! 170:
! 171: : {
! 172: LEXTRACE(": ");
! 173: return(':');
! 174: } /* return ':' */
! 175:
! 176: NOPASSWD[[:blank:]]*: {
! 177: /* cmnd does not require passwd for this user */
! 178: LEXTRACE("NOPASSWD ");
! 179: return(NOPASSWD);
! 180: }
! 181:
! 182: PASSWD[[:blank:]]*: {
! 183: /* cmnd requires passwd for this user */
! 184: LEXTRACE("PASSWD ");
! 185: return(PASSWD);
! 186: }
! 187:
! 188: \+{WORD} {
! 189: /* netgroup */
! 190: fill(yytext, yyleng);
! 191: LEXTRACE("NETGROUP ");
! 192: return(NETGROUP);
! 193: }
! 194:
! 195: \%{WORD} {
! 196: /* UN*X group */
! 197: fill(yytext, yyleng);
! 198: LEXTRACE("GROUP ");
! 199: return(USERGROUP);
! 200: }
! 201:
! 202: {DOTTEDQUAD}(\/{DOTTEDQUAD})? {
! 203: fill(yytext, yyleng);
! 204: LEXTRACE("NTWKADDR ");
! 205: return(NTWKADDR);
! 206: }
! 207:
! 208: {DOTTEDQUAD}\/([12][0-9]*|3[0-2]*) {
! 209: fill(yytext, yyleng);
! 210: LEXTRACE("NTWKADDR ");
! 211: return(NTWKADDR);
! 212: }
! 213:
! 214: [[:alpha:]][[:alnum:]_-]*(\.{HOSTNAME})+ {
! 215: fill(yytext, yyleng);
! 216: LEXTRACE("FQHOST ");
! 217: return(FQHOST);
! 218: }
! 219:
! 220: <INITIAL>\( {
! 221: BEGIN GOTRUNAS;
! 222: LEXTRACE("RUNAS ");
! 223: return (RUNAS);
! 224: }
! 225:
! 226: <GOTRUNAS>[[:upper:]][[:upper:][:digit:]_]* {
! 227: /* Runas_Alias user can run command as or ALL */
! 228: if (strcmp(yytext, "ALL") == 0) {
! 229: LEXTRACE("ALL ");
! 230: return(ALL);
! 231: } else {
! 232: fill(yytext, yyleng);
! 233: LEXTRACE("ALIAS ");
! 234: return(ALIAS);
! 235: }
! 236: }
! 237:
! 238: <GOTRUNAS>#?{WORD} {
! 239: /* username/uid that user can run command as */
! 240: fill(yytext, yyleng);
! 241: LEXTRACE("WORD(2) ");
! 242: return(WORD);
! 243: }
! 244:
! 245: <GOTRUNAS>\) {
! 246: BEGIN INITIAL;
! 247: }
! 248:
! 249: [[:upper:]][[:upper:][:digit:]_]* {
! 250: if (strcmp(yytext, "ALL") == 0) {
! 251: LEXTRACE("ALL ");
! 252: return(ALL);
! 253: } else {
! 254: fill(yytext, yyleng);
! 255: LEXTRACE("ALIAS ");
! 256: return(ALIAS);
! 257: }
! 258: }
! 259:
! 260: <GOTDEFS>{WORD} {
! 261: LEXTRACE("WORD(3) ");
! 262: fill(yytext, yyleng);
! 263: return(WORD);
! 264: }
! 265:
! 266: <INITIAL>^Defaults[:@]? {
! 267: BEGIN GOTDEFS;
! 268: if (yyleng == 9) {
! 269: switch (yytext[8]) {
! 270: case ':' :
! 271: LEXTRACE("DEFAULTS_USER ");
! 272: return(DEFAULTS_USER);
! 273: case '@' :
! 274: LEXTRACE("DEFAULTS_HOST ");
! 275: return(DEFAULTS_HOST);
! 276: }
! 277: } else {
! 278: LEXTRACE("DEFAULTS ");
! 279: return(DEFAULTS);
! 280: }
! 281: }
! 282:
! 283: <INITIAL>^(Host|Cmnd|User|Runas)_Alias {
! 284: fill(yytext, yyleng);
! 285: if (*yytext == 'H') {
! 286: LEXTRACE("HOSTALIAS ");
! 287: return(HOSTALIAS);
! 288: }
! 289: if (*yytext == 'C') {
! 290: LEXTRACE("CMNDALIAS ");
! 291: return(CMNDALIAS);
! 292: }
! 293: if (*yytext == 'U') {
! 294: LEXTRACE("USERALIAS ");
! 295: return(USERALIAS);
! 296: }
! 297: if (*yytext == 'R') {
! 298: LEXTRACE("RUNASALIAS ");
! 299: return(RUNASALIAS);
! 300: }
! 301: }
! 302:
! 303: \/[^\,:=\\ \t\n#]+ {
! 304: /* directories can't have args... */
! 305: if (yytext[yyleng - 1] == '/') {
! 306: LEXTRACE("COMMAND ");
! 307: fill_cmnd(yytext, yyleng);
! 308: return(COMMAND);
! 309: } else {
! 310: BEGIN GOTCMND;
! 311: LEXTRACE("COMMAND ");
! 312: fill_cmnd(yytext, yyleng);
! 313: }
! 314: } /* a pathname */
! 315:
! 316: <INITIAL>{WORD} {
! 317: /* a word */
! 318: fill(yytext, yyleng);
! 319: LEXTRACE("WORD(4) ");
! 320: return(WORD);
! 321: }
! 322:
! 323: . {
! 324: LEXTRACE("ERROR ");
! 325: return(ERROR);
! 326: } /* parse error */
! 327:
! 328: %%
! 329: static void
! 330: fill(s, len)
! 331: char *s;
! 332: int len;
! 333: {
! 334: int i, j;
! 335:
! 336: yylval.string = (char *) malloc(len + 1);
! 337: if (yylval.string == NULL)
! 338: yyerror("unable to allocate memory");
! 339:
! 340: /* Copy the string and collapse any escaped characters. */
! 341: for (i = 0, j = 0; i < len; i++, j++) {
! 342: if (s[i] == '\\' && i != len - 1)
! 343: yylval.string[j] = s[++i];
! 344: else
! 345: yylval.string[j] = s[i];
! 346: }
! 347: yylval.string[j] = '\0';
! 348: }
! 349:
! 350: static void
! 351: fill_cmnd(s, len)
! 352: char *s;
! 353: int len;
! 354: {
! 355: arg_len = arg_size = 0;
! 356:
! 357: yylval.command.cmnd = (char *) malloc(len + 1);
! 358: if (yylval.command.cmnd == NULL)
! 359: yyerror("unable to allocate memory");
! 360:
! 361: /* copy the string and NULL-terminate it */
! 362: (void) strncpy(yylval.command.cmnd, s, len);
! 363: yylval.command.cmnd[len] = '\0';
! 364:
! 365: yylval.command.args = NULL;
! 366: }
! 367:
! 368: static void
! 369: fill_args(s, len, addspace)
! 370: char *s;
! 371: int len;
! 372: int addspace;
! 373: {
! 374: int new_len;
! 375: char *p;
! 376:
! 377: /*
! 378: * If first arg, malloc() some room, else if we don't
! 379: * have enough space realloc() some more.
! 380: */
! 381: if (yylval.command.args == NULL) {
! 382: addspace = 0;
! 383: new_len = len;
! 384:
! 385: while (new_len >= (arg_size += COMMANDARGINC))
! 386: ;
! 387:
! 388: yylval.command.args = (char *) malloc(arg_size);
! 389: if (yylval.command.args == NULL)
! 390: yyerror("unable to allocate memory");
! 391: } else {
! 392: new_len = arg_len + len + addspace;
! 393:
! 394: if (new_len >= arg_size) {
! 395: /* Allocate more space than we need for subsequent args */
! 396: while (new_len >= (arg_size += COMMANDARGINC))
! 397: ;
! 398:
! 399: if ((p = (char *) realloc(yylval.command.args, arg_size)) == NULL) {
! 400: free(yylval.command.args);
! 401: yyerror("unable to allocate memory");
! 402: } else
! 403: yylval.command.args = p;
! 404: }
! 405: }
! 406:
! 407: /* Efficiently append the arg (with a leading space if needed). */
! 408: p = yylval.command.args + arg_len;
! 409: if (addspace)
! 410: *p++ = ' ';
! 411: (void) strcpy(p, s);
! 412: arg_len = new_len;
! 413: }
! 414:
! 415: int
! 416: yywrap()
! 417: {
! 418:
! 419: /* Free space used by the aliases unless called by testsudoers. */
! 420: if (clearaliases)
! 421: reset_aliases();
! 422:
! 423: return(TRUE);
! 424: }