Annotation of src/usr.bin/sudo/parse.lex, Revision 1.15
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.15 ! millert 58: __unused static const char rcsid[] = "$Sudo: parse.lex,v 1.132.2.10 2008/06/26 11:53:50 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>{
1.15 ! millert 154: \\[[:blank:]]*\n[[:blank:]]* {
1.14 millert 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:
1.15 ! millert 166: \\ {
! 167: LEXTRACE("BACKSLASH ");
! 168: append(yytext, yyleng);
! 169: }
! 170:
! 171: ([^\"\n\\]|\\\")+ {
1.14 millert 172: LEXTRACE("STRBODY ");
173: append(yytext, yyleng);
174: }
175: }
176:
1.4 millert 177: <GOTCMND>{
1.11 millert 178: \\[\*\?\[\]\!] {
179: /* quoted fnmatch glob char, pass verbatim */
180: LEXTRACE("QUOTEDCHAR ");
181: fill_args(yytext, 2, sawspace);
182: sawspace = FALSE;
183: }
184:
1.5 millert 185: \\[:\\,= \t#] {
1.11 millert 186: /* quoted sudoers special char, strip backslash */
1.4 millert 187: LEXTRACE("QUOTEDCHAR ");
188: fill_args(yytext + 1, 1, sawspace);
189: sawspace = FALSE;
1.1 millert 190: }
191:
1.4 millert 192: [#:\,=\n] {
1.1 millert 193: BEGIN INITIAL;
194: unput(*yytext);
195: return(COMMAND);
196: } /* end of command line args */
197:
1.5 millert 198: [^\\:, \t\n]+ {
1.1 millert 199: LEXTRACE("ARG ");
200: fill_args(yytext, yyleng, sawspace);
201: sawspace = FALSE;
1.4 millert 202: } /* a command line arg */
203: }
1.1 millert 204:
1.9 millert 205: <INITIAL>^Defaults[:@>]? {
1.4 millert 206: BEGIN GOTDEFS;
207: switch (yytext[8]) {
208: case ':':
209: LEXTRACE("DEFAULTS_USER ");
210: return(DEFAULTS_USER);
1.9 millert 211: case '>':
212: LEXTRACE("DEFAULTS_RUNAS ");
213: return(DEFAULTS_RUNAS);
1.4 millert 214: case '@':
215: LEXTRACE("DEFAULTS_HOST ");
216: return(DEFAULTS_HOST);
217: default:
218: LEXTRACE("DEFAULTS ");
219: return(DEFAULTS);
220: }
221: }
1.1 millert 222:
1.4 millert 223: <INITIAL>^(Host|Cmnd|User|Runas)_Alias {
224: fill(yytext, yyleng);
225: switch (*yytext) {
226: case 'H':
227: LEXTRACE("HOSTALIAS ");
228: return(HOSTALIAS);
229: case 'C':
230: LEXTRACE("CMNDALIAS ");
231: return(CMNDALIAS);
232: case 'U':
233: LEXTRACE("USERALIAS ");
234: return(USERALIAS);
235: case 'R':
236: LEXTRACE("RUNASALIAS ");
237: BEGIN GOTRUNAS;
238: return(RUNASALIAS);
239: }
1.1 millert 240: }
241:
242: NOPASSWD[[:blank:]]*: {
243: /* cmnd does not require passwd for this user */
244: LEXTRACE("NOPASSWD ");
245: return(NOPASSWD);
246: }
247:
248: PASSWD[[:blank:]]*: {
249: /* cmnd requires passwd for this user */
250: LEXTRACE("PASSWD ");
251: return(PASSWD);
252: }
253:
1.11 millert 254: NOEXEC[[:blank:]]*: {
255: LEXTRACE("NOEXEC ");
256: return(NOEXEC);
257: }
258:
259: EXEC[[:blank:]]*: {
260: LEXTRACE("EXEC ");
261: return(EXEC);
262: }
263:
1.12 millert 264: SETENV[[:blank:]]*: {
265: LEXTRACE("SETENV ");
266: return(SETENV);
267: }
268:
269: NOSETENV[[:blank:]]*: {
270: LEXTRACE("NOSETENV ");
271: return(NOSETENV);
272: }
273:
1.1 millert 274: \+{WORD} {
275: /* netgroup */
276: fill(yytext, yyleng);
277: LEXTRACE("NETGROUP ");
278: return(NETGROUP);
279: }
280:
281: \%{WORD} {
282: /* UN*X group */
283: fill(yytext, yyleng);
284: LEXTRACE("GROUP ");
285: return(USERGROUP);
286: }
287:
1.14 millert 288: {IPV4ADDR}(\/{IPV4ADDR})? {
1.1 millert 289: fill(yytext, yyleng);
290: LEXTRACE("NTWKADDR ");
291: return(NTWKADDR);
292: }
293:
1.14 millert 294: {IPV4ADDR}\/([12][0-9]*|3[0-2]*) {
1.1 millert 295: fill(yytext, yyleng);
296: LEXTRACE("NTWKADDR ");
297: return(NTWKADDR);
298: }
1.13 millert 299:
300: {IPV6ADDR}(\/{IPV6ADDR})? {
1.14 millert 301: if (!ipv6_valid(yytext)) {
302: LEXTRACE("ERROR ");
303: return(ERROR);
304: }
1.13 millert 305: fill(yytext, yyleng);
306: LEXTRACE("NTWKADDR ");
307: return(NTWKADDR);
308: }
309:
310: {IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
1.14 millert 311: if (!ipv6_valid(yytext)) {
312: LEXTRACE("ERROR ");
313: return(ERROR);
314: }
1.13 millert 315: fill(yytext, yyleng);
316: LEXTRACE("NTWKADDR ");
317: return(NTWKADDR);
318: }
1.1 millert 319:
320: <INITIAL>\( {
321: BEGIN GOTRUNAS;
322: LEXTRACE("RUNAS ");
323: return (RUNAS);
324: }
325:
1.4 millert 326: [[:upper:]][[:upper:][:digit:]_]* {
1.1 millert 327: if (strcmp(yytext, "ALL") == 0) {
328: LEXTRACE("ALL ");
329: return(ALL);
330: }
1.15 ! millert 331: #ifdef HAVE_SELINUX
! 332: /* XXX - restrict type/role to initial state */
! 333: if (strcmp(yytext, "TYPE") == 0) {
! 334: LEXTRACE("TYPE ");
! 335: return(TYPE);
! 336: }
! 337: if (strcmp(yytext, "ROLE") == 0) {
! 338: LEXTRACE("ROLE ");
! 339: return(ROLE);
! 340: }
! 341: #endif /* HAVE_SELINUX */
! 342: fill(yytext, yyleng);
! 343: LEXTRACE("ALIAS ");
! 344: return(ALIAS);
1.1 millert 345: }
346:
1.4 millert 347: <GOTRUNAS>(#[0-9-]+|{WORD}) {
1.1 millert 348: /* username/uid that user can run command as */
349: fill(yytext, yyleng);
1.4 millert 350: LEXTRACE("WORD(3) ");
1.1 millert 351: return(WORD);
352: }
353:
1.14 millert 354: <GOTRUNAS>#[^0-9-].*\n {
355: BEGIN INITIAL;
356: ++sudolineno;
357: LEXTRACE("\n");
358: return(COMMENT);
359: }
360:
1.1 millert 361: <GOTRUNAS>\) {
362: BEGIN INITIAL;
363: }
1.11 millert 364:
365: sudoedit {
366: BEGIN GOTCMND;
367: LEXTRACE("COMMAND ");
368: fill_cmnd(yytext, yyleng);
369: } /* sudo -e */
1.1 millert 370:
1.4 millert 371: \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+ {
1.1 millert 372: /* directories can't have args... */
373: if (yytext[yyleng - 1] == '/') {
374: LEXTRACE("COMMAND ");
375: fill_cmnd(yytext, yyleng);
376: return(COMMAND);
377: } else {
378: BEGIN GOTCMND;
379: LEXTRACE("COMMAND ");
380: fill_cmnd(yytext, yyleng);
381: }
382: } /* a pathname */
383:
1.4 millert 384: <INITIAL,GOTDEFS>{WORD} {
1.1 millert 385: /* a word */
386: fill(yytext, yyleng);
387: LEXTRACE("WORD(4) ");
388: return(WORD);
389: }
390:
1.4 millert 391: , {
392: LEXTRACE(", ");
393: return(',');
394: } /* return ',' */
395:
396: = {
397: LEXTRACE("= ");
398: return('=');
399: } /* return '=' */
400:
401: : {
402: LEXTRACE(": ");
403: return(':');
404: } /* return ':' */
405:
406: <*>!+ {
407: if (yyleng % 2 == 1)
408: return('!'); /* return '!' */
409: }
410:
411: <*>\n {
412: BEGIN INITIAL;
413: ++sudolineno;
414: LEXTRACE("\n");
415: return(COMMENT);
416: } /* return newline */
417:
418: <*>[[:blank:]]+ { /* throw away space/tabs */
419: sawspace = TRUE; /* but remember for fill_args */
420: }
421:
422: <*>\\[[:blank:]]*\n {
423: sawspace = TRUE; /* remember for fill_args */
424: ++sudolineno;
425: LEXTRACE("\n\t");
426: } /* throw away EOL after \ */
427:
428: <INITIAL,STARTDEFS,INDEFS>#.*\n {
429: BEGIN INITIAL;
430: ++sudolineno;
431: LEXTRACE("\n");
432: return(COMMENT);
433: } /* return comments */
434:
435: <*>. {
1.1 millert 436: LEXTRACE("ERROR ");
437: return(ERROR);
438: } /* parse error */
1.8 millert 439:
440: <*><<EOF>> {
441: if (YY_START != INITIAL) {
442: BEGIN INITIAL;
443: LEXTRACE("ERROR ");
444: return(ERROR);
445: }
446: yyterminate();
447: }
1.1 millert 448:
449: %%
450: static void
1.14 millert 451: _fill(src, len, olen)
452: char *src;
453: int len, olen;
1.1 millert 454: {
455: int i, j;
1.14 millert 456: char *dst;
1.1 millert 457:
1.14 millert 458: dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1);
459: if (dst == NULL) {
1.1 millert 460: yyerror("unable to allocate memory");
1.9 millert 461: return;
462: }
1.14 millert 463: yylval.string = dst;
1.1 millert 464:
465: /* Copy the string and collapse any escaped characters. */
1.14 millert 466: dst += olen;
1.1 millert 467: for (i = 0, j = 0; i < len; i++, j++) {
1.14 millert 468: if (src[i] == '\\' && i != len - 1)
469: dst[j] = src[++i];
1.1 millert 470: else
1.14 millert 471: dst[j] = src[i];
1.1 millert 472: }
1.14 millert 473: dst[j] = '\0';
474: }
475:
476: static void
477: append(src, len)
478: char *src;
479: int len;
480: {
481: int olen = 0;
482:
483: if (yylval.string != NULL)
484: olen = strlen(yylval.string);
485:
486: _fill(src, len, olen);
1.1 millert 487: }
488:
489: static void
490: fill_cmnd(s, len)
491: char *s;
492: int len;
493: {
494: arg_len = arg_size = 0;
495:
1.9 millert 496: yylval.command.cmnd = (char *) malloc(++len);
497: if (yylval.command.cmnd == NULL) {
1.1 millert 498: yyerror("unable to allocate memory");
1.9 millert 499: return;
500: }
1.1 millert 501:
1.4 millert 502: /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
1.9 millert 503: (void) strlcpy(yylval.command.cmnd, s, len);
1.1 millert 504:
505: yylval.command.args = NULL;
506: }
507:
508: static void
509: fill_args(s, len, addspace)
510: char *s;
511: int len;
512: int addspace;
513: {
514: int new_len;
515: char *p;
516:
517: if (yylval.command.args == NULL) {
518: addspace = 0;
519: new_len = len;
1.9 millert 520: } else
521: new_len = arg_len + len + addspace;
1.1 millert 522:
1.9 millert 523: if (new_len >= arg_size) {
524: /* Allocate more space than we need for subsequent args */
1.1 millert 525: while (new_len >= (arg_size += COMMANDARGINC))
526: ;
527:
1.9 millert 528: p = yylval.command.args ?
529: (char *) realloc(yylval.command.args, arg_size) :
530: (char *) malloc(arg_size);
531: if (p == NULL) {
1.12 millert 532: efree(yylval.command.args);
1.1 millert 533: yyerror("unable to allocate memory");
1.9 millert 534: return;
535: } else
536: yylval.command.args = p;
1.1 millert 537: }
538:
539: /* Efficiently append the arg (with a leading space if needed). */
540: p = yylval.command.args + arg_len;
541: if (addspace)
542: *p++ = ' ';
1.9 millert 543: if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len)
544: yyerror("fill_args: buffer overflow"); /* paranoia */
1.1 millert 545: arg_len = new_len;
1.14 millert 546: }
547:
548: /*
549: * Check to make sure an IPv6 address does not contain multiple instances
550: * of the string "::". Assumes strlen(s) >= 1.
551: * Returns TRUE if address is valid else FALSE.
552: */
553: static int
554: ipv6_valid(s)
555: const char *s;
556: {
557: int nmatch = 0;
558:
559: for (; *s != '\0'; s++) {
560: if (s[0] == ':' && s[1] == ':') {
561: if (++nmatch > 1)
562: break;
563: }
564: if (s[0] == '/')
565: nmatch = 0; /* reset if we hit netmask */
566: }
567:
568: return (nmatch <= 1);
1.1 millert 569: }
570:
571: int
572: yywrap()
573: {
574:
575: /* Free space used by the aliases unless called by testsudoers. */
576: if (clearaliases)
577: reset_aliases();
578:
579: return(TRUE);
580: }