]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-smtp: server: Added max_recipients setting, which enforces a recipient limit...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sun, 10 Dec 2017 10:28:44 +0000 (11:28 +0100)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 11 Dec 2017 13:44:18 +0000 (15:44 +0200)
src/lib-smtp/smtp-server-cmd-rcpt.c
src/lib-smtp/smtp-server-connection.c
src/lib-smtp/smtp-server.c
src/lib-smtp/smtp-server.h
src/lib-smtp/test-smtp-server-errors.c

index 0bbca247f6f5d822c012a30366a8a4da1bc47aa4..0fefa59d3634b1ece953a9d1856d5072eaac6e07 100644 (file)
@@ -17,9 +17,9 @@ cmd_rcpt_check_state(struct smtp_server_cmd_ctx *cmd)
 {
        struct smtp_server_connection *conn = cmd->conn;
        struct smtp_server_command *command = cmd->cmd;
+       struct smtp_server_transaction *trans = conn->state.trans;
 
-       if (conn->state.pending_mail_cmds == 0 &&
-               conn->state.trans == NULL) {
+       if (conn->state.pending_mail_cmds == 0 && trans == NULL) {
                if (command->hook_replied != NULL) {
                        conn->state.pending_rcpt_cmds--;
                        command->hook_replied = NULL;
@@ -28,6 +28,13 @@ cmd_rcpt_check_state(struct smtp_server_cmd_ctx *cmd)
                        503, "5.5.0", "MAIL needed first");
                return FALSE;
        }
+       if (conn->set.max_recipients > 0 && trans != NULL &&
+               smtp_server_transaction_rcpt_count(trans) >=
+                       conn->set.max_recipients) {
+               smtp_server_reply(cmd,
+                       451, "4.5.3", "Too many recipients");
+               return FALSE;
+       }
 
        return TRUE;
 }
index 9dcf36b3731853d75d0aa787b54afde885cd1d6f..c78e89fd63dcbfcad43b75ea24080a83c4bcdfe4 100644 (file)
@@ -802,6 +802,8 @@ smtp_server_connection_alloc(struct smtp_server *server,
                if (set->max_bad_commands > 0) {
                        conn->set.max_bad_commands = set->max_bad_commands;
                }
+               if (set->max_recipients > 0)
+                       conn->set.max_recipients = set->max_recipients;
                smtp_command_limits_merge(&conn->set.command_limits,
                                          &set->command_limits);
 
index 30fadd8f43e03441b2f0c32165ca57224a19e88b..bc68c9a9e9f7543d3ad0da0d243852c8c57740d7 100644 (file)
@@ -48,6 +48,7 @@ struct smtp_server *smtp_server_init(const struct smtp_server_settings *set)
                set->max_pipelined_commands : 1);
        server->set.max_bad_commands = (set->max_bad_commands > 0 ?
                set->max_bad_commands : SMTP_SERVER_DEFAULT_MAX_BAD_COMMANDS);
+       server->set.max_recipients = set->max_recipients;
        server->set.command_limits = set->command_limits;
 
        if (set->xclient_extensions != NULL) {
index 4d9aca836dc63cd22d741a7aa05341061c9ab923..898586224ab322dbbcbaf4531a677e17f29c6887 100644 (file)
@@ -240,6 +240,10 @@ struct smtp_server_settings {
        /* maximum number of sequential bad commands */
        unsigned int max_bad_commands;
 
+       /* maximum number of recipients in a transaction
+          (0 means unlimited, which is the default) */
+       unsigned int max_recipients;
+
        /* command limits */
        struct smtp_command_limits command_limits;
 
index dbe7dbc5ebb2670974b785f7d72f886b0e432b9b..98f21890dbe8f46b62db8ceec65278b07129016e 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "str.h"
+#include "array.h"
 #include "hostpid.h"
 #include "ioloop.h"
 #include "istream.h"
@@ -906,6 +907,108 @@ static void test_bad_ehlo(void)
        test_end();
 }
 
+/*
+ * Too many recipients
+ */
+
+/* client */
+
+static void
+test_too_many_recipients_connected(struct client_connection *conn)
+{
+       (void)o_stream_send_str(conn->conn.output,
+               "EHLO frop\r\n"
+               "MAIL FROM:<sender@example.com>\r\n"
+               "RCPT TO:<recipient1@example.com>\r\n"
+               "RCPT TO:<recipient2@example.com>\r\n"
+               "RCPT TO:<recipient3@example.com>\r\n"
+               "RCPT TO:<recipient4@example.com>\r\n"
+               "RCPT TO:<recipient5@example.com>\r\n"
+               "RCPT TO:<recipient6@example.com>\r\n"
+               "RCPT TO:<recipient7@example.com>\r\n"
+               "RCPT TO:<recipient8@example.com>\r\n"
+               "RCPT TO:<recipient9@example.com>\r\n"
+               "RCPT TO:<recipient10@example.com>\r\n"
+               "RCPT TO:<recipient11@example.com>\r\n"
+               "DATA\r\n"
+               "0123456789ABCDEF0123456789ABCDEF\r\n"
+               "0123456789ABCDEF0123456789ABCDEF\r\n"
+               "0123456789ABCDEF0123456789ABCDEF\r\n"
+               "0123456789ABCDEF0123456789ABCDEF\r\n"
+               "0123456789ABCDEF0123456789ABCDEF\r\n"
+               "0123456789ABCDEF0123456789ABCDEF\r\n"
+               "0123456789ABCDEF0123456789ABCDEF\r\n"
+               ".\r\n");
+}
+
+static void test_client_too_many_recipients(unsigned int index)
+{
+       test_client_connected = test_too_many_recipients_connected;
+       test_client_run(index);
+}
+
+/* server */
+
+static void
+test_server_too_many_recipients_trans_free(void *conn_ctx  ATTR_UNUSED,
+       struct smtp_server_transaction *trans ATTR_UNUSED)
+{
+       io_loop_stop(ioloop);
+}
+
+static int
+test_server_too_many_recipients_rcpt(void *conn_ctx ATTR_UNUSED,
+       struct smtp_server_cmd_ctx *cmd ATTR_UNUSED,
+       struct smtp_server_cmd_rcpt *data)
+{
+       if (debug) {
+               i_debug("RCPT TO:%s",
+                       smtp_address_encode(data->path));
+       }
+       return 1;
+}
+
+static int
+test_server_too_many_recipients_data_begin(void *conn_ctx ATTR_UNUSED,
+       struct smtp_server_cmd_ctx *cmd,
+       struct smtp_server_transaction *trans,
+       struct istream *data_input ATTR_UNUSED)
+{
+       test_assert(array_count(&trans->rcpt_to) == 10);
+
+       smtp_server_reply(cmd, 250, "2.0.0", "OK");
+       return 1;
+}
+
+static void test_server_too_many_recipients
+(const struct smtp_server_settings *server_set)
+{
+       server_callbacks.conn_trans_free =
+               test_server_too_many_recipients_trans_free;
+       server_callbacks.conn_cmd_rcpt =
+               test_server_too_many_recipients_rcpt;
+       server_callbacks.conn_cmd_data_begin =
+               test_server_too_many_recipients_data_begin;
+       test_server_run(server_set);
+}
+
+/* test */
+
+static void test_too_many_recipients(void)
+{
+       struct smtp_server_settings smtp_server_set;
+
+       test_server_defaults(&smtp_server_set);
+       smtp_server_set.max_client_idle_time_msecs = 1000;
+       smtp_server_set.max_recipients = 10;
+
+       test_begin("too many recipients");
+       test_run_client_server(&smtp_server_set,
+               test_server_too_many_recipients,
+               test_client_too_many_recipients, 1);
+       test_end();
+}
+
 /*
  * All tests
  */
@@ -918,6 +1021,7 @@ static void (*const test_functions[])(void) = {
        test_long_command,
        test_big_data,
        test_bad_ehlo,
+       test_too_many_recipients,
        NULL
 };