? run.sh
Index: auth-request.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/auth-request.c,v
retrieving revision 1.93
diff -u -r1.93 auth-request.c
--- auth-request.c	25 Mar 2007 18:31:37 -0000	1.93
+++ auth-request.c	29 Mar 2007 06:19:13 -0000
@@ -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);
 	}
 }
 
Index: auth-request.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/auth-request.h,v
retrieving revision 1.34
diff -u -r1.34 auth-request.h
--- auth-request.h	10 Mar 2007 14:04:34 -0000	1.34
+++ auth-request.h	29 Mar 2007 06:19:13 -0000
@@ -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,
Index: auth-worker-client.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/auth-worker-client.c,v
retrieving revision 1.31
diff -u -r1.31 auth-worker-client.c
--- auth-worker-client.c	16 Feb 2007 12:08:32 -0000	1.31
+++ auth-worker-client.c	29 Mar 2007 06:19:13 -0000
@@ -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
Index: db-sql.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/db-sql.c,v
retrieving revision 1.11
diff -u -r1.11 db-sql.c
--- db-sql.c	15 Dec 2006 18:38:08 -0000	1.11
+++ db-sql.c	29 Mar 2007 06:19:13 -0000
@@ -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;
Index: db-sql.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/db-sql.h,v
retrieving revision 1.4
diff -u -r1.4 db-sql.h
--- db-sql.h	8 Nov 2006 20:22:08 -0000	1.4
+++ db-sql.h	29 Mar 2007 06:19:13 -0000
@@ -10,6 +10,8 @@
 	const char *user_query;
 	const char *update_query;
 	const char *default_pass_scheme;
+
+	bool allow_multiple_rows;
 };
 
 struct sql_connection {
Index: mech-apop.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-apop.c,v
retrieving revision 1.24
diff -u -r1.24 mech-apop.c
--- mech-apop.c	26 Jan 2007 13:40:51 -0000	1.24
+++ mech-apop.c	29 Mar 2007 06:19:13 -0000
@@ -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
Index: mech-cram-md5.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-cram-md5.c,v
retrieving revision 1.25
diff -u -r1.25 mech-cram-md5.c
--- mech-cram-md5.c	8 Nov 2006 20:22:08 -0000	1.25
+++ mech-cram-md5.c	29 Mar 2007 06:19:13 -0000
@@ -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
Index: mech-digest-md5.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-digest-md5.c,v
retrieving revision 1.43
diff -u -r1.43 mech-digest-md5.c
--- mech-digest-md5.c	8 Nov 2006 20:22:08 -0000	1.43
+++ mech-digest-md5.c	29 Mar 2007 06:19:13 -0000
@@ -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
Index: mech-ntlm.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-ntlm.c,v
retrieving revision 1.27
diff -u -r1.27 mech-ntlm.c
--- mech-ntlm.c	8 Nov 2006 20:22:08 -0000	1.27
+++ mech-ntlm.c	29 Mar 2007 06:19:13 -0000
@@ -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;
-		}
-		if (ret < 0) {
-			auth_request_fail(auth_request);
-			return;
+			return TRUE;
 		}
+		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
Index: mech-otp.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-otp.c,v
retrieving revision 1.1
diff -u -r1.1 mech-otp.c
--- mech-otp.c	12 Nov 2006 19:36:41 -0000	1.1
+++ mech-otp.c	29 Mar 2007 06:19:13 -0000
@@ -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
Index: mech-rpa.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-rpa.c,v
retrieving revision 1.28
diff -u -r1.28 mech-rpa.c
--- mech-rpa.c	26 Jan 2007 13:58:48 -0000	1.28
+++ mech-rpa.c	29 Mar 2007 06:19:13 -0000
@@ -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
Index: mech-skey.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech-skey.c,v
retrieving revision 1.1
diff -u -r1.1 mech-skey.c
--- mech-skey.c	12 Nov 2006 19:36:41 -0000	1.1
+++ mech-skey.c	29 Mar 2007 06:19:13 -0000
@@ -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
Index: passdb-sql.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb-sql.c,v
retrieving revision 1.31
diff -u -r1.31 passdb-sql.c
--- passdb-sql.c	15 Dec 2006 18:38:08 -0000	1.31
+++ passdb-sql.c	29 Mar 2007 06:19:13 -0000
@@ -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_query_next_row(result, sql_request);
+		if (row > 0 && ret == 0) {
+			/* no more rows. use the last result. */
+			send_last = TRUE;
+			break;
+		}
 
-	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);
-
-		/* 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);
-
-	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;
+		scheme = password_get_scheme(&password);
+		/* auth_request_set_field() sets scheme */
+		i_assert(password == NULL || scheme != NULL);
+
+		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;
+
+		if (!passdb_handle_credentials(PASSDB_RESULT_END_OF_LIST, NULL,
+					       NULL, callback, auth_request))
+			i_unreached();
 	}
-
-	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);
 	auth_request_unref(&auth_request);
 }
 
Index: passdb.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb.c,v
retrieving revision 1.47
diff -u -r1.47 passdb.c
--- passdb.c	15 Feb 2007 11:51:33 -0000	1.47
+++ passdb.c	29 Mar 2007 06:19:13 -0000
@@ -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,
Index: passdb.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb.h,v
retrieving revision 1.37
diff -u -r1.37 passdb.h
--- passdb.h	16 Dec 2006 13:37:32 -0000	1.37
+++ passdb.h	29 Mar 2007 06:19:13 -0000
@@ -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);
Index: userdb-static.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/userdb-static.c,v
retrieving revision 1.23
diff -u -r1.23 userdb-static.c
--- userdb-static.c	21 Mar 2007 20:13:00 -0000	1.23
+++ userdb-static.c	29 Mar 2007 06:19:13 -0000
@@ -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,
