summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Wickert <wickert@kolabsys.com>2011-09-17 13:49:37 (GMT)
committerChristoph Wickert <wickert@kolabsys.com>2011-09-17 13:49:37 (GMT)
commit7a5433de527d0f039fdf14a3b59dfef8c4e0e7c4 (patch)
treececb2b865491efa08fb8ab01ca64566a49bb7391
parent4066b337abde1d573bed6d1f96e39742303de89b (diff)
downloadserver-7a5433de527d0f039fdf14a3b59dfef8c4e0e7c4.tar.gz
imapd: Add missing patches for 2.3.17
-rw-r--r--imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Cyradm_Annotations.patch82
-rw-r--r--imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Folder-names.patch17
-rw-r--r--imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Groups2.patch233
-rw-r--r--imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Logging.patch39
-rw-r--r--imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_UID.patch117
-rw-r--r--imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_cross-domain-acls.patch375
-rw-r--r--imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_timsieved_starttls-sendcaps.patch21
-rw-r--r--imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_workaround-for-missing-user_deny.db.patch42
-rw-r--r--imapd/patches/cyrus-imapd-2.3.17/series9
9 files changed, 935 insertions, 0 deletions
diff --git a/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Cyradm_Annotations.patch b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Cyradm_Annotations.patch
new file mode 100644
index 0000000..08cbe6b
--- /dev/null
+++ b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Cyradm_Annotations.patch
@@ -0,0 +1,82 @@
+Allows to use arbitrary annotations with the cyradm tool.
+
+diff -r 69927cac0b1b doc/man/cyradm.1.html
+--- a/doc/man/cyradm.1.html Fri Dec 04 10:32:26 2009 +0100
++++ b/doc/man/cyradm.1.html Fri Dec 04 10:32:33 2009 +0100
+@@ -220,6 +220,13 @@
+ <dd>
+ <p>Sets an email address to which messages injected into the server via NNTP
+ will be sent.</p>
++</dd>
++</li>
++<dt><strong><a NAME="item__2fexplicit_2fannotation"><code>/explicit/annotation</code></a></strong>
++
++<dd>
++<p>Sets the annotation <em>/explicit/annotation</em>
++on <em>mailbox</em> to <em>value</em>.</p>
+ </dd>
+ <dt><strong><a name="sharedseen" class="item"><code>sharedseen</code></a></strong></dt>
+
+diff -r 69927cac0b1b perl/imap/IMAP/Admin.pm
+--- a/perl/imap/IMAP/Admin.pm Fri Dec 04 10:32:26 2009 +0100
++++ b/perl/imap/IMAP/Admin.pm Fri Dec 04 10:32:33 2009 +0100
+@@ -797,11 +797,11 @@
+ return undef;
+ }
+
+- if(!exists($values{$entry})) {
+- $self->{error} = "Unknown parameter $entry";
++ if(exists($values{$entry})) {
++ $entry = $values{$entry};
++ } else {
++ $self->{error} = "Unknown parameter $entry" unless substr($entry,0,1) eq "/";
+ }
+-
+- $entry = $values{$entry};
+
+ my ($rc, $msg);
+
+diff -r 69927cac0b1b perl/imap/IMAP/Shell.pm
+--- a/perl/imap/IMAP/Shell.pm Fri Dec 04 10:32:26 2009 +0100
++++ b/perl/imap/IMAP/Shell.pm Fri Dec 04 10:32:33 2009 +0100
+@@ -127,7 +127,7 @@
+ [\&_sc_info, '[mailbox]',
+ 'display mailbox/server metadata'],
+ mboxcfg =>
+- [\&_sc_mboxcfg, 'mailbox [comment|condstore|expire|news2mail|sharedseen|sieve|squat] value',
++ [\&_sc_mboxcfg, 'mailbox [comment|condstore|news2mail|expire|sieve|squat|/<explicit annotation>] value',
+ 'configure mailbox'],
+ mboxconfig => 'mboxcfg',
+ reconstruct =>
+@@ -1437,7 +1437,7 @@
+ while (defined ($opt = shift(@argv))) {
+ last if $opt eq '--';
+ if ($opt =~ /^-/) {
+- die "usage: mboxconfig mailbox [comment|condstore|expire|news2mail|sharedseen|sieve|squat] value\n";
++ die "usage: mboxconfig mailbox [comment|condstore|expire|news2mail|sharedseen|sieve|squat|/<explicit annotation>] value\n";
+ }
+ else {
+ push(@nargv, $opt);
+@@ -1446,7 +1446,7 @@
+ }
+ push(@nargv, @argv);
+ if (@nargv < 2) {
+- die "usage: mboxconfig mailbox [comment|condstore|expire|news2mail|sharedseen|sieve|squat] value\n";
++ die "usage: mboxconfig mailbox [comment|condstore|expire|news2mail|sharedseen|sieve|squat|/<explicit annotation>] value\n";
+ }
+ if (!$cyrref || !$$cyrref) {
+ die "mboxconfig: no connection to server\n";
+diff -r 69927cac0b1b perl/imap/cyradm.sh
+--- a/perl/imap/cyradm.sh Fri Dec 04 10:32:26 2009 +0100
++++ b/perl/imap/cyradm.sh Fri Dec 04 10:32:33 2009 +0100
+@@ -241,6 +241,10 @@
+
+ Indicates that the mailbox should have a squat index created for it.
+
++=item C</explicit/annotation>
++
++Sets the annotation I</explicit/annotation> on I<mailbox> to I<value>.
++
+ =back
+
+ =item C<renamemailbox> [C<--partition> I<partition>] I<oldname> I<newname>
diff --git a/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Folder-names.patch b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Folder-names.patch
new file mode 100644
index 0000000..2f8689a
--- /dev/null
+++ b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Folder-names.patch
@@ -0,0 +1,17 @@
+Modifies the set of accepted characters in folder names for the cyrus imapd server [Version: 2.3.9]
+
+diff -r 17e54b46d7b6 imap/mboxname.c
+--- a/imap/mboxname.c Mon Oct 27 18:44:56 2008 +0100
++++ b/imap/mboxname.c Mon Oct 27 18:47:11 2008 +0100
+@@ -713,8 +713,10 @@
+ /*
+ * Apply site policy restrictions on mailbox names.
+ * Restrictions are hardwired for now.
++ * original definition
++#define GOODCHARS " #$'+,-.0123456789:=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"
+ */
+-#define GOODCHARS " #$'+,-.0123456789:=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"
++#define GOODCHARS " #$%'()*+,-.0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~"
+ int mboxname_policycheck(char *name)
+ {
+ unsigned i;
diff --git a/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Groups2.patch b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Groups2.patch
new file mode 100644
index 0000000..0cb71d8
--- /dev/null
+++ b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Groups2.patch
@@ -0,0 +1,233 @@
+diff -r 37030bf2b2bb lib/auth_unix.c
+--- a/lib/auth_unix.c Fri Dec 04 10:25:24 2009 +0100
++++ b/lib/auth_unix.c Fri Dec 04 10:32:19 2009 +0100
+@@ -46,6 +46,7 @@
+ #include <stdlib.h>
+ #include <pwd.h>
+ #include <grp.h>
++#include <stdio.h>
+ #include <ctype.h>
+ #include <string.h>
+
+@@ -54,6 +55,126 @@
+ #include "xmalloc.h"
+ #include "util.h"
+
++#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
++/*
++ * __getgrent.c - This file is part of the libc-8086/grp package for ELKS,
++ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the Free
++ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++
++static struct group *__getgrent(int grp_fd, char *line_buff, char **members)
++{
++ short line_index;
++ short buff_size;
++ static struct group group;
++ register char *ptr;
++ char *field_begin;
++ short member_num;
++ char *endptr;
++ int line_len;
++
++ /* We use the restart label to handle malformatted lines */
++ restart:
++ line_index = 0;
++ buff_size = 256;
++
++ line_buff = realloc(line_buff, buff_size);
++ while (1) {
++ if ((line_len = read(grp_fd, line_buff + line_index,
++ buff_size - line_index)) <= 0) {
++ return NULL;
++ }
++ field_begin = strchr(line_buff, '\n');
++ if (field_begin != NULL) {
++ lseek(grp_fd,
++ (long) (1 + field_begin -
++ (line_len + line_index + line_buff)), SEEK_CUR);
++ *field_begin = '\0';
++ if (*line_buff == '#' || *line_buff == ' '
++ || *line_buff == '\n' || *line_buff == '\t')
++ goto restart;
++ break;
++ } else {
++ /* Allocate some more space */
++ line_index = buff_size;
++ buff_size += 256;
++ line_buff = realloc(line_buff, buff_size);
++ }
++ }
++
++ /* Now parse the line */
++ group.gr_name = line_buff;
++ ptr = strchr(line_buff, ':');
++ if (ptr == NULL)
++ goto restart;
++ *ptr++ = '\0';
++
++ group.gr_passwd = ptr;
++ ptr = strchr(ptr, ':');
++ if (ptr == NULL)
++ goto restart;
++ *ptr++ = '\0';
++
++ field_begin = ptr;
++ ptr = strchr(ptr, ':');
++ if (ptr == NULL)
++ goto restart;
++ *ptr++ = '\0';
++
++ group.gr_gid = (gid_t) strtoul(field_begin, &endptr, 10);
++ if (*endptr != '\0')
++ goto restart;
++
++ member_num = 0;
++ field_begin = ptr;
++
++ if (members != NULL)
++ free(members);
++ members = (char **) malloc((member_num + 1) * sizeof(char *));
++ for ( ; field_begin && *field_begin != '\0'; field_begin = ptr) {
++ if ((ptr = strchr(field_begin, ',')) != NULL)
++ *ptr++ = '\0';
++ members[member_num++] = field_begin;
++ members = (char **) realloc(members,
++ (member_num + 1) * sizeof(char *));
++ }
++ members[member_num] = NULL;
++
++ group.gr_mem = members;
++ return &group;
++}
++
++static char *line_buff = NULL;
++static char **members = NULL;
++
++struct group *fgetgrent(FILE *file)
++{
++ if (file == NULL) {
++ errno = EINTR;
++ return NULL;
++ }
++ return __getgrent(fileno(file), line_buff, members);
++}
++#endif /* __FreeBSD__ */
++
+ struct auth_state {
+ char userid[81];
+ char **group;
+@@ -141,6 +262,25 @@
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
++static struct group* fgetgrnam(const char* name)
++{
++ struct group *grp;
++ FILE *groupfile;
++
++ groupfile = fopen("/etc/imapd.group", "r");
++ if (!groupfile) groupfile = fopen("/etc/group", "r");
++ if (groupfile) {
++ while ((grp = fgetgrent(groupfile))) {
++ if (strcmp(grp->gr_name, name) == 0) {
++ fclose(groupfile);
++ return grp;
++ }
++ }
++ }
++ if (groupfile) fclose(groupfile);
++ return NULL;
++}
++
+ /*
+ * Convert 'identifier' into canonical form.
+ * Returns a pointer to a static buffer containing the canonical form
+@@ -176,7 +316,7 @@
+ */
+
+ if (!strncmp(retbuf, "group:", 6)) {
+- grp = getgrnam(retbuf+6);
++ grp = fgetgrnam(retbuf+6);
+ if (!grp) return NULL;
+ if (strlen(grp->gr_name) >= sizeof(retbuf)-6)
+ return NULL;
+@@ -224,11 +364,12 @@
+ struct auth_state *newstate;
+ struct passwd *pwd;
+ struct group *grp;
+-#if defined(HAVE_GETGROUPLIST) && defined(__GLIBC__)
++#if 0 && defined(HAVE_GETGROUPLIST) && defined(__GLIBC__)
+ gid_t gid, *groupids = NULL;
+ int ret, ngroups = 10;
+ #else
+ char **mem;
++ FILE *groupfile;
+ #endif
+
+ identifier = mycanonifyid(identifier, 0);
+@@ -246,7 +387,7 @@
+
+ pwd = getpwnam(identifier);
+
+-#if defined(HAVE_GETGROUPLIST) && defined(__GLIBC__)
++#if 0 && defined(HAVE_GETGROUPLIST) && defined(__GLIBC__)
+ gid = pwd ? pwd->pw_gid : (gid_t) -1;
+
+ /* get the group ids */
+@@ -284,20 +425,23 @@
+ if (groupids) free(groupids);
+
+ #else /* !HAVE_GETGROUPLIST */
+- setgrent();
+- while ((grp = getgrent())) {
+- for (mem = grp->gr_mem; *mem; mem++) {
+- if (!strcmp(*mem, identifier)) break;
+- }
++ groupfile = fopen("/etc/imapd.group", "r");
++ if (!groupfile) groupfile = fopen("/etc/group", "r");
++ if (groupfile) {
++ while ((grp = fgetgrent(groupfile))) {
++ for (mem = grp->gr_mem; *mem; mem++) {
++ if (!strcmp(*mem, identifier)) break;
++ }
+
+- if (*mem || (pwd && pwd->pw_gid == grp->gr_gid)) {
+- newstate->ngroups++;
+- newstate->group = (char **)xrealloc((char *)newstate->group,
+- newstate->ngroups * sizeof(char *));
+- newstate->group[newstate->ngroups-1] = xstrdup(grp->gr_name);
+- }
+- }
+- endgrent();
++ if (*mem || (pwd && pwd->pw_gid == grp->gr_gid)) {
++ newstate->ngroups++;
++ newstate->group = (char **)xrealloc((char *)newstate->group,
++ newstate->ngroups * sizeof(char *));
++ newstate->group[newstate->ngroups-1] = xstrdup(grp->gr_name);
++ }
++ }
++ fclose(groupfile);
++ }
+ #endif /* HAVE_GETGROUPLIST */
+
+ return newstate;
diff --git a/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Logging.patch b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Logging.patch
new file mode 100644
index 0000000..fd7a765
--- /dev/null
+++ b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_Logging.patch
@@ -0,0 +1,39 @@
+Provides improved logging for the cyrus imapd server [Version: 2.3.9]
+
+diff -r e17e42827afc imap/append.c
+--- a/imap/append.c Wed Dec 23 20:17:41 2009 +0100
++++ b/imap/append.c Wed Dec 23 20:49:56 2009 +0100
+@@ -654,6 +654,9 @@
+ /* ok, we've successfully added a message */
+ as->quota_used += message_index.size;
+
++ syslog(LOG_DEBUG, "append_fromstage: message %d added to %s",
++ message_index.uid, mailbox->name );
++
+ return 0;
+ }
+
+diff -r e17e42827afc imap/imapd.c
+--- a/imap/imapd.c Wed Dec 23 20:17:41 2009 +0100
++++ b/imap/imapd.c Wed Dec 23 20:49:56 2009 +0100
+@@ -3638,6 +3638,8 @@
+ if ((cmd[0] == 'C') && (imapd_mailbox->myrights & ACL_EXPUNGE)) {
+ if (!mailbox_expunge(imapd_mailbox, NULL, NULL, 0)) {
+ sync_log_mailbox(imapd_mailbox->name);
++ syslog(LOG_DEBUG, "cmd_expunge: user %s, mailbox %s, sequence %s",
++ imapd_userid, imapd_mailbox->name, "''");
+ }
+ }
+
+diff -r e17e42827afc imap/mailbox.c
+--- a/imap/mailbox.c Wed Dec 23 20:17:41 2009 +0100
++++ b/imap/mailbox.c Wed Dec 23 20:49:56 2009 +0100
+@@ -2575,6 +2575,8 @@
+ *(fname->tail)++ = '/';
+ fname->len++;
+ for (msgno = 0; msgno < numdeleted; msgno++) {
++ syslog(LOG_DEBUG, "mailbox_expunge: removing mail %s:%d",
++ mailbox->name, deleted[msgno]);
+ mailbox_message_get_fname(mailbox, deleted[msgno],
+ fname->tail,
+ sizeof(fname->buf) - fname->len);
diff --git a/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_UID.patch b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_UID.patch
new file mode 100644
index 0000000..ecc960d
--- /dev/null
+++ b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_UID.patch
@@ -0,0 +1,117 @@
+Allows login by uid rather than the mail address on the cyrus imapd server [Version: 2.3.9]
+
+diff -r 2ebe14b7db9d configure
+--- a/configure Mon Oct 27 18:47:12 2008 +0100
++++ b/configure Mon Oct 27 18:48:18 2008 +0100
+@@ -19667,7 +19667,7 @@
+ done
+
+ IMAP_COM_ERR_LIBS="${COM_ERR_LIBS}"
+-IMAP_LIBS="${LIB_SASL} ${LIBS} ${SQL_LIBS}"
++IMAP_LIBS="${LIB_SASL} -lldap -llber ${LIBS} ${SQL_LIBS}"
+
+
+
+diff -r 2ebe14b7db9d imap/global.c
+--- a/imap/global.c Mon Oct 27 18:47:12 2008 +0100
++++ b/imap/global.c Mon Oct 27 18:48:18 2008 +0100
+@@ -52,6 +52,9 @@
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ #include <sys/stat.h>
++
++#include <ldap.h>
++#include <lber.h>
+
+ #if HAVE_UNISTD_H
+ # include <unistd.h>
+@@ -378,6 +381,18 @@
+ char *domain = NULL;
+ int len = strlen(user);
+ char buf[81];
++ const char *uri;
++ const char *base;
++ const char *binddn;
++ const char *bindpw;
++ struct timeval timeout;
++ char filter[255];
++ LDAP *handle;
++ LDAPMessage *res;
++ LDAPMessage *entry;
++ struct berval** vals;
++
++ int rc;
+
+ /* check for domain */
+ if (config_virtdomains &&
+@@ -396,6 +411,49 @@
+ }
+
+ if (config_virtdomains) {
++ if (config_virtdomains == IMAP_ENUM_VIRTDOMAINS_LDAP) {
++ uri = config_getstring(IMAPOPT_LDAP_URI);
++ base = config_getstring(IMAPOPT_LDAP_BASE);
++ binddn = config_getstring(IMAPOPT_LDAP_BIND_DN);
++ bindpw = config_getstring(IMAPOPT_LDAP_PASSWORD);
++ timeout.tv_sec = config_getint(IMAPOPT_LDAP_TIME_LIMIT);
++ timeout.tv_usec = 0;
++ sprintf(filter, "(uid=%s)", user);
++ rc = ldap_initialize(&handle, uri);
++ if (rc != LDAP_SUCCESS) {
++ syslog(LOG_ERR, "ldap_initialize failed (%s)", uri);
++ } else {
++ rc = ldap_simple_bind_s(handle, binddn, bindpw);
++ if (rc != LDAP_SUCCESS) {
++ syslog(LOG_ERR, "ldap_simple_bind() failed %d (%s)", rc, ldap_err2string(rc));
++ } else {
++ rc = ldap_search_st(handle, base, LDAP_SCOPE_SUBTREE, filter, NULL, 0, &timeout, &res);
++ if (rc != LDAP_SUCCESS) {
++ syslog(LOG_ERR, "ldap_search_st failed %d (%s)", rc, ldap_err2string(rc));
++ } else {
++ if ( (entry = ldap_first_entry(handle, res)) != NULL ) {
++ // read mail attribute from entry
++ if ( (vals = ldap_get_values_len(handle, entry, "mail")) ) {
++ if (memchr(vals[0]->bv_val, '@', vals[0]->bv_len)) {
++ static char buf[81]; /* same size as in auth_canonifyid */
++ int len = ((sizeof(buf) - 1) > vals[0]->bv_len ? vals[0]->bv_len : sizeof(buf) - 1);
++ strncpy( buf, vals[0]->bv_val, len);
++ buf[len] = '\0'; /* make sure it's null-terminated */
++ ldap_value_free_len( vals );
++ ldap_msgfree( res );
++ ldap_unbind_s(handle); /* also frees handle */
++ syslog(LOG_DEBUG, "canonify: '%s'\n", buf);
++ return auth_canonifyid( buf, 0) ;
++ }
++ ldap_value_free_len( vals );
++ }
++ }
++ ldap_msgfree( res );
++ }
++ }
++ ldap_unbind_s(handle); /* also frees handle */
++ }
++ }
+ if (domain) {
+ if (config_defdomain && !strcasecmp(config_defdomain, domain+1)) {
+ *domain = '\0'; /* trim the default domain */
+@@ -408,7 +466,7 @@
+ user = buf;
+ }
+ }
+- else if (config_virtdomains != IMAP_ENUM_VIRTDOMAINS_USERID) {
++ else if (config_virtdomains != IMAP_ENUM_VIRTDOMAINS_USERID && config_virtdomains != IMAP_ENUM_VIRTDOMAINS_LDAP) {
+ socklen_t salen;
+ int error;
+ struct sockaddr_storage localaddr;
+diff -r 2ebe14b7db9d lib/imapoptions
+--- a/lib/imapoptions Mon Oct 27 18:47:12 2008 +0100
++++ b/lib/imapoptions Mon Oct 27 18:48:18 2008 +0100
+@@ -1114,7 +1114,7 @@
+ mailbox hierarchy. The default is to use the netnews separator
+ character '.'. */
+
+-{ "virtdomains", "off", ENUM("off", "userid", "on") }
++{ "virtdomains", "off", ENUM("off", "userid", "ldap", "on") }
+ /* Enable virtual domain support. If enabled, the user's domain will
+ be determined by splitting a fully qualified userid at the last '@'
+ or '%' symbol. If the userid is unqualified, and the virtdomains
diff --git a/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_cross-domain-acls.patch b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_cross-domain-acls.patch
new file mode 100644
index 0000000..210f004
--- /dev/null
+++ b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_cross-domain-acls.patch
@@ -0,0 +1,375 @@
+Index: imap/mboxlist.c
+===================================================================
+RCS file: /cvs/src/cyrus/imap/mboxlist.c,v
+retrieving revision 1.270
+diff -u -r1.270 mboxlist.c
+--- imap/mboxlist.c 28 Jul 2009 02:46:23 -0000 1.270
++++ imap/mboxlist.c 11 Dec 2009 20:49:36 -0000
+@@ -1576,7 +1576,7 @@
+ except for "anonymous", "anyone", the global admin
+ and users in the default domain */
+ if ((cp = strchr(identifier, '@'))) {
+- if (rights &&
++ if (!config_getswitch(IMAPOPT_ALLOWCROSSDOMAINACLS) && rights &&
+ ((domain && strncasecmp(cp+1, domain, strlen(cp+1))) ||
+ (!domain && (!config_defdomain ||
+ strcasecmp(config_defdomain, cp+1))))) {
+@@ -1918,6 +1918,7 @@
+ int usermboxnamelen;
+ int checkmboxlist;
+ int checkshared;
++ int crossdomain;
+ int isadmin;
+ struct auth_state *auth_state;
+ int (*proc)(char *, int, int, void *rock);
+@@ -1935,7 +1936,9 @@
+ long matchlen;
+
+ /* don't list mailboxes outside of the default domain */
+- if (!rock->domainlen && !rock->isadmin && memchr(key, '!', keylen)) return 0;
++ if (!rock->domainlen && !rock->isadmin && memchr(key, '!', keylen) &&
++ !config_getswitch(IMAPOPT_ALLOWCROSSDOMAINACLS))
++ return 0;
+
+ minmatch = 0;
+ if (rock->inboxoffset) {
+@@ -2108,6 +2111,23 @@
+ }
+
+ rock->checkshared = 0;
++
++ if (rock->find_namespace == NAMESPACE_USER &&
++ config_getswitch(IMAPOPT_ALLOWCROSSDOMAINACLS) && !rock->isadmin &&
++ !rock->crossdomain) {
++ char *cp = strchr(namebuf+rock->inboxoffset, '!');
++ if (cp) {
++ int local_matchlen = (matchlen - 1 -
++ (cp - (namebuf+rock->inboxoffset)));
++ if (!strncmp(cp + 1, "user", local_matchlen)) {
++ r = (*rock->proc)(cp + 1, local_matchlen, 1,
++ rock->procrock);
++ return CYRUSDB_DONE;
++ }
++ }
++ }
++
++
+ r = (*rock->proc)(namebuf+rock->inboxoffset, matchlen,
+ 1, rock->procrock);
+
+@@ -2128,6 +2148,91 @@
+ return r;
+ }
+
++
++static void convert_cross_domain_pattern(char *domainpat, int domainpatlen,
++ char **converted_pattern,
++ const char *pattern, int *crossdomainmatch,
++ const char *domain)
++{
++ int patternlen = strlen(pattern);
++ char *domain_pattern, *local_dest;
++ char *local_pattern, *domain_dest;
++ int local_prefix_len;
++ const char *src;
++ int c;
++
++ domain_dest = domain_pattern = xmalloc(patternlen + 1);
++ local_dest = local_pattern = xmalloc(patternlen + 1);
++ src = pattern;
++
++ while ((c = *src++)) {
++ *local_dest++ = c;
++ if (c == '.' || c == '*')
++ break;
++ }
++
++ local_prefix_len = local_dest - local_pattern;
++ if (c && c != '.')
++ local_prefix_len -= 1;
++ if (strncmp(pattern, "user.", local_prefix_len) == 0) {
++ /* pattern matches "user.*". so convert the domain part of the
++ * pattern */
++
++ if (c == '*') {
++ /* the pattern can match any domain */
++ *domain_dest++ = '*';
++ }
++ else if (c == '.') {
++ while ((c = *src++)) {
++ if (c == '.')
++ break;
++ if (c == '^')
++ c = '.';
++ *domain_dest++ = (c == '%' ? '*' : c);
++ if (c == '*')
++ break;
++ }
++
++ if (c == '*') {
++ *local_dest++ = '*';
++ }
++ }
++
++ if (c) {
++ strcpy(local_dest, src);
++ }
++ else {
++ if (local_dest > local_pattern) {
++ if (local_dest[-1] == '.') {
++ local_dest--;
++ }
++ }
++ *local_dest = 0;
++ }
++
++ if (domain_dest == domain_pattern) {
++ *domain_dest++ = '*';
++ }
++ *domain_dest++ = '!';
++ *domain_dest = 0;
++
++ strncpy(domainpat, domain_pattern, domainpatlen);
++ domainpat[domainpatlen - 1] = 0;
++ strncat(domainpat, local_pattern, domainpatlen - strlen(domainpat) - 1);
++
++ *converted_pattern = xstrdup(local_pattern);
++ *crossdomainmatch = 1;
++ }
++ else {
++ /* pattern doesn't contain an explicit domain part */
++ snprintf(domainpat, domainpatlen, "*!%s", pattern);
++ *crossdomainmatch = 0;
++ }
++
++ free(domain_pattern);
++ free(local_pattern);
++}
++
+ /*
+ * Find all mailboxes that match 'pattern'.
+ * 'isadmin' is nonzero if user is a mailbox admin. 'userid'
+@@ -2151,8 +2256,11 @@
+ char *p;
+ int prefixlen;
+ int userlen = userid ? strlen(userid) : 0, domainlen = 0;
++ int domainpat_prefixlen = 0;
+ char domainpat[MAX_MAILBOX_BUFFER] = ""; /* do intra-domain fetches only */
+ char *pat = NULL;
++ char *converted_pattern = NULL;
++ int crossdomainmatch = 0;
+
+ if (config_virtdomains) {
+ char *domain;
+@@ -2162,8 +2270,10 @@
+ domainlen = strlen(domain); /* includes separator */
+
+ if ((p = strchr(pattern , '!'))) {
+- if ((p-pattern != domainlen-1) ||
+- strncmp(pattern, domain+1, domainlen-1)) {
++ if (!(config_getswitch(IMAPOPT_ALLOWCROSSDOMAINACLS) &&
++ !isadmin) &&
++ ((p-pattern != domainlen-1) ||
++ strncmp(pattern, domain+1, domainlen-1))) {
+ /* don't allow cross-domain access */
+ return IMAP_MAILBOX_BADNAME;
+ }
+@@ -2171,7 +2281,16 @@
+ pattern = p+1;
+ }
+
+- snprintf(domainpat, sizeof(domainpat), "%s!%s", domain+1, pattern);
++ if (!(config_getswitch(IMAPOPT_ALLOWCROSSDOMAINACLS) && !isadmin)) {
++ snprintf(domainpat, sizeof(domainpat), "%s!%s", domain+1, pattern);
++ }
++ else {
++ convert_cross_domain_pattern(domainpat, sizeof(domainpat),
++ &converted_pattern, pattern,
++ &crossdomainmatch, domain + 1);
++ if (converted_pattern)
++ pattern = converted_pattern;
++ }
+ }
+ if ((p = strrchr(pattern, '@'))) {
+ /* global admin specified mbox@domain */
+@@ -2201,6 +2320,7 @@
+ cbrock.auth_state = auth_state;
+ cbrock.checkmboxlist = 0; /* don't duplicate work */
+ cbrock.checkshared = 0;
++ cbrock.crossdomain = 0;
+ cbrock.proc = proc;
+ cbrock.procrock = rock;
+
+@@ -2260,6 +2380,12 @@
+ prefixlen = p - pattern;
+ *p = '\0';
+
++ /* Find fixed-string domain pattern prefix */
++ for (p = domainpat; *p; p++) {
++ if (*p == '*' || *p == '%' || *p == '?' || *p == '@') break;
++ }
++ domainpat_prefixlen = p - domainpat;
++
+ /*
+ * If user.X.* or INBOX.* can match pattern,
+ * search for those mailboxes next
+@@ -2292,6 +2418,7 @@
+ glob_free(&cbrock.g);
+ cbrock.g = glob_init(domainpat, GLOB_HIERARCHY);
+ cbrock.inboxoffset = 0;
++ cbrock.crossdomain = crossdomainmatch;
+ if (usermboxnamelen) {
+ usermboxname[--usermboxnamelen] = '\0';
+ cbrock.usermboxname = usermboxname;
+@@ -2301,7 +2428,7 @@
+ just bother looking at the ones that have the same pattern
+ prefix. */
+ r = DB->foreach(mbdb,
+- domainpat, domainlen + prefixlen,
++ domainpat, domainpat_prefixlen,
+ &find_p, &find_cb, &cbrock,
+ NULL);
+ }
+@@ -2310,6 +2437,7 @@
+ done:
+ glob_free(&cbrock.g);
+ if (pat) free(pat);
++ if (converted_pattern) free(converted_pattern);
+
+ return r;
+ }
+@@ -2347,6 +2475,7 @@
+ cbrock.auth_state = auth_state;
+ cbrock.checkmboxlist = 0; /* don't duplicate work */
+ cbrock.checkshared = 0;
++ cbrock.crossdomain = 0;
+ cbrock.proc = proc;
+ cbrock.procrock = rock;
+
+@@ -2987,6 +3116,7 @@
+ cbrock.auth_state = auth_state;
+ cbrock.checkmboxlist = !force;
+ cbrock.checkshared = 0;
++ cbrock.crossdomain = 0;
+ cbrock.proc = proc;
+ cbrock.procrock = rock;
+
+@@ -3138,6 +3268,7 @@
+ cbrock.auth_state = auth_state;
+ cbrock.checkmboxlist = !force;
+ cbrock.checkshared = 0;
++ cbrock.crossdomain = 0;
+ cbrock.proc = proc;
+ cbrock.procrock = rock;
+
+Index: imap/mboxname.c
+===================================================================
+RCS file: /cvs/src/cyrus/imap/mboxname.c,v
+retrieving revision 1.47
+diff -u -r1.47 mboxname.c
+--- imap/mboxname.c 28 Jul 2009 06:17:26 -0000 1.47
++++ imap/mboxname.c 11 Dec 2009 20:49:36 -0000
+@@ -112,6 +112,8 @@
+ {
+ char *cp;
+ int userlen, domainlen = 0, namelen;
++ int name_has_domain = 0;
++ const char *name_local_part = NULL;
+
+ /* Blank the result, just in case */
+ result[0] = '\0';
+@@ -156,6 +158,18 @@
+ }
+ }
+
++ if (config_getswitch(IMAPOPT_ALLOWCROSSDOMAINACLS) &&
++ !namespace->isadmin &&
++ !strncmp(name, "user", 4) && name[4] == namespace->hier_sep) {
++ name_local_part = strchr(name + 5, namespace->hier_sep);
++ if (!name_local_part) {
++ name_local_part = name + strlen(name);
++ }
++ domainlen = name_local_part - (name + 5) + 1;
++ sprintf(result, "%.*s!", domainlen - 1, name + 5);
++ name_has_domain = 1;
++ }
++
+ /* if no domain specified, we're in the default domain */
+ }
+
+@@ -186,7 +200,13 @@
+ if (domainlen+namelen > MAX_MAILBOX_NAME) {
+ return IMAP_MAILBOX_BADNAME;
+ }
+- sprintf(result, "%.*s", namelen, name);
++
++ if (name_has_domain) {
++ sprintf(result, "user%s", name_local_part ? name_local_part : "");
++ }
++ else {
++ sprintf(result, "%.*s", namelen, name);
++ }
+
+ /* Translate any separators in mailboxname */
+ mboxname_hiersep_tointernal(namespace, result, 0);
+@@ -349,6 +369,7 @@
+ {
+ char *domain = NULL, *cp;
+ size_t domainlen = 0, resultlen;
++ int append_domain = 1;
+
+ /* Blank the result, just in case */
+ result[0] = '\0';
+@@ -363,18 +384,29 @@
+ /* don't use the domain if it matches the user's domain */
+ if (userid && (cp = strchr(userid, '@')) &&
+ (strlen(++cp) == domainlen) && !strncmp(domain, cp, domainlen))
+- domain = NULL;
++ append_domain = 0;
+ }
+
+- strcpy(result, name);
+-
+- /* Translate any separators in mailboxname */
+- mboxname_hiersep_toexternal(namespace, result, 0);
++ if (config_getswitch(IMAPOPT_ALLOWCROSSDOMAINACLS) && !namespace->isadmin
++ && domain && !strncmp(name, "user", 4) &&
++ (name[4] == 0 || name[4] == '.')) {
++ sprintf(result, "user%c%.*s", namespace->hier_sep, domainlen, domain);
++ if (name[4] != 0)
++ sprintf(result + domainlen + 5, "%c%s", namespace->hier_sep,
++ name + 5);
++ mboxname_hiersep_toexternal(namespace, result + domainlen + 6, 0);
++ append_domain = 0;
++ }
++ else {
++ strcpy(result, name);
++ /* Translate any separators in mailboxname */
++ mboxname_hiersep_toexternal(namespace, result, 0);
++ }
+
+ resultlen = strlen(result);
+
+ /* Append domain */
+- if (domain) {
++ if (domain && append_domain) {
+ if(resultlen+domainlen+1 > MAX_MAILBOX_NAME)
+ return IMAP_MAILBOX_BADNAME;
+
+Index: lib/imapoptions
+===================================================================
+RCS file: /cvs/src/cyrus/lib/imapoptions,v
+retrieving revision 1.67
+diff -u -r1.67 imapoptions
+--- lib/imapoptions 29 Jun 2009 17:21:06 -0000 1.67
++++ lib/imapoptions 11 Dec 2009 20:49:38 -0000
+@@ -1155,6 +1155,9 @@
+ interface, otherwise the user is assumed to be in the default
+ domain (if set). */
+
++{ "allowcrossdomainacls", 0, SWITCH }
++/* Allow ACL across domain boundaries. */
++
+ /*
+ .SH SEE ALSO
+ .PP
diff --git a/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_timsieved_starttls-sendcaps.patch b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_timsieved_starttls-sendcaps.patch
new file mode 100644
index 0000000..45088d8
--- /dev/null
+++ b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_timsieved_starttls-sendcaps.patch
@@ -0,0 +1,21 @@
+This patch was downloaded from https://bugzilla.andrew.cmu.edu/cgi-bin/cvsweb.cgi/src/cyrus/timsieved/parser.c.diff?r1=1.44;r2=1.45
+(minus the CVS keywords)
+
+It should be reverse-applied with patch -p2 -R to work around the kontact
+behaviour described in kolab/issue2443 (kontact aborts sieve when imapd sends
+capabilities after starttls) and can be dropped as soon as kontact has a way
+to work with old and new cyrus imapd servers.
+
+diff -r 1688e25afb65 timsieved/parser.c
+--- a/timsieved/parser.c Thu Apr 23 23:28:07 2009 +0200
++++ b/timsieved/parser.c Thu Apr 23 23:28:54 2009 +0200
+@@ -908,8 +908,7 @@
+
+ starttls_done = 1;
+
+- return capabilities(sieved_out, sieved_saslconn, starttls_done,
+- authenticated, sasl_ssf);
++ return result;
+ }
+ #else
+ static int cmd_starttls(struct protstream *sieved_out, struct protstream *sieved_in)
diff --git a/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_workaround-for-missing-user_deny.db.patch b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_workaround-for-missing-user_deny.db.patch
new file mode 100644
index 0000000..3bea233
--- /dev/null
+++ b/imapd/patches/cyrus-imapd-2.3.17/KOLAB_cyrus-imapd-2.3.17_workaround-for-missing-user_deny.db.patch
@@ -0,0 +1,42 @@
+From 1bfda761c67e62ebce7568c67d5fefe6a1ace025 Mon Sep 17 00:00:00 2001
+From: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>
+Date: Tue, 3 Aug 2010 10:38:55 +0200
+Subject: [PATCH 12/13] Workaround for missing user_deny.db
+
+If there is no user_deny.db, then all users are denied by default
+in 2.3.16. This patch circumvents that by returning OK when no
+user_deny.db exists.
+---
+ imap/global.c | 8 ++++++++
+ 1 files changed, 8 insertions(+), 0 deletions(-)
+
+diff --git a/imap/global.c b/imap/global.c
+index 5d64895..dac3d1c 100644
+--- a/imap/global.c
++++ b/imap/global.c
+@@ -542,14 +542,22 @@ static int acl_ok(const char *user, struct auth_state *authstate)
+ int access_ok(const char *user, const char *service, char *msgbuf, int size)
+ {
+ static char *fname = NULL;
++ static int nodb = 0;
+ struct db *db = NULL;
+ int r, ret = 1; /* access always granted by default */
+
++ if (nodb) return ret;
++
+ if (!fname) {
++ struct stat s;
+ /* create path to database */
+ fname = xmalloc(strlen(config_dir) + sizeof(FNAME_USERDENYDB) + 1);
+ strcpy(fname, config_dir);
+ strcat(fname, FNAME_USERDENYDB);
++ if (stat(fname, &s) == -1 && errno==ENOENT) {
++ nodb = 1;
++ return ret;
++ }
+ }
+
+ /* try to open database */
+--
+1.7.2
+
diff --git a/imapd/patches/cyrus-imapd-2.3.17/series b/imapd/patches/cyrus-imapd-2.3.17/series
new file mode 100644
index 0000000..fbb1d64
--- /dev/null
+++ b/imapd/patches/cyrus-imapd-2.3.17/series
@@ -0,0 +1,9 @@
+KOLAB_Groups2.patch
+KOLAB_cross-domain-acls.patch
+KOLAB_Logging.patch
+KOLAB_Folder-names.patch
+KOLAB_UID.patch
+KOLAB_Cyradm_Annotations.patch
+KOLAB_timsieved_starttls-sendcaps.patch
+KOLAB_flush-buffer-after-TLS-initiation.patch
+KOLAB_workaround-for-missing-user_deny.db.patch