dovecot-2.2: Various cleanups to checking if mailbox name is valid.

dovecot at dovecot.org dovecot at dovecot.org
Tue Sep 25 22:53:59 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/20edc46254ce
changeset: 15107:20edc46254ce
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Sep 25 22:53:36 2012 +0300
description:
Various cleanups to checking if mailbox name is valid.

diffstat:

 src/doveadm/dsync/dsync-brain-mailbox-tree.c      |  116 +++++++++++----------
 src/lib-storage/list/mailbox-list-fs-iter.c       |    6 +-
 src/lib-storage/list/mailbox-list-fs.c            |    4 +-
 src/lib-storage/list/mailbox-list-subscriptions.c |    8 +-
 src/lib-storage/mail-storage.c                    |   51 +++++++--
 src/lib-storage/mail-storage.h                    |    3 +
 src/lib-storage/mailbox-list.c                    |   76 ++++++--------
 src/lib-storage/mailbox-list.h                    |   12 +-
 src/plugins/acl/acl-backend-vfile.c               |    4 +-
 9 files changed, 151 insertions(+), 129 deletions(-)

diffs (truncated from 515 to 300 lines):

diff -r f0d487918a2b -r 20edc46254ce src/doveadm/dsync/dsync-brain-mailbox-tree.c
--- a/src/doveadm/dsync/dsync-brain-mailbox-tree.c	Tue Sep 25 22:51:46 2012 +0300
+++ b/src/doveadm/dsync/dsync-brain-mailbox-tree.c	Tue Sep 25 22:53:36 2012 +0300
@@ -173,66 +173,71 @@
 	return best_ns;
 }
 
-static const char *
-mailbox_name_cleanup(const char *input, char real_sep, char alt_char)
+static bool
+dsync_is_valid_name(struct mail_namespace *ns, const char *vname)
 {
-	char *output, *p;
+	struct mailbox *box;
+	bool ret;
 
-	output = t_strdup_noconst(input);
-	for (p = output; *p != '\0'; p++) {
-		if (*p == real_sep || (uint8_t)*input < 32 ||
-		    (uint8_t)*input >= 0x80)
+	box = mailbox_alloc(ns->list, vname, 0);
+	ret = mailbox_verify_create_name(box) == 0;
+	mailbox_free(&box);
+	return ret;
+}
+
+static void
+dsync_fix_mailbox_name(struct mail_namespace *ns, string_t *vname,
+		       char alt_char)
+{
+	const char *old_vname;
+	char *p, list_sep = mailbox_list_get_hierarchy_sep(ns->list);
+	guid_128_t guid;
+
+	/* replace control chars */
+	for (p = str_c_modifiable(vname); *p != '\0'; p++) {
+		if ((unsigned char)*p < ' ')
 			*p = alt_char;
 	}
-	return output;
-}
+	/* make it valid UTF8 */
+	if (!uni_utf8_str_is_valid(str_c(vname))) {
+		old_vname = t_strdup(str_c(vname));
+		str_truncate(vname, 0);
+		if (uni_utf8_get_valid_data((const void *)old_vname,
+					    strlen(old_vname), vname))
+			i_unreached();
+	}
+	if (dsync_is_valid_name(ns, str_c(vname)))
+		return;
 
-static const char *mailbox_name_force_cleanup(const char *input, char alt_char)
-{
-	char *output, *p;
+	/* 1) change any real separators to alt separators (this wouldn't
+	   be necessary with listescape, but don't bother detecting it) */
+	if (list_sep != mail_namespace_get_sep(ns)) {
+		for (p = str_c_modifiable(vname); *p != '\0'; p++) {
+			if (*p == list_sep)
+				*p = alt_char;
+		}
+		if (dsync_is_valid_name(ns, str_c(vname)))
+			return;
+	}
+	/* 2) '/' characters aren't valid without listescape */
+	if (mail_namespace_get_sep(ns) != '/' && list_sep != '/') {
+		for (p = str_c_modifiable(vname); *p != '\0'; p++) {
+			if (*p == '/')
+				*p = alt_char;
+		}
+		if (dsync_is_valid_name(ns, str_c(vname)))
+			return;
+	}
+	/* 3) probably some reserved name (e.g. dbox-Mails) */
+	str_insert(vname, 0, "_");
+	if (dsync_is_valid_name(ns, str_c(vname)))
+		return;
 
-	output = t_strdup_noconst(input);
-	for (p = output; *p != '\0'; p++) {
-		if (!i_isalnum(*p))
-			*p = alt_char;
-	}
-	return output;
-}
-
-static const char *
-dsync_fix_mailbox_name(struct mail_namespace *ns, const char *vname,
-		       char alt_char)
-{
-	const char *name;
-	char list_sep;
-
-	name = mailbox_list_get_storage_name(ns->list, vname);
-
-	list_sep = mailbox_list_get_hierarchy_sep(ns->list);
-	if (!mailbox_list_is_valid_create_name(ns->list, name)) {
-		/* change any real separators to alt separators,
-		   drop any potentially invalid characters */
-		name = mailbox_name_cleanup(name, list_sep, alt_char);
-	}
-	if (!mailbox_list_is_valid_create_name(ns->list, name)) {
-		/* still not working, apparently it's not valid mUTF-7.
-		   just drop all non-alphanumeric characters. */
-		name = mailbox_name_force_cleanup(name, alt_char);
-	}
-	if (!mailbox_list_is_valid_create_name(ns->list, name)) {
-		/* probably some reserved name (e.g. dbox-Mails) */
-		name = t_strconcat("_", name, NULL);
-	}
-	if (!mailbox_list_is_valid_create_name(ns->list, name)) {
-		/* name is too long? just give up and generate a
-		   unique name */
-		guid_128_t guid;
-
-		guid_128_generate(guid);
-		name = guid_128_to_string(guid);
-	}
-	i_assert(mailbox_list_is_valid_create_name(ns->list, name));
-	return mailbox_list_get_vname(ns->list, name);
+	/* 4) name is too long? just give up and generate a unique name */
+	guid_128_generate(guid);
+	str_truncate(vname, 0);
+	str_append(vname, guid_128_to_string(guid));
+	i_assert(dsync_is_valid_name(ns, str_c(vname)));
 }
 
 static int
@@ -264,7 +269,8 @@
 	}
 	str_truncate(vname, str_len(vname)-1);
 
-	*name_r = dsync_fix_mailbox_name(ns, str_c(vname), alt_char);
+	dsync_fix_mailbox_name(ns, vname, alt_char);
+	*name_r = str_c(vname);
 	*ns_r = ns;
 	return 0;
 }
diff -r f0d487918a2b -r 20edc46254ce src/lib-storage/list/mailbox-list-fs-iter.c
--- a/src/lib-storage/list/mailbox-list-fs-iter.c	Tue Sep 25 22:51:46 2012 +0300
+++ b/src/lib-storage/list/mailbox-list-fs-iter.c	Tue Sep 25 22:53:36 2012 +0300
@@ -328,7 +328,7 @@
 {
 	struct mailbox_list *_list = ctx->ctx.list;
 	ARRAY(const char *) valid_patterns;
-	const char *pattern, *test_pattern, *real_pattern;
+	const char *pattern, *test_pattern, *real_pattern, *error;
 	unsigned int prefix_len;
 
 	prefix_len = strlen(_list->ns->prefix);
@@ -345,8 +345,8 @@
 		   separators. */
 		real_pattern =
 			mailbox_list_get_storage_name(_list, test_pattern);
-		if (mailbox_list_is_valid_pattern(_list, test_pattern) &&
-		    mailbox_list_is_valid_pattern(_list, real_pattern)) {
+		if (mailbox_list_is_valid_name(_list, test_pattern, &error) &&
+		    mailbox_list_is_valid_name(_list, real_pattern, &error)) {
 			pattern = p_strdup(ctx->ctx.pool, *patterns);
 			array_append(&valid_patterns, &pattern, 1);
 		}
diff -r f0d487918a2b -r 20edc46254ce src/lib-storage/list/mailbox-list-fs.c
--- a/src/lib-storage/list/mailbox-list-fs.c	Tue Sep 25 22:51:46 2012 +0300
+++ b/src/lib-storage/list/mailbox-list-fs.c	Tue Sep 25 22:53:36 2012 +0300
@@ -51,14 +51,14 @@
 		 enum mailbox_list_path_type type)
 {
 	const struct mailbox_list_settings *set = &_list->set;
-	const char *root_dir;
+	const char *root_dir, *error;
 
 	if (name == NULL) {
 		/* return root directories */
 		return mailbox_list_set_get_root_path(set, type);
 	}
 
-	i_assert(mailbox_list_is_valid_pattern(_list, name));
+	i_assert(mailbox_list_is_valid_name(_list, name, &error));
 
 	if (mailbox_list_try_get_absolute_path(_list, &name))
 		return name;
diff -r f0d487918a2b -r 20edc46254ce src/lib-storage/list/mailbox-list-subscriptions.c
--- a/src/lib-storage/list/mailbox-list-subscriptions.c	Tue Sep 25 22:51:46 2012 +0300
+++ b/src/lib-storage/list/mailbox-list-subscriptions.c	Tue Sep 25 22:53:36 2012 +0300
@@ -27,7 +27,7 @@
 	struct mail_namespace *ns, *default_ns = list->ns;
 	struct mail_namespace *namespaces = default_ns->user->namespaces;
 	struct mailbox_node *node;
-	const char *vname, *ns_name;
+	const char *vname, *ns_name, *error;
 	unsigned int len;
 	bool created;
 
@@ -87,7 +87,7 @@
 		name = t_strndup(name, len-1);
 	}
 
-	if (!mailbox_list_is_valid_existing_name(list, name)) {
+	if (!mailbox_list_is_valid_name(list, name, &error)) {
 		/* we'll only get into trouble if we show this */
 		return -1;
 	} else {
@@ -246,7 +246,7 @@
 	struct mailbox_list *list = _ctx->list;
 	struct mailbox_node *node;
 	enum mailbox_info_flags subs_flags;
-	const char *vname, *storage_name;
+	const char *vname, *storage_name, *error;
 	int ret;
 
 	node = mailbox_tree_iterate_next(ctx->iter, &vname);
@@ -265,7 +265,7 @@
 	}
 
 	storage_name = mailbox_list_get_storage_name(list, vname);
-	if (!mailbox_list_is_valid_pattern(list, storage_name)) {
+	if (!mailbox_list_is_valid_name(list, storage_name, &error)) {
 		/* broken entry in subscriptions file */
 		ctx->info.flags = MAILBOX_NONEXISTENT;
 	} else if (mailbox_list_mailbox(list, storage_name,
diff -r f0d487918a2b -r 20edc46254ce src/lib-storage/mail-storage.c
--- a/src/lib-storage/mail-storage.c	Tue Sep 25 22:51:46 2012 +0300
+++ b/src/lib-storage/mail-storage.c	Tue Sep 25 22:53:36 2012 +0300
@@ -709,31 +709,42 @@
 	return box;
 }
 
-static bool mailbox_name_verify_separators(const char *vname, char sep)
+static bool
+mailbox_name_verify_separators(const char *vname, char sep,
+			       const char **error_r)
 {
 	unsigned int i;
-	bool prev_sep = TRUE;
+	bool prev_sep = FALSE;
+
+	if (vname[0] == sep) {
+		*error_r = "Begins with hierarchy separator";
+		return FALSE;
+	}
 
 	/* Make sure the vname is correct: non-empty, doesn't begin or end
 	   with separator and no adjacent separators */
-	for (i = 0; vname[i] != '\0'; i++) {
+	for (i = 1; vname[i] != '\0'; i++) {
 		if (vname[i] == sep) {
-			if (prev_sep)
+			if (prev_sep) {
+				*error_r = "Has adjacent hierarchy separators";
 				return FALSE;
+			}
 			prev_sep = TRUE;
 		} else {
 			prev_sep = FALSE;
 		}
 	}
-	if (prev_sep)
+	if (prev_sep) {
+		*error_r = "Ends with hierarchy separator";
 		return FALSE;
+	}
 	return TRUE;
 }
 
 static int mailbox_verify_name(struct mailbox *box)
 {
 	struct mail_namespace *ns = box->list->ns;
-	const char *vname = box->vname;
+	const char *error, *vname = box->vname;
 	char list_sep, ns_sep;
 
 	if (box->inbox_user) {
@@ -768,24 +779,40 @@
 			"Character not allowed in mailbox name: '%c'", list_sep));
 		return -1;
 	}
-	if (!mailbox_name_verify_separators(box->vname, ns_sep) ||
-	    !mailbox_list_is_valid_existing_name(box->list, box->name)) {
+	if (!mailbox_name_verify_separators(vname, ns_sep, &error) ||
+	    !mailbox_list_is_valid_name(box->list, box->name, &error)) {
 		mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
-				       "Invalid mailbox name");
+			t_strdup_printf("Invalid mailbox name: %s", error));
 		return -1;
 	}
 	return 0;
 }
 
-static int mailbox_verify_create_name(struct mailbox *box)
+static bool mailbox_name_has_control_chars(const char *name)
+{
+	const char *p;
+
+	for (p = name; *p != '\0'; p++) {
+		if ((unsigned char)*p < ' ')
+			return TRUE;
+	}
+	return FALSE;
+}


More information about the dovecot-cvs mailing list