[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1013944: bullseye-pu: package cyrus-imapd/3.2.6-2+deb11u2



Package: release.debian.org
Severity: normal
Tags: bullseye
User: release.debian.org@packages.debian.org
Usertags: pu

[ Reason ]
Bookworm will provide cyrus-imapd 3.6.x. To permit a safe upgrade from
3.2.6, updtream provided a patch for versions 3.4 and 3.2. It ensure
that mailboxes have an unique id.

[ Impact ]
Risk during Bullseye to Bookworm upgrade.

[ Tests ]
Test passed
(https://salsa.debian.org/debian/cyrus-imapd/-/pipelines/393112)

[ Risks ]
This patch is the difference between 3.2.9 and 3.2.10, applied without
any change.

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in (old)stable
  [X] the issue is verified as fixed in unstable

[ Changes ]
Cyrus tools now check if mailbox id is really unique.

Cheers,
Yadd
diff --git a/debian/changelog b/debian/changelog
index ca4d2a92..209a040f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+cyrus-imapd (3.2.6-2+deb11u2) bullseye; urgency=medium
+
+  * Ensure that ctl_cyrusdb -r and reconstruct now ensure the "uniqueid" field
+    is present in and synchronised between mailboxes.db and cyrus.header.
+    Required before 3.6.x upgrade
+
+ -- Yadd <yadd@debian.org>  Mon, 27 Jun 2022 21:41:17 +0200
+
 cyrus-imapd (3.2.6-2+deb11u1) bullseye; urgency=high
 
   * Replace string hashing algorithm (Closes: #993433, CVE-2021-33582)
diff --git a/debian/patches/prepare-3.6-upgrade.patch b/debian/patches/prepare-3.6-upgrade.patch
new file mode 100644
index 00000000..a7b8aea0
--- /dev/null
+++ b/debian/patches/prepare-3.6-upgrade.patch
@@ -0,0 +1,244 @@
+Description: reconstruct mailboxes to prepare
+ ctl_cyrusdb -r and reconstruct now ensure the "uniqueid" field is present
+ in and synchronised between mailboxes.db and cyrus.header.
+Author: ellie timoney <ellie@fastmail.com>
+Origin: upstream, https://github.com/cyrusimap/cyrus-imapd/commit/360e5d153
+ https://github.com/cyrusimap/cyrus-imapd/commit/93b01dd83
+ https://github.com/cyrusimap/cyrus-imapd/commit/0f59f9f36
+ https://github.com/cyrusimap/cyrus-imapd/commit/0ee7d128a
+ https://github.com/cyrusimap/cyrus-imapd/commit/2918ce8f0
+ https://github.com/cyrusimap/cyrus-imapd/commit/a330b471f
+ https://github.com/cyrusimap/cyrus-imapd/commit/df58b26cb
+Bug: https://github.com/cyrusimap/cyrus-imapd/pull/4100
+Forwarded: not-needed
+Reviewed-By: Yadd <yadd@debian.org>
+Last-Update: 2022-06-27
+
+--- a/imap/ctl_cyrusdb.c
++++ b/imap/ctl_cyrusdb.c
+@@ -129,7 +129,7 @@
+ static int fixmbox(const mbentry_t *mbentry,
+                    void *rock __attribute__((unused)))
+ {
+-    int r;
++    int r, r2;
+ 
+     /* if MBTYPE_RESERVED, unset it & call mboxlist_delete */
+     if (mbentry->mbtype & MBTYPE_RESERVE) {
+@@ -172,12 +172,66 @@
+                mbentry->name, cyrusdb_strerror(r));
+     }
+ 
++    /* make sure every local mbentry has a uniqueid!  */
++    if (!mbentry->uniqueid && mbentry_is_local_mailbox(mbentry)) {
++        struct mailbox *mailbox = NULL;
++        struct mboxlock *namespacelock = NULL;
++        mbentry_t *copy = NULL;
++
++        r = mailbox_open_iwl(mbentry->name, &mailbox);
++        if (r) {
++            /* XXX what does it mean if there's an mbentry, but the mailbox
++             * XXX was not openable?
++             */
++            syslog(LOG_DEBUG, "%s: mailbox_open_iwl %s returned %s",
++                              __func__, mbentry->name, error_message(r));
++            goto skip_uniqueid;
++        }
++
++        if (!mailbox->uniqueid) {
++            /* yikes, no uniqueid in header either! */
++            mailbox_make_uniqueid(mailbox);
++            syslog(LOG_INFO, "mailbox %s header had no uniqueid, creating %s",
++                             mbentry->name, mailbox->uniqueid);
++        }
++
++        copy = mboxlist_entry_copy(mbentry);
++        copy->uniqueid = xstrdup(mailbox->uniqueid);
++        syslog(LOG_INFO, "mbentry %s had no uniqueid, setting %s from header",
++                         copy->name, copy->uniqueid);
++
++        namespacelock = mboxname_usernamespacelock(copy->name);
++        r = mboxlist_update(copy, /*localonly*/1);
++        mboxname_release(&namespacelock);
++        if (r) {
++            syslog(LOG_ERR, "failed to update mboxlist for %s: %s",
++                            mbentry->name, error_message(r));
++            r2 = mailbox_abort(mailbox);
++            if (r2) {
++                syslog(LOG_ERR, "DBERROR: error aborting transaction: %s",
++                                cyrusdb_strerror(r2));
++            }
++        }
++        else {
++            r2 = mailbox_commit(mailbox);
++            if (r2) {
++                syslog(LOG_ERR, "DBERROR: error committing transaction: %s",
++                                cyrusdb_strerror(r2));
++            }
++        }
++        mailbox_close(&mailbox);
++        mboxlist_entry_free(&copy);
++
++skip_uniqueid:
++        ;   /* hush "label at end of compound statement" warning */
++    }
++
+     return 0;
+ }
+ 
+ static void process_mboxlist(void)
+ {
+-    /* build a list of mailboxes - we're using internal names here */
++    /* run fixmbox across all mboxlist entries */
+     mboxlist_allmbox(NULL, fixmbox, NULL, MBOXTREE_INTERMEDIATES);
+ 
+     /* enable or disable RACLs per config */
+--- a/imap/mailbox.c
++++ b/imap/mailbox.c
+@@ -995,6 +995,12 @@
+         goto done;
+     }
+ 
++    /* XXX can we even get here for remote mbentries? */
++    if (!mbentry->uniqueid && mbentry_is_local_mailbox(mbentry)) {
++        syslog(LOG_NOTICE, "mbentry %s has no uniqueid, needs reconstruct",
++                            mailbox->name);
++    }
++
+     mailbox->part = xstrdup(mbentry->partition);
+ 
+     /* Note that the header does have the ACL information, but it is only
+@@ -1288,7 +1294,11 @@
+         if (!tab || tab > eol) tab = eol;
+         mailbox->uniqueid = xstrndup(p, tab - p);
+     }
+-    /* else, uniqueid needs to be generated when we know the uidvalidity */
++    else {
++        /* ancient cyrus.header file without a uniqueid field! */
++        syslog(LOG_NOTICE, "mailbox %s header has no uniqueid, needs reconstruct",
++                           mailbox->name);
++    }
+ 
+     /* Read names of user flags */
+     p = eol + 1;
+@@ -6148,6 +6158,9 @@
+                 mailbox_set_uniqueid(mailbox, mbentry->uniqueid);
+             }
+             else {
++                if (!mailbox->uniqueid) {
++                    mailbox_make_uniqueid(mailbox);
++                }
+                 free(mbentry->uniqueid);
+                 mbentry->uniqueid = xstrdup(mailbox->uniqueid);
+                 r = mboxlist_update(mbentry, 0);
+--- a/imap/mboxlist.c
++++ b/imap/mboxlist.c
+@@ -271,6 +271,26 @@
+                              uid);
+ }
+ 
++EXPORTED int mbentry_is_local_mailbox(const struct mboxlist_entry *mbentry)
++{
++    if (config_mupdate_server && !config_getstring(IMAPOPT_PROXYSERVERS)) {
++        /* dedicated frontends never have local mailboxes */
++        return 0;
++    }
++    else if ((mbentry->mbtype & MBTYPE_REMOTE)) {
++        /* mbentry has the remote flag set */
++        return 0;
++    }
++    else if (mbentry->server
++             && 0 != strcmpsafe(mbentry->server, config_servername))
++    {
++        /* it's on some server that is not this one */
++        return 0;
++    }
++
++    return 1;
++}
++
+ /*
+  * read a single record from the mailboxes.db and return a pointer to it
+  */
+--- a/imap/mboxlist.h
++++ b/imap/mboxlist.h
+@@ -123,6 +123,9 @@
+ char *mbentry_metapath(const struct mboxlist_entry *mbentry, int metatype, int isnew);
+ char *mbentry_datapath(const struct mboxlist_entry *mbentry, uint32_t);
+ 
++int mbentry_is_local_mailbox(const struct mboxlist_entry *mbentry);
++#define mbentry_is_remote_mailbox(mbentry) (!mbentry_is_local_mailbox(mbentry))
++
+ int mboxlist_parse_entry(mbentry_t **mbentryptr,
+                          const char *name, size_t namelen,
+                          const char *data, size_t datalen);
+--- a/imap/reconstruct.c
++++ b/imap/reconstruct.c
+@@ -468,33 +468,45 @@
+         return 0;
+     }
+ 
+-    other = hash_lookup(mailbox->uniqueid, &unqid_table);
+-    if (other) {
+-        mbentry_t *oldmbentry = NULL;
+-        /* check that the old one still exists! */
+-        r = mboxlist_lookup(other, &oldmbentry, NULL);
+-        if (!r && !strcmpsafe(oldmbentry->uniqueid, mailbox->uniqueid)) {
+-            /* uniqueid change required! */
+-            if (updateuniqueids) {
+-                mailbox_make_uniqueid(mailbox);
+-                syslog (LOG_ERR, "uniqueid clash with %s - changed %s (%s => %s)",
+-                        other, mailbox->name, oldmbentry->uniqueid, mailbox->uniqueid);
+-            }
+-            else {
+-                syslog (LOG_ERR, "uniqueid clash with %s for %s (%s)",
+-                        other, mailbox->name, mailbox->uniqueid);
+-            }
+-        }
+-        mboxlist_entry_free(&oldmbentry);
+-    }
+-
+-    hash_insert(mailbox->uniqueid, xstrdup(mailbox->name), &unqid_table);
+-
+     /* Convert internal name to external */
+     char *extname = mboxname_to_external(name, &recon_namespace, NULL);
+     if (!(reconstruct_flags & RECONSTRUCT_QUIET))
+         printf("%s\n", extname);
+ 
++    if (mailbox->uniqueid) {
++        other = hash_lookup(mailbox->uniqueid, &unqid_table);
++        if (other) {
++            mbentry_t *oldmbentry = NULL;
++            /* check that the old one still exists! */
++            r = mboxlist_lookup(other, &oldmbentry, NULL);
++            if (!r && !strcmpsafe(oldmbentry->uniqueid, mailbox->uniqueid)) {
++                /* uniqueid change required! */
++                if (updateuniqueids) {
++                    mailbox_make_uniqueid(mailbox);
++                    syslog (LOG_ERR, "uniqueid clash with %s - changed %s (%s => %s)",
++                            other, mailbox->name, oldmbentry->uniqueid, mailbox->uniqueid);
++                }
++                else {
++                    syslog (LOG_ERR, "uniqueid clash with %s for %s (%s)",
++                            other, mailbox->name, mailbox->uniqueid);
++                }
++            }
++            mboxlist_entry_free(&oldmbentry);
++        }
++
++        hash_insert(mailbox->uniqueid, xstrdup(mailbox->name), &unqid_table);
++    }
++    else {
++        /* We should only get here for -V (setversion) or -n (no changes)
++         * modes.  Otherwise, mailbox_reconstruct() should have dealt with it
++         * already.
++         * It would be nice if -V would also ensure there's a uniqueid, but
++         * that change would require a refactor that's already on 3.6 but too
++         * intrusive to backport.
++         */
++        printf("%s has no uniqueid, needs real reconstruct\n", extname);
++    }
++
+     strncpy(outpath, mailbox_meta_fname(mailbox, META_HEADER), MAX_MAILBOX_NAME);
+ 
+     if (setversion && setversion != mailbox->i.minor_version) {
diff --git a/debian/patches/series b/debian/patches/series
index 1577d428..60373820 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -9,3 +9,4 @@
 0018-increase-test-timeout.patch
 CVE-2021-32056.patch
 CVE-2021-33582.patch
+prepare-3.6-upgrade.patch

Reply to: