Skip to content

Commit

Permalink
lib-master: Support validating config filters against requests
Browse files Browse the repository at this point in the history
Validation will sanitize the input request and drop any fields
that have no filter in config. E.g. if you have a local block
with name, and nothing else, then lip/rip will be dropped
from the request.
  • Loading branch information
cmouse authored and villesavolainen committed Mar 6, 2018
1 parent 424ca44 commit d93e71a
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/lib-master/Makefile.am
Expand Up @@ -4,6 +4,7 @@ noinst_LTLIBRARIES = libmaster.la

AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-dns \
-I$(top_srcdir)/src/lib-test \
-I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-ssl-iostream \
Expand Down Expand Up @@ -58,6 +59,7 @@ noinst_PROGRAMS = $(test_programs)

test_libs = \
../lib-test/libtest.la \
../lib-dns/libdns.la \
../lib/liblib.la

test_deps = $(noinst_LTLIBRARIES) $(test_libs)
Expand Down
90 changes: 90 additions & 0 deletions src/lib-master/master-service-settings-cache.c
@@ -1,9 +1,11 @@
/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "wildcard-match.h"
#include "hash.h"
#include "llist.h"
#include "settings-parser.h"
#include "dns-util.h"
#include "master-service-private.h"
#include "master-service-settings.h"
#include "master-service-settings-cache.h"
Expand All @@ -12,6 +14,14 @@
#define CACHE_INITIAL_ENTRY_POOL_SIZE (1024*16)
#define CACHE_ADD_ENTRY_POOL_SIZE 1024

struct config_filter {
struct config_filter *prev, *next;

const char *local_name;
struct ip_addr local_ip, remote_ip;
unsigned int local_bits, remote_bits;
};

struct settings_entry {
struct settings_entry *prev, *next;

Expand Down Expand Up @@ -41,6 +51,8 @@ struct master_service_settings_cache {
HASH_TABLE(char *, struct settings_entry *) local_name_hash;
HASH_TABLE(struct ip_addr *, struct settings_entry *) local_ip_hash;

struct config_filter *filters;

/* Initial size for new settings entry pools */
size_t approx_entry_pool_size;
/* number of bytes malloced by cached settings entries
Expand Down Expand Up @@ -70,6 +82,78 @@ master_service_settings_cache_init(struct master_service *service,
return cache;
}

int master_service_settings_cache_init_filter(struct master_service_settings_cache *cache)
{
const char *const *filters;
const char *error;

if (cache->filters != NULL)
return 0;
if (master_service_settings_get_filters(cache->service, &filters, &error) < 0) {
i_error("master-service: cannot get filters: %s", error);
return -1;
}

/* parse filters */
while(*filters != NULL) {
const char *const *keys = t_strsplit_spaces(*filters, " ");
struct config_filter *filter =
p_new(cache->pool, struct config_filter, 1);
while(*keys != NULL) {
if (strncmp(*keys, "local-net=", 10) == 0) {
(void)net_parse_range((*keys)+10,
&filter->local_ip, &filter->local_bits);
} else if (strncmp(*keys, "remote-net=", 11) == 0) {
(void)net_parse_range((*keys)+11,
&filter->remote_ip, &filter->remote_bits);
} else if (strncmp(*keys, "local-name=", 11) == 0) {
filter->local_name = p_strdup(cache->pool, (*keys)+11);
}
keys++;
}
DLLIST_PREPEND(&cache->filters, filter);
filters++;
}
return 0;
}

/* Remove any elements which there is no filter for */
static void
master_service_settings_cache_fix_input(struct master_service_settings_cache *cache,
const struct master_service_settings_input *input,
struct master_service_settings_input *new_input)
{
bool found_lip, found_rip, found_local_name;

found_lip = found_rip = found_local_name = FALSE;

struct config_filter *filter = cache->filters;
while(filter != NULL) {
if (filter->local_bits > 0 &&
net_is_in_network(&input->local_ip, &filter->local_ip,
filter->local_bits))
found_lip = TRUE;
if (filter->remote_bits > 0 &&
net_is_in_network(&input->remote_ip, &filter->remote_ip,
filter->remote_bits))
found_rip = TRUE;
if (filter->local_name != NULL &&
dns_match_wildcard(input->local_name, filter->local_name))
found_local_name = TRUE;
filter = filter->next;
};

*new_input = *input;

if (!found_lip)
i_zero(&new_input->local_ip);
if (!found_rip)
i_zero(&new_input->remote_ip);
if (!found_local_name)
new_input->local_name = NULL;
}


void master_service_settings_cache_deinit(struct master_service_settings_cache **_cache)
{
struct master_service_settings_cache *cache = *_cache;
Expand Down Expand Up @@ -273,6 +357,12 @@ int master_service_settings_cache_read(struct master_service_settings_cache *cac
return 0;

new_input = *input;
if (cache->filters != NULL) {
master_service_settings_cache_fix_input(cache, input, &new_input);
if (cache_find(cache, &new_input, parser_r))
return 0;
}

if (dyn_parsers != NULL) {
settings_parser_dyn_update(cache->pool, &new_input.roots,
dyn_parsers);
Expand Down
2 changes: 1 addition & 1 deletion src/lib-master/master-service-settings-cache.h
Expand Up @@ -6,7 +6,7 @@ master_service_settings_cache_init(struct master_service *service,
const char *module,
const char *service_name);
void master_service_settings_cache_deinit(struct master_service_settings_cache **cache);

int master_service_settings_cache_init_filter(struct master_service_settings_cache *cache);
int master_service_settings_cache_read(struct master_service_settings_cache *cache,
const struct master_service_settings_input *input,
const struct dynamic_settings_parser *dyn_parsers,
Expand Down
60 changes: 60 additions & 0 deletions src/lib-master/master-service-settings.c
Expand Up @@ -341,6 +341,18 @@ config_send_request(struct master_service *service,
return 0;
}

static int
config_send_filters_request(int fd, const char *path, const char **error_r)
{
int ret;
ret = write_full(fd, CONFIG_HANDSHAKE"FILTERS\n", strlen(CONFIG_HANDSHAKE"FILTERS\n"));
if (ret < 0) {
*error_r = t_strdup_printf("write_full(%s) failed: %m", path);
return -1;
}
return 0;
}

static int
master_service_apply_config_overrides(struct master_service *service,
struct setting_parser_context *parser,
Expand Down Expand Up @@ -437,6 +449,54 @@ void master_service_config_socket_try_open(struct master_service *service)
service->config_fd = fd;
}

int master_service_settings_get_filters(struct master_service *service,
const char *const **filters,
const char **error_r)
{
struct master_service_settings_input input;
int fd;
bool retry = TRUE;
const char *path = NULL;
ARRAY_TYPE(const_string) filters_tmp;
t_array_init(&filters_tmp, 8);
i_zero(&input);

if (getenv("DOVECONF_ENV") == NULL &&
(service->flags & MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS) == 0) {
retry = service->config_fd != -1;
for (;;) {
fd = master_service_open_config(service, &input, &path, error_r);
if (fd == -1) {
return -1;
}
if (config_send_filters_request(fd, path, error_r) == 0)
break;

i_close_fd(&fd);
if (!retry)
return -1;
retry = FALSE;
}
service->config_fd = fd;
struct istream *is = i_stream_create_fd(fd, (size_t)-1);
const char *line;
/* try read response */
while((line = i_stream_read_next_line(is)) != NULL) {
if (*line == '\0')
break;
if (strncmp(line, "FILTER\t", 7) == 0) {
line = t_strdup(line+7);
array_append(&filters_tmp, &line, 1);
}
}
i_stream_unref(&is);
}

array_append_zero(&filters_tmp);
*filters = array_idx(&filters_tmp, 0);
return 0;
}

int master_service_settings_read(struct master_service *service,
const struct master_service_settings_input *input,
struct master_service_settings_output *output_r,
Expand Down
3 changes: 3 additions & 0 deletions src/lib-master/master-service-settings.h
Expand Up @@ -69,6 +69,9 @@ extern const struct setting_parser_info master_service_setting_parser_info;
/* Try to open the config socket if it's going to be needed later by
master_service_settings_read*() */
void master_service_config_socket_try_open(struct master_service *service);
int master_service_settings_get_filters(struct master_service *service,
const char *const **filters,
const char **error_r);
int master_service_settings_read(struct master_service *service,
const struct master_service_settings_input *input,
struct master_service_settings_output *output_r,
Expand Down
8 changes: 8 additions & 0 deletions src/lib-master/test-master-service-settings-cache.c
Expand Up @@ -53,6 +53,14 @@ int master_service_settings_read(struct master_service *service ATTR_UNUSED,
return 0;
}

int master_service_settings_get_filters(struct master_service *service ATTR_UNUSED,
const char *const **filters ATTR_UNUSED,
const char **error_r ATTR_UNUSED)
{
return -1;
}


const struct master_service_settings *
master_service_settings_get(struct master_service *service ATTR_UNUSED)
{
Expand Down

0 comments on commit d93e71a

Please sign in to comment.