Imported Upstream version 1.6.8p12
[debian/sudo] / parse.lex
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 }