]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Support transferring original IPs and ports through IMAP proxies.
authorTimo Sirainen <tss@iki.fi>
Sat, 21 Jun 2008 07:10:06 +0000 (10:10 +0300)
committerTimo Sirainen <tss@iki.fi>
Sat, 21 Jun 2008 07:10:06 +0000 (10:10 +0300)
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.

--HG--
branch : HEAD

12 files changed:
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

index ebad3364c2d263495110ae340e67e2e7aab3b4a3..a7d58352ad7ff682d276fe7d020351320d3f2a04 100644 (file)
 # 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.
index 8dfad62195b028bad3e23c28f3452fc44f91adc2..7c01ce465af1223c941012b2958da30d4fe1c16c 100644 (file)
@@ -200,12 +200,40 @@ static int cmd_starttls(struct imap_client *client)
        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 @@ struct client *client_create(int fd, bool ssl, const struct ip_addr *local_ip,
        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);
index 9d212eb9061c24f78513d21f6d90b4f19aa60530..e3c186acbd4813ba7de4ce52abbbf51dfa39c4bf 100644 (file)
 #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 @@ static int proxy_input_line(struct imap_client *client,
                        return -1;
                }
 
-               /* send LOGIN command */
                str = t_str_new(128);
+               if (imap_banner_has_capability(line + 5, "ID"))
+                       proxy_write_id(client, str);
+
+               /* send LOGIN command */
                str_append(str, "P LOGIN ");
                imap_quote_append_string(str, client->proxy_user, FALSE);
                str_append_c(str, ' ');
index 86b23e4f348fc143b9dcaf20d807a577fae53f4a..3c70772bc9ee308332efba2b89f032b8ebf0973b 100644 (file)
@@ -151,3 +151,26 @@ void client_syslog(struct client *client, const char *msg)
                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;
+}
index 850412bd66ce771ea3e9e7871b3fd8f0dc85426f..23ea65d76979f3b74bd59d03fa957f5e1dc37467 100644 (file)
@@ -27,6 +27,7 @@ struct client {
        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 @@ void client_unlink(struct client *client);
 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);
index 205580282ea42ef8f7cba2bc3356d93ebe763002..68158ecee68535f13e00dc11b3484328464fffa0 100644 (file)
@@ -18,6 +18,7 @@ extern bool verbose_proctitle, verbose_ssl, verbose_auth;
 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;
index 42778073c8c4ddfc92fd52f815b66dd46554110e..282030e36966fa5bb58e525dd839d4659ab05e71 100644 (file)
@@ -23,6 +23,7 @@ bool disable_plaintext_auth, process_per_connection, greeting_capability;
 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 @@ static void main_init(void)
        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");
index 6cd7d63e48803ff04c4ec148a3ddba54c4474285..be254d9623a24c104377d7cb2c9e57e160f82f3e 100644 (file)
@@ -582,6 +582,10 @@ static void login_process_init_env(struct login_group *group, pid_t pid)
                                    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)
index 41b21b72f80dd2673eb78f32fdc9a218cbf1c4d0..cc458ab860fba5b1efb2c96fffb45a7518799cce 100644 (file)
@@ -46,6 +46,7 @@ static struct setting_def setting_defs[] = {
        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),
index ea87462f5ac7f85bc4abc90e8774c3affaa9853c..46e695b4540da129e329645d2a4dfb39693ee4f3 100644 (file)
@@ -208,6 +208,7 @@ struct settings default_settings = {
        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,
index 58fe37430fc07e868b477abb8066d1c2d4973fb5..fb6d41ba859fe316b02bda4fb40c805d952d4611 100644 (file)
@@ -60,6 +60,7 @@ struct settings {
        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;
index a2ad08e218c26a689888e2493136ab49e3f6db5f..bf5fe0ef249af23833163e5b47b5105a67dba81f 100644 (file)
@@ -317,12 +317,15 @@ struct client *client_create(int fd, bool ssl, const struct ip_addr *local_ip,
        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);