From: Stephan Bosch Date: Fri, 9 Feb 2018 21:06:49 +0000 (+0100) Subject: lib-smtp: server: Allow creating server with custom SSL settings. X-Git-Tag: 2.3.9~1802 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee6288f22b02930f440619c44e116e0342f19f83;p=thirdparty%2Fdovecot%2Fcore.git lib-smtp: server: Allow creating server with custom SSL settings. Normally, the settings are obtained through lib-master, but that is not really suitable for the test suite. --- diff --git a/src/lib-smtp/smtp-server-connection.c b/src/lib-smtp/smtp-server-connection.c index f75221b0fd..f767d2a8e8 100644 --- a/src/lib-smtp/smtp-server-connection.c +++ b/src/lib-smtp/smtp-server-connection.c @@ -339,9 +339,42 @@ smtp_server_connection_handle_command(struct smtp_server_connection *conn, return (cmd == NULL || !cmd->input_locked); } +static int +smtp_server_connection_init_ssl_ctx(struct smtp_server_connection *conn, + const char **error_r) +{ + struct smtp_server *server = conn->server; + const char *error; + + if (conn->ssl_ctx != NULL || conn->set.ssl == NULL) + return 0; + if (conn->set.ssl == server->set.ssl) { + if (smtp_server_init_ssl_ctx(server, error_r) < 0) + return -1; + conn->ssl_ctx = server->ssl_ctx; + ssl_iostream_context_ref(conn->ssl_ctx); + return 0; + } + + if (ssl_iostream_server_context_cache_get(conn->set.ssl, + &conn->ssl_ctx, &error) < 0) { + *error_r = t_strdup_printf("Couldn't initialize SSL context: %s", + error); + return -1; + } + return 0; +} + int smtp_server_connection_ssl_init(struct smtp_server_connection *conn) { const char *error; + int ret; + + if (smtp_server_connection_init_ssl_ctx(conn, &error) < 0) { + smtp_server_connection_error(conn, + "Couldn't initialize SSL: %s", error); + return -1; + } smtp_server_connection_debug(conn, "Starting SSL handshake"); @@ -356,9 +389,16 @@ int smtp_server_connection_ssl_init(struct smtp_server_connection *conn) } smtp_server_connection_input_halt(conn); - if (master_service_ssl_init(master_service, - &conn->conn.input, &conn->conn.output, - &conn->ssl_iostream, &error) < 0) { + if (conn->ssl_ctx == NULL) { + ret = master_service_ssl_init(master_service, + &conn->conn.input, &conn->conn.output, + &conn->ssl_iostream, &error); + } else { + ret = io_stream_create_ssl_server(conn->ssl_ctx, + conn->set.ssl, &conn->conn.input, &conn->conn.output, + &conn->ssl_iostream, &error); + } + if (ret < 0) { smtp_server_connection_error(conn, "Couldn't initialize SSL server for %s: %s", conn->conn.name, error); @@ -785,6 +825,10 @@ smtp_server_connection_alloc(struct smtp_server *server, conn->set.protocol = server->set.protocol; if (set->rawlog_dir != NULL && *set->rawlog_dir != '\0') conn->set.rawlog_dir = p_strdup(pool, set->rawlog_dir); + + if (set->ssl != NULL) + conn->set.ssl = ssl_iostream_settings_dup(pool, set->ssl); + if (set->hostname != NULL && *set->hostname != '\0') conn->set.hostname = p_strdup(pool, set->hostname); if (set->login_greeting != NULL && @@ -1046,6 +1090,8 @@ smtp_server_connection_disconnect(struct smtp_server_connection *conn, if (conn->smtp_parser != NULL) smtp_command_parser_deinit(&conn->smtp_parser); ssl_iostream_destroy(&conn->ssl_iostream); + if (conn->ssl_ctx != NULL) + ssl_iostream_context_unref(&conn->ssl_ctx); if (conn->callbacks != NULL && conn->callbacks->conn_disconnect != NULL) { diff --git a/src/lib-smtp/smtp-server-private.h b/src/lib-smtp/smtp-server-private.h index 58972646ca..876c84d205 100644 --- a/src/lib-smtp/smtp-server-private.h +++ b/src/lib-smtp/smtp-server-private.h @@ -143,6 +143,7 @@ struct smtp_server_connection { struct timeout *to_idle; struct istream *raw_input; struct ostream *raw_output; + struct ssl_iostream_context *ssl_ctx; struct ssl_iostream *ssl_iostream; struct smtp_command_parser *smtp_parser; @@ -179,6 +180,7 @@ struct smtp_server { struct smtp_server_settings set; struct ioloop *ioloop; + struct ssl_iostream_context *ssl_ctx; ARRAY(struct smtp_server_command_reg) commands_reg; @@ -357,4 +359,10 @@ bool smtp_server_transaction_has_rcpt(struct smtp_server_transaction *trans); unsigned int smtp_server_transaction_rcpt_count(struct smtp_server_transaction *trans); +/* + * Server + */ + +int smtp_server_init_ssl_ctx(struct smtp_server *server, const char **error_r); + #endif diff --git a/src/lib-smtp/smtp-server.c b/src/lib-smtp/smtp-server.c index 4cc0fabef8..d83652046e 100644 --- a/src/lib-smtp/smtp-server.c +++ b/src/lib-smtp/smtp-server.c @@ -30,6 +30,12 @@ struct smtp_server *smtp_server_init(const struct smtp_server_settings *set) server->pool = pool; server->set.protocol = set->protocol; server->set.rawlog_dir = p_strdup_empty(pool, set->rawlog_dir); + + if (set->ssl != NULL) { + server->set.ssl = + ssl_iostream_settings_dup(server->pool, set->ssl); + } + if (set->hostname != NULL && *set->hostname != '\0') server->set.hostname = p_strdup(pool, set->hostname); else @@ -78,6 +84,8 @@ void smtp_server_deinit(struct smtp_server **_server) connection_list_deinit(&server->conn_list); + if (server->ssl_ctx != NULL) + ssl_iostream_context_unref(&server->ssl_ctx); pool_unref(&server->pool); *_server = NULL; } @@ -97,3 +105,19 @@ void smtp_server_switch_ioloop(struct smtp_server *server) smtp_server_connection_switch_ioloop(conn); } } + +int smtp_server_init_ssl_ctx(struct smtp_server *server, const char **error_r) +{ + const char *error; + + if (server->ssl_ctx != NULL || server->set.ssl == NULL) + return 0; + + if (ssl_iostream_server_context_cache_get(server->set.ssl, + &server->ssl_ctx, &error) < 0) { + *error_r = t_strdup_printf("Couldn't initialize SSL context: %s", + error); + return -1; + } + return 0; +} diff --git a/src/lib-smtp/smtp-server.h b/src/lib-smtp/smtp-server.h index 972d5219c5..fe33c8fedf 100644 --- a/src/lib-smtp/smtp-server.h +++ b/src/lib-smtp/smtp-server.h @@ -240,6 +240,9 @@ struct smtp_server_settings { const char *login_greeting; const char *rawlog_dir; + /* SSL settings; if NULL, master_service_ssl_init() is used instead */ + const struct ssl_iostream_settings *ssl; + /* The maximum time in milliseconds a client is allowed to be idle before it is disconnected. */ unsigned int max_client_idle_time_msecs;