From: Timo Sirainen Date: Tue, 31 Oct 2017 23:27:36 +0000 (+0200) Subject: login-common: Use lib-ssl-iostream for incoming SSL/TLS connections X-Git-Tag: 2.3.0.rc1~513 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=feb8f7b9490ddef989094ee21d7d1a222ccc4cb2;p=thirdparty%2Fdovecot%2Fcore.git login-common: Use lib-ssl-iostream for incoming SSL/TLS connections --- diff --git a/src/login-common/client-common.c b/src/login-common/client-common.c index d9f6222815..4fa250039e 100644 --- a/src/login-common/client-common.c +++ b/src/login-common/client-common.c @@ -6,6 +6,7 @@ #include "llist.h" #include "istream.h" #include "ostream.h" +#include "iostream-ssl.h" #include "iostream-proxy.h" #include "iostream-rawlog.h" #include "process-title.h" @@ -202,6 +203,7 @@ client_alloc(int fd, pool_t pool, net_ip_compare(&conn->real_remote_ip, &conn->real_local_ip); } client->proxy_ttl = LOGIN_PROXY_TTL; + client_open_streams(client); return client; } @@ -215,7 +217,6 @@ void client_init(struct client *client, void **other_sets) client->to_disconnect = timeout_add(CLIENT_LOGIN_TIMEOUT_MSECS, client_idle_disconnect_timeout, client); - client_open_streams(client); hook_login_client_allocated(client); client->v.create(client, other_sets); @@ -257,8 +258,8 @@ void client_destroy(struct client *client, const char *reason) o_stream_uncork(client->output); if (!client->login_success) { io_remove(&client->io); - if (client->ssl_proxy != NULL) - ssl_proxy_destroy(client->ssl_proxy); + if (client->ssl_iostream != NULL) + ssl_iostream_destroy(&client->ssl_iostream); if (client->iostream_fd_proxy != NULL) iostream_proxy_unref(&client->iostream_fd_proxy); i_stream_close(client->input); @@ -339,6 +340,8 @@ bool client_unref(struct client **_client) return TRUE; if (!client->create_finished) { + i_stream_unref(&client->input); + o_stream_unref(&client->output); pool_unref(&client->preproxy_pool); pool_unref(&client->pool); return FALSE; @@ -350,8 +353,8 @@ bool client_unref(struct client **_client) if (client->v.free != NULL) client->v.free(client); - if (client->ssl_proxy != NULL) - ssl_proxy_free(&client->ssl_proxy); + if (client->ssl_iostream != NULL) + ssl_iostream_unref(&client->ssl_iostream); if (client->iostream_fd_proxy != NULL) iostream_proxy_unref(&client->iostream_fd_proxy); if (client->fd_proxying) { @@ -425,29 +428,81 @@ void clients_destroy_all(void) clients_destroy_all_reason("Disconnected: Shutting down"); } +static int client_sni_callback(const char *name, const char **error_r, + void *context) +{ + struct client *client = context; + struct ssl_iostream_context *ssl_ctx; + struct ssl_iostream_settings ssl_set; + void **other_sets; + const char *error; + + if (client->ssl_servername_settings_read) + return 0; + client->ssl_servername_settings_read = TRUE; + + client->local_name = p_strdup(client->pool, name); + client->set = login_settings_read(client->pool, &client->local_ip, + &client->ip, name, + &client->ssl_set, &other_sets); + + master_service_ssl_settings_to_iostream_set(client->ssl_set, + pool_datastack_create(), + MASTER_SERVICE_SSL_SETTINGS_TYPE_SERVER, &ssl_set); + if (ssl_iostream_server_context_cache_get(&ssl_set, &ssl_ctx, &error) < 0) { + *error_r = t_strdup_printf( + "Failed to initialize SSL server context: %s", error); + return -1; + } + ssl_iostream_change_context(client->ssl_iostream, ssl_ctx); + ssl_iostream_context_unref(&ssl_ctx); + return 0; +} + int client_init_ssl(struct client *client) { - int fd_ssl; + struct ssl_iostream_context *ssl_ctx; + struct ssl_iostream_settings ssl_set; + const char *error; i_assert(client->fd != -1); - fd_ssl = ssl_proxy_alloc(client->fd, &client->ip, client->pool, - client->set, client->ssl_set, - &client->ssl_proxy); - if (fd_ssl == -1) + master_service_ssl_settings_to_iostream_set(client->ssl_set, + pool_datastack_create(), + MASTER_SERVICE_SSL_SETTINGS_TYPE_SERVER, &ssl_set); + /* If the client cert is invalid, we'll reply NO to the login + command. */ + ssl_set.allow_invalid_cert = TRUE; + if (ssl_iostream_server_context_cache_get(&ssl_set, &ssl_ctx, &error) < 0) { + client_log_err(client, t_strdup_printf( + "Failed to initialize SSL server context: %s", error)); return -1; - - ssl_proxy_set_client(client->ssl_proxy, client); - ssl_proxy_start(client->ssl_proxy); + } + if (io_stream_create_ssl_server(ssl_ctx, &ssl_set, + &client->input, &client->output, + &client->ssl_iostream, &error) < 0) { + client_log_err(client, t_strdup_printf( + "Failed to initialize SSL connection: %s", error)); + ssl_iostream_context_unref(&ssl_ctx); + return -1; + } + ssl_iostream_context_unref(&ssl_ctx); + ssl_iostream_set_sni_callback(client->ssl_iostream, + client_sni_callback, client); client->tls = TRUE; client->secured = TRUE; - client->fd = fd_ssl; + + if (client->starttls) { + io_remove(&client->io); + client->io = io_add_istream(client->input, client_input, client); + } return 0; } static void client_start_tls(struct client *client) { + client->starttls = TRUE; if (client_init_ssl(client) < 0) { client_notify_disconnect(client, CLIENT_DISCONNECT_INTERNAL_ERROR, @@ -456,15 +511,8 @@ static void client_start_tls(struct client *client) "Disconnected: TLS initialization failed."); return; } - - client->starttls = TRUE; login_refresh_proctitle(); - client->io = io_add(client->fd, IO_READ, client_input, client); - i_stream_unref(&client->input); - o_stream_unref(&client->output); - client_open_streams(client); - client->v.starttls(client); } @@ -704,15 +752,15 @@ get_var_expand_table(struct client *client) tab[12].value = ""; } else { const char *ssl_state = - ssl_proxy_is_handshaked(client->ssl_proxy) ? + ssl_iostream_is_handshaked(client->ssl_iostream) ? "TLS" : "TLS handshaking"; const char *ssl_error = - ssl_proxy_get_last_error(client->ssl_proxy); + ssl_iostream_get_last_error(client->ssl_iostream); tab[11].value = ssl_error == NULL ? ssl_state : t_strdup_printf("%s: %s", ssl_state, ssl_error); tab[12].value = - ssl_proxy_get_security_string(client->ssl_proxy); + ssl_iostream_get_security_string(client->ssl_iostream); } tab[13].value = client->mail_pid == 0 ? "" : dec2str(client->mail_pid); @@ -879,10 +927,10 @@ const char *client_get_extra_disconnect_reason(struct client *client) ioloop_time - client->auth_first_started; if (client->set->auth_ssl_require_client_cert && - client->ssl_proxy != NULL) { - if (ssl_proxy_has_broken_client_cert(client->ssl_proxy)) + client->ssl_iostream != NULL) { + if (ssl_iostream_has_broken_client_cert(client->ssl_iostream)) return "(client sent an invalid cert)"; - if (!ssl_proxy_has_valid_client_cert(client->ssl_proxy)) + if (!ssl_iostream_has_valid_client_cert(client->ssl_iostream)) return "(client didn't send a cert)"; } @@ -902,7 +950,7 @@ const char *client_get_extra_disconnect_reason(struct client *client) /* some auth attempts without SSL/TLS */ if (client->set->auth_ssl_require_client_cert && - client->ssl_proxy == NULL) + client->ssl_iostream == NULL) return "(cert required, client didn't start TLS)"; if (client->auth_waiting && client->auth_attempts == 1) { diff --git a/src/login-common/client-common.h b/src/login-common/client-common.h index 2d644c139b..0164b67b53 100644 --- a/src/login-common/client-common.h +++ b/src/login-common/client-common.h @@ -147,7 +147,7 @@ struct client { struct ip_addr real_remote_ip, real_local_ip; in_port_t local_port, remote_port; in_port_t real_local_port, real_remote_port; - struct ssl_proxy *ssl_proxy; + struct ssl_iostream *ssl_iostream; const struct login_settings *set; const struct master_service_ssl_settings *ssl_set; const char *session_id, *listener_name, *postlogin_socket_path; diff --git a/src/login-common/sasl-server.c b/src/login-common/sasl-server.c index 83963925c9..0c08c8516a 100644 --- a/src/login-common/sasl-server.c +++ b/src/login-common/sasl-server.c @@ -12,7 +12,7 @@ #include "str-sanitize.h" #include "anvil-client.h" #include "auth-client.h" -#include "ssl-proxy.h" +#include "iostream-ssl.h" #include "master-service.h" #include "master-service-ssl-settings.h" #include "master-interface.h" @@ -65,8 +65,8 @@ client_get_auth_flags(struct client *client) { enum auth_request_flags auth_flags = 0; - if (client->ssl_proxy != NULL && - ssl_proxy_has_valid_client_cert(client->ssl_proxy)) + if (client->ssl_iostream != NULL && + ssl_iostream_has_valid_client_cert(client->ssl_iostream)) auth_flags |= AUTH_REQUEST_FLAG_VALID_CLIENT_CERT; if (client->secured) auth_flags |= AUTH_REQUEST_FLAG_SECURED; @@ -136,8 +136,8 @@ static int master_send_request(struct anvil_request *anvil_request) req.local_ip = client->local_ip; req.remote_ip = client->ip; req.client_pid = getpid(); - if (client->ssl_proxy != NULL && - ssl_proxy_get_compression(client->ssl_proxy) != NULL) + if (client->ssl_iostream != NULL && + ssl_iostream_get_compression(client->ssl_iostream) != NULL) req.flags |= MAIL_AUTH_REQUEST_FLAG_TLS_COMPRESSION; memcpy(req.cookie, anvil_request->cookie, sizeof(req.cookie)); @@ -370,8 +370,8 @@ void sasl_server_auth_begin(struct client *client, info.session_id = client_get_session_id(client); if (client->client_cert_common_name != NULL) info.cert_username = client->client_cert_common_name; - else if (client->ssl_proxy != NULL) - info.cert_username = ssl_proxy_get_peer_name(client->ssl_proxy); + else if (client->ssl_iostream != NULL) + info.cert_username = ssl_iostream_get_peer_name(client->ssl_iostream); info.flags = client_get_auth_flags(client); info.local_ip = client->local_ip; info.remote_ip = client->ip;