]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-imap: imap-parser: Turned the fatal error flag into a proper error code.
authorStephan Bosch <stephan@dovecot.fi>
Sun, 29 May 2016 17:23:39 +0000 (19:23 +0200)
committerStephan Bosch <stephan@dovecot.fi>
Sun, 29 May 2016 18:30:31 +0000 (20:30 +0200)
src/imap-login/imap-login-client.c
src/imap/cmd-append.c
src/imap/cmd-setmetadata.c
src/imap/imap-client.c
src/lib-imap/imap-parser.c
src/lib-imap/imap-parser.h
src/lib-imap/test-imap-parser.c

index b1a6d67a7a7316b30c5a1987e29545c126ce9564..8e539e7126248510fb309e5e65161031579407a9 100644 (file)
@@ -55,15 +55,20 @@ static bool client_handle_parser_error(struct imap_client *client,
                                       struct imap_parser *parser)
 {
        const char *msg;
-       bool fatal;
+       enum imap_parser_error parse_error;
 
-       msg = imap_parser_get_error(parser, &fatal);
-       if (fatal) {
+       msg = imap_parser_get_error(parser, &parse_error);
+       switch (parse_error) {
+       case IMAP_PARSE_ERROR_NONE:
+               i_unreached();
+       case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
                client_send_reply(&client->common,
                                  IMAP_CMD_REPLY_BYE, msg);
                client_destroy(&client->common,
                               t_strconcat("Disconnected: ", msg, NULL));
                return FALSE;
+       default:
+               break;
        }
 
        client_send_reply(&client->common, IMAP_CMD_REPLY_BAD, msg);
index 3d9a3d1f04ae633fe0e2c97c7ac87b7671ca85d0..6bfac49141b3b5f53809fb75244ff01b74b569df 100644 (file)
@@ -392,7 +392,8 @@ static bool cmd_append_continue_catenate(struct client_command_context *cmd)
        struct cmd_append_context *ctx = cmd->context;
        const struct imap_arg *args;
        const char *msg;
-       bool fatal, nonsync = FALSE;
+       enum imap_parser_error parse_error;
+       bool nonsync = FALSE;
        int ret;
 
        if (cmd->cancel) {
@@ -412,11 +413,17 @@ static bool cmd_append_continue_catenate(struct client_command_context *cmd)
                                            IMAP_PARSE_FLAG_INSIDE_LIST, &args);
        } while (ret > 0 && !catenate_args_can_stop(ctx, args));
        if (ret == -1) {
-               msg = imap_parser_get_error(ctx->save_parser, &fatal);
-               if (fatal)
+               msg = imap_parser_get_error(ctx->save_parser, &parse_error);
+               switch (parse_error) {
+               case IMAP_PARSE_ERROR_NONE:
+                       i_unreached();
+               case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
                        client_disconnect_with_error(client, msg);
-               else if (!ctx->failed)
-                       client_send_command_error(cmd, msg);
+                       break;
+               default:
+                       if (!ctx->failed)
+                               client_send_command_error(cmd, msg);
+               }
                client->input_skip_line = TRUE;
                cmd_append_finish(ctx);
                return TRUE;
@@ -714,8 +721,9 @@ static bool cmd_append_parse_new_msg(struct client_command_context *cmd)
        struct cmd_append_context *ctx = cmd->context;
        const struct imap_arg *args;
        const char *msg;
+       enum imap_parser_error parse_error;
        unsigned int arg_min_count;
-       bool fatal, nonsync, last_literal;
+       bool nonsync, last_literal;
        int ret;
 
        /* this function gets called 1) after parsing APPEND <mailbox> and
@@ -748,11 +756,16 @@ static bool cmd_append_parse_new_msg(struct client_command_context *cmd)
                 !cmd_append_args_can_stop(ctx, args, &last_literal));
        if (ret == -1) {
                if (!ctx->failed) {
-                       msg = imap_parser_get_error(ctx->save_parser, &fatal);
-                       if (fatal)
+                       msg = imap_parser_get_error(ctx->save_parser, &parse_error);
+                       switch (parse_error) {
+                       case IMAP_PARSE_ERROR_NONE:
+                               i_unreached();
+                       case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
                                client_disconnect_with_error(client, msg);
-                       else
+                               break;
+                       default:
                                client_send_command_error(cmd, msg);
+                       }
                }
                cmd_append_finish(ctx);
                return TRUE;
index bd18498e863e8d6c7fb0810a63a8e3cec62f7c39..652e13491aa8132b728e470220b1a9406e71222f 100644 (file)
@@ -46,8 +46,8 @@ cmd_setmetadata_parse_entryvalue(struct imap_setmetadata_context *ctx,
 {
        const struct imap_arg *args;
        const char *name, *error;
+       enum imap_parser_error parse_error;
        int ret;
-       bool fatal;
 
        /* parse the entry name */
        ret = imap_parser_read_args(ctx->parser, 1,
@@ -72,12 +72,17 @@ cmd_setmetadata_parse_entryvalue(struct imap_setmetadata_context *ctx,
        if (ret < 0) {
                if (ret == -2)
                        return 0;
-               error = imap_parser_get_error(ctx->parser, &fatal);
-               if (fatal) {
+               error = imap_parser_get_error(ctx->parser, &parse_error);
+               switch (parse_error) {
+               case IMAP_PARSE_ERROR_NONE:
+                       i_unreached();
+               case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
                        client_disconnect_with_error(ctx->cmd->client, error);
-                       return -1;
+                       break;
+               default:
+                       client_send_command_error(ctx->cmd, error);
+                       break;
                }
-               client_send_command_error(ctx->cmd, error);
                return -1;
        }
        if (args[1].type == IMAP_ARG_EOL) {
index b5046015643f4c778701d522445a73c299685f77..7f48d983a7f6ca96e8b7c9e03ecf7a9e4590a585 100644 (file)
@@ -535,13 +535,18 @@ void client_send_command_error(struct client_command_context *cmd,
 {
        struct client *client = cmd->client;
        const char *error, *cmd_name;
-       bool fatal;
+       enum imap_parser_error parse_error;
 
        if (msg == NULL) {
-               msg = imap_parser_get_error(cmd->parser, &fatal);
-               if (fatal) {
+               msg = imap_parser_get_error(cmd->parser, &parse_error);
+               switch (parse_error) {
+               case IMAP_PARSE_ERROR_NONE:
+                       i_unreached();
+               case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
                        client_disconnect_with_error(client, msg);
                        return;
+               default:
+                       break;
                }
        }
 
index 4a5cab9cb14f182cd4ebe2893b8a4bff516ea465..63474c3790b344db812da91d59293ff8209a059f 100644 (file)
@@ -54,6 +54,7 @@ struct imap_parser {
        int str_first_escape; /* ARG_PARSE_STRING: index to first '\' */
        uoff_t literal_size; /* ARG_PARSE_LITERAL: string size */
 
+       enum imap_parser_error error;
        const char *error_msg;
 
        unsigned int literal_skip_crlf:1;
@@ -120,6 +121,7 @@ void imap_parser_reset(struct imap_parser *parser)
        parser->str_first_escape = 0;
        parser->literal_size = 0;
 
+       parser->error = IMAP_PARSE_ERROR_NONE;
        parser->error_msg = NULL;
 
        parser->literal_skip_crlf = FALSE;
@@ -135,10 +137,11 @@ void imap_parser_set_streams(struct imap_parser *parser, struct istream *input,
        parser->output = output;
 }
 
-const char *imap_parser_get_error(struct imap_parser *parser, bool *fatal)
+const char *imap_parser_get_error(struct imap_parser *parser,
+       enum imap_parser_error *error_r)
 {
-       if (fatal != NULL)
-               *fatal = parser->fatal_error;
+       if (error_r != NULL)
+               *error_r = parser->error;
        return parser->error_msg;
 }
 
@@ -195,6 +198,7 @@ static int imap_parser_close_list(struct imap_parser *parser)
                        return TRUE;
                }
                parser->error_msg = "Unexpected ')'";
+               parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                return FALSE;
        }
 
@@ -302,6 +306,7 @@ static int is_valid_atom_char(struct imap_parser *parser, char chr)
 
        if ((parser->flags & IMAP_PARSE_FLAG_ATOM_ALLCHARS) != 0)
                return TRUE;
+       parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
        parser->error_msg = error_msg;
        return FALSE;
 }
@@ -323,6 +328,7 @@ static int imap_parser_read_atom(struct imap_parser *parser,
                                break;
                        } else if ((parser->flags &
                                    IMAP_PARSE_FLAG_ATOM_ALLCHARS) == 0) {
+                               parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                                parser->error_msg = "Unexpected ')'";
                                return FALSE;
                        }
@@ -369,6 +375,7 @@ static int imap_parser_read_string(struct imap_parser *parser,
                   a linebreak.. */
                if (is_linebreak(data[i]) &&
                    (parser->flags & IMAP_PARSE_FLAG_MULTILINE_STR) == 0) {
+                       parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                        parser->error_msg = "Missing '\"'";
                        return FALSE;
                }
@@ -385,8 +392,8 @@ static int imap_parser_literal_end(struct imap_parser *parser)
                    parser->literal_size >
                    parser->max_line_size - parser->line_size) {
                        /* too long string, abort. */
+                       parser->error = IMAP_PARSE_ERROR_LITERAL_TOO_BIG;
                        parser->error_msg = "Literal size too large";
-                       parser->fatal_error = TRUE;
                        return FALSE;
                }
 
@@ -418,6 +425,7 @@ static int imap_parser_read_literal(struct imap_parser *parser,
                }
 
                if (parser->literal_nonsync) {
+                       parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                        parser->error_msg = "Expecting '}' after '+'";
                        return FALSE;
                }
@@ -428,6 +436,7 @@ static int imap_parser_read_literal(struct imap_parser *parser,
                }
 
                if (data[i] < '0' || data[i] > '9') {
+                       parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                        parser->error_msg = "Invalid literal size";
                        return FALSE;
                }
@@ -437,6 +446,7 @@ static int imap_parser_read_literal(struct imap_parser *parser,
 
                if (parser->literal_size < prev_size) {
                        /* wrapped around, abort. */
+                       parser->error = IMAP_PARSE_ERROR_LITERAL_TOO_BIG;
                        parser->error_msg = "Literal size too large";
                        return FALSE;
                }
@@ -465,6 +475,7 @@ static int imap_parser_read_literal_data(struct imap_parser *parser,
                }
 
                if (*data != '\n') {
+                       parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                        parser->error_msg = "Missing LF after literal size";
                        return FALSE;
                }
@@ -578,6 +589,7 @@ static int imap_parser_read_arg(struct imap_parser *parser)
                                return FALSE;
                        }
                        if (data[1] != '\n') {
+                               parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                                parser->error_msg = "CR sent without LF";
                                return FALSE;
                        }
@@ -585,6 +597,7 @@ static int imap_parser_read_arg(struct imap_parser *parser)
                case '\n':
                        /* unexpected end of line */
                        if ((parser->flags & IMAP_PARSE_FLAG_INSIDE_LIST) != 0) {
+                               parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                                parser->error_msg = "Missing ')'";
                                return FALSE;
                        }
@@ -605,6 +618,7 @@ static int imap_parser_read_arg(struct imap_parser *parser)
                                break;
                        }
                        if ((parser->flags & IMAP_PARSE_FLAG_LITERAL8) == 0) {
+                               parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                                parser->error_msg = "literal8 not allowed here";
                                return FALSE;
                        }
@@ -671,6 +685,7 @@ static int imap_parser_read_arg(struct imap_parser *parser)
                if (parser->cur_pos == data_size)
                        return FALSE;
                if (data[parser->cur_pos] != '{') {
+                       parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
                        parser->error_msg = "Expected '{'";
                        return FALSE;
                }
@@ -722,6 +737,7 @@ static int finish_line(struct imap_parser *parser, unsigned int count,
 
        if (parser->list_arg != NULL && !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;
@@ -755,12 +771,13 @@ int imap_parser_read_args(struct imap_parser *parser, unsigned int count,
                        break;
 
                if (parser->line_size > parser->max_line_size) {
+                       parser->error = IMAP_PARSE_ERROR_LINE_TOO_LONG;
                        parser->error_msg = "IMAP command line too large";
                        break;
                }
        }
 
-       if (parser->error_msg != NULL) {
+       if (parser->error != IMAP_PARSE_ERROR_NONE) {
                /* error, abort */
                parser->line_size += parser->cur_pos;
                i_stream_skip(parser->input, parser->cur_pos);
index 25e77c8f07c5b9a5323129197a32451a56ca3150..25dfda0672b39a3053fe6bcca0554c4beda6b548 100644 (file)
@@ -29,6 +29,15 @@ enum imap_parser_flags {
        IMAP_PARSE_FLAG_STOP_AT_LIST    = 0x100
 };
 
+enum imap_parser_error {
+       /* not fatal */
+       IMAP_PARSE_ERROR_NONE = 0,
+       IMAP_PARSE_ERROR_BAD_SYNTAX,
+       IMAP_PARSE_ERROR_LINE_TOO_LONG,
+       /* fatal */
+       IMAP_PARSE_ERROR_LITERAL_TOO_BIG
+};
+
 struct imap_parser;
 
 /* Create new IMAP argument parser. output is used for sending command
@@ -58,8 +67,8 @@ void imap_parser_set_streams(struct imap_parser *parser, struct istream *input,
 /* Return the last error in parser. fatal is set to TRUE if there's no way to
    continue parsing, currently only if too large non-sync literal size was
    given. */
-const char *imap_parser_get_error(struct imap_parser *parser, bool *fatal)
-       ATTR_NULL(2);
+const char *imap_parser_get_error(struct imap_parser *parser,
+       enum imap_parser_error *error_r) ATTR_NULL(2);
 
 /* Read a number of arguments. This function doesn't call i_stream_read(), you
    need to do that. Returns number of arguments read (may be less than count
index 791c01d093c7f399d8d2960f6f2b7a64ca5f3db9..cb4fb0024653b10bf51560a01d76fb8631f1c0f5 100644 (file)
@@ -12,7 +12,7 @@ static void test_imap_parser_crlf(void)
        struct imap_parser *parser;
        const struct imap_arg *args;
        unsigned int i;
-       bool fatal;
+       enum imap_parser_error parse_error;
 
        test_begin("imap parser crlf handling");
        input = test_istream_create(test_input);
@@ -42,7 +42,9 @@ static void test_imap_parser_crlf(void)
        test_istream_set_size(input, ++i);
        (void)i_stream_read(input);
        test_assert(imap_parser_read_args(parser, 0, 0, &args) == -1);
-       test_assert(strcmp(imap_parser_get_error(parser, &fatal), "CR sent without LF") == 0 && !fatal);
+       test_assert(strcmp(imap_parser_get_error
+               (parser, &parse_error), "CR sent without LF") == 0 &&
+               parse_error == IMAP_PARSE_ERROR_BAD_SYNTAX);
 
        imap_parser_unref(&parser);
        i_stream_destroy(&input);