]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: uri - Allow parameters directly with semicolon
authorAki Tuomi <aki.tuomi@open-xchange.com>
Tue, 5 Nov 2024 11:19:49 +0000 (13:19 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 12 Feb 2025 10:34:14 +0000 (12:34 +0200)
Fixes AAA validation.

src/lib/test-uri.c
src/lib/uri-util.c
src/lib/uri-util.h

index efb1703127cc9e440e5f3282bef2650547035ba2..9b0edf8ee8f4421a9f3a632de12b14c8ca1c0b50 100644 (file)
@@ -507,14 +507,12 @@ const char *rfc_uri_tests[] = {
        /* from RFC 6694 */
        "about:blank",
        /* from RFC 6733 */
-#if 0 // these don't comply with RFC 3986
        "aaa://host.example.com;transport=tcp",
        "aaa://host.example.com:6666;transport=tcp",
        "aaa://host.example.com;protocol=diameter",
        "aaa://host.example.com:6666;protocol=diameter",
        "aaa://host.example.com:6666;transport=tcp;protocol=diameter",
        "aaa://host.example.com:1813;transport=udp;protocol=radius",
-#endif
        /* from RFC 6787 */
        "session:request1@form-level.store",
        "session:help@root-level.store",
@@ -800,10 +798,37 @@ static void test_uri_escape(void)
        test_end();
 }
 
+static void test_uri_aaa(void)
+{
+       test_begin("uri aaa");
+
+       const char *uri = "aaa://host.example.com:6666;transport=tcp;protocol=diameter";
+       struct uri_parser parser;
+       uri_parser_init(&parser, pool_datastack_create(), uri);
+       parser.semicolon_params = TRUE;
+
+       const char *scheme;
+       struct uri_authority auth;
+       const char *query;
+       int ret;
+       ret = uri_parse_scheme(&parser, &scheme);
+       test_assert(ret > 0);
+       test_assert_strcmp(scheme, "aaa");
+       ret = uri_parse_slashslash_host_authority(&parser, &auth);
+       test_assert(ret > 0);
+       test_assert_strcmp(auth.host.name, "host.example.com");
+       test_assert_ucmp(auth.port, ==, 6666);
+       ret = uri_parse_query(&parser, &query);
+       test_assert(ret > 0);
+       test_assert_strcmp(query, "transport=tcp;protocol=diameter");
+       test_end();
+}
+
 void test_uri(void)
 {
        test_uri_valid();
        test_uri_invalid();
        test_uri_rfc();
        test_uri_escape();
+       test_uri_aaa();
 }
index 9bec8817cfd576ff820f362a82585297fed526cc..12e3c5ec2689b13b36351d9498a5a4399a158654 100644 (file)
@@ -789,6 +789,10 @@ uri_do_parse_authority(struct uri_parser *parser, struct uri_authority *auth,
        switch (*parser->cur) {
        case ':': case '/': case '?': case '#':
                break;
+       case ';':
+               if (parser->semicolon_params)
+                       break;
+               /* fall-through */
        default:
                if (parser->parse_prefix)
                        break;
@@ -808,6 +812,10 @@ uri_do_parse_authority(struct uri_parser *parser, struct uri_authority *auth,
                switch (*parser->cur) {
                case '/': case '?': case '#':
                        break;
+               case ';':
+                       if (parser->semicolon_params)
+                               break;
+                       /* fall-through */
                default:
                        if (parser->parse_prefix)
                                break;
@@ -1009,7 +1017,9 @@ int uri_parse_query(struct uri_parser *parser, const char **query_r)
           query         = *( pchar / "/" / "?" )
           pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
         */
-       if (parser->cur >= parser->end || *parser->cur != '?')
+       if (parser->cur >= parser->end ||
+           (!parser->semicolon_params && *parser->cur != '?') ||
+           (parser->semicolon_params && *parser->cur != ';'))
                return 0;
        parser->cur++;
 
@@ -1135,11 +1145,16 @@ int uri_parse_absolute_generic(struct uri_parser *parser,
         */
 
        /* scheme ":" */
-       if ((flags & URI_PARSE_SCHEME_EXTERNAL) == 0 &&
-           (ret = uri_parse_scheme(parser, NULL)) <= 0) {
-               if (ret == 0)
-                       parser->error = "Missing scheme";
-               return -1;
+       if ((flags & URI_PARSE_SCHEME_EXTERNAL) == 0) {
+               const char *scheme;
+               if ((ret = uri_parse_scheme(parser, &scheme)) <= 0) {
+                       if (ret == 0)
+                               parser->error = "Missing scheme";
+                       return -1;
+               }
+               if (strcmp(scheme, "aaa") == 0 ||
+                   (flags & URI_PARSE_SEMICOLON_PARAMS) != 0)
+                       parser->semicolon_params = TRUE;
        }
 
        /* "//" authority */
index a8753b8b10f8ba72c48b39907da6eaa22e691f0f..29283bd09e25b965b4e75e4eee7fba96ecca5879 100644 (file)
@@ -12,6 +12,8 @@ enum uri_parse_flags {
        URI_PARSE_SCHEME_EXTERNAL = BIT(0),
        /* Allow '#fragment' part in URI */
        URI_PARSE_ALLOW_FRAGMENT_PART = BIT(1),
+       /* Allow ';param' after host - violates RFC3986 */
+       URI_PARSE_SEMICOLON_PARAMS = BIT(2),
 };
 
 struct uri_host {
@@ -37,6 +39,7 @@ struct uri_parser {
 
        bool allow_pct_nul:1;
        bool parse_prefix:1;
+       bool semicolon_params:1;
 };
 
 static inline const char *uri_char_sanitize(unsigned char c)