From 5f2855fe620b87f960dc24e16c578a4c820ef45c Mon Sep 17 00:00:00 2001 From: Stephan Bosch Date: Sun, 6 Nov 2016 17:34:25 +0100 Subject: [PATCH] lmtp: Moved code relating to proxy from commands.c to lmtp-proxy.c. --- src/lmtp/commands.c | 211 ----------------------------------------- src/lmtp/lmtp-proxy.c | 215 ++++++++++++++++++++++++++++++++++++++++++ src/lmtp/lmtp-proxy.h | 10 ++ 3 files changed, 225 insertions(+), 211 deletions(-) diff --git a/src/lmtp/commands.c b/src/lmtp/commands.c index d4cc914449..f7f12dec1e 100644 --- a/src/lmtp/commands.c +++ b/src/lmtp/commands.c @@ -16,7 +16,6 @@ #include "iostream-ssl.h" #include "rfc822-parser.h" #include "message-date.h" -#include "auth-master.h" #include "mail-storage-service.h" #include "index/raw/raw-storage.h" #include "lda-settings.h" @@ -30,11 +29,6 @@ #include "lmtp-proxy.h" #define ERRSTR_TEMP_MAILBOX_FAIL "451 4.3.0 <%s> Temporary internal error" -#define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> " -#define ERRSTR_TEMP_USERDB_FAIL \ - ERRSTR_TEMP_USERDB_FAIL_PREFIX "Temporary user lookup failure" - -#define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*125) int cmd_lhlo(struct client *client, const char *args) { @@ -173,211 +167,6 @@ int cmd_mail(struct client *client, const char *args) return 0; } -static bool -client_proxy_rcpt_parse_fields(struct lmtp_proxy_rcpt_settings *set, - const char *const *args, const char **address) -{ - const char *p, *key, *value; - bool proxying = FALSE, port_set = 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, "hostip") == 0) { - if (net_addr2ip(value, &set->hostip) < 0) { - i_error("proxy: Invalid hostip %s", value); - return FALSE; - } - } else if (strcmp(key, "port") == 0) { - if (net_str2port(value, &set->port) < 0) { - i_error("proxy: Invalid port number %s", value); - return FALSE; - } - port_set = TRUE; - } else if (strcmp(key, "proxy_timeout") == 0) { - if (str_to_uint(value, &set->timeout_msecs) < 0) { - i_error("proxy: Invalid proxy_timeout value %s", value); - return FALSE; - } - set->timeout_msecs *= 1000; - } else if (strcmp(key, "protocol") == 0) { - if (strcmp(value, "lmtp") == 0) { - set->protocol = SMTP_PROTOCOL_LMTP; - if (!port_set) - set->port = 24; - } else if (strcmp(value, "smtp") == 0) { - set->protocol = SMTP_PROTOCOL_SMTP; - if (!port_set) - set->port = 25; - } else { - i_error("proxy: Unknown protocol %s", value); - return FALSE; - } - } else if (strcmp(key, "user") == 0 || - strcmp(key, "destuser") == 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_rcpt_settings *set) -{ - struct ip_addr ip; - - if (set->port != client->local_port) - return FALSE; - - if (set->hostip.family != 0) - ip = set->hostip; - else { - 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, - struct smtp_address *address, - const char *username, const char *detail, char delim, - struct smtp_params_rcpt *params) -{ - struct auth_master_connection *auth_conn; - struct lmtp_proxy_rcpt_settings set; - struct auth_user_info info; - struct mail_storage_service_input input; - const char *const *fields, *errstr, *orig_username = username; - struct smtp_address *user; - pool_t pool; - int ret; - - i_zero(&input); - input.module = input.service = "lmtp"; - mail_storage_service_init_settings(storage_service, &input); - - i_zero(&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_get_auth_conn(storage_service); - ret = auth_master_pass_lookup(auth_conn, username, &info, - pool, &fields); - if (ret <= 0) { - errstr = ret < 0 && fields[0] != NULL ? t_strdup(fields[0]) : - t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL, - smtp_address_encode(address)); - pool_unref(&pool); - if (ret < 0) { - client_send_line(client, "%s", errstr); - return TRUE; - } else { - /* user not found from passdb. try userdb also. */ - return FALSE; - } - } - - i_zero(&set); - set.port = client->local_port; - set.protocol = SMTP_PROTOCOL_LMTP; - set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS; - set.params = *params; - - if (!client_proxy_rcpt_parse_fields(&set, fields, &username)) { - /* not proxying this user */ - pool_unref(&pool); - return FALSE; - } - if (strcmp(username, orig_username) != 0) { - if (smtp_address_parse_username(pool_datastack_create(), - username, &user, &errstr) < 0) { - i_error("%s: Username `%s' returned by passdb lookup is not a valid SMTP address", - orig_username, username); - client_send_line(client, "550 5.3.5 <%s> " - "Internal user lookup failure", - smtp_address_encode(address)); - pool_unref(&pool); - return FALSE; - } - /* username changed. change the address as well */ - if (*detail == '\0') { - address = user; - } else { - address = smtp_address_add_detail_temp(user, detail, delim); - } - } else if (client_proxy_is_ourself(client, &set)) { - i_error("Proxying to <%s> loops to itself", username); - client_send_line(client, "554 5.4.6 <%s> " - "Proxying loops to itself", - smtp_address_encode(address)); - pool_unref(&pool); - return TRUE; - } - - if (client->proxy_ttl <= 1) { - i_error("Proxying to <%s> appears to be looping (TTL=0)", - username); - client_send_line(client, "554 5.4.6 <%s> " - "Proxying appears to be looping (TTL=0)", - username); - pool_unref(&pool); - return TRUE; - } - if (array_count(&client->state.rcpt_to) != 0) { - client_send_line(client, "451 4.3.0 <%s> " - "Can't handle mixed proxy/non-proxy destinations", - smtp_address_encode(address)); - pool_unref(&pool); - return TRUE; - } - if (client->proxy == NULL) { - struct lmtp_proxy_settings proxy_set; - - i_zero(&proxy_set); - proxy_set.my_hostname = client->my_domain; - proxy_set.dns_client_socket_path = dns_client_socket_path; - proxy_set.session_id = client->state.session_id; - proxy_set.source_ip = client->remote_ip; - proxy_set.source_port = client->remote_port; - proxy_set.proxy_ttl = client->proxy_ttl-1; - - client->proxy = lmtp_proxy_init(&proxy_set, client->output); - lmtp_proxy_mail_from(client->proxy, client->state.mail_from, - &client->state.mail_params); - } - if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0) - client_send_line(client, "451 4.4.0 Remote server not answering"); - 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; diff --git a/src/lmtp/lmtp-proxy.c b/src/lmtp/lmtp-proxy.c index 95cb868d46..63667919f2 100644 --- a/src/lmtp/lmtp-proxy.c +++ b/src/lmtp/lmtp-proxy.c @@ -12,9 +12,19 @@ #include "smtp-client.h" #include "smtp-client-connection.h" #include "smtp-client-transaction.h" +#include "auth-master.h" +#include "master-service.h" +#include "mail-storage-service.h" +#include "client.h" +#include "main.h" #include "lmtp-proxy.h" #define LMTP_MAX_LINE_LEN 1024 +#define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*125) + +#define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> " +#define ERRSTR_TEMP_USERDB_FAIL \ + ERRSTR_TEMP_USERDB_FAIL_PREFIX "Temporary user lookup failure" struct lmtp_proxy_recipient { struct lmtp_proxy_connection *conn; @@ -380,6 +390,211 @@ lmtp_proxy_data_dummy_cb(const struct smtp_reply *proxy_reply ATTR_UNUSED, /* nothing */ } +static bool +client_proxy_rcpt_parse_fields(struct lmtp_proxy_rcpt_settings *set, + const char *const *args, const char **address) +{ + const char *p, *key, *value; + bool proxying = FALSE, port_set = 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, "hostip") == 0) { + if (net_addr2ip(value, &set->hostip) < 0) { + i_error("proxy: Invalid hostip %s", value); + return FALSE; + } + } else if (strcmp(key, "port") == 0) { + if (net_str2port(value, &set->port) < 0) { + i_error("proxy: Invalid port number %s", value); + return FALSE; + } + port_set = TRUE; + } else if (strcmp(key, "proxy_timeout") == 0) { + if (str_to_uint(value, &set->timeout_msecs) < 0) { + i_error("proxy: Invalid proxy_timeout value %s", value); + return FALSE; + } + set->timeout_msecs *= 1000; + } else if (strcmp(key, "protocol") == 0) { + if (strcmp(value, "lmtp") == 0) { + set->protocol = SMTP_PROTOCOL_LMTP; + if (!port_set) + set->port = 24; + } else if (strcmp(value, "smtp") == 0) { + set->protocol = SMTP_PROTOCOL_SMTP; + if (!port_set) + set->port = 25; + } else { + i_error("proxy: Unknown protocol %s", value); + return FALSE; + } + } else if (strcmp(key, "user") == 0 || + strcmp(key, "destuser") == 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_rcpt_settings *set) +{ + struct ip_addr ip; + + if (set->port != client->local_port) + return FALSE; + + if (set->hostip.family != 0) + ip = set->hostip; + else { + if (net_addr2ip(set->host, &ip) < 0) + return FALSE; + } + if (!net_ip_compare(&ip, &client->local_ip)) + return FALSE; + return TRUE; +} + +bool client_proxy_rcpt(struct client *client, + struct smtp_address *address, + const char *username, const char *detail, char delim, + struct smtp_params_rcpt *params) +{ + struct auth_master_connection *auth_conn; + struct lmtp_proxy_rcpt_settings set; + struct auth_user_info info; + struct mail_storage_service_input input; + const char *const *fields, *errstr, *orig_username = username; + struct smtp_address *user; + pool_t pool; + int ret; + + i_zero(&input); + input.module = input.service = "lmtp"; + mail_storage_service_init_settings(storage_service, &input); + + i_zero(&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_get_auth_conn(storage_service); + ret = auth_master_pass_lookup(auth_conn, username, &info, + pool, &fields); + if (ret <= 0) { + errstr = ret < 0 && fields[0] != NULL ? t_strdup(fields[0]) : + t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL, + smtp_address_encode(address)); + pool_unref(&pool); + if (ret < 0) { + client_send_line(client, "%s", errstr); + return TRUE; + } else { + /* user not found from passdb. try userdb also. */ + return FALSE; + } + } + + i_zero(&set); + set.port = client->local_port; + set.protocol = SMTP_PROTOCOL_LMTP; + set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS; + set.params = *params; + + if (!client_proxy_rcpt_parse_fields(&set, fields, &username)) { + /* not proxying this user */ + pool_unref(&pool); + return FALSE; + } + if (strcmp(username, orig_username) != 0) { + if (smtp_address_parse_username(pool_datastack_create(), + username, &user, &errstr) < 0) { + i_error("%s: Username `%s' returned by passdb lookup is not a valid SMTP address", + orig_username, username); + client_send_line(client, "550 5.3.5 <%s> " + "Internal user lookup failure", + smtp_address_encode(address)); + pool_unref(&pool); + return FALSE; + } + /* username changed. change the address as well */ + if (*detail == '\0') { + address = user; + } else { + address = smtp_address_add_detail_temp(user, detail, delim); + } + } else if (client_proxy_is_ourself(client, &set)) { + i_error("Proxying to <%s> loops to itself", username); + client_send_line(client, "554 5.4.6 <%s> " + "Proxying loops to itself", + smtp_address_encode(address)); + pool_unref(&pool); + return TRUE; + } + + if (client->proxy_ttl <= 1) { + i_error("Proxying to <%s> appears to be looping (TTL=0)", + username); + client_send_line(client, "554 5.4.6 <%s> " + "Proxying appears to be looping (TTL=0)", + username); + pool_unref(&pool); + return TRUE; + } + if (array_count(&client->state.rcpt_to) != 0) { + client_send_line(client, "451 4.3.0 <%s> " + "Can't handle mixed proxy/non-proxy destinations", + smtp_address_encode(address)); + pool_unref(&pool); + return TRUE; + } + if (client->proxy == NULL) { + struct lmtp_proxy_settings proxy_set; + + i_zero(&proxy_set); + proxy_set.my_hostname = client->my_domain; + proxy_set.dns_client_socket_path = dns_client_socket_path; + proxy_set.session_id = client->state.session_id; + proxy_set.source_ip = client->remote_ip; + proxy_set.source_port = client->remote_port; + proxy_set.proxy_ttl = client->proxy_ttl-1; + + client->proxy = lmtp_proxy_init(&proxy_set, client->output); + lmtp_proxy_mail_from(client->proxy, client->state.mail_from, + &client->state.mail_params); + } + if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0) + client_send_line(client, "451 4.4.0 Remote server not answering"); + else + client_send_line(client, "250 2.1.5 OK"); + pool_unref(&pool); + return TRUE; +} + void lmtp_proxy_start(struct lmtp_proxy *proxy, struct istream *data_input, lmtp_proxy_finish_callback_t *callback, void *context) { diff --git a/src/lmtp/lmtp-proxy.h b/src/lmtp/lmtp-proxy.h index 05c7a05159..f10e73bb50 100644 --- a/src/lmtp/lmtp-proxy.h +++ b/src/lmtp/lmtp-proxy.h @@ -8,6 +8,9 @@ #define LMTP_PROXY_DEFAULT_TTL 5 +struct smtp_address; +struct client; + struct lmtp_proxy_settings { const char *my_hostname; const char *dns_client_socket_path; @@ -44,9 +47,16 @@ void lmtp_proxy_mail_from(struct lmtp_proxy *proxy, int lmtp_proxy_add_rcpt(struct lmtp_proxy *proxy, const struct smtp_address *address, const struct lmtp_proxy_rcpt_settings *set); + +bool client_proxy_rcpt(struct client *client, + struct smtp_address *address, + const char *username, const char *detail, char delim, + struct smtp_params_rcpt *params); + /* Start proxying */ void lmtp_proxy_start(struct lmtp_proxy *proxy, struct istream *data_input, lmtp_proxy_finish_callback_t *callback, void *context) ATTR_NULL(3); + #endif -- 2.47.3