bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "lib.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "llist.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "array.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "str.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "ioloop.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "istream.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "ostream.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "iostream.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "connection.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "iostream-rawlog.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "iostream-ssl.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "master-service.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "master-service-ssl.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-command-parser.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#include "smtp-server-private.h"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschconst char *const smtp_server_state_names[] = {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "GREETING",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "XCLIENT",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "HELO",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "STARTTLS",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "AUTH",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "READY",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "MAIL FROM",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "RCPT TO",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "DATA"
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch};
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch/*
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch * Logging
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_debug(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *format, ...)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_list args;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->set.debug) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_start(args, format);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_debug("%s-server: conn %s: %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_protocol_name(conn->set.protocol),
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_label(conn),
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch t_strdup_vprintf(format, args));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_end(args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_error(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *format, ...)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_list args;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_start(args, format);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_error("%s-server: conn %s: %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_protocol_name(conn->set.protocol),
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_label(conn),
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch t_strdup_vprintf(format, args));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_end(args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch/*
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch * Connection
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_input(struct connection *_conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic int
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_output(struct smtp_server_connection *conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_disconnect(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *reason) ATTR_NULL(2);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_update_stats(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->conn.input != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->stats.input = conn->conn.input->v_offset;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->conn.output != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->stats.output = conn->conn.output->offset;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschconst struct smtp_server_stats *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_stats(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_update_stats(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return &conn->stats;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_input_halt(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
a103512f10310a976e5491d73a2d64c5f16768f7Stephan Bosch connection_input_halt(&conn->conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_input_resume(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch bool cmd_locked = FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->conn.io == NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* only resume when we actually can */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->input_locked || conn->input_broken ||
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->disconnected)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->command_queue_count >
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->server->set.max_pipelined_commands)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* is queued command still blocking input? */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = conn->command_queue_head;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch while (cmd != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->input_locked) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd_locked = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = cmd->next;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd_locked)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* restore input handler */
a103512f10310a976e5491d73a2d64c5f16768f7Stephan Bosch connection_input_resume(&conn->conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->conn.io != NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_stream_have_bytes_left(conn->conn.input)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch io_set_pending(conn->conn.io);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_input_lock(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->input_locked = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_halt(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_input_unlock(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->input_locked = FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_resume(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch#undef smtp_server_connection_input_capture
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_input_capture(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_input_callback_t *callback, void *context)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(!conn->input_broken && !conn->disconnected);
a103512f10310a976e5491d73a2d64c5f16768f7Stephan Bosch connection_input_halt(&conn->conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->conn.io = io_add_istream(conn->conn.input, *callback, context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_update_rawlog(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct stat st;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->set.rawlog_dir == NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!conn->rawlog_checked) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->rawlog_checked = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (stat(conn->set.rawlog_dir, &st) == 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->rawlog_enabled = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->rawlog_enabled) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch iostream_rawlog_create(conn->set.rawlog_dir,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->conn.input, &conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_streams_changed(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_update_rawlog(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_command_parser_set_stream(conn->smtp_parser, conn->conn.input);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_callback(conn->conn.output,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_output, conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_pending(conn->conn.output, TRUE);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_set_streams(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct istream *input, struct ostream *output)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct istream *old_input = conn->conn.input;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct ostream *old_output = conn->conn.output;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(conn->created_from_streams);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->conn.input = input;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_stream_ref(conn->conn.input);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->conn.output = output;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_ref(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_no_error_handling(conn->conn.output, TRUE);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_stream_unref(&old_input);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_unref(&old_output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_streams_changed(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Boschvoid smtp_server_connection_set_ssl_streams(struct smtp_server_connection *conn,
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch struct istream *input, struct ostream *output)
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch{
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch conn->ssl_secured = TRUE;
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch smtp_server_connection_set_streams(conn, input, output);
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch}
55f1e5a6f22a7ea13a12b17be715e661e7f02471Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_idle_timeout(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_terminate(&conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "4.4.2", "Disconnected for inactivity");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_timeout_stop(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->to_idle != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Timeout stop");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch timeout_remove(&conn->to_idle);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_timeout_start(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->disconnected)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->to_idle == NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.max_client_idle_time_msecs > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Timeout start");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->to_idle = timeout_add(
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.max_client_idle_time_msecs,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_idle_timeout, conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_timeout_reset(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->to_idle != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch timeout_reset(conn->to_idle);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_timeout_update(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd = conn->command_queue_head;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd == NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_timeout_start(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch switch (cmd->state) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_NEW:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_timeout_start(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_PROCESSING:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->input_captured) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* command updates timeout internally */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_timeout_stop(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_timeout_stop(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_FINISHED:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_SERVER_COMMAND_STATE_ABORTED:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_unreached();
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_ready(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->raw_input = conn->conn.input;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->raw_output = conn->conn.output;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_update_rawlog(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->smtp_parser = smtp_command_parser_init(conn->conn.input,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->server->set.command_limits);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_callback(conn->conn.output,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_output, conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
9a3c4a10fddf508c14d19fdc508d86b1be6d145bStephan Bosch o_stream_cork(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->authenticated) {
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 smtp_server_connection_send_line(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "235 2.7.0 Logged in.");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_send_line(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "220 %s %s", conn->set.hostname,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.login_greeting);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!conn->corked)
9a3c4a10fddf508c14d19fdc508d86b1be6d145bStephan Bosch o_stream_uncork(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void smtp_server_connection_destroy(struct connection *_conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch (struct smtp_server_connection *)_conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_disconnect(conn, NULL);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_unref(&conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic bool
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_handle_command(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *cmd_name, const char *cmd_params)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *tmp_conn = conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_ref(tmp_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 destroyed */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd != NULL && conn->command_queue_head == cmd)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_next_to_reply(cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_timeout_update(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return (cmd == NULL || !cmd->input_locked);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschint smtp_server_connection_ssl_init(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *error;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Starting SSL handshake");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->raw_input != conn->conn.input) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* recreate rawlog after STARTTLS */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_stream_ref(conn->raw_input);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_ref(conn->raw_output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_stream_destroy(&conn->conn.input);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_destroy(&conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->conn.input = conn->raw_input;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->conn.output = conn->raw_output;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
bca3d380d02db7dc1f5a0c0c2929dbf61cfe4e0eStephan Bosch smtp_server_connection_input_halt(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (master_service_ssl_init(master_service,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->conn.input, &conn->conn.output,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->ssl_iostream, &error) < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_error(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Couldn't initialize SSL server for %s: %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->conn.name, error);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return -1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
bca3d380d02db7dc1f5a0c0c2929dbf61cfe4e0eStephan Bosch smtp_server_connection_input_resume(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_error(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "SSL handshake failed: %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch ssl_iostream_get_last_error(conn->ssl_iostream));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return -1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->ssl_secured = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->ssl_start)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_ready(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_streams_changed(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return 0;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_handle_input(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *pending_command;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch enum smtp_command_parse_error error_code;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *cmd_name, *cmd_params, *error;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch int ret;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* check whether we are continuing a command */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pending_command = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->command_queue_tail != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pending_command = (conn->command_queue_tail->state ==
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY ?
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->command_queue_tail : NULL);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_timeout_reset(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* parse commands */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch ret = 1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch while (!conn->closing && ret != 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch while ((ret = smtp_command_parse_next(conn->smtp_parser,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &cmd_name, &cmd_params, &error_code, &error)) > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (pending_command != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* previous command is now fully read and ready
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch to reply */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_ready_to_reply(pending_command);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pending_command = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Received new command: %s %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd_name, cmd_params);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->stats.command_count++;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* handle command
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd may be destroyed after this */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!smtp_server_connection_handle_command(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd_name, cmd_params))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->disconnected)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* client indicated it will close after this command;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch stop trying to read more. */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->closing)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->command_queue_count >=
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->server->set.max_pipelined_commands) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_halt(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->command_queue_tail != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pending_command = (conn->command_queue_tail->state ==
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY ?
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->command_queue_tail : NULL);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (ret < 0 && conn->conn.input->eof) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch int stream_errno = conn->conn.input->stream_errno;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (stream_errno != 0 && stream_errno != EPIPE &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch stream_errno != ECONNRESET) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_error(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Connection lost: read(%s) failed: %s",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_stream_get_name(conn->conn.input),
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_stream_get_error(conn->conn.input));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_close(&conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Read failure");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Connection lost: Remote disconnected");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->command_queue_head == NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* no pending commands; close */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_close(&conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Remote closed connection");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if (conn->command_queue_head->state <
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* unfinished command; close */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_close(&conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Remote closed connection unexpectedly");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* a command is still processing;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch only drop input io for now */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->input_broken = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_halt(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (ret < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Client sent invalid command: %s", error);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch switch (error_code) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_COMMAND_PARSE_ERROR_BROKEN_COMMAND:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->input_broken = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* fall through */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_COMMAND_PARSE_ERROR_BAD_COMMAND:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = smtp_server_command_alloc(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_fail(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 500, "5.5.2", "Invalid command syntax");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_COMMAND_PARSE_ERROR_LINE_TOO_LONG:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = smtp_server_command_alloc(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_fail(cmd,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch 500, "5.5.2", "Line too long");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_COMMAND_PARSE_ERROR_DATA_TOO_LARGE:
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 smtp_server_connection_close(&conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Command data size exceeds absolute limit");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_COMMAND_PARSE_ERROR_BROKEN_STREAM:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_close(&conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Command data ended prematurely");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch default:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_unreached();
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->disconnected)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->input_broken || conn->closing) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_halt(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (ret == 0 && pending_command != NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch !smtp_command_parser_pending_data(conn->smtp_parser)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* previous command is now fully read and ready to
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch reply */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_ready_to_reply(pending_command);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void smtp_server_connection_input(struct connection *_conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch (struct smtp_server_connection *)_conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(!conn->input_broken);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->handling_input)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_timeout_reset(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->ssl_start && conn->ssl_iostream == NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (smtp_server_connection_ssl_init(conn) < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_close(&conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "SSL Initialization failed");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch if (conn->halted) {
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch smtp_server_connection_input_lock(conn);
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch return;
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch i_assert(!conn->halted);
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->command_queue_count >
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->server->set.max_pipelined_commands) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_input_halt(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_ref(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->handling_input = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->callbacks != NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_cmd_input_pre != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_cmd_input_pre(conn->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_handle_input(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->callbacks != NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_cmd_input_post != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_cmd_input_post(conn->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->handling_input = FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_unref(&conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_connection_pending_command_data(
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
5dfe0fedb007f58f9baae082fbbe14161890600aTimo Sirainen if (conn->smtp_parser == NULL)
5dfe0fedb007f58f9baae082fbbe14161890600aTimo Sirainen return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return smtp_command_parser_pending_data(conn->smtp_parser);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch/*
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch * Command reply handling
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Boschvoid smtp_server_connection_handle_output_error(
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch struct smtp_server_connection *conn)
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch{
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch struct ostream *output = conn->conn.output;
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch if (output->stream_errno != EPIPE &&
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch output->stream_errno != ECONNRESET) {
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch smtp_server_connection_error(conn,
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch "Connection lost: write(%s) failed: %s",
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch o_stream_get_name(output),
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch o_stream_get_error(output));
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch smtp_server_connection_close(&conn,
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch "Write failure");
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch } else {
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch smtp_server_connection_debug(conn,
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch "Connection lost: Remote disconnected");
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch smtp_server_connection_close(&conn,
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch "Remote closed connection unexpectedly");
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch }
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch}
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic bool
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_next_reply(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int i;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = conn->command_queue_head;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd == NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* no commands pending */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "No more commands pending");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->state < SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_next_to_reply(cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(cmd->state == SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY &&
3bded60597c6c3bf09eaa09790c36d439cb3a018Stephan Bosch array_is_created(&cmd->replies));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_completed(cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
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 for (i = 0; i < cmd->replies_expected; i++) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_reply *reply;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch reply = array_idx_modifiable(&cmd->replies, i);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!reply->submitted) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(!reply->sent);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd->state = SMTP_SERVER_COMMAND_STATE_PROCESSING;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
2f07c9a5d854404dad3380c5968b409e03fb4108Stephan Bosch if (smtp_server_reply_send(reply) < 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (cmd->state == SMTP_SERVER_COMMAND_STATE_PROCESSING)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_finished(cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_cork(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->corked = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->conn.output != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_cork(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_uncork(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
be6741282be725d76462110e1d7024956e2a100bStephan Bosch conn->corked = FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->conn.output != NULL) {
be6741282be725d76462110e1d7024956e2a100bStephan Bosch if (o_stream_uncork_flush(conn->conn.output) < 0) {
be6741282be725d76462110e1d7024956e2a100bStephan Bosch smtp_server_connection_handle_output_error(conn);
be6741282be725d76462110e1d7024956e2a100bStephan Bosch return;
be6741282be725d76462110e1d7024956e2a100bStephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_trigger_output(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_send_replies(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
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
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_timeout_update(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* accept more commands if possible */
479f238c944ecf94f05008cf14e48225743c9febStephan Bosch smtp_server_connection_input_resume(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschint smtp_server_connection_flush(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct ostream *output = conn->conn.output;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch int ret;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if ((ret = o_stream_flush(output)) <= 0) {
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch if (ret < 0)
1e3de3981ee5b13f59d84c6f9cd3722ae3084852Stephan Bosch smtp_server_connection_handle_output_error(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return ret;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return 1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic int
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_output(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch int ret;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Sending replies");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_ref(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_cork(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if ((ret=smtp_server_connection_flush(conn)) > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_timeout_reset(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_send_replies(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
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);
be6741282be725d76462110e1d7024956e2a100bStephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_unref(&conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return ret;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_trigger_output(
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->conn.output != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "Trigger output");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_set_flush_pending(conn->conn.output, TRUE);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch/*
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic struct connection_settings smtp_server_connection_set = {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch .input_max_size = (size_t)-1,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch .output_max_size = (size_t)-1,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch .client = FALSE
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch};
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic const struct connection_vfuncs smtp_server_connection_vfuncs = {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch .destroy = smtp_server_connection_destroy,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch .input = smtp_server_connection_input
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch};
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstruct connection_list *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_list_init(void)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return connection_list_init(&smtp_server_connection_set,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &smtp_server_connection_vfuncs);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
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{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch static unsigned int id = 0;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pool_t pool;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pool = pool_alloconly_create("smtp server", 512);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn = p_new(pool, struct smtp_server_connection, 1);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->pool = pool;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->refcount = 1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->id = id++;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->server = server;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks = callbacks;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->context = context;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* merge settings with global server settings */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set = server->set;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.protocol = server->set.protocol;
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 if (set->login_greeting != NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch *set->login_greeting != '\0') {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.login_greeting =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch p_strdup(pool, set->login_greeting);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->capabilities != 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.capabilities = set->capabilities;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->max_client_idle_time_msecs > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.max_client_idle_time_msecs =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set->max_client_idle_time_msecs;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->max_pipelined_commands > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.max_pipelined_commands =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set->max_pipelined_commands;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->max_bad_commands > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.max_bad_commands = set->max_bad_commands;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch if (set->max_recipients > 0)
4dd460cf19f1df3b51090427fea87e9c4b73c6d4Stephan Bosch conn->set.max_recipients = set->max_recipients;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_command_limits_merge(&conn->set.command_limits,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &set->command_limits);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->xclient_extensions != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch server->set.xclient_extensions =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch p_strarray_dup(pool, set->xclient_extensions);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->socket_send_buffer_size > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.socket_send_buffer_size =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set->socket_send_buffer_size;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->socket_recv_buffer_size > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.socket_recv_buffer_size =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set->socket_recv_buffer_size;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.tls_required =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.tls_required || set->tls_required;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.auth_optional =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.auth_optional || set->auth_optional;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.rcpt_domain_optional =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.rcpt_domain_optional ||
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set->rcpt_domain_optional;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.param_extensions =
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.param_extensions || set->param_extensions;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.debug = conn->set.debug || set->debug;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_pid = (pid_t)-1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_uid = (uid_t)-1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (remote_ip != NULL && remote_ip->family != 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_ip = *remote_ip;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_port = remote_port;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->socket_family = conn->remote_ip.family;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if (fd_in != fd_out || net_getpeername(fd_in,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->remote_ip, &conn->remote_port) < 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* tty connection probably */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->remote_ip.family == 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct net_unix_cred cred;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* unix */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->socket_family = AF_UNIX;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (net_getunixcred(fd_in, &cred) >= 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_pid = cred.pid;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_uid = cred.uid;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* ip / ip6 */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->socket_family = conn->remote_ip.family;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch net_set_nonblock(fd_in, TRUE);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (fd_in != fd_out)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch net_set_nonblock(fd_out, TRUE);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch (void)net_set_tcp_nodelay(fd_out, TRUE);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set = &conn->set;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->socket_send_buffer_size > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (net_set_send_buffer_size(fd_out,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set->socket_send_buffer_size) < 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_error("net_set_send_buffer_size(%"PRIuSIZE_T") failed: %m",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set->socket_send_buffer_size);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (set->socket_recv_buffer_size > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (net_set_recv_buffer_size(fd_in,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set->socket_recv_buffer_size) < 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_error("net_set_recv_buffer_size(%"PRIuSIZE_T") failed: %m",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set->socket_recv_buffer_size);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic const char *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_name(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *name;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* get a name for this connection */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch switch (conn->socket_family) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case 0:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name = t_strdup_printf("[%u]", conn->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case AF_UNIX:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->remote_uid == (uid_t)-1) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name = t_strdup_printf("unix [%u]", conn->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else if (conn->remote_pid == (pid_t)-1) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name = t_strdup_printf("unix:uid=%u [%u]",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_uid, conn->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } else {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name = t_strdup_printf("unix:pid=%u,uid=%u [%u]",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_pid, conn->remote_uid, conn->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case AF_INET6:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name = t_strdup_printf("[%s]:%u [%u]",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch net_ip2addr(&conn->remote_ip), conn->remote_port, conn->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case AF_INET:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name = t_strdup_printf("%s:%u [%u]",
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch net_ip2addr(&conn->remote_ip), conn->remote_port, conn->id);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch default:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_unreached();
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return name;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstruct smtp_server_connection *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_create(struct smtp_server *server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch int fd_in, int fd_out,
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)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *name;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn = smtp_server_connection_alloc(server,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch set, fd_in, fd_out, remote_ip, remote_port,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch callbacks, context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name = smtp_server_connection_get_name(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch connection_init_server(server->conn_list,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->conn, name, fd_in, fd_out);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
40a926a1aeae93b3d4944b56eacb013d3059b549Stephan Bosch conn->ssl_start = ssl_start;
40a926a1aeae93b3d4944b56eacb013d3059b549Stephan Bosch if (ssl_start)
40a926a1aeae93b3d4944b56eacb013d3059b549Stephan Bosch conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
40a926a1aeae93b3d4944b56eacb013d3059b549Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* halt input until started */
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch smtp_server_connection_halt(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Connection created");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstruct smtp_server_connection *
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_settings *set,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_server_callbacks *callbacks, void *context)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *name;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch int fd_in, fd_out;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch fd_in = i_stream_get_fd(input);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch fd_out = o_stream_get_fd(output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(fd_in >= 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(fd_out >= 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn = smtp_server_connection_alloc(server, set,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch fd_in, fd_out, remote_ip, remote_port,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch callbacks, context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch name = smtp_server_connection_get_name(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch connection_init_from_streams(server->conn_list,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch &conn->conn, name, input, output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->created_from_streams = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* halt input until started */
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch smtp_server_connection_halt(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Connection created");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_ref(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->refcount++;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic const char *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_disconnect_reason(
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *err;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->ssl_iostream != NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch !ssl_iostream_is_handshaked(conn->ssl_iostream)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch err = ssl_iostream_get_last_error(conn->ssl_iostream);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (err != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return t_strdup_printf(
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "TLS handshaking failed: %s", err);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return io_stream_get_disconnect_reason(conn->conn.input,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstatic void
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_disconnect(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *reason)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->disconnected)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->disconnected = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (reason == NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch reason = smtp_server_connection_get_disconnect_reason(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Disconnected: %s", reason);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->disconnect_reason = i_strdup(reason);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* preserve statistics */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_update_stats(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_timeout_stop(conn);
c13d3128fdf314fc8b550c9cf03fe673b33ce32fStephan Bosch if (conn->conn.output != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_uncork(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->smtp_parser != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_command_parser_deinit(&conn->smtp_parser);
ac581db9a4ff22c5f99cf1666a0a1a7f7889e0a2Josef 'Jeff' Sipek ssl_iostream_destroy(&conn->ssl_iostream);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->callbacks != NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_disconnect != NULL) {
ad9dc923a7169d70d8fdefc5746a87af6eda646dTimo Sirainen /* the callback may close the fd, so remove IO before that */
ad9dc923a7169d70d8fdefc5746a87af6eda646dTimo Sirainen io_remove(&conn->conn.io);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_disconnect(conn->context,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch reason);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!conn->created_from_streams)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch connection_disconnect(&conn->conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->conn.fd_in = conn->conn.fd_out = -1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch io_remove(&conn->conn.io);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_stream_unref(&conn->conn.input);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_unref(&conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_connection_unref(struct smtp_server_connection **_conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = *_conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_command *cmd, *cmd_next;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch *_conn = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(conn->refcount > 0);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (--conn->refcount > 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_disconnect(conn, NULL);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Connection destroy");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* drop transaction */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_reset_state(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* clear command queue */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = conn->command_queue_head;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch while (cmd != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd_next = cmd->next;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_command_abort(&cmd);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch cmd = cmd_next;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->callbacks != NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_destroy != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_destroy(conn->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch connection_deinit(&conn->conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_free(conn->helo_domain);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_free(conn->helo_login);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_free(conn->username);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_free(conn->disconnect_reason);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch pool_unref(&conn->pool);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_send_line(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *fmt, ...)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_list args;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_start(args, fmt);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch T_BEGIN {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch string_t *str;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str = t_str_new(256);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_vprintfa(str, fmt, args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "\r\n");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_nsend(conn->conn.output, str_data(str), str_len(str));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } T_END;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_end(args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_reply_immediate(
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch unsigned int status, const char *fmt, ...)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_list args;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_start(args, fmt);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch T_BEGIN {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch string_t *str;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str = t_str_new(256);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_printfa(str, "%03u ", status);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_vprintfa(str, fmt, args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(str, "\r\n");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_nsend(conn->conn.output, str_data(str), str_len(str));
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch } T_END;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch va_end(args);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* send immediately */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (o_stream_is_corked(conn->conn.output)) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_uncork(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch o_stream_cork(conn->conn.output);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_login(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *username, const char *helo,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const unsigned char *pdata, unsigned int pdata_len,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch bool ssl_secured)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
3feb1ab03917f2773f379fa79315a0f87db59bc5Stephan Bosch i_assert(!conn->started);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(conn->username == NULL);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->username = i_strdup(username);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->helo_login = i_strdup(helo);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->authenticated = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->ssl_secured = ssl_secured;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (pdata_len > 0) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (!i_stream_add_data(conn->conn.input, pdata, pdata_len))
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_panic("Couldn't add client input to stream");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Boschvoid smtp_server_connection_start_pending(struct smtp_server_connection *conn)
b85a1bcaa9f82dd5b326967da5f1a26595173ee9Stephan Bosch{
f091dd12d19df22e5403855f93dedee437bd7d87Stephan Bosch i_assert(!conn->started);
f091dd12d19df22e5403855f93dedee437bd7d87Stephan Bosch conn->started = TRUE;
f091dd12d19df22e5403855f93dedee437bd7d87Stephan Bosch
b85a1bcaa9f82dd5b326967da5f1a26595173ee9Stephan Bosch conn->raw_input = conn->conn.input;
b85a1bcaa9f82dd5b326967da5f1a26595173ee9Stephan Bosch conn->raw_output = conn->conn.output;
b85a1bcaa9f82dd5b326967da5f1a26595173ee9Stephan Bosch
b85a1bcaa9f82dd5b326967da5f1a26595173ee9Stephan Bosch if (!conn->ssl_start)
b85a1bcaa9f82dd5b326967da5f1a26595173ee9Stephan Bosch smtp_server_connection_ready(conn);
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch else if (conn->ssl_iostream == NULL)
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch smtp_server_connection_input_unlock(conn);
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch}
9a3c4a10fddf508c14d19fdc508d86b1be6d145bStephan Bosch
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Boschvoid smtp_server_connection_start(struct smtp_server_connection *conn)
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch{
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch smtp_server_connection_start_pending(conn);
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch smtp_server_connection_resume(conn);
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch}
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Boschvoid smtp_server_connection_halt(struct smtp_server_connection *conn)
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch{
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch conn->halted = TRUE;
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch smtp_server_connection_timeout_stop(conn);
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch if (!conn->started || !conn->ssl_start || conn->ssl_iostream != NULL)
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch smtp_server_connection_input_lock(conn);
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch}
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Boschvoid smtp_server_connection_resume(struct smtp_server_connection *conn)
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch{
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch smtp_server_connection_input_unlock(conn);
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch smtp_server_connection_timeout_update(conn);
912e87d5be9dd8895e8cb7c6cb51d8a752edbe8cStephan Bosch conn->halted = FALSE;
b85a1bcaa9f82dd5b326967da5f1a26595173ee9Stephan Bosch}
b85a1bcaa9f82dd5b326967da5f1a26595173ee9Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_close(struct smtp_server_connection **_conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *reason)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = *_conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch *_conn = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->closed)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->closed = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_disconnect(conn, reason);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_unref(&conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_terminate(struct smtp_server_connection **_conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const char *enh_code, const char *reason)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn = *_conn;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch *_conn = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->closed)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_assert(enh_code[0] == '4' && enh_code[1] == '.');
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_send_line(conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch "421 %s %s %s", enh_code, conn->set.hostname, reason);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_close(&conn, reason);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstruct smtp_server_helo_data *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_helo_data(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return &conn->helo;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschenum smtp_server_state
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_state(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn->state.state;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_set_state(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch enum smtp_server_state state)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->state.state != state) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->state.state = state;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->callbacks != NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_state_changed != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_state_changed(conn->context, state);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschconst char *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_security_string(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->ssl_iostream == NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return ssl_iostream_get_security_string(conn->ssl_iostream);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_reset_state(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Connection state reset");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->state.trans != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->callbacks != NULL &&
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_trans_free != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->callbacks->conn_trans_free(conn->context,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->state.trans);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_transaction_free(&conn->state.trans);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
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 the session.
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->state.data_input != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_stream_destroy(&conn->state.data_input);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->state.data_chain = NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch /* reset state */
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_zero(&conn->state);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_READY);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_clear(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_debug(conn, "Connection clear");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_free(conn->helo_domain);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_free(conn->helo_login);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_zero(&conn->helo);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch smtp_server_connection_reset_state(conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_set_capabilities(
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_server_connection *conn, enum smtp_capability capabilities)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->set.capabilities = capabilities;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid *smtp_server_connection_get_context(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn->context;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_connection_is_ssl_secured(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn->ssl_secured;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschbool smtp_server_connection_is_trusted(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->callbacks == NULL || conn->callbacks->conn_is_trusted == NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return FALSE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn->callbacks->conn_is_trusted(conn->context);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschenum smtp_protocol
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_protocol(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn->set.protocol;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschconst char *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_protocol_name(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch string_t *pname = t_str_new(16);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch switch (conn->set.protocol) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_PROTOCOL_SMTP:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->helo.old_smtp)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(pname, "SMTP");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(pname, "ESMTP");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch case SMTP_PROTOCOL_LMTP:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append(pname, "LMTP");
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch break;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch default:
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_unreached();
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->ssl_secured)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append_c(pname, 'S');
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->authenticated)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch str_append_c(pname, 'A');
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return str_c(pname);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschstruct smtp_server_transaction *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_transaction(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn->state.trans;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschconst char *
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschsmtp_server_connection_get_transaction_id(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->state.trans == NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return NULL;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch return conn->state.trans->id;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_get_proxy_data(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch struct smtp_proxy_data *proxy_data)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_zero(proxy_data);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->source_ip = conn->remote_ip;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->source_port = conn->remote_port;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->helo.domain_valid)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->helo = conn->helo.domain;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->login = conn->username;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->proxy_proto != SMTP_PROXY_PROTOCOL_UNKNOWN)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->proto = conn->proxy_proto;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else if (conn->set.protocol == SMTP_PROTOCOL_LMTP)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->proto = SMTP_PROXY_PROTOCOL_LMTP;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else if (conn->helo.old_smtp)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->proto = SMTP_PROXY_PROTOCOL_SMTP;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch else
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->proto = SMTP_PROXY_PROTOCOL_ESMTP;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->ttl_plus_1 = conn->proxy_ttl_plus_1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch proxy_data->timeout_secs = conn->proxy_timeout_secs;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_set_proxy_data(struct smtp_server_connection *conn,
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch const struct smtp_proxy_data *proxy_data)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (proxy_data->source_ip.family != 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_ip = proxy_data->source_ip;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (proxy_data->source_port != 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->remote_port = proxy_data->source_port;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (proxy_data->helo != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_free(conn->helo_domain);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->helo_domain = i_strdup(proxy_data->helo);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->helo.domain = conn->helo_domain;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->helo.domain_valid = TRUE;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (proxy_data->login != NULL) {
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch i_free(conn->username);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->username = i_strdup(proxy_data->login);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (proxy_data->proto != SMTP_PROXY_PROTOCOL_UNKNOWN)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->proxy_proto = proxy_data->proto;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (proxy_data->ttl_plus_1 > 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->proxy_ttl_plus_1 = proxy_data->ttl_plus_1;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->proxy_timeout_secs > 0)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->proxy_timeout_secs = proxy_data->timeout_secs;
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->callbacks != NULL &&
8366c177e4901d851c94eb612633ffccaf5a9712Stephan Bosch conn->callbacks->conn_proxy_data_updated != NULL) {
8366c177e4901d851c94eb612633ffccaf5a9712Stephan Bosch conn->callbacks->
8366c177e4901d851c94eb612633ffccaf5a9712Stephan Bosch conn_proxy_data_updated(conn->context, proxy_data);
8366c177e4901d851c94eb612633ffccaf5a9712Stephan Bosch }
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Boschvoid smtp_server_connection_switch_ioloop(struct smtp_server_connection *conn)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch{
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch if (conn->to_idle != NULL)
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch conn->to_idle = io_loop_move_timeout(&conn->to_idle);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch connection_switch_ioloop(&conn->conn);
56dd928c164ec5c0d1158a1760154b58c5f1f6e7Stephan Bosch}