3 * Copyright (c) 1996, 1998-2004, 2007
4 * Todd C. Miller <Todd.Miller@courtesan.com>
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.
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.
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.
28 #include <sys/types.h>
29 #include <sys/param.h>
38 #endif /* STDC_HEADERS */
42 # ifdef HAVE_STRINGS_H
45 #endif /* HAVE_STRING_H */
48 #endif /* HAVE_UNISTD_H */
49 #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
51 #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
58 __unused static const char rcsid[] = "$Sudo: parse.lex,v 1.132.2.8 2008/02/09 14:44:48 millert Exp $";
61 #undef yywrap /* guard against a yywrap macro */
63 extern YYSTYPE yylval;
64 extern int clearaliases;
66 static int sawspace = 0;
67 static int arg_len = 0;
68 static int arg_size = 0;
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 *));
78 #define fill(a, b) _fill(a, b, 0)
80 /* realloc() to size + COMMANDARGINC to make room for command args */
81 #define COMMANDARGINC 64
84 #define LEXTRACE(msg) fputs(msg, stderr)
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}
95 HOSTNAME [[:alnum:]_-]+
96 WORD ([^#>@!=:,\(\) \t\n\\]|\\[^\n])+
97 ENVAR ([^#!=, \t\n\\\"]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
100 /* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */
109 <GOTDEFS>[[:blank:]]+ BEGIN STARTDEFS;
111 <STARTDEFS>{DEFVAR} {
114 fill(yytext, yyleng);
141 LEXTRACE("BEGINSTR ");
142 yylval.string = NULL;
147 LEXTRACE("WORD(2) ");
148 fill(yytext, yyleng);
155 /* Line continuation char followed by newline. */
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]))
172 append(yytext, yyleng);
178 /* quoted fnmatch glob char, pass verbatim */
179 LEXTRACE("QUOTEDCHAR ");
180 fill_args(yytext, 2, sawspace);
185 /* quoted sudoers special char, strip backslash */
186 LEXTRACE("QUOTEDCHAR ");
187 fill_args(yytext + 1, 1, sawspace);
195 } /* end of command line args */
199 fill_args(yytext, yyleng, sawspace);
201 } /* a command line arg */
204 <INITIAL>^Defaults[:@>]? {
208 LEXTRACE("DEFAULTS_USER ");
209 return(DEFAULTS_USER);
211 LEXTRACE("DEFAULTS_RUNAS ");
212 return(DEFAULTS_RUNAS);
214 LEXTRACE("DEFAULTS_HOST ");
215 return(DEFAULTS_HOST);
217 LEXTRACE("DEFAULTS ");
222 <INITIAL>^(Host|Cmnd|User|Runas)_Alias {
223 fill(yytext, yyleng);
226 LEXTRACE("HOSTALIAS ");
229 LEXTRACE("CMNDALIAS ");
232 LEXTRACE("USERALIAS ");
235 LEXTRACE("RUNASALIAS ");
241 NOPASSWD[[:blank:]]*: {
242 /* cmnd does not require passwd for this user */
243 LEXTRACE("NOPASSWD ");
247 PASSWD[[:blank:]]*: {
248 /* cmnd requires passwd for this user */
253 NOEXEC[[:blank:]]*: {
263 SETENV[[:blank:]]*: {
268 NOSETENV[[:blank:]]*: {
269 LEXTRACE("NOSETENV ");
275 fill(yytext, yyleng);
276 LEXTRACE("NETGROUP ");
282 fill(yytext, yyleng);
287 {IPV4ADDR}(\/{IPV4ADDR})? {
288 fill(yytext, yyleng);
289 LEXTRACE("NTWKADDR ");
293 {IPV4ADDR}\/([12][0-9]*|3[0-2]*) {
294 fill(yytext, yyleng);
295 LEXTRACE("NTWKADDR ");
299 {IPV6ADDR}(\/{IPV6ADDR})? {
300 if (!ipv6_valid(yytext)) {
304 fill(yytext, yyleng);
305 LEXTRACE("NTWKADDR ");
309 {IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
310 if (!ipv6_valid(yytext)) {
314 fill(yytext, yyleng);
315 LEXTRACE("NTWKADDR ");
325 [[:upper:]][[:upper:][:digit:]_]* {
326 if (strcmp(yytext, "ALL") == 0) {
331 /* XXX - restrict type/role to initial state */
332 if (strcmp(yytext, "TYPE") == 0) {
336 if (strcmp(yytext, "ROLE") == 0) {
340 #endif /* HAVE_SELINUX */
341 fill(yytext, yyleng);
346 <GOTRUNAS>(#[0-9-]+|{WORD}) {
347 /* username/uid that user can run command as */
348 fill(yytext, yyleng);
349 LEXTRACE("WORD(3) ");
353 <GOTRUNAS>#[^0-9-].*\n {
366 LEXTRACE("COMMAND ");
367 fill_cmnd(yytext, yyleng);
370 \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+ {
371 /* directories can't have args... */
372 if (yytext[yyleng - 1] == '/') {
373 LEXTRACE("COMMAND ");
374 fill_cmnd(yytext, yyleng);
378 LEXTRACE("COMMAND ");
379 fill_cmnd(yytext, yyleng);
383 <INITIAL,GOTDEFS>{WORD} {
385 fill(yytext, yyleng);
386 LEXTRACE("WORD(4) ");
407 return('!'); /* return '!' */
415 } /* return newline */
417 <*>[[:blank:]]+ { /* throw away space/tabs */
418 sawspace = TRUE; /* but remember for fill_args */
421 <*>\\[[:blank:]]*\n {
422 sawspace = TRUE; /* remember for fill_args */
425 } /* throw away EOL after \ */
427 <INITIAL,STARTDEFS,INDEFS>#.*\n {
432 } /* return comments */
440 if (YY_START != INITIAL) {
450 _fill(src, len, olen)
457 dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1);
459 yyerror("unable to allocate memory");
464 /* Copy the string and collapse any escaped characters. */
466 for (i = 0, j = 0; i < len; i++, j++) {
467 if (src[i] == '\\' && i != len - 1)
482 if (yylval.string != NULL)
483 olen = strlen(yylval.string);
485 _fill(src, len, olen);
493 arg_len = arg_size = 0;
495 yylval.command.cmnd = (char *) malloc(++len);
496 if (yylval.command.cmnd == NULL) {
497 yyerror("unable to allocate memory");
501 /* copy the string and NULL-terminate it (escapes handled by fnmatch) */
502 (void) strlcpy(yylval.command.cmnd, s, len);
504 yylval.command.args = NULL;
508 fill_args(s, len, addspace)
516 if (yylval.command.args == NULL) {
520 new_len = arg_len + len + addspace;
522 if (new_len >= arg_size) {
523 /* Allocate more space than we need for subsequent args */
524 while (new_len >= (arg_size += COMMANDARGINC))
527 p = yylval.command.args ?
528 (char *) realloc(yylval.command.args, arg_size) :
529 (char *) malloc(arg_size);
531 efree(yylval.command.args);
532 yyerror("unable to allocate memory");
535 yylval.command.args = p;
538 /* Efficiently append the arg (with a leading space if needed). */
539 p = yylval.command.args + arg_len;
542 if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len)
543 yyerror("fill_args: buffer overflow"); /* paranoia */
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.
558 for (; *s != '\0'; s++) {
559 if (s[0] == ':' && s[1] == ':') {
564 nmatch = 0; /* reset if we hit netmask */
567 return (nmatch <= 1);
574 /* Free space used by the aliases unless called by testsudoers. */