bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch struct mail_storage_service_user *service_user;
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschlmtp_local_rcpt_deinit(struct lmtp_local_recipient *rcpt);
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschstatic struct lmtp_local *
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschvoid lmtp_local_deinit(struct lmtp_local **_local)
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch array_foreach_modifiable(&local->rcpt_to, rcptp)
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch struct mailbox_transaction_context *raw_trans =
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch struct mailbox *raw_box = local->raw_mail->box;
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschlmtp_local_rcpt_anvil_disconnect(struct lmtp_local_recipient *rcpt)
0029bf606761c2adb611571c00cad699ae37c36aStephan Bosch const struct mail_storage_service_input *input;
0029bf606761c2adb611571c00cad699ae37c36aStephan Bosch input = mail_storage_service_user_get_input(rcpt->service_user);
0029bf606761c2adb611571c00cad699ae37c36aStephan Bosch master_service_anvil_send(master_service, t_strconcat(
0029bf606761c2adb611571c00cad699ae37c36aStephan Bosch "DISCONNECT\t", my_pid, "\t", master_service_get_name(master_service),
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschlmtp_local_rcpt_deinit(struct lmtp_local_recipient *rcpt)
70dfae6db8fd17ed79f1a48358f392841e9c9031Stephan Bosch anvil_client_query_abort(anvil, &rcpt->anvil_query);
70dfae6db8fd17ed79f1a48358f392841e9c9031Stephan Bosch mail_storage_service_user_unref(&rcpt->service_user);
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschlmtp_local_rcpt_reply_overquota(struct lmtp_local_recipient *rcpt,
2bf919786518d138cc07d9cc21e14ad5e07e5e56Stephan Bosch struct smtp_address *address = rcpt->rcpt.path;
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch mail_storage_service_user_get_set(rcpt->service_user)[2];
f8d9e6c977847a411af9986c9be62f74e4b06143Stephan Bosch i_assert(rcpt_idx == 0 || rcpt->rcpt.rcpt_cmd == NULL);
f8d9e6c977847a411af9986c9be62f74e4b06143Stephan Bosch smtp_server_reply_index(cmd, rcpt_idx, 452, "4.2.2", "<%s> %s",
f8d9e6c977847a411af9986c9be62f74e4b06143Stephan Bosch smtp_server_reply_index(cmd, rcpt_idx, 552, "5.2.2", "<%s> %s",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschlmtp_local_rcpt_fail_all(struct lmtp_local *local,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch const char *fmt, ...)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch for (i = 0; i < count; i++) {
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch smtp_server_reply_index(cmd, rcpts[i]->rcpt.index,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch smtp_address_encode(rcpts[i]->rcpt.rcpt->path), msg);
1c1396ed2f41328c88c1cfd73cb0168389507123Stephan Bosch * RCPT command
540ac35c2e2e0a88619c2224a9cccef51fecc37cStephan Boschstatic void lmtp_local_rcpt_cmd_destroy(struct smtp_server_cmd_ctx *cmd)
540ac35c2e2e0a88619c2224a9cccef51fecc37cStephan Bosch /* failed in RCPT command; clean up early */
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschlmtp_local_rcpt_check_quota(struct lmtp_local_recipient *rcpt)
cdbcc8db8e0a04b2cbf6ca9f20b3ee7f7173552dStephan Bosch struct smtp_server_cmd_ctx *cmd = rcpt->rcpt.rcpt_cmd;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_address *address = rcpt->rcpt.path;
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch /* mail user will be created second time when mail is saved,
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch so it's session_id needs to be different,
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch but second time session_id needs to be the same as rcpt session_id and
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch mail user session id for the first rcpt should not overlap with session id
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch of the second recipient, so add custom ":quota" suffix to the session_id without
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch session_id counter increment, so next time mail user will get
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch the same session id as rcpt */
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch ret = mail_storage_service_next_with_session_suffix(storage_service,
6fe14de90326d137e8a79c4fa02bbc4981f8c5faStephan Bosch ns = mail_namespace_find_inbox(user->namespaces);
6fe14de90326d137e8a79c4fa02bbc4981f8c5faStephan Bosch ret = mailbox_get_status(box, STATUS_CHECK_OVER_QUOTA, &status);
755372f8ed9aa3440cb0aa53e7f131694fb654faStephan Bosch error = mailbox_get_last_error(box, &mail_error);
c23717da4af9d3275cb45cbc67faaa8daa353ec1Stephan Bosch lmtp_local_rcpt_reply_overquota(rcpt, cmd, error);
6fe14de90326d137e8a79c4fa02bbc4981f8c5faStephan Bosch i_error("mailbox_get_status(%s, STATUS_CHECK_OVER_QUOTA) "
6fe14de90326d137e8a79c4fa02bbc4981f8c5faStephan Bosch "failed: %s",
cdbcc8db8e0a04b2cbf6ca9f20b3ee7f7173552dStephan Bosch "<%s> Temporary internal error",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch unsigned int index)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch if (!smtp_server_command_replied_success(cmd->cmd)) {
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* failed in RCPT command; clean up early */
c116e589182c258b463850327755e6dd9a731616Stephan Bosch lmtp_recipient_finish(&rcpt->rcpt, trcpt, index);
80f5e1ea615677c1c37be6e7abb888c9cc22de3bStephan Bosch /* resolve duplicate recipient */
80f5e1ea615677c1c37be6e7abb888c9cc22de3bStephan Bosch rcpt->duplicate = (struct lmtp_local_recipient *)
80f5e1ea615677c1c37be6e7abb888c9cc22de3bStephan Bosch lmtp_recipient_find_duplicate(&rcpt->rcpt, trans);
80f5e1ea615677c1c37be6e7abb888c9cc22de3bStephan Bosch i_assert(rcpt->duplicate == NULL || rcpt->duplicate->duplicate == NULL);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* add to local recipients */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch array_append(&client->local->rcpt_to, &rcpt, 1);
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschlmtp_local_rcpt_anvil_finish(struct lmtp_local_recipient *rcpt)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_cmd_ctx *cmd = rcpt->rcpt.rcpt_cmd;
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch if ((ret = lmtp_local_rcpt_check_quota(rcpt)) < 0) {
eb61a9ec4673adbc33d15be920cef99fd3657352Stephan Boschlmtp_local_rcpt_anvil_cb(const char *reply, void *context)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_cmd_ctx *cmd = rcpt->rcpt.rcpt_cmd;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_address *address = rcpt->rcpt.path;
a3259cc32f0d62c6e495b959393b2c2f4184167bStephan Bosch const struct mail_storage_service_input *input;
a3259cc32f0d62c6e495b959393b2c2f4184167bStephan Bosch /* lookup failed */
a3259cc32f0d62c6e495b959393b2c2f4184167bStephan Bosch } else if (str_to_uint(reply, ¶llel_count) < 0) {
a3259cc32f0d62c6e495b959393b2c2f4184167bStephan Bosch i_error("Invalid reply from anvil: %s", reply);
a3259cc32f0d62c6e495b959393b2c2f4184167bStephan Bosch if (parallel_count >= client->lmtp_set->lmtp_user_concurrency_limit) {
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch "<%s> Too many concurrent deliveries for user",
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch } else if (lmtp_local_rcpt_anvil_finish(rcpt)) {
a3259cc32f0d62c6e495b959393b2c2f4184167bStephan Bosch input = mail_storage_service_user_get_input(rcpt->service_user);
a3259cc32f0d62c6e495b959393b2c2f4184167bStephan Bosch master_service_anvil_send(master_service, t_strconcat(
a3259cc32f0d62c6e495b959393b2c2f4184167bStephan Bosch "CONNECT\t", my_pid, "\t", master_service_get_name(master_service),
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_connection *conn = cmd->conn;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch const struct smtp_address *address = data->path;
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch struct mail_storage_service_user *service_user;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch trans = smtp_server_connection_get_transaction(conn);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch i_assert(trans != NULL); /* MAIL command is synchronous */
bc1306f129e92eae1738a544a89bd7b2e4f6f735Stephan Bosch /* Use a unique session_id for each mail delivery. This is especially
bc1306f129e92eae1738a544a89bd7b2e4f6f735Stephan Bosch important for stats process to not see duplicate sessions. */
211caf3c233d562b0c8137e5eefae3cb1ef13003Stephan Bosch smtp_server_connection_is_ssl_secured(client->conn);
211caf3c233d562b0c8137e5eefae3cb1ef13003Stephan Bosch input.conn_secured = input.conn_ssl_secured ||
211caf3c233d562b0c8137e5eefae3cb1ef13003Stephan Bosch smtp_server_connection_is_trusted(client->conn);
bc1306f129e92eae1738a544a89bd7b2e4f6f735Stephan Bosch ret = mail_storage_service_lookup(storage_service, &input,
bc1306f129e92eae1738a544a89bd7b2e4f6f735Stephan Bosch i_error("Failed to lookup user %s: %s", username, error);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch "<%s> Temporary internal error",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch "<%s> User doesn't exist: %s",
540ac35c2e2e0a88619c2224a9cccef51fecc37cStephan Bosch cmd->hook_destroy = lmtp_local_rcpt_cmd_destroy;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch data->hook_finished = lmtp_local_rcpt_finished;
bc1306f129e92eae1738a544a89bd7b2e4f6f735Stephan Bosch if (client->lmtp_set->lmtp_user_concurrency_limit == 0) {
bc1306f129e92eae1738a544a89bd7b2e4f6f735Stephan Bosch /* NOTE: username may change as the result of the userdb
bc1306f129e92eae1738a544a89bd7b2e4f6f735Stephan Bosch lookup. Look up the new one via service_user. */
bc1306f129e92eae1738a544a89bd7b2e4f6f735Stephan Bosch const struct mail_storage_service_input *input =
bc1306f129e92eae1738a544a89bd7b2e4f6f735Stephan Bosch mail_storage_service_user_get_input(rcpt->service_user);
bc1306f129e92eae1738a544a89bd7b2e4f6f735Stephan Bosch rcpt->anvil_query = anvil_client_query(anvil, query,
1c1396ed2f41328c88c1cfd73cb0168389507123Stephan Bosch * DATA command
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschvoid lmtp_local_add_headers(struct lmtp_local *local,
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch sets = mail_storage_service_user_get_set(rcpts[0]->service_user);
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch switch (lmtp_set->parsed_lmtp_hdr_delivery_address) {
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch rcpt_to = rcpts[0]->rcpt.rcpt->params.orcpt.addr;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_address *rcpt_to = rcpt->rcpt.rcpt->path;
28585a42776a3e2bc530e604e21446832975b816Stephan Bosch struct mail_storage_service_user *service_user = rcpt->service_user;
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch const struct mail_storage_service_input *input;
28585a42776a3e2bc530e604e21446832975b816Stephan Bosch input = mail_storage_service_user_get_input(service_user);
28585a42776a3e2bc530e604e21446832975b816Stephan Bosch mail_set = mail_storage_service_user_get_mail_set(service_user);
28585a42776a3e2bc530e604e21446832975b816Stephan Bosch set_parser = mail_storage_service_user_get_settings_parser(service_user);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch mail_set->mail_max_lock_timeout > proxy_data.timeout_secs)) {
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch /* set lock timeout waits to be less than when proxy has
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch advertised that it's going to timeout the connection.
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch this avoids duplicate deliveries in case the delivery
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch succeeds after the proxy has already disconnected from us. */
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch line = t_strdup_printf("mail_max_lock_timeout=%us",
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch if (settings_parse_line(set_parser, line) < 0)
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch /* get the timestamp before user is created, since it starts the I/O */
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch i_set_failure_prefix("lmtp(%s, %s): ", my_pid, username);
28585a42776a3e2bc530e604e21446832975b816Stephan Bosch if (mail_storage_service_next(storage_service, service_user,
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch i_error("Failed to initialize user: %s", error);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch smtp_server_reply_index(cmd, rcpt_idx, 451, "4.3.0",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch "<%s> Temporary internal error",
28585a42776a3e2bc530e604e21446832975b816Stephan Bosch sets = mail_storage_service_user_get_set(service_user);
4bc2df90527f33dc51a9f367b64f18751c88ee25Stephan Bosch var_table = mail_user_var_expand_table(rcpt_user);
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch i_error("Failed to expand settings: %s", error);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch smtp_server_reply_index(cmd, rcpt_idx, 451, "4.3.0",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch "<%s> Temporary internal error",
4bc2df90527f33dc51a9f367b64f18751c88ee25Stephan Bosch if (var_expand_with_funcs(str, rcpt_user->set->mail_log_prefix,
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch i_error("Failed to expand mail_log_prefix=%s: %s",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch smtp_server_reply_index(cmd, rcpt_idx, 451, "4.3.0",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch "<%s> Temporary internal error",
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch /* MAIL FROM */
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch /* RCPT TO */
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch *dctx.set->lda_original_recipient_header != '\0') {
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch !client->lmtp_set->lmtp_save_to_detail_mailbox)
4bc2df90527f33dc51a9f367b64f18751c88ee25Stephan Bosch ns = mail_namespace_find_inbox(rcpt_user->namespaces);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch dctx.save_dest_mail = array_count(&trans->rcpt_to) > 1 &&
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch timeval_diff_msecs(&client->state.data_end_timeval,
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch dctx.delivery_time_started = delivery_time_started;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch smtp_address_encode(rcpt_to), rcpt->session_id);
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch error = mail_storage_get_last_error(storage, &mail_error);
c23717da4af9d3275cb45cbc67faaa8daa353ec1Stephan Bosch lmtp_local_rcpt_reply_overquota(rcpt, cmd, error);
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch /* This shouldn't happen */
4c10d203d1581b9e850a0e4552567fe7fec9598bStephan Bosch i_error("BUG: Saving failed to unknown storage");
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch smtp_server_reply_index(cmd, rcpt_idx, 451, "4.3.0",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch "<%s> Temporary internal error",
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschlmtp_local_deliver_to_rcpts(struct lmtp_local *local,
ce7a45d15786c7434546bd9da60fae08fc157f13Stephan Bosch for (i = 0; i < count; i++) {
80f5e1ea615677c1c37be6e7abb888c9cc22de3bStephan Bosch /* don't deliver more than once to the same recipient */
80f5e1ea615677c1c37be6e7abb888c9cc22de3bStephan Bosch rcpt->rcpt.index, rcpt->duplicate->rcpt.index);
fb2e20a30de93e83bbfe407f8231181f69ae684fStephan Bosch /* succeeded and mail_user is not saved in first_saved_mail */
fb2e20a30de93e83bbfe407f8231181f69ae684fStephan Bosch if ((ret == 0 &&
fb2e20a30de93e83bbfe407f8231181f69ae684fStephan Bosch /* failed. try the next one. */
fb2e20a30de93e83bbfe407f8231181f69ae684fStephan Bosch } else if (ret == 0) {
fb2e20a30de93e83bbfe407f8231181f69ae684fStephan Bosch /* use the first saved message to save it elsewhere too.
fb2e20a30de93e83bbfe407f8231181f69ae684fStephan Bosch this might allow hard linking the files.
fb2e20a30de93e83bbfe407f8231181f69ae684fStephan Bosch mail_user is saved in first_saved_mail,
fb2e20a30de93e83bbfe407f8231181f69ae684fStephan Bosch will be unreferenced later on */
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschlmtp_local_open_raw_mail(struct lmtp_local *local,
e3d554ca3408b7ea692f6f0b9ef5e6579e345627Stephan Bosch "From", "To", "Message-ID", "Subject", "Return-Path",
e3d554ca3408b7ea692f6f0b9ef5e6579e345627Stephan Bosch struct mailbox_header_lookup_ctx *headers_ctx;
e3d554ca3408b7ea692f6f0b9ef5e6579e345627Stephan Bosch if (raw_mailbox_alloc_stream(client->raw_mail_user, input,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch (time_t)-1, smtp_address_encode(trans->mail_from),
e3d554ca3408b7ea692f6f0b9ef5e6579e345627Stephan Bosch i_error("Can't open delivery mail as raw: %s",
e3d554ca3408b7ea692f6f0b9ef5e6579e345627Stephan Bosch mailbox_get_last_internal_error(box, &error));
cfc330f2ca4d1a8f9091c01305bb7f665f256798Stephan Bosch mtrans = mailbox_transaction_begin(box, 0, __func__);
e3d554ca3408b7ea692f6f0b9ef5e6579e345627Stephan Bosch headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Bosch local->raw_mail = mail_alloc(mtrans, 0, headers_ctx);
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch if (lmtp_local_open_raw_mail(local, cmd, trans, input) < 0)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch first_uid = lmtp_local_deliver_to_rcpts(local, cmd, trans, session);
cbd1d1a197f57d894c22863058b0ea3f2d2f68ffStephan Bosch struct mailbox_transaction_context *trans = mail->transaction;
cbd1d1a197f57d894c22863058b0ea3f2d2f68ffStephan Bosch /* just in case these functions are going to write anything,
cbd1d1a197f57d894c22863058b0ea3f2d2f68ffStephan Bosch change uid back to user's own one */
cbd1d1a197f57d894c22863058b0ea3f2d2f68ffStephan Bosch /* switch back to running as root, since that's what we're
cbd1d1a197f57d894c22863058b0ea3f2d2f68ffStephan Bosch practically doing anyway. it's also important in case we
cbd1d1a197f57d894c22863058b0ea3f2d2f68ffStephan Bosch lose e.g. config connection and need to reconnect to it. */
cbd1d1a197f57d894c22863058b0ea3f2d2f68ffStephan Bosch /* enable core dumping again. we need to chdir also to
cbd1d1a197f57d894c22863058b0ea3f2d2f68ffStephan Bosch root-owned directory to get core dumps. */