From: Stephan Bosch Date: Tue, 17 Sep 2013 18:57:48 +0000 (+0300) Subject: lib-http: Added (non-default) support for parsing user:pasword from HTTP URL. X-Git-Tag: 2.2.6~63 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1e653c7406ec0b062c0bacfdf2e7568a3f860500;p=thirdparty%2Fdovecot%2Fcore.git lib-http: Added (non-default) support for parsing user:pasword from HTTP URL. --- diff --git a/src/lib-http/http-url.c b/src/lib-http/http-url.c index 7454f68d2b..37f13dd89f 100644 --- a/src/lib-http/http-url.c +++ b/src/lib-http/http-url.c @@ -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; diff --git a/src/lib-http/http-url.h b/src/lib-http/http-url.h index f4d85c9f40..ca058a1a60 100644 --- a/src/lib-http/http-url.h +++ b/src/lib-http/http-url.h @@ -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, diff --git a/src/lib-http/test-http-url.c b/src/lib-http/test-http-url.c index fbaa1bfea2..5e0acbb3fa 100644 --- a/src/lib-http/test-http-url.c +++ b/src/lib-http/test-http-url.c @@ -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);