]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap: Add regression test for mailbox state import error handling main
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Fri, 26 Jun 2026 10:34:39 +0000 (10:34 +0000)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 3 Aug 2026 14:10:52 +0000 (14:10 +0000)
Export a valid mailbox state, then recreate the mailbox with a different
GUID so the stored mailbox no longer matches the exported state, and
verify imap_state_import_internal() rejects it instead of returning
IMAP_STATE_OK. Without the import_state_mailbox() fix the mailbox-open
error is swallowed and import wrongly succeeds, which this test catches.

src/imap/test-imap-client-hibernate.c

index 0dde6ecaad83f7252c87056b05d2a43ad7c3dd60..0518ca899ed2a8ef4c57b391f0e578e86a610963 100644 (file)
 #include "smtp-submit.h"
 #include "mail-storage-service.h"
 #include "mail-storage-private.h"
+#include "buffer.h"
 #include "imap-common.h"
 #include "imap-settings.h"
 #include "imap-client.h"
+#include "imap-state.h"
 
 #include <sys/stat.h>
 
@@ -240,6 +242,51 @@ static void test_imap_client_hibernate(void)
        test_assert(strstr(error, "notgood") != NULL);
        test_end();
 
+       /* Regression test for swallowed mailbox-open errors during state
+          import. import_state_mailbox() used to check the result of
+          import_state_mailbox_open() with "< 0", but that function returns
+          enum imap_state_result where errors are positive values, so the
+          errors were ignored and import wrongly reported success. That could
+          leave the client with a mailbox but no keywords array and crash in
+          the following sync. Verify that importing a state whose mailbox no
+          longer matches is rejected. */
+       test_begin("imap client state import: inconsistent mailbox rejected");
+       struct mailbox *import_box =
+               mailbox_alloc(client->user->namespaces->list, "importbox", 0);
+       struct mailbox_update import_update = {
+               .uid_validity = 11111111,
+       };
+       memset(import_update.mailbox_guid, 0x34,
+              sizeof(import_update.mailbox_guid));
+       test_assert(mailbox_create(import_box, &import_update, FALSE) == 0);
+       test_assert(mailbox_open(import_box) == 0);
+       test_assert(mailbox_sync(import_box, 0) == 0);
+       client->mailbox = import_box;
+
+       buffer_t *state = t_buffer_create(256);
+       test_assert(imap_state_export_internal(client, state, &error) == 1);
+
+       /* close the exported mailbox and recreate it with a different GUID,
+          so the exported state no longer matches the stored mailbox */
+       mailbox_free(&client->mailbox);
+       client->keywords.names = NULL;
+       import_box = mailbox_alloc(client->user->namespaces->list,
+                                  "importbox", 0);
+       test_assert(mailbox_delete(import_box) == 0);
+       mailbox_free(&import_box);
+       import_box = mailbox_alloc(client->user->namespaces->list,
+                                  "importbox", 0);
+       memset(import_update.mailbox_guid, 0x56,
+              sizeof(import_update.mailbox_guid));
+       test_assert(mailbox_create(import_box, &import_update, FALSE) == 0);
+       mailbox_free(&import_box);
+
+       const char *import_error = NULL;
+       test_assert(imap_state_import_internal(client, state->data,
+               state->used, &import_error) != IMAP_STATE_OK);
+       test_assert(client->mailbox == NULL);
+       test_end();
+
        /* create and open evil mailbox */
        client->mailbox = mailbox_alloc(client->user->namespaces->list,
                                        "testbox", 0);