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