Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Please unblock package cyrus-imapd Hi all, Buster has currently cyrus-imapd 3.0.8. Upstram last version is 3.0.9. This version has one new little feature: "The new ``cyrus_group`` option in :cyrusman:`imapd.conf(5)` can be used to set the UNIX group that Cyrus processes run as (thanks Jakob Gahde). The default is to use the primary group of the configured ``cyrus_user``. The old ``--with-cyrus-group`` configure option has been non-functional for many years, and has been removed." and fixes many bugs - LMTP segfault (RC bug #927142) - some memory leaks - mailboxes with space in name - idle sockets - UTF problems It add also Clamav 0.101.x support. Since Buster has Clamav 0.101.2 and Cyrus-Imapd has no reverse dependencies, I think it would be a good thing to upgrate cyrus-imapd instead of backporting the majority of these changes. Diff contains also many documentation updates that have no consequences on upgrade. Cheers, Xavier unblock cyrus-imapd/3.0.9-1 -- System Information: Debian Release: buster/sid APT prefers testing APT policy: (900, 'testing'), (500, 'unstable') Architecture: amd64 (x86_64) Kernel: Linux 4.19.0-4-amd64 (SMP w/8 CPU cores) Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8), LANGUAGE= (charmap=UTF-8) Shell: /bin/sh linked to /usr/bin/dash Init: systemd (via /run/systemd/system) LSM: AppArmor: enabled
diff --git a/Makefile.am b/Makefile.am index df77bbf92..fef9554f0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -121,7 +121,7 @@ EXTRA_DIST = \ if COM_ERR COMPILE_ET_DEP = com_err/et/compile_et -BUILT_SOURCES += com_err/et/compile_et +BUILT_SOURCES += com_err/et/compile_et com_err/et/libcyrus_com_err.la lib_LTLIBRARIES += com_err/et/libcyrus_com_err.la endif # COM_ERR @@ -879,6 +879,7 @@ imap_cyr_sphinxmgr_SOURCES = imap/cli_fatal.c imap/cyr_sphinxmgr.c imap/mutex_fa imap_cyr_sphinxmgr_LDADD = $(LD_UTILITY_ADD) imap_cyr_virusscan_SOURCES = imap/cli_fatal.c imap/cyr_virusscan.c imap/mutex_fake.c +imap_cyr_virusscan_CFLAGS = $(AM_CFLAGS) $(CLAMAV_CFLAGS) $(CFLAG_VISIBILITY) imap_cyr_virusscan_LDADD = $(LD_UTILITY_ADD) $(CLAMAV_LIBS) imap_ctl_zoneinfo_SOURCES = imap/cli_fatal.c imap/ctl_zoneinfo.c imap/mutex_fake.c imap/zoneinfo_db.c diff --git a/backup/ctl_backups.c b/backup/ctl_backups.c index cbc37e5b7..77607ca34 100644 --- a/backup/ctl_backups.c +++ b/backup/ctl_backups.c @@ -898,6 +898,7 @@ static int lock_run_pipe(const char *userid, const char *fname, if (r) { printf("NO failed (%s)\n", error_message(r)); + r = backup_close(&backup); return EC_SOFTWARE; // FIXME would something else be more appropriate? } @@ -934,6 +935,7 @@ static int lock_run_sqlite(const char *userid, const char *fname, fprintf(stderr, "unable to lock %s: %s\n", userid ? userid : fname, error_message(r)); + r = backup_close(&backup); return EC_SOFTWARE; } @@ -994,6 +996,7 @@ static int lock_run_exec(const char *userid, const char *fname, fprintf(stderr, "unable to lock %s: %s\n", userid ? userid : fname, error_message(r)); + r = backup_close(&backup); return EC_SOFTWARE; } diff --git a/backup/lcb.c b/backup/lcb.c index f01371283..354d25d21 100644 --- a/backup/lcb.c +++ b/backup/lcb.c @@ -182,6 +182,7 @@ HIDDEN int backup_real_open(struct backup **backupp, if (r) { syslog(LOG_ERR, "IOERROR: (f)stat %s: %m", backup->data_fname); r = IMAP_IOERROR; + close(fd); goto error; } diff --git a/configure.ac b/configure.ac index 965b2594f..18049eca5 100644 --- a/configure.ac +++ b/configure.ac @@ -112,10 +112,6 @@ AC_ARG_WITH(cyrus-user, cyrus_user="$withval",cyrus_user="cyrus") AC_SUBST(cyrus_user) AC_DEFINE_UNQUOTED(CYRUS_USER, "$cyrus_user",[What user will we run as?]) -AC_ARG_WITH(cyrus-group, - [AS_HELP_STRING([--with-cyrus-group=GROUPID], [use GROUPID cyrus group])], - cyrus_group="$withval",cyrus_group="mail") -AC_SUBST(cyrus_group) dnl allow users to override $sysconfdir, but retain old default (/etc) dnl if not specified @@ -2254,6 +2250,7 @@ Cyrus Server configured components calalarmd: $enable_calalarmd objectstore: $enable_objectstore backup: $enable_backup + com_err: $with_com_err External dependencies: ldap: $have_ldap diff --git a/cunit/backend.testc b/cunit/backend.testc index 453ee8ad7..5f684a4dd 100644 --- a/cunit/backend.testc +++ b/cunit/backend.testc @@ -608,6 +608,7 @@ static void server_unaccept(struct server_state *state) state->out = NULL; sasl_dispose(&state->saslconn); state->is_connected = 0; + state->is_authenticated = 0; state->is_tls = 0; #ifdef HAVE_SSL if (state->tls_conn) { diff --git a/cunit/charset.testc b/cunit/charset.testc index 63f1ecac6..039973f91 100644 --- a/cunit/charset.testc +++ b/cunit/charset.testc @@ -274,6 +274,14 @@ static void test_encode_mimeheader(void) char *s = charset_encode_mimeheader(_in, 0); \ CU_ASSERT_PTR_NOT_NULL(s); \ CU_ASSERT_STRING_EQUAL(s, _exp); \ + const char *p, *lf; \ + for (lf = s, p = s; *p != '\0'; p++) { \ + if (*p == '\n') { \ + CU_ASSERT(p - lf <= 76); \ + lf = p; \ + } \ + } \ + CU_ASSERT(p - lf <= 76); \ free(s); \ } @@ -287,6 +295,15 @@ static void test_encode_mimeheader(void) /* wrap */ TESTCASE("abc\r\n xyz", "=?UTF-8?Q?abc?=\r\n =?UTF-8?Q?xyz?="); + /* three-byte UTF-8 word barely fits line length limit */ + TESTCASE("0123456789012345678901234567890123456789012345678901234\xe2\x82\xac", + "=?UTF-8?Q?0123456789012345678901234567890123456789012345678901234=E2=82=AC?="); + + /* three-byte UTF-8 word must not be split */ + TESTCASE("01234567890123456789012345678901234567890123456789012345\xe2\x82\xac", + "=?UTF-8?Q?01234567890123456789012345678901234567890123456789012345?=" + "\r\n ""=?UTF-8?Q?=E2=82=AC?="); + #undef TESTCASE } diff --git a/imap/conversations.c b/imap/conversations.c index 56eccff63..46042e3cb 100644 --- a/imap/conversations.c +++ b/imap/conversations.c @@ -1842,7 +1842,6 @@ EXPORTED int conversations_update_record(struct conversations_state *cstate, int *delta_counts = NULL; int i; modseq_t modseq = 0; - const struct index_record *record = NULL; int r = 0; if (old && new) { @@ -1864,21 +1863,15 @@ EXPORTED int conversations_update_record(struct conversations_state *cstate, } } + const struct index_record *record = new ? new : old; if (new && !old) { /* add the conversation */ r = mailbox_cacherecord(mailbox, new); /* make sure it's loaded */ if (r) return r; r = message_update_conversations(cstate, new, &conv); if (r) return r; - record = new; - /* possible if silent (i.e. replica) */ - if (!record->cid) return 0; } - else { - record = new ? new : old; - /* skip out on non-CIDed records */ - if (!record->cid) return 0; - + else if (record->cid) { r = conversation_load(cstate, record->cid, &conv); if (r) return r; if (!conv) { @@ -1893,6 +1886,24 @@ EXPORTED int conversations_update_record(struct conversations_state *cstate, } } + // always update the GUID information first, as it's used for search + // even if conversations have not been set on this email + if (new) { + if (!old) { + r = conversations_set_guid(cstate, mailbox, new, /*add*/1); + if (r) return r; + } + } + else { + if (old) { + r = conversations_set_guid(cstate, mailbox, old, /*add*/0); + if (r) return r; + } + } + + // the rest is bookkeeping for CIDs only + if (!record->cid) return 0; + if (cstate->counted_flags) delta_counts = xzmalloc(sizeof(int) * cstate->counted_flags->count); @@ -1928,10 +1939,6 @@ EXPORTED int conversations_update_record(struct conversations_state *cstate, } delta_num_records--; modseq = MAX(modseq, old->modseq); - if (!new) { - r = conversations_set_guid(cstate, mailbox, old, /*add*/0); - if (r) return r; - } } if (new) { @@ -1953,10 +1960,6 @@ EXPORTED int conversations_update_record(struct conversations_state *cstate, } delta_num_records++; modseq = MAX(modseq, new->modseq); - if (!old) { - r = conversations_set_guid(cstate, mailbox, new, /*add*/1); - if (r) return r; - } } /* XXX - combine this with the earlier cache parsing */ diff --git a/imap/cyr_virusscan.c b/imap/cyr_virusscan.c index 863a85870..8f578855e 100644 --- a/imap/cyr_virusscan.c +++ b/imap/cyr_virusscan.c @@ -193,8 +193,17 @@ int clamav_scanfile(void *state, const char *fname, int r; /* scan file */ +#if LIBCLAMAV_MAJORVER < 9 r = cl_scanfile(fname, virname, NULL, st->av_engine, CL_SCAN_STDOPT); +#else + static struct cl_scan_options options; + + memset(&options, 0, sizeof(struct cl_scan_options)); + options.parse |= ~0; /* enable all parsers */ + + r = cl_scanfile(fname, virname, NULL, st->av_engine, &options); +#endif switch (r) { case CL_CLEAN: diff --git a/imap/idle.c b/imap/idle.c index e1239cea0..bf1bf0ac4 100644 --- a/imap/idle.c +++ b/imap/idle.c @@ -116,11 +116,14 @@ EXPORTED void idle_init(void) struct sockaddr_un local; int fdflags; int s; + int r; if (!idle_enabled()) return; - assert(idle_make_client_address(&local)); - assert(idle_make_server_address(&idle_remote)); + r = idle_make_client_address(&local); + assert(r); + r = idle_make_server_address(&idle_remote); + assert(r); idle_method_desc = "poll"; diff --git a/imap/ipurge.c b/imap/ipurge.c index 4b1a49b69..80c51716b 100644 --- a/imap/ipurge.c +++ b/imap/ipurge.c @@ -233,7 +233,7 @@ static int usage(const char *name) /* we don't check what comes in on matchlen and category, should we? */ static int purge_me(struct findall_data *data, void *rock __attribute__((unused))) { - if (!data) return 0; + if (!data || !data->mbname) return 0; struct mailbox *mailbox = NULL; int r; mbox_stats_t stats; diff --git a/imap/lmtp_sieve.c b/imap/lmtp_sieve.c index 4c3bbc3b7..9ba030f38 100644 --- a/imap/lmtp_sieve.c +++ b/imap/lmtp_sieve.c @@ -414,7 +414,7 @@ static int sieve_redirect(void *ac, /* if we have a msgid, we can track our redirects */ if (m->id) { snprintf(buf, sizeof(buf), "%s-%s", m->id, rc->addr); - sievedb = make_sieve_db(mbname_userid(sd->mbname)); + sievedb = make_sieve_db(mbname_recipient(sd->mbname, ((deliver_data_t *) mc)->ns)); dkey.id = buf; dkey.to = sievedb; @@ -496,7 +496,7 @@ static int sieve_reject(void *ac, body = msg_getheader(md, "original-recipient"); origreceip = body ? body[0] : NULL; if ((res = send_rejection(md->id, md->return_path, - origreceip, mbname_userid(sd->mbname), + origreceip, mbname_recipient(sd->mbname, ((deliver_data_t *) mc)->ns), rc->msg, md->data)) == 0) { snmp_increment(SIEVE_REJECT, 1); syslog(LOG_INFO, "sieve rejected: %s to: %s", @@ -735,7 +735,7 @@ static int send_response(void *ac, while (waitpid(sm_pid, &sm_stat, 0) < 0); if (sm_stat == 0) { /* sendmail exit value */ - sievedb = make_sieve_db(mbname_userid(sdata->mbname)); + sievedb = make_sieve_db(mbname_recipient(sdata->mbname, ((deliver_data_t *) mc)->ns)); dkey.id = outmsgid; dkey.to = sievedb; diff --git a/imap/mbexamine.c b/imap/mbexamine.c index 670b27d4f..25cf003ed 100644 --- a/imap/mbexamine.c +++ b/imap/mbexamine.c @@ -216,11 +216,6 @@ static int do_examine(struct findall_data *data, void *rock __attribute__((unuse r = mailbox_open_irl(name, &mailbox); if (r) return r; - if (chdir(mailbox_datapath(mailbox, 0)) == -1) { - r = IMAP_IOERROR; - goto done; - } - printf(" Mailbox Header Info:\n"); printf(" Path to mailbox: %s\n", mailbox_datapath(mailbox, 0)); printf(" Mailbox ACL: %s\n", mailbox->acl); /* xxx parse */ @@ -352,7 +347,6 @@ static int do_examine(struct findall_data *data, void *rock __attribute__((unuse printf("Desired message not found\n"); } - done: mailbox_close(&mailbox); return r; @@ -384,11 +378,6 @@ static int do_quota(struct findall_data *data, void *rock __attribute__((unused) r = mailbox_open_irl(name, &mailbox); if (r) return r; - if (chdir(mailbox_datapath(mailbox, 0)) == -1) { - r = IMAP_IOERROR; - goto done; - } - struct mailbox_iter *iter = mailbox_iter_init(mailbox, 0, ITER_SKIP_EXPUNGED); const message_t *msg; while ((msg = mailbox_iter_step(iter))) { diff --git a/lib/charset.c b/lib/charset.c index 0fa6c1415..6c5eaa3e6 100644 --- a/lib/charset.c +++ b/lib/charset.c @@ -2766,19 +2766,25 @@ static char *qp_encode(const char *data, size_t len, int isheader, unsigned char this = data[n]; unsigned char next = (n < len - 1) ? data[n+1] : '\0'; - if (cnt >= BASE64_MAX_LINE_LEN) { - if (isheader) { - /* split encoded token with fold */ - buf_appendcstr(&buf, "?="); - buf_appendcstr(&buf, "\r\n "); - buf_appendcstr(&buf, "=?UTF-8?Q?"); + /* Insert line break before exceeding line length limits */ + if (isheader) { + /* RFC2047 forbids splitting multi-octet characters */ + int needbytes; + if (this < 0x80) needbytes = 0; + else if (this < 0xc0) needbytes = 0; // UTF-8 continuation + else if (this < 0xe0) needbytes = 3; + else if (this < 0xf0) needbytes = 6; + else if (this < 0xf8) needbytes = 9; + else needbytes = 0; // impossible UTF-8 encoding + if (cnt + needbytes >= BASE64_MAX_LINE_LEN) { + buf_appendcstr(&buf, "?=\r\n =?UTF-8?Q?"); cnt = 11; } - else { - /* add soft line break to body */ - buf_appendcstr(&buf, "=\r\n"); - cnt = 0; - } + } + else if (cnt >= BASE64_MAX_LINE_LEN) { + /* add soft line break to body */ + buf_appendcstr(&buf, "=\r\n"); + cnt = 0; } if ((QPSAFECHAR[this] diff --git a/lib/imapoptions b/lib/imapoptions index 294b073cb..e321a35fc 100644 --- a/lib/imapoptions +++ b/lib/imapoptions @@ -613,6 +613,11 @@ Blank lines and lines beginning with ``#'' are ignored. /* only show the domain for users in other domains than your own (for backwards compatibility if you're already sharing */ +{ "cyrus_group", NULL, STRING } +/* The name of the group Cyrus services will run as. If not configured, the + primary group of cyrus_user will be used. Can be further overridden by + setting the $CYRUS_GROUP environment variable. */ + { "cyrus_user", NULL, STRING } /* The username to use as the 'cyrus' user. If not configured, the compile time default will be used. Can be further overridden by setting the diff --git a/lib/util.c b/lib/util.c index 62ad7bdea..5f3cb1933 100644 --- a/lib/util.c +++ b/lib/util.c @@ -593,6 +593,7 @@ static int cap_setuid(int uid, int is_master) EXPORTED int become_cyrus(int is_master) { struct passwd *p; + struct group *g; uid_t newuid; gid_t newgid; int result; @@ -601,6 +602,7 @@ EXPORTED int become_cyrus(int is_master) if (uid) return cap_setuid(uid, is_master); const char *cyrus = cyrus_user(); + const char *mail = cyrus_group(); p = getpwnam(cyrus); if (p == NULL) { @@ -612,6 +614,15 @@ EXPORTED int become_cyrus(int is_master) newuid = p->pw_uid; newgid = p->pw_gid; + if (mail != NULL) { + g = getgrnam(mail); + if (g == NULL) { + syslog(LOG_ERR, "no entry in /etc/group for group %s", mail); + return -1; + } + newgid = g->gr_gid; + } + if (newuid == geteuid() && newuid == getuid() && newgid == getegid() && @@ -651,6 +662,13 @@ EXPORTED const char *cyrus_user(void) return cyrus; } +EXPORTED const char *cyrus_group(void) +{ + const char *mail = getenv("CYRUS_GROUP"); + if (!mail) mail = config_getstring(IMAPOPT_CYRUS_GROUP); + return mail; +} + static int cmdtime_enabled = 0; static struct timeval cmdtime_start, cmdtime_end, nettime_start, nettime_end; static double totaltime, cmdtime, nettime, search_maxtime; diff --git a/lib/util.h b/lib/util.h index 8233cfd1d..d55c56811 100644 --- a/lib/util.h +++ b/lib/util.h @@ -206,6 +206,7 @@ enum { extern int set_caps(int stage, int is_master); extern int become_cyrus(int is_master); extern const char *cyrus_user(void); +extern const char *cyrus_group(void); /* Some systems have very inefficient implementations of isdigit, * and we use it in a lot of inner loops diff --git a/perl/imap/IMAP/Admin.pm b/perl/imap/IMAP/Admin.pm index e2ef12cc8..1ca412a10 100644 --- a/perl/imap/IMAP/Admin.pm +++ b/perl/imap/IMAP/Admin.pm @@ -575,7 +575,11 @@ sub listquotaroot { $self->addcallback({-trigger => 'QUOTAROOT', -callback => sub { my %d = @_; - return unless $d{-text} =~ /^\S+ (\S+)/; + return unless ( $d{-text} =~ /^\"[^\"]+\" \"([^\"]+)\"/ or + $d{-text} =~ /^\"[^\"]+\" (\S+)/ or + $d{-text} =~ /[^\"]\S+ \"([^\"]+)\"/ or + $d{-text} =~ /^[^\"]\S+ (\S+)/ + ); ${$d{-rock}} = $1; }, -rock => \$qr}, @@ -583,7 +587,7 @@ sub listquotaroot { -callback => sub { my %d = @_; return unless - $d{-text} =~ s/^\S+ \((\S+) (\S+) (\S+)\)//; + $d{-text} =~ s/\((\S+) (\S+) (\S+)\)$//; push @{$d{-rock}}, $1, [$2, $3]; }, -rock => \@info}); diff --git a/ptclient/ldap.c b/ptclient/ldap.c index e6cbc5d71..5d324e5f2 100644 --- a/ptclient/ldap.c +++ b/ptclient/ldap.c @@ -932,7 +932,7 @@ static int ptsmodule_get_dn( { rc = ptsmodule_expand_tokens(ptsm->filter, canon_id, NULL, &filter); if (rc != PTSM_OK) - return rc; + goto done; if (ptsm->domain_base_dn && ptsm->domain_base_dn[0] != '\0' && (strrchr(canon_id, '@') == NULL)) { syslog(LOG_DEBUG, "collecting all domains from %s", ptsm->domain_base_dn); @@ -948,15 +948,18 @@ static int ptsmodule_get_dn( syslog(LOG_ERR, "LDAP not available: %s", ldap_err2string(rc)); ldap_unbind(ptsm->ld); ptsm->ld = NULL; - return PTSM_RETRY; + rc = PTSM_RETRY; + goto done; } syslog(LOG_ERR, "LDAP search for domain failed: %s", ldap_err2string(rc)); - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } if (ldap_count_entries(ptsm->ld, res) < 1) { syslog(LOG_ERR, "No domain found"); - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } else if (ldap_count_entries(ptsm->ld, res) >= 1) { int count_matches = 0; char *temp_base = NULL; @@ -976,10 +979,12 @@ static int ptsmodule_get_dn( if (count_matches > 1) { syslog(LOG_ERR, "LDAP search for %s failed because it matches multiple accounts.", canon_id); - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } else if (count_matches == 0) { syslog(LOG_ERR, "LDAP search for %s failed because it does not match any account in all domains.", canon_id); - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } syslog(LOG_DEBUG, "we have found %s in %s", canon_id, base); @@ -1006,19 +1011,23 @@ static int ptsmodule_get_dn( ldap_unbind(ptsm->ld); ptsm->ld = NULL; syslog(LOG_ERR, "LDAP not available: %s", ldap_err2string(rc)); - return PTSM_RETRY; + rc = PTSM_RETRY; + goto done; } syslog(LOG_ERR, "LDAP search for domain failed: %s", ldap_err2string(rc)); - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } if (ldap_count_entries(ptsm->ld, res) < 1) { syslog(LOG_ERR, "No domain %s found", domain); - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } else if (ldap_count_entries(ptsm->ld, res) > 1) { syslog(LOG_ERR, "Multiple domains %s found", domain); - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } else { if ((entry = ldap_first_entry(ptsm->ld, res)) != NULL) { if ((vals = ldap_get_values(ptsm->ld, entry, ptsm->domain_result_attribute)) != NULL) { @@ -1033,7 +1042,7 @@ static int ptsmodule_get_dn( } if (rc != PTSM_OK) { - return rc; + goto done; } else { base = xstrdup(ptsm->base); syslog(LOG_DEBUG, "Continuing with ptsm->base: %s", ptsm->base); @@ -1044,23 +1053,23 @@ static int ptsmodule_get_dn( } else { rc = ptsmodule_expand_tokens(ptsm->base, canon_id, NULL, &base); if (rc != PTSM_OK) - return rc; + goto done; } rc = ldap_search_st(ptsm->ld, base, ptsm->scope, filter, attrs, 0, &(ptsm->timeout), &res); if (rc != LDAP_SUCCESS) { - syslog(LOG_DEBUG, "Searching %s with %s failed", base, base); - free(filter); - free(base); + syslog(LOG_DEBUG, "Searching %s with %s failed", base, filter); if (rc == LDAP_SERVER_DOWN) { ldap_unbind(ptsm->ld); ptsm->ld = NULL; - return PTSM_RETRY; + rc = PTSM_RETRY; + goto done; } - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } free(filter); @@ -1086,6 +1095,13 @@ static int ptsmodule_get_dn( } return (*ret ? PTSM_OK : PTSM_FAIL); + + done: + if (filter) + free(filter); + if (base) + free(base); + return rc; } @@ -1320,11 +1336,15 @@ static int ptsmodule_make_authstate_filter( syslog(LOG_ERR, "No values for attribute '%s' on entry '%s'", ptsm->member_attribute, errdn); + *reply = "no values"; + rc = PTSM_FAIL; + ldap_value_free(vals); + vals = NULL; + goto done; } else if (ldap_count_values(vals) > 1) { syslog(LOG_ERR, "Too many values for attribute '%s' on entry '%s'", ptsm->member_attribute, errdn); - } else { *reply = "too many values"; rc = PTSM_FAIL; ldap_value_free(vals); @@ -1388,13 +1408,14 @@ static int ptsmodule_make_authstate_group( if (strncmp(canon_id, "group:", 6)) { // Sanity check *reply = "not a group identifier"; - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } rc = ptsmodule_connect(); if (rc != PTSM_OK) { *reply = "ptsmodule_connect() failed"; - return rc; + goto done; } rc = ptsmodule_expand_tokens(ptsm->group_filter, canon_id+6, NULL, &filter); @@ -1425,17 +1446,19 @@ static int ptsmodule_make_authstate_group( if (rc != LDAP_SUCCESS) { syslog(LOG_DEBUG, "(groups) Result from domain query not OK"); - return rc; + goto done; } else { syslog(LOG_DEBUG, "(groups) Result from domain query OK"); } if (ldap_count_entries(ptsm->ld, res) < 1) { syslog(LOG_ERR, "(groups) No domain %s found", domain); - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } else if (ldap_count_entries(ptsm->ld, res) > 1) { syslog(LOG_ERR, "(groups) Multiple domains %s found", domain); - return PTSM_FAIL; + rc = PTSM_FAIL; + goto done; } else { syslog(LOG_DEBUG, "(groups) Domain %s found", domain); if ((entry = ldap_first_entry(ptsm->ld, res)) != NULL) { @@ -1452,7 +1475,7 @@ static int ptsmodule_make_authstate_group( } if (rc != PTSM_OK) { - return rc; + goto done; } else { base = xstrdup(ptsm->group_base); syslog(LOG_DEBUG, "Continuing with ptsm->group_base: %s", ptsm->group_base); @@ -1462,7 +1485,7 @@ static int ptsmodule_make_authstate_group( } else { rc = ptsmodule_expand_tokens(ptsm->group_base, canon_id, NULL, &base); if (rc != PTSM_OK) - return rc; + goto done; } syslog(LOG_DEBUG, "(groups) about to search %s for %s", base, filter); diff --git a/ptclient/ptdump.c b/ptclient/ptdump.c index fb59a894f..6676e3884 100644 --- a/ptclient/ptdump.c +++ b/ptclient/ptdump.c @@ -71,11 +71,11 @@ static int dump_cb(void *rockp __attribute__((unused)), int main(int argc, char *argv[]) { struct db *ptdb; - char fnamebuf[1024]; extern char *optarg; int opt; int r; - char *alt_config = NULL; + const char *fname; + char *alt_config = NULL, *tofree = NULL; while ((opt = getopt(argc, argv, "C:")) != EOF) { switch (opt) { @@ -95,15 +95,21 @@ int main(int argc, char *argv[]) cyrus_init(alt_config, "ptdump", 0, 0); /* open database */ - strcpy(fnamebuf, config_dir); - strcat(fnamebuf, PTS_DBFIL); - r = cyrusdb_open(config_ptscache_db, fnamebuf, CYRUSDB_CREATE, &ptdb); + fname = config_getstring(IMAPOPT_PTSCACHE_DB_PATH); + if (!fname) { + tofree = strconcat(config_dir, PTS_DBFIL, NULL); + fname = tofree; + } + + r = cyrusdb_open(config_ptscache_db, fname, CYRUSDB_CREATE, &ptdb); if(r != CYRUSDB_OK) { - fprintf(stderr,"error opening %s (%s)", fnamebuf, + fprintf(stderr,"error opening %s (%s)", fname, cyrusdb_strerror(r)); exit(1); } + if (tofree) free(tofree); + /* iterate through db, wiping expired entries */ cyrusdb_foreach(ptdb, "", 0, NULL, dump_cb, ptdb, NULL); diff --git a/ptclient/ptexpire.c b/ptclient/ptexpire.c index e8eeaa7f9..96abfca43 100644 --- a/ptclient/ptexpire.c +++ b/ptclient/ptexpire.c @@ -102,11 +102,11 @@ static int expire_cb(void *rockp, int main(int argc, char *argv[]) { struct db *ptdb; - char fnamebuf[1024]; extern char *optarg; int opt; int r; - char *alt_config = NULL; + const char *fname; + char *alt_config = NULL, *tofree = NULL; if ((geteuid()) == 0 && (become_cyrus(/*is_master*/0) != 0)) { fatal("must run as the Cyrus user", EC_USAGE); @@ -142,15 +142,21 @@ int main(int argc, char *argv[]) syslog(LOG_DEBUG, "ptexpire.c %s", PACKAGE_VERSION); /* open database */ - strcpy(fnamebuf, config_dir); - strcat(fnamebuf, PTS_DBFIL); - r = cyrusdb_open(config_ptscache_db, fnamebuf, CYRUSDB_CREATE, &ptdb); + fname = config_getstring(IMAPOPT_PTSCACHE_DB_PATH); + if (!fname) { + tofree = strconcat(config_dir, PTS_DBFIL, NULL); + fname = tofree; + } + + r = cyrusdb_open(config_ptscache_db, fname, CYRUSDB_CREATE, &ptdb); if(r != CYRUSDB_OK) { - syslog(LOG_ERR, "error opening %s (%s)", fnamebuf, + syslog(LOG_ERR, "error opening %s (%s)", fname, cyrusdb_strerror(r)); exit(1); } + if (tofree) free(tofree); + /* iterate through db, wiping expired entries */ cyrusdb_foreach(ptdb, "", 0, expire_p, expire_cb, ptdb, NULL); diff --git a/ptclient/ptloader.c b/ptclient/ptloader.c index b425afd79..ef6877f97 100644 --- a/ptclient/ptloader.c +++ b/ptclient/ptloader.c @@ -119,9 +119,6 @@ struct auth_state *ptsmodule_make_authstate(const char *identifier, /* config.c info (libimap) */ const int config_need_data = 0; -/* Globals */ -#define DB (config_ptscache_db) - static char ptclient_debug = 0; struct db *ptsdb = NULL; @@ -129,8 +126,9 @@ int service_init(int argc, char *argv[], char **envp __attribute__((unused))) { int r; int opt; - char fnamebuf[1024]; extern char *optarg; + const char *fname; + char *tofree = NULL; if (geteuid() == 0) fatal("must run as the Cyrus user", EC_USAGE); setproctitle_init(argc, argv, envp); @@ -155,15 +153,21 @@ int service_init(int argc, char *argv[], char **envp __attribute__((unused))) } } - strcpy(fnamebuf, config_dir); - strcat(fnamebuf, PTS_DBFIL); - r = cyrusdb_open(DB, fnamebuf, CYRUSDB_CREATE, &ptsdb); + fname = config_getstring(IMAPOPT_PTSCACHE_DB_PATH); + if (!fname) { + tofree = strconcat(config_dir, PTS_DBFIL, NULL); + fname = tofree; + } + + r = cyrusdb_open(config_ptscache_db, fname, CYRUSDB_CREATE, &ptsdb); if (r != 0) { - syslog(LOG_ERR, "DBERROR: opening %s: %s", fnamebuf, + syslog(LOG_ERR, "DBERROR: opening %s: %s", fname, cyrusdb_strerror(ret)); fatal("can't read pts database", EC_TEMPFAIL); } + if (tofree) free(tofree); + ptsmodule_init(); return 0; diff --git a/docsrc/conf.py b/docsrc/conf.py index 174263c5a..f68db4157 100644 --- a/docsrc/conf.py +++ b/docsrc/conf.py @@ -92,9 +92,9 @@ copyright = u'1993-2017, The Cyrus Team' # May need to also update toplevel index.rst to point to other versions. # # The short X.Y version. -version = '3.0.8' +version = '3.0.9' # The full version, including alpha/beta/rc tags. -release = '3.0.8 (stable)' +release = '3.0.9 (stable)' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -424,11 +424,11 @@ epub_exclude_files = ['search.html'] # When this is updated, you may also need to update the version and release # definitions listed above to stay up to date. rst_prolog = """ -.. |imap_last_stable_version| replace:: 2.5.11 +.. |imap_last_stable_version| replace:: 2.5.12 .. |imap_last_stable_branch| replace:: `cyrus-imapd-2.5` -.. |imap_current_stable_version| replace:: 3.0.8 +.. |imap_current_stable_version| replace:: 3.0.9 .. |imap_current_stable_branch| replace:: `cyrus-imapd-3.0` -.. |imap_latest_development_version| replace:: 3.1.5 +.. |imap_latest_development_version| replace:: 3.1.6 .. |imap_latest_development_branch| replace:: master .. |imap_tikanga_stock_version| replace:: 2.3.7 .. |imap_santiago_stock_version| replace:: 2.3.16 @@ -438,14 +438,14 @@ rst_prolog = """ .. |imap_utopic_stock_version| replace:: 2.4.17+caldav~beta10-5 .. |imap_vivid_stock_version| replace:: 2.4.17+caldav~beta10-17 .. |imap_wily_stock_version| replace:: 2.4.17+caldav~beta10-17 -.. |sasl_current_stable_version| replace:: 2.1.26 +.. |sasl_current_stable_version| replace:: 2.1.27 .. |imap_stable_release_notes| raw:: html - <a href="3.0/x/3.0.8.html">3.0.8</a> + <a href="3.0/x/3.0.9.html">3.0.9</a> .. |imap_development_release_notes| raw:: html - <a href="3.1/x/3.1.5.html">3.1.5</a> + <a href="3.1/x/3.1.6.html">3.1.6</a> """ diff --git a/docsrc/imap/concepts/deployment/authentication_and_authorization.rst b/docsrc/imap/concepts/deployment/authentication_and_authorization.rst index f8308bc9a..71df519a0 100644 --- a/docsrc/imap/concepts/deployment/authentication_and_authorization.rst +++ b/docsrc/imap/concepts/deployment/authentication_and_authorization.rst @@ -7,13 +7,13 @@ Typically, an authentication and authorization database, such as for example LDA For example, when a user wants to set group permissions on an IMAP folder, the most intuitive attribute in LDAP to refer to the group is the Common Name (CN). This attribute however is not guaranteed to be unique. Uniqueness can be enforced within LDAP, although that may be too restrictive, and so the groups available in Cyrus IMAP can be limited to scope one, while the cn is used in the rdn (the cn is the naming attribute to compose the dn with); effectively enforcing uniqueness for those groups available to Cyrus IMAP. -Similarly, many deployments choose to use the mail LDAP attribute value as the mailbox name, while mail is a multi-valued attribute and is not configured to be enforced globally unique in the LDAP information tree under the root dn. In addition, attributes such as amilAlternateAddress and/or alias could potentially hold the same value as anyone's mail attribute. These limitations or such implications become very clear when canonification of the authentication ID to the desired authorization ID is attempted. +Similarly, many deployments choose to use the mail LDAP attribute value as the mailbox name, while mail is a multi-valued attribute and is not configured to be enforced globally unique in the LDAP information tree under the root dn. In addition, attributes such as ``mailAlternativeAddress`` and/or alias could potentially hold the same value as anyone's mail attribute. These limitations or such implications become very clear when canonification of the authentication ID to the desired authorization ID is attempted. -For example, if <literal>jdoe</literal> is the login username, and Cyrus IMAP has a default realm configured <literal>example.org</literal>, the authentication ID becomes <literal>j...@example.org</literal>. It is this authentication ID, and not the supplied login username, that Cyrus IMAP uses to verify the credentials. +For example, if ``jdoe`` is the login username, and Cyrus IMAP has a default realm configured ``example.org``, the authentication ID becomes ``j...@example.org``. It is this authentication ID, and not the supplied login username, that Cyrus IMAP uses to verify the credentials. -Cyrus IMAP thereafter allows authorization mechanisms, such as <emphasis>ptclient</emphasis> modules, to canonify the authentication ID to then ultimately return the authorization ID. +Cyrus IMAP thereafter allows authorization mechanisms, such as *ptclient* modules, to canonify the authentication ID to then ultimately return the authorization ID. -Suppose in the case of <literal>j...@example.org</literal>, where the authentication ID had been set, an LDAP module for ptloader could search LDAP for a <literal>uid=%U</literal> (where %U is the local part of the authentication ID), find the mail attribute value is <literal>john....@example.org</literal>, and authorize the user as such. Effectively, this enables Cyrus IMAP users to log in both with their username (uid) as well as their email address (or any of the aliases). +Suppose in the case of ``j...@example.org``, where the authentication ID had been set, an LDAP module for ptloader could search LDAP for a ``uid=%U`` (where ``%U`` is the local part of the authentication ID), find the mail attribute value is ``john....@example.org``, and authorize the user as such. Effectively, this enables Cyrus IMAP users to log in both with their username (uid) as well as their email address (or any of the aliases). The process of client authentication and authorization @@ -30,7 +30,7 @@ The exchange and verification of identity information provided by a client, othe The most common set of credentials is a *username* and *password*, but other forms exist like Kerberos v5 ticket exchange (for which, to obtain such, most often a password is supplied), or certificate based authentication (the secret keys for which are most often locked with a passphrase). In any case, authentication works based on a shared secret, and/or a trusted source for verification. Kerberos v5 works based on shared secrets (keytab), and certificate based authentication works based on shared, trusted sources for verification. -In the case of usernames and passwords though, the exchange and verification of the credentials is at the basis of its security. Sending plain text usernames and passwords over the wire would not allow any application to verify the source of the credentials is actually the user –who is supposed to be the only party to know the unique combination of username and password. +In the case of usernames and passwords though, the exchange and verification of the credentials is at the basis of its security. Sending plain text usernames and passwords over the wire would not allow any application to verify the source of the credentials is actually the user — who is supposed to be the only party to know the unique combination of username and password. To obfuscate the login credentials, authentication can be encrypted with CRAM-MD5 or DIGEST-MD5, but this requires the server to have a copy of the original, plain text password. The password in this case becomes the shared secret. @@ -43,13 +43,13 @@ User mailboxes have a globally unique identifier which is not necessarily the sa The **user login credentials** that are associated with the user authentication entity and verify the user is who the user claims to be. -For example, the user logs in with username <code>john....@example.org</code> and password <code>verysecret</code>. +For example, the user logs in with username ``john....@example.org`` and password ``verysecret``. -The **user's authentication entity** - with all attributes associated with it - can have one of those attributes be used to create the relationship between the user authentication entity on the one side, and the mailbox entity on the other side. +The **user's authentication entity** — with all attributes associated with it — can have one of those attributes be used to create the relationship between the user authentication entity on the one side, and the mailbox entity on the other side. -For example, the user that authenticated as <code>john....@example.org</code> may have a mailbox named <code>jdoe</code>. +For example, the user that authenticated as ``john....@example.org`` may have a mailbox named ``jdoe``. The **authorization entity**, used to assign certain permissions to the user, uses the same attribute used to determine the mailbox name. -For example, the user that authenticated as <code>john....@example.com</code> and has mailbox <code>jdoe</code> needs an access control list entry on that mailbox that assigns <code>jdoe</code> certain rights on said mailbox. +For example, the user that authenticated as ``john....@example.com`` and has mailbox ``jdoe`` needs an access control list entry on that mailbox that assigns ``jdoe`` certain rights on said mailbox. diff --git a/docsrc/imap/concepts/deployment/databases.rst b/docsrc/imap/concepts/deployment/databases.rst index 240897bc2..39252b5a8 100644 --- a/docsrc/imap/concepts/deployment/databases.rst +++ b/docsrc/imap/concepts/deployment/databases.rst @@ -370,20 +370,20 @@ slow for reads and writes, and is easily corrupted. Twoskip ------- -**Recommended**. A robust implementation of `https://en.wikipedia.org/wiki/Skip_list <Skip List>`_. -Developers interested in the details can find more information at `http://opera.brong.fastmail.fm.user.fm/talks/twoskip/twoskip-yapc12.pdf <these talk slides>`_. +**Recommended**. A robust implementation of `Skip List <https://en.wikipedia.org/wiki/Skip_list>`_. +Developers interested in the details can find more information at `these talk slides <http://opera.brong.fastmail.fm.user.fm/talks/twoskip/twoskip-yapc12.pdf>`_. Skiplist -------- -An implementation of the `https://en.wikipedia.org/wiki/Skip_list <Skip List>`_ +An implementation of the `Skip List <https://en.wikipedia.org/wiki/Skip_list>`_ data structure. Deprecated in favour of `Twoskip`_ as it is not robust in the face of disk failure. lmdb ---- -`http://symas.com/mdb <Lightning Memory-Mapped Database (lmdb)>`_ is a +`Lightning Memory-Mapped Database (lmdb) <http://symas.com/mdb>`_ is a high-performance transactional key-value store. Fast while in memory, but slow when the database is loaded. Best for databases diff --git a/docsrc/imap/developer/install-xapian.rst b/docsrc/imap/developer/install-xapian.rst index fb8b78df5..3122f18e1 100644 --- a/docsrc/imap/developer/install-xapian.rst +++ b/docsrc/imap/developer/install-xapian.rst @@ -46,7 +46,7 @@ Xapian requires a running :cyrusman:`squatter(8)` instance: * In :cyrusman:`cyrus.conf(5)` set up a daemon squatter to run: :: - START { + DAEMON { # run a rolling squatter squatter cmd="squatter -R" } diff --git a/docsrc/imap/download/release-notes/2.5/x/2.5.12.rst b/docsrc/imap/download/release-notes/2.5/x/2.5.12.rst new file mode 100644 index 000000000..8cdc12674 --- /dev/null +++ b/docsrc/imap/download/release-notes/2.5/x/2.5.12.rst @@ -0,0 +1,73 @@ +:tocdepth: 3 + +=============================== +Cyrus IMAP 2.5.12 Release Notes +=============================== + +.. IMPORTANT:: + + This is a bug-fix release in the `stable 2.5 series <http://www.cyrusimap.org/stable>`_. + + Refer to the Cyrus IMAP 2.5.0 Release Notes for important information + about the 2.5 series, including upgrading instructions. + +Download via HTTPS: + + * https://github.com/cyrusimap/cyrus-imapd/releases/download/cyrus-imapd-2.5.12/cyrus-imapd-2.5.12.tar.gz + * https://github.com/cyrusimap/cyrus-imapd/releases/download/cyrus-imapd-2.5.12/cyrus-imapd-2.5.12.tar.gz.sig + +.. _relnotes-2.5.12-changes: + +Changes Since 2.5.11 +==================== + +Release changes +--------------- + +We’re trialing using the Github Releases feature. If you have trouble +downloading this release, please report this to the mailing lists. Thanks! + +Dependency changes +------------------ + +ClamAV now configures and builds correctly, using pkg-config for detection. +You can use the ``--without-clamav`` option to configure if you have ClamAV +installed but do *not* want to build Cyrus with support for it. The old +``--with-clamav=DIR`` variant no longer works (but it also didn't work before!) + +Cyrus should now build cleanly with LibreSSL 2.7 (thanks Bernard Spil). + +Other changes +------------- + +* Cyrus release version is now preserved across autoreconf runs. This means + it is now safe to run autoreconf on a release tarball source tree. + +Bug fixes +--------- + +* Fixed: cyr_virusscan now integrates with event notifications properly +* Fixed: mailbox expunge event notifications no longer cause a crash +* Fixed :issue:`2378`: ACLs containing spaces no longer break mailboxes.db +* Fixed :issue:`2253`: master now rejects unix domain listen paths that are too + long +* Fixed: smilint warnings for CYRUS-MASTER.mib fixed (thanks Fabrice Bacchella) +* Fixed :issue:`2177`: backend connections no longer ignore STARTTLS failures + (thanks Wolfgang Breyha) +* Fixed :issue:`2222`: dav_reconstruct no longer crashes on expunged entries +* Fixed :issue:`2221`: dav_reconstruct no longer crashes given bad user id + (thanks Wolfgang Breyha) +* Fixed: tls_prune memory leak +* Fixed: tls_prune doesn't fail when tls_sessions.db is missing +* Fixed :issue:`2199`: recovery from mupdate failure now in correct order + (thanks Michael Menge) +* Fixed: backend connections no longer crash if no banner found +* Fixed: backend connections no longer return success on certain types of failure +* Fixed :issue:`2185`: squatter no longer tries to index non-IMAP mailboxes + (thanks Wolfgang Breyha) +* Fixed: special-use proxying in murder (thanks Wolfgang Breyha) +* Fixed :issue:`1090`: send OK NIL to subsequent ID commands +* Fixed :issue:`1434`: auth_pts will now error when given a too-long socket file name +* Fixed :issue:`1964`: correctly detect when librt is needed +* Fixed :issue:`1967`: tell EXISTS count earlier when needed +* Fixed: memory leak in httpd DAV support diff --git a/docsrc/imap/download/release-notes/3.0/x/3.0.9.rst b/docsrc/imap/download/release-notes/3.0/x/3.0.9.rst new file mode 100644 index 000000000..1e8506775 --- /dev/null +++ b/docsrc/imap/download/release-notes/3.0/x/3.0.9.rst @@ -0,0 +1,68 @@ +:tocdepth: 3 + +=============================== +Cyrus IMAP 3.0.9 Release Notes +=============================== + +.. IMPORTANT:: + + This is a bug-fix release in the stable 3.0 series. + + Refer to the Cyrus IMAP 3.0.0 Release Notes for important information + about the 3.0 series, including upgrading instructions. + +Download via HTTPS: + + * https://github.com/cyrusimap/cyrus-imapd/releases/download/cyrus-imapd-3.0.9/cyrus-imapd-3.0.9.tar.gz + * https://github.com/cyrusimap/cyrus-imapd/releases/download/cyrus-imapd-3.0.9/cyrus-imapd-3.0.9.tar.gz.sig + + +.. _relnotes-3.0.9-changes: + +Changes Since 3.0.8 +=================== + +Release changes +--------------- + +We're trialing using the Github Releases feature. If you have trouble downloading +this release, please report this to the mailing lists. Thanks! + +Dependency changes +------------------ + +* ClamAV 0.101 is now supported (thanks Adam Gołębiowski) + +New configuration options +------------------------- + +* The new ``cyrus_group`` option in :cyrusman:`imapd.conf(5)` can be used to + set the UNIX group that Cyrus processes run as (thanks Jakob Gahde). The + default is to use the primary group of the configured ``cyrus_user``. The + old ``--with-cyrus-group`` configure option has been non-functional for many + years, and has been removed. + +Bug fixes +--------- + +* Fixed :issue:`2521`: cyradm getquotaroot now supports mailbox names + containing spaces (thanks Marco Favero) +* Fixed :issue:`2524`: ipurge no longer crashes on partial name matches +* Fixed: various memory leaks (thanks Pavel Zhukov) +* Fixed :issue:`2534`: com_err now built early enough (thanks + Дилян Палаузов) +* Fixed :issue:`2566`: idle socket setup no longer wrapped by asserts (thanks + Zan Lynx) +* Fixed :issue:`2597`: lmtpd segfault with sieve redirections on shared folder + (thanks Anthony Prades) +* Fixed :issue:`2449`: lmtpd segfault with sieve rejections on shared folder + (thanks Anthony Prades) +* Fixed :issue:`2609`: mbexamine now correctly handles mailbox where all mail + is archived and ``archive-partition`` and ``meta-partition`` are enabled + (thanks Michael Menge) +* Fixed :issue:`2625`: the ``ptscache_db_path`` setting now works correctly +* Fixed :issue:`2643`: ptclient now returns correct group names when resolved + by filter (thanks Felix Schumacher) +* Fixed: conversationsdb now stores GUID even if message has no CID +* Fixed :issue:`2663`: Q-encoded MIME headers no longer split multi-octet + UTF words (thanks Дилян Палаузов)