]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: Added (non-default) support for parsing user:pasword from HTTP URL.
authorStephan Bosch <stephan@rename-it.nl>
Tue, 17 Sep 2013 18:57:48 +0000 (21:57 +0300)
committerStephan Bosch <stephan@rename-it.nl>
Tue, 17 Sep 2013 18:57:48 +0000 (21:57 +0300)
src/lib-http/http-url.c
src/lib-http/http-url.h
src/lib-http/test-http-url.c

index 7454f68d2bc5f9a4d21c249943eb27d8a33b4e47..37f13dd89f1bfb5bb51c748e023f12b86ecd325e 100644 (file)
@@ -32,25 +32,41 @@ static bool http_url_parse_authority(struct http_url_parser *url_parser)
        struct uri_parser *parser = &url_parser->parser;
        struct http_url *url = url_parser->url;
        struct uri_authority auth;
+       const char *user = NULL, *password = NULL;
        int ret;
 
        if ((ret = uri_parse_authority(parser, &auth)) < 0)
                return FALSE;
        if (ret > 0) {
                if (auth.enc_userinfo != NULL) {
-                       /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-20
+                       const char *p;
 
-                                Section 2.8.1:
+                       if ((url_parser->flags & HTTP_URL_ALLOW_USERINFO_PART) == 0) {
+                               /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-20
 
-                          {...} Senders MUST NOT include a userinfo subcomponent (and its "@"
-                          delimiter) when transmitting an "http" URI in a message. Recipients
-                          of HTTP messages that contain a URI reference SHOULD parse for the
-                          existence of userinfo and treat its presence as an error, likely
-                          indicating that the deprecated subcomponent is being used to
-                          obscure the authority for the sake of phishing attacks.
-                        */
-                       parser->error = "HTTP URL does not allow `userinfo@' part";
-                       return FALSE;
+                                        Section 2.8.1:
+
+                                        {...} Senders MUST NOT include a userinfo subcomponent (and its "@"
+                                        delimiter) when transmitting an "http" URI in a message. Recipients
+                                        of HTTP messages that contain a URI reference SHOULD parse for the
+                                        existence of userinfo and treat its presence as an error, likely
+                                        indicating that the deprecated subcomponent is being used to
+                                        obscure the authority for the sake of phishing attacks.
+                                */
+                               parser->error = "HTTP URL does not allow `userinfo@' part";
+                               return FALSE;
+                       }
+
+                       p = strchr(auth.enc_userinfo, ':');
+                       if (p == NULL) {
+                               if (!uri_data_decode(parser, auth.enc_userinfo, NULL, &user))
+                                       return FALSE;
+                       } else {
+                               if (!uri_data_decode(parser, auth.enc_userinfo, p, &user))
+                                       return FALSE;
+                               if (!uri_data_decode(parser, p+1, NULL, &password))
+                                       return FALSE;
+                       }
                }
        }
        if (url != NULL) {
@@ -59,6 +75,8 @@ static bool http_url_parse_authority(struct http_url_parser *url_parser)
                url->have_host_ip = auth.have_host_ip;
                url->port = auth.port;
                url->have_port = auth.have_port;
+               url->user = p_strdup(parser->pool, user);
+               url->password = p_strdup(parser->pool, password);
        }
        return TRUE;
 }
@@ -210,12 +228,14 @@ static bool http_url_do_parse(struct http_url_parser *url_parser)
                        parser->error = "Relative HTTP URL not allowed";
                        return FALSE;
                } else if (!have_authority && url != NULL) {
-                       url->host_name = p_strdup(parser->pool, base->host_name); 
+                       url->host_name = p_strdup_empty(parser->pool, base->host_name); 
                        url->host_ip = base->host_ip;
                        url->have_host_ip = base->have_host_ip;
                        url->port = base->port;
                        url->have_port = base->have_port;
                        url->have_ssl = base->have_ssl;
+                       url->user = p_strdup_empty(parser->pool, base->user);
+                       url->password = p_strdup_empty(parser->pool, base->password);
                }
 
                url_parser->relative = TRUE;
index f4d85c9f40b0066373c82a9ca052826eee0bd146..ca058a1a6063e035b2996b3be8834fc01dce286a 100644 (file)
@@ -11,6 +11,10 @@ struct http_url {
        struct ip_addr host_ip;
        in_port_t port;
 
+       /* userinfo (not parsed by default) */
+       const char *user;
+       const char *password;
+
        /* path */
        const char *path;
 
@@ -33,8 +37,10 @@ enum http_url_parse_flags {
        /* Scheme part 'http:' is already parsed externally. This implies that
           this is an absolute HTTP URL. */
        HTTP_URL_PARSE_SCHEME_EXTERNAL  = 0x01,
-       /* Allow '#fragment' part in URL */
-       HTTP_URL_ALLOW_FRAGMENT_PART = 0x02
+       /* Allow '#fragment' part in HTTP URL */
+       HTTP_URL_ALLOW_FRAGMENT_PART = 0x02,
+       /* Allow 'user:password@' part in HTTP URL */
+       HTTP_URL_ALLOW_USERINFO_PART = 0x04
 };
 
 int http_url_parse(const char *url, struct http_url *base,
index fbaa1bfea203c21f43f66c6ad2301556b15e6d6c..5e0acbb3fa47d182c7847f77e15604fd786f20c0 100644 (file)
@@ -47,6 +47,23 @@ static struct valid_http_url_test valid_url_tests[] = {
                        .have_host_ip = TRUE,
                        .port = 8080, .have_port = TRUE }
 #endif
+       },{
+               .url = "http://user@api.dovecot.org",
+               .flags = HTTP_URL_ALLOW_USERINFO_PART,
+               .url_parsed = {
+                       .host_name = "api.dovecot.org", .user = "user" }
+       },{
+               .url = "http://userid:secret@api.dovecot.org",
+               .flags = HTTP_URL_ALLOW_USERINFO_PART,
+               .url_parsed = {
+                       .host_name = "api.dovecot.org",
+                       .user = "userid", .password = "secret" }
+       },{
+               .url = "http://su%3auserid:secret@api.dovecot.org",
+               .flags = HTTP_URL_ALLOW_USERINFO_PART,
+               .url_parsed = {
+                       .host_name = "api.dovecot.org",
+                       .user = "su:userid", .password = "secret" }
        },{
                .url = "http://www.example.com/"
                        "?question=What%20are%20you%20doing%3f&answer=Nothing.",
@@ -296,6 +313,20 @@ static void test_http_url_valid(void)
                                test_out("url->host_ip = (valid)",
                                        urlp->have_host_ip == urlt->have_host_ip);
                        }
+                       if (urlp->user == NULL || urlt->user == NULL) {
+                               test_out(t_strdup_printf("url->user = %s", urlp->user),
+                                       urlp->user == urlt->user);
+                       } else {
+                               test_out(t_strdup_printf("url->user = %s", urlp->user),
+                                       strcmp(urlp->user, urlt->user) == 0);
+                       }
+                       if (urlp->password == NULL || urlt->password == NULL) {
+                               test_out(t_strdup_printf("url->password = %s", urlp->password),
+                                       urlp->password == urlt->password);
+                       } else {
+                               test_out(t_strdup_printf("url->password = %s", urlp->password),
+                                       strcmp(urlp->password, urlt->password) == 0);
+                       }
                        if (urlp->path == NULL || urlt->path == NULL) {
                                test_out(t_strdup_printf("url->path = %s", urlp->path),
                                        urlp->path == urlt->path);