File KOLAB_cyrus-imapd-2.3.18_cross-domain-acls.patch of Package cyrus-imapd.3194
Index: cyrus-imapd-2.3.17/imap/mboxlist.c
===================================================================
--- cyrus-imapd-2.3.17.orig/imap/mboxlist.c
+++ cyrus-imapd-2.3.17/imap/mboxlist.c
@@ -1618,7 +1618,7 @@ int mboxlist_setacl(const char *name, co
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))))) {
@@ -1960,6 +1960,7 @@ struct find_rock {
int usermboxnamelen;
int checkmboxlist;
int checkshared;
+ int crossdomain;
int isadmin;
struct auth_state *auth_state;
int (*proc)(char *, int, int, void *rock);
@@ -1977,7 +1978,9 @@ static int find_p(void *rockp,
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) {
@@ -2150,6 +2153,23 @@ static int find_cb(void *rockp,
}
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);
@@ -2170,6 +2190,91 @@ static int find_cb(void *rockp,
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'
@@ -2193,8 +2298,11 @@ int mboxlist_findall(struct namespace *n
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;
@@ -2204,8 +2312,10 @@ int mboxlist_findall(struct namespace *n
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;
}
@@ -2213,7 +2323,16 @@ int mboxlist_findall(struct namespace *n
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 */
@@ -2243,6 +2362,7 @@ int mboxlist_findall(struct namespace *n
cbrock.auth_state = auth_state;
cbrock.checkmboxlist = 0; /* don't duplicate work */
cbrock.checkshared = 0;
+ cbrock.crossdomain = 0;
cbrock.proc = proc;
cbrock.procrock = rock;
@@ -2302,6 +2422,12 @@ int mboxlist_findall(struct namespace *n
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
@@ -2334,6 +2460,7 @@ int mboxlist_findall(struct namespace *n
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;
@@ -2343,7 +2470,7 @@ int mboxlist_findall(struct namespace *n
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);
}
@@ -2352,6 +2479,7 @@ int mboxlist_findall(struct namespace *n
done:
glob_free(&cbrock.g);
if (pat) free(pat);
+ if (converted_pattern) free(converted_pattern);
return r;
}
@@ -2389,6 +2517,7 @@ int mboxlist_findall_alt(struct namespac
cbrock.auth_state = auth_state;
cbrock.checkmboxlist = 0; /* don't duplicate work */
cbrock.checkshared = 0;
+ cbrock.crossdomain = 0;
cbrock.proc = proc;
cbrock.procrock = rock;
@@ -3029,6 +3158,7 @@ int mboxlist_findsub(struct namespace *n
cbrock.auth_state = auth_state;
cbrock.checkmboxlist = !force;
cbrock.checkshared = 0;
+ cbrock.crossdomain = 0;
cbrock.proc = proc;
cbrock.procrock = rock;
@@ -3180,6 +3310,7 @@ int mboxlist_findsub_alt(struct namespac
cbrock.auth_state = auth_state;
cbrock.checkmboxlist = !force;
cbrock.checkshared = 0;
+ cbrock.crossdomain = 0;
cbrock.proc = proc;
cbrock.procrock = rock;
Index: cyrus-imapd-2.3.17/imap/mboxname.c
===================================================================
--- cyrus-imapd-2.3.17.orig/imap/mboxname.c
+++ cyrus-imapd-2.3.17/imap/mboxname.c
@@ -113,6 +113,8 @@ static int mboxname_tointernal(struct na
char *cp;
char *atp;
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';
@@ -163,6 +165,18 @@ static int mboxname_tointernal(struct na
}
}
+ 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 */
}
@@ -193,7 +207,13 @@ static int mboxname_tointernal(struct na
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);
@@ -356,6 +376,7 @@ static int mboxname_toexternal(struct na
{
char *domain = NULL, *cp;
size_t domainlen = 0, resultlen;
+ int append_domain = 1;
/* Blank the result, just in case */
result[0] = '\0';
@@ -370,18 +391,29 @@ static int mboxname_toexternal(struct na
/* 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: cyrus-imapd-2.3.17/lib/imapoptions
===================================================================
--- cyrus-imapd-2.3.17.orig/lib/imapoptions
+++ cyrus-imapd-2.3.17/lib/imapoptions
@@ -1278,6 +1278,9 @@ product version in the capabilities */
/* Send mail to mailboxes, which do not exists, to this user. NOTE: This must
be an existing local mailbox name. NOT an email address! */
+{ "allowcrossdomainacls", 0, SWITCH }
+/* Allow ACL across domain boundaries. */
+
/*
.SH SEE ALSO
.PP