]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
uri-util: Implemented proper parsing of DNS-based host name for URI schemes that...
authorStephan Bosch <stephan@rename-it.nl>
Sun, 8 May 2016 20:59:09 +0000 (22:59 +0200)
committerGitLab <gitlab@git.dovecot.net>
Mon, 16 May 2016 07:36:48 +0000 (10:36 +0300)
src/lib-http/http-url.c
src/lib-http/test-http-url.c
src/lib-imap/imap-url.c
src/lib-imap/test-imap-url.c
src/lib/uri-util.c
src/lib/uri-util.h

index 9b7050cbae55c0235dba368fb2f68da8eefb9718..375c63337ee9b669ec229715d43e1550d1ddfa65 100644 (file)
@@ -35,7 +35,7 @@ static bool http_url_parse_authority(struct http_url_parser *url_parser)
        const char *user = NULL, *password = NULL;
        int ret;
 
-       if ((ret = uri_parse_authority(parser, &auth)) < 0)
+       if ((ret = uri_parse_authority(parser, &auth, TRUE)) < 0)
                return FALSE;
        if (auth.host_literal == NULL || *auth.host_literal == '\0') {
                /* RFC 7230, Section 2.7.1: http URI Scheme
@@ -369,7 +369,7 @@ int http_url_request_target_parse(const char *request_target,
        parser = &url_parser.parser;
        uri_parser_init(parser, pool, host_header);
 
-       if (uri_parse_authority(parser, &host) <= 0) {
+       if (uri_parse_authority(parser, &host, TRUE) <= 0) {
                *error_r = t_strdup_printf("Invalid Host header: %s", parser->error);
                return -1;
        }
index 87daf07ae59259689ba030cad56e36e1126fb118..fc1aa5c03b3956d253b2fd170e59f64b3dc2ae02 100644 (file)
@@ -434,7 +434,6 @@ static const char *parse_create_url_tests[] = {
        "http://www.example.com:993/",
        "http://www.example.com/index.html",
        "http://www.example.com/settings/index.html",
-       "http://ww.%23example.com/",
        "http://www.example.com/%23shared/news",
        "http://www.example.com/query.php?name=Hendrik%20Visser",
        "http://www.example.com/network.html#IMAP%20Server",
index a0ec9648e2bdb5495066b2182202fe57ef3edc6a..ecd7058e50f350051fd30201a10136111e73ff48 100644 (file)
@@ -191,7 +191,8 @@ static int imap_url_parse_iserver(struct imap_url_parser *url_parser)
         */
 
        /* "//" iserver */
-       if ((ret = uri_parse_slashslash_authority(parser, &auth)) <= 0)
+       if ((ret = uri_parse_slashslash_authority
+               (parser, &auth, TRUE)) <= 0)
                return ret;
        if (auth.host_literal == NULL || *auth.host_literal == '\0') {
                /* This situation is not documented anywhere, but it is not
index f3bfdc5668f853f0043566968deb878fc83946a6..cfc3f1f7b34f632c14a520b752cb10b30166e999 100644 (file)
@@ -976,7 +976,6 @@ static const char *parse_create_url_tests[] = {
        "imap://user;AUTH=PLAIN@host.example.com/INBOX;UIDVALIDITY=15/;UID=5"
                "/;SECTION=TEXT/;PARTIAL=1.14;URLAUTH=user+username",
        "imap://user;AUTH=PLAIN@host.example.com/INBOX?SUBJECT%20%22Frop?%22",
-       "imap://host.%23example.com/",
        "imap://user%3ba@host.example.com/",
        "imap://user%40example.com@host.example.com/",
        "imap://user%40example.com;AUTH=STR%23ANGE@host.example.com/",
index d8d5491a1c5fe9b27a9e1a39ddb2a85567ff75be..09485c150850f6acf43515f4b9b90fbed70eafd0 100644 (file)
@@ -372,6 +372,122 @@ uri_parse_reg_name(struct uri_parser *parser,
        return 0;
 }
 
+static int uri_parse_host_name_dns(struct uri_parser *parser,
+       string_t *host_name) ATTR_NULL(2, 3)
+{
+       const unsigned char *first, *part;
+       int ret;
+
+       /* RFC 3986, Section 3.2.2:
+
+          A registered name intended for lookup in the DNS uses the syntax
+          defined in Section 3.5 of [RFC1034] and Section 2.1 of [RFC1123].
+          Such a name consists of a sequence of domain labels separated by ".",
+          each domain label starting and ending with an alphanumeric character
+          and possibly also containing "-" characters.  The rightmost domain
+          label of a fully qualified domain name in DNS may be followed by a
+          single "." and should be if it is necessary to distinguish between
+          the complete domain name and some local domain.
+
+          RFC 2396, Section 3.2.2 (old URI specification):
+
+          hostname      = *( domainlabel "." ) toplabel [ "." ]
+          domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
+          toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
+
+          The description in RFC 3986 is more liberal, so:
+
+          hostname      = *( domainlabel "." ) domainlabel [ "." ]
+          domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
+
+          We also support percent encoding in spirit of the generic reg-name,
+          even though this should explicitly not be used according to the RFC.
+          It is, however, not strictly forbidden (unlike older RFC), so we
+          support it.
+        */
+
+       first = part = parser->cur;
+       for (;;) {
+               const unsigned char *offset;
+               unsigned char ch, pch;
+
+               /* alphanum */
+               offset = parser->cur;
+               ch = pch = *parser->cur;
+               if (parser->cur >= parser->end)
+                       break;
+               if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0) {
+                       return -1;
+               } else if (ret > 0) {
+                       if (!i_isalnum(ch))
+                               return -1;
+                       if (host_name != NULL)
+                               str_append_c(host_name, ch);
+                       part = parser->cur;
+               } else {
+                       if (!i_isalnum(*parser->cur))
+                               break;
+                       parser->cur++;
+               }
+
+               if (parser->cur < parser->end) {
+                       /* *( alphanum | "-" ) alphanum */
+                       do {
+                               offset = parser->cur;
+
+                               if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0) {
+                                       return -1;
+                               } else if (ret > 0) {
+                                       if (!i_isalnum(ch) && ch != '-')
+                                               break;
+                                       if (host_name != NULL) {
+                                               if (offset > part)
+                                                       str_append_n(host_name, part, offset - part);
+                                               str_append_c(host_name, ch);
+                                       }
+                                       part = parser->cur;
+                               } else {
+                                       ch = *parser->cur;
+                                       if (!i_isalnum(ch) && ch != '-')
+                                               break;
+                                       parser->cur++;
+                               }
+                               pch = ch;
+                       } while (parser->cur < parser->end);
+
+                       if (!i_isalnum(pch)) {
+                               parser->error = "Invalid domain label in hostname";
+                               return -1;
+                       }
+               }
+
+               if (host_name != NULL && parser->cur > part)
+                       str_append_n(host_name, part, parser->cur - part);
+
+               /* "." */
+               if (parser->cur >= parser->end || ch != '.')
+                       break;
+               if (host_name != NULL)
+                       str_append_c(host_name, '.');
+               if (parser->cur == offset)
+                       parser->cur++;
+               part = parser->cur;
+       }
+
+       if (parser->cur == first)
+               return 0;
+
+       /* remove trailing '.' */
+       if (host_name != NULL) {
+               const char *name = str_c(host_name);
+
+               i_assert(str_len(host_name) > 0);
+               if (name[str_len(host_name)-1] == '.')
+                       str_truncate(host_name, str_len(host_name)-1);
+       }
+       return 1;
+}
+
 static int
 uri_parse_ip_literal(struct uri_parser *parser, string_t *literal,
                     struct in6_addr *ip6_r) ATTR_NULL(2,3)
@@ -425,7 +541,7 @@ uri_parse_ip_literal(struct uri_parser *parser, string_t *literal,
 
 static int 
 uri_parse_host(struct uri_parser *parser,
-       struct uri_authority *auth) ATTR_NULL(2)
+       struct uri_authority *auth, bool dns_name) ATTR_NULL(2)
 {
        const unsigned char *preserve;
        struct in_addr ip4;
@@ -470,7 +586,10 @@ uri_parse_host(struct uri_parser *parser,
        str_truncate(literal, 0);
 
        /* reg-name */
-       if (uri_parse_reg_name(parser, literal) < 0)
+       if (dns_name) {
+               if (uri_parse_host_name_dns(parser, literal) < 0)
+                       return -1;
+       } else  if (uri_parse_reg_name(parser, literal) < 0)
                return -1;
        if (auth != NULL)
                auth->host_literal = p_strdup(parser->pool, str_c(literal));
@@ -506,7 +625,7 @@ uri_parse_port(struct uri_parser *parser,
 }
 
 int uri_parse_authority(struct uri_parser *parser,
-       struct uri_authority *auth)
+       struct uri_authority *auth, bool dns_name)
 {
        const unsigned char *p;
        int ret;
@@ -537,7 +656,7 @@ int uri_parse_authority(struct uri_parser *parser,
        }
 
        /* host */
-       if (uri_parse_host(parser, auth) < 0)
+       if (uri_parse_host(parser, auth, dns_name) < 0)
                return -1;
        if (parser->cur == parser->end)
                return 1;
@@ -570,7 +689,7 @@ int uri_parse_authority(struct uri_parser *parser,
 }
 
 int uri_parse_slashslash_authority(struct uri_parser *parser,
-       struct uri_authority *auth)
+       struct uri_authority *auth, bool dns_name)
 {
        /* "//" authority */
 
@@ -579,7 +698,7 @@ int uri_parse_slashslash_authority(struct uri_parser *parser,
                return 0;
 
        parser->cur += 2;
-       return uri_parse_authority(parser, auth);
+       return uri_parse_authority(parser, auth, dns_name);
 }
 
 int uri_parse_path_segment(struct uri_parser *parser, const char **segment_r)
index 02e1b39a0c1a97b71fb6bb5818558a71d88b54da..bfb31f0f95065def21d34571cb940626a17d8815 100644 (file)
@@ -37,9 +37,9 @@ int uri_cut_scheme(const char **uri_p, const char **scheme_r)
 int uri_parse_scheme(struct uri_parser *parser, const char **scheme_r)
        ATTR_NULL(2);
 int uri_parse_authority(struct uri_parser *parser,
-       struct uri_authority *auth)      ATTR_NULL(2);
+       struct uri_authority *auth, bool dns_name) ATTR_NULL(2);
 int uri_parse_slashslash_authority(struct uri_parser *parser,
-       struct uri_authority *auth) ATTR_NULL(2);
+       struct uri_authority *auth, bool dns_name) ATTR_NULL(2);
 
 int uri_parse_path_segment(struct uri_parser *parser,
        const char **segment_r) ATTR_NULL(2);