1 %{
2 /*
3  * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
4  *
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.
8  *
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.
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.
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.
23  */
24 
25 #include "config.h"
26 
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <stdio.h>
30 #ifdef STDC_HEADERS
31 # include <stdlib.h>
32 # include <stddef.h>
33 #else
34 # ifdef HAVE_STDLIB_H
35 #  include <stdlib.h>
36 # endif
37 #endif /* STDC_HEADERS */
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 */
45 #ifdef HAVE_UNISTD_H
46 # include <unistd.h>
47 #endif /* HAVE_UNISTD_H */
48 #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
49 # include <malloc.h>
50 #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
51 #include <ctype.h>
52 #include "sudo.h"
53 #include "parse.h"
54 #include <sudo.tab.h>
55 
56 #ifndef lint
57 static const char rcsid[] = "$Sudo: parse.lex,v 1.132 2004/05/17 20:51:13 millert Exp $";
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:]_-]+
88 WORD			([^#>@!=:,\(\) \t\n\\]|\\[^\n])+
89 ENVAR			([^#!=, \t\n\\]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
90 DEFVAR			[a-z_]+
91 
92 /* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */
93 %s	GOTRUNAS
94 %s	GOTDEFS
95 %x	GOTCMND
96 %x	STARTDEFS
97 %x	INDEFS
98 
99 %%
100 <GOTDEFS>[[:blank:]]+	BEGIN STARTDEFS;
101 
102 <STARTDEFS>{DEFVAR}	{
103 			    BEGIN INDEFS;
104 			    LEXTRACE("DEFVAR ");
105 			    fill(yytext, yyleng);
106 			    return(DEFVAR);
107 			}
108 
109 <INDEFS>{
110     ,			{
111 			    BEGIN STARTDEFS;
112 			    LEXTRACE(", ");
113 			    return(',');
114 			}			/* return ',' */
115 
116     =			{
117 			    LEXTRACE("= ");
118 			    return('=');
119 			}			/* return '=' */
120 
121     \+=			{
122 			    LEXTRACE("+= ");
123 			    return('+');
124 			}			/* return '+' */
125 
126     -=			{
127 			    LEXTRACE("-= ");
128 			    return('-');
129 			}			/* return '-' */
130 
131     \"([^\"]|\\\")+\"	{
132 			    LEXTRACE("WORD(1) ");
133 			    fill(yytext + 1, yyleng - 2);
134 			    return(WORD);
135 			}
136 
137     {ENVAR}		{
138 			    LEXTRACE("WORD(2) ");
139 			    fill(yytext, yyleng);
140 			    return(WORD);
141 			}
142 }
143 
144 <GOTCMND>{
145     \\[\*\?\[\]\!]	{
146 			    /* quoted fnmatch glob char, pass verbatim */
147 			    LEXTRACE("QUOTEDCHAR ");
148 			    fill_args(yytext, 2, sawspace);
149 			    sawspace = FALSE;
150 			}
151 
152     \\[:\\,= \t#]	{
153 			    /* quoted sudoers special char, strip backslash */
154 			    LEXTRACE("QUOTEDCHAR ");
155 			    fill_args(yytext + 1, 1, sawspace);
156 			    sawspace = FALSE;
157 			}
158 
159     [#:\,=\n]		{
160 			    BEGIN INITIAL;
161 			    unput(*yytext);
162 			    return(COMMAND);
163 			}			/* end of command line args */
164 
165     [^\\:, \t\n]+ 	{
166 			    LEXTRACE("ARG ");
167 			    fill_args(yytext, yyleng, sawspace);
168 			    sawspace = FALSE;
169 			}			/* a command line arg */
170 }
171 
172 <INITIAL>^Defaults[:@>]? {
173 			    BEGIN GOTDEFS;
174 			    switch (yytext[8]) {
175 				case ':':
176 				    LEXTRACE("DEFAULTS_USER ");
177 				    return(DEFAULTS_USER);
178 				case '>':
179 				    LEXTRACE("DEFAULTS_RUNAS ");
180 				    return(DEFAULTS_RUNAS);
181 				case '@':
182 				    LEXTRACE("DEFAULTS_HOST ");
183 				    return(DEFAULTS_HOST);
184 				default:
185 				    LEXTRACE("DEFAULTS ");
186 				    return(DEFAULTS);
187 			    }
188 			}
189 
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 			    }
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 
221 NOEXEC[[:blank:]]*:	{
222 			    	LEXTRACE("NOEXEC ");
223 			    	return(NOEXEC);
224 			}
225 
226 EXEC[[:blank:]]*:	{
227 			    	LEXTRACE("EXEC ");
228 			    	return(EXEC);
229 			}
230 
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 
263 [[:upper:]][[:upper:][:digit:]_]* {
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 
274 <GOTRUNAS>(#[0-9-]+|{WORD}) {
275 			    /* username/uid that user can run command as */
276 			    fill(yytext, yyleng);
277 			    LEXTRACE("WORD(3) ");
278 			    return(WORD);
279 			}
280 
281 <GOTRUNAS>\)		{
282 			    BEGIN INITIAL;
283 			}
284 
285 sudoedit		{
286 			    BEGIN GOTCMND;
287 			    LEXTRACE("COMMAND ");
288 			    fill_cmnd(yytext, yyleng);
289 			}			/* sudo -e */
290 
291 \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+	{
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 
304 <INITIAL,GOTDEFS>{WORD} {
305 			    /* a word */
306 			    fill(yytext, yyleng);
307 			    LEXTRACE("WORD(4) ");
308 			    return(WORD);
309 			}
310 
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 <*>.			{
356 			    LEXTRACE("ERROR ");
357 			    return(ERROR);
358 			}	/* parse error */
359 
360 <*><<EOF>>		{
361 			    if (YY_START != INITIAL) {
362 			    	BEGIN INITIAL;
363 				LEXTRACE("ERROR ");
364 				return(ERROR);
365 			    }
366 			    yyterminate();
367 			}
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);
378     if (yylval.string == NULL) {
379 	yyerror("unable to allocate memory");
380 	return;
381     }
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 
400     yylval.command.cmnd = (char *) malloc(++len);
401     if (yylval.command.cmnd == NULL) {
402 	yyerror("unable to allocate memory");
403 	return;
404     }
405 
406     /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
407     (void) strlcpy(yylval.command.cmnd, s, len);
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;
424     } else
425 	new_len = arg_len + len + addspace;
426 
427     if (new_len >= arg_size) {
428 	/* Allocate more space than we need for subsequent args */
429 	while (new_len >= (arg_size += COMMANDARGINC))
430 	    ;
431 
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);
438 	    yyerror("unable to allocate memory");
439 	    return;
440 	} else
441 	    yylval.command.args = p;
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++ = ' ';
448     if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len)
449 	yyerror("fill_args: buffer overflow");	/* paranoia */
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 }
463