From: Timo Sirainen Date: Sat, 21 Jun 2008 07:10:06 +0000 (+0300) Subject: Support transferring original IPs and ports through IMAP proxies. X-Git-Tag: 1.2.alpha1~241 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=89795c6bbbc52bb382e88bc8617d22092223e9a5;p=thirdparty%2Fdovecot%2Fcore.git 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. --HG-- branch : HEAD --- diff --git a/dovecot-example.conf b/dovecot-example.conf index ebad3364c2..a7d58352ad 100644 --- a/dovecot-example.conf +++ b/dovecot-example.conf @@ -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. diff --git a/src/imap-login/client.c b/src/imap-login/client.c index 8dfad62195..7c01ce465a 100644 --- a/src/imap-login/client.c +++ b/src/imap-login/client.c @@ -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); diff --git a/src/imap-login/imap-proxy.c b/src/imap-login/imap-proxy.c index 9d212eb906..e3c186acbd 100644 --- a/src/imap-login/imap-proxy.c +++ b/src/imap-login/imap-proxy.c @@ -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 @@ 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, ' '); diff --git a/src/login-common/client-common.c b/src/login-common/client-common.c index 86b23e4f34..3c70772bc9 100644 --- a/src/login-common/client-common.c +++ b/src/login-common/client-common.c @@ -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; +} diff --git a/src/login-common/client-common.h b/src/login-common/client-common.h index 850412bd66..23ea65d769 100644 --- a/src/login-common/client-common.h +++ b/src/login-common/client-common.h @@ -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); diff --git a/src/login-common/common.h b/src/login-common/common.h index 205580282e..68158ecee6 100644 --- a/src/login-common/common.h +++ b/src/login-common/common.h @@ -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; diff --git a/src/login-common/main.c b/src/login-common/main.c index 42778073c8..282030e369 100644 --- a/src/login-common/main.c +++ b/src/login-common/main.c @@ -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"); diff --git a/src/master/login-process.c b/src/master/login-process.c index 6cd7d63e48..be254d9623 100644 --- a/src/master/login-process.c +++ b/src/master/login-process.c @@ -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) diff --git a/src/master/master-settings-defs.c b/src/master/master-settings-defs.c index 41b21b72f8..cc458ab860 100644 --- a/src/master/master-settings-defs.c +++ b/src/master/master-settings-defs.c @@ -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), diff --git a/src/master/master-settings.c b/src/master/master-settings.c index ea87462f5a..46e695b454 100644 --- a/src/master/master-settings.c +++ b/src/master/master-settings.c @@ -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, diff --git a/src/master/master-settings.h b/src/master/master-settings.h index 58fe37430f..fb6d41ba85 100644 --- a/src/master/master-settings.h +++ b/src/master/master-settings.h @@ -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; diff --git a/src/pop3-login/client.c b/src/pop3-login/client.c index a2ad08e218..bf5fe0ef24 100644 --- a/src/pop3-login/client.c +++ b/src/pop3-login/client.c @@ -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);