bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschconst char *const smtp_server_state_names[] = {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_debug(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *format, ...)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_error(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *format, ...)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_input(struct connection *_conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_output(struct smtp_server_connection *conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_disconnect(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_update_stats(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->stats.input = conn->conn.input->v_offset;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->stats.output = conn->conn.output->offset;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_stats(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_input_halt(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_input_resume(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* only resume when we actually can */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->input_locked || conn->input_broken ||
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* is queued command still blocking input? */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* restore input handler */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_input_lock(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_input_unlock(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_input_capture(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_input_callback_t *callback, void *context)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(!conn->input_broken && !conn->disconnected);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->conn.io = io_add_istream(conn->conn.input, *callback, context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_update_rawlog(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_streams_changed(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_command_parser_set_stream(conn->smtp_parser, conn->conn.input);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_callback(conn->conn.output,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_pending(conn->conn.output, TRUE);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_set_streams(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct istream *input, struct ostream *output)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct ostream *old_output = conn->conn.output;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_no_error_handling(conn->conn.output, TRUE);
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Boschvoid smtp_server_connection_set_ssl_streams(struct smtp_server_connection *conn,
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch struct istream *input, struct ostream *output)
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch smtp_server_connection_set_streams(conn, input, output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_idle_timeout(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_timeout_stop(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Timeout stop");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_timeout_start(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Timeout start");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_timeout_reset(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_timeout_update(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd = conn->command_queue_head;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* command updates timeout internally */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_ready(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->smtp_parser = smtp_command_parser_init(conn->conn.input,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_callback(conn->conn.output,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* RFC 4954, Section 4:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch Should the client successfully complete the exchange, the
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP server issues a 235 reply. */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "235 2.7.0 Logged in.");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void smtp_server_connection_destroy(struct connection *_conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_disconnect(conn, NULL);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_handle_command(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *tmp_conn = conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = smtp_server_command_new(tmp_conn, cmd_name, cmd_params);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_connection_unref(&tmp_conn)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* the command start callback managed to get this connection
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd != NULL && conn->command_queue_head == cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschint smtp_server_connection_ssl_init(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Starting SSL handshake");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* recreate rawlog after STARTTLS */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Couldn't initialize SSL server for %s: %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "SSL handshake failed: %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch ssl_iostream_get_last_error(conn->ssl_iostream));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_handle_input(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* check whether we are continuing a command */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pending_command = (conn->command_queue_tail->state ==
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* parse commands */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch while ((ret = smtp_command_parse_next(conn->smtp_parser,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &cmd_name, &cmd_params, &error_code, &error)) > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* previous command is now fully read and ready
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_ready_to_reply(pending_command);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Received new command: %s %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* handle command
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd may be destroyed after this */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_connection_handle_command(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* client indicated it will close after this command;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch stop trying to read more. */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pending_command = (conn->command_queue_tail->state ==
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch int stream_errno = conn->conn.input->stream_errno;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (stream_errno != 0 && stream_errno != EPIPE &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Connection lost: read(%s) failed: %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Read failure");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Connection lost: Remote disconnected");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* no pending commands; close */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Remote closed connection");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* unfinished command; close */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Remote closed connection unexpectedly");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* a command is still processing;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch only drop input io for now */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* fall through */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* Command data size exceeds the absolute limit;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i.e. beyond which we don't even want to skip
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch data anymore. The command error is usually
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch already submitted by the application and sent
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch to the client. */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Command data size exceeds absolute limit");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Command data ended prematurely");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch !smtp_command_parser_pending_data(conn->smtp_parser)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* previous command is now fully read and ready to
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_ready_to_reply(pending_command);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void smtp_server_connection_input(struct connection *_conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->ssl_start && conn->ssl_iostream == NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (smtp_server_connection_ssl_init(conn) < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "SSL Initialization failed");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_cmd_input_pre != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_cmd_input_pre(conn->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_cmd_input_post != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_cmd_input_post(conn->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_connection_pending_command_data(
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return smtp_command_parser_pending_data(conn->smtp_parser);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch * Command reply handling
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Boschvoid smtp_server_connection_handle_output_error(
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch "Connection lost: write(%s) failed: %s",
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch "Write failure");
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch "Connection lost: Remote disconnected");
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch "Remote closed connection unexpectedly");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_next_reply(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int i;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* no commands pending */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "No more commands pending");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->state < SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(cmd->state == SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* send command replies */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch // FIXME: handle LMTP DATA command with enormous number of recipients;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch // i.e. don't keep filling output stream with replies indefinitely.
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch reply = array_idx_modifiable(&cmd->replies, i);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->state = SMTP_SERVER_COMMAND_STATE_PROCESSING;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->state == SMTP_SERVER_COMMAND_STATE_PROCESSING)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_cork(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_uncork(struct smtp_server_connection *conn)
be6741282be725d76462110e1d7024956e2a100bStephan Bosch if (o_stream_uncork_flush(conn->conn.output) < 0) {
be6741282be725d76462110e1d7024956e2a100bStephan Bosch smtp_server_connection_handle_output_error(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_send_replies(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* send more replies until no more replies remain, the output
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch blocks again, or the connection is closed */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch while (!conn->disconnected && smtp_server_connection_next_reply(conn));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* accept more commands if possible */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschint smtp_server_connection_flush(struct smtp_server_connection *conn)
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch smtp_server_connection_handle_output_error(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_output(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Sending replies");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if ((ret=smtp_server_connection_flush(conn)) > 0) {
be6741282be725d76462110e1d7024956e2a100bStephan Bosch if (ret >= 0 && !conn->corked && conn->conn.output != NULL) {
be6741282be725d76462110e1d7024956e2a100bStephan Bosch if ((ret=o_stream_uncork_flush(conn->conn.output)) < 0)
be6741282be725d76462110e1d7024956e2a100bStephan Bosch smtp_server_connection_handle_output_error(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Trigger output");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_pending(conn->conn.output, TRUE);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic struct connection_settings smtp_server_connection_set = {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic const struct connection_vfuncs smtp_server_connection_vfuncs = {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return connection_list_init(&smtp_server_connection_set,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic struct smtp_server_connection * ATTR_NULL(5, 6)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_alloc(struct smtp_server *server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_settings *set, int fd_in, int fd_out,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct ip_addr *remote_ip, in_port_t remote_port,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_callbacks *callbacks, void *context)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pool = pool_alloconly_create("smtp server", 512);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn = p_new(pool, struct smtp_server_connection, 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* merge settings with global server settings */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->rawlog_dir != NULL && *set->rawlog_dir != '\0')
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.rawlog_dir = p_strdup(pool, set->rawlog_dir);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->hostname != NULL && *set->hostname != '\0')
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.hostname = p_strdup(pool, set->hostname);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.max_bad_commands = set->max_bad_commands;
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch conn->set.max_recipients = set->max_recipients;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_command_limits_merge(&conn->set.command_limits,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch p_strarray_dup(pool, set->xclient_extensions);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.auth_optional || set->auth_optional;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.param_extensions || set->param_extensions;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.debug = conn->set.debug || set->debug;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (remote_ip != NULL && remote_ip->family != 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if (fd_in != fd_out || net_getpeername(fd_in,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* tty connection probably */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* ip / ip6 */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_error("net_set_send_buffer_size(%"PRIuSIZE_T") failed: %m",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_error("net_set_recv_buffer_size(%"PRIuSIZE_T") failed: %m",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic const char *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_name(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* get a name for this connection */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name = t_strdup_printf("unix [%u]", conn->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name = t_strdup_printf("unix:pid=%u,uid=%u [%u]",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_pid, conn->remote_uid, conn->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch net_ip2addr(&conn->remote_ip), conn->remote_port, conn->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch net_ip2addr(&conn->remote_ip), conn->remote_port, conn->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_create(struct smtp_server *server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct ip_addr *remote_ip, in_port_t remote_port,
40a926a1aeae93b3d4944b56eacb013d3059b549Stephan Bosch bool ssl_start, const struct smtp_server_settings *set,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_callbacks *callbacks, void *context)
40a926a1aeae93b3d4944b56eacb013d3059b549Stephan Bosch conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* halt input until started */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Connection created");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_create_from_streams(struct smtp_server *server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct istream *input, struct ostream *output,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct ip_addr *remote_ip, in_port_t remote_port,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_callbacks *callbacks, void *context)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn = smtp_server_connection_alloc(server, set,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch connection_init_from_streams(server->conn_list,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* halt input until started */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Connection created");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_ref(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic const char *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch !ssl_iostream_is_handshaked(conn->ssl_iostream)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch err = ssl_iostream_get_last_error(conn->ssl_iostream);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return io_stream_get_disconnect_reason(conn->conn.input,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_disconnect(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch reason = smtp_server_connection_get_disconnect_reason(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Disconnected: %s", reason);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* preserve statistics */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_command_parser_deinit(&conn->smtp_parser);
ac581db9a4ff22c5f99cf1666a0a1a7f7889e0a2Josef 'Jeff' Sipek ssl_iostream_destroy(&conn->ssl_iostream);
ad9dc923a7169d70d8fdefc5746a87af6eda646dTimo Sirainen /* the callback may close the fd, so remove IO before that */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_disconnect(conn->context,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_connection_unref(struct smtp_server_connection **_conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_disconnect(conn, NULL);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Connection destroy");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* drop transaction */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* clear command queue */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_send_line(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *fmt, ...)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_nsend(conn->conn.output, str_data(str), str_len(str));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_nsend(conn->conn.output, str_data(str), str_len(str));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* send immediately */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_login(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const unsigned char *pdata, unsigned int pdata_len,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!i_stream_add_data(conn->conn.input, pdata, pdata_len))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_panic("Couldn't add client input to stream");
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Boschvoid smtp_server_connection_start_pending(struct smtp_server_connection *conn)
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Boschvoid smtp_server_connection_start(struct smtp_server_connection *conn)
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Boschvoid smtp_server_connection_halt(struct smtp_server_connection *conn)
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch if (!conn->started || !conn->ssl_start || conn->ssl_iostream != NULL)
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Boschvoid smtp_server_connection_resume(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_close(struct smtp_server_connection **_conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_disconnect(conn, reason);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_terminate(struct smtp_server_connection **_conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(enh_code[0] == '4' && enh_code[1] == '.');
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "421 %s %s %s", enh_code, conn->set.hostname, reason);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_helo_data(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_state(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_set_state(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_state_changed != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_state_changed(conn->context, state);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_security_string(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return ssl_iostream_get_security_string(conn->ssl_iostream);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_reset_state(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Connection state reset");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_trans_free(conn->context,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_transaction_free(&conn->state.trans);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* RFC 3030, Section 2:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch The RSET command, when issued after the first BDAT and before the
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch BDAT LAST, clears all segments sent during that transaction and resets
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* reset state */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_READY);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_clear(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Connection clear");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn, enum smtp_capability capabilities)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid *smtp_server_connection_get_context(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_connection_is_ssl_secured(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_connection_is_trusted(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->callbacks == NULL || conn->callbacks->conn_is_trusted == NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn->callbacks->conn_is_trusted(conn->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_protocol(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_protocol_name(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_transaction(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_transaction_id(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_get_proxy_data(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->proxy_proto != SMTP_PROXY_PROTOCOL_UNKNOWN)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else if (conn->set.protocol == SMTP_PROTOCOL_LMTP)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->proto = SMTP_PROXY_PROTOCOL_ESMTP;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->ttl_plus_1 = conn->proxy_ttl_plus_1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->timeout_secs = conn->proxy_timeout_secs;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_set_proxy_data(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->helo_domain = i_strdup(proxy_data->helo);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (proxy_data->proto != SMTP_PROXY_PROTOCOL_UNKNOWN)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->proxy_ttl_plus_1 = proxy_data->ttl_plus_1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->proxy_timeout_secs = proxy_data->timeout_secs;
8366c177e4901d851c94eb612633ffccaf5a9712Stephan Bosch conn->callbacks->conn_proxy_data_updated != NULL) {
8366c177e4901d851c94eb612633ffccaf5a9712Stephan Bosch conn_proxy_data_updated(conn->context, proxy_data);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_switch_ioloop(struct smtp_server_connection *conn)