doveadm-connection.c revision 5f5870385cff47efd2f58e7892f251cf13761528
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2010-2012 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ioloop.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "network.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "istream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ostream.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "array.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "str.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "llist.h"
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen#include "master-service.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "user-directory.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-host.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-host.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "director-request.h"
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen#include "director-connection.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "doveadm-connection.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include <unistd.h>
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen#define DOVEADM_PROTOCOL_VERSION_MAJOR 1
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen#define DOVEADM_HANDSHAKE "VERSION\tdirector-doveadm\t1\t0\n"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define MAX_VALID_VHOST_COUNT 1000
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct doveadm_connection {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct doveadm_connection *prev, *next;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct io *io;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct istream *input;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ostream *output;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director *dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int handshaked:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic struct doveadm_connection *doveadm_connections;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void doveadm_connection_deinit(struct doveadm_connection **_conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void doveadm_cmd_host_list(struct doveadm_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *const *hostp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen string_t *str = t_str_new(1024);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen array_foreach(mail_hosts_get(conn->dir->mail_hosts), hostp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_printfa(str, "%s\t%u\t%u\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_ip2addr(&(*hostp)->ip), (*hostp)->vhost_count,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (*hostp)->user_count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_append_c(str, '\n');
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send(conn->output, str_data(str), str_len(str));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainenstatic void doveadm_cmd_host_list_removed(struct doveadm_connection *conn)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen{
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen struct mail_host_list *orig_hosts_list;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen struct mail_host *const *orig_hosts, *const *cur_hosts;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen unsigned int i, j, orig_hosts_count, cur_hosts_count;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen string_t *str = t_str_new(1024);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen int ret;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen orig_hosts_list = mail_hosts_init();
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen (void)mail_hosts_parse_and_add(orig_hosts_list,
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen conn->dir->set->director_mail_servers);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen orig_hosts = array_get(mail_hosts_get(orig_hosts_list),
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen &orig_hosts_count);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen cur_hosts = array_get(mail_hosts_get(conn->dir->mail_hosts),
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen &cur_hosts_count);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen /* the hosts are sorted by IP */
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen for (i = j = 0; i < orig_hosts_count && j < cur_hosts_count; ) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen ret = net_ip_cmp(&orig_hosts[i]->ip, &cur_hosts[j]->ip);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (ret == 0)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen i++, j++;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen else if (ret > 0)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen j++;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen else {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen str_printfa(str, "%s\n",
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen net_ip2addr(&orig_hosts[i]->ip));
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen i++;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen for (; i < orig_hosts_count; i++)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen str_printfa(str, "%s\n", net_ip2addr(&orig_hosts[i]->ip));
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen str_append_c(str, '\n');
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen o_stream_send(conn->output, str_data(str), str_len(str));
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_hosts_deinit(&orig_hosts_list);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen}
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void doveadm_cmd_director_list(struct doveadm_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct director_host *const *hostp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen string_t *str = t_str_new(1024);
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen const char *type;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen bool left, right;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen array_foreach(&dir->dir_hosts, hostp) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen const struct director_host *host = *hostp;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen left = dir->left != NULL &&
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen director_connection_get_host(dir->left) == host;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen right = dir->right != NULL &&
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen director_connection_get_host(dir->right) == host;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (dir->self_host == host)
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen type = "self";
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen else if (left)
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen type = right ? "l+r" : "left";
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen else if (right)
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen type = "right";
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen else
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen type = "";
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen str_printfa(str, "%s\t%u\t%s\t%lu\n",
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen net_ip2addr(&host->ip), host->port, type,
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen (unsigned long)host->last_failed);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_append_c(str, '\n');
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send(conn->output, str_data(str), str_len(str));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendoveadm_cmd_host_set(struct doveadm_connection *conn, const char *line)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen struct director *dir = conn->dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char *const *args;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int vhost_count = -1U;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen args = t_strsplit(line, "\t");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (args[0] == NULL ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen net_addr2ip(args[0], &ip) < 0 ||
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (args[1] != NULL && str_to_uint(args[1], &vhost_count) < 0)) {
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen i_error("doveadm sent invalid HOST-SET parameters: %s", line);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (vhost_count > MAX_VALID_VHOST_COUNT && vhost_count != -1U) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send_str(conn->output, "vhost count too large\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen host = mail_host_lookup(dir->mail_hosts, &ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host == NULL)
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen host = mail_host_add_ip(dir->mail_hosts, &ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (vhost_count != -1U)
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen mail_host_set_vhost_count(dir->mail_hosts, host, vhost_count);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_update_host(dir, dir->self_host, NULL, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send(conn->output, "OK\n", 3);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendoveadm_cmd_host_remove(struct doveadm_connection *conn, const char *line)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ip_addr ip;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (net_addr2ip(line, &ip) < 0) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen i_error("doveadm sent invalid HOST-REMOVE parameters");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (host == NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send_str(conn->output, "NOTFOUND\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_remove_host(conn->dir, conn->dir->self_host,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen NULL, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send(conn->output, "OK\n", 3);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainenstatic void
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainendoveadm_cmd_host_flush_all(struct doveadm_connection *conn)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen{
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen struct mail_host *const *hostp;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen array_foreach(mail_hosts_get(conn->dir->mail_hosts), hostp) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_flush_host(conn->dir, conn->dir->self_host,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen NULL, *hostp);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen o_stream_send(conn->output, "OK\n", 3);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen}
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainenstatic bool
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainendoveadm_cmd_host_flush(struct doveadm_connection *conn, const char *line)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen{
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen struct mail_host *host;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen struct ip_addr ip;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (*line == '\0') {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen doveadm_cmd_host_flush_all(conn);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen return TRUE;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (net_addr2ip(line, &ip) < 0) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen i_error("doveadm sent invalid HOST-FLUSH parameters");
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen return FALSE;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (host == NULL)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen o_stream_send_str(conn->output, "NOTFOUND\n");
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen else {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen director_flush_host(conn->dir, conn->dir->self_host,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen NULL, host);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen o_stream_send(conn->output, "OK\n", 3);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen return TRUE;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen}
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainenstatic bool
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainendoveadm_cmd_user_lookup(struct doveadm_connection *conn, const char *line)
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen{
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen struct user *user;
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen struct mail_host *host;
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen unsigned int username_hash;
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen string_t *str = t_str_new(256);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen if (str_to_uint(line, &username_hash) < 0)
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen username_hash = user_directory_get_username_hash(line);
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen /* get user's current host */
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen user = user_directory_lookup(conn->dir->users, username_hash);
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen if (user == NULL)
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen str_append(str, "\t0");
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen else {
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen str_printfa(str, "%s\t%u", net_ip2addr(&user->host->ip),
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen user->timestamp +
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen conn->dir->set->director_user_expire);
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen }
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen /* get host if it wasn't in user directory */
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen host = mail_host_get_by_hash(conn->dir->mail_hosts, username_hash);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen if (host == NULL)
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen str_append(str, "\t");
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen else
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen str_printfa(str, "\t%s", net_ip2addr(&host->ip));
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen /* get host with default configuration */
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen host = mail_host_get_by_hash(conn->dir->orig_config_hosts,
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen username_hash);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen if (host == NULL)
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen str_append(str, "\t");
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen else
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen str_printfa(str, "\t%s\n", net_ip2addr(&host->ip));
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen o_stream_send(conn->output, str_data(str), str_len(str));
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen return TRUE;
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen}
b2024fa4e6ed39f9b5b6bb6c051f6d535fc0e011Timo Sirainen
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainenstatic bool
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainendoveadm_cmd_user_list(struct doveadm_connection *conn, const char *line)
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen{
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen struct user_directory_iter *iter;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen struct user *user;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen struct ip_addr ip;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen if (*line != '\0') {
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen if (net_addr2ip(line, &ip) < 0) {
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen i_error("doveadm sent invalid USER-LIST parameters");
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen return FALSE;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen }
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen } else {
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen ip.family = 0;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen }
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen iter = user_directory_iter_init(conn->dir->users);
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen while ((user = user_directory_iter_next(iter)) != NULL) {
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen if (ip.family == 0 ||
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen net_ip_compare(&ip, &user->host->ip)) T_BEGIN {
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen unsigned int expire_time = user->timestamp +
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen conn->dir->set->director_user_expire;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen o_stream_send_str(conn->output, t_strdup_printf(
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen "%u\t%u\t%s\n",
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen user->username_hash, expire_time,
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen net_ip2addr(&user->host->ip)));
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen } T_END;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen }
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen user_directory_iter_deinit(&iter);
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen o_stream_send(conn->output, "\n", 1);
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen return TRUE;
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen}
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic bool
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainendoveadm_cmd_user_move(struct doveadm_connection *conn, const char *line)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen unsigned int username_hash;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen const char *const *args;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct user *user;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct mail_host *host;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct ip_addr ip;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen args = t_strsplit(line, "\t");
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (args[0] == NULL || args[1] == NULL ||
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen net_addr2ip(args[1], &ip) < 0) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen i_error("doveadm sent invalid USER-MOVE parameters: %s", line);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return FALSE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (host == NULL) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen o_stream_send_str(conn->output, "NOTFOUND\n");
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return TRUE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (str_to_uint(args[0], &username_hash) < 0)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen username_hash = user_directory_get_username_hash(line);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen user = user_directory_lookup(conn->dir->users, username_hash);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen if (user != NULL && user->kill_state != USER_KILL_STATE_NONE) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen o_stream_send_str(conn->output, "TRYAGAIN\n");
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return TRUE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen director_move_user(conn->dir, conn->dir->self_host, NULL,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen username_hash, host);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen o_stream_send(conn->output, "OK\n", 3);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return TRUE;
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen}
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void doveadm_connection_input(struct doveadm_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen const char *line, *cmd, *args;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen bool ret = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->handshaked) {
d2cadbf5445156fc12988506279d51d0e53b0449Timo Sirainen if ((line = i_stream_read_next_line(conn->input)) == NULL) {
d2cadbf5445156fc12988506279d51d0e53b0449Timo Sirainen if (conn->input->eof || conn->input->stream_errno != 0)
d2cadbf5445156fc12988506279d51d0e53b0449Timo Sirainen doveadm_connection_deinit(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
d2cadbf5445156fc12988506279d51d0e53b0449Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (!version_string_verify(line, "director-doveadm",
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen DOVEADM_PROTOCOL_VERSION_MAJOR)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("doveadm not compatible with this server "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "(mixed old and new binaries?)");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen doveadm_connection_deinit(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->handshaked = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while ((line = i_stream_read_next_line(conn->input)) != NULL && ret) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen args = strchr(line, '\t');
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (args == NULL) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen cmd = line;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen args = "";
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen } else {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen cmd = t_strdup_until(line, args);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen args++;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (strcmp(cmd, "HOST-LIST") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen doveadm_cmd_host_list(conn);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen else if (strcmp(cmd, "HOST-LIST-REMOVED") == 0)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen doveadm_cmd_host_list_removed(conn);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen else if (strcmp(cmd, "DIRECTOR-LIST") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen doveadm_cmd_director_list(conn);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen else if (strcmp(cmd, "HOST-SET") == 0)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen ret = doveadm_cmd_host_set(conn, args);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen else if (strcmp(cmd, "HOST-REMOVE") == 0)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen ret = doveadm_cmd_host_remove(conn, args);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen else if (strcmp(cmd, "HOST-FLUSH") == 0)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen ret = doveadm_cmd_host_flush(conn, args);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen else if (strcmp(cmd, "USER-LOOKUP") == 0)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen ret = doveadm_cmd_user_lookup(conn, args);
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen else if (strcmp(cmd, "USER-LIST") == 0)
caa1fa99c79c568ce2e42477bc169e7024fb220bTimo Sirainen ret = doveadm_cmd_user_list(conn, args);
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen else if (strcmp(cmd, "USER-MOVE") == 0)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen ret = doveadm_cmd_user_move(conn, args);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("doveadm sent unknown command: %s", line);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = FALSE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (conn->input->eof || conn->input->stream_errno != 0 || !ret)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen doveadm_connection_deinit(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct doveadm_connection *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainendoveadm_connection_init(struct director *dir, int fd)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct doveadm_connection *conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn = i_new(struct doveadm_connection, 1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->fd = fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->dir = dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->input = i_stream_create_fd(conn->fd, 1024, FALSE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen conn->io = io_add(conn->fd, IO_READ, doveadm_connection_input, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send_str(conn->output, DOVEADM_HANDSHAKE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DLLIST_PREPEND(&doveadm_connections, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void doveadm_connection_deinit(struct doveadm_connection **_conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct doveadm_connection *conn = *_conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *_conn = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DLLIST_REMOVE(&doveadm_connections, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen io_remove(&conn->io);
bcbca4b66800f0fbfe2643a86d5a6b63d752454dTimo Sirainen i_stream_unref(&conn->input);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_unref(&conn->output);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (close(conn->fd) < 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("close(doveadm connection) failed: %m");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_free(conn);
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen master_service_client_connection_destroyed(master_service);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid doveadm_connections_deinit(void)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while (doveadm_connections != NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct doveadm_connection *conn = doveadm_connections;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen doveadm_connection_deinit(&conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}