#define MAX_OUTBUF_SIZE 1024
-/* max. number of IMAP argument elements to accept. The maximum memory usage
- for command from user is around MAX_INBUF_SIZE * MAX_IMAP_ARG_ELEMENTS */
-#define MAX_IMAP_ARG_ELEMENTS 4
+/* maximum length for IMAP command line. */
+#define MAX_IMAP_LINE 8192
/* Disconnect client after idling this many seconds */
#define CLIENT_LOGIN_IDLE_TIMEOUT 60
client->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE,
FALSE);
client->parser = imap_parser_create(client->input, client->output,
- MAX_INBUF_SIZE,
- MAX_IMAP_ARG_ELEMENTS);
+ MAX_IMAP_LINE);
}
/* Skip incoming data until newline is found,
#include <stdlib.h>
-/* max. size of one parameter in line */
-#define MAX_INBUF_SIZE 8192
-
/* If we can't send a buffer in a minute, disconnect the client */
#define CLIENT_OUTPUT_TIMEOUT (60*1000)
client = i_new(struct client, 1);
client->input = i_stream_create_file(hin, default_pool,
- MAX_INBUF_SIZE, FALSE);
+ imap_max_line_length, FALSE);
client->output = o_stream_create_file(hout, default_pool, 4096, FALSE);
/* set timeout for reading expected data (eg. APPEND). This is
client->io = io_add(hin, IO_READ, _client_input, client);
client->parser = imap_parser_create(client->input, client->output,
- MAX_INBUF_SIZE,
- MAX_IMAP_ARG_ELEMENTS);
+ imap_max_line_length);
client->last_input = ioloop_time;
client->mailbox_flags.pool =
count = 0;
failed = TRUE;
save_parser = imap_parser_create(client->input, client->output,
- 0, MAX_IMAP_ARG_ELEMENTS);
+ imap_max_line_length);
for (;;) {
/* [<flags>] [<internal date>] <message literal> */
#include "lib.h"
#include "client.h"
-/* max. number of IMAP argument elements to accept. The maximum memory usage
- for command from user is around MAX_INBUF_SIZE * MAX_IMAP_ARG_ELEMENTS */
-#define MAX_IMAP_ARG_ELEMENTS 128
-
/* Disconnect client after idling this many seconds */
#define CLIENT_IDLE_TIMEOUT (60*30)
+/* RFC-2683 recommends at least 8000 bytes. Some clients however don't
+ break large message sets to multiple commands, so we're pretty liberal
+ by default. */
+#define DEFAULT_IMAP_MAX_LINE_LENGTH 65536
+
#define DEFAULT_MAX_CUSTOM_FLAG_LENGTH 50
extern struct ioloop *ioloop;
extern unsigned int max_custom_flag_length, mailbox_check_interval;
+extern unsigned int imap_max_line_length;
extern string_t *capability_string;
struct ioloop *ioloop;
unsigned int max_custom_flag_length, mailbox_check_interval;
+unsigned int imap_max_line_length;
static struct module *modules;
static char log_prefix[128]; /* syslog() needs this to be permanent */
}
}
+ str = getenv("IMAP_MAX_LINE_LENGTH");
+ imap_max_line_length = str != NULL ?
+ (unsigned int)strtoul(str, NULL, 10) :
+ DEFAULT_IMAP_MAX_LINE_LENGTH;
+
str = getenv("MAIL_MAX_FLAG_LENGTH");
max_custom_flag_length = str != NULL ?
(unsigned int)strtoul(str, NULL, 10) :
input = i_stream_create_from_data(data_stack_pool, bodystructure, len);
(void)i_stream_read(input);
- parser = imap_parser_create(input, NULL, 0, (size_t)-1);
+ parser = imap_parser_create(input, NULL, (size_t)-1);
ret = imap_parser_read_args(parser, 0, IMAP_PARSE_FLAG_NO_UNESCAPE |
IMAP_PARSE_FLAG_LITERAL_TYPE, &args);
input = i_stream_create_from_data(data_stack_pool, envelope,
strlen(envelope));
- parser = imap_parser_create(input, NULL, (size_t)-1, (size_t)-1);
+ parser = imap_parser_create(input, NULL, (size_t)-1);
(void)i_stream_read(input);
ret = imap_parser_read_args(parser, field+1, 0, &args);
pool_t pool;
struct istream *input;
struct ostream *output;
- size_t max_literal_size, max_elements;
+ size_t max_line_size;
enum imap_parser_flags flags;
/* reset by imap_parser_reset(): */
- struct imap_arg_list *root_list;
+ size_t line_size;
+ struct imap_arg_list *root_list;
struct imap_arg_list *cur_list;
struct imap_arg *list_arg;
size_t element_count;
struct imap_parser *
imap_parser_create(struct istream *input, struct ostream *output,
- size_t max_literal_size, size_t max_elements)
+ size_t max_line_size)
{
struct imap_parser *parser;
parser->pool = pool_alloconly_create("IMAP parser", 8192);
parser->input = input;
parser->output = output;
- parser->max_literal_size = max_literal_size;
- parser->max_elements = max_elements;
+ parser->max_line_size = max_line_size;
imap_args_realloc(parser, LIST_ALLOC_SIZE);
return parser;
{
p_clear(parser->pool);
+ parser->line_size = 0;
+
parser->root_list = NULL;
parser->cur_list = NULL;
parser->list_arg = NULL;
break;
}
+ parser->line_size += i;
i_stream_skip(parser->input, i);
parser->cur_pos = 0;
static int imap_parser_literal_end(struct imap_parser *parser)
{
if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) == 0) {
- if (parser->literal_size > parser->max_literal_size) {
+ if (parser->line_size >= parser->max_line_size ||
+ parser->literal_size >
+ parser->max_line_size - parser->line_size) {
/* too long string, abort. */
parser->error = "Literal size too large";
parser->fatal_error = TRUE;
/* expecting digits + "}" */
for (i = parser->cur_pos; i < data_size; i++) {
if (data[i] == '}') {
+ parser->line_size += i+1;
i_stream_skip(parser->input, i+1);
return imap_parser_literal_end(parser);
}
return FALSE;
if (*data == '\r') {
+ parser->line_size++;
data++; data_size--;
i_stream_skip(parser->input, 1);
return FALSE;
}
+ parser->line_size++;
data++; data_size--;
i_stream_skip(parser->input, 1);
+
parser->literal_skip_crlf = FALSE;
i_assert(parser->cur_pos == 0);
if (!imap_parser_read_arg(parser))
break;
- if (parser->element_count > parser->max_elements) {
- parser->error = "Too many argument elements";
+ if (parser->line_size > parser->max_line_size) {
+ parser->error = "IMAP command line too large";
break;
}
}
if (parser->error != NULL) {
/* error, abort */
+ parser->line_size += parser->cur_pos;
i_stream_skip(parser->input, parser->cur_pos);
parser->cur_pos = 0;
*args = NULL;
} else if ((!IS_UNFINISHED(parser) && count > 0 &&
parser->root_list->size >= count) || parser->eol) {
/* all arguments read / end of line. */
+ parser->line_size += parser->cur_pos;
i_stream_skip(parser->input, parser->cur_pos);
parser->cur_pos = 0;
}
if (i < data_size) {
- i_stream_skip(parser->input, i + (data[i] == ' ' ? 1 : 0));
- return p_strndup(parser->pool, data, i);
- } else {
- return NULL;
- }
-}
-
-const char *imap_parser_read_line(struct imap_parser *parser)
-{
- const unsigned char *data;
- size_t i, data_size;
-
- data = i_stream_get_data(parser->input, &data_size);
-
- for (i = 0; i < data_size; i++) {
- if (data[i] == '\r' || data[i] == '\n')
- break;
- }
-
- if (i < data_size) {
- i_stream_skip(parser->input, i);
+ data_size = i + (data[i] == ' ' ? 1 : 0);
+ parser->line_size += data_size;
+ i_stream_skip(parser->input, data_size);
return p_strndup(parser->pool, data, i);
} else {
return NULL;
struct imap_arg args[1]; /* variable size */
};
-/* Create new IMAP argument parser. There's no limit in argument sizes, only
- the maximum buffer size of input stream limits it. max_literal_size limits
- the maximum size of internally handled literals (ie. FLAG_LITERAL_SIZE is
- unset). max_elements sets the number of elements we allow entirely so that
- user can't give huge lists or lists inside lists. output is used for sending
- command continuation requests for literals. */
+/* Create new IMAP argument parser. output is used for sending command
+ continuation requests for literals.
+
+ max_line_size can be used to approximately limit the maximum amount of
+ memory that gets allocated when parsing a line. Input buffer size limits
+ the maximum size of each parsed token.
+
+ Usually the largest lines are large only because they have a one huge
+ message set token, so you'll probably want to keep input buffer size the
+ same as max_line_size. That means the maximum memory usage is around
+ 2 * max_line_size. */
struct imap_parser *
imap_parser_create(struct istream *input, struct ostream *output,
- size_t max_literal_size, size_t max_elements);
+ size_t max_line_size);
void imap_parser_destroy(struct imap_parser *parser);
/* Reset the parser to initial state. */
Returns NULL if more data is needed. */
const char *imap_parser_read_word(struct imap_parser *parser);
-/* Read the rest of the line. Returns NULL if more data is needed. */
-const char *imap_parser_read_line(struct imap_parser *parser);
-
/* Returns the imap argument as string. NIL returns "" and list returns NULL. */
const char *imap_arg_string(struct imap_arg *arg);