From 4064f32fc9a00a2aafcf8dfd80d709f4b0db253d Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Thu, 17 Jun 2021 13:17:31 +0300 Subject: [PATCH] *-login: Use auth proxy parsing API --- src/imap-login/client-authenticate.c | 8 +- src/imap-login/imap-proxy.c | 5 +- src/login-common/client-common-auth.c | 167 +++++++++--------------- src/login-common/client-common.h | 15 +-- src/login-common/login-proxy.c | 10 +- src/login-common/login-proxy.h | 14 +- src/pop3-login/pop3-proxy.c | 4 +- src/submission-login/submission-proxy.c | 4 +- 8 files changed, 80 insertions(+), 147 deletions(-) diff --git a/src/imap-login/client-authenticate.c b/src/imap-login/client-authenticate.c index c8c3db288f..f08c313bca 100644 --- a/src/imap-login/client-authenticate.c +++ b/src/imap-login/client-authenticate.c @@ -58,11 +58,11 @@ void imap_client_auth_result(struct client *client, referral = t_str_new(128); i_zero(&url); - url.userid = reply->destuser; + url.userid = reply->proxy.username; url.auth_type = client->auth_mech_name; - url.host.name = reply->host; - if (reply->port != 143) - url.port = reply->port; + url.host.name = reply->proxy.host; + if (reply->proxy.port != 143) + url.port = reply->proxy.port; str_append(referral, "REFERRAL "); str_append(referral, imap_url_create(&url)); diff --git a/src/imap-login/imap-proxy.c b/src/imap-login/imap-proxy.c index f185f3d8ca..772515dada 100644 --- a/src/imap-login/imap-proxy.c +++ b/src/imap-login/imap-proxy.c @@ -68,8 +68,9 @@ static void proxy_write_id(struct imap_client *client, string_t *str) static int proxy_write_starttls(struct imap_client *client, string_t *str) { - enum login_proxy_ssl_flags ssl_flags = login_proxy_get_ssl_flags(client->common.login_proxy); - if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) { + enum auth_proxy_ssl_flags ssl_flags = + login_proxy_get_ssl_flags(client->common.login_proxy); + if ((ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) != 0) { if (client->proxy_backend_capability != NULL && !str_array_icase_find(t_strsplit(client->proxy_backend_capability, " "), "STARTTLS")) { login_proxy_failed(client->common.login_proxy, diff --git a/src/login-common/client-common-auth.c b/src/login-common/client-common-auth.c index 848285a14e..671c835cec 100644 --- a/src/login-common/client-common-auth.c +++ b/src/login-common/client-common-auth.c @@ -135,6 +135,7 @@ static bool client_auth_parse_args(const struct client *client, bool success, struct client_auth_reply *reply_r) { const char *key, *value, *p, *error; + int ret; i_zero(reply_r); t_array_init(&reply_r->alt_usernames, 4); @@ -150,55 +151,22 @@ static bool client_auth_parse_args(const struct client *client, bool success, key = t_strdup_until(*args, p); value = p + 1; } + ret = auth_proxy_settings_parse(&reply_r->proxy, NULL, + key, value, &error); + if (ret < 0) { + e_error(client->event, "Auth service returned invalid " + "%s value '%s': %s", key, value, error); + return FALSE; + } + if (ret > 0) + continue; + if (strcmp(key, "nologin") == 0) { reply_r->nologin = TRUE; reply_r->fail_code = CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED; - } else if (strcmp(key, "proxy") == 0) - reply_r->proxy = TRUE; - else if (strcmp(key, "reason") == 0) + } else if (strcmp(key, "reason") == 0) reply_r->reason = value; - else if (strcmp(key, "host") == 0) - reply_r->host = value; - else if (strcmp(key, "hostip") == 0) { - if (value[0] != '\0' && - net_addr2ip(value, &reply_r->host_ip) < 0) { - e_error(client->event, - "Auth service returned invalid " - "hostip %s", value); - return FALSE; - } - } else if (strcmp(key, "source_ip") == 0) { - if (value[0] != '\0' && - net_addr2ip(value, &reply_r->source_ip) < 0) { - e_error(client->event, - "Auth service returned invalid " - "source_ip %s", value); - return FALSE; - } - } else if (strcmp(key, "port") == 0) { - if (net_str2port(value, &reply_r->port) < 0) { - e_error(client->event, - "Auth service returned invalid " - "port number: %s", value); - return FALSE; - } - } else if (strcmp(key, "destuser") == 0) - reply_r->destuser = value; - else if (strcmp(key, "pass") == 0) - reply_r->password = value; - else if (strcmp(key, "proxy_timeout") == 0) { - /* backwards compatibility: plain number is seconds */ - if (str_to_uint(value, &reply_r->proxy_timeout_msecs) == 0) - reply_r->proxy_timeout_msecs *= 1000; - else if (settings_get_time_msecs(value, - &reply_r->proxy_timeout_msecs, &error) < 0) { - e_error(client->event, - "Auth service returned invalid " - "proxy_timeout value '%s': %s", - value, error); - return FALSE; - } - } else if (strcmp(key, "proxy_host_immediate_failure_after") == 0) { + else if (strcmp(key, "proxy_host_immediate_failure_after") == 0) { if (settings_get_time(value, &reply_r->proxy_host_immediate_failure_after_secs, &error) < 0) { @@ -215,31 +183,6 @@ static bool client_auth_parse_args(const struct client *client, bool success, "proxy_refresh value: %s", value); return FALSE; } - } else if (strcmp(key, "proxy_mech") == 0) - reply_r->proxy_mech = value; - else if (strcmp(key, "proxy_noauth") == 0) - reply_r->proxy_noauth = TRUE; - else if (strcmp(key, "proxy_nopipelining") == 0) - reply_r->proxy_nopipelining = TRUE; - else if (strcmp(key, "proxy_not_trusted") == 0) - reply_r->proxy_not_trusted = TRUE; - else if (strcmp(key, "proxy_redirect_reauth") == 0) - reply_r->proxy_redirect_reauth = TRUE; - else if (strcmp(key, "master") == 0) { - /* ignore empty master field */ - if (*value != '\0') - reply_r->master_user = value; - } else if (strcmp(key, "ssl") == 0) { - reply_r->ssl_flags |= PROXY_SSL_FLAG_YES; - if (strcmp(value, "any-cert") == 0) - reply_r->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT; - if (reply_r->port == 0) - reply_r->port = login_binary->default_ssl_port; - } else if (strcmp(key, "starttls") == 0) { - reply_r->ssl_flags |= PROXY_SSL_FLAG_YES | - PROXY_SSL_FLAG_STARTTLS; - if (strcmp(value, "any-cert") == 0) - reply_r->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT; } else if (strcmp(key, "code") == 0) { if (reply_r->fail_code != CLIENT_AUTH_FAIL_CODE_NONE) { /* code already assigned */ @@ -259,27 +202,34 @@ static bool client_auth_parse_args(const struct client *client, bool success, } else e_debug(event_auth, "Ignoring unknown passdb extra field: %s", key); } - if (reply_r->port == 0) - reply_r->port = login_binary->default_port; + if (reply_r->proxy.port == 0) { + if ((reply_r->proxy.ssl_flags & AUTH_PROXY_SSL_FLAG_YES) != 0 && + (reply_r->proxy.ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) == 0) + reply_r->proxy.port = login_binary->default_ssl_port; + else + reply_r->proxy.port = login_binary->default_port; + } - if (reply_r->destuser == NULL) - reply_r->destuser = client->virtual_user; + if (reply_r->proxy.username == NULL) + reply_r->proxy.username = client->virtual_user; - if (reply_r->proxy) { - if (reply_r->password == NULL) { + if (reply_r->proxy.proxy) { + if (reply_r->proxy.password == NULL) { e_error(client->event, "proxy: pass field is missing"); return FALSE; } - if (reply_r->host == NULL || reply_r->host[0] == '\0') { + if (reply_r->proxy.host == NULL || + reply_r->proxy.host[0] == '\0') { e_error(client->event, "proxy: host field not given"); return FALSE; } - if (reply_r->host_ip.family == 0 && - net_addr2ip(reply_r->host, &reply_r->host_ip) < 0) { + if (reply_r->proxy.host_ip.family == 0 && + net_addr2ip(reply_r->proxy.host, + &reply_r->proxy.host_ip) < 0) { e_error(client->event, "proxy: host %s is not an IP (auth should have changed it)", - reply_r->host); + reply_r->proxy.host); return FALSE; } } @@ -446,12 +396,13 @@ proxy_redirect_reauth_callback(struct auth_client_request *request, break; } - if (!reply.proxy) { + if (!reply.proxy.proxy) { error = "Redirect authentication is missing proxy field"; break; } login_proxy_redirect_finish(client->login_proxy, - &reply.host_ip, reply.port); + &reply.proxy.host_ip, + reply.proxy.port); return; case AUTH_REQUEST_STATUS_INTERNAL_FAIL: error = "Internal authentication failure"; @@ -592,24 +543,24 @@ proxy_check_start(struct client *client, struct event *event, const struct client_auth_reply *reply, const struct dsasl_client_mech **sasl_mech_r) { - i_assert(reply->password != NULL); - i_assert(reply->host != NULL && reply->host[0] != '\0'); - i_assert(reply->host_ip.family != 0); + i_assert(reply->proxy.password != NULL); + i_assert(reply->proxy.host != NULL && reply->proxy.host[0] != '\0'); + i_assert(reply->proxy.host_ip.family != 0); - if (reply->proxy_mech != NULL) { - *sasl_mech_r = dsasl_client_mech_find(reply->proxy_mech); + if (reply->proxy.sasl_mechanism != NULL) { + *sasl_mech_r = dsasl_client_mech_find(reply->proxy.sasl_mechanism); if (*sasl_mech_r == NULL) { e_error(event, "Unsupported SASL mechanism %s", - reply->proxy_mech); + reply->proxy.sasl_mechanism); return FALSE; } - } else if (reply->master_user != NULL) { + } else if (reply->proxy.master_user != NULL) { /* have to use PLAIN authentication with master user logins */ *sasl_mech_r = &dsasl_client_mech_plain; } - if (login_proxy_is_ourself(client, reply->host, reply->port, - reply->destuser)) { + if (login_proxy_is_ourself(client, reply->proxy.host, reply->proxy.port, + reply->proxy.username)) { e_error(event, "Proxying loops to itself"); return FALSE; } @@ -623,7 +574,7 @@ static int proxy_start(struct client *client, const struct dsasl_client_mech *sasl_mech = NULL; struct event *event; - i_assert(reply->destuser != NULL); + i_assert(reply->proxy.username != NULL); i_assert(client->refcount > 1); i_assert(!client->destroyed); i_assert(client->proxy_sasl_client == NULL); @@ -643,34 +594,34 @@ static int proxy_start(struct client *client, } i_zero(&proxy_set); - proxy_set.host = reply->host; - proxy_set.ip = reply->host_ip; - if (reply->source_ip.family != 0) { - proxy_set.source_ip = reply->source_ip; + proxy_set.host = reply->proxy.host; + proxy_set.ip = reply->proxy.host_ip; + if (reply->proxy.source_ip.family != 0) { + proxy_set.source_ip = reply->proxy.source_ip; } else if (login_source_ips_count > 0) { /* select the next source IP with round robin. */ proxy_set.source_ip = login_source_ips[login_source_ips_idx]; login_source_ips_idx = (login_source_ips_idx + 1) % login_source_ips_count; } - proxy_set.port = reply->port; - proxy_set.connect_timeout_msecs = reply->proxy_timeout_msecs; + proxy_set.port = reply->proxy.port; + proxy_set.connect_timeout_msecs = reply->proxy.timeout_msecs; if (proxy_set.connect_timeout_msecs == 0) proxy_set.connect_timeout_msecs = client->set->login_proxy_timeout; proxy_set.notify_refresh_secs = reply->proxy_refresh_secs; - proxy_set.ssl_flags = reply->ssl_flags; + proxy_set.ssl_flags = reply->proxy.ssl_flags; proxy_set.host_immediate_failure_after_secs = reply->proxy_host_immediate_failure_after_secs; proxy_set.rawlog_dir = client->set->login_proxy_rawlog_dir; client->proxy_mech = sasl_mech; - client->proxy_user = i_strdup(reply->destuser); - client->proxy_master_user = i_strdup(reply->master_user); - client->proxy_password = i_strdup(reply->password); - client->proxy_noauth = reply->proxy_noauth; - client->proxy_nopipelining = reply->proxy_nopipelining; - client->proxy_not_trusted = reply->proxy_not_trusted; - client->proxy_redirect_reauth = reply->proxy_redirect_reauth; + client->proxy_user = i_strdup(reply->proxy.username); + client->proxy_master_user = i_strdup(reply->proxy.master_user); + client->proxy_password = i_strdup(reply->proxy.password); + client->proxy_nopipelining = reply->proxy.nopipelining; + client->proxy_noauth = reply->proxy.noauth; + client->proxy_not_trusted = reply->proxy.remote_not_trusted; + client->proxy_redirect_reauth = reply->proxy.redirect_reauth; if (login_proxy_new(client, event, &proxy_set, proxy_input, client->v.proxy_failed, proxy_redirect) < 0) { @@ -707,7 +658,7 @@ client_auth_handle_reply(struct client *client, client->alt_usernames = alt; } - if (reply->proxy) { + if (reply->proxy.proxy) { /* we want to proxy the connection to another server. don't do this unless authentication succeeded. with master user proxying we can get FAIL with proxy still set. @@ -726,7 +677,7 @@ client_auth_handle_reply(struct client *client, return TRUE; } - if (reply->host != NULL) { + if (reply->proxy.host != NULL) { const char *reason; if (reply->reason != NULL) diff --git a/src/login-common/client-common.h b/src/login-common/client-common.h index b3e7d72019..7ad29cc929 100644 --- a/src/login-common/client-common.h +++ b/src/login-common/client-common.h @@ -94,28 +94,17 @@ enum client_list_type { }; struct client_auth_reply { - const char *master_user, *reason; + const char *reason; enum client_auth_fail_code fail_code; ARRAY_TYPE(const_string) alt_usernames; - /* for proxying */ - const char *host; - struct ip_addr source_ip, host_ip; - const char *destuser, *password, *proxy_mech; - in_port_t port; - unsigned int proxy_timeout_msecs; + struct auth_proxy_settings proxy; unsigned int proxy_refresh_secs; unsigned int proxy_host_immediate_failure_after_secs; - enum login_proxy_ssl_flags ssl_flags; /* all the key=value fields returned by passdb */ const char *const *all_fields; - bool proxy:1; - bool proxy_noauth:1; - bool proxy_nopipelining:1; - bool proxy_not_trusted:1; - bool proxy_redirect_reauth:1; bool nologin:1; }; diff --git a/src/login-common/login-proxy.c b/src/login-common/login-proxy.c index 643512e45e..1d5b0055ed 100644 --- a/src/login-common/login-proxy.c +++ b/src/login-common/login-proxy.c @@ -74,7 +74,7 @@ struct login_proxy { unsigned int notify_refresh_secs; unsigned int host_immediate_failure_after_secs; unsigned int reconnect_count; - enum login_proxy_ssl_flags ssl_flags; + enum auth_proxy_ssl_flags ssl_flags; char *rawlog_dir; login_proxy_input_callback_t *input_callback; @@ -335,8 +335,8 @@ static void proxy_wait_connect(struct login_proxy *proxy) io_remove(&proxy->server_io); proxy_plain_connected(proxy); - if ((proxy->ssl_flags & PROXY_SSL_FLAG_YES) != 0 && - (proxy->ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) { + if ((proxy->ssl_flags & AUTH_PROXY_SSL_FLAG_YES) != 0 && + (proxy->ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) == 0) { if (login_proxy_starttls(proxy) < 0) { /* proxy is already destroyed */ } @@ -805,7 +805,7 @@ in_port_t login_proxy_get_port(const struct login_proxy *proxy) return proxy->port; } -enum login_proxy_ssl_flags +enum auth_proxy_ssl_flags login_proxy_get_ssl_flags(const struct login_proxy *proxy) { return proxy->ssl_flags; @@ -913,7 +913,7 @@ int login_proxy_starttls(struct login_proxy *proxy) master_service_ssl_client_settings_to_iostream_set( proxy->client->ssl_set, pool_datastack_create(), &ssl_set); - if ((proxy->ssl_flags & PROXY_SSL_FLAG_ANY_CERT) != 0) + if ((proxy->ssl_flags & AUTH_PROXY_SSL_FLAG_ANY_CERT) != 0) ssl_set.allow_invalid_cert = TRUE; /* NOTE: We're explicitly disabling ssl_client_ca_* settings for now at least. The main problem is that we're chrooted, so we can't read diff --git a/src/login-common/login-proxy.h b/src/login-common/login-proxy.h index 48cf0bf629..7cdc3beabc 100644 --- a/src/login-common/login-proxy.h +++ b/src/login-common/login-proxy.h @@ -2,6 +2,7 @@ #define LOGIN_PROXY_H #include "net.h" +#include "auth-proxy.h" /* Max. number of embedded proxying connections until proxying fails. This is intended to avoid an accidental configuration where two proxies @@ -16,15 +17,6 @@ struct client; struct login_proxy; -enum login_proxy_ssl_flags { - /* Use SSL/TLS enabled */ - PROXY_SSL_FLAG_YES = 0x01, - /* Don't do SSL handshake immediately after connected */ - PROXY_SSL_FLAG_STARTTLS = 0x02, - /* Don't require that the received certificate is valid */ - PROXY_SSL_FLAG_ANY_CERT = 0x04 -}; - enum login_proxy_failure_type { /* connect() failed or remote disconnected us. */ LOGIN_PROXY_FAILURE_TYPE_CONNECT, @@ -59,7 +51,7 @@ struct login_proxy_settings { every n seconds */ unsigned int notify_refresh_secs; unsigned int host_immediate_failure_after_secs; - enum login_proxy_ssl_flags ssl_flags; + enum auth_proxy_ssl_flags ssl_flags; const char *rawlog_dir; }; @@ -121,7 +113,7 @@ const char *login_proxy_get_source_host(const struct login_proxy *proxy) ATTR_PU const char *login_proxy_get_host(const struct login_proxy *proxy) ATTR_PURE; const char *login_proxy_get_ip_str(const struct login_proxy *proxy) ATTR_PURE; in_port_t login_proxy_get_port(const struct login_proxy *proxy) ATTR_PURE; -enum login_proxy_ssl_flags +enum auth_proxy_ssl_flags login_proxy_get_ssl_flags(const struct login_proxy *proxy) ATTR_PURE; unsigned int login_proxy_get_connect_timeout_msecs(const struct login_proxy *proxy) ATTR_PURE; diff --git a/src/pop3-login/pop3-proxy.c b/src/pop3-login/pop3-proxy.c index fd8dfcef93..3eb2d1b109 100644 --- a/src/pop3-login/pop3-proxy.c +++ b/src/pop3-login/pop3-proxy.c @@ -145,7 +145,7 @@ int pop3_proxy_parse_line(struct client *client, const char *line) { struct pop3_client *pop3_client = (struct pop3_client *)client; struct ostream *output; - enum login_proxy_ssl_flags ssl_flags; + enum auth_proxy_ssl_flags ssl_flags; i_assert(!client->destroyed); @@ -165,7 +165,7 @@ int pop3_proxy_parse_line(struct client *client, const char *line) str_begins(line+3, " [XCLIENT]"); ssl_flags = login_proxy_get_ssl_flags(client->login_proxy); - if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) { + if ((ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) == 0) { if (proxy_send_login(pop3_client, output) < 0) return -1; } else { diff --git a/src/submission-login/submission-proxy.c b/src/submission-login/submission-proxy.c index 0148c43556..600ff2e38b 100644 --- a/src/submission-login/submission-proxy.c +++ b/src/submission-login/submission-proxy.c @@ -32,10 +32,10 @@ submission_proxy_success_reply_sent( static int proxy_send_starttls(struct submission_client *client, struct ostream *output) { - enum login_proxy_ssl_flags ssl_flags; + enum auth_proxy_ssl_flags ssl_flags; ssl_flags = login_proxy_get_ssl_flags(client->common.login_proxy); - if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) + if ((ssl_flags & AUTH_PROXY_SSL_FLAG_STARTTLS) == 0) return 0; if ((client->proxy_capability & SMTP_CAPABILITY_STARTTLS) == 0) { -- 2.47.3