changeset 5462:163b48489bc6 HEAD

Moved all storage destruction code to mail-storage.c and made destroy() optional. Removed set_callbacks(). Made autodetect() optional.
author Timo Sirainen <tss@iki.fi>
date Fri, 30 Mar 2007 17:12:46 +0300
parents 08b42ced91a6
children 56832d6557dc
files src/auth/auth-request.c src/auth/auth-request.h src/auth/auth-worker-client.c src/auth/db-sql.c src/auth/db-sql.h src/auth/mech-apop.c src/auth/mech-cram-md5.c src/auth/mech-digest-md5.c src/auth/mech-ntlm.c src/auth/mech-otp.c src/auth/mech-rpa.c src/auth/mech-skey.c src/auth/passdb-sql.c src/auth/passdb.c src/auth/passdb.h src/auth/userdb-static.c src/lib-storage/index/cydir/cydir-storage.c src/lib-storage/index/dbox/dbox-storage.c src/lib-storage/index/index-storage.c src/lib-storage/index/index-storage.h src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c
diffstat 24 files changed, 220 insertions(+), 177 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/auth-request.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/auth-request.c	Fri Mar 30 17:12:46 2007 +0300
@@ -180,6 +180,14 @@
 	request->mech->auth_continue(request, data, data_size);
 }
 
+void auth_request_reset_passdb_lookup(struct auth_request *request)
+{
+	request->passdb_password = NULL;
+
+	if (request->extra_fields != NULL)
+		auth_stream_reply_reset(request->extra_fields);
+}
+
 static void auth_request_save_cache(struct auth_request *request,
 				    enum passdb_result result)
 {
@@ -200,6 +208,7 @@
 		   return success. */
 		return;
 	case PASSDB_RESULT_INTERNAL_FAILURE:
+	case PASSDB_RESULT_END_OF_LIST:
 		i_unreached();
 	}
 
@@ -336,7 +345,7 @@
 		   *result != PASSDB_RESULT_USER_DISABLED) {
 		/* try next passdb. */
                 request->passdb = request->passdb->next;
-		request->passdb_password = NULL;
+		auth_request_reset_passdb_lookup(request);
 
                 if (*result == PASSDB_RESULT_INTERNAL_FAILURE) {
 			/* remember that we have had an internal failure. at
@@ -344,9 +353,6 @@
 			   successfully login. */
 			request->passdb_internal_failure = TRUE;
 		}
-		if (request->extra_fields != NULL)
-			auth_stream_reply_reset(request->extra_fields);
-
 		return FALSE;
 	} else if (request->passdb_internal_failure) {
 		/* last passdb lookup returned internal failure. it may have
@@ -445,27 +451,33 @@
 	}
 }
 
-static void
+static bool
 auth_request_lookup_credentials_callback_finish(enum passdb_result result,
 						const char *password,
 						struct auth_request *request)
 {
 	if (!auth_request_handle_passdb_callback(&result, request)) {
+		if (result != PASSDB_RESULT_END_OF_LIST) {
+			/* see if we can get more credentials */
+			return FALSE;
+		}
+
 		/* try next passdb */
 		auth_request_lookup_credentials(request, request->credentials,
                 	request->private_callback.lookup_credentials);
+		return TRUE;
 	} else {
 		if (request->auth->verbose_debug_passwords &&
 		    result == PASSDB_RESULT_OK) {
 			auth_request_log_debug(request, "password",
 				"Credentials: %s", password);
 		}
-		request->private_callback.
+		return request->private_callback.
 			lookup_credentials(result, password, request);
 	}
 }
 
-void auth_request_lookup_credentials_callback(enum passdb_result result,
+bool auth_request_lookup_credentials_callback(enum passdb_result result,
 					      const char *password,
 					      struct auth_request *request)
 {
@@ -475,7 +487,9 @@
 
 	request->state = AUTH_REQUEST_STATE_MECH_CONTINUE;
 
-	if (result != PASSDB_RESULT_INTERNAL_FAILURE)
+	if (result == PASSDB_RESULT_END_OF_LIST) {
+		/* no more results */
+	} else if (result != PASSDB_RESULT_INTERNAL_FAILURE)
 		auth_request_save_cache(request, result);
 	else {
 		/* lookup failed. if we're looking here only because the
@@ -494,8 +508,12 @@
 		}
 	}
 
-	auth_request_lookup_credentials_callback_finish(result, password,
-							request);
+	if (!auth_request_lookup_credentials_callback_finish(result, password,
+							     request)) {
+		request->state = AUTH_REQUEST_STATE_PASSDB;
+		return FALSE;
+	}
+	return TRUE;
 }
 
 void auth_request_lookup_credentials(struct auth_request *request,
@@ -534,8 +552,9 @@
 			auth_request_lookup_credentials_callback);
 	} else {
 		/* this passdb doesn't support credentials */
-		auth_request_lookup_credentials_callback(
+		bool ret = auth_request_lookup_credentials_callback(
 			PASSDB_RESULT_SCHEME_NOT_AVAILABLE, NULL, request);
+		i_assert(ret);
 	}
 }
 
--- a/src/auth/auth-request.h	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/auth-request.h	Fri Mar 30 17:12:46 2007 +0300
@@ -110,6 +110,7 @@
 			  const unsigned char *data, size_t data_size);
 void auth_request_continue(struct auth_request *request,
 			   const unsigned char *data, size_t data_size);
+void auth_request_reset_passdb_lookup(struct auth_request *request);
 
 void auth_request_verify_plain(struct auth_request *request,
 			       const char *password,
@@ -156,9 +157,10 @@
 
 void auth_request_verify_plain_callback(enum passdb_result result,
 					struct auth_request *request);
-void auth_request_lookup_credentials_callback(enum passdb_result result,
+bool auth_request_lookup_credentials_callback(enum passdb_result result,
 					      const char *credentials,
-					      struct auth_request *request);
+					      struct auth_request *request)
+	__attr_warn_unused_result__;
 void auth_request_set_credentials(struct auth_request *request,
 				  enum passdb_credentials credentials,
 				  const char *data,
--- a/src/auth/auth-worker-client.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/auth-worker-client.c	Fri Mar 30 17:12:46 2007 +0300
@@ -164,7 +164,7 @@
 		verify_plain(auth_request, password, verify_plain_callback);
 }
 
-static void
+static bool
 lookup_credentials_callback(enum passdb_result result, const char *credentials,
 			    struct auth_request *request)
 {
@@ -195,6 +195,7 @@
 	auth_request_unref(&request);
 	auth_worker_client_check_throttle(client);
 	auth_worker_client_unref(&client);
+	return TRUE;
 }
 
 static void
--- a/src/auth/db-sql.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/db-sql.c	Fri Mar 30 17:12:46 2007 +0300
@@ -20,6 +20,7 @@
 	DEF(SET_STR, user_query),
  	DEF(SET_STR, update_query),
 	DEF(SET_STR, default_pass_scheme),
+	DEF(SET_BOOL, allow_multiple_rows),
 
 	{ 0, NULL, 0 }
 };
@@ -30,7 +31,8 @@
 	MEMBER(password_query) "SELECT password FROM users WHERE userid = '%u'",
 	MEMBER(user_query) "SELECT home, uid, gid FROM users WHERE userid = '%u'",
 	MEMBER(update_query) "UPDATE users SET password = '%w' WHERE userid = '%u'",
-	MEMBER(default_pass_scheme) "PLAIN-MD5"
+	MEMBER(default_pass_scheme) "PLAIN-MD5",
+	MEMBER(allow_multiple_rows) FALSE
 };
 
 static struct sql_connection *connections = NULL;
--- a/src/auth/db-sql.h	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/db-sql.h	Fri Mar 30 17:12:46 2007 +0300
@@ -10,6 +10,8 @@
 	const char *user_query;
 	const char *update_query;
 	const char *default_pass_scheme;
+
+	bool allow_multiple_rows;
 };
 
 struct sql_connection {
--- a/src/auth/mech-apop.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/mech-apop.c	Fri Mar 30 17:12:46 2007 +0300
@@ -43,7 +43,7 @@
 	return memcmp(digest, request->digest, 16) == 0;
 }
 
-static void
+static bool
 apop_credentials_callback(enum passdb_result result,
 			  const char *credentials,
 			  struct auth_request *auth_request)
@@ -53,10 +53,9 @@
 
 	switch (result) {
 	case PASSDB_RESULT_OK:
-		if (verify_credentials(request, credentials))
-			auth_request_success(auth_request, NULL, 0);
-		else
-			auth_request_fail(auth_request);
+		if (!verify_credentials(request, credentials))
+			return FALSE;
+		auth_request_success(auth_request, NULL, 0);
 		break;
 	case PASSDB_RESULT_INTERNAL_FAILURE:
 		auth_request_internal_failure(auth_request);
@@ -65,6 +64,7 @@
 		auth_request_fail(auth_request);
 		break;
 	}
+	return TRUE;
 }
 
 static void
--- a/src/auth/mech-cram-md5.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/mech-cram-md5.c	Fri Mar 30 17:12:46 2007 +0300
@@ -107,7 +107,7 @@
 	return TRUE;
 }
 
-static void credentials_callback(enum passdb_result result,
+static bool credentials_callback(enum passdb_result result,
 				 const char *credentials,
 				 struct auth_request *auth_request)
 {
@@ -116,10 +116,11 @@
 
 	switch (result) {
 	case PASSDB_RESULT_OK:
-		if (verify_credentials(request, credentials))
-			auth_request_success(auth_request, NULL, 0);
-		else
-			auth_request_fail(auth_request);
+		if (!verify_credentials(request, credentials)) {
+			/* see if we have more credentials */
+			return FALSE;
+		}
+		auth_request_success(auth_request, NULL, 0);
 		break;
 	case PASSDB_RESULT_INTERNAL_FAILURE:
 		auth_request_internal_failure(auth_request);
@@ -128,6 +129,7 @@
 		auth_request_fail(auth_request);
 		break;
 	}
+	return TRUE;
 }
 
 static void
--- a/src/auth/mech-digest-md5.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/mech-digest-md5.c	Fri Mar 30 17:12:46 2007 +0300
@@ -518,7 +518,7 @@
 	return !failed;
 }
 
-static void credentials_callback(enum passdb_result result,
+static bool credentials_callback(enum passdb_result result,
 				 const char *credentials,
 				 struct auth_request *auth_request)
 {
@@ -527,10 +527,8 @@
 
 	switch (result) {
 	case PASSDB_RESULT_OK:
-		if (!verify_credentials(request, credentials)) {
-			auth_request_fail(auth_request);
-			return;
-		}
+		if (!verify_credentials(request, credentials))
+			return FALSE;
 
 		request->authenticated = TRUE;
 		auth_request->callback(auth_request,
@@ -545,6 +543,7 @@
 		auth_request_fail(auth_request);
 		break;
 	}
+	return TRUE;
 }
 
 static void
--- a/src/auth/mech-ntlm.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/mech-ntlm.c	Fri Mar 30 17:12:46 2007 +0300
@@ -61,7 +61,7 @@
 	return memcmp(lm_response, client_response, LM_RESPONSE_SIZE) == 0;
 }
 
-static void
+static bool
 lm_credentials_callback(enum passdb_result result,
 			const char *credentials,
 			struct auth_request *auth_request)
@@ -71,10 +71,10 @@
 
 	switch (result) {
 	case PASSDB_RESULT_OK:
-		if (lm_verify_credentials(request, credentials))
-			auth_request_success(auth_request, NULL, 0);
-		else
-			auth_request_fail(auth_request);
+		if (!lm_verify_credentials(request, credentials))
+			return FALSE;
+
+		auth_request_success(auth_request, NULL, 0);
 		break;
 	case PASSDB_RESULT_INTERNAL_FAILURE:
 		auth_request_internal_failure(auth_request);
@@ -83,6 +83,7 @@
 		auth_request_fail(auth_request);
 		break;
 	}
+	return TRUE;
 }
 
 static int ntlm_verify_credentials(struct ntlm_auth_request *request,
@@ -145,7 +146,7 @@
 	}
 }
 
-static void
+static bool
 ntlm_credentials_callback(enum passdb_result result,
 			  const char *credentials,
 			  struct auth_request *auth_request)
@@ -159,16 +160,14 @@
 		ret = ntlm_verify_credentials(request, credentials);
 		if (ret > 0) {
 			auth_request_success(auth_request, NULL, 0);
-			return;
+			return TRUE;
 		}
-		if (ret < 0) {
-			auth_request_fail(auth_request);
-			return;
-		}
+		if (ret < 0)
+			return FALSE;
 		break;
 	case PASSDB_RESULT_INTERNAL_FAILURE:
 		auth_request_internal_failure(auth_request);
-		return;
+		return TRUE;
 	default:
 		break;
 	}
@@ -177,6 +176,7 @@
 	   try with LM credentials */
 	auth_request_lookup_credentials(auth_request, PASSDB_CREDENTIALS_LANMAN,
 					lm_credentials_callback);
+	return TRUE;
 }
 
 static void
--- a/src/auth/mech-otp.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/mech-otp.c	Fri Mar 30 17:12:46 2007 +0300
@@ -54,7 +54,7 @@
 			       answer, strlen(answer));
 }
 
-static void
+static bool
 skey_credentials_callback(enum passdb_result result,
 			  const char *credentials,
 			  struct auth_request *auth_request)
@@ -70,9 +70,10 @@
 		auth_request_fail(auth_request);
 		break;
 	}
+	return TRUE;
 }
 
-static void
+static bool
 otp_credentials_callback(enum passdb_result result,
 			 const char *credentials,
 			 struct auth_request *auth_request)
@@ -91,6 +92,7 @@
 						skey_credentials_callback);
 		break;
 	}
+	return TRUE;
 }
 
 static void
--- a/src/auth/mech-rpa.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/mech-rpa.c	Fri Mar 30 17:12:46 2007 +0300
@@ -453,7 +453,7 @@
 	return memcmp(response, request->user_response, 16) == 0;
 }
 
-static void
+static bool
 rpa_credentials_callback(enum passdb_result result,
 			 const char *credentials,
 			 struct auth_request *auth_request)
@@ -466,14 +466,13 @@
 	switch (result) {
 	case PASSDB_RESULT_OK:
 		if (!verify_credentials(request, credentials))
-			auth_request_fail(auth_request);
-		else {
-			token4 = mech_rpa_build_token4(request, &token4_size);
-			auth_request->callback(auth_request,
-					       AUTH_CLIENT_RESULT_CONTINUE,
-					       token4, token4_size);
-			request->phase = 2;
-		}
+			return FALSE;
+
+		token4 = mech_rpa_build_token4(request, &token4_size);
+		auth_request->callback(auth_request,
+				       AUTH_CLIENT_RESULT_CONTINUE,
+				       token4, token4_size);
+		request->phase = 2;
 		break;
 	case PASSDB_RESULT_INTERNAL_FAILURE:
 		auth_request_internal_failure(auth_request);
@@ -482,6 +481,7 @@
 		auth_request_fail(auth_request);
 		break;
 	}
+	return TRUE;
 }
 
 static void
--- a/src/auth/mech-skey.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/mech-skey.c	Fri Mar 30 17:12:46 2007 +0300
@@ -60,7 +60,7 @@
 			       answer, strlen(answer));
 }
 
-static void
+static bool
 otp_credentials_callback(enum passdb_result result,
 			 const char *credentials,
 			 struct auth_request *auth_request)
@@ -76,9 +76,10 @@
 		auth_request_fail(auth_request);
 		break;
 	}
+	return TRUE;
 }
 
-static void
+static bool
 skey_credentials_callback(enum passdb_result result,
 			  const char *credentials,
 			  struct auth_request *auth_request)
@@ -97,6 +98,7 @@
 						otp_credentials_callback);
 		break;
 	}
+	return TRUE;
 }
 
 static void
--- a/src/auth/passdb-sql.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/passdb-sql.c	Fri Mar 30 17:12:46 2007 +0300
@@ -52,76 +52,131 @@
 	}
 }
 
+static int sql_query_next_row(struct sql_result *result,
+			      struct passdb_sql_request *sql_request)
+{
+	struct auth_request *auth_request = sql_request->auth_request;
+	struct passdb_module *_module = auth_request->passdb->passdb;
+	struct sql_passdb_module *module = (struct sql_passdb_module *)_module;
+	int ret;
+
+	ret = sql_result_next_row(result);
+	if (ret <= 0) {
+		if (ret == 0)
+			return 0;
+
+		auth_request_log_error(auth_request, "sql",
+				       "Password query failed: %s",
+				       sql_result_get_error(result));
+		return -1;
+	}
+
+	sql_query_save_results(result, sql_request);
+
+	/* Note that we really want to check if the password field is
+	   found. Just checking if password is set isn't enough,
+	   because with proxies we might want to return NULL as
+	   password. */
+	if (sql_result_find_field(result, "password") < 0) {
+		auth_request_log_error(auth_request, "sql",
+			"Password query must return a field named 'password'");
+	}
+
+	if (!module->conn->set.allow_multiple_rows) {
+		if (sql_result_next_row(result) > 0) {
+			auth_request_log_error(auth_request, "sql",
+				"Password query returned multiple matches "
+				"and allow_multiple_rows=no");
+			return -1;
+		}
+	}
+	return 1;
+}
+
 static void sql_query_callback(struct sql_result *result,
 			       struct passdb_sql_request *sql_request)
 {
 	struct auth_request *auth_request = sql_request->auth_request;
 	enum passdb_result passdb_result;
 	const char *user, *password, *scheme;
+	unsigned int row;
 	int ret;
+	bool send_last = FALSE;
 
 	passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
+
 	user = auth_request->user;
-	password = NULL;
+	for (row = 0;; row++) {
+		if (row > 0)
+			auth_request_reset_passdb_lookup(auth_request);
 
-	ret = sql_result_next_row(result);
-	if (ret < 0) {
-		auth_request_log_error(auth_request, "sql",
-				       "Password query failed: %s",
-				       sql_result_get_error(result));
-	} else if (ret == 0) {
-		auth_request_log_info(auth_request, "sql", "unknown user");
-		passdb_result = PASSDB_RESULT_USER_UNKNOWN;
-	} else {
-		sql_query_save_results(result, sql_request);
+		ret = sql_query_next_row(result, sql_request);
+		if (row > 0 && ret == 0) {
+			/* no more rows. use the last result. */
+			send_last = TRUE;
+			break;
+		}
 
-		/* Note that we really want to check if the password field is
-		   found. Just checking if password is set isn't enough,
-		   because with proxies we might want to return NULL as
-		   password. */
-		if (sql_result_find_field(result, "password") < 0) {
-			auth_request_log_error(auth_request, "sql",
-				"Password query must return a field named "
-				"'password'");
-		} else if (sql_result_next_row(result) > 0) {
-			auth_request_log_error(auth_request, "sql",
-				"Password query returned multiple matches");
-		} else {
+		switch (ret) {
+		case 1:
 			/* passdb_password may change on the way,
 			   so we'll need to strdup. */
 			password = t_strdup(auth_request->passdb_password);
 			if (password == NULL)
 				auth_request->no_password = TRUE;
 			passdb_result = PASSDB_RESULT_OK;
+			break;
+		case 0:
+			auth_request_log_info(auth_request, "sql",
+					      "unknown user");
+			passdb_result = PASSDB_RESULT_USER_UNKNOWN;
+			password = NULL;
+			break;
+		default:
+			passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
+			password = NULL;
+			break;
 		}
-	}
 
-	scheme = password_get_scheme(&password);
-	/* auth_request_set_field() sets scheme */
-	i_assert(password == NULL || scheme != NULL);
+		scheme = password_get_scheme(&password);
+		/* auth_request_set_field() sets scheme */
+		i_assert(password == NULL || scheme != NULL);
 
-	if (auth_request->credentials != -1) {
-		passdb_handle_credentials(passdb_result, password, scheme,
-			sql_request->callback.lookup_credentials,
-			auth_request);
-		auth_request_unref(&auth_request);
-		return;
+		if (auth_request->credentials != -1) {
+			lookup_credentials_callback_t *callback =
+				sql_request->callback.lookup_credentials;
+
+			if (passdb_handle_credentials(passdb_result, password,
+						      scheme, callback,
+						      auth_request))
+				break;
+		} else {
+			/* verify plain */
+			if (password == NULL)
+				break;
+
+			if (auth_request_password_verify(auth_request,
+						auth_request->mech_password,
+						password, scheme, "sql") > 0) {
+				passdb_result = PASSDB_RESULT_OK;
+				break;
+			}
+			passdb_result = PASSDB_RESULT_PASSWORD_MISMATCH;
+		}
+
+		/* see if there's another row */
 	}
 
-	/* verify plain */
-	if (password == NULL) {
+	if (auth_request->credentials == -1)
 		sql_request->callback.verify_plain(passdb_result, auth_request);
-		auth_request_unref(&auth_request);
-		return;
-	}
+	else if (send_last) {
+		lookup_credentials_callback_t *callback =
+			sql_request->callback.lookup_credentials;
 
-	ret = auth_request_password_verify(auth_request,
-					   auth_request->mech_password,
-					   password, scheme, "sql");
-
-	sql_request->callback.verify_plain(ret > 0 ? PASSDB_RESULT_OK :
-					   PASSDB_RESULT_PASSWORD_MISMATCH,
-					   auth_request);
+		if (!passdb_handle_credentials(PASSDB_RESULT_END_OF_LIST, NULL,
+					       NULL, callback, auth_request))
+			i_unreached();
+	}
 	auth_request_unref(&auth_request);
 }
 
--- a/src/auth/passdb.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/passdb.c	Fri Mar 30 17:12:46 2007 +0300
@@ -118,21 +118,19 @@
 	return password;
 }
 
-void passdb_handle_credentials(enum passdb_result result,
+bool passdb_handle_credentials(enum passdb_result result,
 			       const char *password, const char *scheme,
 			       lookup_credentials_callback_t *callback,
                                struct auth_request *auth_request)
 {
-	if (result != PASSDB_RESULT_OK) {
-		callback(result, NULL, auth_request);
-		return;
-	}
+	if (result != PASSDB_RESULT_OK)
+		return callback(result, NULL, auth_request);
 
 	password = password == NULL ? NULL :
 		passdb_get_credentials(auth_request, password, scheme);
 	if (password == NULL)
 		result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE;
-	callback(result, password, auth_request);
+	return callback(result, password, auth_request);
 }
 
 struct auth_passdb *passdb_preinit(struct auth *auth, const char *driver,
--- a/src/auth/passdb.h	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/passdb.h	Fri Mar 30 17:12:46 2007 +0300
@@ -27,6 +27,7 @@
 	PASSDB_RESULT_USER_UNKNOWN = -3,
 	PASSDB_RESULT_USER_DISABLED = -4,
 	PASSDB_RESULT_PASS_EXPIRED = -5,
+	PASSDB_RESULT_END_OF_LIST = -6,
 
 	PASSDB_RESULT_PASSWORD_MISMATCH = 0,
 	PASSDB_RESULT_OK = 1
@@ -34,7 +35,11 @@
 
 typedef void verify_plain_callback_t(enum passdb_result result,
 				     struct auth_request *request);
-typedef void lookup_credentials_callback_t(enum passdb_result result,
+/* Returns TRUE if successful, FALSE if more credentials are wanted
+   (ie. support for multiple passwords). If FALSE is returned, the caller must
+   call this function again. If there are no more results,
+   result=PASSDB_RESULT_END_OF_LIST */
+typedef bool lookup_credentials_callback_t(enum passdb_result result,
 					   const char *password,
 					   struct auth_request *request);
 typedef void set_credentials_callback_t(enum passdb_result result,
@@ -80,10 +85,11 @@
 passdb_get_credentials(struct auth_request *auth_request,
 		       const char *password, const char *scheme);
 
-void passdb_handle_credentials(enum passdb_result result,
+bool passdb_handle_credentials(enum passdb_result result,
 			       const char *password, const char *scheme,
 			       lookup_credentials_callback_t *callback,
-                               struct auth_request *auth_request);
+			       struct auth_request *auth_request)
+	__attr_warn_unused_result__;
 
 const char *passdb_credentials_to_str(enum passdb_credentials credentials,
 				      const char *wanted_scheme);
--- a/src/auth/userdb-static.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/auth/userdb-static.c	Fri Mar 30 17:12:46 2007 +0300
@@ -60,7 +60,7 @@
 	t_pop();
 }
 
-static void
+static bool
 static_credentials_callback(enum passdb_result result,
 			    const char *password __attr_unused__,
 			    struct auth_request *auth_request)
@@ -92,6 +92,7 @@
 	}
 
 	i_free(ctx);
+	return TRUE;
 }
 
 static void static_lookup(struct auth_request *auth_request,
--- a/src/lib-storage/index/cydir/cydir-storage.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/lib-storage/index/cydir/cydir-storage.c	Fri Mar 30 17:12:46 2007 +0300
@@ -138,18 +138,6 @@
 	return 0;
 }
 
-static void cydir_free(struct mail_storage *storage)
-{
-	index_storage_deinit(storage);
-	pool_unref(storage->pool);
-}
-
-static bool cydir_autodetect(const char *data __attr_unused__,
-			     enum mail_storage_flags flags __attr_unused__)
-{
-	return FALSE;
-}
-
 static int create_cydir(struct mail_storage *storage, const char *path)
 {
 	const char *error;
@@ -480,9 +468,8 @@
 		cydir_class_deinit,
 		cydir_alloc,
 		cydir_create,
-		cydir_free,
-		cydir_autodetect,
-		index_storage_set_callbacks,
+		NULL,
+		NULL,
 		cydir_mailbox_open,
 		cydir_mailbox_create,
 		index_storage_get_last_error
--- a/src/lib-storage/index/dbox/dbox-storage.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Fri Mar 30 17:12:46 2007 +0300
@@ -231,12 +231,6 @@
 	return 0;
 }
 
-static void dbox_free(struct mail_storage *storage)
-{
-	index_storage_deinit(storage);
-	pool_unref(storage->pool);
-}
-
 static bool dbox_autodetect(const char *data, enum mail_storage_flags flags)
 {
 	bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
@@ -611,9 +605,8 @@
 		dbox_class_deinit,
 		dbox_alloc,
 		dbox_create,
-		dbox_free,
+		NULL,
 		dbox_autodetect,
-		index_storage_set_callbacks,
 		dbox_mailbox_open,
 		dbox_mailbox_create,
 		index_storage_get_last_error
--- a/src/lib-storage/index/index-storage.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/lib-storage/index/index-storage.c	Fri Mar 30 17:12:46 2007 +0300
@@ -39,14 +39,6 @@
 static struct index_list *indexes = NULL;
 static struct timeout *to_index = NULL;
 
-void index_storage_deinit(struct mail_storage *storage)
-{
-	mailbox_list_deinit(storage->list);
-	i_free(storage->error);
-
-        index_storage_destroy_unrefed();
-}
-
 static void index_storage_add(struct mail_index *index,
 			      const char *mailbox_path, struct stat *st)
 {
@@ -416,14 +408,6 @@
 	return mail_index_view_is_inconsistent(ibox->view);
 }
 
-void index_storage_set_callbacks(struct mail_storage *storage,
-				 struct mail_storage_callbacks *callbacks,
-				 void *context)
-{
-	*storage->callbacks = *callbacks;
-	storage->callback_context = context;
-}
-
 const char *index_storage_get_last_error(struct mail_storage *storage,
 					 bool *syntax_error_r,
 					 bool *temporary_error_r)
--- a/src/lib-storage/index/index-storage.h	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/lib-storage/index/index-storage.h	Fri Mar 30 17:12:46 2007 +0300
@@ -101,8 +101,6 @@
 void index_storage_unref(struct mail_index *index);
 void index_storage_destroy_unrefed(void);
 
-void index_storage_deinit(struct mail_storage *storage);
-
 void index_storage_mailbox_init(struct index_mailbox *ibox, const char *name,
 				enum mailbox_open_flags flags,
 				bool move_to_memory);
@@ -139,9 +137,6 @@
 
 int index_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
 
-void index_storage_set_callbacks(struct mail_storage *storage,
-				 struct mail_storage_callbacks *callbacks,
-				 void *context);
 const char *index_storage_get_last_error(struct mail_storage *storage,
 					 bool *syntax_error_r,
 					 bool *temporary_error_r);
--- a/src/lib-storage/index/maildir/maildir-storage.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Fri Mar 30 17:12:46 2007 +0300
@@ -292,12 +292,6 @@
 	return 0;
 }
 
-static void maildir_free(struct mail_storage *storage)
-{
-	index_storage_deinit(storage);
-	pool_unref(storage->pool);
-}
-
 static bool maildir_autodetect(const char *data, enum mail_storage_flags flags)
 {
 	bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
@@ -1070,9 +1064,8 @@
 		maildir_class_deinit,
 		maildir_alloc,
 		maildir_create,
-		maildir_free,
+		NULL,
 		maildir_autodetect,
-		index_storage_set_callbacks,
 		maildir_mailbox_open,
 		maildir_mailbox_create,
 		index_storage_get_last_error
--- a/src/lib-storage/index/mbox/mbox-storage.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Fri Mar 30 17:12:46 2007 +0300
@@ -444,12 +444,6 @@
 	return 0;
 }
 
-static void mbox_free(struct mail_storage *storage)
-{
-	index_storage_deinit(storage);
-	pool_unref(storage->pool);
-}
-
 static int create_mbox_index_dirs(struct mail_storage *storage,
 				  const char *name)
 {
@@ -1012,9 +1006,8 @@
 		mbox_class_deinit,
 		mbox_alloc,
 		mbox_create,
-		mbox_free,
+		NULL,
 		mbox_autodetect,
-		index_storage_set_callbacks,
 		mbox_mailbox_open,
 		mbox_mailbox_create,
 		index_storage_get_last_error
--- a/src/lib-storage/mail-storage-private.h	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/lib-storage/mail-storage-private.h	Fri Mar 30 17:12:46 2007 +0300
@@ -29,10 +29,6 @@
 
 	bool (*autodetect)(const char *data, enum mail_storage_flags flags);
 
-	void (*set_callbacks)(struct mail_storage *storage,
-			      struct mail_storage_callbacks *callbacks,
-			      void *context);
-
 	struct mailbox *(*mailbox_open)(struct mail_storage *storage,
 					const char *name,
 					struct istream *input,
--- a/src/lib-storage/mail-storage.c	Fri Mar 30 16:40:12 2007 +0300
+++ b/src/lib-storage/mail-storage.c	Fri Mar 30 17:12:46 2007 +0300
@@ -7,6 +7,7 @@
 #include "mail-index-private.h"
 #include "mailbox-list-private.h"
 #include "mail-storage-private.h"
+#include "index/index-storage.h"
 
 #include <stdlib.h>
 #include <time.h>
@@ -122,7 +123,8 @@
 
 	classes = array_get(&storages, &count);
 	for (i = 0; i < count; i++) {
-		if (classes[i]->v.autodetect(data, flags))
+		if (classes[i]->v.autodetect != NULL &&
+		    classes[i]->v.autodetect(data, flags))
 			return classes[i];
 	}
 	return NULL;
@@ -214,7 +216,15 @@
 	i_assert(storage != NULL);
 
 	*_storage = NULL;
-	storage->v.destroy(storage);
+
+	if (storage->v.destroy != NULL)
+		storage->v.destroy(storage);
+
+	mailbox_list_deinit(storage->list);
+	i_free(storage->error);
+	pool_unref(storage->pool);
+
+	index_storage_destroy_unrefed();
 }
 
 void mail_storage_clear_error(struct mail_storage *storage)
@@ -313,7 +323,8 @@
 				struct mail_storage_callbacks *callbacks,
 				void *context)
 {
-	storage->v.set_callbacks(storage, callbacks, context);
+	*storage->callbacks = *callbacks;
+	storage->callback_context = context;
 }
 
 int mail_storage_mailbox_create(struct mail_storage *storage, const char *name,