bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "lib.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "istream.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "ostream.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "iostream-ssl.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "master-service.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "master-service-ssl.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-syntax.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-server-private.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch/* STARTTLS command (RFC 3207) */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic int cmd_starttls_start(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_callbacks *callbacks = conn->callbacks;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Starting TLS");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (callbacks != NULL && callbacks->conn_start_tls != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *tmp_conn = conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct istream *input = conn->conn.input;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct ostream *output = conn->conn.output;
9249c80276766fdc4d31fc3eebc22fba7d53d77cStephan Bosch int ret;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_ref(tmp_conn);
9249c80276766fdc4d31fc3eebc22fba7d53d77cStephan Bosch ret = callbacks->conn_start_tls(tmp_conn->context,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &input, &output);
9249c80276766fdc4d31fc3eebc22fba7d53d77cStephan Bosch if (!smtp_server_connection_unref(&tmp_conn) || ret < 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return -1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
1171e5f92b20e8e126b2dcf62ea0731fa864b4bbStephan Bosch smtp_server_connection_set_ssl_streams(conn, input, output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if (smtp_server_connection_ssl_init(conn) < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_close(&conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "SSL Initialization failed");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return -1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* RFC 3207, Section 4.2:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
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 Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_clear(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_unlock(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return 0;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic int cmd_starttls_output(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch int ret;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if ((ret=smtp_server_connection_flush(conn)) < 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return 1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (ret > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_unset_flush_callback(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd_starttls_start(conn) < 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return -1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return 1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void cmd_starttls_destroy(struct smtp_server_cmd_ctx *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = cmd->conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *command = cmd->cmd;
95a139b8f929e4e8aeec8d19ccc9b7587bda37e9Stephan Bosch int ret;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->conn.output == NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
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));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* uncork */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_uncork(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
95a139b8f929e4e8aeec8d19ccc9b7587bda37e9Stephan Bosch /* flush */
95a139b8f929e4e8aeec8d19ccc9b7587bda37e9Stephan Bosch if ((ret=smtp_server_connection_flush(conn)) < 0) {
95a139b8f929e4e8aeec8d19ccc9b7587bda37e9Stephan Bosch return;
95a139b8f929e4e8aeec8d19ccc9b7587bda37e9Stephan Bosch } else if (ret == 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* the buffer has to be flushed */
95a139b8f929e4e8aeec8d19ccc9b7587bda37e9Stephan Bosch i_assert(!conn->conn.output->closed);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_callback(conn->conn.output,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd_starttls_output,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_pending(conn->conn.output, TRUE);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd_starttls_start(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void cmd_starttls_next(struct smtp_server_cmd_ctx *cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
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 int ret;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_STARTTLS);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_ref(command);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (callbacks != NULL && callbacks->conn_cmd_starttls != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch ret = callbacks->conn_cmd_starttls(conn->context, cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch ret = 1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command->hook_destroy = cmd_starttls_destroy;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (ret <= 0) {
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 smtp_server_command_unref(&command);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_command_is_replied(command)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 220, "2.0.0", "Begin TLS negotiation now.");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_unref(&command);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_cmd_starttls(struct smtp_server_cmd_ctx *cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *params)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
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
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->ssl_secured) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert((capabilities & SMTP_CAPABILITY_STARTTLS) == 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 502, "5.5.1", "TLS is already active.");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if ((capabilities & SMTP_CAPABILITY_STARTTLS) == 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 502, "5.5.1", "TLS support is not enabled.");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* "STARTTLS" CRLF */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (*params != '\0') {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_reply(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 501, "5.5.4", "Invalid parameters");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_input_lock(cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_lock(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch command->hook_next = cmd_starttls_next;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}