Imported Debian patch 1.6.9p11-1
[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.7 2007/08/25 02:48:01 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                             } else {
330                                 fill(yytext, yyleng);
331                                 LEXTRACE("ALIAS ");
332                                 return(ALIAS);
333                             }
334                         }
335
336 <GOTRUNAS>(#[0-9-]+|{WORD}) {
337                             /* username/uid that user can run command as */
338                             fill(yytext, yyleng);
339                             LEXTRACE("WORD(3) ");
340                             return(WORD);
341                         }
342
343 <GOTRUNAS>#[^0-9-].*\n  {
344                             BEGIN INITIAL;
345                             ++sudolineno;
346                             LEXTRACE("\n");
347                             return(COMMENT);
348                         }
349
350 <GOTRUNAS>\)            {
351                             BEGIN INITIAL;
352                         }
353
354 sudoedit                {
355                             BEGIN GOTCMND;
356                             LEXTRACE("COMMAND ");
357                             fill_cmnd(yytext, yyleng);
358                         }                       /* sudo -e */
359
360 \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+       {
361                             /* directories can't have args... */
362                             if (yytext[yyleng - 1] == '/') {
363                                 LEXTRACE("COMMAND ");
364                                 fill_cmnd(yytext, yyleng);
365                                 return(COMMAND);
366                             } else {
367                                 BEGIN GOTCMND;
368                                 LEXTRACE("COMMAND ");
369                                 fill_cmnd(yytext, yyleng);
370                             }
371                         }                       /* a pathname */
372
373 <INITIAL,GOTDEFS>{WORD} {
374                             /* a word */
375                             fill(yytext, yyleng);
376                             LEXTRACE("WORD(4) ");
377                             return(WORD);
378                         }
379
380 ,                       {
381                             LEXTRACE(", ");
382                             return(',');
383                         }                       /* return ',' */
384
385 =                       {
386                             LEXTRACE("= ");
387                             return('=');
388                         }                       /* return '=' */
389
390 :                       {
391                             LEXTRACE(": ");
392                             return(':');
393                         }                       /* return ':' */
394
395 <*>!+                   {
396                             if (yyleng % 2 == 1)
397                                 return('!');    /* return '!' */
398                         }
399
400 <*>\n                   {
401                             BEGIN INITIAL;
402                             ++sudolineno;
403                             LEXTRACE("\n");
404                             return(COMMENT);
405                         }                       /* return newline */
406
407 <*>[[:blank:]]+         {                       /* throw away space/tabs */
408                             sawspace = TRUE;    /* but remember for fill_args */
409                         }
410
411 <*>\\[[:blank:]]*\n     {
412                             sawspace = TRUE;    /* remember for fill_args */
413                             ++sudolineno;
414                             LEXTRACE("\n\t");
415                         }                       /* throw away EOL after \ */
416
417 <INITIAL,STARTDEFS,INDEFS>#.*\n {
418                             BEGIN INITIAL;
419                             ++sudolineno;
420                             LEXTRACE("\n");
421                             return(COMMENT);
422                         }                       /* return comments */
423
424 <*>.                    {
425                             LEXTRACE("ERROR ");
426                             return(ERROR);
427                         }       /* parse error */
428
429 <*><<EOF>>              {
430                             if (YY_START != INITIAL) {
431                                 BEGIN INITIAL;
432                                 LEXTRACE("ERROR ");
433                                 return(ERROR);
434                             }
435                             yyterminate();
436                         }
437
438 %%
439 static void
440 _fill(src, len, olen)
441     char *src;
442     int len, olen;
443 {
444     int i, j;
445     char *dst;
446
447     dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1);
448     if (dst == NULL) {
449         yyerror("unable to allocate memory");
450         return;
451     }
452     yylval.string = dst;
453
454     /* Copy the string and collapse any escaped characters. */
455     dst += olen;
456     for (i = 0, j = 0; i < len; i++, j++) {
457         if (src[i] == '\\' && i != len - 1)
458             dst[j] = src[++i];
459         else
460             dst[j] = src[i];
461     }
462     dst[j] = '\0';
463 }
464
465 static void
466 append(src, len)
467     char *src;
468     int len;
469 {
470     int olen = 0;
471
472     if (yylval.string != NULL)
473         olen = strlen(yylval.string);
474
475     _fill(src, len, olen);
476 }
477
478 static void
479 fill_cmnd(s, len)
480     char *s;
481     int len;
482 {
483     arg_len = arg_size = 0;
484
485     yylval.command.cmnd = (char *) malloc(++len);
486     if (yylval.command.cmnd == NULL) {
487         yyerror("unable to allocate memory");
488         return;
489     }
490
491     /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
492     (void) strlcpy(yylval.command.cmnd, s, len);
493
494     yylval.command.args = NULL;
495 }
496
497 static void
498 fill_args(s, len, addspace)
499     char *s;
500     int len;
501     int addspace;
502 {
503     int new_len;
504     char *p;
505
506     if (yylval.command.args == NULL) {
507         addspace = 0;
508         new_len = len;
509     } else
510         new_len = arg_len + len + addspace;
511
512     if (new_len >= arg_size) {
513         /* Allocate more space than we need for subsequent args */
514         while (new_len >= (arg_size += COMMANDARGINC))
515             ;
516
517         p = yylval.command.args ?
518             (char *) realloc(yylval.command.args, arg_size) :
519             (char *) malloc(arg_size);
520         if (p == NULL) {
521             efree(yylval.command.args);
522             yyerror("unable to allocate memory");
523             return;
524         } else
525             yylval.command.args = p;
526     }
527
528     /* Efficiently append the arg (with a leading space if needed). */
529     p = yylval.command.args + arg_len;
530     if (addspace)
531         *p++ = ' ';
532     if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len)
533         yyerror("fill_args: buffer overflow");  /* paranoia */
534     arg_len = new_len;
535 }
536
537 /*
538  * Check to make sure an IPv6 address does not contain multiple instances
539  * of the string "::".  Assumes strlen(s) >= 1.
540  * Returns TRUE if address is valid else FALSE.
541  */
542 static int
543 ipv6_valid(s)
544     const char *s;
545 {
546     int nmatch = 0;
547
548     for (; *s != '\0'; s++) {
549         if (s[0] == ':' && s[1] == ':') {
550             if (++nmatch > 1)
551                 break;
552         }
553         if (s[0] == '/')
554             nmatch = 0;                 /* reset if we hit netmask */
555     }
556
557     return (nmatch <= 1);
558 }
559
560 int
561 yywrap()
562 {
563
564     /* Free space used by the aliases unless called by testsudoers. */
565     if (clearaliases)
566         reset_aliases();
567
568     return(TRUE);
569 }