lmtp-local.c revision 11c80f46431050af464b044126887e81cb91e929
/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "str.h"
#include "istream.h"
#include "strescape.h"
#include "array.h"
#include "time-util.h"
#include "hostpid.h"
#include "var-expand.h"
#include "ioloop.h"
#include "restrict-access.h"
#include "anvil-client.h"
#include "settings-parser.h"
#include "mail-storage.h"
#include "mail-storage-service.h"
#include "mail-namespace.h"
#include "mail-deliver.h"
#include "mail-autoexpunge.h"
#include "index/raw/raw-storage.h"
#include "master-service.h"
#include "smtp-common.h"
#include "smtp-params.h"
#include "smtp-address.h"
#include "smtp-submit-settings.h"
#include "smtp-server.h"
#include "lda-settings.h"
#include "lmtp-settings.h"
#include "client.h"
#include "main.h"
#include "lmtp-common.h"
#include "lmtp-settings.h"
#include "lmtp-local.h"
struct lmtp_local_recipient {
struct lmtp_recipient rcpt;
char *session_id;
char *detail;
struct mail_storage_service_user *service_user;
struct anvil_query *anvil_query;
bool anvil_connect_sent:1;
};
struct lmtp_local {
};
static void
/*
* LMTP local
*/
static struct lmtp_local *
{
struct lmtp_local *local;
return local;
}
{
struct lmtp_local_recipient *const *rcptp;
}
struct mailbox_transaction_context *raw_trans =
}
}
/*
* Recipient
*/
static void
{
const struct mail_storage_service_input *input;
if (!rcpt->anvil_connect_sent)
return;
}
static void
{
}
static void
const char *error)
{
struct lda_settings *lda_set =
if (lda_set->quota_full_tempfail) {
452, "4.2.2", "<%s> %s",
} else {
552, "5.2.2", "<%s> %s",
}
}
struct smtp_server_cmd_ctx *cmd,
const char *fmt, ...)
{
struct lmtp_local_recipient *const *rcpts;
const char *msg;
unsigned int count, i;
for (i = 0; i < count; i++) {
}
}
/*
* RCPT command
*/
{
struct lmtp_local_recipient *rcpt =
return;
/* failed in RCPT command; clean up early */
return;
}
static int
{
struct mail_namespace *ns;
struct mailbox_status status;
enum mail_error mail_error;
const char *error;
int ret;
return 0;
/* mail user will be created second time when mail is saved,
so it's session_id needs to be different,
but second time session_id needs to be the same as rcpt session_id and
mail user session id for the first rcpt should not overlap with session id
of the second recipient, so add custom ":quota" suffix to the session_id without
session_id counter increment, so next time mail user will get
the same session id as rcpt */
"quota",
if (ret < 0) {
i_error("Failed to initialize user %s: %s",
ret = -1;
} else {
if (ret < 0) {
if (mail_error == MAIL_ERROR_NOQUOTA) {
} else {
i_error("mailbox_get_status(%s, STATUS_CHECK_OVER_QUOTA) "
"failed: %s",
}
ret = -1;
}
mailbox_free(&box);
}
if (ret < 0 &&
451, "4.3.0", "<%s> Temporary internal error",
}
return ret;
}
static void lmtp_local_rcpt_finished(
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_recipient *trcpt,
unsigned int index)
{
struct lmtp_local_recipient *rcpt =
/* failed in RCPT command; clean up early */
return;
}
/* add to local recipients */
}
static bool
{
int ret;
return FALSE;
}
return TRUE;
}
static void
{
struct lmtp_local_recipient *rcpt =
(struct lmtp_local_recipient *)context;
const struct mail_storage_service_input *input;
unsigned int parallel_count = 0;
/* lookup failed */
}
"<%s> Too many concurrent deliveries for user",
} else if (lmtp_local_rcpt_anvil_finish(rcpt)) {
}
}
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_rcpt *data,
{
struct smtp_server_transaction *trans;
struct lmtp_local_recipient *rcpt;
struct mail_storage_service_input input;
struct mail_storage_service_user *service_user;
int ret = 0;
/* Use a unique session_id for each mail delivery. This is especially
important for stats process to not see duplicate sessions. */
else {
}
&service_user, &error);
if (ret < 0) {
"<%s> Temporary internal error",
return -1;
}
if (ret == 0) {
"<%s> User doesn't exist: %s",
return -1;
}
(void)lmtp_local_rcpt_anvil_finish(rcpt);
} else {
/* NOTE: username may change as the result of the userdb
lookup. Look up the new one via service_user. */
const struct mail_storage_service_input *input =
return 0;
}
return 1;
}
/*
* DATA command
*/
struct smtp_server_transaction *trans,
{
struct lmtp_local_recipient *const *rcpts;
const struct lmtp_settings *lmtp_set;
unsigned int count;
void **sets;
if (count == 1) {
switch (lmtp_set->parsed_lmtp_hdr_delivery_address) {
break;
break;
break;
}
}
}
}
static int
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct lmtp_local_recipient *rcpt,
struct mail_deliver_session *session)
{
const struct smtp_server_recipient *trcpt =
struct mail_deliver_context dctx;
struct mail_storage *storage;
const struct mail_storage_service_input *input;
const struct mail_storage_settings *mail_set;
struct smtp_submit_settings *smtp_set;
struct smtp_proxy_data proxy_data;
struct lda_settings *lda_set;
struct mail_namespace *ns;
struct setting_parser_context *set_parser;
const struct var_expand_table *var_table;
struct timeval delivery_time_started;
void **sets;
enum mail_error mail_error;
int ret;
if (proxy_data.timeout_secs > 0 &&
(mail_set->mail_max_lock_timeout == 0 ||
/* set lock timeout waits to be less than when proxy has
advertised that it's going to timeout the connection.
this avoids duplicate deliveries in case the delivery
succeeds after the proxy has already disconnected from us. */
i_unreached();
}
/* get the timestamp before user is created, since it starts the I/O */
"<%s> Temporary internal error",
return -1;
}
&error);
if (ret > 0) {
&error);
}
if (ret <= 0) {
"<%s> Temporary internal error",
return -1;
}
i_error("Failed to expand mail_log_prefix=%s: %s",
"<%s> Temporary internal error",
return -1;
}
/* MAIL FROM */
/* RCPT TO */
}
else {
}
}
250, "2.0.0", "<%s> %s Saved",
ret = 0;
451, "4.2.0", "<%s> %s",
ret = -1;
if (mail_error == MAIL_ERROR_NOQUOTA) {
} else {
451, "4.2.0", "<%s> %s",
}
ret = -1;
} else {
/* This shouldn't happen */
i_error("BUG: Saving failed to unknown storage");
"<%s> Temporary internal error",
ret = -1;
}
return ret;
}
static uid_t
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct mail_deliver_session *session)
{
struct lmtp_local_recipient *const *rcpts;
unsigned int count, i;
int ret;
for (i = 0; i < count; i++) {
/* succeeded and mail_user is not saved in first_saved_mail */
if ((ret == 0 &&
/* failed. try the next one. */
if (i == (count - 1))
} else if (ret == 0) {
/* use the first saved message to save it elsewhere too.
this might allow hard linking the files.
mail_user is saved in first_saved_mail,
will be unreferenced later on */
}
}
return first_uid;
}
static int
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
{
static const char *wanted_headers[] = {
"From", "To", "Message-ID", "Subject", "Return-Path",
};
struct mailbox_transaction_context *mtrans;
struct mailbox_header_lookup_ctx *headers_ctx;
enum mail_error error;
&box) < 0) {
i_error("Can't open delivery mail as raw: %s",
mailbox_free(&box);
451, "4.3.0", "Temporary internal error");
return -1;
}
return 0;
}
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
{
struct mail_deliver_session *session;
return;
/* just in case these functions are going to write anything,
change uid back to user's own one */
if (seteuid(0) < 0)
i_fatal("seteuid(0) failed: %m");
i_fatal("seteuid() failed: %m");
}
mailbox_free(&box);
}
if (old_uid == 0) {
/* switch back to running as root, since that's what we're
practically doing anyway. it's also important in case we
lose e.g. config connection and need to reconnect to it. */
if (seteuid(0) < 0)
i_fatal("seteuid(0) failed: %m");
/* enable core dumping again. we need to chdir also to
root-owned directory to get core dumps. */
}
}