[dovecot-cvs] dovecot/src/auth auth-request.c, 1.31, 1.32 auth-worker-client.c, 1.14, 1.15 passdb-blocking.c, 1.7, 1.8 passdb-cache.c, 1.12, 1.13 passdb-cache.h, 1.4, 1.5 passdb-ldap.c, 1.32, 1.33 passdb-passwd-file.c, 1.19, 1.20 passdb-sql.c, 1.20, 1.21 passdb.c, 1.36, 1.37 passdb.h, 1.27, 1.28

cras at dovecot.org cras at dovecot.org
Sun Oct 16 15:03:39 EEST 2005


Update of /var/lib/cvs/dovecot/src/auth
In directory talvi:/tmp/cvs-serv1340

Modified Files:
	auth-request.c auth-worker-client.c passdb-blocking.c 
	passdb-cache.c passdb-cache.h passdb-ldap.c 
	passdb-passwd-file.c passdb-sql.c passdb.c passdb.h 
Log Message:
Fixes and cleanups to credentials handling. Also fixed auth caching to work
more correctly in case of internal failures.



Index: auth-request.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/auth-request.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -d -r1.31 -r1.32
--- auth-request.c	7 Oct 2005 10:43:12 -0000	1.31
+++ auth-request.c	16 Oct 2005 12:03:37 -0000	1.32
@@ -29,6 +29,7 @@
 
 	request->refcount = 1;
 	request->created = ioloop_time;
+	request->credentials = -1;
 
 	request->auth = auth;
 	request->mech = mech;
@@ -51,6 +52,7 @@
 	auth_request->auth = auth;
 	auth_request->passdb = auth->passdbs;
 	auth_request->userdb = auth->userdbs;
+	auth_request->credentials = -1;
 
 	return auth_request;
 }
@@ -163,6 +165,21 @@
 	const char *extra_fields;
 	string_t *str;
 
+	switch (result) {
+	case PASSDB_RESULT_USER_UNKNOWN:
+	case PASSDB_RESULT_PASSWORD_MISMATCH:
+	case PASSDB_RESULT_OK:
+	case PASSDB_RESULT_SCHEME_NOT_AVAILABLE:
+		/* can be cached */
+		break;
+	case PASSDB_RESULT_USER_DISABLED:
+		/* FIXME: we can't cache this now, or cache lookup would
+		   return success. */
+		return;
+	case PASSDB_RESULT_INTERNAL_FAILURE:
+		i_unreached();
+	}
+
 	extra_fields = request->extra_fields == NULL ? NULL :
 		auth_stream_reply_export(request->extra_fields);
 	i_assert(extra_fields == NULL ||
@@ -214,69 +231,84 @@
 	auth_cache_insert(passdb_cache, request, passdb->cache_key, str_c(str));
 }
 
+static int
+auth_request_handle_passdb_callback(enum passdb_result *result,
+				    struct auth_request *request)
+{
+	if (request->passdb_password != NULL) {
+		safe_memset(request->passdb_password, 0,
+			    strlen(request->passdb_password));
+	}
+
+	if (request->passdb->deny && *result != PASSDB_RESULT_USER_UNKNOWN) {
+		/* deny passdb. we can get through this step only if the
+		   lookup returned that user doesn't exist in it. internal
+		   errors are fatal here. */
+		if (*result != PASSDB_RESULT_INTERNAL_FAILURE) {
+			auth_request_log_info(request, "passdb",
+					      "User found from deny passdb");
+			*result = PASSDB_RESULT_USER_DISABLED;
+		}
+	} else if (*result != PASSDB_RESULT_OK &&
+		   *result != PASSDB_RESULT_USER_DISABLED &&
+		   request->passdb->next != NULL) {
+		/* try next passdb. */
+		if (*result == PASSDB_RESULT_INTERNAL_FAILURE) {
+			/* remember that we have had an internal failure. at
+			   the end return internal failure if we couldn't
+			   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 &&
+		   *result != PASSDB_RESULT_OK) {
+		/* one of the passdb lookups returned internal failure.
+		   it may have had the correct password, so return internal
+		   failure instead of plain failure. */
+		*result = PASSDB_RESULT_INTERNAL_FAILURE;
+	}
+
+	return TRUE;
+}
+
 void auth_request_verify_plain_callback(enum passdb_result result,
 					struct auth_request *request)
 {
-	const char *cache_key;
-
 	i_assert(request->state == AUTH_REQUEST_STATE_PASSDB);
 
 	request->state = AUTH_REQUEST_STATE_MECH_CONTINUE;
 
-        auth_request_save_cache(request, result);
-
-	cache_key = passdb_cache == NULL ? NULL :
-		request->passdb->passdb->cache_key;
-	if (result == PASSDB_RESULT_INTERNAL_FAILURE && cache_key != NULL) {
+	if (result != PASSDB_RESULT_INTERNAL_FAILURE)
+		auth_request_save_cache(request, result);
+	else {
 		/* lookup failed. if we're looking here only because the
 		   request was expired in cache, fallback to using cached
 		   expired record. */
+		const char *cache_key = request->passdb->passdb->cache_key;
+
 		if (passdb_cache_verify_plain(request, cache_key,
 					      request->mech_password,
 					      &result, TRUE)) {
-			request->private_callback.verify_plain(result, request);
-			safe_memset(request->mech_password, 0,
-				    strlen(request->mech_password));
-			return;
+			auth_request_log_info(request, "passdb",
+				"Fallbacking to expired data from cache");
 		}
 	}
 
-	if (request->passdb_password != NULL) {
-		safe_memset(request->passdb_password, 0,
-			    strlen(request->passdb_password));
-	}
-
-	if (result != PASSDB_RESULT_USER_UNKNOWN && request->passdb->deny) {
-		/* user found from deny passdb. deny this authentication. */
-		auth_request_log_info(request, "passdb",
-				      "User found from deny passdb");
-		result = PASSDB_RESULT_USER_DISABLED;
-	} else if (result != PASSDB_RESULT_OK &&
-		   result != PASSDB_RESULT_USER_DISABLED &&
-		   request->passdb->next != NULL) {
-		/* try next passdb. */
-		if (result == PASSDB_RESULT_INTERNAL_FAILURE)
-			request->passdb_internal_failure = TRUE;
-		if (request->extra_fields != NULL)
-			auth_stream_reply_reset(request->extra_fields);
-
-                request->state = AUTH_REQUEST_STATE_MECH_CONTINUE;
+	if (!auth_request_handle_passdb_callback(&result, request)) {
+		/* try next passdb */
 		request->passdb = request->passdb->next;
 		auth_request_verify_plain(request, request->mech_password,
 			request->private_callback.verify_plain);
-		return;
-	} else if (request->passdb_internal_failure &&
-		   result != PASSDB_RESULT_OK) {
-		/* one of the passdb lookups returned internal failure.
-		   it may have had the correct password, so return internal
-		   failure instead of plain failure. */
-		result = PASSDB_RESULT_INTERNAL_FAILURE;
+	} else {
+		auth_request_ref(request);
+		request->private_callback.verify_plain(result, request);
+		safe_memset(request->mech_password, 0,
+			    strlen(request->mech_password));
+		auth_request_unref(request);
 	}
-
-	auth_request_ref(request);
-	request->private_callback.verify_plain(result, request);
-        safe_memset(request->mech_password, 0, strlen(request->mech_password));
-	auth_request_unref(request);
 }
 
 void auth_request_verify_plain(struct auth_request *request,
@@ -303,6 +335,7 @@
 	}
 
 	request->state = AUTH_REQUEST_STATE_PASSDB;
+	request->credentials = -1;
 
 	if (passdb->blocking)
 		passdb_blocking_verify_plain(request);
@@ -313,41 +346,45 @@
 }
 
 void auth_request_lookup_credentials_callback(enum passdb_result result,
-					      const char *credentials,
+					      const char *password,
 					      struct auth_request *request)
 {
-	const char *cache_key, *scheme;
+	const char *scheme;
 
 	i_assert(request->state == AUTH_REQUEST_STATE_PASSDB);
 
 	request->state = AUTH_REQUEST_STATE_MECH_CONTINUE;
-        auth_request_save_cache(request, result);
 
-	if (request->passdb_password != NULL) {
-		safe_memset(request->passdb_password, 0,
-			    strlen(request->passdb_password));
-	}
-
-	cache_key = passdb_cache == NULL ? NULL :
-		request->passdb->passdb->cache_key;
-	if (result == PASSDB_RESULT_INTERNAL_FAILURE && cache_key != NULL) {
+	if (result != PASSDB_RESULT_INTERNAL_FAILURE)
+		auth_request_save_cache(request, result);
+	else {
 		/* lookup failed. if we're looking here only because the
 		   request was expired in cache, fallback to using cached
 		   expired record. */
+		const char *cache_key = request->passdb->passdb->cache_key;
+
 		if (passdb_cache_lookup_credentials(request, cache_key,
-						    &credentials, &scheme,
-						    TRUE)) {
-			passdb_handle_credentials(credentials != NULL ?
-				PASSDB_RESULT_OK : PASSDB_RESULT_USER_UNKNOWN,
-				request->credentials, credentials, scheme,
-				request->private_callback.lookup_credentials,
-				request);
-			return;
+						    &password, &scheme,
+						    &result, TRUE)) {
+			auth_request_log_info(request, "passdb",
+				"Fallbacking to expired data from cache");
+			password = result != PASSDB_RESULT_OK ? NULL :
+				passdb_get_credentials(request, password,
+						       scheme);
+			if (password == NULL && result == PASSDB_RESULT_OK)
+				result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE;
 		}
 	}
 
-	request->private_callback.lookup_credentials(result, credentials,
-						     request);
+	if (!auth_request_handle_passdb_callback(&result, request)) {
+		/* try next passdb */
+		request->passdb = request->passdb->next;
+		auth_request_lookup_credentials(request, request->credentials,
+                	request->private_callback.lookup_credentials);
+	} else {
+		request->private_callback.
+			lookup_credentials(result, password, request);
+	}
 }
 
 void auth_request_lookup_credentials(struct auth_request *request,
@@ -355,18 +392,17 @@
 				     lookup_credentials_callback_t *callback)
 {
 	struct passdb_module *passdb = request->passdb->passdb;
-	const char *cache_key, *result, *scheme;
+	const char *cache_key, *password, *scheme;
+	enum passdb_result result;
 
 	i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
 
 	cache_key = passdb_cache == NULL ? NULL : passdb->cache_key;
 	if (cache_key != NULL) {
 		if (passdb_cache_lookup_credentials(request, cache_key,
-						    &result, &scheme, FALSE)) {
-			passdb_handle_credentials(result != NULL ?
-						  PASSDB_RESULT_OK :
-						  PASSDB_RESULT_USER_UNKNOWN,
-						  credentials, result, scheme,
+						    &password, &scheme,
+						    &result, FALSE)) {
+			passdb_handle_credentials(result, password, scheme,
 						  callback, request);
 			return;
 		}
@@ -378,9 +414,13 @@
 
 	if (passdb->blocking)
 		passdb_blocking_lookup_credentials(request);
-	else {
-		passdb->lookup_credentials(request, credentials,
+	else if (passdb->lookup_credentials != NULL) {
+		passdb->lookup_credentials(request,
 			auth_request_lookup_credentials_callback);
+	} else {
+		/* this passdb doesn't support credentials */
+		auth_request_lookup_credentials_callback(
+			PASSDB_RESULT_SCHEME_NOT_AVAILABLE, NULL, request);
 	}
 }
 

Index: auth-worker-client.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/auth-worker-client.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- auth-worker-client.c	7 Aug 2005 11:41:19 -0000	1.14
+++ auth-worker-client.c	16 Oct 2005 12:03:37 -0000	1.15
@@ -221,8 +221,7 @@
 	}
 
 	auth_request->passdb->passdb->
-		lookup_credentials(auth_request, credentials,
-				   lookup_credentials_callback);
+		lookup_credentials(auth_request, lookup_credentials_callback);
 }
 
 static void

Index: passdb-blocking.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb-blocking.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- passdb-blocking.c	1 Oct 2005 10:52:14 -0000	1.7
+++ passdb-blocking.c	16 Oct 2005 12:03:37 -0000	1.8
@@ -135,8 +135,7 @@
 			result = PASSDB_RESULT_INTERNAL_FAILURE;
 	}
 
-	passdb_handle_credentials(result, request->credentials,
-				  password, scheme,
+	passdb_handle_credentials(result, password, scheme,
 				  auth_request_lookup_credentials_callback,
 				  request);
 }

Index: passdb-cache.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb-cache.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- passdb-cache.c	7 Oct 2005 10:43:28 -0000	1.12
+++ passdb-cache.c	16 Oct 2005 12:03:37 -0000	1.13
@@ -82,8 +82,10 @@
 }
 
 int passdb_cache_lookup_credentials(struct auth_request *request,
-				    const char *key, const char **result_r,
-				    const char **scheme_r, int use_expired)
+				    const char *key, const char **password_r,
+				    const char **scheme_r,
+				    enum passdb_result *result_r,
+				    int use_expired)
 {
 	const char *value, *const *list;
 	int expired;
@@ -97,7 +99,8 @@
 
 	if (*value == '\0') {
 		/* negative cache entry */
-		*result_r = NULL;
+		*result_r = PASSDB_RESULT_USER_UNKNOWN;
+		*password_r = NULL;
 		*scheme_r = NULL;
 		return TRUE;
 	}
@@ -105,8 +108,9 @@
 	list = t_strsplit(value, "\t");
         list_save(request, list + 1);
 
-	*result_r = list[0];
-	*scheme_r = password_get_scheme(result_r);
+	*result_r = PASSDB_RESULT_OK;
+	*password_r = list[0];
+	*scheme_r = password_get_scheme(password_r);
 	i_assert(*scheme_r != NULL);
 	return TRUE;
 }

Index: passdb-cache.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb-cache.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- passdb-cache.h	5 Mar 2005 11:48:13 -0000	1.4
+++ passdb-cache.h	16 Oct 2005 12:03:37 -0000	1.5
@@ -10,8 +10,10 @@
 			      const char *password,
 			      enum passdb_result *result_r, int use_expired);
 int passdb_cache_lookup_credentials(struct auth_request *request,
-				    const char *key, const char **result_r,
-				    const char **scheme_r, int use_expired);
+				    const char *key, const char **password_r,
+				    const char **scheme_r,
+				    enum passdb_result *result_r,
+				    int use_expired);
 
 void passdb_cache_init(void);
 void passdb_cache_deinit(void);

Index: passdb-ldap.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb-ldap.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- passdb-ldap.c	12 Jul 2005 12:58:47 -0000	1.32
+++ passdb-ldap.c	16 Oct 2005 12:03:37 -0000	1.33
@@ -24,7 +24,6 @@
 struct passdb_ldap_request {
 	struct ldap_request request;
 
-	enum passdb_credentials credentials;
 	union {
 		verify_plain_callback_t *verify_plain;
                 lookup_credentials_callback_t *lookup_credentials;
@@ -139,9 +138,8 @@
 	/* auth_request_set_field() sets scheme */
 	i_assert(password == NULL || scheme != NULL);
 
-	if (ldap_request->credentials != -1) {
-		passdb_handle_credentials(passdb_result,
-			ldap_request->credentials, password, scheme,
+	if (auth_request->credentials != -1) {
+		passdb_handle_credentials(passdb_result, password, scheme,
 			ldap_request->callback.lookup_credentials,
 			auth_request);
 		return;
@@ -210,20 +208,17 @@
 	struct passdb_ldap_request *ldap_request;
 
 	ldap_request = p_new(request->pool, struct passdb_ldap_request, 1);
-	ldap_request->credentials = -1;
 	ldap_request->callback.verify_plain = callback;
 
         ldap_lookup_pass(request, &ldap_request->request);
 }
 
 static void ldap_lookup_credentials(struct auth_request *request,
-				    enum passdb_credentials credentials,
 				    lookup_credentials_callback_t *callback)
 {
 	struct passdb_ldap_request *ldap_request;
 
 	ldap_request = p_new(request->pool, struct passdb_ldap_request, 1);
-	ldap_request->credentials = credentials;
 	ldap_request->callback.lookup_credentials = callback;
 
         ldap_lookup_pass(request, &ldap_request->request);

Index: passdb-passwd-file.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb-passwd-file.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- passdb-passwd-file.c	22 Jul 2005 12:42:57 -0000	1.19
+++ passdb-passwd-file.c	16 Oct 2005 12:03:37 -0000	1.20
@@ -46,7 +46,6 @@
 
 static void
 passwd_file_lookup_credentials(struct auth_request *request,
-			       enum passdb_credentials credentials,
 			       lookup_credentials_callback_t *callback)
 {
 	struct passwd_user *pu;
@@ -61,8 +60,8 @@
 	crypted_pass = pu->password;
 	scheme = password_get_scheme(&crypted_pass);
 
-	passdb_handle_credentials(PASSDB_RESULT_OK, credentials, crypted_pass,
-				  scheme, callback, request);
+	passdb_handle_credentials(PASSDB_RESULT_OK, crypted_pass, scheme,
+				  callback, request);
 }
 
 static void passwd_file_init(const char *args)

Index: passdb-sql.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb-sql.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- passdb-sql.c	12 Jul 2005 12:58:47 -0000	1.20
+++ passdb-sql.c	16 Oct 2005 12:03:37 -0000	1.21
@@ -19,7 +19,6 @@
 
 struct passdb_sql_request {
 	struct auth_request *auth_request;
-	enum passdb_credentials credentials;
 	union {
 		verify_plain_callback_t *verify_plain;
                 lookup_credentials_callback_t *lookup_credentials;
@@ -92,9 +91,8 @@
 	/* auth_request_set_field() sets scheme */
 	i_assert(password == NULL || scheme != NULL);
 
-	if (sql_request->credentials != -1) {
-		passdb_handle_credentials(passdb_result,
-			sql_request->credentials, password, scheme,
+	if (auth_request->credentials != -1) {
+		passdb_handle_credentials(passdb_result, password, scheme,
 			sql_request->callback.lookup_credentials,
 			auth_request);
 		return;
@@ -144,21 +142,18 @@
 
 	sql_request = p_new(request->pool, struct passdb_sql_request, 1);
 	sql_request->auth_request = request;
-	sql_request->credentials = -1;
 	sql_request->callback.verify_plain = callback;
 
 	sql_lookup_pass(sql_request);
 }
 
 static void sql_lookup_credentials(struct auth_request *request,
-				   enum passdb_credentials credentials,
 				   lookup_credentials_callback_t *callback)
 {
 	struct passdb_sql_request *sql_request;
 
 	sql_request = p_new(request->pool, struct passdb_sql_request, 1);
 	sql_request->auth_request = request;
-	sql_request->credentials = credentials;
 	sql_request->callback.lookup_credentials = callback;
 
         sql_lookup_pass(sql_request);

Index: passdb.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -d -r1.36 -r1.37
--- passdb.c	24 Sep 2005 12:55:23 -0000	1.36
+++ passdb.c	16 Oct 2005 12:03:37 -0000	1.37
@@ -74,37 +74,25 @@
 	return "??";
 }
 
-void passdb_handle_credentials(enum passdb_result result,
-			       enum passdb_credentials credentials,
-			       const char *password, const char *scheme,
-			       lookup_credentials_callback_t *callback,
-                               struct auth_request *auth_request)
+const char *
+passdb_get_credentials(struct auth_request *auth_request,
+		       const char *password, const char *scheme)
 {
 	const char *wanted_scheme;
 
-	if (result != PASSDB_RESULT_OK) {
-		callback(result, NULL, auth_request);
-		return;
-	}
-	i_assert(password != NULL);
-
-	if (credentials == PASSDB_CREDENTIALS_CRYPT) {
+	if (auth_request->credentials == PASSDB_CREDENTIALS_CRYPT) {
 		/* anything goes */
-		password = t_strdup_printf("{%s}%s", scheme, password);
-		callback(result, password, auth_request);
-		return;
+		return t_strdup_printf("{%s}%s", scheme, password);
 	}
 
-	wanted_scheme = passdb_credentials_to_str(credentials);
+	wanted_scheme = passdb_credentials_to_str(auth_request->credentials);
 	if (strcasecmp(scheme, wanted_scheme) != 0) {
 		if (strcasecmp(scheme, "PLAIN") != 0 &&
 		    strcasecmp(scheme, "CLEARTEXT") != 0) {
 			auth_request_log_info(auth_request, "password",
 				"Requested %s scheme, but we have only %s",
 				wanted_scheme, scheme);
-			callback(PASSDB_RESULT_SCHEME_NOT_AVAILABLE,
-				 NULL, auth_request);
-			return;
+			return NULL;
 		}
 
 		/* we can generate anything out of plaintext passwords */
@@ -113,7 +101,24 @@
 		i_assert(password != NULL);
 	}
 
-	callback(PASSDB_RESULT_OK, password, auth_request);
+	return password;
+}
+
+void 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;
+	}
+	i_assert(password != NULL);
+
+	password = passdb_get_credentials(auth_request, password, scheme);
+	if (password == NULL)
+		result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE;
+	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.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- passdb.h	24 Sep 2005 12:55:23 -0000	1.27
+++ passdb.h	16 Oct 2005 12:03:37 -0000	1.28
@@ -31,7 +31,7 @@
 typedef void verify_plain_callback_t(enum passdb_result result,
 				     struct auth_request *request);
 typedef void lookup_credentials_callback_t(enum passdb_result result,
-					   const char *credentials,
+					   const char *password,
 					   struct auth_request *request);
 
 struct passdb_module {
@@ -54,15 +54,17 @@
 	void (*verify_plain)(struct auth_request *request, const char *password,
 			     verify_plain_callback_t *callback);
 
-	/* Return authentication credentials. Type is authentication mechanism
-	   specific value that is requested. */
+	/* Return authentication credentials, set in
+	   auth_request->credentials. */
 	void (*lookup_credentials)(struct auth_request *request, 
-				   enum passdb_credentials credentials,
 				   lookup_credentials_callback_t *callback);
 };
 
+const char *
+passdb_get_credentials(struct auth_request *auth_request,
+		       const char *password, const char *scheme);
+
 void passdb_handle_credentials(enum passdb_result result,
-			       enum passdb_credentials credentials,
 			       const char *password, const char *scheme,
 			       lookup_credentials_callback_t *callback,
                                struct auth_request *auth_request);



More information about the dovecot-cvs mailing list