Tweak parsing so that hostnames starting with 0-9 are accepted.
authorkrw <krw@openbsd.org>
Mon, 18 May 2015 17:51:21 +0000 (17:51 +0000)
committerkrw <krw@openbsd.org>
Mon, 18 May 2015 17:51:21 +0000 (17:51 +0000)
Reported long ago by matthieu@. Also Jacob Berkman via the lists.

Tests and suggestions from Jacob and Matthieu.

sbin/dhclient/clparse.c
sbin/dhclient/conflex.c
sbin/dhclient/parse.c
usr.sbin/dhcpd/conflex.c
usr.sbin/dhcpd/confpars.c
usr.sbin/dhcpd/parse.c

index f0bd69a..ae33a75 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: clparse.c,v 1.91 2015/02/01 18:43:39 krw Exp $        */
+/*     $OpenBSD: clparse.c,v 1.92 2015/05/18 17:51:21 krw Exp $        */
 
 /* Parser for dhclient config and lease files. */
 
@@ -286,7 +286,7 @@ parse_X(FILE *cfile, u_int8_t *buf, int max)
        int      len;
 
        token = peek_token(&val, cfile);
-       if (token == TOK_NUMBER_OR_NAME || token == TOK_NUMBER) {
+       if (token == TOK_NUMBER_OR_NAME) {
                len = 0;
                for (token = ':'; token == ':';
                     token = next_token(NULL, cfile)) {
index f1e3090..427b4a8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conflex.c,v 1.31 2015/05/02 14:29:32 krw Exp $        */
+/*     $OpenBSD: conflex.c,v 1.32 2015/05/18 17:51:21 krw Exp $        */
 
 /* Lexical scanner for dhclient config file. */
 
@@ -68,7 +68,6 @@ static int get_char(FILE *);
 static int get_token(FILE *);
 static void skip_to_eol(FILE *);
 static int read_string(FILE *);
-static int read_number(int, FILE *);
 static int read_num_or_name(int, FILE *);
 static int intern(char *, int);
 
@@ -152,11 +151,7 @@ get_token(FILE *cfile)
                if (c == '"') {
                        ttok = read_string(cfile);
                        break;
-               }
-               if ((isascii(c) && isdigit(c)) || c == '-') {
-                       ttok = read_number(c, cfile);
-                       break;
-               } else if (isascii(c) && isalpha(c)) {
+               } else if (c == '-' || (isascii(c) && isalnum(c))) {
                        ttok = read_num_or_name(c, cfile);
                        break;
                } else {
@@ -268,59 +263,46 @@ read_string(FILE *cfile)
        return (TOK_STRING);
 }
 
-static int
-read_number(int c, FILE *cfile)
-{
-       int     seenx = 0, i = 0, token = TOK_NUMBER;
-
-       tokbuf[i++] = c;
-       for (; i < sizeof(tokbuf); i++) {
-               c = get_char(cfile);
-               if (!seenx && c == 'x')
-                       seenx = 1;
-               else if (!isascii(c) || !isxdigit(c)) {
-                       ungetc(c, cfile);
-                       ugflag = 1;
-                       break;
-               }
-               tokbuf[i] = c;
-       }
-       if (i == sizeof(tokbuf)) {
-               parse_warn("numeric token larger than internal buffer");
-               i--;
-       }
-       tokbuf[i] = 0;
-       tval = tokbuf;
-
-       return (token);
-}
-
 static int
 read_num_or_name(int c, FILE *cfile)
 {
-       int     i = 0;
-       int     rv = TOK_NUMBER_OR_NAME;
+       int i, rv, xdigits;
+
+       xdigits = isxdigit(c) ? 1 : 0;
 
-       tokbuf[i++] = c;
-       for (; i < sizeof(tokbuf); i++) {
+       tokbuf[0] = c;
+       for (i = 1; i < sizeof(tokbuf); i++) {
                c = get_char(cfile);
                if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
                        ungetc(c, cfile);
                        ugflag = 1;
                        break;
                }
-               if (!isxdigit(c))
-                       rv = TOK_NAME;
+               if (isxdigit(c))
+                       xdigits++;
                tokbuf[i] = c;
        }
        if (i == sizeof(tokbuf)) {
                parse_warn("token larger than internal buffer");
                i--;
+               c = tokbuf[i];
+               if (isxdigit(c))
+                       xdigits--;
        }
        tokbuf[i] = 0;
        tval = tokbuf;
 
-       return (intern(tval, rv));
+       c = (unsigned int)tokbuf[0];
+
+       if (c == '-')
+               rv = TOK_NUMBER;
+       else
+               rv = intern(tval, TOK_NUMBER_OR_NAME);
+
+       if (rv == TOK_NUMBER_OR_NAME && xdigits != i)
+               rv = TOK_NAME;
+
+       return (rv);
 }
 
 static const struct keywords {
index bd71ccc..f53e62f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parse.c,v 1.38 2014/05/05 18:02:49 krw Exp $  */
+/*     $OpenBSD: parse.c,v 1.39 2015/05/18 17:51:21 krw Exp $  */
 
 /* Common parser code for dhcpd and dhclient. */
 
@@ -351,6 +351,7 @@ parse_date(FILE *cfile)
                switch (token) {
                case TOK_NAME:
                case TOK_NUMBER:
+               case TOK_NUMBER_OR_NAME:
                case '/':
                case ':':
                        token = next_token(&val, cfile);
index 5f31921..ee1611d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conflex.c,v 1.14 2015/05/02 14:29:32 krw Exp $        */
+/*     $OpenBSD: conflex.c,v 1.15 2015/05/18 17:51:21 krw Exp $        */
 
 /* Lexical scanner for dhcpd config file... */
 
@@ -68,7 +68,6 @@ static int get_char(FILE *);
 static int get_token(FILE *);
 static void skip_to_eol(FILE *);
 static int read_string(FILE *);
-static int read_number(int, FILE *);
 static int read_num_or_name(int, FILE *);
 static int intern(char *, int);
 
@@ -136,11 +135,7 @@ get_token(FILE *cfile)
                if (c == '"') {
                        ttok = read_string(cfile);
                        break;
-               }
-               if ((isascii(c) && isdigit(c)) || c == '-') {
-                       ttok = read_number(c, cfile);
-                       break;
-               } else if (isascii(c) && isalpha(c)) {
+               } else if (c == '-' || (isascii(c) && isalnum(c))) {
                        ttok = read_num_or_name(c, cfile);
                        break;
                } else {
@@ -243,59 +238,46 @@ read_string(FILE *cfile)
        return (TOK_STRING);
 }
 
-static int
-read_number(int c, FILE *cfile)
-{
-       int     seenx = 0, i = 0, token = TOK_NUMBER;
-
-       tokbuf[i++] = c;
-       for (; i < sizeof(tokbuf); i++) {
-               c = get_char(cfile);
-               if (!seenx && c == 'x')
-                       seenx = 1;
-               else if (!isascii(c) || !isxdigit(c)) {
-                       ungetc(c, cfile);
-                       ugflag = 1;
-                       break;
-               }
-               tokbuf[i] = c;
-       }
-       if (i == sizeof(tokbuf)) {
-               parse_warn("numeric token larger than internal buffer");
-               i--;
-       }
-       tokbuf[i] = 0;
-       tval = tokbuf;
-
-       return (token);
-}
-
 static int
 read_num_or_name(int c, FILE *cfile)
 {
-       int     i = 0;
-       int     rv = TOK_NUMBER_OR_NAME;
+       int i, rv, xdigits;
+
+       xdigits = isxdigit(c) ? 1 : 0;
 
-       tokbuf[i++] = c;
-       for (; i < sizeof(tokbuf); i++) {
+       tokbuf[0] = c;
+       for (i = 1; i < sizeof(tokbuf); i++) {
                c = get_char(cfile);
                if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
                        ungetc(c, cfile);
                        ugflag = 1;
                        break;
                }
-               if (!isxdigit(c))
-                       rv = TOK_NAME;
+               if (isxdigit(c))
+                       xdigits++;
                tokbuf[i] = c;
        }
        if (i == sizeof(tokbuf)) {
                parse_warn("token larger than internal buffer");
                i--;
+               c = tokbuf[i];
+               if (isxdigit(c))
+                       xdigits--;
        }
        tokbuf[i] = 0;
        tval = tokbuf;
 
-       return (intern(tval, rv));
+       c = (unsigned int)tokbuf[0];
+
+       if (c == '-')
+               rv = TOK_NUMBER;
+       else
+               rv = intern(tval, TOK_NUMBER_OR_NAME);
+
+       if (rv == TOK_NUMBER_OR_NAME && xdigits != i)
+               rv = TOK_NAME;
+
+       return (rv);
 }
 
 static const struct keywords {
index 654b7a5..8b79d26 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: confpars.c,v 1.23 2014/07/09 13:42:24 yasuoka Exp $ */
+/*     $OpenBSD: confpars.c,v 1.24 2015/05/18 17:51:21 krw Exp $ */
 
 /*
  * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
@@ -825,6 +825,7 @@ void parse_group_declaration(cfile, group)
 int
 parse_cidr(FILE *cfile, unsigned char *addr, unsigned char *prefix)
 {
+       const char *errstr;
        char *val;
        int token;
        int len = 4;
@@ -842,12 +843,12 @@ parse_cidr(FILE *cfile, unsigned char *addr, unsigned char *prefix)
                goto nocidr;
        }
 
-       *prefix = 0;
        token = next_token(&val, cfile);
-       if (token == TOK_NUMBER)
-               convert_num(prefix, val, 10, 8);
+       if (token == TOK_NUMBER_OR_NAME)
+               *prefix = strtonum(val, 0, 32, &errstr);
 
-       if (token != TOK_NUMBER || *prefix > 32) {
+       if (token != TOK_NUMBER_OR_NAME || errstr) {
+               *prefix = 0;
                parse_warn("Expecting CIDR prefix length, got '%s'", val);
                goto nocidr;
        }
@@ -879,23 +880,28 @@ struct tree *parse_ip_addr_or_hostname(cfile, uniform)
        struct tree *rv;
        struct hostent *h;
 
+       name = NULL;
+       h = NULL;
+
        token = peek_token(&val, cfile);
        if (is_identifier(token)) {
                name = parse_host_name(cfile);
-               if (!name)
-                       return NULL;
-               h = gethostbyname(name);
-               if (h == NULL) {
-                       parse_warn("%s (%d): could not resolve hostname",
-                           val, token);
-                       return NULL;
+               if (name)
+                       h = gethostbyname(name);
+               if (name && h) {
+                       rv = tree_const(h->h_addr_list[0], h->h_length);
+                       if (!uniform)
+                               rv = tree_limit(rv, 4);
+                       return rv;
                }
-               rv = tree_const(h->h_addr_list[0], h->h_length);
-               if (!uniform)
-                       rv = tree_limit(rv, 4);
-       } else if (token == TOK_NUMBER) {
-               if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
+       }
+
+       if (token == TOK_NUMBER_OR_NAME) {
+               if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
+                       parse_warn("%s (%d): expecting IP address or hostname",
+                                   val, token);
                        return NULL;
+               }
                rv = tree_const(addr, len);
        } else {
                if (token != '{' && token != '}')
@@ -1037,15 +1043,13 @@ void parse_option_param(cfile, group)
                        switch (*fmt) {
                        case 'X':
                                token = peek_token(&val, cfile);
-                               if (token == TOK_NUMBER_OR_NAME ||
-                                   token == TOK_NUMBER) {
+                               if (token == TOK_NUMBER_OR_NAME) {
                                        do {
                                                token = next_token
                                                        (&val, cfile);
-                                               if (token != TOK_NUMBER &&
-                                                   token != TOK_NUMBER_OR_NAME) {
+                                               if (token != TOK_NUMBER_OR_NAME) {
                                                        parse_warn("expecting "
-                                                           "number.");
+                                                           "hex number.");
                                                        if (token != ';')
                                                                skip_to_semi(
                                                                    cfile);
@@ -1096,7 +1100,8 @@ void parse_option_param(cfile, group)
                        case 'L': /* Unsigned 32-bit integer... */
                        case 'l':       /* Signed 32-bit integer... */
                                token = next_token(&val, cfile);
-                               if (token != TOK_NUMBER) {
+                               if (token != TOK_NUMBER && token !=
+                                   TOK_NUMBER_OR_NAME) {
                                        parse_warn("expecting number.");
                                        if (token != ';')
                                                skip_to_semi(cfile);
@@ -1108,7 +1113,8 @@ void parse_option_param(cfile, group)
                        case 's':       /* Signed 16-bit integer. */
                        case 'S':       /* Unsigned 16-bit integer. */
                                token = next_token(&val, cfile);
-                               if (token != TOK_NUMBER) {
+                               if (token != TOK_NUMBER && token !=
+                                   TOK_NUMBER_OR_NAME) {
                                        parse_warn("expecting number.");
                                        if (token != ';')
                                                skip_to_semi(cfile);
@@ -1120,7 +1126,8 @@ void parse_option_param(cfile, group)
                        case 'b':       /* Signed 8-bit integer. */
                        case 'B':       /* Unsigned 8-bit integer. */
                                token = next_token(&val, cfile);
-                               if (token != TOK_NUMBER) {
+                               if (token != TOK_NUMBER && token !=
+                                   TOK_NUMBER_OR_NAME) {
                                        parse_warn("expecting number.");
                                        if (token != ';')
                                                skip_to_semi(cfile);
index c7056a5..12c2d18 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parse.c,v 1.17 2013/12/18 20:37:04 krw Exp $  */
+/*     $OpenBSD: parse.c,v 1.18 2015/05/18 17:51:21 krw Exp $  */
 
 /* Common parser code for dhcpd and dhclient. */
 
@@ -40,6 +40,8 @@
  * Enterprises, see ``http://www.vix.com''.
  */
 
+#include  <stdint.h>
+
 #include "dhcpd.h"
 #include "dhctoken.h"
 
@@ -148,7 +150,7 @@ parse_host_name(FILE *cfile)
        do {
                /* Read a token, which should be an identifier. */
                token = next_token(&val, cfile);
-               if (!is_identifier(token) && token != TOK_NUMBER) {
+               if (!is_identifier(token)) {
                        parse_warn("expecting an identifier in hostname");
                        skip_to_semi(cfile);
                        return (NULL);
@@ -252,19 +254,19 @@ parse_hardware_param(FILE *cfile, struct hardware *hardware)
 void
 parse_lease_time(FILE *cfile, time_t *timep)
 {
+       const char *errstr;
        char *val;
        uint32_t value;
        int token;
 
        token = next_token(&val, cfile);
-       if (token != TOK_NUMBER) {
-               parse_warn("Expecting numeric lease time");
+
+       value = strtonum(val, 0, UINT32_MAX, &errstr);
+       if (errstr) {
+               parse_warn("lease time is %s: %s", errstr, val);
                skip_to_semi(cfile);
                return;
        }
-       convert_num((unsigned char *)&value, val, 10, 32);
-       /* Unswap the number - convert_num returns stuff in NBO. */
-       *timep = ntohl(value);  /* XXX */
 
        parse_semi(cfile);
 }
@@ -314,9 +316,7 @@ parse_numeric_aggregate(FILE *cfile, unsigned char *buf, int *max,
                        parse_warn("unexpected end of file");
                        break;
                }
-               /* Allow NUMBER_OR_NAME if base is 16. */
-               if (token != TOK_NUMBER &&
-                   (base != 16 || token != TOK_NUMBER_OR_NAME)) {
+               if (token != TOK_NUMBER && token != TOK_NUMBER_OR_NAME) {
                        parse_warn("expecting numeric value.");
                        skip_to_semi(cfile);
                        return (NULL);
@@ -484,6 +484,7 @@ parse_date(FILE *cfile)
                switch (token) {
                case TOK_NAME:
                case TOK_NUMBER:
+               case TOK_NUMBER_OR_NAME:
                case '/':
                case ':':
                        token = next_token(&val, cfile);