imap-master-client.c revision efe78d3ba24fc866af1c79b9223dc0809ba26cad
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2014-2016 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-common.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "connection.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-unix.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ostream.h"
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen#include "base64.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "strescape.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "master-service.h"
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen#include "mail-storage-service.h"
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen#include "imap-client.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-state.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-master-client.h"
8ef80b0b9c73fb0a0188788b14b3e15084b7a452Timo Sirainen
56561d472db25ebda35ae6afdc7f7deb75c323fcTimo Sirainenstruct imap_master_client {
687794a61c9e3bf27c712b442b8fc8836c63ae44Timo Sirainen struct connection conn;
f1765f773591385d513fb68e1799fd1cb4206852Timo Sirainen bool imap_client_created;
f1765f773591385d513fb68e1799fd1cb4206852Timo Sirainen};
f1765f773591385d513fb68e1799fd1cb4206852Timo Sirainen
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainenstruct imap_master_input {
687794a61c9e3bf27c712b442b8fc8836c63ae44Timo Sirainen /* input we've already read from the IMAP client. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_t *client_input;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* output that imap-hibernate was supposed to send to IMAP client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen but couldn't send it yet. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_t *client_output;
919875067c26fb261a15b3f7afdb67d7eeddb226Timo Sirainen /* IMAP connection state */
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen buffer_t *state;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen /* command tag */
b6612c334604eeb27e1ca2bd804ac66dcbc2eaadTimo Sirainen const char *tag;
919875067c26fb261a15b3f7afdb67d7eeddb226Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen dev_t peer_dev;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen ino_t peer_ino;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool state_import_bad_idle_done;
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen bool state_import_idle_continue;
5a58037ad75b88356d82240fab2bc604de03107eTimo Sirainen};
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainenstatic struct connection_list *master_clients = NULL;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainenstatic void imap_master_client_destroy(struct connection *conn)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct imap_master_client *client = (struct imap_master_client *)conn;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
49e9acb52bb5d328f8cf10bce1082c4bc213caeaTimo Sirainen if (!client->imap_client_created)
9a25d843320a418799494ebaef91112ade0c5fdcTimo Sirainen master_service_client_connection_destroyed(master_service);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen connection_deinit(conn);
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen i_free(conn);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainenstatic int
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainenimap_master_client_parse_input(const char *const *args, pool_t pool,
9a25d843320a418799494ebaef91112ade0c5fdcTimo Sirainen struct mail_storage_service_input *input_r,
9a25d843320a418799494ebaef91112ade0c5fdcTimo Sirainen struct imap_master_input *master_input_r,
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen const char **error_r)
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen const char *key, *value;
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen unsigned int peer_dev_major = 0, peer_dev_minor = 0;
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen i_zero(input_r);
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen i_zero(master_input_r);
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen master_input_r->client_input = buffer_create_dynamic(pool, 64);
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen master_input_r->client_output = buffer_create_dynamic(pool, 16);
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen master_input_r->state = buffer_create_dynamic(pool, 512);
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen input_r->module = input_r->service = "imap";
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen /* we never want to do userdb lookup again when restoring the client.
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen we have the userdb_fields cached already. */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen input_r->flags_override_remove = MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (args[0] == NULL) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen *error_r = "Missing username in input";
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return -1;
49e9acb52bb5d328f8cf10bce1082c4bc213caeaTimo Sirainen }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen input_r->username = args[0];
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen for (args++; *args != NULL; args++) {
49e9acb52bb5d328f8cf10bce1082c4bc213caeaTimo Sirainen value = strchr(*args, '=');
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (value != NULL)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen key = t_strdup_until(*args, value++);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen else {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen key = *args;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen value = "";
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (strcmp(key, "lip") == 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (net_addr2ip(value, &input_r->local_ip) < 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen *error_r = t_strdup_printf(
c680a6b35b459045e92814778908da5a93922107Timo Sirainen "Invalid lip value: %s", value);
c680a6b35b459045e92814778908da5a93922107Timo Sirainen return -1;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen } else if (strcmp(key, "rip") == 0) {
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen if (net_addr2ip(value, &input_r->remote_ip) < 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen *error_r = t_strdup_printf(
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen "Invalid rip value: %s", value);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return -1;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen } else if (strcmp(key, "peer_dev_major") == 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (str_to_uint(value, &peer_dev_major) < 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen *error_r = t_strdup_printf(
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen "Invalid peer_dev_major value: %s", value);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen return -1;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen } else if (strcmp(key, "peer_dev_minor") == 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (str_to_uint(value, &peer_dev_minor) < 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen *error_r = t_strdup_printf(
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen "Invalid peer_dev_minor value: %s", value);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen return -1;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen } else if (strcmp(key, "peer_ino") == 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (str_to_ino(value, &master_input_r->peer_ino) < 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen *error_r = t_strdup_printf(
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen "Invalid peer_ino value: %s", value);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen return -1;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen } else if (strcmp(key, "session") == 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen input_r->session_id = value;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen } else if (strcmp(key, "session_created") == 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (str_to_time(value, &input_r->session_create_time) < 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen *error_r = t_strdup_printf(
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen "Invalid session_created value: %s", value);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen return -1;
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen }
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen } else if (strcmp(key, "userdb_fields") == 0) {
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen input_r->userdb_fields =
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen t_strsplit_tabescaped(value);
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen } else if (strcmp(key, "client_input") == 0) {
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen if (base64_decode(value, strlen(value), NULL,
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen master_input_r->client_input) < 0) {
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen *error_r = t_strdup_printf(
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen "Invalid client_input base64 value: %s", value);
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen return -1;
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen }
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen } else if (strcmp(key, "client_output") == 0) {
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen if (base64_decode(value, strlen(value), NULL,
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen master_input_r->client_output) < 0) {
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen *error_r = t_strdup_printf(
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen "Invalid client_output base64 value: %s", value);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return -1;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen } else if (strcmp(key, "state") == 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (base64_decode(value, strlen(value), NULL,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen master_input_r->state) < 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen *error_r = t_strdup_printf(
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen "Invalid state base64 value: %s", value);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return -1;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen } else if (strcmp(key, "tag") == 0) {
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen master_input_r->tag = t_strdup(value);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen } else if (strcmp(key, "bad-done") == 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen master_input_r->state_import_bad_idle_done = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (strcmp(key, "idle-continue") == 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen master_input_r->state_import_idle_continue = TRUE;
687794a61c9e3bf27c712b442b8fc8836c63ae44Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (peer_dev_major != 0 || peer_dev_minor != 0) {
659fe5d24825b160cae512538088020d97a60239Timo Sirainen master_input_r->peer_dev =
659fe5d24825b160cae512538088020d97a60239Timo Sirainen makedev(peer_dev_major, peer_dev_minor);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen }
659fe5d24825b160cae512538088020d97a60239Timo Sirainen return 0;
5cdd348121e62a6244ba2f93db781731f7129a71Timo Sirainen}
5cdd348121e62a6244ba2f93db781731f7129a71Timo Sirainen
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainenstatic int imap_master_client_verify(const struct imap_master_input *master_input,
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen int fd_client, const char **error_r)
b43bb773ee6534c1013b01a62fbd5703e3b0d17dTimo Sirainen{
659fe5d24825b160cae512538088020d97a60239Timo Sirainen struct stat peer_st;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen if (master_input->peer_ino == 0)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return 0;
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen /* make sure we have the right fd */
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (fstat(fd_client, &peer_st) < 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen *error_r = t_strdup_printf("fstat(peer) failed: %m");
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return -1;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (peer_st.st_ino != master_input->peer_ino ||
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen !CMP_DEV_T(peer_st.st_dev, master_input->peer_dev)) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen *error_r = t_strdup_printf(
659fe5d24825b160cae512538088020d97a60239Timo Sirainen "BUG: Expected peer device=%lu,%lu inode=%s doesn't match "
b43bb773ee6534c1013b01a62fbd5703e3b0d17dTimo Sirainen "client fd's actual device=%lu,%lu inode=%s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (unsigned long)major(peer_st.st_dev),
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen (unsigned long)minor(peer_st.st_dev), dec2str(peer_st.st_ino),
f4ca89823693b9faa82a0c39c24510a7b0e606afTimo Sirainen (unsigned long)major(master_input->peer_dev),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (unsigned long)minor(master_input->peer_dev),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dec2str(master_input->peer_ino));
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen return -1;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen }
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen return 0;
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen}
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainenstatic int
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainenimap_master_client_input_args(struct connection *conn, const char *const *args,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen int fd_client, pool_t pool)
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen{
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen struct imap_master_client *client = (struct imap_master_client *)conn;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen struct client *imap_client;
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen struct mail_storage_service_input input;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen struct imap_master_input master_input;
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen const char *error;
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen int ret;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (imap_master_client_parse_input(args, pool, &input, &master_input,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen &error) < 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_error("imap-master: Failed to parse client input: %s", error);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen o_stream_nsend_str(conn->output, t_strdup_printf(
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen "-Failed to parse client input: %s\n", error));
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_close_fd(&fd_client);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return -1;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (imap_master_client_verify(&master_input, fd_client, &error) < 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_error("imap-master: Failed to verify client input: %s", error);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen o_stream_nsend_str(conn->output, t_strdup_printf(
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen "-Failed to verify client input: %s\n", error));
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_close_fd(&fd_client);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return -1;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen /* Send a success notification before we start anything that lasts
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen potentially a long time. imap-hibernate process is waiting for us
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen to answer. Even if we fail later, we log the error anyway. */
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen o_stream_nsend_str(conn->output, "+\n");
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen /* NOTE: before client_create_from_input() on failures we need to close
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen fd_client, but afterward it gets closed by client_destroy() */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen ret = client_create_from_input(&input, fd_client, fd_client,
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen &imap_client, &error);
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen if (ret < 0) {
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen i_error("imap-master(%s): Failed to create client: %s",
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen input.username, error);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_close_fd(&fd_client);
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen return -1;
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* log prefix is set at this point, so we don't need to add the
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen username anymore to the log messages */
220195605754218b4d6e3a51f5a25be9d0e202e0Timo Sirainen client->imap_client_created = TRUE;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen o_stream_nsend(imap_client->output,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen master_input.client_output->data,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen master_input.client_output->used);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (master_input.client_input->used > 0 &&
220195605754218b4d6e3a51f5a25be9d0e202e0Timo Sirainen !i_stream_add_data(imap_client->input,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen master_input.client_input->data,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen master_input.client_input->used)) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_error("imap-master: Couldn't add %"PRIuSIZE_T
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen " bytes to client's input stream",
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen master_input.client_input->used);
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen client_destroy(imap_client, "Client initialization failed");
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return -1;
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen }
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen imap_client->state_import_bad_idle_done =
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen master_input.state_import_bad_idle_done;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen imap_client->state_import_idle_continue =
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen master_input.state_import_idle_continue;
fd3f33bdb57170d63aea66ecacc8bea0f0145d6aTimo Sirainen ret = imap_state_import_internal(imap_client, master_input.state->data,
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen master_input.state->used, &error);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (ret <= 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen i_error("imap-master: Failed to import client state: %s", error);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen client_destroy(imap_client, "Client state initialization failed");
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen return -1;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (master_input.tag != NULL)
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen imap_state_import_idle_cmd_tag(imap_client, master_input.tag);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen /* make sure all pending input gets handled */
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen i_assert(imap_client->to_delayed_input == NULL);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (master_input.client_input->used > 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen imap_client->to_delayed_input =
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen timeout_add(0, client_input, imap_client);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen imap_refresh_proctitle();
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen /* we'll always disconnect the client afterwards */
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen return -1;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen}
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainenstatic int
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainenimap_master_client_input_line(struct connection *conn, const char *line)
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen{
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen char *const *args;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen pool_t pool;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen int fd_client, ret;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (!conn->version_received) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (connection_verify_version(conn, t_strsplit_tabescaped(line)) < 0)
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen return -1;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen conn->version_received = TRUE;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen return 1;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen fd_client = i_stream_unix_get_read_fd(conn->input);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (fd_client == -1) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen i_error("imap-master: IMAP client fd not received");
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen return -1;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen }
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (imap_debug)
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen i_debug("imap-master: Client input: %s", line);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen pool = pool_alloconly_create("imap master client cmd", 1024);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen args = p_strsplit_tabescaped(pool, line);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen ret = imap_master_client_input_args(conn, (void *)args, fd_client, pool);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen pool_unref(&pool);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen return ret;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen}
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainenvoid imap_master_client_create(int fd)
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen{
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen struct imap_master_client *client;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen client = i_new(struct imap_master_client, 1);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen connection_init_server(master_clients, &client->conn,
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen "imap-master", fd, fd);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen i_assert(client->conn.input == NULL);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen client->conn.input = i_stream_create_unix(fd, (size_t)-1);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen /* read the first file descriptor that we can */
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen i_stream_unix_set_read_fd(client->conn.input);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen}
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainenstatic struct connection_settings client_set = {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen .service_name_in = "imap-master",
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen .service_name_out = "imap-master",
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen .major_version = 1,
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen .minor_version = 0,
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen .input_max_size = 0, /* don't auto-create istream */
919875067c26fb261a15b3f7afdb67d7eeddb226Timo Sirainen .output_max_size = (size_t)-1,
919875067c26fb261a15b3f7afdb67d7eeddb226Timo Sirainen .client = FALSE
b6612c334604eeb27e1ca2bd804ac66dcbc2eaadTimo Sirainen};
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainenstatic const struct connection_vfuncs client_vfuncs = {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen .destroy = imap_master_client_destroy,
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen .input_line = imap_master_client_input_line
919875067c26fb261a15b3f7afdb67d7eeddb226Timo Sirainen};
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainenvoid imap_master_clients_init(void)
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen{
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen master_clients = connection_list_init(&client_set, &client_vfuncs);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen}
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainenvoid imap_master_clients_deinit(void)
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen{
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen connection_list_deinit(&master_clients);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen}
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen