changeset 7920:3644883cf44e HEAD

Support transferring original IPs and ports through IMAP proxies. Clients from login_trusted_networks are allowed to override them. Dovecot's IMAP proxy sends them via IMAP ID command. They're always sent if the remote advertises ID in the banner's CAPABILITY.
author Timo Sirainen <tss@iki.fi>
date Sat, 21 Jun 2008 10:10:06 +0300
parents 423b8e3fedbb
children 9a7469e52f91
files dovecot-example.conf src/imap-login/client.c src/imap-login/imap-proxy.c src/login-common/client-common.c src/login-common/client-common.h src/login-common/common.h src/login-common/main.c src/master/login-process.c src/master/master-settings-defs.c src/master/master-settings.c src/master/master-settings.h src/pop3-login/client.c
diffstat 12 files changed, 118 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Sat Jun 21 09:54:26 2008 +0300
+++ b/dovecot-example.conf	Sat Jun 21 10:10:06 2008 +0300
@@ -174,6 +174,12 @@
 # Greeting message for clients.
 #login_greeting = Dovecot ready.
 
+# Space separated list of trusted network ranges. Connections from these
+# IPs are allowed to override their IP addresses and ports (for logging and
+# for authentication checks). disable_plaintext_auth is also ignored for
+# these networks. Typically you'd specify your IMAP proxy servers here.
+#login_trusted_networks =
+
 # Space-separated list of elements we want to log. The elements which have
 # a non-empty variable value are joined together to form a comma-separated
 # string.
--- a/src/imap-login/client.c	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/imap-login/client.c	Sat Jun 21 10:10:06 2008 +0300
@@ -200,12 +200,40 @@
 	return 1;
 }
 
+static void
+client_update_info(struct imap_client *client, const struct imap_arg *args)
+{
+	const char *key, *value;
+
+	if (args->type != IMAP_ARG_LIST)
+		return;
+	args = IMAP_ARG_LIST_ARGS(args);
+
+	while (args->type == IMAP_ARG_STRING &&
+	       args[1].type == IMAP_ARG_STRING) {
+		key = IMAP_ARG_STR_NONULL(&args[0]);
+		value = IMAP_ARG_STR_NONULL(&args[1]);
+		if (strcasecmp(key, "x-originating-ip") == 0)
+			(void)net_addr2ip(value, &client->common.ip);
+		else if (strcasecmp(key, "x-originating-port") == 0)
+			client->common.remote_port = atoi(value);
+		else if (strcasecmp(key, "x-local-ip") == 0)
+			(void)net_addr2ip(value, &client->common.local_ip);
+		else if (strcasecmp(key, "x-local-port") == 0)
+			client->common.local_port = atoi(value);
+		args += 2;
+	}
+}
+
 static int cmd_id(struct imap_client *client, const struct imap_arg *args)
 {
 	const char *env, *value;
 
 	if (!client->id_logged) {
 		client->id_logged = TRUE;
+		if (client->common.trusted)
+			client_update_info(client, args);
+
 		env = getenv("IMAP_ID_LOG");
 		value = imap_id_args_get_log_reply(args, env);
 		if (value != NULL) {
@@ -478,12 +506,14 @@
 	client = i_new(struct imap_client, 1);
 	client->created = ioloop_time;
 	client->refcount = 1;
-	client->common.tls = ssl;
-	client->common.secured = ssl || net_ip_compare(ip, local_ip);
 
 	client->common.local_ip = *local_ip;
 	client->common.ip = *ip;
 	client->common.fd = fd;
+	client->common.tls = ssl;
+	client->common.trusted = client_is_trusted(&client->common);
+	client->common.secured = ssl || client->common.trusted ||
+		net_ip_compare(ip, local_ip);
 
 	client_open_streams(client, fd);
 	client->io = io_add(fd, IO_READ, client_input, client);
--- a/src/imap-login/imap-proxy.c	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/imap-login/imap-proxy.c	Sat Jun 21 10:10:06 2008 +0300
@@ -11,6 +11,41 @@
 #include "imap-quote.h"
 #include "imap-proxy.h"
 
+static bool imap_banner_has_capability(const char *line, const char *capability)
+{
+	unsigned int capability_len = strlen(capability);
+
+	if (strncmp(line, "[CAPABILITY ", 12) != 0)
+		return FALSE;
+
+	line += 12;
+	while (strncmp(line, capability, capability_len) != 0 ||
+	       (line[capability_len] != ' ' &&
+		line[capability_len] != '\0')) {
+		/* skip over the capability */
+		while (*line != ' ') {
+			if (*line == '\0')
+				return FALSE;
+			line++;
+		}
+		line++;
+	}
+	return TRUE;
+}
+
+static void proxy_write_id(struct imap_client *client, string_t *str)
+{
+	str_printfa(str, "I ID ("
+		    "\"x-originating-ip\" \"%s\" "
+		    "\"x-originating-port\" \"%u\" "
+		    "\"x-local-ip\" \"%s\" "
+		    "\"x-local-port\" \"%u\")\r\n",
+		    net_ip2addr(&client->common.ip),
+		    client->common.remote_port,
+		    net_ip2addr(&client->common.local_ip),
+		    client->common.local_port);
+}
+
 static int proxy_input_line(struct imap_client *client,
 			    struct ostream *output, const char *line)
 {
@@ -29,8 +64,11 @@
 			return -1;
 		}
 
+		str = t_str_new(128);
+		if (imap_banner_has_capability(line + 5, "ID"))
+			proxy_write_id(client, str);
+
 		/* send LOGIN command */
-		str = t_str_new(128);
 		str_append(str, "P LOGIN ");
 		imap_quote_append_string(str, client->proxy_user, FALSE);
 		str_append_c(str, ' ');
--- a/src/login-common/client-common.c	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/login-common/client-common.c	Sat Jun 21 10:10:06 2008 +0300
@@ -151,3 +151,26 @@
 		client_syslog_real(client, msg);
 	} T_END;
 }
+
+bool client_is_trusted(struct client *client)
+{
+	const char *const *net;
+	struct ip_addr net_ip;
+	unsigned int bits;
+
+	if (trusted_networks == NULL)
+		return FALSE;
+
+	net = t_strsplit_spaces(trusted_networks, ", ");
+	for (; *net != NULL; net++) {
+		if (net_parse_range(*net, &net_ip, &bits) < 0) {
+			i_error("login_trusted_networks: "
+				"Invalid network '%s'", *net);
+			break;
+		}
+
+		if (net_is_in_network(&client->ip, &net_ip, bits))
+			return TRUE;
+	}
+	return FALSE;
+}
--- a/src/login-common/client-common.h	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/login-common/client-common.h	Sat Jun 21 10:10:06 2008 +0300
@@ -27,6 +27,7 @@
 	char *virtual_user;
 	unsigned int tls:1;
 	unsigned int secured:1;
+	unsigned int trusted:1;
 	unsigned int authenticating:1;
 	unsigned int auth_tried_disabled_plaintext:1;
 	/* ... */
@@ -42,6 +43,7 @@
 unsigned int clients_get_count(void) ATTR_PURE;
 
 void client_syslog(struct client *client, const char *msg);
+bool client_is_trusted(struct client *client);
 
 void clients_notify_auth_connected(void);
 void client_destroy_oldest(void);
--- a/src/login-common/common.h	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/login-common/common.h	Sat Jun 21 10:10:06 2008 +0300
@@ -18,6 +18,7 @@
 extern const char *greeting, *log_format;
 extern const char *const *log_format_elements;
 extern const char *capability_string;
+extern const char *trusted_networks;
 extern unsigned int max_connections;
 extern unsigned int login_process_uid;
 extern struct auth_client *auth_client;
--- a/src/login-common/main.c	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/login-common/main.c	Sat Jun 21 10:10:06 2008 +0300
@@ -23,6 +23,7 @@
 bool verbose_proctitle, verbose_ssl, verbose_auth;
 const char *greeting, *log_format;
 const char *const *log_format_elements;
+const char *trusted_networks;
 unsigned int max_connections;
 unsigned int login_process_uid;
 struct auth_client *auth_client;
@@ -329,6 +330,8 @@
 	if (log_format == NULL)
 		log_format = "%$: %s";
 
+	trusted_networks = getenv("TRUSTED_NETWORKS");
+
 	value = getenv("PROCESS_UID");
 	if (value == NULL)
 		i_fatal("BUG: PROCESS_UID environment not given");
--- a/src/master/login-process.c	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/master/login-process.c	Sat Jun 21 10:10:06 2008 +0300
@@ -582,6 +582,10 @@
 				    set->imap_capability :
 				    set->imap_generated_capability, NULL));
 	}
+	if (*set->login_trusted_networks != '\0') {
+		env_put(t_strconcat("TRUSTED_NETWORKS=",
+				    set->login_trusted_networks, NULL));
+	}
 }
 
 static pid_t create_login_process(struct login_group *group)
--- a/src/master/master-settings-defs.c	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/master/master-settings-defs.c	Sat Jun 21 10:10:06 2008 +0300
@@ -46,6 +46,7 @@
 	DEF_BOOL(login_process_per_connection),
 	DEF_BOOL(login_chroot),
 	DEF_BOOL(login_greeting_capability),
+	DEF_STR(login_trusted_networks),
 
 	DEF_INT(login_process_size),
 	DEF_INT(login_processes_count),
--- a/src/master/master-settings.c	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/master/master-settings.c	Sat Jun 21 10:10:06 2008 +0300
@@ -208,6 +208,7 @@
 	MEMBER(login_process_per_connection) TRUE,
 	MEMBER(login_chroot) TRUE,
 	MEMBER(login_greeting_capability) FALSE,
+	MEMBER(login_trusted_networks) "",
 
 	MEMBER(login_process_size) 64,
 	MEMBER(login_processes_count) 3,
--- a/src/master/master-settings.h	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/master/master-settings.h	Sat Jun 21 10:10:06 2008 +0300
@@ -60,6 +60,7 @@
 	bool login_process_per_connection;
 	bool login_chroot;
 	bool login_greeting_capability;
+	const char *login_trusted_networks;
 
 	unsigned int login_process_size;
 	unsigned int login_processes_count;
--- a/src/pop3-login/client.c	Sat Jun 21 09:54:26 2008 +0300
+++ b/src/pop3-login/client.c	Sat Jun 21 10:10:06 2008 +0300
@@ -317,12 +317,15 @@
 	client = i_new(struct pop3_client, 1);
 	client->created = ioloop_time;
 	client->refcount = 1;
-	client->common.tls = ssl;
-	client->common.secured = ssl || net_ip_compare(ip, local_ip);
 
 	client->common.local_ip = *local_ip;
 	client->common.ip = *ip;
 	client->common.fd = fd;
+	client->common.tls = ssl;
+	client->common.trusted = client_is_trusted(&client->common);
+	client->common.secured = ssl || client->common.trusted ||
+		net_ip_compare(ip, local_ip);
+
 	client_open_streams(client, fd);
 	client_link(&client->common);