smtp-server-connection.c revision 479f238c944ecf94f05008cf14e48225743c9feb
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "lib.h"
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen#include "llist.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "array.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "str.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "ioloop.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "istream.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "ostream.h"
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen#include "iostream.h"
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen#include "connection.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "iostream-rawlog.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "iostream-ssl.h"
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen#include "master-service.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "master-service-ssl.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "smtp-command-parser.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen#include "smtp-server-private.h"
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenconst char *const smtp_server_state_names[] = {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen "GREETING",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen "XCLIENT",
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen "HELO",
5e615a0e4682b75cadb5bea4bff689f3fcf8e9feTimo Sirainen "STARTTLS",
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen "AUTH",
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen "READY",
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen "MAIL FROM",
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen "RCPT TO",
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen "DATA"
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen};
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen/*
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen * Logging
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen */
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenvoid smtp_server_connection_debug(struct smtp_server_connection *conn,
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen const char *format, ...)
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen{
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen va_list args;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (conn->set.debug) {
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen va_start(args, format);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen i_debug("%s-server: conn %s: %s",
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen smtp_protocol_name(conn->set.protocol),
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen smtp_server_connection_label(conn),
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen t_strdup_vprintf(format, args));
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen va_end(args);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen}
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenvoid smtp_server_connection_error(struct smtp_server_connection *conn,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen const char *format, ...)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen{
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen va_list args;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen va_start(args, format);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_error("%s-server: conn %s: %s",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen smtp_protocol_name(conn->set.protocol),
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen smtp_server_connection_label(conn),
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen t_strdup_vprintf(format, args));
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen va_end(args);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen/*
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen * Connection
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen */
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenstatic void
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainensmtp_server_connection_input(struct connection *_conn);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic int
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainensmtp_server_connection_output(struct smtp_server_connection *conn);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic void
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainensmtp_server_connection_disconnect(struct smtp_server_connection *conn,
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen const char *reason) ATTR_NULL(2);
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainenstatic void
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainensmtp_server_connection_update_stats(struct smtp_server_connection *conn)
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen{
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen if (conn->conn.input != NULL)
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen conn->stats.input = conn->conn.input->v_offset;
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen if (conn->conn.output != NULL)
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen conn->stats.output = conn->conn.output->offset;
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen}
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainenconst struct smtp_server_stats *
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainensmtp_server_connection_get_stats(struct smtp_server_connection *conn)
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen{
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen smtp_server_connection_update_stats(conn);
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen return &conn->stats;
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen}
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainenvoid smtp_server_connection_input_halt(struct smtp_server_connection *conn)
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen{
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen if (conn->conn.io != NULL)
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen io_remove(&conn->conn.io);
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen}
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenvoid smtp_server_connection_input_resume(struct smtp_server_connection *conn)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen{
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen struct smtp_server_command *cmd;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen bool cmd_locked = FALSE;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (conn->conn.io == NULL) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen /* only resume when we actually can */
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (conn->input_locked || conn->input_broken ||
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen conn->disconnected)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen return;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (conn->command_queue_count >
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->server->set.max_pipelined_commands)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen return;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen /* is queued command still blocking input? */
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen cmd = conn->command_queue_head;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen while (cmd != NULL) {
992118a50af940482b6cf884a89be56d7015580aTimo Sirainen if (cmd->input_locked) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen cmd_locked = TRUE;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen break;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen cmd = cmd->next;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (cmd_locked)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen return;
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen /* restore input handler */
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen conn->conn.io = io_add_istream(conn->conn.input,
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen smtp_server_connection_input, &conn->conn);
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (conn->conn.io != NULL &&
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen i_stream_have_bytes_left(conn->conn.input)) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen io_set_pending(conn->conn.io);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenvoid smtp_server_connection_input_lock(struct smtp_server_connection *conn)
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen{
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen conn->input_locked = TRUE;
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen smtp_server_connection_input_halt(conn);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenvoid smtp_server_connection_input_unlock(struct smtp_server_connection *conn)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen{
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen conn->input_locked = FALSE;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen smtp_server_connection_input_resume(conn);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen#undef smtp_server_connection_input_capture
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainenvoid smtp_server_connection_input_capture(struct smtp_server_connection *conn,
38a4c09de37bc2ebdc38427a2b958c46dfdcffb1Timo Sirainen smtp_server_input_callback_t *callback, void *context)
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen{
0f55802e8fdd95ae4290da6da077819209b71f70Timo Sirainen i_assert(!conn->input_broken && !conn->disconnected);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (conn->conn.io != NULL)
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen io_remove(&conn->conn.io);
20b136f04257b0ba338e49f31a999c0d4b243647Timo Sirainen conn->conn.io = io_add_istream(conn->conn.input, *callback, context);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic void
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainensmtp_server_connection_update_rawlog(struct smtp_server_connection *conn)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen{
992118a50af940482b6cf884a89be56d7015580aTimo Sirainen struct stat st;
992118a50af940482b6cf884a89be56d7015580aTimo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (conn->set.rawlog_dir == NULL)
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen return;
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen if (!conn->rawlog_checked) {
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen conn->rawlog_checked = TRUE;
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen if (stat(conn->set.rawlog_dir, &st) == 0)
c37e5edd83ff696d396131f7147ef971cf678911Timo Sirainen conn->rawlog_enabled = TRUE;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (conn->rawlog_enabled) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen iostream_rawlog_create(conn->set.rawlog_dir,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen &conn->conn.input, &conn->conn.output);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstatic void
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainensmtp_server_connection_streams_changed(struct smtp_server_connection *conn)
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen{
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen smtp_server_connection_update_rawlog(conn);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_command_parser_set_stream(conn->smtp_parser, conn->conn.input);
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainen
e22b857e838fe118de3f78513aad6a3c6f4306b3Timo Sirainen o_stream_set_flush_callback(conn->conn.output,
e22b857e838fe118de3f78513aad6a3c6f4306b3Timo Sirainen smtp_server_connection_output, conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen o_stream_set_flush_pending(conn->conn.output, TRUE);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenvoid smtp_server_connection_set_streams(struct smtp_server_connection *conn,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct istream *input, struct ostream *output)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen{
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct istream *old_input = conn->conn.input;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct ostream *old_output = conn->conn.output;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen i_assert(conn->created_from_streams);
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen conn->conn.input = input;
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen i_stream_ref(conn->conn.input);
1176124297af5c56e932c0863c6637ff21d8a0efTimo Sirainen
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen conn->conn.output = output;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen o_stream_ref(conn->conn.output);
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen o_stream_set_no_error_handling(conn->conn.output, TRUE);
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen i_stream_unref(&old_input);
c06cd6539a3dbd68eb546464076187be6bc4290fTimo Sirainen o_stream_unref(&old_output);
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen smtp_server_connection_streams_changed(conn);
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen}
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenstatic void
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainensmtp_server_connection_idle_timeout(struct smtp_server_connection *conn)
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen{
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen smtp_server_connection_terminate(&conn,
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen "4.4.2", "Disconnected for inactivity");
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen}
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenvoid smtp_server_connection_timeout_stop(struct smtp_server_connection *conn)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (conn->to_idle != NULL) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_debug(conn, "Timeout stop");
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen timeout_remove(&conn->to_idle);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenvoid smtp_server_connection_timeout_start(struct smtp_server_connection *conn)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (conn->disconnected)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen return;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (conn->to_idle == NULL &&
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->set.max_client_idle_time_msecs > 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_debug(conn, "Timeout start");
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->to_idle = timeout_add(
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->set.max_client_idle_time_msecs,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_idle_timeout, conn);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenvoid smtp_server_connection_timeout_reset(struct smtp_server_connection *conn)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (conn->to_idle != NULL)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen timeout_reset(conn->to_idle);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic void
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainensmtp_server_connection_timeout_update(struct smtp_server_connection *conn)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct smtp_server_command *cmd = conn->command_queue_head;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (cmd == NULL) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_timeout_start(conn);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen return;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen switch (cmd->state) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen case SMTP_SERVER_COMMAND_STATE_NEW:
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_timeout_start(conn);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen break;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen case SMTP_SERVER_COMMAND_STATE_PROCESSING:
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (cmd->input_captured) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* command updates timeout internally */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen return;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_timeout_stop(conn);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen break;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen case SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY:
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen case SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY:
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_timeout_stop(conn);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen break;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen case SMTP_SERVER_COMMAND_STATE_FINISHED:
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen case SMTP_SERVER_COMMAND_STATE_ABORTED:
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen i_unreached();
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainenstatic void
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainensmtp_server_connection_ready(struct smtp_server_connection *conn)
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen{
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen struct ostream *output;
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen conn->raw_input = conn->conn.input;
ff01c351d308504551048039304725d578978c2eTimo Sirainen conn->raw_output = conn->conn.output;
ff01c351d308504551048039304725d578978c2eTimo Sirainen
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen smtp_server_connection_update_rawlog(conn);
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen
af3f857bb3166ed99595e11a9d18e5b5cc670e1aTimo Sirainen conn->smtp_parser = smtp_command_parser_init(conn->conn.input,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen &conn->server->set.command_limits);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen o_stream_set_flush_callback(conn->conn.output,
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen smtp_server_connection_output, conn);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen output = conn->conn.output;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen o_stream_ref(output);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen o_stream_cork(output);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (conn->authenticated) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* RFC 4954, Section 4:
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen Should the client successfully complete the exchange, the
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen SMTP server issues a 235 reply. */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_send_line(conn,
ff01c351d308504551048039304725d578978c2eTimo Sirainen "235 2.7.0 Logged in.");
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen } else {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_send_line(conn,
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen "220 %s %s", conn->set.hostname,
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen conn->set.login_greeting);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (i_stream_get_data_size(conn->conn.input) > 0)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_input(&conn->conn);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (!conn->corked)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen o_stream_uncork(output);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen o_stream_unref(&output);
ff01c351d308504551048039304725d578978c2eTimo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic void smtp_server_connection_destroy(struct connection *_conn)
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct smtp_server_connection *conn =
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen (struct smtp_server_connection *)_conn;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
ff01c351d308504551048039304725d578978c2eTimo Sirainen smtp_server_connection_disconnect(conn, NULL);
ff01c351d308504551048039304725d578978c2eTimo Sirainen smtp_server_connection_unref(&conn);
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen}
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic bool
ff01c351d308504551048039304725d578978c2eTimo Sirainensmtp_server_connection_handle_command(struct smtp_server_connection *conn,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen const char *cmd_name, const char *cmd_params)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct smtp_server_connection *tmp_conn = conn;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct smtp_server_command *cmd;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
ff01c351d308504551048039304725d578978c2eTimo Sirainen smtp_server_connection_ref(tmp_conn);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen cmd = smtp_server_command_new(tmp_conn, cmd_name, cmd_params);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (!smtp_server_connection_unref(&tmp_conn)) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* the command start callback managed to get this connection
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen destroyed */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen return FALSE;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (cmd != NULL && conn->command_queue_head == cmd)
ff01c351d308504551048039304725d578978c2eTimo Sirainen smtp_server_command_next_to_reply(cmd);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_timeout_update(conn);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen return (cmd == NULL || !cmd->input_locked);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
ff01c351d308504551048039304725d578978c2eTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenint smtp_server_connection_ssl_init(struct smtp_server_connection *conn)
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen{
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen const char *error;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_debug(conn, "Starting SSL handshake");
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (conn->raw_input != conn->conn.input) {
ff01c351d308504551048039304725d578978c2eTimo Sirainen /* recreate rawlog after STARTTLS */
ff01c351d308504551048039304725d578978c2eTimo Sirainen i_stream_ref(conn->raw_input);
ff01c351d308504551048039304725d578978c2eTimo Sirainen o_stream_ref(conn->raw_output);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_stream_destroy(&conn->conn.input);
ff01c351d308504551048039304725d578978c2eTimo Sirainen o_stream_destroy(&conn->conn.output);
ff01c351d308504551048039304725d578978c2eTimo Sirainen conn->conn.input = conn->raw_input;
ff01c351d308504551048039304725d578978c2eTimo Sirainen conn->conn.output = conn->raw_output;
ff01c351d308504551048039304725d578978c2eTimo Sirainen }
ff01c351d308504551048039304725d578978c2eTimo Sirainen
ff01c351d308504551048039304725d578978c2eTimo Sirainen if (master_service_ssl_init(master_service,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen &conn->conn.input, &conn->conn.output,
ff01c351d308504551048039304725d578978c2eTimo Sirainen &conn->ssl_iostream, &error) < 0) {
ff01c351d308504551048039304725d578978c2eTimo Sirainen smtp_server_connection_error(conn,
ff01c351d308504551048039304725d578978c2eTimo Sirainen "Couldn't initialize SSL server for %s: %s",
ff01c351d308504551048039304725d578978c2eTimo Sirainen conn->conn.name, error);
ff01c351d308504551048039304725d578978c2eTimo Sirainen return -1;
ff01c351d308504551048039304725d578978c2eTimo Sirainen }
ff01c351d308504551048039304725d578978c2eTimo Sirainen
ff01c351d308504551048039304725d578978c2eTimo Sirainen if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_connection_error(conn,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen "SSL handshake failed: %s",
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ssl_iostream_get_last_error(conn->ssl_iostream));
ff01c351d308504551048039304725d578978c2eTimo Sirainen return -1;
ff01c351d308504551048039304725d578978c2eTimo Sirainen }
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen
ff01c351d308504551048039304725d578978c2eTimo Sirainen conn->ssl_secured = TRUE;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (conn->ssl_start)
ff01c351d308504551048039304725d578978c2eTimo Sirainen smtp_server_connection_ready(conn);
ff01c351d308504551048039304725d578978c2eTimo Sirainen else
ff01c351d308504551048039304725d578978c2eTimo Sirainen smtp_server_connection_streams_changed(conn);
ff01c351d308504551048039304725d578978c2eTimo Sirainen return 0;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
ff01c351d308504551048039304725d578978c2eTimo Sirainen
ff01c351d308504551048039304725d578978c2eTimo Sirainenstatic void
ff01c351d308504551048039304725d578978c2eTimo Sirainensmtp_server_connection_handle_input(struct smtp_server_connection *conn)
ff01c351d308504551048039304725d578978c2eTimo Sirainen{
ff01c351d308504551048039304725d578978c2eTimo Sirainen struct smtp_server_command *pending_command;
ff01c351d308504551048039304725d578978c2eTimo Sirainen enum smtp_command_parse_error error_code;
ff01c351d308504551048039304725d578978c2eTimo Sirainen const char *cmd_name, *cmd_params, *error;
ff01c351d308504551048039304725d578978c2eTimo Sirainen int ret;
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* check whether we are continuing a command */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen pending_command = NULL;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (conn->command_queue_tail != NULL) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen pending_command = (conn->command_queue_tail->state ==
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY ?
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->command_queue_tail : NULL);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
ff01c351d308504551048039304725d578978c2eTimo Sirainen smtp_server_connection_timeout_reset(conn);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* parse commands */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen ret = 1;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen while (!conn->closing && ret != 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen while ((ret = smtp_command_parse_next(conn->smtp_parser,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen &cmd_name, &cmd_params, &error_code, &error)) > 0) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (pending_command != NULL) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* previous command is now fully read and ready
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen to reply */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_command_ready_to_reply(pending_command);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen pending_command = NULL;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen }
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen smtp_server_connection_debug(conn,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen "Received new command: %s %s",
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen cmd_name, cmd_params);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->stats.command_count++;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* handle command
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen cmd may be destroyed after this */
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen if (!smtp_server_connection_handle_command(conn,
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen cmd_name, cmd_params))
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen return;
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen if (conn->disconnected)
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen return;
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen /* client indicated it will close after this command;
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen stop trying to read more. */
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen if (conn->closing)
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen break;
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen if (conn->command_queue_count >=
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen conn->server->set.max_pipelined_commands) {
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen smtp_server_connection_input_halt(conn);
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen return;
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen }
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen if (conn->command_queue_tail != NULL) {
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen pending_command = (conn->command_queue_tail->state ==
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY ?
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen conn->command_queue_tail : NULL);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen }
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (ret < 0 && conn->conn.input->eof) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen int stream_errno = conn->conn.input->stream_errno;
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen if (stream_errno != 0 && stream_errno != EPIPE &&
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen stream_errno != ECONNRESET) {
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen smtp_server_connection_error(conn,
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen "Connection lost: read(%s) failed: %s",
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen i_stream_get_name(conn->conn.input),
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen i_stream_get_error(conn->conn.input));
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_close(&conn,
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen "Read failure");
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen } else {
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen smtp_server_connection_debug(conn,
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen "Connection lost: Remote disconnected");
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (conn->command_queue_head == NULL) {
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen /* no pending commands; close */
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen smtp_server_connection_close(&conn,
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen "Remote closed connection");
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen } else if (conn->command_queue_head->state <
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY) {
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen /* unfinished command; close */
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen smtp_server_connection_close(&conn,
d0ef8bc2b961a68dd0f75662c2160bd296b9476bTimo Sirainen "Remote closed connection unexpectedly");
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen } else {
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen /* a command is still processing;
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen only drop input io for now */
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen conn->input_broken = TRUE;
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen smtp_server_connection_input_halt(conn);
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen }
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen }
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen return;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen }
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (ret < 0) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen struct smtp_server_command *cmd;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen smtp_server_connection_debug(conn,
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen "Client sent invalid command: %s", error);
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen switch (error_code) {
1176124297af5c56e932c0863c6637ff21d8a0efTimo Sirainen case SMTP_COMMAND_PARSE_ERROR_BROKEN_COMMAND:
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen conn->input_broken = TRUE;
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen /* fall through */
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen case SMTP_COMMAND_PARSE_ERROR_BAD_COMMAND:
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen cmd = smtp_server_command_alloc(conn);
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen smtp_server_command_fail(cmd,
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen 500, "5.5.2", "Invalid command syntax");
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen break;
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen case SMTP_COMMAND_PARSE_ERROR_LINE_TOO_LONG:
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen cmd = smtp_server_command_alloc(conn);
1176124297af5c56e932c0863c6637ff21d8a0efTimo Sirainen smtp_server_command_fail(cmd,
1176124297af5c56e932c0863c6637ff21d8a0efTimo Sirainen 500, "5.5.2", "Line too long");
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen break;
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen case SMTP_COMMAND_PARSE_ERROR_DATA_TOO_LARGE:
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen /* Command data size exceeds the absolute limit;
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen i.e. beyond which we don't even want to skip
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen data anymore. The command error is usually
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen already submitted by the application and sent
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen to the client. */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen smtp_server_connection_close(&conn,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen "Command data size exceeds absolute limit");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen case SMTP_COMMAND_PARSE_ERROR_BROKEN_STREAM:
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen smtp_server_connection_close(&conn,
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen "Command data ended prematurely");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen default:
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen i_unreached();
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen }
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen }
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen if (conn->disconnected)
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (conn->input_broken || conn->closing) {
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen smtp_server_connection_input_halt(conn);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen }
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen if (ret == 0 && pending_command != NULL &&
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen !smtp_command_parser_pending_data(conn->smtp_parser)) {
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen /* previous command is now fully read and ready to
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen reply */
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen smtp_server_command_ready_to_reply(pending_command);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen }
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen}
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenstatic void smtp_server_connection_input(struct connection *_conn)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen{
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen struct smtp_server_connection *conn =
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen (struct smtp_server_connection *)_conn;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
0fd246126fece57712566c725d6353f255f5fcfaTimo Sirainen i_assert(!conn->input_broken);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (conn->handling_input)
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen return;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen smtp_server_connection_timeout_reset(conn);
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if (conn->ssl_start && conn->ssl_iostream == NULL) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if (smtp_server_connection_ssl_init(conn) < 0) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen smtp_server_connection_close(&conn,
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen "SSL Initialization failed");
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen return;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen }
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen }
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if (conn->command_queue_count >
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen conn->server->set.max_pipelined_commands) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen smtp_server_connection_input_halt(conn);
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen return;
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen smtp_server_connection_ref(conn);
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen conn->handling_input = TRUE;
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen if (conn->callbacks != NULL &&
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen conn->callbacks->conn_cmd_input_pre != NULL) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->callbacks->conn_cmd_input_pre(conn->context);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen smtp_server_connection_handle_input(conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (conn->callbacks != NULL &&
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen conn->callbacks->conn_cmd_input_post != NULL) {
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen conn->callbacks->conn_cmd_input_post(conn->context);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->handling_input = FALSE;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_unref(&conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen}
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenbool smtp_server_connection_pending_command_data(
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen struct smtp_server_connection *conn)
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen{
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen return smtp_command_parser_pending_data(conn->smtp_parser);
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen}
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen/*
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen * Command reply handling
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen */
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenstatic bool
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainensmtp_server_connection_next_reply(struct smtp_server_connection *conn)
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen{
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen struct smtp_server_command *cmd;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen const char *error = NULL;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen unsigned int i;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen cmd = conn->command_queue_head;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (cmd == NULL) {
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen /* no commands pending */
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen smtp_server_connection_debug(conn,
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen "No more commands pending");
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return FALSE;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (cmd->state < SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_command_next_to_reply(cmd);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return FALSE;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen i_assert(cmd->state == SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY &&
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen smtp_server_command_is_replied(cmd));
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen smtp_server_command_completed(cmd);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen /* send command replies */
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen // FIXME: handle LMTP DATA command with enormous number of recipients;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen // i.e. don't keep filling output stream with replies indefinitely.
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen for (i = 0; i < cmd->replies_expected; i++) {
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen struct smtp_server_reply *reply;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (!array_is_created(&cmd->replies))
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen break;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen reply = array_idx_modifiable(&cmd->replies, i);
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (!reply->submitted) {
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen i_assert(!reply->sent);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen cmd->state = SMTP_SERVER_COMMAND_STATE_PROCESSING;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen break;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen }
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen if (smtp_server_reply_send(reply, &error) < 0) {
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen if (error != NULL) {
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen smtp_server_connection_error(conn,
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen "Failed to send reply: %s", error);
bc93929cdd9000ca560a5f42a27f50ab307f1efbTimo Sirainen smtp_server_connection_close(&conn,
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen "Write failure");
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen } else {
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen smtp_server_connection_debug(conn,
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen "Failed to send reply: "
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen "Remote disconnected");
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen smtp_server_connection_close(&conn,
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen "Remote closed connection");
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen }
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen return FALSE;
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen }
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainen }
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainen if (cmd->state == SMTP_SERVER_COMMAND_STATE_PROCESSING)
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainen return FALSE;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen smtp_server_command_finished(cmd);
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen return TRUE;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen}
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainen
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainenvoid smtp_server_connection_cork(struct smtp_server_connection *conn)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen{
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->corked = TRUE;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (conn->conn.output != NULL)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen o_stream_cork(conn->conn.output);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen}
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenvoid smtp_server_connection_uncork(struct smtp_server_connection *conn)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen{
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (conn->conn.output != NULL) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen o_stream_uncork(conn->conn.output);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_trigger_output(conn);
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->corked = FALSE;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen}
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainenstatic void
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainensmtp_server_connection_send_replies(struct smtp_server_connection *conn)
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen{
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen /* send more replies until no more replies remain, the output
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen blocks again, or the connection is closed */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen while (!conn->disconnected && smtp_server_connection_next_reply(conn));
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_timeout_update(conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* accept more commands if possible */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_input_resume(conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen}
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenint smtp_server_connection_flush(struct smtp_server_connection *conn)
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen{
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen struct ostream *output = conn->conn.output;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen int ret;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if ((ret = o_stream_flush(output)) <= 0) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if (ret < 0) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if (errno != EPIPE && errno != ECONNRESET) {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen smtp_server_connection_error(conn,
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen "Connection lost: write(%s) failed: %s",
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen o_stream_get_name(output),
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen o_stream_get_error(output));
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen smtp_server_connection_close(&conn,
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen "Write failure");
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen } else {
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen smtp_server_connection_debug(conn,
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainen "Connection lost: Remote disconnected");
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen smtp_server_connection_close(&conn,
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen "Remote closed connection unexpectedly");
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen return ret;
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainen }
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainen return 1;
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainen}
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic int
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainensmtp_server_connection_output(struct smtp_server_connection *conn)
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen{
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen int ret;
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_debug(conn,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen "Sending replies");
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_ref(conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen o_stream_cork(conn->conn.output);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if ((ret=smtp_server_connection_flush(conn)) > 0) {
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen smtp_server_connection_timeout_reset(conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_send_replies(conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen if (!conn->corked && conn->conn.output != NULL)
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen o_stream_uncork(conn->conn.output);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_unref(&conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen return ret;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen}
a1f517528af314cb6f5f39187a71dbed8a6e1152Timo Sirainen
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainenvoid smtp_server_connection_trigger_output(
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen struct smtp_server_connection *conn)
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainen{
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen if (conn->conn.output != NULL) {
a1f517528af314cb6f5f39187a71dbed8a6e1152Timo Sirainen smtp_server_connection_debug(conn,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen "Trigger output");
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen o_stream_set_flush_pending(conn->conn.output, TRUE);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen}
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen/*
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen *
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenstatic struct connection_settings smtp_server_connection_set = {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen .input_max_size = (size_t)-1,
4bffa20ff6fc61ba7b47375722e38be7f87dfe64Timo Sirainen .output_max_size = (size_t)-1,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen .client = FALSE
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen};
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainenstatic const struct connection_vfuncs smtp_server_connection_vfuncs = {
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen .destroy = smtp_server_connection_destroy,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen .input = smtp_server_connection_input
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen};
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainenstruct connection_list *
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainensmtp_server_connection_list_init(void)
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen{
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainen return connection_list_init(&smtp_server_connection_set,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen &smtp_server_connection_vfuncs);
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainenstatic struct smtp_server_connection * ATTR_NULL(5, 6)
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainensmtp_server_connection_alloc(struct smtp_server *server,
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen const struct smtp_server_settings *set, int fd_in, int fd_out,
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen const struct ip_addr *remote_ip, in_port_t remote_port,
c63c3c4d548416914b8c6734fe18dd69bb900775Timo Sirainen const struct smtp_server_callbacks *callbacks, void *context)
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainen{
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen static unsigned int id = 0;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen struct smtp_server_connection *conn;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen pool_t pool;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen pool = pool_alloconly_create("smtp server", 512);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn = p_new(pool, struct smtp_server_connection, 1);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->pool = pool;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->refcount = 1;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->id = id++;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->server = server;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->callbacks = callbacks;
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen conn->context = context;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* merge settings with global server settings */
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen conn->set = server->set;
94f90df2cfb7587bb5af432b2ba065d1c364e1f7Timo Sirainen if (set != NULL) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen conn->set.protocol = server->set.protocol;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (set->rawlog_dir != NULL && *set->rawlog_dir != '\0')
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->set.rawlog_dir = p_strdup(pool, set->rawlog_dir);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (set->hostname != NULL && *set->hostname != '\0')
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->set.hostname = p_strdup(pool, set->hostname);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (set->login_greeting != NULL &&
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen *set->login_greeting != '\0') {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->set.login_greeting =
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen p_strdup(pool, set->login_greeting);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (set->capabilities != 0)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->set.capabilities = set->capabilities;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (set->max_client_idle_time_msecs > 0) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->set.max_client_idle_time_msecs =
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen set->max_client_idle_time_msecs;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (set->max_pipelined_commands > 0) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->set.max_pipelined_commands =
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen set->max_pipelined_commands;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (set->max_bad_commands > 0) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->set.max_bad_commands = set->max_bad_commands;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen smtp_command_limits_merge(&conn->set.command_limits,
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen &set->command_limits);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen if (set->xclient_extensions != NULL) {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen server->set.xclient_extensions =
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen p_strarray_dup(pool, set->xclient_extensions);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (set->socket_send_buffer_size > 0) {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->set.socket_send_buffer_size =
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen set->socket_send_buffer_size;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen }
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen if (set->socket_recv_buffer_size > 0) {
f210ec6b25f80d06419921e9231465bb114ee971Timo Sirainen conn->set.socket_recv_buffer_size =
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen set->socket_recv_buffer_size;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->set.tls_required =
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->set.tls_required || set->tls_required;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->set.auth_optional =
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->set.auth_optional || set->auth_optional;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->set.rcpt_domain_optional =
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->set.rcpt_domain_optional ||
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen set->rcpt_domain_optional;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->set.param_extensions =
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen conn->set.param_extensions || set->param_extensions;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen conn->set.debug = conn->set.debug || set->debug;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen conn->remote_pid = (pid_t)-1;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen conn->remote_uid = (uid_t)-1;
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen if (remote_ip != NULL && remote_ip->family != 0) {
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen conn->remote_ip = *remote_ip;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->remote_port = remote_port;
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen conn->socket_family = conn->remote_ip.family;
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen } else if (fd_in != fd_out || net_getpeername(fd_in,
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen &conn->remote_ip, &conn->remote_port) < 0) {
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen /* tty connection probably */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen } else {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (conn->remote_ip.family == 0) {
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen struct net_unix_cred cred;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* unix */
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->socket_family = AF_UNIX;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (net_getunixcred(fd_in, &cred) >= 0) {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->remote_pid = cred.pid;
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen conn->remote_uid = cred.uid;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen } else {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen /* ip / ip6 */
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->socket_family = conn->remote_ip.family;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen net_set_nonblock(fd_in, TRUE);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (fd_in != fd_out)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen net_set_nonblock(fd_out, TRUE);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen (void)net_set_tcp_nodelay(fd_out, TRUE);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen set = &conn->set;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (set->socket_send_buffer_size > 0) {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (net_set_send_buffer_size(fd_out,
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen set->socket_send_buffer_size) < 0)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen i_error("net_set_send_buffer_size(%"PRIuSIZE_T") failed: %m",
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen set->socket_send_buffer_size);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen }
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (set->socket_recv_buffer_size > 0) {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen if (net_set_recv_buffer_size(fd_in,
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen set->socket_recv_buffer_size) < 0)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen i_error("net_set_recv_buffer_size(%"PRIuSIZE_T") failed: %m",
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen set->socket_recv_buffer_size);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen }
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen return conn;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen}
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainenstatic const char *
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainensmtp_server_connection_get_name(struct smtp_server_connection *conn)
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen{
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen const char *name;
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen /* get a name for this connection */
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen switch (conn->socket_family) {
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen case 0:
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen name = t_strdup_printf("[%u]", conn->id);
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen break;
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen case AF_UNIX:
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen if (conn->remote_uid == (uid_t)-1) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen name = t_strdup_printf("unix [%u]", conn->id);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } else if (conn->remote_pid == (pid_t)-1) {
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen name = t_strdup_printf("unix:uid=%u [%u]",
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen conn->remote_uid, conn->id);
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen } else {
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen name = t_strdup_printf("unix:pid=%u,uid=%u [%u]",
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->remote_pid, conn->remote_uid, conn->id);
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen }
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen break;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen case AF_INET6:
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen name = t_strdup_printf("[%s]:%u [%u]",
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen net_ip2addr(&conn->remote_ip), conn->remote_port, conn->id);
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen break;
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen case AF_INET:
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen name = t_strdup_printf("%s:%u [%u]",
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen net_ip2addr(&conn->remote_ip), conn->remote_port, conn->id);
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen break;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen default:
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen i_unreached();
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen }
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen return name;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen}
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainenstruct smtp_server_connection *
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainensmtp_server_connection_create(struct smtp_server *server,
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen int fd_in, int fd_out,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen const struct ip_addr *remote_ip, in_port_t remote_port,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen const struct smtp_server_settings *set,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen const struct smtp_server_callbacks *callbacks, void *context)
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen{
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen struct smtp_server_connection *conn;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen const char *name;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen conn = smtp_server_connection_alloc(server,
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen set, fd_in, fd_out, remote_ip, remote_port,
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen callbacks, context);
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen name = smtp_server_connection_get_name(conn);
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen connection_init_server(server->conn_list,
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen &conn->conn, name, fd_in, fd_out);
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* halt input until started */
14bb36cbb67b42e32105c3d843a8c974dc7ed436Timo Sirainen smtp_server_connection_input_halt(conn);
14bb36cbb67b42e32105c3d843a8c974dc7ed436Timo Sirainen
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen smtp_server_connection_debug(conn, "Connection created");
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen return conn;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen}
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainenstruct smtp_server_connection *
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainensmtp_server_connection_create_from_streams(struct smtp_server *server,
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen struct istream *input, struct ostream *output,
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen const struct ip_addr *remote_ip, in_port_t remote_port,
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen const struct smtp_server_settings *set,
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen const struct smtp_server_callbacks *callbacks, void *context)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen{
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen struct smtp_server_connection *conn;
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen const char *name;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen int fd_in, fd_out;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen fd_in = i_stream_get_fd(input);
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen fd_out = o_stream_get_fd(output);
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen i_assert(fd_in >= 0);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_assert(fd_out >= 0);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen conn = smtp_server_connection_alloc(server, set,
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen fd_in, fd_out, remote_ip, remote_port,
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen callbacks, context);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen name = smtp_server_connection_get_name(conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen connection_init_from_streams(server->conn_list,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen &conn->conn, name, input, output);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->created_from_streams = TRUE;
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* halt input until started */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_input_halt(conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen smtp_server_connection_debug(conn, "Connection created");
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen return conn;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen}
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainenvoid smtp_server_connection_ref(struct smtp_server_connection *conn)
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen{
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen conn->refcount++;
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen}
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainenstatic const char *
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainensmtp_server_connection_get_disconnect_reason(
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen struct smtp_server_connection *conn)
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen{
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen const char *err;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen if (conn->ssl_iostream != NULL &&
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen !ssl_iostream_is_handshaked(conn->ssl_iostream)) {
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen err = ssl_iostream_get_last_error(conn->ssl_iostream);
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen if (err != NULL) {
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen return t_strdup_printf(
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen "TLS handshaking failed: %s", err);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen }
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen return io_stream_get_disconnect_reason(conn->conn.input,
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->conn.output);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainenstatic void
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainensmtp_server_connection_disconnect(struct smtp_server_connection *conn,
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen const char *reason)
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen{
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen if (conn->disconnected)
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen return;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen conn->disconnected = TRUE;
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen if (reason == NULL)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen reason = smtp_server_connection_get_disconnect_reason(conn);
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen smtp_server_connection_debug(conn, "Disconnected: %s", reason);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen conn->disconnect_reason = i_strdup(reason);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen /* preserve statistics */
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_update_stats(conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen smtp_server_connection_timeout_stop(conn);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (conn->conn.output != NULL)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen o_stream_uncork(conn->conn.output);
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen if (conn->smtp_parser != NULL)
eb0ede66120bb63c0212bad69e67efca1eb47324Timo Sirainen smtp_command_parser_deinit(&conn->smtp_parser);
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen if (conn->ssl_iostream != NULL)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen ssl_iostream_destroy(&conn->ssl_iostream);
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen if (conn->callbacks != NULL &&
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen conn->callbacks->conn_disconnect != NULL) {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen conn->callbacks->conn_disconnect(conn->context,
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen reason);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
a1761856683b4bf745eb4e32cefabeb851efb301Timo Sirainen if (!conn->created_from_streams)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen connection_disconnect(&conn->conn);
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen else {
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen conn->conn.fd_in = conn->conn.fd_out = -1;
88dc563319efecd6e68bad16b0d92672da05584aTimo Sirainen io_remove(&conn->conn.io);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_stream_unref(&conn->conn.input);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen o_stream_unref(&conn->conn.output);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen}
fda168427e1950518acd6d600f1a10a29a5baef0Timo Sirainen
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainenbool smtp_server_connection_unref(struct smtp_server_connection **_conn)
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen{
85a4ae7e8df7ea45a7665828e5edf48a5fc85730Timo Sirainen struct smtp_server_connection *conn = *_conn;
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen struct smtp_server_command *cmd, *cmd_next;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
2793e3bd31d212d6506686aa70773e13d9d98195Timo Sirainen *_conn = NULL;
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_assert(conn->refcount > 0);
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen if (--conn->refcount > 0)
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen return TRUE;
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen smtp_server_connection_disconnect(conn, NULL);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen smtp_server_connection_debug(conn, "Connection destroy");
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* drop transaction */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen smtp_server_connection_reset_state(conn);
e726bf74fcc8d24f4c9d0d83217b3db4314d9d1fTimo Sirainen
/* clear command queue */
cmd = conn->command_queue_head;
while (cmd != NULL) {
cmd_next = cmd->next;
smtp_server_command_abort(&cmd);
cmd = cmd_next;
}
if (conn->callbacks != NULL &&
conn->callbacks->conn_destroy != NULL)
conn->callbacks->conn_destroy(conn->context);
connection_deinit(&conn->conn);
i_free(conn->helo_domain);
i_free(conn->helo_login);
i_free(conn->username);
i_free(conn->disconnect_reason);
pool_unref(&conn->pool);
return FALSE;
}
void smtp_server_connection_send_line(struct smtp_server_connection *conn,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
T_BEGIN {
string_t *str;
str = t_str_new(256);
str_vprintfa(str, fmt, args);
str_append(str, "\r\n");
o_stream_nsend(conn->conn.output, str_data(str), str_len(str));
} T_END;
va_end(args);
}
void smtp_server_connection_reply_immediate(
struct smtp_server_connection *conn,
unsigned int status, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
T_BEGIN {
string_t *str;
str = t_str_new(256);
str_printfa(str, "%03u ", status);
str_vprintfa(str, fmt, args);
str_append(str, "\r\n");
o_stream_nsend(conn->conn.output, str_data(str), str_len(str));
} T_END;
va_end(args);
/* send immediately */
if (o_stream_is_corked(conn->conn.output)) {
o_stream_uncork(conn->conn.output);
o_stream_cork(conn->conn.output);
}
}
void smtp_server_connection_start(struct smtp_server_connection *conn,
bool ssl_start)
{
conn->raw_input = conn->conn.input;
conn->raw_output = conn->conn.output;
smtp_server_connection_timeout_start(conn);
smtp_server_connection_input_resume(conn);
conn->ssl_start = ssl_start;
if (ssl_start)
conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
else
smtp_server_connection_ready(conn);
}
void smtp_server_connection_login(struct smtp_server_connection *conn,
const char *username, const char *helo,
const unsigned char *pdata, unsigned int pdata_len,
bool ssl_secured)
{
conn->raw_input = conn->conn.input;
conn->raw_output = conn->conn.output;
smtp_server_connection_timeout_start(conn);
smtp_server_connection_input_resume(conn);
i_assert(conn->username == NULL);
conn->set.capabilities &= ~SMTP_CAPABILITY_STARTTLS;
conn->username = i_strdup(username);
conn->helo_login = i_strdup(helo);
conn->authenticated = TRUE;
conn->ssl_secured = ssl_secured;
if (pdata_len > 0) {
if (!i_stream_add_data(conn->conn.input, pdata, pdata_len))
i_panic("Couldn't add client input to stream");
}
smtp_server_connection_ready(conn);
}
void smtp_server_connection_close(struct smtp_server_connection **_conn,
const char *reason)
{
struct smtp_server_connection *conn = *_conn;
*_conn = NULL;
if (conn->closed)
return;
conn->closed = TRUE;
smtp_server_connection_disconnect(conn, reason);
smtp_server_connection_unref(&conn);
}
void smtp_server_connection_terminate(struct smtp_server_connection **_conn,
const char *enh_code, const char *reason)
{
struct smtp_server_connection *conn = *_conn;
*_conn = NULL;
if (conn->closed)
return;
i_assert(enh_code[0] == '4' && enh_code[1] == '.');
smtp_server_connection_send_line(conn,
"421 %s %s %s", enh_code, conn->set.hostname, reason);
smtp_server_connection_close(&conn, reason);
}
struct smtp_server_helo_data *
smtp_server_connection_get_helo_data(struct smtp_server_connection *conn)
{
return &conn->helo;
}
enum smtp_server_state
smtp_server_connection_get_state(struct smtp_server_connection *conn)
{
return conn->state.state;
}
void smtp_server_connection_set_state(struct smtp_server_connection *conn,
enum smtp_server_state state)
{
if (conn->state.state != state) {
conn->state.state = state;
if (conn->callbacks != NULL &&
conn->callbacks->conn_state_changed != NULL) {
conn->callbacks->conn_state_changed(conn->context, state);
}
}
}
const char *
smtp_server_connection_get_security_string(struct smtp_server_connection *conn)
{
if (conn->ssl_iostream == NULL)
return NULL;
return ssl_iostream_get_security_string(conn->ssl_iostream);
}
void smtp_server_connection_reset_state(struct smtp_server_connection *conn)
{
smtp_server_connection_debug(conn, "Connection state reset");
if (conn->state.trans != NULL) {
if (conn->callbacks != NULL &&
conn->callbacks->conn_trans_free != NULL) {
conn->callbacks->conn_trans_free(conn->context,
conn->state.trans);
}
smtp_server_transaction_free(&conn->state.trans);
}
/* RFC 3030, Section 2:
The RSET command, when issued after the first BDAT and before the
BDAT LAST, clears all segments sent during that transaction and resets
the session.
*/
if (conn->state.data_input != NULL)
i_stream_destroy(&conn->state.data_input);
conn->state.data_chain = NULL;
/* reset state */
i_zero(&conn->state);
smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_READY);
}
void smtp_server_connection_clear(struct smtp_server_connection *conn)
{
smtp_server_connection_debug(conn, "Connection clear");
i_free(conn->helo_domain);
i_free(conn->helo_login);
i_zero(&conn->helo);
smtp_server_connection_reset_state(conn);
}
void smtp_server_connection_set_capabilities(
struct smtp_server_connection *conn, enum smtp_capability capabilities)
{
conn->set.capabilities = capabilities;
}
void *smtp_server_connection_get_context(struct smtp_server_connection *conn)
{
return conn->context;
}
bool smtp_server_connection_is_ssl_secured(struct smtp_server_connection *conn)
{
return conn->ssl_secured;
}
bool smtp_server_connection_is_trusted(struct smtp_server_connection *conn)
{
if (conn->callbacks == NULL || conn->callbacks->conn_is_trusted == NULL)
return FALSE;
return conn->callbacks->conn_is_trusted(conn->context);
}
enum smtp_protocol
smtp_server_connection_get_protocol(struct smtp_server_connection *conn)
{
return conn->set.protocol;
}
const char *
smtp_server_connection_get_protocol_name(struct smtp_server_connection *conn)
{
string_t *pname = t_str_new(16);
switch (conn->set.protocol) {
case SMTP_PROTOCOL_SMTP:
if (conn->helo.old_smtp)
str_append(pname, "SMTP");
else
str_append(pname, "ESMTP");
break;
case SMTP_PROTOCOL_LMTP:
str_append(pname, "LMTP");
break;
default:
i_unreached();
}
if (conn->ssl_secured)
str_append_c(pname, 'S');
if (conn->authenticated)
str_append_c(pname, 'A');
return str_c(pname);
}
struct smtp_server_transaction *
smtp_server_connection_get_transaction(struct smtp_server_connection *conn)
{
return conn->state.trans;
}
const char *
smtp_server_connection_get_transaction_id(struct smtp_server_connection *conn)
{
if (conn->state.trans == NULL)
return NULL;
return conn->state.trans->id;
}
void smtp_server_connection_get_proxy_data(struct smtp_server_connection *conn,
struct smtp_proxy_data *proxy_data)
{
i_zero(proxy_data);
proxy_data->source_ip = conn->remote_ip;
proxy_data->source_port = conn->remote_port;
if (conn->helo.domain_valid)
proxy_data->helo = conn->helo.domain;
proxy_data->login = conn->username;
if (conn->proxy_proto != SMTP_PROXY_PROTOCOL_UNKNOWN)
proxy_data->proto = conn->proxy_proto;
else if (conn->set.protocol == SMTP_PROTOCOL_LMTP)
proxy_data->proto = SMTP_PROXY_PROTOCOL_LMTP;
else if (conn->helo.old_smtp)
proxy_data->proto = SMTP_PROXY_PROTOCOL_SMTP;
else
proxy_data->proto = SMTP_PROXY_PROTOCOL_ESMTP;
proxy_data->ttl_plus_1 = conn->proxy_ttl_plus_1;
proxy_data->timeout_secs = conn->proxy_timeout_secs;
}
void smtp_server_connection_set_proxy_data(struct smtp_server_connection *conn,
const struct smtp_proxy_data *proxy_data)
{
if (proxy_data->source_ip.family != 0)
conn->remote_ip = proxy_data->source_ip;
if (proxy_data->source_port != 0)
conn->remote_port = proxy_data->source_port;
if (proxy_data->helo != NULL) {
i_free(conn->helo_domain);
conn->helo_domain = i_strdup(proxy_data->helo);
conn->helo.domain = conn->helo_domain;
conn->helo.domain_valid = TRUE;
}
if (proxy_data->login != NULL) {
i_free(conn->username);
conn->username = i_strdup(proxy_data->login);
}
if (proxy_data->proto != SMTP_PROXY_PROTOCOL_UNKNOWN)
conn->proxy_proto = proxy_data->proto;
if (proxy_data->ttl_plus_1 > 0)
conn->proxy_ttl_plus_1 = proxy_data->ttl_plus_1;
if (conn->proxy_timeout_secs > 0)
conn->proxy_timeout_secs = proxy_data->timeout_secs;
if (conn->callbacks != NULL &&
conn->callbacks->conn_proxy_data_updated != NULL)
conn->callbacks->conn_proxy_data_updated(conn, proxy_data);
}
void smtp_server_connection_switch_ioloop(struct smtp_server_connection *conn)
{
if (conn->to_idle != NULL)
conn->to_idle = io_loop_move_timeout(&conn->to_idle);
connection_switch_ioloop(&conn->conn);
}