bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic bool config_filter_match_service(const struct config_filter *mask,
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen /* not service */
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen if (strcmp(filter->service, mask->service + 1) == 0)
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen if (strcmp(filter->service, mask->service) != 0)
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainenconfig_filter_match_local_name(const struct config_filter *mask,
211c638d81d382517d196ad47565e0d85012c927klemens /* Handle multiple names separated by spaces in local_name
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen * Ex: local_name "mail.domain.tld domain.tld mx.domain.tld" { ... } */
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen const char *const *local_name = t_strsplit_spaces(mask->local_name, " ");
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen if (dns_match_wildcard(filter_local_name, *local_name) == 0)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic bool config_filter_match_rest(const struct config_filter *mask,
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen matched = config_filter_match_local_name(mask, filter->local_name);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* FIXME: it's not comparing full masks */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (!net_is_in_network(&filter->remote_net, &mask->remote_net,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (!net_is_in_network(&filter->local_net, &mask->local_net,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenbool config_filter_match(const struct config_filter *mask,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if (!config_filter_match_service(mask, filter))
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return config_filter_match_rest(mask, filter);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenbool config_filters_equal(const struct config_filter *f1,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (null_strcmp(f1->service, f2->service) != 0)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (!net_ip_compare(&f1->remote_net, &f2->remote_net))
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (!net_ip_compare(&f1->local_net, &f2->local_net))
c19c44f87ef3fe40cae4be9a86ee9327a7370e46Aki Tuomi if (null_strcasecmp(f1->local_name, f2->local_name) != 0)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenstruct config_filter_context *config_filter_init(pool_t pool)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ctx = p_new(pool, struct config_filter_context, 1);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenvoid config_filter_deinit(struct config_filter_context **_ctx)
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen unsigned int i;
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen config_filter_parsers_free(ctx->parsers[i]->parsers);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenvoid config_filter_add_all(struct config_filter_context *ctx,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_filter_parser_cmp(struct config_filter_parser *const *p1,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const struct config_filter *f1 = &(*p1)->filter, *f2 = &(*p2)->filter;
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen /* remote and locals are first, although it doesn't really
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen matter which one comes first */
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (f1->local_name != NULL && f2->local_name == NULL)
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (f1->local_name == NULL && f2->local_name != NULL)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (f1->service != NULL && f2->service == NULL)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (f1->service == NULL && f2->service != NULL)
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainenconfig_filter_parser_cmp_rev(struct config_filter_parser *const *p1,
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainenstatic bool str_array_contains(ARRAY_TYPE(const_string) *arr, const char *str)
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen const char *const *p;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainenstatic bool have_changed_settings(const struct config_filter_parser *parser,
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen const char *const *modules)
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen for (i = 0; parser->parsers[i].root != NULL; i++) {
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen if (!config_module_want_parser(config_module_parsers,
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen changes = settings_parser_get_changes(parser->parsers[i].parser);
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen for (j = 0; j < size; j++) {
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenstatic struct config_filter_parser *const *
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainenconfig_filter_find_all(struct config_filter_context *ctx, pool_t pool,
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen const char *const *modules,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct master_service_settings_output *output_r)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen unsigned int i;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen const struct config_filter *mask = &ctx->parsers[i]->filter;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen if (!config_filter_match_service(mask, filter)) {
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen if (!str_array_contains(&service_names, mask->service) &&
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen have_changed_settings(ctx->parsers[i], modules))
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen array_append(&service_names, &mask->service, 1);
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (mask->local_bits > 0 || mask->local_name != NULL)
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (mask->local_bits > 0 || mask->local_name != NULL)
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen output_r->specific_services = array_idx(&service_names, 0);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen array_sort(&matches, config_filter_parser_cmp);
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainenconfig_filter_find_subset(struct config_filter_context *ctx,
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen unsigned int i;
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen const struct config_filter *mask = &ctx->parsers[i]->filter;
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen if (!config_filter_match_service(mask, filter))
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen if (config_filter_match_rest(&tmp_mask, filter))
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen array_sort(&matches, config_filter_parser_cmp_rev);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_filter_is_superset(const struct config_filter *sup,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen /* assume that both of the filters match the same subset, so we don't
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen need to compare IPs and service name. */
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (sup->local_name != NULL && filter->local_name == NULL) {
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (sup->service != NULL && filter->service == NULL)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_module_parser_apply_changes(struct config_module_parser *dest,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen unsigned int i;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (settings_parser_apply_changes(dest[i].parser,
13be7f7215efe02d020e9d823772861df98b82bdTimo Sirainen *error_r = t_strdup_printf("Conflict in setting %s "
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainenint config_filter_parsers_get(struct config_filter_context *ctx, pool_t pool,
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen const char *const *modules,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct master_service_settings_output *output_r,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const char **error_r)
297901b5b638a1e4d34904b4f7667bbcee0e7a80Timo Sirainen /* get the matching filters. the most specific ones are handled first,
297901b5b638a1e4d34904b4f7667bbcee0e7a80Timo Sirainen so that if more generic filters try to override settings we'll fail
297901b5b638a1e4d34904b4f7667bbcee0e7a80Timo Sirainen with an error. Merging SET_STRLIST types requires
297901b5b638a1e4d34904b4f7667bbcee0e7a80Timo Sirainen settings_parser_apply_changes() to work a bit unintuitively by
297901b5b638a1e4d34904b4f7667bbcee0e7a80Timo Sirainen letting the destination settings override the source settings. */
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen src = config_filter_find_all(ctx, pool, modules, filter, output_r);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen /* all of them should have the same number of parsers.
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen duplicate our initial parsers from the first match */
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen for (count = 0; src[0]->parsers[count].root != NULL; count++) ;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen dest = p_new(pool, struct config_module_parser, count + 1);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen for (i = 0; i < count; i++) {
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen settings_parser_dup(src[0]->parsers[i].parser, pool);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen /* apply the changes from rest of the matches */
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen if (config_filter_is_superset(&src[i]->filter,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (config_module_parser_apply_changes(dest, src[i], pool,
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainenvoid config_filter_parsers_free(struct config_module_parser *parsers)
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen unsigned int i;