From 8a30bf2e05e741ee6711822be613336548968cef Mon Sep 17 00:00:00 2001
From: Bron Gondwana <brong@fastmail.fm>
Date: Wed, 24 Dec 2008 23:26:30 +1100
Subject: [PATCH] Limit User Folders

A user managed to synchronise our server with their UWash IMAP
server's view of a very busy home directory, creating tens of
thousands of folders and showing that there's a DOS risk against
mailboxes.db here.

This patch creates a new config variable user_folder_limit which,
if set, returns IMAP_PERMISSION_DENIED to any further attempts to
create a folder if the user has too many folders already.
---
 imap/mboxlist.c |   20 +++++++++++++++++++-
 lib/imapoptions |    4 ++++
 2 files changed, 23 insertions(+), 1 deletions(-)

diff --git a/imap/mboxlist.c b/imap/mboxlist.c
index 0ca5eeb..99696ef 100644
--- a/imap/mboxlist.c
+++ b/imap/mboxlist.c
@@ -370,6 +370,7 @@ mboxlist_mycreatemailboxcheck(char *name,
     unsigned long parentpartitionlen = 0;
     unsigned long parentacllen = 0;
     int mbtype;
+    int user_folder_limit;
     
     /* Check for invalid name/partition */
     if (partition && strlen(partition) > MAX_PARTITION_LEN) {
@@ -443,6 +444,23 @@ mboxlist_mycreatemailboxcheck(char *name,
 	    break;
 	}
     }
+
+    /* check the folder limit */
+    if (!isadmin && (user_folder_limit = config_getint(IMAPOPT_USER_FOLDER_LIMIT))) {
+	char buf[MAX_MAILBOX_NAME+1];
+	strncpy(buf, mbox, strlen(mbox));
+	if (!strncmp(buf, "user.", 5)) {
+	    char *firstdot = strchr(buf+5, '.');
+	    if (firstdot) *firstdot = '\0';
+	    if (mboxlist_count_inferiors(buf, isadmin, userid, auth_state) + 1
+					 >= user_folder_limit) {
+		syslog(LOG_ERR, "LIMIT: refused to create %s for %s because of limit %d",
+			        mbox, userid, user_folder_limit);
+		return IMAP_PERMISSION_DENIED;
+	    }
+	}
+    }
+
     if (parentlen != 0) {
 	/* check acl */
 	if (!isadmin &&
@@ -3455,7 +3473,7 @@ mboxlist_count_addmbox(char *name __attribute__((unused)),
 {
     int *count = (int *)rock;
 
-    *count++;
+    (*count)++;
     
     return 0;
 }
diff --git a/lib/imapoptions b/lib/imapoptions
index 70f40b9..e8e0f6c 100644
--- a/lib/imapoptions
+++ b/lib/imapoptions
@@ -1144,6 +1144,10 @@ product version in the capabilities */
 { "umask", "077", STRING }
 /* The umask value used by various Cyrus IMAP programs. */
 
+{ "user_folder_limit", 0, INT }
+/* Limit the number of folders a user can create in their INBOX.  
+   Set to 0 (default) for no limit.  Only affects folders in user. */
+
 { "username_tolower", 1, SWITCH }
 /* Convert usernames to all lowercase before login/authentication.  This
    is useful with authentication backends which ignore case during
-- 
1.5.6.5

