/* 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 {
char *session_id;
char *detail;
};
struct lmtp_local {
};
static void
/*
* LMTP local
*/
static struct lmtp_local *
{
return local;
}
{
}
}
}
/*
* Recipient
*/
static void
{
if (!rcpt->anvil_connect_sent)
return;
}
static void
{
}
static void
struct smtp_server_cmd_ctx *cmd,
const char *error)
{
if (lda_set->quota_full_tempfail) {
} else {
}
}
struct smtp_server_cmd_ctx *cmd,
const char *fmt, ...)
{
const char *msg;
unsigned int count, i;
for (i = 0; i < count; i++) {
}
}
/*
* RCPT command
*/
{
return;
/* failed in RCPT command; clean up early */
return;
}
static int
{
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 &&
"<%s> Temporary internal error",
}
return ret;
}
static void lmtp_local_rcpt_finished(
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_transaction *trans,
struct smtp_server_recipient *trcpt,
unsigned int index)
{
/* failed in RCPT command; clean up early */
return;
}
/* resolve duplicate recipient */
/* add to local recipients */
}
static bool
{
int ret;
return FALSE;
}
return TRUE;
}
static void
{
(struct lmtp_local_recipient *)context;
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,
{
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. */
return 0;
}
return 1;
}
/*
* DATA command
*/
struct smtp_server_transaction *trans,
{
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)
{
void **sets;
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)
{
unsigned int count, i;
int ret;
for (i = 0; i < count; i++) {
/* don't deliver more than once to the same recipient */
continue;
}
/* 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",
};
&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,
{
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. */
}
}