Skip to content

Commit

Permalink
lib-smtp: server: Implement enforcement of maximum message size.
Browse files Browse the repository at this point in the history
  • Loading branch information
stephanbosch authored and cmouse committed May 12, 2018
1 parent 356f78b commit d006a41
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 4 deletions.
46 changes: 45 additions & 1 deletion src/lib-smtp/smtp-server-cmd-data.c
Expand Up @@ -21,6 +21,33 @@ struct cmd_data_context {
bool chunk_last:1;
};

static void
smtp_server_cmd_data_size_limit_exceeded(struct smtp_server_cmd_ctx *cmd)
{
struct smtp_server_command *command = cmd->cmd;

smtp_server_command_fail(command, 552, "5.2.3",
"Message size exceeds administrative limit");
}

bool smtp_server_cmd_data_check_size(struct smtp_server_cmd_ctx *cmd)
{
struct smtp_server_connection *conn = cmd->conn;
const struct smtp_server_settings *set = &conn->set;

i_assert(conn->state.state == SMTP_SERVER_STATE_DATA);

if (conn->state.data_input == NULL)
return TRUE;
if (set->max_message_size == 0)
return TRUE;
if (conn->state.data_input->v_offset <= set->max_message_size)
return TRUE;

smtp_server_cmd_data_size_limit_exceeded(cmd);
return FALSE;
}

bool smtp_server_connection_data_check_state(struct smtp_server_cmd_ctx *cmd)
{
struct smtp_server_connection *conn = cmd->conn;
Expand Down Expand Up @@ -213,14 +240,20 @@ static int cmd_data_handle_input(struct smtp_server_cmd_ctx *cmd)

i_assert(data_cmd != NULL);

if (!smtp_server_cmd_data_check_size(cmd))
return -1;

/* continue reading from client */
smtp_server_command_ref(command);
i_assert(callbacks != NULL &&
callbacks->conn_cmd_data_continue != NULL);
ret = callbacks->conn_cmd_data_continue(conn->context,
cmd, conn->state.trans);
if (ret >= 0) {
if (!i_stream_have_bytes_left(conn->state.data_input)) {
if (!smtp_server_cmd_data_check_size(cmd)) {
smtp_server_command_unref(&command);
return -1;
} else if (!i_stream_have_bytes_left(conn->state.data_input)) {
smtp_server_command_debug(cmd,
"End of data");
smtp_server_command_input_lock(cmd);
Expand Down Expand Up @@ -451,16 +484,27 @@ int smtp_server_connection_data_chunk_add(struct smtp_server_cmd_ctx *cmd,
bool client_input)
{
struct smtp_server_connection *conn = cmd->conn;
const struct smtp_server_settings *set = &conn->set;
struct smtp_server_command *command = cmd->cmd;
struct cmd_data_context *data_cmd =
(struct cmd_data_context *)command->data;
struct istream *input;
uoff_t new_size;

i_assert(data_cmd != NULL);

if (!smtp_server_connection_data_check_state(cmd))
return -1;

/* check message size increase early */
new_size = conn->state.data_size + chunk_size;
if (new_size < conn->state.data_size ||
(set->max_message_size > 0 && new_size > set->max_message_size)) {
smtp_server_cmd_data_size_limit_exceeded(cmd);
return -1;
}
conn->state.data_size = new_size;

command->hook_replied = (chunk_last ?
cmd_data_replied : cmd_data_chunk_replied);

Expand Down
9 changes: 9 additions & 0 deletions src/lib-smtp/smtp-server-cmd-helo.c
Expand Up @@ -122,6 +122,15 @@ smtp_server_cmd_helo_run(struct smtp_server_cmd_ctx *cmd, const char *params,
"ENHANCEDSTATUSCODES");
}
smtp_server_reply_ehlo_add(reply, "PIPELINING");
if ((caps & SMTP_CAPABILITY_SIZE) != 0) {
uoff_t cap_size = conn->set.max_message_size;
if (cap_size > 0 && cap_size != (uoff_t)-1) {
smtp_server_reply_ehlo_add_param(reply,
"SIZE", "%"PRIuUOFF_T, cap_size);
} else {
smtp_server_reply_ehlo_add(reply, "SIZE");
}
}
if ((caps & SMTP_CAPABILITY_STARTTLS) != 0)
smtp_server_reply_ehlo_add(reply, "STARTTLS");
smtp_server_reply_ehlo_add(reply, "VRFY");
Expand Down
7 changes: 7 additions & 0 deletions src/lib-smtp/smtp-server-cmd-mail.c
Expand Up @@ -151,6 +151,13 @@ void smtp_server_cmd_mail(struct smtp_server_cmd_ctx *cmd,
return;
}

if ((caps & SMTP_CAPABILITY_SIZE) != 0 && set->max_message_size > 0 &&
mail_data->params.size > set->max_message_size) {
smtp_server_reply(cmd, 552, "5.2.3",
"Message size exceeds administrative limit");
return;
}

mail_data->path = smtp_address_clone(cmd->pool, path);
mail_data->timestamp = ioloop_timeval;

Expand Down
18 changes: 18 additions & 0 deletions src/lib-smtp/smtp-server-connection.c
Expand Up @@ -812,6 +812,24 @@ smtp_server_connection_alloc(struct smtp_server *server,
smtp_command_limits_merge(&conn->set.command_limits,
&set->command_limits);

conn->set.max_message_size = set->max_message_size;
if (set->max_message_size == 0 ||
set->max_message_size == (uoff_t)-1) {
conn->set.command_limits.max_data_size = UOFF_T_MAX;
} else if (conn->set.command_limits.max_data_size != 0) {
/* explicit limit given */
} else if (set->max_message_size >
(UOFF_T_MAX - SMTP_SERVER_DEFAULT_MAX_SIZE_EXCESS_LIMIT)) {
/* very high limit */
conn->set.command_limits.max_data_size = UOFF_T_MAX;
} else {
/* absolute maximum before connection is closed in DATA
command */
conn->set.command_limits.max_data_size =
set->max_message_size +
SMTP_SERVER_DEFAULT_MAX_SIZE_EXCESS_LIMIT;
}

if (set->xclient_extensions != NULL) {
server->set.xclient_extensions =
p_strarray_dup(pool, set->xclient_extensions);
Expand Down
8 changes: 5 additions & 3 deletions src/lib-smtp/smtp-server-private.h
Expand Up @@ -5,10 +5,11 @@

#include "smtp-server.h"

#define SMTP_SERVER_COMMAND_POOL_MAX (8 * 1024)
#define SMTP_SERVER_COMMAND_POOL_MAX (8 * 1024)

#define SMTP_SERVER_DEFAULT_MAX_COMMAND_LINE (4 * 1024)
#define SMTP_SERVER_DEFAULT_MAX_BAD_COMMANDS 10
#define SMTP_SERVER_DEFAULT_MAX_COMMAND_LINE (4 * 1024)
#define SMTP_SERVER_DEFAULT_MAX_BAD_COMMANDS 10
#define SMTP_SERVER_DEFAULT_MAX_SIZE_EXCESS_LIMIT (1024*1024)

#define SMTP_SERVER_DEFAULT_CAPABILITIES \
(SMTP_CAPABILITY_SIZE | SMTP_CAPABILITY_ENHANCEDSTATUSCODES | \
Expand Down Expand Up @@ -110,6 +111,7 @@ struct smtp_server_state_data {
struct istream *data_input, *data_chain_input;
struct istream_chain *data_chain;
unsigned int data_chunks;
uoff_t data_size;

bool data_failed:1;
};
Expand Down
1 change: 1 addition & 0 deletions src/lib-smtp/smtp-server.c
Expand Up @@ -51,6 +51,7 @@ struct smtp_server *smtp_server_init(const struct smtp_server_settings *set)
set->max_bad_commands : SMTP_SERVER_DEFAULT_MAX_BAD_COMMANDS);
server->set.max_recipients = set->max_recipients;
server->set.command_limits = set->command_limits;
server->set.max_message_size = set->max_message_size;

if (set->xclient_extensions != NULL) {
server->set.xclient_extensions =
Expand Down
7 changes: 7 additions & 0 deletions src/lib-smtp/smtp-server.h
Expand Up @@ -258,6 +258,9 @@ struct smtp_server_settings {
/* command limits */
struct smtp_command_limits command_limits;

/* message size limit */
uoff_t max_message_size;

/* accept these additional custom XCLIENT fields */
const char *const *xclient_extensions;

Expand Down Expand Up @@ -454,6 +457,10 @@ void smtp_server_cmd_auth_success(struct smtp_server_cmd_ctx *cmd,
const char *username, const char *success_msg)
ATTR_NULL(3);

/* DATA */

bool smtp_server_cmd_data_check_size(struct smtp_server_cmd_ctx *cmd);

/*
* Reply
*/
Expand Down

0 comments on commit d006a41

Please sign in to comment.