Annotation of src/usr.bin/sudo/parse.lex, Revision 1.5
1.1 millert 1: %{
2: /*
1.4 millert 3: * Copyright (c) 1996, 1998-2001 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 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:
1.4 millert 42: #include <sys/types.h>
43: #include <sys/param.h>
44: #include <stdio.h>
1.1 millert 45: #ifdef STDC_HEADERS
1.4 millert 46: # include <stdlib.h>
47: # include <stddef.h>
48: #else
49: # ifdef HAVE_STDLIB_H
50: # include <stdlib.h>
51: # endif
1.1 millert 52: #endif /* STDC_HEADERS */
1.4 millert 53: #ifdef HAVE_STRING_H
54: # include <string.h>
55: #else
56: # ifdef HAVE_STRINGS_H
57: # include <strings.h>
58: # endif
59: #endif /* HAVE_STRING_H */
1.1 millert 60: #ifdef HAVE_UNISTD_H
1.4 millert 61: # include <unistd.h>
1.1 millert 62: #endif /* HAVE_UNISTD_H */
63: #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
1.4 millert 64: # include <malloc.h>
1.1 millert 65: #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
66: #include <ctype.h>
67: #include "sudo.h"
68: #include "parse.h"
1.4 millert 69: #include <sudo.tab.h>
1.1 millert 70:
71: #ifndef lint
1.5 ! millert 72: static const char rcsid[] = "$Sudo: parse.lex,v 1.118 2002/01/15 18:16:31 millert Exp $";
1.1 millert 73: #endif /* lint */
74:
75: #undef yywrap /* guard against a yywrap macro */
76:
77: extern YYSTYPE yylval;
78: extern int clearaliases;
79: int sudolineno = 1;
80: static int sawspace = 0;
81: static int arg_len = 0;
82: static int arg_size = 0;
83:
84: static void fill __P((char *, int));
85: static void fill_cmnd __P((char *, int));
86: static void fill_args __P((char *, int, int));
87: extern void reset_aliases __P((void));
88: extern void yyerror __P((char *));
89:
90: /* realloc() to size + COMMANDARGINC to make room for command args */
91: #define COMMANDARGINC 64
92:
93: #ifdef TRACELEXER
94: #define LEXTRACE(msg) fputs(msg, stderr)
95: #else
96: #define LEXTRACE(msg)
97: #endif
98: %}
99:
100: OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
101: DOTTEDQUAD {OCTET}(\.{OCTET}){3}
102: HOSTNAME [[:alnum:]_-]+
1.4 millert 103: WORD ([^#@!=:,\(\) \t\n\\]|\\[^\n])+
104: ENVAR ([^#!=, \t\n\\]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
105: DEFVAR [a-z_]+
1.1 millert 106:
1.4 millert 107: /* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */
1.1 millert 108: %s GOTRUNAS
109: %s GOTDEFS
1.4 millert 110: %x GOTCMND
111: %x STARTDEFS
112: %x INDEFS
1.1 millert 113:
114: %%
1.4 millert 115: <GOTDEFS>[[:blank:]]+ BEGIN STARTDEFS;
116:
117: <STARTDEFS>{DEFVAR} {
118: BEGIN INDEFS;
119: LEXTRACE("DEFVAR ");
120: fill(yytext, yyleng);
121: return(DEFVAR);
1.1 millert 122: }
123:
1.4 millert 124: <INDEFS>{
125: , {
126: BEGIN STARTDEFS;
127: LEXTRACE(", ");
128: return(',');
129: } /* return ',' */
130:
131: = {
132: LEXTRACE("= ");
133: return('=');
134: } /* return '=' */
1.1 millert 135:
1.4 millert 136: \+= {
137: LEXTRACE("+= ");
138: return('+');
139: } /* return '+' */
140:
141: -= {
142: LEXTRACE("-= ");
143: return('-');
144: } /* return '-' */
1.1 millert 145:
1.4 millert 146: \"([^\"]|\\\")+\" {
1.1 millert 147: LEXTRACE("WORD(1) ");
148: fill(yytext + 1, yyleng - 2);
149: return(WORD);
150: }
151:
1.4 millert 152: {ENVAR} {
153: LEXTRACE("WORD(2) ");
154: fill(yytext, yyleng);
155: return(WORD);
156: }
157: }
158:
159: <GOTCMND>{
1.5 ! millert 160: \\[:\\,= \t#] {
1.4 millert 161: LEXTRACE("QUOTEDCHAR ");
162: fill_args(yytext + 1, 1, sawspace);
163: sawspace = FALSE;
1.1 millert 164: }
165:
1.4 millert 166: [#:\,=\n] {
1.1 millert 167: BEGIN INITIAL;
168: unput(*yytext);
169: return(COMMAND);
170: } /* end of command line args */
171:
1.5 ! millert 172: [^\\:, \t\n]+ {
1.1 millert 173: LEXTRACE("ARG ");
174: fill_args(yytext, yyleng, sawspace);
175: sawspace = FALSE;
1.4 millert 176: } /* a command line arg */
177: }
1.1 millert 178:
1.4 millert 179: <INITIAL>^Defaults[:@]? {
180: BEGIN GOTDEFS;
181: switch (yytext[8]) {
182: case ':':
183: LEXTRACE("DEFAULTS_USER ");
184: return(DEFAULTS_USER);
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:
225: \+{WORD} {
226: /* netgroup */
227: fill(yytext, yyleng);
228: LEXTRACE("NETGROUP ");
229: return(NETGROUP);
230: }
231:
232: \%{WORD} {
233: /* UN*X group */
234: fill(yytext, yyleng);
235: LEXTRACE("GROUP ");
236: return(USERGROUP);
237: }
238:
239: {DOTTEDQUAD}(\/{DOTTEDQUAD})? {
240: fill(yytext, yyleng);
241: LEXTRACE("NTWKADDR ");
242: return(NTWKADDR);
243: }
244:
245: {DOTTEDQUAD}\/([12][0-9]*|3[0-2]*) {
246: fill(yytext, yyleng);
247: LEXTRACE("NTWKADDR ");
248: return(NTWKADDR);
249: }
250:
251: <INITIAL>\( {
252: BEGIN GOTRUNAS;
253: LEXTRACE("RUNAS ");
254: return (RUNAS);
255: }
256:
1.4 millert 257: [[:upper:]][[:upper:][:digit:]_]* {
1.1 millert 258: if (strcmp(yytext, "ALL") == 0) {
259: LEXTRACE("ALL ");
260: return(ALL);
261: } else {
262: fill(yytext, yyleng);
263: LEXTRACE("ALIAS ");
264: return(ALIAS);
265: }
266: }
267:
1.4 millert 268: <GOTRUNAS>(#[0-9-]+|{WORD}) {
1.1 millert 269: /* username/uid that user can run command as */
270: fill(yytext, yyleng);
1.4 millert 271: LEXTRACE("WORD(3) ");
1.1 millert 272: return(WORD);
273: }
274:
275: <GOTRUNAS>\) {
276: BEGIN INITIAL;
277: }
278:
1.4 millert 279: \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+ {
1.1 millert 280: /* directories can't have args... */
281: if (yytext[yyleng - 1] == '/') {
282: LEXTRACE("COMMAND ");
283: fill_cmnd(yytext, yyleng);
284: return(COMMAND);
285: } else {
286: BEGIN GOTCMND;
287: LEXTRACE("COMMAND ");
288: fill_cmnd(yytext, yyleng);
289: }
290: } /* a pathname */
291:
1.4 millert 292: <INITIAL,GOTDEFS>{WORD} {
1.1 millert 293: /* a word */
294: fill(yytext, yyleng);
295: LEXTRACE("WORD(4) ");
296: return(WORD);
297: }
298:
1.4 millert 299: , {
300: LEXTRACE(", ");
301: return(',');
302: } /* return ',' */
303:
304: = {
305: LEXTRACE("= ");
306: return('=');
307: } /* return '=' */
308:
309: : {
310: LEXTRACE(": ");
311: return(':');
312: } /* return ':' */
313:
314: <*>!+ {
315: if (yyleng % 2 == 1)
316: return('!'); /* return '!' */
317: }
318:
319: <*>\n {
320: BEGIN INITIAL;
321: ++sudolineno;
322: LEXTRACE("\n");
323: return(COMMENT);
324: } /* return newline */
325:
326: <*>[[:blank:]]+ { /* throw away space/tabs */
327: sawspace = TRUE; /* but remember for fill_args */
328: }
329:
330: <*>\\[[:blank:]]*\n {
331: sawspace = TRUE; /* remember for fill_args */
332: ++sudolineno;
333: LEXTRACE("\n\t");
334: } /* throw away EOL after \ */
335:
336: <INITIAL,STARTDEFS,INDEFS>#.*\n {
337: BEGIN INITIAL;
338: ++sudolineno;
339: LEXTRACE("\n");
340: return(COMMENT);
341: } /* return comments */
342:
343: <*>. {
1.1 millert 344: LEXTRACE("ERROR ");
345: return(ERROR);
346: } /* parse error */
347:
348: %%
349: static void
350: fill(s, len)
351: char *s;
352: int len;
353: {
354: int i, j;
355:
356: yylval.string = (char *) malloc(len + 1);
357: if (yylval.string == NULL)
358: yyerror("unable to allocate memory");
359:
360: /* Copy the string and collapse any escaped characters. */
361: for (i = 0, j = 0; i < len; i++, j++) {
362: if (s[i] == '\\' && i != len - 1)
363: yylval.string[j] = s[++i];
364: else
365: yylval.string[j] = s[i];
366: }
367: yylval.string[j] = '\0';
368: }
369:
370: static void
371: fill_cmnd(s, len)
372: char *s;
373: int len;
374: {
375: arg_len = arg_size = 0;
376:
377: yylval.command.cmnd = (char *) malloc(len + 1);
378: if (yylval.command.cmnd == NULL)
379: yyerror("unable to allocate memory");
380:
1.4 millert 381: /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
1.1 millert 382: (void) strncpy(yylval.command.cmnd, s, len);
383: yylval.command.cmnd[len] = '\0';
384:
385: yylval.command.args = NULL;
386: }
387:
388: static void
389: fill_args(s, len, addspace)
390: char *s;
391: int len;
392: int addspace;
393: {
394: int new_len;
395: char *p;
396:
397: /*
398: * If first arg, malloc() some room, else if we don't
399: * have enough space realloc() some more.
400: */
401: if (yylval.command.args == NULL) {
402: addspace = 0;
403: new_len = len;
404:
405: while (new_len >= (arg_size += COMMANDARGINC))
406: ;
407:
408: yylval.command.args = (char *) malloc(arg_size);
409: if (yylval.command.args == NULL)
410: yyerror("unable to allocate memory");
411: } else {
412: new_len = arg_len + len + addspace;
413:
414: if (new_len >= arg_size) {
415: /* Allocate more space than we need for subsequent args */
416: while (new_len >= (arg_size += COMMANDARGINC))
417: ;
418:
419: if ((p = (char *) realloc(yylval.command.args, arg_size)) == NULL) {
420: free(yylval.command.args);
421: yyerror("unable to allocate memory");
422: } else
423: yylval.command.args = p;
424: }
425: }
426:
427: /* Efficiently append the arg (with a leading space if needed). */
428: p = yylval.command.args + arg_len;
429: if (addspace)
430: *p++ = ' ';
431: (void) strcpy(p, s);
432: arg_len = new_len;
433: }
434:
435: int
436: yywrap()
437: {
438:
439: /* Free space used by the aliases unless called by testsudoers. */
440: if (clearaliases)
441: reset_aliases();
442:
443: return(TRUE);
444: }