]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
config: Change config_filter to a tree
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 15 May 2023 10:42:03 +0000 (13:42 +0300)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 20 Nov 2023 12:21:56 +0000 (14:21 +0200)
The child filters no longer contain parent filters' contents. For example
local { protocol { ...  } } will now contain a parent config_filter that
contains the "local" filter and a child filter containing only the
"protocol" filter (not both local and protocol as before). Config filter
matching is changed to look at also the parent filters to preserve the
correct behavior.

src/config/config-dump-full.c
src/config/config-filter.c
src/config/config-filter.h
src/config/config-parser.c
src/config/config-parser.h
src/config/doveconf.c

index 0273813df244d2575fbcc91eaccfe614fe248b38..71267238d5892f62c65e49523ea4bc09ed5fe742 100644 (file)
@@ -66,14 +66,9 @@ static int output_blob_size(struct ostream *output, uoff_t blob_size_offset)
 }
 
 static void
-config_dump_full_append_filter(string_t *str,
-                              const struct config_filter *filter,
-                              enum config_dump_full_dest dest)
+config_dump_full_append_filter_query(string_t *str,
+                                    const struct config_filter *filter)
 {
-       if (dest == CONFIG_DUMP_FULL_DEST_STDOUT)
-               str_append(str, ":FILTER ");
-       unsigned int prefix_len = str_len(str);
-
        if (filter->service != NULL) {
                if (filter->service[0] != '!') {
                        str_printfa(str, "protocol=\"%s\" AND ",
@@ -97,6 +92,21 @@ config_dump_full_append_filter(string_t *str,
                            net_ip2addr(&filter->remote_net),
                            filter->remote_bits);
        }
+}
+
+static void
+config_dump_full_append_filter(string_t *str,
+                              const struct config_filter *filter,
+                              enum config_dump_full_dest dest)
+{
+       if (dest == CONFIG_DUMP_FULL_DEST_STDOUT)
+               str_append(str, ":FILTER ");
+       unsigned int prefix_len = str_len(str);
+
+       do {
+               config_dump_full_append_filter_query(str, filter);
+               filter = filter->parent;
+       } while (filter != NULL);
 
        i_assert(str_len(str) > prefix_len);
        str_delete(str, str_len(str) - 4, 4);
index fc9e42c94cf3f732055b05d9eebdbc8bdb14fbbd..fd22f7a9ea43eb08deb2be4fd11ef3f552bfe54a 100644 (file)
@@ -77,10 +77,16 @@ static bool config_filter_match_rest(const struct config_filter *mask,
 bool config_filter_match(const struct config_filter *mask,
                         const struct config_filter *filter)
 {
-       if (!config_filter_match_service(mask, filter))
-               return FALSE;
+       do {
+               if (!config_filter_match_service(mask, filter))
+                       return FALSE;
 
-       return config_filter_match_rest(mask, filter);
+               if (!config_filter_match_rest(mask, filter))
+                       return FALSE;
+               mask = mask->parent;
+               filter = filter->parent;
+       } while (mask != NULL && filter != NULL);
+       return mask == NULL && filter == NULL;
 }
 
 bool config_filters_equal(const struct config_filter *f1,
@@ -104,30 +110,3 @@ bool config_filters_equal(const struct config_filter *f1,
 
        return TRUE;
 }
-
-int config_filter_sort_cmp(const struct config_filter *f1,
-                          const struct config_filter *f2)
-{
-       /* remote and locals are first, although it doesn't really
-          matter which one comes first */
-       if (f1->local_name != NULL && f2->local_name == NULL)
-               return 1;
-       if (f1->local_name == NULL && f2->local_name != NULL)
-               return -1;
-
-       if (f1->local_bits > f2->local_bits)
-               return 1;
-       if (f1->local_bits < f2->local_bits)
-               return -1;
-
-       if (f1->remote_bits > f2->remote_bits)
-               return 1;
-       if (f1->remote_bits < f2->remote_bits)
-               return -1;
-
-       if (f1->service != NULL && f2->service == NULL)
-               return 1;
-       if (f1->service == NULL && f2->service != NULL)
-               return -1;
-       return 0;
-}
index 48f62315690e01613dfbf65a7accb2ab5d154abd..3e9382f284abfb45d33624d1d327883087eac976 100644 (file)
@@ -4,6 +4,8 @@
 #include "net.h"
 
 struct config_filter {
+       struct config_filter *parent;
+
        const char *service;
        /* local_name is for TLS SNI requests.
           both local_name and local_bits can't be set at the same time. */
@@ -30,8 +32,4 @@ bool config_filter_match(const struct config_filter *mask,
 bool config_filters_equal(const struct config_filter *f1,
                          const struct config_filter *f2);
 
-/* Used for sorting filters - doesn't return exact equality. */
-int config_filter_sort_cmp(const struct config_filter *f1,
-                          const struct config_filter *f2);
-
 #endif
index 360246f0d2f30d0952694f03fcf5c0f9a85a981f..bebd9c4cb3067baed8a955e45aafc41e876c7fd5 100644 (file)
@@ -101,8 +101,13 @@ config_parser_is_in_localremote(struct config_section_stack *section)
 {
        const struct config_filter *filter = &section->filter;
 
-       return filter->local_name != NULL || filter->local_bits > 0 ||
-               filter->remote_bits > 0;
+       do {
+               if (filter->local_name != NULL || filter->local_bits > 0 ||
+                   filter->remote_bits > 0)
+                       return TRUE;
+               filter = filter->parent;
+       } while (filter != NULL);
+       return FALSE;
 }
 
 static void
@@ -335,6 +340,9 @@ config_filter_add_new_filter(struct config_parser_context *ctx,
        struct config_filter_parser *filter_parser;
        const char *error;
 
+       i_zero(filter);
+       filter->parent = parent;
+
        if (strcmp(key, "protocol") == 0) {
                if (parent->service != NULL)
                        ctx->error = "Nested protocol { protocol { .. } } block not allowed";
@@ -787,13 +795,6 @@ config_parse_line(struct config_parser_context *ctx,
        config_line_r->type = CONFIG_LINE_TYPE_SECTION_BEGIN;
 }
 
-static int
-config_filter_parser_cmp(struct config_filter_parser *const *p1,
-                        struct config_filter_parser *const *p2)
-{
-       return config_filter_sort_cmp(&(*p1)->filter, &(*p2)->filter);
-}
-
 static int
 config_parse_finish(struct config_parser_context *ctx,
                    enum config_parse_flags flags,
@@ -811,11 +812,6 @@ config_parse_finish(struct config_parser_context *ctx,
        pool_ref(new_config->pool);
        p_array_init(&new_config->errors, ctx->pool, 1);
 
-       struct config_filter_parser *global_filter =
-               array_idx_elem(&ctx->all_filter_parsers, 0);
-       array_sort(&ctx->all_filter_parsers, config_filter_parser_cmp);
-       i_assert(global_filter == array_idx_elem(&ctx->all_filter_parsers, 0));
-
        array_append_zero(&ctx->all_filter_parsers);
        new_config->filter_parsers = array_front(&ctx->all_filter_parsers);
 
index 8467ff5866e6b2f8e276043c0545061bec1b9f6f..252cb600bbc9778451cbf0c55f294be55a36dc33 100644 (file)
@@ -44,7 +44,7 @@ config_parsed_get_errors(struct config_parsed *config);
 /* Returns the global filter */
 struct config_filter_parser *
 config_parsed_get_global_filter_parser(struct config_parsed *config);
-/* Returns all filters sorted */
+/* Returns all filters */
 struct config_filter_parser *const *
 config_parsed_get_filter_parsers(struct config_parsed *config);
 void config_parsed_free(struct config_parsed **config);
index b66d528a7409b5d41682c000edc9117094f51545..c036b93a42c9d3229701d5288d43f6cb9620bac4 100644 (file)
@@ -481,6 +481,9 @@ config_dump_filter_begin(string_t *str,
 {
        unsigned int indent = 0;
 
+       if (filter->parent != NULL)
+               indent = config_dump_filter_begin(str, filter->parent);
+
        if (filter->local_bits > 0) {
                str_printfa(str, "local %s", net_ip2addr(&filter->local_net));