diff options
author | brooks <brooks@FreeBSD.org> | 2005-08-30 18:20:46 +0000 |
---|---|---|
committer | brooks <brooks@FreeBSD.org> | 2005-08-30 18:20:46 +0000 |
commit | 40d25976f11fbf40e8b37a57763c0e2a223bc034 (patch) | |
tree | 7b4686fbd67a0783431c6a825e4abf47e83b6f34 /sbin | |
parent | 42baca97e54dc0985cc6f2e8c148438572be0394 (diff) | |
download | FreeBSD-src-40d25976f11fbf40e8b37a57763c0e2a223bc034.zip FreeBSD-src-40d25976f11fbf40e8b37a57763c0e2a223bc034.tar.gz |
Introduce a new helper function check_search() derived for res_hnok to
check the domain-name parameter according to the rules for "search"
strings as documented in resolv.conf(5). Specifically, the string must
be no more than 256 bytes long and contain no more than six valid domain
names separated by white space.
The previous unchecked values could result in a mangled resolv.conf
file which could effectively deny access to local sites. This is not
a security issue as rogue dhcp servers could already do this without
sending invalid strings.
Reviewed by: cperciva
MFC After: 3 days
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/dhclient/dhclient.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c index bcf09a7..5a62c3d 100644 --- a/sbin/dhclient/dhclient.c +++ b/sbin/dhclient/dhclient.c @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \ ((c) >= 0x61 && (c) <= 0x7a)) #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) +#define whitechar(c) ((c) == ' ' || (c) == '\t') #define borderchar(c) (alphachar(c) || digitchar(c)) #define middlechar(c) (borderchar(c) || hyphenchar(c)) @@ -116,6 +117,7 @@ void usage(void); int check_option(struct client_lease *l, int option); int ipv4addrs(char * buf); int res_hnok(const char *dn); +int check_search(const char *srch); char *option_as_string(unsigned int code, unsigned char *data, int len); int fork_privchld(int, int); @@ -2250,6 +2252,14 @@ check_option(struct client_lease *l, int option) } return (1); case DHO_DOMAIN_NAME: + if (!res_hnok(sbuf)) { + if (!check_search(sbuf)) { + warning("Bogus domain search list %d: %s (%s)", + option, sbuf, opbuf); + return (0); + } + } + return (1); case DHO_PAD: case DHO_TIME_OFFSET: case DHO_BOOT_SIZE: @@ -2325,6 +2335,52 @@ res_hnok(const char *dn) return (1); } +int +check_search(const char *srch) +{ + int pch = PERIOD, ch = *srch++; + int domains = 1; + + /* 256 char limit re resolv.conf(5) */ + if (strlen(srch) > 256) + return (0); + + while (whitechar(ch)) + ch = *srch++; + + while (ch != '\0') { + int nch = *srch++; + + if (periodchar(ch) || whitechar(ch)) { + ; + } else if (periodchar(pch)) { + if (!borderchar(ch)) + return (0); + } else if (periodchar(nch) || nch == '\0') { + if (!borderchar(ch)) + return (0); + } else { + if (!middlechar(ch)) + return (0); + } + if (!whitechar(ch)) { + pch = ch; + } else { + while (whitechar(nch)) { + nch = *srch++; + } + if (nch != '\0') + domains++; + pch = PERIOD; + } + ch = nch; + } + /* 6 domain limit re resolv.conf(5) */ + if (domains > 6) + return (0); + return (1); +} + /* Does buf consist only of dotted decimal ipv4 addrs? * return how many if so, * otherwise, return 0 |