bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen#include "lib.h"
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen#include "array.h"
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen#include "settings-parser.h"
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen#include "master-service-settings.h"
ec1a4f4306496380e9d96ee08a3718a669d0875aTimo Sirainen#include "config-parser.h"
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen#include "config-filter.h"
6baee5cd05602df1c39e502c7784501e58b3241dAki Tuomi#include "dns-util.h"
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenstruct config_filter_context {
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen pool_t pool;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct config_filter_parser *const *parsers;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen};
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic bool config_filter_match_service(const struct config_filter *mask,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen const struct config_filter *filter)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen{
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (mask->service != NULL) {
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (filter->service == NULL)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen if (mask->service[0] == '!') {
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen /* not service */
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen if (strcmp(filter->service, mask->service + 1) == 0)
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen return FALSE;
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen } else {
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen if (strcmp(filter->service, mask->service) != 0)
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen return FALSE;
4c104ff1cf1d5adbc7c20b650741dee364aa9234Timo Sirainen }
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen }
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return TRUE;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen}
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainenstatic bool
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainenconfig_filter_match_local_name(const struct config_filter *mask,
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen const char *filter_local_name)
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen{
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
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen for (; *local_name != NULL; local_name++) {
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen if (dns_match_wildcard(filter_local_name, *local_name) == 0)
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen return TRUE;
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen }
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen return FALSE;
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen}
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic bool config_filter_match_rest(const struct config_filter *mask,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen const struct config_filter *filter)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen{
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen bool matched;
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (mask->local_name != NULL) {
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (filter->local_name == NULL)
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen return FALSE;
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen T_BEGIN {
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen matched = config_filter_match_local_name(mask, filter->local_name);
b6188d7d62ef9ab46f9f074d88b26caea0e15f6aTimo Sirainen } T_END;
fb13dfaa903c5efb492e993888aa444138001e8eJ. Nick Koston if (!matched)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen }
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen /* FIXME: it's not comparing full masks */
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (mask->remote_bits != 0) {
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (filter->remote_bits == 0)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (!net_is_in_network(&filter->remote_net, &mask->remote_net,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen mask->remote_bits))
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen }
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (mask->local_bits != 0) {
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (filter->local_bits == 0)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (!net_is_in_network(&filter->local_net, &mask->local_net,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen mask->local_bits))
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen }
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return TRUE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen}
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenbool config_filter_match(const struct config_filter *mask,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen const struct config_filter *filter)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen{
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if (!config_filter_match_service(mask, filter))
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return FALSE;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return config_filter_match_rest(mask, filter);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen}
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenbool config_filters_equal(const struct config_filter *f1,
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen const struct config_filter *f2)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen{
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (null_strcmp(f1->service, f2->service) != 0)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (f1->remote_bits != f2->remote_bits)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (!net_ip_compare(&f1->remote_net, &f2->remote_net))
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (f1->local_bits != f2->local_bits)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen if (!net_ip_compare(&f1->local_net, &f2->local_net))
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return FALSE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
c19c44f87ef3fe40cae4be9a86ee9327a7370e46Aki Tuomi if (null_strcasecmp(f1->local_name, f2->local_name) != 0)
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen return FALSE;
08e7163a8d12979119fa56c92676af4ba6304f1aTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return TRUE;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen}
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenstruct config_filter_context *config_filter_init(pool_t pool)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen{
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen struct config_filter_context *ctx;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ctx = p_new(pool, struct config_filter_context, 1);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ctx->pool = pool;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return ctx;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen}
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenvoid config_filter_deinit(struct config_filter_context **_ctx)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen{
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen struct config_filter_context *ctx = *_ctx;
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen unsigned int i;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen *_ctx = NULL;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen for (i = 0; ctx->parsers[i] != NULL; i++)
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen config_filter_parsers_free(ctx->parsers[i]->parsers);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen pool_unref(&ctx->pool);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen}
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainenvoid config_filter_add_all(struct config_filter_context *ctx,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct config_filter_parser *const *parsers)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen{
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen ctx->parsers = parsers;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen}
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenstatic int
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_filter_parser_cmp(struct config_filter_parser *const *p1,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct config_filter_parser *const *p2)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen{
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const struct config_filter *f1 = &(*p1)->filter, *f2 = &(*p2)->filter;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
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 return -1;
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (f1->local_name == NULL && f2->local_name != NULL)
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen return 1;
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (f1->local_bits > f2->local_bits)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return -1;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (f1->local_bits < f2->local_bits)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return 1;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (f1->remote_bits > f2->remote_bits)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return -1;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (f1->remote_bits < f2->remote_bits)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return 1;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (f1->service != NULL && f2->service == NULL)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return -1;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (f1->service == NULL && f2->service != NULL)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen return 1;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return 0;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen}
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainenstatic int
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainenconfig_filter_parser_cmp_rev(struct config_filter_parser *const *p1,
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen struct config_filter_parser *const *p2)
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen{
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen return -config_filter_parser_cmp(p1, p2);
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen}
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainenstatic bool str_array_contains(ARRAY_TYPE(const_string) *arr, const char *str)
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen{
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen const char *const *p;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen array_foreach(arr, p) {
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen if (strcmp(*p, str) == 0)
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen return TRUE;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen }
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen return FALSE;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen}
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainenstatic bool have_changed_settings(const struct config_filter_parser *parser,
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen const char *const *modules)
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen{
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen const unsigned char *changes;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen unsigned int i, j, size;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen for (i = 0; parser->parsers[i].root != NULL; i++) {
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen if (!config_module_want_parser(config_module_parsers,
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen modules, parser->parsers[i].root))
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen continue;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen changes = settings_parser_get_changes(parser->parsers[i].parser);
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen size = parser->parsers[i].root->struct_size;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen for (j = 0; j < size; j++) {
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen if (changes[j] != 0)
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen return TRUE;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen }
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen }
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen return FALSE;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen}
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen
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 const struct config_filter *filter,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct master_service_settings_output *output_r)
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen{
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen ARRAY_TYPE(config_filter_parsers) matches;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen ARRAY_TYPE(const_string) service_names;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen unsigned int i;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(output_r);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen p_array_init(&matches, pool, 8);
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen p_array_init(&service_names, pool, 8);
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen for (i = 0; ctx->parsers[i] != NULL; i++) {
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen const struct config_filter *mask = &ctx->parsers[i]->filter;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
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);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen continue;
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen }
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (mask->local_bits > 0 || mask->local_name != NULL)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen output_r->service_uses_local = TRUE;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if (mask->remote_bits > 0)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen output_r->service_uses_remote = TRUE;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if (config_filter_match_rest(mask, filter)) {
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (mask->local_bits > 0 || mask->local_name != NULL)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen output_r->used_local = TRUE;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen if (mask->remote_bits > 0)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen output_r->used_remote = TRUE;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen array_append(&matches, &ctx->parsers[i], 1);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen }
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen }
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen if (filter->service == NULL) {
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&service_names);
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen output_r->specific_services = array_idx(&service_names, 0);
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen }
194755bdfb97c07ca8b9df071099f68947b971e3Timo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen array_sort(&matches, config_filter_parser_cmp);
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&matches);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return array_idx(&matches, 0);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen}
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainenstruct config_filter_parser *const *
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainenconfig_filter_find_subset(struct config_filter_context *ctx,
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen const struct config_filter *filter)
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen{
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen ARRAY_TYPE(config_filter_parsers) matches;
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen struct config_filter tmp_mask;
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen unsigned int i;
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen t_array_init(&matches, 8);
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen for (i = 0; ctx->parsers[i] != NULL; i++) {
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen const struct config_filter *mask = &ctx->parsers[i]->filter;
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen if (filter->service != NULL) {
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen if (!config_filter_match_service(mask, filter))
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen continue;
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen }
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen tmp_mask = *mask;
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (filter->local_name == NULL)
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen tmp_mask.local_name = NULL;
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen if (filter->local_bits == 0)
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen tmp_mask.local_bits = 0;
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen if (filter->remote_bits == 0)
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen tmp_mask.remote_bits = 0;
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen if (config_filter_match_rest(&tmp_mask, filter))
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen array_append(&matches, &ctx->parsers[i], 1);
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen }
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen array_sort(&matches, config_filter_parser_cmp_rev);
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&matches);
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen return array_idx(&matches, 0);
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen}
c0787d6ab19f4a17ec08699d0bbc77f13a9b02a9Timo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenstatic bool
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_filter_is_superset(const struct config_filter *sup,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const struct config_filter *filter)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen{
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. */
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen if (sup->local_bits > filter->local_bits)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return FALSE;
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen if (sup->remote_bits > filter->remote_bits)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return FALSE;
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen if (sup->local_name != NULL && filter->local_name == NULL) {
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen i_warning("%s", sup->local_name);
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen return FALSE;
41942258112e4131de96b6a4399c1a8ac83a23cbTimo Sirainen }
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (sup->service != NULL && filter->service == NULL)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return FALSE;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return TRUE;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen}
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenstatic int
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainenconfig_module_parser_apply_changes(struct config_module_parser *dest,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const struct config_filter_parser *src,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen pool_t pool, const char **error_r)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen{
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen const char *conflict_key;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen unsigned int i;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen for (i = 0; dest[i].root != NULL; i++) {
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (settings_parser_apply_changes(dest[i].parser,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen src->parsers[i].parser, pool,
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen error_r == NULL ? NULL :
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen &conflict_key) < 0) {
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen i_assert(error_r != NULL);
13be7f7215efe02d020e9d823772861df98b82bdTimo Sirainen *error_r = t_strdup_printf("Conflict in setting %s "
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen "found from filter at %s", conflict_key,
13be7f7215efe02d020e9d823772861df98b82bdTimo Sirainen src->file_and_line);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return -1;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen }
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen }
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return 0;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen}
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainenint config_filter_parsers_get(struct config_filter_context *ctx, pool_t pool,
633a3da9d3e9a5befd3405f6651043a6bdd327cbTimo Sirainen const char *const *modules,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const struct config_filter *filter,
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen struct config_module_parser **parsers_r,
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct master_service_settings_output *output_r,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen const char **error_r)
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen{
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct config_filter_parser *const *src;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen struct config_module_parser *dest;
e376e08040b5f21ff79a15ae728d2532a34207f6Timo Sirainen const char *error = NULL, **error_p;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen unsigned int i, count;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
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
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 dest[i] = src[0]->parsers[i];
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen dest[i].parser =
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen settings_parser_dup(src[0]->parsers[i].parser, pool);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen }
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen /* apply the changes from rest of the matches */
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen for (i = 1; src[i] != NULL; i++) {
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen if (config_filter_is_superset(&src[i]->filter,
04ce187ba9c7c98b4f3fbaa833a2dc929e4281b8Timo Sirainen &src[i-1]->filter))
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen error_p = NULL;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen else
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen error_p = &error;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen if (config_module_parser_apply_changes(dest, src[i], pool,
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen error_p) < 0) {
e376e08040b5f21ff79a15ae728d2532a34207f6Timo Sirainen i_assert(error != NULL);
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen config_filter_parsers_free(dest);
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen *error_r = error;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return -1;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen }
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen }
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen *parsers_r = dest;
637ec4c33b4715737a41f7e58c9b6d1f693c27e2Timo Sirainen return 0;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen}
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainenvoid config_filter_parsers_free(struct config_module_parser *parsers)
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen{
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen unsigned int i;
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen
1cfdcb36985904eff281fc6d7ea2d13b3c375980Timo Sirainen for (i = 0; parsers[i].root != NULL; i++)
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen settings_parser_deinit(&parsers[i].parser);
6ed1e82824590b514201d9db84ba96bdfc832dd5Timo Sirainen}