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