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;
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 &&
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);
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);
"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");
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;
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);
#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 | \
struct istream *data_input, *data_chain_input;
struct istream_chain *data_chain;
unsigned int data_chunks;
+ uoff_t data_size;
bool data_failed:1;
};
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 =
/* 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;
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
*/