Skip to content
Permalink
Browse files

mboxname: support '^' as '.' in non-unixhs so all names can map

  • Loading branch information
brong committed Feb 26, 2016
1 parent 94a848a commit 6203e4664e6031e05e0b1cf82de822f1ce991a38
Showing with 102 additions and 19 deletions.
  1. +69 −3 cunit/mboxname.testc
  2. +33 −16 imap/mboxname.c
@@ -310,9 +310,11 @@ static void toexternal_helper(const char *intname,
r = mboxname_init_namespace(&ns, conf.isadmin);
CU_ASSERT_EQUAL_FATAL(r, 0);

char *extname = mboxname_to_external(intname, &ns, conf.userid);
CU_ASSERT_STRING_EQUAL(extname, extname_expected);
free(extname);
if (intname) {
char *extname = mboxname_to_external(intname, &ns, conf.userid);
CU_ASSERT_STRING_EQUAL(extname, extname_expected);
free(extname);
}

if (extname_expected) {
char *intname_reversed = mboxname_from_external(extname_expected, &ns, conf.userid);
@@ -499,6 +501,8 @@ static void test_toexternal_simple(void)
toexternal_helper("user.fred.foo.barracuda", "INBOX.foo.barracuda");
toexternal_helper("user.jane", "user.jane");
toexternal_helper("user.jane.baz", "user.jane.baz");
toexternal_helper("user.jane.with^a^hat", "user.jane.with^a^hat");
toexternal_helper("user.hatty^smith", "user.hatty^smith");
toexternal_helper("shared.quux", "shared.quux");

/* check that @ doesn't get polluted */
@@ -516,6 +520,8 @@ static void test_toexternal_domains(void)
toexternal_helper("bloggs.com!user.fred.foo.barracuda", "INBOX.foo.barracuda");
toexternal_helper("bloggs.com!user.jane", "user.jane");
toexternal_helper("bloggs.com!user.jane.baz", "user.jane.baz");
toexternal_helper("bloggs.com!user.jane.with^a^hat", "user.jane.with^a^hat");
toexternal_helper("bloggs.com!user.hatty^smith", "user.hatty^smith");
toexternal_helper("bloggs.com!shared.quux", "shared.quux");
/* cross domain sharing is not allowed */
toexternal_helper("boop.com!user.betty", NULL);
@@ -535,11 +541,39 @@ static void test_toexternal_crossdomains(void)
toexternal_helper("bloggs.com!user.fred.foo.barracuda", "INBOX/foo/barracuda");
toexternal_helper("bloggs.com!user.jane", "user/jane@bloggs.com");
toexternal_helper("bloggs.com!user.jane.baz", "user/jane@bloggs.com/baz");
toexternal_helper("bloggs.com!user.jane.with^a^hat", "user/jane@bloggs.com/with.a.hat");
toexternal_helper("bloggs.com!user.hatty^smith", "user/hatty.smith@bloggs.com");
// no domains in shared folders in crossdomain
toexternal_helper("bloggs.com!shared.quux", "shared/quux");

toexternal_helper("boop.com!user.betty", "user/betty@boop.com");
toexternal_helper("boop.com!user.betty.foo.bar", "user/betty@boop.com/foo/bar");
toexternal_helper("boop.com!user.betty.foo^bar", "user/betty@boop.com/foo.bar");
// shared folders in other domains can't be seen
toexternal_helper("boop.com!shared.quux", NULL);
}

static void test_toexternal_crossdomains_nouhs(void)
{
memset(&conf, 0, sizeof(conf));
conf.virtdomains = 1;
conf.crossdomains = 1;
conf.unixhierarchysep = 0;
conf.userid = "fred@bloggs.com";

toexternal_helper("bloggs.com!user.fred", "INBOX");
toexternal_helper("bloggs.com!user.fred.foo", "INBOX.foo");
toexternal_helper("bloggs.com!user.fred.foo.barracuda", "INBOX.foo.barracuda");
toexternal_helper("bloggs.com!user.jane", "user.jane@bloggs^com");
toexternal_helper("bloggs.com!user.jane.baz", "user.jane@bloggs^com.baz");
toexternal_helper("bloggs.com!user.jane.with^a^hat", "user.jane@bloggs^com.with^a^hat");
toexternal_helper("bloggs.com!user.hatty^smith", "user.hatty^smith@bloggs^com");
// no domains in shared folders in crossdomain
toexternal_helper("bloggs.com!shared.quux", "shared.quux");

toexternal_helper("boop.com!user.betty", "user.betty@boop^com");
toexternal_helper("boop.com!user.betty.foo.bar", "user.betty@boop^com.foo.bar");
toexternal_helper("boop.com!user.betty.foo^bar", "user.betty@boop^com.foo^bar");
// shared folders in other domains can't be seen
toexternal_helper("boop.com!shared.quux", NULL);
}
@@ -560,11 +594,40 @@ static void test_toexternal_crossdomains_alt(void)
toexternal_helper("bloggs.com!user.fred.foo.barracuda", "foo/barracuda");
toexternal_helper("bloggs.com!user.jane", "User Magic/jane@bloggs.com");
toexternal_helper("bloggs.com!user.jane.baz", "User Magic/jane@bloggs.com/baz");
toexternal_helper("bloggs.com!user.jane.with^a^hat", "User Magic/jane@bloggs.com/with.a.hat");
toexternal_helper("bloggs.com!user.hatty^smith", "User Magic/hatty.smith@bloggs.com");
// no domains in shared folders in crossdomain
toexternal_helper("bloggs.com!shared.quux", "Shared Magic/shared/quux");

toexternal_helper("boop.com!user.betty", "User Magic/betty@boop.com");
toexternal_helper("boop.com!user.betty.foo.bar", "User Magic/betty@boop.com/foo/bar");
toexternal_helper("boop.com!user.betty.foo^bar", "User Magic/betty@boop.com/foo.bar");
}

static void test_toexternal_crossdomains_alt_nouhs(void)
{
memset(&conf, 0, sizeof(conf));
conf.altnamespace = 1;
conf.virtdomains = 1;
conf.crossdomains = 1;
conf.unixhierarchysep = 0;
conf.userprefix = "User Magic";
conf.sharedprefix = "Shared Magic";
conf.userid = "fred@bloggs.com";

toexternal_helper("bloggs.com!user.fred", "INBOX");
toexternal_helper("bloggs.com!user.fred.foo", "foo");
toexternal_helper("bloggs.com!user.fred.foo.barracuda", "foo.barracuda");
toexternal_helper("bloggs.com!user.jane", "User Magic.jane@bloggs^com");
toexternal_helper("bloggs.com!user.jane.baz", "User Magic.jane@bloggs^com.baz");
toexternal_helper("bloggs.com!user.jane.with^a^hat", "User Magic.jane@bloggs^com.with^a^hat");
toexternal_helper("bloggs.com!user.hatty^smith", "User Magic.hatty^smith@bloggs^com");
// no domains in shared folders in crossdomain
toexternal_helper("bloggs.com!shared.quux", "Shared Magic.shared.quux");

toexternal_helper("boop.com!user.betty", "User Magic.betty@boop^com");
toexternal_helper("boop.com!user.betty.foo.bar", "User Magic.betty@boop^com.foo.bar");
toexternal_helper("boop.com!user.betty.foo^bar", "User Magic.betty@boop^com.foo^bar");
}

static void test_toexternal_unixhier(void)
@@ -584,6 +647,9 @@ static void test_toexternal_unixhier(void)
/* check that @ doesn't get polluted */
toexternal_helper("user.fred.folder@place", "INBOX/folder@place");
toexternal_helper("user.fred^smith@example^com.folder@place", "user/fred.smith@example.com/folder@place");

/* can't have a hat on the outside */
toexternal_helper(NULL, "user/fred^smith");
}

static void test_toexternal_alt(void)
@@ -508,6 +508,10 @@ EXPORTED mbname_t *mbname_from_extname(const char *extname, const struct namespa
if (!*extname)
return mbname; // empty string, *sigh*

/* ^ is bogus in external names */
if (ns->hier_sep == '/' && strchr(extname, '^'))
return mbname;

mbname_t *userparts = mbname_from_userid(userid);

mbname->extname = xstrdup(extname); // may as well cache it
@@ -534,6 +538,10 @@ EXPORTED mbname_t *mbname_from_extname(const char *extname, const struct namespa

mbname->boxes = strarray_split(mbname->extname, sepstr, 0);
if (p) *p = '@'; // rebuild extname for later use
int i;
for (i = 0; i < mbname->boxes->count; i++) {
_add_dots(mbname->boxes->data[i]);
}

if (!strarray_size(mbname->boxes))
goto done;
@@ -810,6 +818,19 @@ EXPORTED const char *mbname_recipient(const mbname_t *mbname, const struct names
return mbname->recipient;
}

static void _append_nodots(const struct namespace *ns, struct buf *buf, const char *val)
{
if (ns->hier_sep == '/') {
buf_appendcstr(buf, val);
}
else {
char *copy = xstrdup(val);
_rm_dots(copy);
buf_appendcstr(buf, copy);
free(copy);
}
}

/* This is one of the most complex parts of the code - generating an external
* name based on the namespace, the 'isadmin' status, and of course the current
* user. There are some interesting things to look out for:
@@ -867,7 +888,7 @@ EXPORTED const char *mbname_extname(const mbname_t *mbname, const struct namespa
int i;
for (i = 0; i < strarray_size(boxes); i++) {
buf_putc(&buf, ns->hier_sep);
buf_appendcstr(&buf, strarray_nth(boxes, i));
_append_nodots(ns, &buf, strarray_nth(boxes, i));
}
goto end;
}
@@ -876,17 +897,17 @@ EXPORTED const char *mbname_extname(const mbname_t *mbname, const struct namespa
if (strcmpsafe(mbname_userid(mbname), userid)) {
buf_appendcstr(&buf, up);
buf_putc(&buf, ns->hier_sep);
buf_appendcstr(&buf, mbname_localpart(mbname));
_append_nodots(ns, &buf, mbname_localpart(mbname));
if (crossdomains) {
const char *domain = mbname_domain(mbname);
if (!domain) domain = config_defdomain;
buf_putc(&buf, '@');
buf_appendcstr(&buf, domain);
_append_nodots(ns, &buf, domain);
}
int i;
for (i = 0; i < strarray_size(boxes); i++) {
buf_putc(&buf, ns->hier_sep);
buf_appendcstr(&buf, strarray_nth(boxes, i));
_append_nodots(ns, &buf, strarray_nth(boxes, i));
}
goto end;
}
@@ -912,7 +933,7 @@ EXPORTED const char *mbname_extname(const mbname_t *mbname, const struct namespa
int i;
for (i = 0; i < strarray_size(boxes); i++) {
if (i) buf_putc(&buf, ns->hier_sep);
buf_appendcstr(&buf, strarray_nth(boxes, i));
_append_nodots(ns, &buf, strarray_nth(boxes, i));
}

goto end;
@@ -940,7 +961,7 @@ EXPORTED const char *mbname_extname(const mbname_t *mbname, const struct namespa
int i;
for (i = 0; i < strarray_size(boxes); i++) {
if (i) buf_putc(&buf, ns->hier_sep);
buf_appendcstr(&buf, strarray_nth(boxes, i));
_append_nodots(ns, &buf, strarray_nth(boxes, i));
}

goto end;
@@ -950,20 +971,20 @@ EXPORTED const char *mbname_extname(const mbname_t *mbname, const struct namespa
if (strcmpsafe(mbname_userid(mbname), userid)) {
buf_appendcstr(&buf, "user");
buf_putc(&buf, ns->hier_sep);
buf_appendcstr(&buf, mbname_localpart(mbname));
_append_nodots(ns, &buf, mbname_localpart(mbname));
if (crossdomains) {
const char *domain = mbname_domain(mbname);
if (!domain) domain = config_defdomain;
buf_putc(&buf, '@');
buf_appendcstr(&buf, domain);
_append_nodots(ns, &buf, domain);
}
/* shared folders can ONLY be in the same domain except for admin */
else if (!admindomains && strcmpsafe(mbname_domain(mbname), mbname_domain(userparts)))
goto done;
int i;
for (i = 0; i < strarray_size(boxes); i++) {
buf_putc(&buf, ns->hier_sep);
buf_appendcstr(&buf, strarray_nth(boxes, i));
_append_nodots(ns, &buf, strarray_nth(boxes, i));
}
goto end;
}
@@ -972,7 +993,7 @@ EXPORTED const char *mbname_extname(const mbname_t *mbname, const struct namespa
int i;
for (i = 0; i < strarray_size(boxes); i++) {
buf_putc(&buf, ns->hier_sep);
buf_appendcstr(&buf, strarray_nth(boxes, i));
_append_nodots(ns, &buf, strarray_nth(boxes, i));
}

end:
@@ -1309,18 +1330,15 @@ EXPORTED int mboxname_same_userid(const char *name1, const char *name2)
* Apply site policy restrictions on mailbox names.
* Restrictions are hardwired for now.
*/
#define GOODCHARS " #$'+,-.0123456789:=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~[]()?"
#define GOODCHARS " #$'+,-.0123456789:=@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~[]()?^"
HIDDEN int mboxname_policycheck(const char *name)
{
const char *p;
int sawutf7 = 0;
unsigned c1, c2, c3, c4, c5, c6, c7, c8;
int ucs4;
int unixsep;
int namelen = strlen(name);

unixsep = config_getswitch(IMAPOPT_UNIXHIERARCHYSEP);

/* Skip policy check on mailbox created in delayed delete namespace
* assuming the mailbox existed before and was OK then.
* This should allow mailboxes that are extremely long to be
@@ -1434,8 +1452,7 @@ HIDDEN int mboxname_policycheck(const char *name)
}
else {
/* If we're using unixhierarchysep, DOTCHAR is allowed */
if (!strchr(GOODCHARS, *name) &&
!(unixsep && *name == DOTCHAR))
if (!strchr(GOODCHARS, *name))
return IMAP_MAILBOX_BADNAME;
name++;
sawutf7 = 0;

0 comments on commit 6203e46

Please sign in to comment.
You can’t perform that action at this time.