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