Imported Upstream version 1.6.9p6
[debian/sudo] / parse.lex
index 6e904626d3d449c7a4ee184a73fde2cd8fefb4bd..1c4bbc79b9a3cf2e657c24e20be8e53b4e1fcd55 100644 (file)
--- a/parse.lex
+++ b/parse.lex
@@ -1,6 +1,7 @@
 %{
 /*
- * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998-2004, 2007
+ *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -22,7 +23,7 @@
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -54,7 +55,7 @@
 #include <sudo.tab.h>
 
 #ifndef lint
-static const char rcsid[] = "$Sudo: parse.lex,v 1.132 2004/05/17 20:51:13 millert Exp $";
+__unused static const char rcsid[] = "$Sudo: parse.lex,v 1.132.2.7 2007/08/25 02:48:01 millert Exp $";
 #endif /* lint */
 
 #undef yywrap          /* guard against a yywrap macro */
@@ -66,12 +67,16 @@ static int sawspace = 0;
 static int arg_len = 0;
 static int arg_size = 0;
 
-static void fill               __P((char *, int));
+static int ipv6_valid          __P((const char *s));
+static void _fill              __P((char *, int, int));
+static void append             __P((char *, int));
 static void fill_cmnd          __P((char *, int));
 static void fill_args          __P((char *, int, int));
 extern void reset_aliases      __P((void));
 extern void yyerror            __P((char *));
 
+#define fill(a, b)             _fill(a, b, 0)
+
 /* realloc() to size + COMMANDARGINC to make room for command args */
 #define COMMANDARGINC  64
 
@@ -82,11 +87,14 @@ extern void yyerror         __P((char *));
 #endif
 %}
 
+HEX16                  [0-9A-Fa-f]{1,4}
 OCTET                  (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5])
-DOTTEDQUAD             {OCTET}(\.{OCTET}){3}
+IPV4ADDR               {OCTET}(\.{OCTET}){3}
+IPV6ADDR               ({HEX16}?:){2,7}{HEX16}?|({HEX16}?:){2,6}:{IPV4ADDR}
+
 HOSTNAME               [[:alnum:]_-]+
 WORD                   ([^#>@!=:,\(\) \t\n\\]|\\[^\n])+
-ENVAR                  ([^#!=, \t\n\\]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
+ENVAR                  ([^#!=, \t\n\\\"]|\\[^\n])([^#=, \t\n\\]|\\[^\n])*
 DEFVAR                 [a-z_]+
 
 /* XXX - convert GOTRUNAS to exclusive state (GOTDEFS cannot be) */
@@ -95,6 +103,7 @@ DEFVAR                       [a-z_]+
 %x     GOTCMND
 %x     STARTDEFS
 %x     INDEFS
+%x     INSTR
 
 %%
 <GOTDEFS>[[:blank:]]+  BEGIN STARTDEFS;
@@ -128,10 +137,10 @@ DEFVAR                    [a-z_]+
                            return('-');
                        }                       /* return '-' */
 
-    \"([^\"]|\\\")+\"  {
-                           LEXTRACE("WORD(1) ");
-                           fill(yytext + 1, yyleng - 2);
-                           return(WORD);
+    \"                 {
+                           LEXTRACE("BEGINSTR ");
+                           yylval.string = NULL;
+                           BEGIN INSTR;
                        }
 
     {ENVAR}            {
@@ -141,6 +150,29 @@ DEFVAR                     [a-z_]+
                        }
 }
 
+<INSTR>{
+    \\\n[[:blank:]]*   {
+                           /* Line continuation char followed by newline. */
+                           ++sudolineno;
+                           LEXTRACE("\n");
+                       }
+
+    \"                 {
+                           LEXTRACE("ENDSTR ");
+                           BEGIN INDEFS;
+                           return(WORD);
+                       }
+
+    ([^\"\n]|\\\")+    {
+                           LEXTRACE("STRBODY ");
+                           /* Push back line continuation char if present */
+                           if (yyleng > 2 && yytext[yyleng - 1] == '\\' &&
+                               isspace((unsigned char)yytext[yyleng - 2]))
+                               yyless(yyleng - 1);
+                           append(yytext, yyleng);
+                       }
+}
+
 <GOTCMND>{
     \\[\*\?\[\]\!]     {
                            /* quoted fnmatch glob char, pass verbatim */
@@ -228,6 +260,16 @@ EXEC[[:blank:]]*:  {
                                return(EXEC);
                        }
 
+SETENV[[:blank:]]*:    {
+                               LEXTRACE("SETENV ");
+                               return(SETENV);
+                       }
+
+NOSETENV[[:blank:]]*:  {
+                               LEXTRACE("NOSETENV ");
+                               return(NOSETENV);
+                       }
+
 \+{WORD}               {
                            /* netgroup */
                            fill(yytext, yyleng);
@@ -242,18 +284,38 @@ EXEC[[:blank:]]*: {
                            return(USERGROUP);
                        }
 
-{DOTTEDQUAD}(\/{DOTTEDQUAD})? {
+{IPV4ADDR}(\/{IPV4ADDR})? {
                            fill(yytext, yyleng);
                            LEXTRACE("NTWKADDR ");
                            return(NTWKADDR);
                        }
 
-{DOTTEDQUAD}\/([12][0-9]*|3[0-2]*) {
+{IPV4ADDR}\/([12][0-9]*|3[0-2]*) {
                            fill(yytext, yyleng);
                            LEXTRACE("NTWKADDR ");
                            return(NTWKADDR);
                        }
 
+{IPV6ADDR}(\/{IPV6ADDR})? {
+                           if (!ipv6_valid(yytext)) {
+                               LEXTRACE("ERROR ");
+                               return(ERROR);
+                           }
+                           fill(yytext, yyleng);
+                           LEXTRACE("NTWKADDR ");
+                           return(NTWKADDR);
+                       }
+
+{IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) {
+                           if (!ipv6_valid(yytext)) {
+                               LEXTRACE("ERROR ");
+                               return(ERROR);
+                           }
+                           fill(yytext, yyleng);
+                           LEXTRACE("NTWKADDR ");
+                           return(NTWKADDR);
+                       }
+
 <INITIAL>\(            {
                                BEGIN GOTRUNAS;
                                LEXTRACE("RUNAS ");
@@ -278,6 +340,13 @@ EXEC[[:blank:]]*:  {
                            return(WORD);
                        }
 
+<GOTRUNAS>#[^0-9-].*\n {
+                           BEGIN INITIAL;
+                           ++sudolineno;
+                           LEXTRACE("\n");
+                           return(COMMENT);
+                       }
+
 <GOTRUNAS>\)           {
                            BEGIN INITIAL;
                        }
@@ -368,26 +437,42 @@ sudoedit          {
 
 %%
 static void
-fill(s, len)
-    char *s;
-    int len;
+_fill(src, len, olen)
+    char *src;
+    int len, olen;
 {
     int i, j;
+    char *dst;
 
-    yylval.string = (char *) malloc(len + 1);
-    if (yylval.string == NULL) {
+    dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1);
+    if (dst == NULL) {
        yyerror("unable to allocate memory");
        return;
     }
+    yylval.string = dst;
 
     /* Copy the string and collapse any escaped characters. */
+    dst += olen;
     for (i = 0, j = 0; i < len; i++, j++) {
-       if (s[i] == '\\' && i != len - 1)
-           yylval.string[j] = s[++i];
+       if (src[i] == '\\' && i != len - 1)
+           dst[j] = src[++i];
        else
-           yylval.string[j] = s[i];
+           dst[j] = src[i];
     }
-    yylval.string[j] = '\0';
+    dst[j] = '\0';
+}
+
+static void
+append(src, len)
+    char *src;
+    int len;
+{
+    int olen = 0;
+
+    if (yylval.string != NULL)
+       olen = strlen(yylval.string);
+
+    _fill(src, len, olen);
 }
 
 static void
@@ -433,8 +518,7 @@ fill_args(s, len, addspace)
            (char *) realloc(yylval.command.args, arg_size) :
            (char *) malloc(arg_size);
        if (p == NULL) {
-           if (yylval.command.args != NULL)
-               free(yylval.command.args);
+           efree(yylval.command.args);
            yyerror("unable to allocate memory");
            return;
        } else
@@ -450,6 +534,29 @@ fill_args(s, len, addspace)
     arg_len = new_len;
 }
 
+/*
+ * Check to make sure an IPv6 address does not contain multiple instances
+ * of the string "::".  Assumes strlen(s) >= 1.
+ * Returns TRUE if address is valid else FALSE.
+ */
+static int
+ipv6_valid(s)
+    const char *s;
+{
+    int nmatch = 0;
+
+    for (; *s != '\0'; s++) {
+       if (s[0] == ':' && s[1] == ':') {
+           if (++nmatch > 1)
+               break;
+       }
+       if (s[0] == '/')
+           nmatch = 0;                 /* reset if we hit netmask */
+    }
+
+    return (nmatch <= 1);
+}
+
 int
 yywrap()
 {