Package: release.debian.org Severity: normal Tags: bullseye User: release.debian....@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 <y...@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 <el...@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 <y...@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(©); ++ ++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