From 8d9de5b10a24bd2d79ed99f139c0ac28c09b15ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Tue, 27 Nov 2018 10:45:14 +0000 Subject: [PATCH] Improve URL parsing. In particular, convert scheme and host to lowercase. MFC after: 1 week --- lib/libfetch/common.c | 8 ++--- lib/libfetch/fetch.c | 83 +++++++++++++++++++++++++------------------ lib/libfetch/ftp.c | 8 ++--- 3 files changed, 56 insertions(+), 43 deletions(-) diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c index 74bc145f6873..80a63123abdb 100644 --- a/lib/libfetch/common.c +++ b/lib/libfetch/common.c @@ -189,9 +189,9 @@ fetch_default_port(const char *scheme) if ((se = getservbyname(scheme, "tcp")) != NULL) return (ntohs(se->s_port)); - if (strcasecmp(scheme, SCHEME_FTP) == 0) + if (strcmp(scheme, SCHEME_FTP) == 0) return (FTP_DEFAULT_PORT); - if (strcasecmp(scheme, SCHEME_HTTP) == 0) + if (strcmp(scheme, SCHEME_HTTP) == 0) return (HTTP_DEFAULT_PORT); return (0); } @@ -202,9 +202,9 @@ fetch_default_port(const char *scheme) int fetch_default_proxy_port(const char *scheme) { - if (strcasecmp(scheme, SCHEME_FTP) == 0) + if (strcmp(scheme, SCHEME_FTP) == 0) return (FTP_DEFAULT_PROXY_PORT); - if (strcasecmp(scheme, SCHEME_HTTP) == 0) + if (strcmp(scheme, SCHEME_HTTP) == 0) return (HTTP_DEFAULT_PROXY_PORT); return (0); } diff --git a/lib/libfetch/fetch.c b/lib/libfetch/fetch.c index ea8c33864706..b3ed702b3185 100644 --- a/lib/libfetch/fetch.c +++ b/lib/libfetch/fetch.c @@ -32,8 +32,10 @@ __FBSDID("$FreeBSD$"); #include -#include +#include + +#include #include #include #include @@ -81,13 +83,13 @@ fetchXGet(struct url *URL, struct url_stat *us, const char *flags) us->size = -1; us->atime = us->mtime = 0; } - if (strcasecmp(URL->scheme, SCHEME_FILE) == 0) + if (strcmp(URL->scheme, SCHEME_FILE) == 0) return (fetchXGetFile(URL, us, flags)); - else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) + else if (strcmp(URL->scheme, SCHEME_FTP) == 0) return (fetchXGetFTP(URL, us, flags)); - else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0) + else if (strcmp(URL->scheme, SCHEME_HTTP) == 0) return (fetchXGetHTTP(URL, us, flags)); - else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0) + else if (strcmp(URL->scheme, SCHEME_HTTPS) == 0) return (fetchXGetHTTP(URL, us, flags)); url_seterr(URL_BAD_SCHEME); return (NULL); @@ -111,13 +113,13 @@ FILE * fetchPut(struct url *URL, const char *flags) { - if (strcasecmp(URL->scheme, SCHEME_FILE) == 0) + if (strcmp(URL->scheme, SCHEME_FILE) == 0) return (fetchPutFile(URL, flags)); - else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) + else if (strcmp(URL->scheme, SCHEME_FTP) == 0) return (fetchPutFTP(URL, flags)); - else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0) + else if (strcmp(URL->scheme, SCHEME_HTTP) == 0) return (fetchPutHTTP(URL, flags)); - else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0) + else if (strcmp(URL->scheme, SCHEME_HTTPS) == 0) return (fetchPutHTTP(URL, flags)); url_seterr(URL_BAD_SCHEME); return (NULL); @@ -135,13 +137,13 @@ fetchStat(struct url *URL, struct url_stat *us, const char *flags) us->size = -1; us->atime = us->mtime = 0; } - if (strcasecmp(URL->scheme, SCHEME_FILE) == 0) + if (strcmp(URL->scheme, SCHEME_FILE) == 0) return (fetchStatFile(URL, us, flags)); - else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) + else if (strcmp(URL->scheme, SCHEME_FTP) == 0) return (fetchStatFTP(URL, us, flags)); - else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0) + else if (strcmp(URL->scheme, SCHEME_HTTP) == 0) return (fetchStatHTTP(URL, us, flags)); - else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0) + else if (strcmp(URL->scheme, SCHEME_HTTPS) == 0) return (fetchStatHTTP(URL, us, flags)); url_seterr(URL_BAD_SCHEME); return (-1); @@ -155,13 +157,13 @@ struct url_ent * fetchList(struct url *URL, const char *flags) { - if (strcasecmp(URL->scheme, SCHEME_FILE) == 0) + if (strcmp(URL->scheme, SCHEME_FILE) == 0) return (fetchListFile(URL, flags)); - else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) + else if (strcmp(URL->scheme, SCHEME_FTP) == 0) return (fetchListFTP(URL, flags)); - else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0) + else if (strcmp(URL->scheme, SCHEME_HTTP) == 0) return (fetchListHTTP(URL, flags)); - else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0) + else if (strcmp(URL->scheme, SCHEME_HTTPS) == 0) return (fetchListHTTP(URL, flags)); url_seterr(URL_BAD_SCHEME); return (NULL); @@ -345,7 +347,7 @@ fetchParseURL(const char *URL) char *doc; const char *p, *q; struct url *u; - int i; + int i, n; /* allocate struct url */ if ((u = calloc(1, sizeof(*u))) == NULL) { @@ -356,8 +358,10 @@ fetchParseURL(const char *URL) /* scheme name */ if ((p = strstr(URL, ":/"))) { - snprintf(u->scheme, URL_SCHEMELEN+1, - "%.*s", (int)(p - URL), URL); + if (p - URL > URL_SCHEMELEN) + goto ouch; + for (i = 0; URL + i < p; i++) + u->scheme[i] = tolower((unsigned char)URL[i]); URL = ++p; /* * Only one slash: no host, leave slash as part of document @@ -388,28 +392,37 @@ fetchParseURL(const char *URL) } /* hostname */ - if (*p == '[' && (q = strchr(p + 1, ']')) != NULL && - (*++q == '\0' || *q == '/' || *q == ':')) { - if ((i = q - p) > MAXHOSTNAMELEN) - i = MAXHOSTNAMELEN; - strncpy(u->host, p, i); - p = q; + if (*p == '[') { + q = p + 1 + strspn(p + 1, ":0123456789ABCDEFabcdef"); + if (*q++ != ']') + goto ouch; } else { - for (i = 0; *p && (*p != '/') && (*p != ':'); p++) - if (i < MAXHOSTNAMELEN) - u->host[i++] = *p; + /* valid characters in a DNS name */ + q = p + strspn(p, "-." "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "_" + "abcdefghijklmnopqrstuvwxyz"); } + if ((*q != '\0' && *q != '/' && *q != ':') || q - p > MAXHOSTNAMELEN) + goto ouch; + for (i = 0; p + i < q; i++) + u->host[i] = tolower((unsigned char)p[i]); + u->host[i] = '\0'; + p = q; /* port */ if (*p == ':') { - for (q = ++p; *q && (*q != '/'); q++) - if (isdigit((unsigned char)*q)) - u->port = u->port * 10 + (*q - '0'); - else { + for (n = 0, q = ++p; *q && (*q != '/'); q++) { + if (*q >= '0' && *q <= '9' && n < INT_MAX / 10) { + n = n * 10 + (*q - '0'); + } else { /* invalid port */ url_seterr(URL_BAD_PORT); goto ouch; } + } + if (n < 1 || n > IPPORT_MAX) + goto ouch; + u->port = n; p = q; } @@ -418,8 +431,8 @@ nohost: if (!*p) p = "/"; - if (strcasecmp(u->scheme, SCHEME_HTTP) == 0 || - strcasecmp(u->scheme, SCHEME_HTTPS) == 0) { + if (strcmp(u->scheme, SCHEME_HTTP) == 0 || + strcmp(u->scheme, SCHEME_HTTPS) == 0) { const char hexnums[] = "0123456789abcdef"; /* percent-escape whitespace. */ diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c index 18fa673147d4..9a546f3fecad 100644 --- a/lib/libfetch/ftp.c +++ b/lib/libfetch/ftp.c @@ -1085,8 +1085,8 @@ ftp_get_proxy(struct url * url, const char *flags) } if (!purl->port) purl->port = fetch_default_proxy_port(purl->scheme); - if (strcasecmp(purl->scheme, SCHEME_FTP) == 0 || - strcasecmp(purl->scheme, SCHEME_HTTP) == 0) + if (strcmp(purl->scheme, SCHEME_FTP) == 0 || + strcmp(purl->scheme, SCHEME_HTTP) == 0) return (purl); fetchFreeURL(purl); } @@ -1104,8 +1104,8 @@ ftp_request(struct url *url, const char *op, struct url_stat *us, int oflag; /* check if we should use HTTP instead */ - if (purl && (strcasecmp(purl->scheme, SCHEME_HTTP) == 0 || - strcasecmp(purl->scheme, SCHEME_HTTPS) == 0)) { + if (purl && (strcmp(purl->scheme, SCHEME_HTTP) == 0 || + strcmp(purl->scheme, SCHEME_HTTPS) == 0)) { if (strcmp(op, "STAT") == 0) return (http_request(url, "HEAD", us, purl, flags)); else if (strcmp(op, "RETR") == 0)