On 2023/06/29 19:55:52 +0200, Florian Obser <flor...@openbsd.org> wrote: > I'm worried that we pass un-sanitized input through to fcgi. > Of course we are passing *a lot* of un-sanitized input through to fcgi, > so does this matter in the grand scheme of things? > But I'd like if server_http_parsehost() enforces syntactically valid > hostnames first. > > There is valid_domain() in usr.bin/ssh/misc.c or res_hnok in > resolv.h. Which is probably fine to use since we don't care too much > about portable.
right, httpd is happily accepting any nonsense as Host. Here's an adaptation of millert' valid_domain() from usr.bin/ssh/misc.c. Hope noone is relying on using an empty/malformed Host :> diff /usr/src commit - 9832f5035d799ae12e9f848cff5650481b673260 path + /usr/src blob - 091cc86fec946a4a9d422c04a48f5cbfae015ce0 file + usr.sbin/httpd/server_http.c --- usr.sbin/httpd/server_http.c +++ usr.sbin/httpd/server_http.c @@ -831,6 +831,42 @@ char * return (buf); } +static int +valid_domain(char *name, const char **errstr) +{ + size_t i; + unsigned char c, last = '\0'; + + *errstr = NULL; + + if (*name == '\0') { + *errstr = "empty domain name"; + return 0; + } + if (!isalpha((unsigned char)name[0]) && + !isdigit((unsigned char)name[0])) { + *errstr = "domain name starts with an invalid character"; + return 0; + } + for (i = 0; name[i] != '\0'; ++i) { + c = tolower((unsigned char)name[i]); + name[i] = c; + if (last == '.' && c == '.') { + *errstr = "domain name contains consecutive separators"; + return 0; + } + if (c != '.' && c != '-' && !isalnum(c) && + c != '_') /* technically invalid, but common */ { + *errstr = "domain name contains invalid characters"; + return 0; + } + last = c; + } + if (name[i - 1] == '.') + name[i - 1] = '\0'; + return 1; +} + char * server_http_parsehost(char *host, char *buf, size_t len, int *portval) { @@ -863,6 +899,11 @@ server_http_parsehost(char *host, char *buf, size_t le port = NULL; } + if (!valid_domain(start, &errstr)) { + log_debug("%s: %s: %s", __func__, errstr, host); + return (NULL); + } + if (port != NULL) { /* Save the requested port */ *portval = strtonum(port, 0, 0xffff, &errstr);