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