Skip to content

Commit

Permalink
lib-smtp: server: Added max_recipients setting, which enforces a reci…
Browse files Browse the repository at this point in the history
…pient limit per-transaction.
  • Loading branch information
stephanbosch authored and sirainen committed Dec 11, 2017
1 parent 6d76b99 commit 4dd460c
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 2 deletions.
11 changes: 9 additions & 2 deletions src/lib-smtp/smtp-server-cmd-rcpt.c
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib-smtp/smtp-server-connection.c
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions src/lib-smtp/smtp-server.c
Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions src/lib-smtp/smtp-server.h
Expand Up @@ -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;

Expand Down
104 changes: 104 additions & 0 deletions src/lib-smtp/test-smtp-server-errors.c
Expand Up @@ -2,6 +2,7 @@

#include "lib.h"
#include "str.h"
#include "array.h"
#include "hostpid.h"
#include "ioloop.h"
#include "istream.h"
Expand Down Expand Up @@ -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
*/
Expand All @@ -918,6 +1021,7 @@ static void (*const test_functions[])(void) = {
test_long_command,
test_big_data,
test_bad_ehlo,
test_too_many_recipients,
NULL
};

Expand Down

0 comments on commit 4dd460c

Please sign in to comment.