Hello,

there seems to be a problem with the listescape plugin and shared INBOX:

=== Preconditions:
- Dovecot 2.2.21 (or 2.2.13)
- IMAP
- Separator /
- Namespace-prefixes "INBOX/" and "shared/%%u/"
- Maildir(++)
- option mail_plugins = acl listescape
- option mail_shared_explicit_inbox = no
- User "owner" shares the INBOX
- ACLs set for another user "reader", so "reader" is able to access the shared INBOX of "owner"

=== Steps to reproduce by using IMAP commands at a telnet session:
- a1 login reader password
- a2 select shared/owner

=== Result:
Selecting the shared INBOX fails with a response like:
 a2 NO Mailbox doesn't exist: shared/owner

=== Expected:
The "select" command works.

=== Analysis:
The function "mailbox_list_default_get_storage_name" (lib-storage/mailbox-list.c) does not work as expected when using the mail_plugin "listescape". It compares the mailbox name to the namespace prefix. Since the mailbox name is escaped a few lines before, the comparison yields "strings differ", which makes accessing the shared INBOX fail.

For example: for a string vname (mailbox name) "shared/owner", it compares "shared.owner" (escaped string) to the list->ns->prefix which is "shared/owner".

Asuming that the stored prefix should not be escaped, there should be a comparison of the unescaped name to the unescaped prefix (or the escaped name to the escaped prefix?).

=== Patch:
Attached is a small patch which shows a possible solution. When applied, the problem is solved, i.e. the shared INBOX is accessible then. Important note: this patch is experimental, it works for the described special case but might not work with a different configuration or might even break things.

Best Regards,
Rudolf Körner
--- dovecot-2.2.21_orig/src/lib-storage/mailbox-list.c	2015-12-09 16:39:10.000000000 +0100
+++ dovecot-2.2.21_patched/src/lib-storage/mailbox-list.c	2016-02-09 14:35:58.272000000 +0100
@@ -518,14 +518,17 @@
 	struct mail_namespace *ns = list->ns;
 	unsigned int prefix_len = strlen(ns->prefix);
 	const char *storage_name = vname;
+	string_t *unesc_storage_name = NULL;
 	string_t *str;
 	char list_sep, ns_sep, *ret;
 
 	if (strcasecmp(storage_name, "INBOX") == 0 &&
 	    (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0)
 		storage_name = "INBOX";
-	else if (list->set.escape_char != '\0')
+	else if (list->set.escape_char != '\0') {
+		unesc_storage_name = str_new_const(default_pool, vname, strlen(vname));
 		storage_name = mailbox_list_escape_name(list, vname);
+	}
 
 	if (prefix_len > 0 && (strcmp(storage_name, "INBOX") != 0 ||
 			       (ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0)) {
@@ -537,11 +540,19 @@
 			 ns->prefix[prefix_len-1] == mail_namespace_get_sep(ns)) {
 			/* trying to access the namespace prefix itself */
 			storage_name = "";
+		}
+		else if (unesc_storage_name && strncmp(ns->prefix, str_c(unesc_storage_name), prefix_len-1) == 0 &&
+			 str_len(unesc_storage_name) == prefix_len-1 &&
+			 ns->prefix[prefix_len-1] == mail_namespace_get_sep(ns)) {
+			/* trying to access the unescaped namespace prefix itself */
+			storage_name = "";
 		} else {
 			/* we're converting a nonexistent mailbox name,
 			   such as a LIST pattern. */
 		}
 	}
+	if (unesc_storage_name)
+		str_free(&unesc_storage_name);
 
 	if (!list->set.utf8) {
 		/* UTF-8 -> mUTF-7 conversion */

Reply via email to