struct client *client_create(int fd_in, int fd_out,
const struct master_service_connection *conn)
{
+ static const char *rcpt_param_extensions[] = {
+ LMTP_RCPT_FORWARD_PARAMETER, NULL };
+ static const struct smtp_capability_extra cap_rcpt_forward = {
+ .name = LMTP_RCPT_FORWARD_CAPABILITY };
enum lmtp_client_workarounds workarounds;
struct smtp_server_settings lmtp_set;
struct client *client;
lmtp_set.hostname = client->unexpanded_lda_set->hostname;
lmtp_set.login_greeting = client->lmtp_set->login_greeting;
lmtp_set.max_message_size = (uoff_t)-1;
+ lmtp_set.rcpt_param_extensions = rcpt_param_extensions;
lmtp_set.rcpt_domain_optional = TRUE;
lmtp_set.max_client_idle_time_msecs = CLIENT_IDLE_TIMEOUT_MSECS;
lmtp_set.rawlog_dir = client->lmtp_set->lmtp_rawlog_dir;
lmtp_server, fd_in, fd_out,
&conn->remote_ip, conn->remote_port, conn->ssl,
&lmtp_set, &lmtp_callbacks, client);
+ if (smtp_server_connection_is_trusted(client->conn)) {
+ smtp_server_connection_add_extra_capability(
+ client->conn, &cap_rcpt_forward);
+ }
DLLIST_PREPEND(&clients, client);
clients_count++;
* RCPT command
*/
+static int
+cmd_rcpt_handle_forward_fields(struct smtp_server_cmd_ctx *cmd,
+ struct lmtp_recipient *lrcpt)
+{
+ struct smtp_server_recipient *rcpt = lrcpt->rcpt;
+ string_t *xforward;
+ const char *error;
+ int ret;
+
+ ret = smtp_params_rcpt_decode_extra(&rcpt->params,
+ LMTP_RCPT_FORWARD_PARAMETER,
+ &xforward, FALSE, &error);
+ if (ret < 0) {
+ smtp_server_reply(cmd, 501, "5.5.4",
+ "Invalid "LMTP_RCPT_FORWARD_PARAMETER"= "
+ "parameter: %s", error);
+ return -1;
+ }
+ if (ret == 0)
+ return 0;
+
+ /* Check the real IP rather than the proxied client IP, since XCLIENT
+ command will update that, thereby making it untrusted. Unlike the
+ XCLIENT command, the RCPT forward parameter needs to be used after
+ the XCLIENT is first issued. */
+ if (!smtp_server_connection_is_trusted(rcpt->conn)) {
+ smtp_server_reply(cmd, 550, "5.7.14",
+ "Unacceptable "LMTP_RCPT_FORWARD_PARAMETER"= "
+ "parameter: You are not from trusted IP");
+ return -1;
+ }
+
+ lrcpt->forward_fields = p_strdup(rcpt->pool, str_c(xforward));
+ return 0;
+}
+
int cmd_rcpt(void *conn_ctx, struct smtp_server_cmd_ctx *cmd,
struct smtp_server_recipient *rcpt)
{
lrcpt = lmtp_recipient_create(client, rcpt);
+ if (cmd_rcpt_handle_forward_fields(cmd, lrcpt) < 0)
+ return -1;
+
return client->v.cmd_rcpt(client, cmd, lrcpt);
}
#include "ostream.h"
#include "iostream-ssl.h"
#include "str.h"
+#include "strescape.h"
#include "time-util.h"
#include "smtp-common.h"
#include "smtp-params.h"
struct smtp_address *address;
+ const unsigned char *forward_fields;
+ size_t forward_fields_size;
+
bool rcpt_to_failed:1;
bool data_reply_received:1;
};
lmtp_proxy_init(struct client *client,
struct smtp_server_transaction *trans)
{
+ const char *extra_capabilities[] = {
+ LMTP_RCPT_FORWARD_CAPABILITY,
+ NULL };
struct smtp_client_settings lmtp_set;
struct lmtp_proxy *proxy;
i_zero(&lmtp_set);
lmtp_set.my_hostname = client->my_domain;
+ lmtp_set.extra_capabilities = extra_capabilities;
lmtp_set.dns_client_socket_path = dns_client_socket_path;
lmtp_set.max_reply_size = LMTP_MAX_REPLY_SIZE;
lmtp_set.rawlog_dir = client->lmtp_set->lmtp_proxy_rawlog_dir;
*ssl_mode_r = SMTP_CLIENT_SSL_MODE_STARTTLS;
}
+static bool
+lmtp_proxy_connection_has_rcpt_forward(struct lmtp_proxy_connection *conn)
+{
+ const struct smtp_capability_extra *cap_extra =
+ smtp_client_connection_get_extra_capability(
+ conn->lmtp_conn, LMTP_RCPT_FORWARD_CAPABILITY);
+
+ return (cap_extra != NULL);
+}
+
static struct lmtp_proxy_connection *
lmtp_proxy_get_connection(struct lmtp_proxy *proxy,
const struct lmtp_proxy_rcpt_settings *set)
conn->set.host, conn->set.port,
ssl_mode, &lmtp_set);
}
+ smtp_client_connection_accept_extra_capability(
+ conn->lmtp_conn, LMTP_RCPT_FORWARD_CAPABILITY);
smtp_client_connection_connect(conn->lmtp_conn, NULL, NULL);
conn->lmtp_trans = smtp_client_transaction_create(
struct smtp_reply reply;
struct smtp_client_transaction_rcpt *relay_rcpt;
struct smtp_params_rcpt *rcpt_params = &rcpt->params;
- bool add_orcpt_param = FALSE;
+ bool add_orcpt_param = FALSE, add_xrcptforward_param = FALSE;
pool_t param_pool;
if (!lmtp_proxy_handle_reply(lprcpt, proxy_reply, &reply))
!smtp_address_equals(lprcpt->address, rcpt->path))
add_orcpt_param = TRUE;
+ /* Add forward fields parameter when passdb returned forward_* fields */
+ if (lprcpt->forward_fields != NULL &&
+ lmtp_proxy_connection_has_rcpt_forward(conn))
+ add_xrcptforward_param = TRUE;
+
/* Copy params when changes are pending */
param_pool = NULL;
- if (add_orcpt_param) {
+ if (add_orcpt_param || add_xrcptforward_param) {
param_pool = pool_datastack_create();
rcpt_params = p_new(param_pool, struct smtp_params_rcpt, 1);
smtp_params_rcpt_copy(param_pool, rcpt_params, &rcpt->params);
smtp_params_rcpt_set_orcpt(rcpt_params, param_pool,
rcpt->path);
}
+ /* Add forward fields parameter */
+ if (add_xrcptforward_param) {
+ smtp_params_rcpt_encode_extra(
+ rcpt_params, param_pool, LMTP_RCPT_FORWARD_PARAMETER,
+ lprcpt->forward_fields, lprcpt->forward_fields_size);
+ }
smtp_server_recipient_add_hook(
rcpt, SMTP_SERVER_RECIPIENT_HOOK_APPROVED,
const char *const *fields, *errstr, *orig_username = username;
struct smtp_proxy_data proxy_data;
struct smtp_address *user;
+ string_t *fwfields;
pool_t auth_pool;
int ret;
info.real_local_port = client->real_local_port;
info.remote_port = client->remote_port;
info.real_remote_port = client->real_remote_port;
+ info.forward_fields = lrcpt->forward_fields;
// FIXME: make this async
auth_pool = pool_alloconly_create("auth lookup", 1024);
client->proxy = lmtp_proxy_init(client, trans);
conn = lmtp_proxy_get_connection(client->proxy, &set);
- pool_unref(&auth_pool);
lprcpt = p_new(rcpt->pool, struct lmtp_proxy_recipient, 1);
lprcpt->rcpt = lrcpt;
lrcpt->type = LMTP_RECIPIENT_TYPE_PROXY;
lrcpt->backend_context = lprcpt;
+ /* Copy forward fields returned from passdb */
+ fwfields = NULL;
+ for (const char *const *ptr = fields; *ptr != NULL; ptr++) {
+ if (strncasecmp(*ptr, "forward_", 8) != 0)
+ continue;
+
+ if (fwfields == NULL)
+ fwfields = t_str_new(128);
+ else
+ str_append_c(fwfields, '\t');
+
+ str_append_tabescaped(fwfields, (*ptr) + 8);
+ }
+ if (fwfields != NULL) {
+ lprcpt->forward_fields = p_memdup(
+ rcpt->pool, str_data(fwfields), str_len(fwfields));
+ lprcpt->forward_fields_size = str_len(fwfields);
+ }
+
+ pool_unref(&auth_pool);
+
smtp_client_connection_connect(conn->lmtp_conn,
lmtp_proxy_rcpt_login_cb, lprcpt);
return 1;