/* Copyright (c) 2009-2018 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-common.h"
#include "smtp-params.h"
#include "smtp-address.h"
#include "smtp-server.h"
#include "smtp-client.h"
#include "smtp-client-connection.h"
#include "smtp-client-transaction.h"
#include "auth-master.h"
#include "settings-parser.h"
#include "master-service.h"
#include "mail-storage-service.h"
#include "lda-settings.h"
#include "client.h"
#include "main.h"
#include "lmtp-common.h"
#include "lmtp-settings.h"
#include "lmtp-proxy.h"
struct lmtp_proxy_rcpt_settings {
const char *host;
unsigned int timeout_msecs;
};
struct lmtp_proxy_recipient {
};
struct lmtp_proxy_connection {
char *host;
};
struct lmtp_proxy {
unsigned int next_data_reply_idx;
unsigned int max_timeout_msecs;
};
static void
struct lmtp_proxy_recipient *rcpt);
/*
* LMTP proxy
*/
static struct lmtp_proxy *
struct smtp_server_transaction *trans)
{
else
return proxy;
}
static void
{
}
static void
{
}
{
}
static void
{
/* nothing */
}
static void
{
}
static struct lmtp_proxy_connection *
const struct lmtp_proxy_rcpt_settings *set)
{
return conn;
}
return conn;
}
static bool
const struct smtp_reply *reply,
struct smtp_reply *reply_r)
{
if (!smtp_reply_is_remote(reply) ||
break;
detail = " (DNS lookup)";
break;
detail = " (connect)";
break;
detail = " (connection lost)";
break;
detail = " (bad reply)";
break;
detail = " (timed out)";
break;
default:
break;
}
"Remote server not answering%s", detail);
return FALSE;
}
if (!smtp_reply_has_enhanced_code(reply)) {
}
return TRUE;
}
/*
* RCPT command
*/
static bool
{
if (p == NULL) {
value = "";
} else {
value = p + 1;
}
return FALSE;
}
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;
}
static void
{
}
static void
struct smtp_server_recipient *trcpt,
unsigned int index)
{
/* failed in RCPT command; clean up early */
return;
}
/* add to local recipients */
}
static void
struct lmtp_proxy_recipient *rcpt)
{
return;
if (smtp_reply_is_success(proxy_reply)) {
/* if backend accepts it, we accept it too */
/* the default 2.0.0 code won't do */
}
/* forward reply */
}
struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_rcpt *data,
char delim)
{
int ret;
// FIXME: make this async
if (ret <= 0) {
if (ret < 0) {
return -1;
} else {
/* user not found from passdb. revert to local delivery */
return 0;
}
}
/* not proxying this user */
return 0;
}
i_error("%s: Username `%s' returned by passdb lookup is not a valid SMTP address",
"Internal user lookup failure",
return -1;
}
/* username changed. change the address as well */
if (*detail == '\0') {
} else {
}
"<%s> Proxying loops to itself",
return -1;
}
i_error("Proxying to <%s> appears to be looping (TTL=0)",
username);
"<%s> Proxying appears to be looping (TTL=0)",
return -1;
}
return 1;
}
/*
* DATA command
*/
static void
struct lmtp_proxy_recipient *rcpt)
{
/* compose log message */
else
/* handle reply */
if (smtp_reply_is_success(proxy_reply)) {
/* if backend accepts it, we accept it too */
/* substitute our own success message */
/* do let the enhanced code through */
else
} else {
if (smtp_reply_is_remote(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 {
}
return;
}
/* forward reply */
}
static void
{
/* nothing */
}
struct smtp_server_cmd_ctx *cmd,
struct istream *data_input)
{
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) */
/* this connection had already failed */
continue;
}
}
}