imap-master-client.c revision efe78d3ba24fc866af1c79b9223dc0809ba26cad
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2014-2016 Dovecot authors, see the included COPYING file */
687794a61c9e3bf27c712b442b8fc8836c63ae44Timo Sirainen /* input we've already read from the IMAP client. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* output that imap-hibernate was supposed to send to IMAP client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen but couldn't send it yet. */
919875067c26fb261a15b3f7afdb67d7eeddb226Timo Sirainen /* IMAP connection state */
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen /* command tag */
b6612c334604eeb27e1ca2bd804ac66dcbc2eaadTimo Sirainen const char *tag;
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainenstatic struct connection_list *master_clients = NULL;
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainenstatic void imap_master_client_destroy(struct connection *conn)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct imap_master_client *client = (struct imap_master_client *)conn;
9a25d843320a418799494ebaef91112ade0c5fdcTimo Sirainen master_service_client_connection_destroyed(master_service);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainenimap_master_client_parse_input(const char *const *args, pool_t pool,
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen const char **error_r)
1da9587dfb6632ac6446ad12b09fdf77c8542e2cTimo Sirainen unsigned int peer_dev_major = 0, peer_dev_minor = 0;
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 /* 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 if (net_addr2ip(value, &input_r->local_ip) < 0) {
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen if (net_addr2ip(value, &input_r->remote_ip) < 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen } else if (strcmp(key, "peer_dev_major") == 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (str_to_uint(value, &peer_dev_major) < 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen } else if (strcmp(key, "peer_dev_minor") == 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (str_to_uint(value, &peer_dev_minor) < 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (str_to_ino(value, &master_input_r->peer_ino) < 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen } else if (strcmp(key, "session_created") == 0) {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (str_to_time(value, &input_r->session_create_time) < 0) {
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen } else if (strcmp(key, "userdb_fields") == 0) {
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen } else if (strcmp(key, "client_input") == 0) {
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen "Invalid client_input base64 value: %s", value);
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainen } else if (strcmp(key, "client_output") == 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen "Invalid client_output base64 value: %s", value);
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;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (peer_dev_major != 0 || peer_dev_minor != 0) {
3f99d19bf3361a4b0952e4e3ad64d4d6988de469Timo Sirainenstatic int imap_master_client_verify(const struct imap_master_input *master_input,
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen /* make sure we have the right fd */
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen *error_r = t_strdup_printf("fstat(peer) failed: %m");
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (peer_st.st_ino != master_input->peer_ino ||
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen !CMP_DEV_T(peer_st.st_dev, master_input->peer_dev)) {
659fe5d24825b160cae512538088020d97a60239Timo Sirainen "BUG: Expected peer device=%lu,%lu inode=%s doesn't match "
b43bb773ee6534c1013b01a62fbd5703e3b0d17dTimo Sirainen "client fd's actual device=%lu,%lu inode=%s",
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen (unsigned long)minor(peer_st.st_dev), dec2str(peer_st.st_ino),
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainenimap_master_client_input_args(struct connection *conn, const char *const *args,
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen struct imap_master_client *client = (struct imap_master_client *)conn;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (imap_master_client_parse_input(args, pool, &input, &master_input,
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 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));
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. */
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 i_error("imap-master(%s): Failed to create client: %s",
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 */
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_error("imap-master: Couldn't add %"PRIuSIZE_T
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen " bytes to client's input stream",
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen client_destroy(imap_client, "Client initialization failed");
fd3f33bdb57170d63aea66ecacc8bea0f0145d6aTimo Sirainen ret = imap_state_import_internal(imap_client, master_input.state->data,
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 imap_state_import_idle_cmd_tag(imap_client, master_input.tag);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen /* make sure all pending input gets handled */
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen i_assert(imap_client->to_delayed_input == NULL);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen /* we'll always disconnect the client afterwards */
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainenimap_master_client_input_line(struct connection *conn, const char *line)
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen char *const *args;
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen if (connection_verify_version(conn, t_strsplit_tabescaped(line)) < 0)
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen fd_client = i_stream_unix_get_read_fd(conn->input);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen i_error("imap-master: IMAP client fd not received");
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen i_debug("imap-master: Client input: %s", line);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen pool = pool_alloconly_create("imap master client cmd", 1024);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen ret = imap_master_client_input_args(conn, (void *)args, fd_client, pool);
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen connection_init_server(master_clients, &client->conn,
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 Sirainenstatic struct connection_settings client_set = {
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainen .input_max_size = 0, /* don't auto-create istream */
20c892309312df8f4f73cfcaf8acd2ededda8b05Timo Sirainenstatic const struct connection_vfuncs client_vfuncs = {