]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-imap: Add IMAP_ARG_EOL parameter also for unfinished lists
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Fri, 8 Nov 2019 08:57:01 +0000 (10:57 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 13 Nov 2019 08:31:26 +0000 (10:31 +0200)
If list parsing was stopped due to IMAP_ARG_LITERAL_SIZE* the list didn't
have IMAP_ARG_EOL added. However, imap_arg_get_list() could still have
been used for it, which assumes that the IMAP_ARG_EOL exists.

This didn't seem to cause any actual bugs so far, but the following commits
require this.

The IMAP_ARG_EOL is appended and deleted immediately. This way it's seen by
imap_arg_get_list(), but it won't change any other behavior unexpectedly.

src/lib-imap/imap-arg.c
src/lib-imap/imap-parser.c

index fcfea5f83119191b8f4161b81465ea3f3df2261a..3011b5fd00665dc73f6a8fb42ca4cd2195c4d764 100644 (file)
@@ -79,9 +79,14 @@ bool imap_arg_get_list_full(const struct imap_arg *arg,
 
        *list_r = array_get(&arg->_data.list, &count);
 
-       /* drop IMAP_ARG_EOL from list size */
-       i_assert(count > 0);
-       *list_count_r = count - 1;
+       if (count > 0 && (*list_r)[count-1].type == IMAP_ARG_EOL)
+               count--;
+       else {
+               /* imap-parser stopped early (e.g. due to reading literal size).
+                  The IMAP_ARG_EOL was added to the list only temporarily. */
+               i_assert((*list_r)[count].type == IMAP_ARG_EOL);
+       }
+       *list_count_r = count;
        return TRUE;
 }
 
index 7f58d99e2f912aea9e0a8b1bbc66ff817101f84f..238d2efa0a5696c1020f2b0f7f2fdc7a1d649ae6 100644 (file)
@@ -759,12 +759,18 @@ static int finish_line(struct imap_parser *parser, unsigned int count,
        parser->cur_pos = 0;
        parser->cur_resp_text = FALSE;
 
-       if (parser->list_arg != NULL && !parser->literal_size_return &&
-           (parser->flags & IMAP_PARSE_FLAG_STOP_AT_LIST) == 0) {
+       if (parser->list_arg == NULL) {
+               /* no open list */
+       } else if (!parser->literal_size_return &&
+                  (parser->flags & IMAP_PARSE_FLAG_STOP_AT_LIST) == 0) {
                parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                parser->error_msg = "Missing ')'";
                *args_r = NULL;
                return -1;
+       } else {
+               arg = array_append_space(&parser->list_arg->_data.list);
+               arg->type = IMAP_ARG_EOL;
+               array_pop_back(&parser->list_arg->_data.list);
        }
 
        arg = array_append_space(&parser->root_list);
@@ -775,6 +781,12 @@ static int finish_line(struct imap_parser *parser, unsigned int count,
        return ret;
 }
 
+static void imap_parser_delete_extra_eol(struct imap_parser *parser)
+{
+       array_pop_back(&parser->root_list);
+       parser->args_added_extra_eol = FALSE;
+}
+
 int imap_parser_read_args(struct imap_parser *parser, unsigned int count,
                          enum imap_parser_flags flags,
                          const struct imap_arg **args_r)
@@ -783,8 +795,7 @@ int imap_parser_read_args(struct imap_parser *parser, unsigned int count,
 
        if (parser->args_added_extra_eol) {
                /* delete EOL */
-               array_pop_back(&parser->root_list);
-               parser->args_added_extra_eol = FALSE;
+               imap_parser_delete_extra_eol(parser);
                parser->literal_size_return = FALSE;
        }
 
@@ -866,6 +877,7 @@ void imap_parser_read_last_literal(struct imap_parser *parser)
        struct imap_arg *last_arg;
 
        i_assert(parser->literal_size_return);
+       i_assert(parser->args_added_extra_eol);
 
        last_arg = imap_parser_get_last_literal_size(parser, &list);
        i_assert(last_arg != NULL);
@@ -874,8 +886,7 @@ void imap_parser_read_last_literal(struct imap_parser *parser)
        i_assert(parser->literal_size == last_arg->_data.literal_size);
 
        /* delete EOL */
-       array_pop_back(&parser->root_list);
-       parser->args_added_extra_eol = FALSE;
+       imap_parser_delete_extra_eol(parser);
 
        /* delete literal size */
        array_pop_back(list);