doveadm-connection.c revision 2670cd577aa57eb9f915a4f4220ae48c9b4fc5fb
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "ioloop.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "network.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "istream.h"
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen#include "ostream.h"
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen#include "array.h"
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen#include "str.h"
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen#include "llist.h"
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen#include "user-directory.h"
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen#include "mail-host.h"
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen#include "director.h"
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen#include "director-host.h"
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen#include "director-request.h"
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen#include "doveadm-connection.h"
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen#include <unistd.h>
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen#define DOVEADM_HANDSHAKE_EXPECTED "VERSION\tdirector-doveadm\t1\t"
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen#define DOVEADM_HANDSHAKE DOVEADM_HANDSHAKE_EXPECTED"0\n"
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen#define MAX_VALID_VHOST_COUNT 1000
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainenstruct doveadm_connection {
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen struct doveadm_connection *prev, *next;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen int fd;
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen struct io *io;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen struct istream *input;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen struct ostream *output;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen struct director *dir;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int handshaked:1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic struct doveadm_connection *doveadm_connections;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenstatic void doveadm_connection_deinit(struct doveadm_connection **_conn);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenstatic void doveadm_cmd_host_list(struct doveadm_connection *conn)
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen{
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen struct mail_host *const *hostp;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen string_t *str = t_str_new(1024);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen array_foreach(mail_hosts_get(), hostp) {
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen str_printfa(str, "%s\t%u\t%u\n",
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen net_ip2addr(&(*hostp)->ip), (*hostp)->vhost_count,
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen (*hostp)->user_count);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen }
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen str_append_c(str, '\n');
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen o_stream_send(conn->output, str_data(str), str_len(str));
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen}
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenstatic void doveadm_cmd_director_list(struct doveadm_connection *conn)
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen{
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen struct director_host *const *hostp;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen string_t *str = t_str_new(1024);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen array_foreach(&conn->dir->dir_hosts, hostp) {
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen str_printfa(str, "%s\t%u\n",
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen net_ip2addr(&(*hostp)->ip), (*hostp)->port);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen str_append_c(str, '\n');
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send(conn->output, str_data(str), str_len(str));
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen}
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainenstatic bool
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainendoveadm_cmd_host_set(struct doveadm_connection *conn, const char *line)
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen const char *const *args;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen struct mail_host *host;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen struct ip_addr ip;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen unsigned int vhost_count = -1U;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen args = t_strsplit(line, "\t");
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (args[0] == NULL ||
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen net_addr2ip(args[0], &ip) < 0 ||
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen (args[1] != NULL && str_to_uint(args[1], &vhost_count) < 0)) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_error("doveadm sent invalid HOST-SET parameters");
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen return FALSE;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (vhost_count > MAX_VALID_VHOST_COUNT && vhost_count != -1U) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen o_stream_send_str(conn->output, "vhost count too large\n");
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen return TRUE;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen host = mail_host_lookup(&ip);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (host == NULL)
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen host = mail_host_add_ip(&ip);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (vhost_count != -1U)
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen mail_host_set_vhost_count(host, vhost_count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_update_host(conn->dir, conn->dir->self_host, host);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_send(conn->output, "OK\n", 3);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
009217abb57a24a4076092e8e4e165545747839eStephan Bosch
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic bool
009217abb57a24a4076092e8e4e165545747839eStephan Boschdoveadm_cmd_host_remove(struct doveadm_connection *conn, const char *line)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen struct ip_addr ip;
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (net_addr2ip(line, &ip) < 0) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen i_error("doveadm sent invalid HOST-SET parameters");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return FALSE;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen host = mail_host_lookup(&ip);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (host == NULL)
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen o_stream_send_str(conn->output, "NOTFOUND\n");
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen director_remove_host(conn->dir, conn->dir->self_host, host);
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen o_stream_send(conn->output, "OK\n", 3);
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen }
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen return TRUE;
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen}
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void doveadm_connection_input(struct doveadm_connection *conn)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
d3bae1f9d2448e5c398145ea250849ec12583845Timo Sirainen const char *line;
d3bae1f9d2448e5c398145ea250849ec12583845Timo Sirainen bool ret = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!conn->handshaked) {
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen if ((line = i_stream_read_next_line(conn->input)) == NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strncmp(line, DOVEADM_HANDSHAKE_EXPECTED,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen strlen(DOVEADM_HANDSHAKE_EXPECTED)) != 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("doveadm not compatible with this server "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "(mixed old and new binaries?)");
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen doveadm_connection_deinit(&conn);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen conn->handshaked = TRUE;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen while ((line = i_stream_read_next_line(conn->input)) != NULL && ret) {
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen if (strcmp(line, "HOST-LIST") == 0)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen doveadm_cmd_host_list(conn);
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen else if (strcmp(line, "DIRECTOR-LIST") == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen doveadm_cmd_director_list(conn);
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen else if (strncmp(line, "HOST-SET\t", 9) == 0)
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen ret = doveadm_cmd_host_set(conn, line + 9);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen else if (strncmp(line, "HOST-REMOVE\t", 12) == 0)
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen ret = doveadm_cmd_host_remove(conn, line + 12);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_error("doveadm sent unknown command: %s", line);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = FALSE;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (conn->input->eof || conn->input->stream_errno != 0 || !ret)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen doveadm_connection_deinit(&conn);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct doveadm_connection *
1df39b899804fd1dbc560f75382364822935c857Timo Sirainendoveadm_connection_init(struct director *dir, int fd)
1df39b899804fd1dbc560f75382364822935c857Timo 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);
009217abb57a24a4076092e8e4e165545747839eStephan Bosch 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);
c4900d31385344bfadaee53a897daeafdb3063d8Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DLLIST_PREPEND(&doveadm_connections, conn);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainenstatic void doveadm_connection_deinit(struct doveadm_connection **_conn)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen struct doveadm_connection *conn = *_conn;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen *_conn = NULL;
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen DLLIST_REMOVE(&doveadm_connections, conn);
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen io_remove(&conn->io);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen o_stream_unref(&conn->output);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (close(conn->fd) < 0)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i_error("close(doveadm connection) failed: %m");
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen i_free(conn);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid doveadm_connections_deinit(void)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen while (doveadm_connections != NULL) {
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen struct doveadm_connection *conn = doveadm_connections;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen doveadm_connection_deinit(&conn);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen