diff -r 84eea1977632 src/auth/auth-request.c
--- a/src/auth/auth-request.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/auth-request.c	Fri Jan 09 11:16:40 2009 -0500
@@ -506,6 +506,52 @@
 	else {
 		passdb->iface.verify_plain(request, password,
 					   auth_request_verify_plain_callback);
+	}
+}
+
+void auth_request_verify_reponse(struct auth_request *request,
+				 const char *challenge, const char *response,
+				 lookup_credentials_callback_t *callback)
+{
+	struct passdb_module *passdb = request->passdb->passdb;
+	const char *cache_key, *cache_cred, *cache_scheme;
+	const unsigned char *credentials;
+	size_t size;
+	enum passdb_result result;
+
+	i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
+
+	request->private_callback.verify_plain = callback;
+
+#if 0 //FIXME
+	cache_key = passdb_cache == NULL ? NULL : passdb->cache_key;
+	if (cache_key != NULL) {
+		if (passdb_cache_lookup_credentials(request, cache_key,
+						    &cache_cred, &cache_scheme,
+						    &result, FALSE)) {
+			if (result == PASSDB_RESULT_OK &&
+			    !passdb_get_credentials(request, cache_cred,
+						    cache_scheme,
+						    &credentials, &size))
+				result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE;
+			auth_request_lookup_credentials_finish(
+				result, credentials, size, request);
+			return;
+		}
+	}
+#endif
+
+	request->state = AUTH_REQUEST_STATE_PASSDB;
+
+	if (passdb->iface.lookup_credentials == NULL) {
+		/* this passdb doesn't support credentials */
+		auth_request_lookup_credentials_callback(
+			PASSDB_RESULT_SCHEME_NOT_AVAILABLE, NULL, 0, request);
+	} else if (passdb->blocking) {
+		passdb_blocking_lookup_credentials(request);
+	} else {
+		passdb->iface.lookup_credentials(request,
+			auth_request_lookup_credentials_callback);
 	}
 }
 
diff -r 84eea1977632 src/auth/auth-request.h
--- a/src/auth/auth-request.h	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/auth-request.h	Fri Jan 09 11:16:40 2009 -0500
@@ -128,6 +128,14 @@
 void auth_request_lookup_credentials(struct auth_request *request,
 				     const char *scheme,
 				     lookup_credentials_callback_t *callback);
+/* If passdb.verify_response() was used, callback will return success with
+   data=NULL and there's no need to verify it further. Otherwise if
+   passdb.lookup_credentials() was used the data won't be NULL and its
+   correctness must be verified against the challenge+response. */
+void auth_request_verify_reponse(struct auth_request *request,
+				 const char *scheme,
+				 const char *challenge, const char *response,
+				 lookup_credentials_callback_t *callback);
 void auth_request_lookup_user(struct auth_request *request,
 			      userdb_callback_t *callback);
 
diff -r 84eea1977632 src/auth/auth.c
--- a/src/auth/auth.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/auth.c	Fri Jan 09 11:16:40 2009 -0500
@@ -136,6 +136,17 @@
 	return FALSE;
 }
 
+static bool auth_passdb_list_have_verify_response(struct auth *auth)
+{
+	struct auth_passdb *passdb;
+
+	for (passdb = auth->passdbs; passdb != NULL; passdb = passdb->next) {
+		if (passdb->passdb->iface.verify_response != NULL)
+			return TRUE;
+	}
+	return FALSE;
+}
+
 static bool auth_passdb_list_have_lookup_credentials(struct auth *auth)
 {
 	struct auth_passdb *passdb;
@@ -169,6 +180,9 @@
 			return FALSE;
 		break;
 	case MECH_PASSDB_NEED_VERIFY_RESPONSE:
+		if (!auth_passdb_list_have_verify_response(auth))
+			return FALSE;
+		break;
 	case MECH_PASSDB_NEED_LOOKUP_CREDENTIALS:
 		if (!auth_passdb_list_have_lookup_credentials(auth))
 			return FALSE;
diff -r 84eea1977632 src/auth/db-checkpassword.c
--- a/src/auth/db-checkpassword.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/db-checkpassword.c	Fri Jan 09 11:16:40 2009 -0500
@@ -49,6 +49,7 @@
 		safe_memset(request->password, 0, strlen(request->password));
 		i_free(request->password);
 	}
+	i_free(request->challenge);
 	i_free(request);
 }
 
@@ -91,6 +92,7 @@
 	   pipe, also pass some other possibly interesting information
 	   via environment. Use UCSPI names for local/remote IPs. */
 	env_put("PROTO=TCP"); /* UCSPI */
+	env_put(t_strconcat("MECHANISM=", request->mech->mech_name, NULL));
 	env_put(t_strconcat("SERVICE=", request->service, NULL));
 	if (request->local_ip.family != 0) {
 		env_put(t_strconcat("TCPLOCALIP=",
@@ -157,35 +159,37 @@
 
 void checkpassword_child_output(struct chkpw_auth_request *request)
 {
-	/* Send: username \0 password \0 timestamp \0.
-	   Must be 512 bytes or less. The "timestamp" parameter is actually
-	   useful only for APOP authentication. We don't support it, so
-	   keep it empty */
+	/* Send: username \0 password \0 timestamp \0. */
 	struct auth_request *auth_request = request->request;
 	buffer_t *buf;
-	const unsigned char *data;
-	size_t size;
 	ssize_t ret;
 
 	buf = buffer_create_dynamic(pool_datastack_create(), 512+1);
 	buffer_append(buf, auth_request->user, strlen(auth_request->user)+1);
-        if (request->password != NULL)
-                buffer_append(buf, request->password, strlen(request->password)+1);
-        else
-                buffer_append_c(buf, '\0');
-	buffer_append_c(buf, '\0');
-	data = buffer_get_data(buf, &size);
+	if (request->password == NULL)
+		buffer_append_c(buf, '\0');
+	else {
+		buffer_append(buf, request->password,
+			      strlen(request->password) + 1);
+	}
+	if (request->challenge == NULL)
+		buffer_append_c(buf, '\0');
+	else {
+		buffer_append(buf, request->challenge,
+			      strlen(request->challenge) + 1);
+	}
 
-	if (size > 512) {
+	if (buf->used > 512) {
 		auth_request_log_error(request->request, "checkpassword",
-			"output larger than 512 bytes: %"PRIuSIZE_T, size);
+			"output larger than 512 bytes: %"PRIuSIZE_T, buf->used);
 		request->finish_callback(request,
 					 request->internal_failure_code);
 		return;
 	}
 
-	ret = write(request->fd_out, data + request->write_pos,
-		    size - request->write_pos);
+	ret = write(request->fd_out,
+		    CONST_PTR_OFFSET(buf->data, request->write_pos),
+		    buf->used - request->write_pos);
 	if (ret <= 0) {
 		if (ret < 0) {
 			auth_request_log_error(request->request,
@@ -197,7 +201,7 @@
 	}
 
 	request->write_pos += ret;
-	if (request->write_pos < size)
+	if (request->write_pos < buf->used)
 		return;
 
 	io_remove(&request->io_out);
diff -r 84eea1977632 src/auth/db-checkpassword.h
--- a/src/auth/db-checkpassword.h	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/db-checkpassword.h	Fri Jan 09 11:16:40 2009 -0500
@@ -22,7 +22,7 @@
 	pid_t pid;
 
 	string_t *input_buf;
-	char *password;
+	char *challenge, *password;
 	unsigned int write_pos;
 
 	struct auth_request *request;
diff -r 84eea1977632 src/auth/passdb-bsdauth.c
--- a/src/auth/passdb-bsdauth.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb-bsdauth.c	Fri Jan 09 11:16:40 2009 -0500
@@ -78,6 +78,7 @@
 
 	bsdauth_verify_plain,
 	NULL,
+	NULL,
 	NULL
 };
 #else
diff -r 84eea1977632 src/auth/passdb-checkpassword.c
--- a/src/auth/passdb-checkpassword.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb-checkpassword.c	Fri Jan 09 11:16:40 2009 -0500
@@ -143,8 +143,9 @@
 }
 
 static void
-checkpassword_verify_plain(struct auth_request *request, const char *password,
-			   verify_plain_callback_t *callback)
+checkpassword_verify_response(struct auth_request *request,
+			      const char *challenge, const char *password,
+			      verify_plain_callback_t *callback)
 {
 	struct passdb_module *_module = request->passdb->passdb;
 	struct checkpassword_passdb_module *module =
@@ -199,6 +200,7 @@
 	chkpw_auth_request->fd_in = fd_in[0];
 	chkpw_auth_request->fd_out = fd_out[1];
 	chkpw_auth_request->pid = pid;
+	chkpw_auth_request->challenge = i_strdup(challenge);
 	chkpw_auth_request->password = i_strdup(password);
 	chkpw_auth_request->request = request;
 	chkpw_auth_request->callback = callback;
@@ -225,6 +227,13 @@
 		checkpassword_passdb_children =
 			child_wait_new_with_pid(pid, sigchld_handler, module);
 	}
+}
+
+static void
+checkpassword_verify_plain(struct auth_request *request, const char *password,
+			   verify_plain_callback_t *callback)
+{
+	checkpassword_verify_response(request, NULL, password, callback);
 }
 
 static struct passdb_module *
@@ -271,6 +280,7 @@
 	checkpassword_deinit,
 
 	checkpassword_verify_plain,
+	checkpassword_verify_response,
 	NULL,
 	NULL
 };
diff -r 84eea1977632 src/auth/passdb-ldap.c
--- a/src/auth/passdb-ldap.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb-ldap.c	Fri Jan 09 11:16:40 2009 -0500
@@ -424,6 +424,7 @@
 	passdb_ldap_deinit,
 
 	ldap_verify_plain,
+	NULL,
 	ldap_lookup_credentials,
 	NULL
 };
diff -r 84eea1977632 src/auth/passdb-pam.c
--- a/src/auth/passdb-pam.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb-pam.c	Fri Jan 09 11:16:40 2009 -0500
@@ -383,6 +383,7 @@
 
 	pam_verify_plain,
 	NULL,
+	NULL,
 	NULL
 };
 #else
diff -r 84eea1977632 src/auth/passdb-passwd-file.c
--- a/src/auth/passdb-passwd-file.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb-passwd-file.c	Fri Jan 09 11:16:40 2009 -0500
@@ -186,6 +186,7 @@
 	passwd_file_deinit,
 
 	passwd_file_verify_plain,
+	NULL,
 	passwd_file_lookup_credentials,
 	NULL
 };
diff -r 84eea1977632 src/auth/passdb-passwd.c
--- a/src/auth/passdb-passwd.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb-passwd.c	Fri Jan 09 11:16:40 2009 -0500
@@ -82,6 +82,7 @@
 
 	passwd_verify_plain,
 	NULL,
+	NULL,
 	NULL
 };
 
diff -r 84eea1977632 src/auth/passdb-shadow.c
--- a/src/auth/passdb-shadow.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb-shadow.c	Fri Jan 09 11:16:40 2009 -0500
@@ -82,6 +82,7 @@
 
 	shadow_verify_plain,
 	NULL,
+	NULL,
 	NULL
 };
 #else
diff -r 84eea1977632 src/auth/passdb-sia.c
--- a/src/auth/passdb-sia.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb-sia.c	Fri Jan 09 11:16:40 2009 -0500
@@ -57,6 +57,7 @@
 
         local_sia_verify_plain,
 	NULL,
+	NULL,
 	NULL
 };
 #else
diff -r 84eea1977632 src/auth/passdb-sql.c
--- a/src/auth/passdb-sql.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb-sql.c	Fri Jan 09 11:16:40 2009 -0500
@@ -270,6 +270,7 @@
 	passdb_sql_deinit,
        
 	sql_verify_plain,
+	NULL,
 	sql_lookup_credentials,
 	sql_set_credentials
 };
diff -r 84eea1977632 src/auth/passdb-vpopmail.c
--- a/src/auth/passdb-vpopmail.c	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb-vpopmail.c	Fri Jan 09 11:16:40 2009 -0500
@@ -197,6 +197,7 @@
 	vpopmail_deinit,
 
 	vpopmail_verify_plain,
+	NULL,
 	vpopmail_lookup_credentials,
 	NULL
 };
diff -r 84eea1977632 src/auth/passdb.h
--- a/src/auth/passdb.h	Fri Jan 09 11:15:56 2009 -0500
+++ b/src/auth/passdb.h	Fri Jan 09 11:16:40 2009 -0500
@@ -38,6 +38,11 @@
 	/* Check if plaintext password matches */
 	void (*verify_plain)(struct auth_request *request, const char *password,
 			     verify_plain_callback_t *callback);
+	/* Check if challenge+response pair authenticates the user successfully
+	   for the request->mech auth mechanism. */
+	void (*verify_response)(struct auth_request *request,
+				const char *challenge, const char *response,
+				verify_plain_callback_t *callback);
 
 	/* Return authentication credentials, set in
 	   auth_request->credentials. */
