Annotation of src/usr.bin/sudo/parse.lex, Revision 1.14
1.1 millert 1: %{
2: /*
1.12 millert 3: * Copyright (c) 1996, 1998-2004, 2007
4: * Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 5: *
1.11 millert 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.
1.1 millert 9: *
1.11 millert 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.
1.1 millert 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.
1.10 millert 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.
1.1 millert 24: */
25:
1.12 millert 26: #include <config.h>
1.1 millert 27:
1.4 millert 28: #include <sys/types.h>
29: #include <sys/param.h>
30: #include <stdio.h>
1.1 millert 31: #ifdef STDC_HEADERS
1.4 millert 32: # include <stdlib.h>
33: # include <stddef.h>
34: #else
35: # ifdef HAVE_STDLIB_H
36: # include <stdlib.h>
37: # endif
1.1 millert 38: #endif /* STDC_HEADERS */
1.4 millert 39: #ifdef HAVE_STRING_H
40: # include <string.h>
41: #else
42: # ifdef HAVE_STRINGS_H
43: # include <strings.h>
44: # endif
45: #endif /* HAVE_STRING_H */
1.1 millert 46: #ifdef HAVE_UNISTD_H
1.4 millert 47: # include <unistd.h>
1.1 millert 48: #endif /* HAVE_UNISTD_H */
49: #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
1.4 millert 50: # include <malloc.h>
1.1 millert 51: #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
52: #include <ctype.h>
53: #include "sudo.h"
54: #include "parse.h"
1.4 millert 55: #include <sudo.tab.h>
1.1 millert 56:
57: #ifndef lint
1.14 ! millert 58: __unused static const char rcsid[] = "$Sudo: parse.lex,v 1.132.2.7 2007/08/25 02:48:01 millert Exp $";
1.1 millert 59: #endif /* lint */
60:
61: #undef yywrap /* guard against a yywrap macro */
62:
63: extern YYSTYPE yylval;
64: extern int clearaliases;
65: int sudolineno = 1;
66: static int sawspace = 0;
67: static int arg_len = 0;
68: static int arg_size = 0;
69:
1.14 ! millert 70: static int ipv6_valid __P((const char *s));
! 71: static void _fill __P((char *, int, int));
! 72: static void append __P((char *, int));
1.1 millert 73: static void fill_cmnd __P((char *, int));
74: static void fill_args __P((char *, int, int));
75: extern void reset_aliases __P((void));
76: extern void yyerror __P((char *));
77:
1.14 ! millert 78: #define fill(a, b) _fill(a, b, 0)
! 79:
1.1 millert 80: /* realloc() to size + COMMANDARGINC to make room for command args */
81: #define COMMANDARGINC 64
82:
83: #ifdef TRACELEXER
84: #define LEXTRACE(msg) fputs(msg, stderr)
85: #else
86: #define LEXTRACE(msg)
87: #endif
88: %}
89:
1.14 ! millert 90: HEX16 [0-9A-Fa-f]{1,4}
1.1 millert 91: OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
1.14 ! millert 92: IPV4ADDR {OCTET}(\.{OCTET}){3}
! 93: IPV6ADDR ({HEX16}?:){2,7}{HEX16}?|({HEX16}?:){2,6}:{IPV4ADDR}
1.13 millert 94:
1.1 millert 95: HOSTNAME [[:alnum:]_-]+
1.9 millert 96: WORD ([^#>@!=:,\(\) \t\n\\]|\\[^\n])+
1.14 ! millert 97: ENVAR ([^#!=, \t\n\\\"]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
1.4 millert 98: DEFVAR [a-z_]+
1.1 millert 99:
1.4 millert 100: /* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */
1.1 millert 101: %s GOTRUNAS
102: %s GOTDEFS
1.4 millert 103: %x GOTCMND
104: %x STARTDEFS
105: %x INDEFS
1.14 ! millert 106: %x INSTR
1.1 millert 107:
108: %%
1.4 millert 109: <GOTDEFS>[[:blank:]]+ BEGIN STARTDEFS;
110:
111: <STARTDEFS>{DEFVAR} {
112: BEGIN INDEFS;
113: LEXTRACE("DEFVAR ");
114: fill(yytext, yyleng);
115: return(DEFVAR);
1.1 millert 116: }
117:
1.4 millert 118: <INDEFS>{
119: , {
120: BEGIN STARTDEFS;
121: LEXTRACE(", ");
122: return(',');
123: } /* return ',' */
124:
125: = {
126: LEXTRACE("= ");
127: return('=');
128: } /* return '=' */
1.1 millert 129:
1.4 millert 130: \+= {
131: LEXTRACE("+= ");
132: return('+');
133: } /* return '+' */
134:
135: -= {
136: LEXTRACE("-= ");
137: return('-');
138: } /* return '-' */
1.1 millert 139:
1.14 ! millert 140: \" {
! 141: LEXTRACE("BEGINSTR ");
! 142: yylval.string = NULL;
! 143: BEGIN INSTR;
1.1 millert 144: }
145:
1.4 millert 146: {ENVAR} {
147: LEXTRACE("WORD(2) ");
148: fill(yytext, yyleng);
149: return(WORD);
150: }
151: }
152:
1.14 ! millert 153: <INSTR>{
! 154: \\\n[[:blank:]]* {
! 155: /* Line continuation char followed by newline. */
! 156: ++sudolineno;
! 157: LEXTRACE("\n");
! 158: }
! 159:
! 160: \" {
! 161: LEXTRACE("ENDSTR ");
! 162: BEGIN INDEFS;
! 163: return(WORD);
! 164: }
! 165:
! 166: ([^\"\n]|\\\")+ {
! 167: LEXTRACE("STRBODY ");
! 168: /* Push back line continuation char if present */
! 169: if (yyleng > 2 && yytext[yyleng - 1] == '\\' &&
! 170: isspace((unsigned char)yytext[yyleng - 2]))
! 171: yyless(yyleng - 1);
! 172: append(yytext, yyleng);
! 173: }
! 174: }
! 175:
1.4 millert 176: <GOTCMND>{
1.11 millert 177: \\[\*\?\[\]\!] {
178: /* quoted fnmatch glob char, pass verbatim */
179: LEXTRACE("QUOTEDCHAR ");
180: fill_args(yytext, 2, sawspace);
181: sawspace = FALSE;
182: }
183:
1.5 millert 184: \\[:\\,= \t#] {
1.11 millert 185: /* quoted sudoers special char, strip backslash */
1.4 millert 186: LEXTRACE("QUOTEDCHAR ");
187: fill_args(yytext + 1, 1, sawspace);
188: sawspace = FALSE;
1.1 millert 189: }
190:
1.4 millert 191: [#:\,=\n] {
1.1 millert 192: BEGIN INITIAL;
193: unput(*yytext);
194: return(COMMAND);
195: } /* end of command line args */
196:
1.5 millert 197: [^\\:, \t\n]+ {
1.1 millert 198: LEXTRACE("ARG ");
199: fill_args(yytext, yyleng, sawspace);
200: sawspace = FALSE;
1.4 millert 201: } /* a command line arg */
202: }
1.1 millert 203:
1.9 millert 204: <INITIAL>^Defaults[:@>]? {
1.4 millert 205: BEGIN GOTDEFS;
206: switch (yytext[8]) {
207: case ':':
208: LEXTRACE("DEFAULTS_USER ");
209: return(DEFAULTS_USER);
1.9 millert 210: case '>':
211: LEXTRACE("DEFAULTS_RUNAS ");
212: return(DEFAULTS_RUNAS);
1.4 millert 213: case '@':
214: LEXTRACE("DEFAULTS_HOST ");
215: return(DEFAULTS_HOST);
216: default:
217: LEXTRACE("DEFAULTS ");
218: return(DEFAULTS);
219: }
220: }
1.1 millert 221:
1.4 millert 222: <INITIAL>^(Host|Cmnd|User|Runas)_Alias {
223: fill(yytext, yyleng);
224: switch (*yytext) {
225: case 'H':
226: LEXTRACE("HOSTALIAS ");
227: return(HOSTALIAS);
228: case 'C':
229: LEXTRACE("CMNDALIAS ");
230: return(CMNDALIAS);
231: case 'U':
232: LEXTRACE("USERALIAS ");
233: return(USERALIAS);
234: case 'R':
235: LEXTRACE("RUNASALIAS ");
236: BEGIN GOTRUNAS;
237: return(RUNASALIAS);
238: }
1.1 millert 239: }
240:
241: NOPASSWD[[:blank:]]*: {
242: /* cmnd does not require passwd for this user */
243: LEXTRACE("NOPASSWD ");
244: return(NOPASSWD);
245: }
246:
247: PASSWD[[:blank:]]*: {
248: /* cmnd requires passwd for this user */
249: LEXTRACE("PASSWD ");
250: return(PASSWD);
251: }
252:
1.11 millert 253: NOEXEC[[:blank:]]*: {
254: LEXTRACE("NOEXEC ");
255: return(NOEXEC);
256: }
257:
258: EXEC[[:blank:]]*: {
259: LEXTRACE("EXEC ");
260: return(EXEC);
261: }
262:
1.12 millert 263: SETENV[[:blank:]]*: {
264: LEXTRACE("SETENV ");
265: return(SETENV);
266: }
267:
268: NOSETENV[[:blank:]]*: {
269: LEXTRACE("NOSETENV ");
270: return(NOSETENV);
271: }
272:
1.1 millert 273: \+{WORD} {
274: /* netgroup */
275: fill(yytext, yyleng);
276: LEXTRACE("NETGROUP ");
277: return(NETGROUP);
278: }
279:
280: \%{WORD} {
281: /* UN*X group */
282: fill(yytext, yyleng);
283: LEXTRACE("GROUP ");
284: return(USERGROUP);
285: }
286:
1.14 ! millert 287: {IPV4ADDR}(\/{IPV4ADDR})? {
1.1 millert 288: fill(yytext, yyleng);
289: LEXTRACE("NTWKADDR ");
290: return(NTWKADDR);
291: }
292:
1.14 ! millert 293: {IPV4ADDR}\/([12][0-9]*|3[0-2]*) {
1.1 millert 294: fill(yytext, yyleng);
295: LEXTRACE("NTWKADDR ");
296: return(NTWKADDR);
297: }
1.13 millert 298:
299: {IPV6ADDR}(\/{IPV6ADDR})? {
1.14 ! millert 300: if (!ipv6_valid(yytext)) {
! 301: LEXTRACE("ERROR ");
! 302: return(ERROR);
! 303: }
1.13 millert 304: fill(yytext, yyleng);
305: LEXTRACE("NTWKADDR ");
306: return(NTWKADDR);
307: }
308:
309: {IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
1.14 ! millert 310: if (!ipv6_valid(yytext)) {
! 311: LEXTRACE("ERROR ");
! 312: return(ERROR);
! 313: }
1.13 millert 314: fill(yytext, yyleng);
315: LEXTRACE("NTWKADDR ");
316: return(NTWKADDR);
317: }
1.1 millert 318:
319: <INITIAL>\( {
320: BEGIN GOTRUNAS;
321: LEXTRACE("RUNAS ");
322: return (RUNAS);
323: }
324:
1.4 millert 325: [[:upper:]][[:upper:][:digit:]_]* {
1.1 millert 326: if (strcmp(yytext, "ALL") == 0) {
327: LEXTRACE("ALL ");
328: return(ALL);
329: } else {
330: fill(yytext, yyleng);
331: LEXTRACE("ALIAS ");
332: return(ALIAS);
333: }
334: }
335:
1.4 millert 336: <GOTRUNAS>(#[0-9-]+|{WORD}) {
1.1 millert 337: /* username/uid that user can run command as */
338: fill(yytext, yyleng);
1.4 millert 339: LEXTRACE("WORD(3) ");
1.1 millert 340: return(WORD);
341: }
342:
1.14 ! millert 343: <GOTRUNAS>#[^0-9-].*\n {
! 344: BEGIN INITIAL;
! 345: ++sudolineno;
! 346: LEXTRACE("\n");
! 347: return(COMMENT);
! 348: }
! 349:
1.1 millert 350: <GOTRUNAS>\) {
351: BEGIN INITIAL;
352: }
1.11 millert 353:
354: sudoedit {
355: BEGIN GOTCMND;
356: LEXTRACE("COMMAND ");
357: fill_cmnd(yytext, yyleng);
358: } /* sudo -e */
1.1 millert 359:
1.4 millert 360: \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+ {
1.1 millert 361: /* directories can't have args... */
362: if (yytext[yyleng - 1] == '/') {
363: LEXTRACE("COMMAND ");
364: fill_cmnd(yytext, yyleng);
365: return(COMMAND);
366: } else {
367: BEGIN GOTCMND;
368: LEXTRACE("COMMAND ");
369: fill_cmnd(yytext, yyleng);
370: }
371: } /* a pathname */
372:
1.4 millert 373: <INITIAL,GOTDEFS>{WORD} {
1.1 millert 374: /* a word */
375: fill(yytext, yyleng);
376: LEXTRACE("WORD(4) ");
377: return(WORD);
378: }
379:
1.4 millert 380: , {
381: LEXTRACE(", ");
382: return(',');
383: } /* return ',' */
384:
385: = {
386: LEXTRACE("= ");
387: return('=');
388: } /* return '=' */
389:
390: : {
391: LEXTRACE(": ");
392: return(':');
393: } /* return ':' */
394:
395: <*>!+ {
396: if (yyleng % 2 == 1)
397: return('!'); /* return '!' */
398: }
399:
400: <*>\n {
401: BEGIN INITIAL;
402: ++sudolineno;
403: LEXTRACE("\n");
404: return(COMMENT);
405: } /* return newline */
406:
407: <*>[[:blank:]]+ { /* throw away space/tabs */
408: sawspace = TRUE; /* but remember for fill_args */
409: }
410:
411: <*>\\[[:blank:]]*\n {
412: sawspace = TRUE; /* remember for fill_args */
413: ++sudolineno;
414: LEXTRACE("\n\t");
415: } /* throw away EOL after \ */
416:
417: <INITIAL,STARTDEFS,INDEFS>#.*\n {
418: BEGIN INITIAL;
419: ++sudolineno;
420: LEXTRACE("\n");
421: return(COMMENT);
422: } /* return comments */
423:
424: <*>. {
1.1 millert 425: LEXTRACE("ERROR ");
426: return(ERROR);
427: } /* parse error */
1.8 millert 428:
429: <*><<EOF>> {
430: if (YY_START != INITIAL) {
431: BEGIN INITIAL;
432: LEXTRACE("ERROR ");
433: return(ERROR);
434: }
435: yyterminate();
436: }
1.1 millert 437:
438: %%
439: static void
1.14 ! millert 440: _fill(src, len, olen)
! 441: char *src;
! 442: int len, olen;
1.1 millert 443: {
444: int i, j;
1.14 ! millert 445: char *dst;
1.1 millert 446:
1.14 ! millert 447: dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1);
! 448: if (dst == NULL) {
1.1 millert 449: yyerror("unable to allocate memory");
1.9 millert 450: return;
451: }
1.14 ! millert 452: yylval.string = dst;
1.1 millert 453:
454: /* Copy the string and collapse any escaped characters. */
1.14 ! millert 455: dst += olen;
1.1 millert 456: for (i = 0, j = 0; i < len; i++, j++) {
1.14 ! millert 457: if (src[i] == '\\' && i != len - 1)
! 458: dst[j] = src[++i];
1.1 millert 459: else
1.14 ! millert 460: dst[j] = src[i];
1.1 millert 461: }
1.14 ! millert 462: dst[j] = '\0';
! 463: }
! 464:
! 465: static void
! 466: append(src, len)
! 467: char *src;
! 468: int len;
! 469: {
! 470: int olen = 0;
! 471:
! 472: if (yylval.string != NULL)
! 473: olen = strlen(yylval.string);
! 474:
! 475: _fill(src, len, olen);
1.1 millert 476: }
477:
478: static void
479: fill_cmnd(s, len)
480: char *s;
481: int len;
482: {
483: arg_len = arg_size = 0;
484:
1.9 millert 485: yylval.command.cmnd = (char *) malloc(++len);
486: if (yylval.command.cmnd == NULL) {
1.1 millert 487: yyerror("unable to allocate memory");
1.9 millert 488: return;
489: }
1.1 millert 490:
1.4 millert 491: /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
1.9 millert 492: (void) strlcpy(yylval.command.cmnd, s, len);
1.1 millert 493:
494: yylval.command.args = NULL;
495: }
496:
497: static void
498: fill_args(s, len, addspace)
499: char *s;
500: int len;
501: int addspace;
502: {
503: int new_len;
504: char *p;
505:
506: if (yylval.command.args == NULL) {
507: addspace = 0;
508: new_len = len;
1.9 millert 509: } else
510: new_len = arg_len + len + addspace;
1.1 millert 511:
1.9 millert 512: if (new_len >= arg_size) {
513: /* Allocate more space than we need for subsequent args */
1.1 millert 514: while (new_len >= (arg_size += COMMANDARGINC))
515: ;
516:
1.9 millert 517: p = yylval.command.args ?
518: (char *) realloc(yylval.command.args, arg_size) :
519: (char *) malloc(arg_size);
520: if (p == NULL) {
1.12 millert 521: efree(yylval.command.args);
1.1 millert 522: yyerror("unable to allocate memory");
1.9 millert 523: return;
524: } else
525: yylval.command.args = p;
1.1 millert 526: }
527:
528: /* Efficiently append the arg (with a leading space if needed). */
529: p = yylval.command.args + arg_len;
530: if (addspace)
531: *p++ = ' ';
1.9 millert 532: if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len)
533: yyerror("fill_args: buffer overflow"); /* paranoia */
1.1 millert 534: arg_len = new_len;
1.14 ! millert 535: }
! 536:
! 537: /*
! 538: * Check to make sure an IPv6 address does not contain multiple instances
! 539: * of the string "::". Assumes strlen(s) >= 1.
! 540: * Returns TRUE if address is valid else FALSE.
! 541: */
! 542: static int
! 543: ipv6_valid(s)
! 544: const char *s;
! 545: {
! 546: int nmatch = 0;
! 547:
! 548: for (; *s != '\0'; s++) {
! 549: if (s[0] == ':' && s[1] == ':') {
! 550: if (++nmatch > 1)
! 551: break;
! 552: }
! 553: if (s[0] == '/')
! 554: nmatch = 0; /* reset if we hit netmask */
! 555: }
! 556:
! 557: return (nmatch <= 1);
1.1 millert 558: }
559:
560: int
561: yywrap()
562: {
563:
564: /* Free space used by the aliases unless called by testsudoers. */
565: if (clearaliases)
566: reset_aliases();
567:
568: return(TRUE);
569: }