doveadm-connection.c revision 892e25e1c0caad62ced087d9eba2741a59e3d9ce
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "lib.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ioloop.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "net.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "istream.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ostream.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "array.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "str.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "strescape.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "llist.h"
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen#include "master-service.h"
fb08a91e3f2949ecefb647fa38206ca9aad5307fTimo Sirainen#include "user-directory.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "mail-host.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "director.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "director-host.h"
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen#include "director-request.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "director-connection.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "doveadm-connection.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d0720f3037064af4b92eccfc20a8814adcacf827Timo Sirainen#include <unistd.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen#define DOVEADM_PROTOCOL_VERSION_MAJOR 1
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen#define DOVEADM_HANDSHAKE "VERSION\tdirector-doveadm\t1\t0\n"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen#define MAX_VALID_VHOST_COUNT 1000
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainenstruct doveadm_connection {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct doveadm_connection *prev, *next;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen int fd;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen struct io *io;
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen struct istream *input;
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen struct ostream *output;
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen struct director *dir;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
c0e5c6a86e1de5d4f5591d39b4aa921a23c807d7Timo Sirainen bool handshaked:1;
c0e5c6a86e1de5d4f5591d39b4aa921a23c807d7Timo Sirainen};
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainenstatic struct doveadm_connection *doveadm_connections;
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainenstatic void doveadm_connection_deinit(struct doveadm_connection **_conn);
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainenstatic void doveadm_cmd_host_list(struct doveadm_connection *conn)
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen{
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen struct mail_host *const *hostp;
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen string_t *str = t_str_new(1024);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen array_foreach(mail_hosts_get(conn->dir->mail_hosts), hostp) {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen str_printfa(str, "%s\t%u\t%u\t",
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen net_ip2addr(&(*hostp)->ip), (*hostp)->vhost_count,
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen (*hostp)->user_count);
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen str_append_tabescaped(str, mail_host_get_tag(*hostp));
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen str_printfa(str, "\t%c\t%ld", (*hostp)->down ? 'D' : 'U',
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen (long)(*hostp)->last_updown_change);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen str_append_c(str, '\n');
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen }
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen str_append_c(str, '\n');
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen o_stream_nsend(conn->output, str_data(str), str_len(str));
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen}
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainenstatic void doveadm_cmd_host_list_removed(struct doveadm_connection *conn)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen{
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen struct mail_host_list *orig_hosts_list;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen struct mail_host *const *orig_hosts, *const *cur_hosts;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen unsigned int i, j, orig_hosts_count, cur_hosts_count;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen string_t *str = t_str_new(1024);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen int ret;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen orig_hosts_list = mail_hosts_init(conn->dir->set->director_consistent_hashing);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen (void)mail_hosts_parse_and_add(orig_hosts_list,
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen conn->dir->set->director_mail_servers);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen orig_hosts = array_get(mail_hosts_get(orig_hosts_list),
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen &orig_hosts_count);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen cur_hosts = array_get(mail_hosts_get(conn->dir->mail_hosts),
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen &cur_hosts_count);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* the hosts are sorted by IP */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen for (i = j = 0; i < orig_hosts_count && j < cur_hosts_count; ) {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen ret = net_ip_cmp(&orig_hosts[i]->ip, &cur_hosts[j]->ip);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (ret == 0)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen i++, j++;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen else if (ret > 0)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen j++;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen else {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen str_printfa(str, "%s\n",
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen net_ip2addr(&orig_hosts[i]->ip));
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen i++;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen }
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen }
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen for (; i < orig_hosts_count; i++)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen str_printfa(str, "%s\n", net_ip2addr(&orig_hosts[i]->ip));
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen str_append_c(str, '\n');
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen o_stream_nsend(conn->output, str_data(str), str_len(str));
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen mail_hosts_deinit(&orig_hosts_list);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen}
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
c0e5c6a86e1de5d4f5591d39b4aa921a23c807d7Timo Sirainenstatic void doveadm_director_append_status(struct director *dir, string_t *str)
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen{
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (!dir->ring_handshaked)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen str_append(str, "handshaking");
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen else if (dir->ring_synced)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen str_append(str, "synced");
c05d0937e228c2817fa2295fc53e8cb81ae5cb8aTimo Sirainen else {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen str_printfa(str, "syncing - last sync %d secs ago",
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen (int)(ioloop_time - dir->ring_last_sync_time));
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen }
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen}
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainendoveadm_director_connection_append_status(struct director_connection *conn,
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen string_t *str)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen{
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen if (!director_connection_is_handshaked(conn))
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen str_append(str, "handshaking");
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen else if (director_connection_is_synced(conn))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, "synced");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(str, "syncing");
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainendoveadm_director_host_append_status(struct director *dir,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct director_host *host,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen string_t *str)
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct director_connection *conn = NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (dir->left != NULL &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen director_connection_get_host(dir->left) == host)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn = dir->left;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else if (dir->right != NULL &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen director_connection_get_host(dir->right) == host)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn = dir->right;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen /* we might have a connection that is being connected */
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen struct director_connection *const *connp;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_foreach(&dir->connections, connp) {
f6edc54aa72596af8da681c07223108c322712d5Timo Sirainen if (director_connection_get_host(*connp) == host) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn = *connp;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen if (conn != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen doveadm_director_connection_append_status(conn, str);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainenstatic void doveadm_cmd_director_list(struct doveadm_connection *conn)
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct director *dir = conn->dir;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen struct director_host *const *hostp;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen string_t *str = t_str_new(1024);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *type;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen bool left, right;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen time_t last_failed;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen array_foreach(&dir->dir_hosts, hostp) {
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen const struct director_host *host = *hostp;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen left = dir->left != NULL &&
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen director_connection_get_host(dir->left) == host;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen right = dir->right != NULL &&
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen director_connection_get_host(dir->right) == host;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen if (host->removed)
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen type = "removed";
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen else if (dir->self_host == host)
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen type = "self";
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen else if (left)
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen type = right ? "l+r" : "left";
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen else if (right)
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen type = "right";
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen else
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen type = "";
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen last_failed = I_MAX(host->last_network_failure,
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen host->last_protocol_failure);
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen str_printfa(str, "%s\t%u\t%s\t%lu\t",
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen net_ip2addr(&host->ip), host->port, type,
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen (unsigned long)last_failed);
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen if (dir->self_host == host)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen doveadm_director_append_status(dir, str);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen doveadm_director_host_append_status(dir, host, str);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append_c(str, '\n');
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append_c(str, '\n');
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen o_stream_nsend(conn->output, str_data(str), str_len(str));
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen}
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainendoveadm_cmd_director_add(struct doveadm_connection *conn,
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen const char *const *args)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen{
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen struct director_host *host;
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen struct ip_addr ip;
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen in_port_t port = conn->dir->self_port;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (args[0] == NULL ||
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen net_addr2ip(args[0], &ip) < 0 ||
dadd250347d90d90bd65f529d45b50f79d6a0674Timo Sirainen (args[1] != NULL && net_str2port(args[1], &port) < 0)) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen i_error("doveadm sent invalid DIRECTOR-ADD parameters");
699b27536eeb446e05ed9c9c1ab35cc6174ac0aaTimo Sirainen return -1;
dadd250347d90d90bd65f529d45b50f79d6a0674Timo Sirainen }
699b27536eeb446e05ed9c9c1ab35cc6174ac0aaTimo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (director_host_lookup(conn->dir, &ip, port) == NULL) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen host = director_host_add(conn->dir, &ip, port);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen director_notify_ring_added(host, conn->dir->self_host);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen o_stream_nsend(conn->output, "OK\n", 3);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return 1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainenstatic int
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainendoveadm_cmd_director_remove(struct doveadm_connection *conn,
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen const char *const *args)
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen{
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen struct director_host *host;
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen struct ip_addr ip;
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen in_port_t port = 0;
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen if (args[0] == NULL ||
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen net_addr2ip(args[0], &ip) < 0 ||
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen (args[1] != NULL && net_str2port(args[1], &port) < 0)) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen i_error("doveadm sent invalid DIRECTOR-REMOVE parameters");
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen host = port != 0 ?
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen director_host_lookup(conn->dir, &ip, port) :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen director_host_lookup_ip(conn->dir, &ip);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (host == NULL)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen o_stream_nsend_str(conn->output, "NOTFOUND\n");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen director_ring_remove(host, conn->dir->self_host);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen o_stream_nsend(conn->output, "OK\n", 3);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainendoveadm_cmd_host_set_or_update(struct doveadm_connection *conn,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *const *args, bool update)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct director *dir = conn->dir;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen const char *ip_str, *tag = "";
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen struct mail_host *host;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen struct ip_addr ip;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen unsigned int vhost_count = UINT_MAX;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen ip_str = args[0];
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen if (ip_str != NULL) {
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen tag = strchr(ip_str, '@');
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen if (tag == NULL)
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen tag = "";
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen else
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen ip_str = t_strdup_until(ip_str, tag++);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen if (ip_str == NULL || net_addr2ip(ip_str, &ip) < 0 ||
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen (args[1] != NULL && str_to_uint(args[1], &vhost_count) < 0) ||
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen (args[1] == NULL && update)) {
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen i_error("doveadm sent invalid %s parameters",
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen update ? "HOST-UPDATE" : "HOST-SET");
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen return -1;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen }
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen if (vhost_count > MAX_VALID_VHOST_COUNT && vhost_count != UINT_MAX) {
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen o_stream_nsend_str(conn->output, "vhost count too large\n");
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen return 1;
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen host = mail_host_lookup(dir->mail_hosts, &ip);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (host == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (update) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen o_stream_nsend_str(conn->output, "NOTFOUND\n");
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen return 1;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen host = mail_host_add_ip(dir->mail_hosts, &ip, tag);
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen } else if (tag[0] != '\0' && strcmp(mail_host_get_tag(host), tag) != 0) {
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen o_stream_nsend_str(conn->output, "host tag can't be changed\n");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (host->desynced) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen o_stream_nsend_str(conn->output,
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen "host is already being updated - try again later\n");
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen return 1;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen }
f7f13e206c9839f6e868088034b0b59d1d9be13aTimo Sirainen if (vhost_count != UINT_MAX)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_host_set_vhost_count(host, vhost_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* NOTE: we don't support changing a tag for an existing host.
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen it needs to be removed first. otherwise it would be a bit ugly to
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen handle. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen director_update_host(dir, dir->self_host, NULL, host);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen o_stream_nsend(conn->output, "OK\n", 3);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen return 1;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainendoveadm_cmd_host_set(struct doveadm_connection *conn, const char *const *args)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen return doveadm_cmd_host_set_or_update(conn, args, FALSE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainendoveadm_cmd_host_update(struct doveadm_connection *conn, const char *const *args)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return doveadm_cmd_host_set_or_update(conn, args, TRUE);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainendoveadm_cmd_host_updown(struct doveadm_connection *conn, bool down,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const char *const *args)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct mail_host *host;
3005627bf2ed223194c2d08a8c1630769d048f69Timo Sirainen struct ip_addr ip;
3005627bf2ed223194c2d08a8c1630769d048f69Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (args[0] == NULL || net_addr2ip(args[0], &ip) < 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("doveadm sent invalid %s parameters: %s",
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen down ? "HOST-DOWN" : "HOST-UP",
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen args[0] == NULL ? "" : args[0]);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (host == NULL) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen o_stream_nsend_str(conn->output, "NOTFOUND\n");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (host->down == down)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen else if (host->desynced) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen o_stream_nsend_str(conn->output,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "host is already being updated - try again later\n");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen mail_host_set_down(host, down, ioloop_time);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen director_update_host(conn->dir, conn->dir->self_host,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen NULL, host);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen o_stream_nsend(conn->output, "OK\n", 3);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainendoveadm_cmd_host_remove(struct doveadm_connection *conn,
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen const char *const *args)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen{
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen struct mail_host *host;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen struct ip_addr ip;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (args[0] == NULL || net_addr2ip(args[0], &ip) < 0) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen i_error("doveadm sent invalid HOST-REMOVE parameters");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen }
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (host == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen o_stream_nsend_str(conn->output, "NOTFOUND\n");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen director_remove_host(conn->dir, conn->dir->self_host,
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen NULL, host);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen o_stream_nsend(conn->output, "OK\n", 3);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen }
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen return 1;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen}
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainenstatic void
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainendoveadm_cmd_host_flush_all(struct doveadm_connection *conn)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen struct mail_host *const *hostp;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen unsigned int total_user_count = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_foreach(mail_hosts_get(conn->dir->mail_hosts), hostp) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen total_user_count += (*hostp)->user_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen director_flush_host(conn->dir, conn->dir->self_host,
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainen NULL, *hostp);
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainen }
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainen i_warning("Flushed all backend hosts with %u users. This is an unsafe "
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainen "operation and may cause the same users to end up in multiple backends.",
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainen total_user_count);
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainen o_stream_nsend(conn->output, "OK\n", 3);
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainen}
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainen
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainenstatic int
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainendoveadm_cmd_host_flush(struct doveadm_connection *conn, const char *const *args)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_host *host;
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen struct ip_addr ip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (args[0] == NULL || args[0][0] == '\0') {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen doveadm_cmd_host_flush_all(conn);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (net_addr2ip(args[0], &ip) < 0) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen i_error("doveadm sent invalid HOST-FLUSH parameters");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen if (host == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen o_stream_nsend_str(conn->output, "NOTFOUND\n");
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen director_flush_host(conn->dir, conn->dir->self_host,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen NULL, host);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen o_stream_nsend(conn->output, "OK\n", 3);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainendirector_host_reset_users(struct director *dir, struct director_host *src,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct mail_host *host)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct user_directory_iter *iter;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct user *user;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_host *new_host;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (dir->right != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen director_connection_cork(dir->right);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen iter = user_directory_iter_init(dir->users);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen while ((user = user_directory_iter_next(iter)) != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (user->host != host)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen continue;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen new_host = mail_host_get_by_hash(dir->mail_hosts,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen user->username_hash,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_host_get_tag(host));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (new_host != host) T_BEGIN {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen director_move_user(dir, src, NULL,
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainen user->username_hash, new_host);
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainen } T_END;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainen user_directory_iter_deinit(&iter);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (dir->right != NULL)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen director_connection_uncork(dir->right);
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainen}
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainenstatic void
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainendoveadm_cmd_host_reset_users_all(struct doveadm_connection *conn)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen{
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen struct mail_host *const *hostp;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_foreach(mail_hosts_get(conn->dir->mail_hosts), hostp)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen director_host_reset_users(conn->dir, conn->dir->self_host, *hostp);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen o_stream_nsend(conn->output, "OK\n", 3);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainendoveadm_cmd_host_reset_users(struct doveadm_connection *conn,
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen const char *const *args)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_host *host;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct ip_addr ip;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (args[0] == NULL || args[0][0] == '\0') {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen doveadm_cmd_host_reset_users_all(conn);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (net_addr2ip(args[0], &ip) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("doveadm sent invalid HOST-RESET-USERS parameters");
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainen host = mail_host_lookup(conn->dir->mail_hosts, &ip);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (host == NULL)
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen o_stream_nsend_str(conn->output, "NOTFOUND\n");
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen else {
57dc3cb5d5e315272353abf55f702eefc084db26Timo Sirainen director_host_reset_users(conn->dir, conn->dir->self_host, host);
57dc3cb5d5e315272353abf55f702eefc084db26Timo Sirainen o_stream_nsend(conn->output, "OK\n", 3);
57dc3cb5d5e315272353abf55f702eefc084db26Timo Sirainen }
57dc3cb5d5e315272353abf55f702eefc084db26Timo Sirainen return 1;
57dc3cb5d5e315272353abf55f702eefc084db26Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainendoveadm_cmd_user_lookup(struct doveadm_connection *conn,
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainen const char *const *args)
2b2e5f7a24c24d971351877ad4c5150662856bfbTimo Sirainen{
601b455f4d5e780044b9e4fac5f687c1b07ae145Timo Sirainen struct user *user;
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen struct mail_host *host;
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen const char *username, *tag;
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen unsigned int username_hash;
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen string_t *str = t_str_new(256);
57dc3cb5d5e315272353abf55f702eefc084db26Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (args[0] == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen username = "";
tag = "";
} else {
username = args[0];
tag = args[1] != NULL ? args[1] : "";
}
if (str_to_uint(username, &username_hash) < 0)
username_hash = user_directory_get_username_hash(conn->dir->users, username);
/* get user's current host */
user = user_directory_lookup(conn->dir->users, username_hash);
if (user == NULL)
str_append(str, "\t0");
else {
str_printfa(str, "%s\t%u", net_ip2addr(&user->host->ip),
user->timestamp +
conn->dir->set->director_user_expire);
}
/* get host if it wasn't in user directory */
host = mail_host_get_by_hash(conn->dir->mail_hosts, username_hash, tag);
if (host == NULL)
str_append(str, "\t");
else
str_printfa(str, "\t%s", net_ip2addr(&host->ip));
/* get host with default configuration */
host = mail_host_get_by_hash(conn->dir->orig_config_hosts,
username_hash, tag);
if (host == NULL)
str_append(str, "\t\n");
else
str_printfa(str, "\t%s\n", net_ip2addr(&host->ip));
o_stream_nsend(conn->output, str_data(str), str_len(str));
return 1;
}
static int
doveadm_cmd_user_list(struct doveadm_connection *conn, const char *const *args)
{
struct user_directory_iter *iter;
struct user *user;
struct ip_addr ip;
if (args[0] != NULL && args[0][0] != '\0') {
if (net_addr2ip(args[0], &ip) < 0) {
i_error("doveadm sent invalid USER-LIST parameters");
return -1;
}
} else {
ip.family = 0;
}
iter = user_directory_iter_init(conn->dir->users);
while ((user = user_directory_iter_next(iter)) != NULL) {
if (ip.family == 0 ||
net_ip_compare(&ip, &user->host->ip)) T_BEGIN {
unsigned int expire_time = user->timestamp +
conn->dir->set->director_user_expire;
o_stream_nsend_str(conn->output, t_strdup_printf(
"%u\t%u\t%s\n",
user->username_hash, expire_time,
net_ip2addr(&user->host->ip)));
} T_END;
}
user_directory_iter_deinit(&iter);
o_stream_nsend(conn->output, "\n", 1);
return 1;
}
static int
doveadm_cmd_user_move(struct doveadm_connection *conn, const char *const *args)
{
unsigned int username_hash;
struct user *user;
struct mail_host *host;
struct ip_addr ip;
if (args[0] == NULL || args[1] == NULL ||
net_addr2ip(args[1], &ip) < 0) {
i_error("doveadm sent invalid USER-MOVE parameters");
return -1;
}
host = mail_host_lookup(conn->dir->mail_hosts, &ip);
if (host == NULL) {
o_stream_nsend_str(conn->output, "NOTFOUND\n");
return 1;
}
if (str_to_uint(args[0], &username_hash) < 0)
username_hash = user_directory_get_username_hash(conn->dir->users, args[0]);
user = user_directory_lookup(conn->dir->users, username_hash);
if (user != NULL && user->kill_state != USER_KILL_STATE_NONE) {
o_stream_nsend_str(conn->output, "TRYAGAIN\n");
return 1;
}
director_move_user(conn->dir, conn->dir->self_host, NULL,
username_hash, host);
o_stream_nsend(conn->output, "OK\n", 3);
return 1;
}
static int
doveadm_cmd_user_kick(struct doveadm_connection *conn, const char *const *args)
{
if (args[0] == NULL) {
i_error("doveadm sent invalid USER-KICK parameters");
return -1;
}
director_kick_user(conn->dir, conn->dir->self_host, NULL, args[0]);
o_stream_nsend(conn->output, "OK\n", 3);
return 1;
}
static int
doveadm_connection_cmd(struct doveadm_connection *conn, const char *line)
{
const char *cmd, *const *args;
int ret = 1;
args = t_strsplit_tabescaped(line);
if (args[0] == NULL) {
i_error("doveadm sent empty command line");
return -1;
}
cmd = args[0];
args++;
if (strcmp(cmd, "HOST-LIST") == 0)
doveadm_cmd_host_list(conn);
else if (strcmp(cmd, "HOST-LIST-REMOVED") == 0)
doveadm_cmd_host_list_removed(conn);
else if (strcmp(cmd, "DIRECTOR-LIST") == 0)
doveadm_cmd_director_list(conn);
else if (strcmp(cmd, "DIRECTOR-ADD") == 0)
ret = doveadm_cmd_director_add(conn, args);
else if (strcmp(cmd, "DIRECTOR-REMOVE") == 0)
ret = doveadm_cmd_director_remove(conn, args);
else if (strcmp(cmd, "HOST-SET") == 0)
ret = doveadm_cmd_host_set(conn, args);
else if (strcmp(cmd, "HOST-UPDATE") == 0)
ret = doveadm_cmd_host_update(conn, args);
else if (strcmp(cmd, "HOST-UP") == 0)
ret = doveadm_cmd_host_updown(conn, FALSE, args);
else if (strcmp(cmd, "HOST-DOWN") == 0)
ret = doveadm_cmd_host_updown(conn, TRUE, args);
else if (strcmp(cmd, "HOST-REMOVE") == 0)
ret = doveadm_cmd_host_remove(conn, args);
else if (strcmp(cmd, "HOST-FLUSH") == 0)
ret = doveadm_cmd_host_flush(conn, args);
else if (strcmp(cmd, "HOST-RESET-USERS") == 0)
ret = doveadm_cmd_host_reset_users(conn, args);
else if (strcmp(cmd, "USER-LOOKUP") == 0)
ret = doveadm_cmd_user_lookup(conn, args);
else if (strcmp(cmd, "USER-LIST") == 0)
ret = doveadm_cmd_user_list(conn, args);
else if (strcmp(cmd, "USER-MOVE") == 0)
ret = doveadm_cmd_user_move(conn, args);
else if (strcmp(cmd, "USER-KICK") == 0)
ret = doveadm_cmd_user_kick(conn, args);
else {
i_error("doveadm sent unknown command: %s", line);
ret = -1;
}
return ret;
}
static void doveadm_connection_input(struct doveadm_connection *conn)
{
const char *line;
int ret = 1;
if (!conn->handshaked) {
if ((line = i_stream_read_next_line(conn->input)) == NULL) {
if (conn->input->eof || conn->input->stream_errno != 0)
doveadm_connection_deinit(&conn);
return;
}
if (!version_string_verify(line, "director-doveadm",
DOVEADM_PROTOCOL_VERSION_MAJOR)) {
i_error("doveadm not compatible with this server "
"(mixed old and new binaries?)");
doveadm_connection_deinit(&conn);
return;
}
conn->handshaked = TRUE;
}
while ((line = i_stream_read_next_line(conn->input)) != NULL && ret > 0) {
T_BEGIN {
ret = doveadm_connection_cmd(conn, line);
} T_END;
}
if (conn->input->eof || conn->input->stream_errno != 0 || ret < 0)
doveadm_connection_deinit(&conn);
}
struct doveadm_connection *
doveadm_connection_init(struct director *dir, int fd)
{
struct doveadm_connection *conn;
conn = i_new(struct doveadm_connection, 1);
conn->fd = fd;
conn->dir = dir;
conn->input = i_stream_create_fd(conn->fd, 1024);
conn->output = o_stream_create_fd(conn->fd, (size_t)-1);
o_stream_set_no_error_handling(conn->output, TRUE);
conn->io = io_add(conn->fd, IO_READ, doveadm_connection_input, conn);
o_stream_nsend_str(conn->output, DOVEADM_HANDSHAKE);
DLLIST_PREPEND(&doveadm_connections, conn);
return conn;
}
static void doveadm_connection_deinit(struct doveadm_connection **_conn)
{
struct doveadm_connection *conn = *_conn;
*_conn = NULL;
DLLIST_REMOVE(&doveadm_connections, conn);
io_remove(&conn->io);
i_stream_unref(&conn->input);
o_stream_unref(&conn->output);
if (close(conn->fd) < 0)
i_error("close(doveadm connection) failed: %m");
i_free(conn);
master_service_client_connection_destroyed(master_service);
}
void doveadm_connections_deinit(void)
{
while (doveadm_connections != NULL) {
struct doveadm_connection *conn = doveadm_connections;
doveadm_connection_deinit(&conn);
}
}