From 11b1f78ac67154562cb30cbdd164ae54e7e66fd6 Mon Sep 17 00:00:00 2001 From: krw Date: Mon, 18 May 2015 17:51:21 +0000 Subject: [PATCH] Tweak parsing so that hostnames starting with 0-9 are accepted. Reported long ago by matthieu@. Also Jacob Berkman via the lists. Tests and suggestions from Jacob and Matthieu. --- sbin/dhclient/clparse.c | 4 +-- sbin/dhclient/conflex.c | 64 ++++++++++++++------------------------- sbin/dhclient/parse.c | 3 +- usr.sbin/dhcpd/conflex.c | 64 ++++++++++++++------------------------- usr.sbin/dhcpd/confpars.c | 57 +++++++++++++++++++--------------- usr.sbin/dhcpd/parse.c | 21 +++++++------ 6 files changed, 93 insertions(+), 120 deletions(-) diff --git a/sbin/dhclient/clparse.c b/sbin/dhclient/clparse.c index f0bd69ac23e..ae33a75970f 100644 --- a/sbin/dhclient/clparse.c +++ b/sbin/dhclient/clparse.c @@ -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)) { diff --git a/sbin/dhclient/conflex.c b/sbin/dhclient/conflex.c index f1e30909d32..427b4a8c7e5 100644 --- a/sbin/dhclient/conflex.c +++ b/sbin/dhclient/conflex.c @@ -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 { diff --git a/sbin/dhclient/parse.c b/sbin/dhclient/parse.c index bd71cccbd1b..f53e62f1e39 100644 --- a/sbin/dhclient/parse.c +++ b/sbin/dhclient/parse.c @@ -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); diff --git a/usr.sbin/dhcpd/conflex.c b/usr.sbin/dhcpd/conflex.c index 5f31921190b..ee1611d52e0 100644 --- a/usr.sbin/dhcpd/conflex.c +++ b/usr.sbin/dhcpd/conflex.c @@ -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 { diff --git a/usr.sbin/dhcpd/confpars.c b/usr.sbin/dhcpd/confpars.c index 654b7a5d905..8b79d263a80 100644 --- a/usr.sbin/dhcpd/confpars.c +++ b/usr.sbin/dhcpd/confpars.c @@ -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); diff --git a/usr.sbin/dhcpd/parse.c b/usr.sbin/dhcpd/parse.c index c7056a58326..12c2d184e60 100644 --- a/usr.sbin/dhcpd/parse.c +++ b/usr.sbin/dhcpd/parse.c @@ -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 + #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); -- 2.20.1