bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch/* STARTTLS command (RFC 3207) */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic int cmd_starttls_start(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_callbacks *callbacks = conn->callbacks;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Starting TLS");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (callbacks != NULL && callbacks->conn_start_tls != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *tmp_conn = conn;
9249c80276766fdc4d31fc3eebc22fba7d53d77cStephan Bosch ret = callbacks->conn_start_tls(tmp_conn->context,
9249c80276766fdc4d31fc3eebc22fba7d53d77cStephan Bosch if (!smtp_server_connection_unref(&tmp_conn) || ret < 0)
1171e5f92b20e8e126b2dcf62ea0731fa864b4bbStephan Bosch smtp_server_connection_set_ssl_streams(conn, input, output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if (smtp_server_connection_ssl_init(conn) < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "SSL Initialization failed");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* RFC 3207, Section 4.2:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch Upon completion of the TLS handshake, the SMTP protocol is reset to
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch the initial state (the state in SMTP after a server issues a 220
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch service ready greeting). The server MUST discard any knowledge
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch obtained from the client, such as the argument to the EHLO command,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch which was not obtained from the TLS negotiation itself.
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic int cmd_starttls_output(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if ((ret=smtp_server_connection_flush(conn)) < 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_unset_flush_callback(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void cmd_starttls_destroy(struct smtp_server_cmd_ctx *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *command = cmd->cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (smtp_server_command_replied_success(command)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* only one valid success status for STARTTLS command */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(smtp_server_command_reply_status_equals(command, 220));
95a139b8f929e4e8aeec8d19ccc9b7587bda37e9Stephan Bosch if ((ret=smtp_server_connection_flush(conn)) < 0) {
95a139b8f929e4e8aeec8d19ccc9b7587bda37e9Stephan Bosch } else if (ret == 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* the buffer has to be flushed */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_callback(conn->conn.output,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_pending(conn->conn.output, TRUE);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void cmd_starttls_next(struct smtp_server_cmd_ctx *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *command = cmd->cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_callbacks *callbacks = conn->callbacks;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_STARTTLS);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (callbacks != NULL && callbacks->conn_cmd_starttls != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch ret = callbacks->conn_cmd_starttls(conn->context, cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(ret == 0 || smtp_server_command_is_replied(command));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* command is waiting for external event or it failed */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_command_is_replied(command)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_cmd_starttls(struct smtp_server_cmd_ctx *cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *command = cmd->cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch enum smtp_capability capabilities = conn->set.capabilities;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert((capabilities & SMTP_CAPABILITY_STARTTLS) == 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if ((capabilities & SMTP_CAPABILITY_STARTTLS) == 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* "STARTTLS" CRLF */