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