lmtp-local.c revision b73539ef2de3db3abc0ad5f729406e695e4cb76b
0029bf606761c2adb611571c00cad699ae37c36aStephan Bosch/* Copyright (c) 2009-2017 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,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_address *address = rcpt->rcpt.rcpt->path;
1d2e367e199368932c02a306ddedbc7566553a15Stephan Bosch mail_storage_service_user_get_set(rcpt->service_user)[2];
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Boschlmtp_local_rcpt_fail_all(struct lmtp_local *local,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch const char *fmt, ...)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch const char *msg;
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch unsigned int count, i;
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
2b7d6fbaadd62e66c858bae0358232c02369b43bStephan Boschlmtp_local_rcpt_check_quota(struct lmtp_local_recipient *rcpt)
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);
6fe14de90326d137e8a79c4fa02bbc4981f8c5faStephan Bosch i_error("mailbox_get_status(%s, STATUS_CHECK_OVER_QUOTA) "
6fe14de90326d137e8a79c4fa02bbc4981f8c5faStephan Bosch "failed: %s",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch 451, "4.3.0", "<%s> Temporary internal error",
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch struct smtp_server_transaction *trans ATTR_UNUSED,
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch unsigned int index)
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch if (!smtp_server_command_replied_success(cmd->cmd)) {
b73539ef2de3db3abc0ad5f729406e695e4cb76bStephan Bosch /* failed in RCPT command; clean up early */
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 unsigned int parallel_count = 0;
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. */
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",
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 unsigned int count;
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);
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 unsigned int count, i;
ce7a45d15786c7434546bd9da60fae08fc157f13Stephan Bosch for (i = 0; i < count; i++) {
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 static const char *wanted_headers[] = {
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. */