lmtp-proxy.c revision 5f2855fe620b87f960dc24e16c578a4c820ef45c
/* Copyright (c) 2009-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "istream.h"
#include "istream-sized.h"
#include "ostream.h"
#include "str.h"
#include "time-util.h"
#include "smtp-reply.h"
#include "smtp-client.h"
#include "smtp-client-connection.h"
#include "smtp-client-transaction.h"
#include "auth-master.h"
#include "master-service.h"
#include "mail-storage-service.h"
#include "client.h"
#include "main.h"
#include "lmtp-proxy.h"
#define LMTP_MAX_LINE_LEN 1024
#define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> "
#define ERRSTR_TEMP_USERDB_FAIL \
ERRSTR_TEMP_USERDB_FAIL_PREFIX "Temporary user lookup failure"
struct lmtp_proxy_recipient {
struct lmtp_proxy_connection *conn;
const struct smtp_address *address;
const char *reply;
unsigned int idx;
bool rcpt_to_failed:1;
bool data_reply_received:1;
};
struct lmtp_proxy_connection {
struct lmtp_proxy *proxy;
struct lmtp_proxy_rcpt_settings set;
struct smtp_client_transaction *lmtp_trans;
struct istream *data_input;
bool finished:1;
bool failed:1;
};
struct lmtp_proxy {
const struct smtp_address *mail_from;
struct smtp_params_mail mail_params;
struct lmtp_proxy_settings set;
struct smtp_server_transaction *trans;
struct smtp_client *lmtp_client;
unsigned int next_data_reply_idx;
struct istream *data_input;
struct ostream *client_output;
unsigned int max_timeout_msecs;
void *finish_context;
bool finished:1;
};
static void
static void
struct lmtp_proxy_recipient *rcpt);
struct lmtp_proxy *
struct ostream *client_output)
{
struct smtp_client_settings lmtp_set;
struct lmtp_proxy *proxy;
else
return proxy;
}
{
struct lmtp_proxy_connection *const *conns;
}
}
{
}
const struct smtp_address *address,
const struct smtp_params_mail *params)
{
}
static void
{
/* nothing */
}
static struct lmtp_proxy_connection *
const struct lmtp_proxy_rcpt_settings *set)
{
struct smtp_client_connection *lmtp_conn;
return conn;
}
return conn;
}
{
struct lmtp_proxy_recipient *const *rcpt;
unsigned int i, count;
break;
}
proxy->next_data_reply_idx = i;
return i == count;
}
{
}
{
/* DATA command hasn't been sent yet */
return;
}
if (!lmtp_proxy_send_data_replies(proxy)) {
/* we can't received reply from all clients yet */
return;
}
/* do the actual finishing in a timeout handler, since the finish
callback causes the proxy to be destroyed and the code leading up
to this function can be called from many different places. it's
easier this way rather than having all the callers check if the
proxy was already destroyed. */
proxy);
}
}
static void
{
}
static void
{
if (smtp_reply_is_remote(proxy_reply)) {
} else {
switch (proxy_reply->status) {
break;
break;
break;
break;
break;
default:
break;
}
}
}
static void
struct lmtp_proxy_recipient *rcpt)
{
}
static void
struct lmtp_proxy_recipient *rcpt)
{
const struct smtp_client_transaction_times *times =
/* reset timeout in case there are a lot of RCPT TOs */
else
if (smtp_reply_is_success(proxy_reply) ||
/* the problem isn't with the proxy, it's with the remote side.
so the remote side will log an error, while for us this is
just an info event */
} else {
}
}
const struct smtp_address *address,
const struct lmtp_proxy_rcpt_settings *set)
{
struct lmtp_proxy_connection *conn;
struct lmtp_proxy_recipient *rcpt;
return -1;
return 0;
}
static void
{
/* nothing */
}
static bool
{
if (p == NULL) {
value = "";
} else {
value = p + 1;
}
return FALSE;
}
return FALSE;
}
return FALSE;
}
if (!port_set)
if (!port_set)
} else {
return FALSE;
}
/* changing the username */
} else {
/* just ignore it */
}
}
i_error("proxy: host not given");
return FALSE;
}
return proxying;
}
static bool
const struct lmtp_proxy_rcpt_settings *set)
{
return FALSE;
else {
return FALSE;
}
return FALSE;
return TRUE;
}
struct smtp_address *address,
struct smtp_params_rcpt *params)
{
struct auth_master_connection *auth_conn;
struct lmtp_proxy_rcpt_settings set;
struct auth_user_info info;
struct mail_storage_service_input input;
struct smtp_address *user;
int ret;
if (ret <= 0) {
pool_unref(&pool);
if (ret < 0) {
return TRUE;
} else {
/* user not found from passdb. try userdb also. */
return FALSE;
}
}
/* not proxying this user */
pool_unref(&pool);
return FALSE;
}
i_error("%s: Username `%s' returned by passdb lookup is not a valid SMTP address",
"Internal user lookup failure",
pool_unref(&pool);
return FALSE;
}
/* username changed. change the address as well */
if (*detail == '\0') {
} else {
}
"Proxying loops to itself",
pool_unref(&pool);
return TRUE;
}
i_error("Proxying to <%s> appears to be looping (TTL=0)",
username);
"Proxying appears to be looping (TTL=0)",
username);
pool_unref(&pool);
return TRUE;
}
pool_unref(&pool);
return TRUE;
}
struct lmtp_proxy_settings proxy_set;
}
else
pool_unref(&pool);
return TRUE;
}
{
struct lmtp_proxy_connection *const *conns;
i_error("i_stream_get_size(data_input) failed: %s",
}
/* create the data_input streams first */
/* this connection had already failed */
continue;
}
else
}
/* now that all the streams are created, start reading them
(reading them earlier could have caused the data_input parent's
offset to change) */
}
}
/* finish if all of the connections have already failed */
}