dovecot-2.0: lmtp: Added initial support for proxying mails to o...

dovecot at dovecot.org dovecot at dovecot.org
Mon Aug 31 18:38:54 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/3a16bec9c961
changeset: 9832:3a16bec9c961
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Aug 31 11:38:42 2009 -0400
description:
lmtp: Added initial support for proxying mails to other LMTP/SMTP servers.

diffstat:

7 files changed, 629 insertions(+), 42 deletions(-)
src/lmtp/Makefile.am  |    7 
src/lmtp/client.c     |    4 
src/lmtp/client.h     |    5 
src/lmtp/commands.c   |  256 ++++++++++++++++++++++++++++-----
src/lmtp/lmtp-proxy.c |  370 +++++++++++++++++++++++++++++++++++++++++++++++++
src/lmtp/lmtp-proxy.h |   28 +++
src/lmtp/main.c       |    1 

diffs (truncated from 877 to 300 lines):

diff -r c3da5347b1c5 -r 3a16bec9c961 src/lmtp/Makefile.am
--- a/src/lmtp/Makefile.am	Mon Aug 31 11:37:55 2009 -0400
+++ b/src/lmtp/Makefile.am	Mon Aug 31 11:38:42 2009 -0400
@@ -5,6 +5,7 @@ AM_CPPFLAGS = \
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-settings \
+	-I$(top_srcdir)/src/lib-auth \
 	-I$(top_srcdir)/src/lib-mail \
 	-I$(top_srcdir)/src/lib-imap \
 	-I$(top_srcdir)/src/lib-index \
@@ -28,9 +29,11 @@ lmtp_SOURCES = \
 lmtp_SOURCES = \
 	main.c \
 	client.c \
-	commands.c
+	commands.c \
+	lmtp-proxy.c
 
 noinst_HEADERS = \
 	main.h \
 	client.h \
-	commands.h
+	commands.h \
+	lmtp-proxy.h
diff -r c3da5347b1c5 -r 3a16bec9c961 src/lmtp/client.c
--- a/src/lmtp/client.c	Mon Aug 31 11:37:55 2009 -0400
+++ b/src/lmtp/client.c	Mon Aug 31 11:38:42 2009 -0400
@@ -12,6 +12,7 @@
 #include "mail-namespace.h"
 #include "mail-storage.h"
 #include "main.h"
+#include "lmtp-proxy.h"
 #include "commands.h"
 #include "client.h"
 
@@ -161,6 +162,7 @@ struct client *client_create(int fd_in, 
 	client->my_domain = my_hostname;
 	client->state_pool = pool_alloconly_create("client state", 4096);
 	client->state.mail_data_fd = -1;
+	client->try_proxying = TRUE; // FIXME: setting!
 
 	DLLIST_PREPEND(&clients, client);
 	clients_count++;
@@ -180,6 +182,8 @@ void client_destroy(struct client *clien
 	DLLIST_REMOVE(&clients, client);
 
 	mail_user_unref(&client->raw_mail_user);
+	if (client->proxy != NULL)
+		lmtp_proxy_deinit(&client->proxy);
 	if (client->io != NULL)
 		io_remove(&client->io);
 	timeout_remove(&client->to_idle);
diff -r c3da5347b1c5 -r 3a16bec9c961 src/lmtp/client.h
--- a/src/lmtp/client.h	Mon Aug 31 11:37:55 2009 -0400
+++ b/src/lmtp/client.h	Mon Aug 31 11:38:42 2009 -0400
@@ -34,6 +34,7 @@ struct client {
 struct client {
 	struct client *prev, *next;
 
+	const struct lda_settings *set;
 	int fd_in, fd_out;
 	struct io *io;
 	struct istream *input;
@@ -51,8 +52,12 @@ struct client {
 	pool_t state_pool;
 	struct client_state state;
 	struct istream *dot_input;
+	struct lmtp_proxy *proxy;
 
 	unsigned int disconnected:1;
+	unsigned int try_proxying:1;
+	unsigned int mail_body_7bit:1;
+	unsigned int mail_body_8bitmime:1;
 };
 
 extern unsigned int clients_count;
diff -r c3da5347b1c5 -r 3a16bec9c961 src/lmtp/commands.c
--- a/src/lmtp/commands.c	Mon Aug 31 11:37:55 2009 -0400
+++ b/src/lmtp/commands.c	Mon Aug 31 11:38:42 2009 -0400
@@ -8,6 +8,8 @@
 #include "ostream.h"
 #include "istream-dot.h"
 #include "safe-mkstemp.h"
+#include "master-service.h"
+#include "auth-master.h"
 #include "mail-storage-service.h"
 #include "index/raw/raw-storage.h"
 #include "lda-settings.h"
@@ -15,8 +17,12 @@
 #include "main.h"
 #include "client.h"
 #include "commands.h"
-
-#define ERRSTR_MAILBOX_TEMP_FAIL "451 4.2.0 <%s> Temporary internal error"
+#include "lmtp-proxy.h"
+
+#include <stdlib.h>
+
+#define ERRSTR_TEMP_MAILBOX_FAIL "451 4.3.0 <%s> Temporary internal error"
+#define ERRSTR_TEMP_USERDB_FAIL "451 4.3.0 <%s> Temporary user lookup failure"
 
 int cmd_lhlo(struct client *client, const char *args ATTR_UNUSED)
 {
@@ -52,10 +58,11 @@ int cmd_mail(struct client *client, cons
 	}
 
 	for (; *argv != NULL; argv++) {
-		if (strcasecmp(*argv, "BODY=7BIT") == 0 ||
-		    strcasecmp(*argv, "BODY=8BITMIME") == 0) {
-			/* just skip these */
-		} else {
+		if (strcasecmp(*argv, "BODY=7BIT") == 0)
+			client->mail_body_7bit = TRUE;
+		else if (strcasecmp(*argv, "BODY=8BITMIME") == 0)
+			client->mail_body_8bitmime = TRUE;
+		else {
 			client_send_line(client,
 				"501 5.5.4 Unsupported options");
 			return 0;
@@ -82,13 +89,133 @@ static bool rcpt_is_duplicate(struct cli
 	return FALSE;
 }
 
+static bool
+client_proxy_rcpt_parse_fields(struct lmtp_proxy_settings *set,
+			       const char *const *args, const char **address)
+{
+	const char *p, *key, *value;
+	bool proxying = FALSE;
+
+	for (; *args != NULL; args++) {
+		p = strchr(*args, '=');
+		if (p == NULL) {
+			key = *args;
+			value = "";
+		} else {
+			key = t_strdup_until(*args, p);
+			value = p + 1;
+		}
+
+		if (strcmp(key, "proxy") == 0)
+			proxying = TRUE;
+		else if (strcmp(key, "host") == 0)
+			set->host = value;
+		else if (strcmp(key, "port") == 0)
+			set->port = atoi(value);
+		else if (strcmp(key, "user") == 0) {
+			/* changing the username */
+			*address = value;
+		} else {
+			/* just ignore it */
+		}
+	}
+	if (proxying && set->host == NULL) {
+		i_error("proxy: host not given");
+		return FALSE;
+	}
+	return proxying;
+}
+
+static bool
+client_proxy_is_ourself(const struct client *client,
+			const struct lmtp_proxy_settings *set)
+{
+	struct ip_addr ip;
+
+	if (set->port != client->local_port)
+		return FALSE;
+
+	if (net_addr2ip(set->host, &ip) < 0)
+		return FALSE;
+	if (!net_ip_compare(&ip, &client->local_ip))
+		return FALSE;
+	return TRUE;
+}
+
+static bool client_proxy_rcpt(struct client *client, const char *address)
+{
+	struct auth_master_connection *auth_conn;
+	struct lmtp_proxy_settings set;
+	struct auth_user_info info;
+	const char *args, *const *fields, *orig_address = address;
+	pool_t pool;
+	int ret;
+
+	memset(&info, 0, sizeof(info));
+	info.service = master_service_get_name(master_service);
+	info.local_ip = client->local_ip;
+	info.remote_ip = client->remote_ip;
+	info.local_port = client->local_port;
+	info.remote_port = client->remote_port;
+
+	pool = pool_alloconly_create("auth lookup", 1024);
+	auth_conn = mail_storage_service_multi_get_auth_conn(multi_service);
+	ret = auth_master_pass_lookup(auth_conn, address, &info,
+				      pool, &fields);
+	if (ret <= 0) {
+		pool_unref(&pool);
+		if (ret < 0) {
+			client_send_line(client, ERRSTR_TEMP_USERDB_FAIL,
+					 address);
+			return TRUE;
+		} else {
+			/* user not found from passdb. try userdb also. */
+			return FALSE;
+		}
+	}
+
+	memset(&set, 0, sizeof(set));
+	set.port = client->local_port;
+	if (!client_proxy_rcpt_parse_fields(&set, fields, &address)) {
+		/* not proxying this user */
+		pool_unref(&pool);
+		return FALSE;
+	}
+	if (strcmp(address, orig_address) == 0 &&
+	    client_proxy_is_ourself(client, &set)) {
+		i_error("Proxying to <%s> loops to itself", address);
+		client_send_line(client, "554 5.4.6 Proxying loops to itself");
+		pool_unref(&pool);
+		return FALSE;
+	}
+
+	if (client->proxy == NULL) {
+		client->proxy = lmtp_proxy_init(client->set->hostname,
+						client->output);
+		if (client->mail_body_8bitmime)
+			args = " BODY=8BITMIME";
+		else if (client->mail_body_7bit)
+			args = " BODY=7BIT";
+		else
+			args = "";
+		lmtp_proxy_mail_from(client->proxy, t_strdup_printf(
+			"<%s>%s", client->state.mail_from, args));
+	}
+	if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0)
+		client_send_line(client, ERRSTR_TEMP_REMOTE_FAILURE);
+	else
+		client_send_line(client, "250 2.1.5 OK");
+	pool_unref(&pool);
+	return TRUE;
+}
+
 int cmd_rcpt(struct client *client, const char *args)
 {
 	struct mail_recipient rcpt;
 	struct mail_storage_service_input input;
-	const char *name, *error, *addr, *const *argv;
+	const char *name, *error = NULL, *addr, *const *argv;
 	unsigned int len;
-	int ret;
+	int ret = 0;
 
 	if (client->state.mail_from == NULL) {
 		client_send_line(client, "503 5.5.1 MAIL needed first");
@@ -121,6 +248,11 @@ int cmd_rcpt(struct client *client, cons
 		return 0;
 	}
 
+	if (client->try_proxying) {
+		if (client_proxy_rcpt(client, name))
+			return 0;
+	}
+
 	memset(&input, 0, sizeof(input));
 	input.username = name;
 	input.local_ip = client->local_ip;
@@ -129,10 +261,10 @@ int cmd_rcpt(struct client *client, cons
 	ret = mail_storage_service_multi_lookup(multi_service, &input,
 						client->state_pool,
 						&rcpt.multi_user, &error);
+
 	if (ret < 0) {
 		i_error("User lookup failed: %s", error);
-		client_send_line(client,
-				 "451 4.3.0 Temporary user lookup failure");
+		client_send_line(client, ERRSTR_TEMP_USERDB_FAIL, name);
 		return 0;
 	}
 	if (ret == 0) {
@@ -189,7 +321,7 @@ client_deliver(struct client *client, co
 					    &client->state.dest_user,
 					    &error) < 0) {
 		i_error("%s", error);
-		client_send_line(client, ERRSTR_MAILBOX_TEMP_FAIL, rcpt->name);
+		client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, rcpt->name);
 		return -1;
 	}
 	sets = mail_storage_service_multi_user_get_set(rcpt->multi_user);
@@ -215,7 +347,7 @@ client_deliver(struct client *client, co
 	} else if (storage == NULL) {
 		/* This shouldn't happen */
 		i_error("BUG: Saving failed to unknown storage");
-		client_send_line(client, ERRSTR_MAILBOX_TEMP_FAIL,
+		client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
 				 rcpt->name);
 		ret = -1;
 	} else {
@@ -264,12 +396,28 @@ static void client_rcpt_fail_all(struct 


More information about the dovecot-cvs mailing list