Annotation of src/usr.bin/sudo/parse.lex, Revision 1.13
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.13 ! millert 58: __unused static const char rcsid[] = "$Sudo: parse.lex,v 1.132.2.4 2007/08/13 16:30:02 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:
70: static void fill __P((char *, int));
71: static void fill_cmnd __P((char *, int));
72: static void fill_args __P((char *, int, int));
73: extern void reset_aliases __P((void));
74: extern void yyerror __P((char *));
75:
76: /* realloc() to size + COMMANDARGINC to make room for command args */
77: #define COMMANDARGINC 64
78:
79: #ifdef TRACELEXER
80: #define LEXTRACE(msg) fputs(msg, stderr)
81: #else
82: #define LEXTRACE(msg)
83: #endif
84: %}
85:
1.13 ! millert 86: HEXDIGIT [0-9A-Fa-f]{1,4}
1.1 millert 87: OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
88: DOTTEDQUAD {OCTET}(\.{OCTET}){3}
1.13 ! millert 89: IPV6ADDR \:\:|({HEXDIGIT}\:){7}{HEXDIGIT}|({HEXDIGIT}\:){5}{HEXDIGIT}\:{DOTTEDQUAD}|({HEXDIGIT}\:){1,7}\:|({HEXDIGIT}\:){1,6}(\:{HEXDIGIT}){1}|({HEXDIGIT}\:){1,5}(\:{HEXDIGIT}){2}|({HEXDIGIT}\:){1,2}\:{DOTTEDQUAD}|({HEXDIGIT}\:){1,4}(\:{HEXDIGIT}){3}|({HEXDIGIT}\:){1,4}(\:{HEXDIGIT}){1}\:{DOTTEDQUAD}|({HEXDIGIT}\:){1,3}(\:{HEXDIGIT}){4}|({HEXDIGIT}\:){1,3}(\:{HEXDIGIT}){2}\:{DOTTEDQUAD}|({HEXDIGIT}\:){1,2}(\:{HEXDIGIT}){5}|({HEXDIGIT}\:){1,2}(\:{HEXDIGIT}){3}\:{DOTTEDQUAD}|({HEXDIGIT}\:){1}(\:{HEXDIGIT}){6}|({HEXDIGIT}\:){1}(\:{HEXDIGIT}){4}\:{DOTTEDQUAD}|\:(\:{HEXDIGIT}){1,7}|\:(\:{HEXDIGIT}){1,5}\:{DOTTEDQUAD}
! 90:
1.1 millert 91: HOSTNAME [[:alnum:]_-]+
1.9 millert 92: WORD ([^#>@!=:,\(\) \t\n\\]|\\[^\n])+
1.4 millert 93: ENVAR ([^#!=, \t\n\\]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
94: DEFVAR [a-z_]+
1.1 millert 95:
1.4 millert 96: /* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */
1.1 millert 97: %s GOTRUNAS
98: %s GOTDEFS
1.4 millert 99: %x GOTCMND
100: %x STARTDEFS
101: %x INDEFS
1.1 millert 102:
103: %%
1.4 millert 104: <GOTDEFS>[[:blank:]]+ BEGIN STARTDEFS;
105:
106: <STARTDEFS>{DEFVAR} {
107: BEGIN INDEFS;
108: LEXTRACE("DEFVAR ");
109: fill(yytext, yyleng);
110: return(DEFVAR);
1.1 millert 111: }
112:
1.4 millert 113: <INDEFS>{
114: , {
115: BEGIN STARTDEFS;
116: LEXTRACE(", ");
117: return(',');
118: } /* return ',' */
119:
120: = {
121: LEXTRACE("= ");
122: return('=');
123: } /* return '=' */
1.1 millert 124:
1.4 millert 125: \+= {
126: LEXTRACE("+= ");
127: return('+');
128: } /* return '+' */
129:
130: -= {
131: LEXTRACE("-= ");
132: return('-');
133: } /* return '-' */
1.1 millert 134:
1.4 millert 135: \"([^\"]|\\\")+\" {
1.1 millert 136: LEXTRACE("WORD(1) ");
137: fill(yytext + 1, yyleng - 2);
138: return(WORD);
139: }
140:
1.4 millert 141: {ENVAR} {
142: LEXTRACE("WORD(2) ");
143: fill(yytext, yyleng);
144: return(WORD);
145: }
146: }
147:
148: <GOTCMND>{
1.11 millert 149: \\[\*\?\[\]\!] {
150: /* quoted fnmatch glob char, pass verbatim */
151: LEXTRACE("QUOTEDCHAR ");
152: fill_args(yytext, 2, sawspace);
153: sawspace = FALSE;
154: }
155:
1.5 millert 156: \\[:\\,= \t#] {
1.11 millert 157: /* quoted sudoers special char, strip backslash */
1.4 millert 158: LEXTRACE("QUOTEDCHAR ");
159: fill_args(yytext + 1, 1, sawspace);
160: sawspace = FALSE;
1.1 millert 161: }
162:
1.4 millert 163: [#:\,=\n] {
1.1 millert 164: BEGIN INITIAL;
165: unput(*yytext);
166: return(COMMAND);
167: } /* end of command line args */
168:
1.5 millert 169: [^\\:, \t\n]+ {
1.1 millert 170: LEXTRACE("ARG ");
171: fill_args(yytext, yyleng, sawspace);
172: sawspace = FALSE;
1.4 millert 173: } /* a command line arg */
174: }
1.1 millert 175:
1.9 millert 176: <INITIAL>^Defaults[:@>]? {
1.4 millert 177: BEGIN GOTDEFS;
178: switch (yytext[8]) {
179: case ':':
180: LEXTRACE("DEFAULTS_USER ");
181: return(DEFAULTS_USER);
1.9 millert 182: case '>':
183: LEXTRACE("DEFAULTS_RUNAS ");
184: return(DEFAULTS_RUNAS);
1.4 millert 185: case '@':
186: LEXTRACE("DEFAULTS_HOST ");
187: return(DEFAULTS_HOST);
188: default:
189: LEXTRACE("DEFAULTS ");
190: return(DEFAULTS);
191: }
192: }
1.1 millert 193:
1.4 millert 194: <INITIAL>^(Host|Cmnd|User|Runas)_Alias {
195: fill(yytext, yyleng);
196: switch (*yytext) {
197: case 'H':
198: LEXTRACE("HOSTALIAS ");
199: return(HOSTALIAS);
200: case 'C':
201: LEXTRACE("CMNDALIAS ");
202: return(CMNDALIAS);
203: case 'U':
204: LEXTRACE("USERALIAS ");
205: return(USERALIAS);
206: case 'R':
207: LEXTRACE("RUNASALIAS ");
208: BEGIN GOTRUNAS;
209: return(RUNASALIAS);
210: }
1.1 millert 211: }
212:
213: NOPASSWD[[:blank:]]*: {
214: /* cmnd does not require passwd for this user */
215: LEXTRACE("NOPASSWD ");
216: return(NOPASSWD);
217: }
218:
219: PASSWD[[:blank:]]*: {
220: /* cmnd requires passwd for this user */
221: LEXTRACE("PASSWD ");
222: return(PASSWD);
223: }
224:
1.11 millert 225: NOEXEC[[:blank:]]*: {
226: LEXTRACE("NOEXEC ");
227: return(NOEXEC);
228: }
229:
230: EXEC[[:blank:]]*: {
231: LEXTRACE("EXEC ");
232: return(EXEC);
233: }
234:
1.12 millert 235: SETENV[[:blank:]]*: {
236: LEXTRACE("SETENV ");
237: return(SETENV);
238: }
239:
240: NOSETENV[[:blank:]]*: {
241: LEXTRACE("NOSETENV ");
242: return(NOSETENV);
243: }
244:
1.1 millert 245: \+{WORD} {
246: /* netgroup */
247: fill(yytext, yyleng);
248: LEXTRACE("NETGROUP ");
249: return(NETGROUP);
250: }
251:
252: \%{WORD} {
253: /* UN*X group */
254: fill(yytext, yyleng);
255: LEXTRACE("GROUP ");
256: return(USERGROUP);
257: }
258:
259: {DOTTEDQUAD}(\/{DOTTEDQUAD})? {
260: fill(yytext, yyleng);
261: LEXTRACE("NTWKADDR ");
262: return(NTWKADDR);
263: }
264:
265: {DOTTEDQUAD}\/([12][0-9]*|3[0-2]*) {
266: fill(yytext, yyleng);
267: LEXTRACE("NTWKADDR ");
268: return(NTWKADDR);
269: }
1.13 ! millert 270:
! 271: {IPV6ADDR}(\/{IPV6ADDR})? {
! 272: fill(yytext, yyleng);
! 273: LEXTRACE("NTWKADDR ");
! 274: return(NTWKADDR);
! 275: }
! 276:
! 277: {IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
! 278: fill(yytext, yyleng);
! 279: LEXTRACE("NTWKADDR ");
! 280: return(NTWKADDR);
! 281: }
1.1 millert 282:
283: <INITIAL>\( {
284: BEGIN GOTRUNAS;
285: LEXTRACE("RUNAS ");
286: return (RUNAS);
287: }
288:
1.4 millert 289: [[:upper:]][[:upper:][:digit:]_]* {
1.1 millert 290: if (strcmp(yytext, "ALL") == 0) {
291: LEXTRACE("ALL ");
292: return(ALL);
293: } else {
294: fill(yytext, yyleng);
295: LEXTRACE("ALIAS ");
296: return(ALIAS);
297: }
298: }
299:
1.4 millert 300: <GOTRUNAS>(#[0-9-]+|{WORD}) {
1.1 millert 301: /* username/uid that user can run command as */
302: fill(yytext, yyleng);
1.4 millert 303: LEXTRACE("WORD(3) ");
1.1 millert 304: return(WORD);
305: }
306:
307: <GOTRUNAS>\) {
308: BEGIN INITIAL;
309: }
1.11 millert 310:
311: sudoedit {
312: BEGIN GOTCMND;
313: LEXTRACE("COMMAND ");
314: fill_cmnd(yytext, yyleng);
315: } /* sudo -e */
1.1 millert 316:
1.4 millert 317: \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+ {
1.1 millert 318: /* directories can't have args... */
319: if (yytext[yyleng - 1] == '/') {
320: LEXTRACE("COMMAND ");
321: fill_cmnd(yytext, yyleng);
322: return(COMMAND);
323: } else {
324: BEGIN GOTCMND;
325: LEXTRACE("COMMAND ");
326: fill_cmnd(yytext, yyleng);
327: }
328: } /* a pathname */
329:
1.4 millert 330: <INITIAL,GOTDEFS>{WORD} {
1.1 millert 331: /* a word */
332: fill(yytext, yyleng);
333: LEXTRACE("WORD(4) ");
334: return(WORD);
335: }
336:
1.4 millert 337: , {
338: LEXTRACE(", ");
339: return(',');
340: } /* return ',' */
341:
342: = {
343: LEXTRACE("= ");
344: return('=');
345: } /* return '=' */
346:
347: : {
348: LEXTRACE(": ");
349: return(':');
350: } /* return ':' */
351:
352: <*>!+ {
353: if (yyleng % 2 == 1)
354: return('!'); /* return '!' */
355: }
356:
357: <*>\n {
358: BEGIN INITIAL;
359: ++sudolineno;
360: LEXTRACE("\n");
361: return(COMMENT);
362: } /* return newline */
363:
364: <*>[[:blank:]]+ { /* throw away space/tabs */
365: sawspace = TRUE; /* but remember for fill_args */
366: }
367:
368: <*>\\[[:blank:]]*\n {
369: sawspace = TRUE; /* remember for fill_args */
370: ++sudolineno;
371: LEXTRACE("\n\t");
372: } /* throw away EOL after \ */
373:
374: <INITIAL,STARTDEFS,INDEFS>#.*\n {
375: BEGIN INITIAL;
376: ++sudolineno;
377: LEXTRACE("\n");
378: return(COMMENT);
379: } /* return comments */
380:
381: <*>. {
1.1 millert 382: LEXTRACE("ERROR ");
383: return(ERROR);
384: } /* parse error */
1.8 millert 385:
386: <*><<EOF>> {
387: if (YY_START != INITIAL) {
388: BEGIN INITIAL;
389: LEXTRACE("ERROR ");
390: return(ERROR);
391: }
392: yyterminate();
393: }
1.1 millert 394:
395: %%
396: static void
397: fill(s, len)
398: char *s;
399: int len;
400: {
401: int i, j;
402:
403: yylval.string = (char *) malloc(len + 1);
1.9 millert 404: if (yylval.string == NULL) {
1.1 millert 405: yyerror("unable to allocate memory");
1.9 millert 406: return;
407: }
1.1 millert 408:
409: /* Copy the string and collapse any escaped characters. */
410: for (i = 0, j = 0; i < len; i++, j++) {
411: if (s[i] == '\\' && i != len - 1)
412: yylval.string[j] = s[++i];
413: else
414: yylval.string[j] = s[i];
415: }
416: yylval.string[j] = '\0';
417: }
418:
419: static void
420: fill_cmnd(s, len)
421: char *s;
422: int len;
423: {
424: arg_len = arg_size = 0;
425:
1.9 millert 426: yylval.command.cmnd = (char *) malloc(++len);
427: if (yylval.command.cmnd == NULL) {
1.1 millert 428: yyerror("unable to allocate memory");
1.9 millert 429: return;
430: }
1.1 millert 431:
1.4 millert 432: /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
1.9 millert 433: (void) strlcpy(yylval.command.cmnd, s, len);
1.1 millert 434:
435: yylval.command.args = NULL;
436: }
437:
438: static void
439: fill_args(s, len, addspace)
440: char *s;
441: int len;
442: int addspace;
443: {
444: int new_len;
445: char *p;
446:
447: if (yylval.command.args == NULL) {
448: addspace = 0;
449: new_len = len;
1.9 millert 450: } else
451: new_len = arg_len + len + addspace;
1.1 millert 452:
1.9 millert 453: if (new_len >= arg_size) {
454: /* Allocate more space than we need for subsequent args */
1.1 millert 455: while (new_len >= (arg_size += COMMANDARGINC))
456: ;
457:
1.9 millert 458: p = yylval.command.args ?
459: (char *) realloc(yylval.command.args, arg_size) :
460: (char *) malloc(arg_size);
461: if (p == NULL) {
1.12 millert 462: efree(yylval.command.args);
1.1 millert 463: yyerror("unable to allocate memory");
1.9 millert 464: return;
465: } else
466: yylval.command.args = p;
1.1 millert 467: }
468:
469: /* Efficiently append the arg (with a leading space if needed). */
470: p = yylval.command.args + arg_len;
471: if (addspace)
472: *p++ = ' ';
1.9 millert 473: if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len)
474: yyerror("fill_args: buffer overflow"); /* paranoia */
1.1 millert 475: arg_len = new_len;
476: }
477:
478: int
479: yywrap()
480: {
481:
482: /* Free space used by the aliases unless called by testsudoers. */
483: if (clearaliases)
484: reset_aliases();
485:
486: return(TRUE);
487: }