Annotation of src/usr.bin/sudo/parse.lex, Revision 1.11
1.1 millert 1: %{
2: /*
1.11 ! millert 3: * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 4: *
1.11 ! millert 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
1.1 millert 8: *
1.11 ! millert 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 millert 16: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
17: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.10 millert 19: *
20: * Sponsored in part by the Defense Advanced Research Projects
21: * Agency (DARPA) and Air Force Research Laboratory, Air Force
22: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
1.1 millert 23: */
24:
25: #include "config.h"
26:
1.4 millert 27: #include <sys/types.h>
28: #include <sys/param.h>
29: #include <stdio.h>
1.1 millert 30: #ifdef STDC_HEADERS
1.4 millert 31: # include <stdlib.h>
32: # include <stddef.h>
33: #else
34: # ifdef HAVE_STDLIB_H
35: # include <stdlib.h>
36: # endif
1.1 millert 37: #endif /* STDC_HEADERS */
1.4 millert 38: #ifdef HAVE_STRING_H
39: # include <string.h>
40: #else
41: # ifdef HAVE_STRINGS_H
42: # include <strings.h>
43: # endif
44: #endif /* HAVE_STRING_H */
1.1 millert 45: #ifdef HAVE_UNISTD_H
1.4 millert 46: # include <unistd.h>
1.1 millert 47: #endif /* HAVE_UNISTD_H */
48: #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
1.4 millert 49: # include <malloc.h>
1.1 millert 50: #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
51: #include <ctype.h>
52: #include "sudo.h"
53: #include "parse.h"
1.4 millert 54: #include <sudo.tab.h>
1.1 millert 55:
56: #ifndef lint
1.11 ! millert 57: static const char rcsid[] = "$Sudo: parse.lex,v 1.132 2004/05/17 20:51:13 millert Exp $";
1.1 millert 58: #endif /* lint */
59:
60: #undef yywrap /* guard against a yywrap macro */
61:
62: extern YYSTYPE yylval;
63: extern int clearaliases;
64: int sudolineno = 1;
65: static int sawspace = 0;
66: static int arg_len = 0;
67: static int arg_size = 0;
68:
69: static void fill __P((char *, int));
70: static void fill_cmnd __P((char *, int));
71: static void fill_args __P((char *, int, int));
72: extern void reset_aliases __P((void));
73: extern void yyerror __P((char *));
74:
75: /* realloc() to size + COMMANDARGINC to make room for command args */
76: #define COMMANDARGINC 64
77:
78: #ifdef TRACELEXER
79: #define LEXTRACE(msg) fputs(msg, stderr)
80: #else
81: #define LEXTRACE(msg)
82: #endif
83: %}
84:
85: OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
86: DOTTEDQUAD {OCTET}(\.{OCTET}){3}
87: HOSTNAME [[:alnum:]_-]+
1.9 millert 88: WORD ([^#>@!=:,\(\) \t\n\\]|\\[^\n])+
1.4 millert 89: ENVAR ([^#!=, \t\n\\]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
90: DEFVAR [a-z_]+
1.1 millert 91:
1.4 millert 92: /* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */
1.1 millert 93: %s GOTRUNAS
94: %s GOTDEFS
1.4 millert 95: %x GOTCMND
96: %x STARTDEFS
97: %x INDEFS
1.1 millert 98:
99: %%
1.4 millert 100: <GOTDEFS>[[:blank:]]+ BEGIN STARTDEFS;
101:
102: <STARTDEFS>{DEFVAR} {
103: BEGIN INDEFS;
104: LEXTRACE("DEFVAR ");
105: fill(yytext, yyleng);
106: return(DEFVAR);
1.1 millert 107: }
108:
1.4 millert 109: <INDEFS>{
110: , {
111: BEGIN STARTDEFS;
112: LEXTRACE(", ");
113: return(',');
114: } /* return ',' */
115:
116: = {
117: LEXTRACE("= ");
118: return('=');
119: } /* return '=' */
1.1 millert 120:
1.4 millert 121: \+= {
122: LEXTRACE("+= ");
123: return('+');
124: } /* return '+' */
125:
126: -= {
127: LEXTRACE("-= ");
128: return('-');
129: } /* return '-' */
1.1 millert 130:
1.4 millert 131: \"([^\"]|\\\")+\" {
1.1 millert 132: LEXTRACE("WORD(1) ");
133: fill(yytext + 1, yyleng - 2);
134: return(WORD);
135: }
136:
1.4 millert 137: {ENVAR} {
138: LEXTRACE("WORD(2) ");
139: fill(yytext, yyleng);
140: return(WORD);
141: }
142: }
143:
144: <GOTCMND>{
1.11 ! millert 145: \\[\*\?\[\]\!] {
! 146: /* quoted fnmatch glob char, pass verbatim */
! 147: LEXTRACE("QUOTEDCHAR ");
! 148: fill_args(yytext, 2, sawspace);
! 149: sawspace = FALSE;
! 150: }
! 151:
1.5 millert 152: \\[:\\,= \t#] {
1.11 ! millert 153: /* quoted sudoers special char, strip backslash */
1.4 millert 154: LEXTRACE("QUOTEDCHAR ");
155: fill_args(yytext + 1, 1, sawspace);
156: sawspace = FALSE;
1.1 millert 157: }
158:
1.4 millert 159: [#:\,=\n] {
1.1 millert 160: BEGIN INITIAL;
161: unput(*yytext);
162: return(COMMAND);
163: } /* end of command line args */
164:
1.5 millert 165: [^\\:, \t\n]+ {
1.1 millert 166: LEXTRACE("ARG ");
167: fill_args(yytext, yyleng, sawspace);
168: sawspace = FALSE;
1.4 millert 169: } /* a command line arg */
170: }
1.1 millert 171:
1.9 millert 172: <INITIAL>^Defaults[:@>]? {
1.4 millert 173: BEGIN GOTDEFS;
174: switch (yytext[8]) {
175: case ':':
176: LEXTRACE("DEFAULTS_USER ");
177: return(DEFAULTS_USER);
1.9 millert 178: case '>':
179: LEXTRACE("DEFAULTS_RUNAS ");
180: return(DEFAULTS_RUNAS);
1.4 millert 181: case '@':
182: LEXTRACE("DEFAULTS_HOST ");
183: return(DEFAULTS_HOST);
184: default:
185: LEXTRACE("DEFAULTS ");
186: return(DEFAULTS);
187: }
188: }
1.1 millert 189:
1.4 millert 190: <INITIAL>^(Host|Cmnd|User|Runas)_Alias {
191: fill(yytext, yyleng);
192: switch (*yytext) {
193: case 'H':
194: LEXTRACE("HOSTALIAS ");
195: return(HOSTALIAS);
196: case 'C':
197: LEXTRACE("CMNDALIAS ");
198: return(CMNDALIAS);
199: case 'U':
200: LEXTRACE("USERALIAS ");
201: return(USERALIAS);
202: case 'R':
203: LEXTRACE("RUNASALIAS ");
204: BEGIN GOTRUNAS;
205: return(RUNASALIAS);
206: }
1.1 millert 207: }
208:
209: NOPASSWD[[:blank:]]*: {
210: /* cmnd does not require passwd for this user */
211: LEXTRACE("NOPASSWD ");
212: return(NOPASSWD);
213: }
214:
215: PASSWD[[:blank:]]*: {
216: /* cmnd requires passwd for this user */
217: LEXTRACE("PASSWD ");
218: return(PASSWD);
219: }
220:
1.11 ! millert 221: NOEXEC[[:blank:]]*: {
! 222: LEXTRACE("NOEXEC ");
! 223: return(NOEXEC);
! 224: }
! 225:
! 226: EXEC[[:blank:]]*: {
! 227: LEXTRACE("EXEC ");
! 228: return(EXEC);
! 229: }
! 230:
1.1 millert 231: \+{WORD} {
232: /* netgroup */
233: fill(yytext, yyleng);
234: LEXTRACE("NETGROUP ");
235: return(NETGROUP);
236: }
237:
238: \%{WORD} {
239: /* UN*X group */
240: fill(yytext, yyleng);
241: LEXTRACE("GROUP ");
242: return(USERGROUP);
243: }
244:
245: {DOTTEDQUAD}(\/{DOTTEDQUAD})? {
246: fill(yytext, yyleng);
247: LEXTRACE("NTWKADDR ");
248: return(NTWKADDR);
249: }
250:
251: {DOTTEDQUAD}\/([12][0-9]*|3[0-2]*) {
252: fill(yytext, yyleng);
253: LEXTRACE("NTWKADDR ");
254: return(NTWKADDR);
255: }
256:
257: <INITIAL>\( {
258: BEGIN GOTRUNAS;
259: LEXTRACE("RUNAS ");
260: return (RUNAS);
261: }
262:
1.4 millert 263: [[:upper:]][[:upper:][:digit:]_]* {
1.1 millert 264: if (strcmp(yytext, "ALL") == 0) {
265: LEXTRACE("ALL ");
266: return(ALL);
267: } else {
268: fill(yytext, yyleng);
269: LEXTRACE("ALIAS ");
270: return(ALIAS);
271: }
272: }
273:
1.4 millert 274: <GOTRUNAS>(#[0-9-]+|{WORD}) {
1.1 millert 275: /* username/uid that user can run command as */
276: fill(yytext, yyleng);
1.4 millert 277: LEXTRACE("WORD(3) ");
1.1 millert 278: return(WORD);
279: }
280:
281: <GOTRUNAS>\) {
282: BEGIN INITIAL;
283: }
1.11 ! millert 284:
! 285: sudoedit {
! 286: BEGIN GOTCMND;
! 287: LEXTRACE("COMMAND ");
! 288: fill_cmnd(yytext, yyleng);
! 289: } /* sudo -e */
1.1 millert 290:
1.4 millert 291: \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+ {
1.1 millert 292: /* directories can't have args... */
293: if (yytext[yyleng - 1] == '/') {
294: LEXTRACE("COMMAND ");
295: fill_cmnd(yytext, yyleng);
296: return(COMMAND);
297: } else {
298: BEGIN GOTCMND;
299: LEXTRACE("COMMAND ");
300: fill_cmnd(yytext, yyleng);
301: }
302: } /* a pathname */
303:
1.4 millert 304: <INITIAL,GOTDEFS>{WORD} {
1.1 millert 305: /* a word */
306: fill(yytext, yyleng);
307: LEXTRACE("WORD(4) ");
308: return(WORD);
309: }
310:
1.4 millert 311: , {
312: LEXTRACE(", ");
313: return(',');
314: } /* return ',' */
315:
316: = {
317: LEXTRACE("= ");
318: return('=');
319: } /* return '=' */
320:
321: : {
322: LEXTRACE(": ");
323: return(':');
324: } /* return ':' */
325:
326: <*>!+ {
327: if (yyleng % 2 == 1)
328: return('!'); /* return '!' */
329: }
330:
331: <*>\n {
332: BEGIN INITIAL;
333: ++sudolineno;
334: LEXTRACE("\n");
335: return(COMMENT);
336: } /* return newline */
337:
338: <*>[[:blank:]]+ { /* throw away space/tabs */
339: sawspace = TRUE; /* but remember for fill_args */
340: }
341:
342: <*>\\[[:blank:]]*\n {
343: sawspace = TRUE; /* remember for fill_args */
344: ++sudolineno;
345: LEXTRACE("\n\t");
346: } /* throw away EOL after \ */
347:
348: <INITIAL,STARTDEFS,INDEFS>#.*\n {
349: BEGIN INITIAL;
350: ++sudolineno;
351: LEXTRACE("\n");
352: return(COMMENT);
353: } /* return comments */
354:
355: <*>. {
1.1 millert 356: LEXTRACE("ERROR ");
357: return(ERROR);
358: } /* parse error */
1.8 millert 359:
360: <*><<EOF>> {
361: if (YY_START != INITIAL) {
362: BEGIN INITIAL;
363: LEXTRACE("ERROR ");
364: return(ERROR);
365: }
366: yyterminate();
367: }
1.1 millert 368:
369: %%
370: static void
371: fill(s, len)
372: char *s;
373: int len;
374: {
375: int i, j;
376:
377: yylval.string = (char *) malloc(len + 1);
1.9 millert 378: if (yylval.string == NULL) {
1.1 millert 379: yyerror("unable to allocate memory");
1.9 millert 380: return;
381: }
1.1 millert 382:
383: /* Copy the string and collapse any escaped characters. */
384: for (i = 0, j = 0; i < len; i++, j++) {
385: if (s[i] == '\\' && i != len - 1)
386: yylval.string[j] = s[++i];
387: else
388: yylval.string[j] = s[i];
389: }
390: yylval.string[j] = '\0';
391: }
392:
393: static void
394: fill_cmnd(s, len)
395: char *s;
396: int len;
397: {
398: arg_len = arg_size = 0;
399:
1.9 millert 400: yylval.command.cmnd = (char *) malloc(++len);
401: if (yylval.command.cmnd == NULL) {
1.1 millert 402: yyerror("unable to allocate memory");
1.9 millert 403: return;
404: }
1.1 millert 405:
1.4 millert 406: /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
1.9 millert 407: (void) strlcpy(yylval.command.cmnd, s, len);
1.1 millert 408:
409: yylval.command.args = NULL;
410: }
411:
412: static void
413: fill_args(s, len, addspace)
414: char *s;
415: int len;
416: int addspace;
417: {
418: int new_len;
419: char *p;
420:
421: if (yylval.command.args == NULL) {
422: addspace = 0;
423: new_len = len;
1.9 millert 424: } else
425: new_len = arg_len + len + addspace;
1.1 millert 426:
1.9 millert 427: if (new_len >= arg_size) {
428: /* Allocate more space than we need for subsequent args */
1.1 millert 429: while (new_len >= (arg_size += COMMANDARGINC))
430: ;
431:
1.9 millert 432: p = yylval.command.args ?
433: (char *) realloc(yylval.command.args, arg_size) :
434: (char *) malloc(arg_size);
435: if (p == NULL) {
436: if (yylval.command.args != NULL)
437: free(yylval.command.args);
1.1 millert 438: yyerror("unable to allocate memory");
1.9 millert 439: return;
440: } else
441: yylval.command.args = p;
1.1 millert 442: }
443:
444: /* Efficiently append the arg (with a leading space if needed). */
445: p = yylval.command.args + arg_len;
446: if (addspace)
447: *p++ = ' ';
1.9 millert 448: if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len)
449: yyerror("fill_args: buffer overflow"); /* paranoia */
1.1 millert 450: arg_len = new_len;
451: }
452:
453: int
454: yywrap()
455: {
456:
457: /* Free space used by the aliases unless called by testsudoers. */
458: if (clearaliases)
459: reset_aliases();
460:
461: return(TRUE);
462: }