changeset 4880:4ec6a4def05b HEAD

We treated internal userdb lookup errors as "user unknown" errors. In such situations this caused deliver to think the user didn't exist and the mail get bounced.
author Timo Sirainen <tss@iki.fi>
date Sat, 09 Dec 2006 17:11:48 +0200
parents b0ada6e57b07
children 53ac6f2c1242
files src/auth/auth-master-connection.c src/auth/auth-request-handler.c src/auth/auth-request.c src/auth/auth-request.h src/auth/auth-worker-client.c src/auth/userdb-blocking.c src/auth/userdb-ldap.c src/auth/userdb-passwd-file.c src/auth/userdb-passwd.c src/auth/userdb-prefetch.c src/auth/userdb-sql.c src/auth/userdb-static.c src/auth/userdb-vpopmail.c src/auth/userdb.h
diffstat 14 files changed, 105 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/auth-master-connection.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/auth-master-connection.c	Sat Dec 09 17:11:48 2006 +0200
@@ -78,18 +78,25 @@
 }
 
 static void
-user_callback(struct auth_stream_reply *reply,
+user_callback(enum userdb_result result,
+	      struct auth_stream_reply *reply,
 	      struct auth_request *auth_request)
 {
 	struct auth_master_connection *conn = auth_request->context;
 	string_t *str;
 
 	str = t_str_new(128);
-	if (reply == NULL)
+	switch (result) {
+	case USERDB_RESULT_INTERNAL_FAILURE:
+		str_printfa(str, "FAIL\t%u", auth_request->id);
+		break;
+	case USERDB_RESULT_USER_UNKNOWN:
 		str_printfa(str, "NOTFOUND\t%u", auth_request->id);
-	else {
+		break;
+	case USERDB_RESULT_OK:
 		str_printfa(str, "USER\t%u\t", auth_request->id);
 		str_append(str, auth_stream_reply_export(reply));
+		break;
 	}
 
 	if (conn->listener->auth->verbose_debug)
--- a/src/auth/auth-request-handler.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/auth-request-handler.c	Sat Dec 09 17:11:48 2006 +0200
@@ -396,7 +396,8 @@
 	return TRUE;
 }
 
-static void userdb_callback(struct auth_stream_reply *reply,
+static void userdb_callback(enum userdb_result result,
+			    struct auth_stream_reply *reply,
 			    struct auth_request *request)
 {
         struct auth_request_handler *handler = request->context;
@@ -407,15 +408,21 @@
 	request->state = AUTH_REQUEST_STATE_FINISHED;
 
 	str = t_str_new(256);
-	if (reply == NULL)
+	switch (result) {
+	case USERDB_RESULT_INTERNAL_FAILURE:
+		str_printfa(str, "FAIL\t%u", request->id);
+		break;
+	case USERDB_RESULT_USER_UNKNOWN:
 		str_printfa(str, "NOTFOUND\t%u", request->id);
-	else {
+		break;
+	case USERDB_RESULT_OK:
 		if (request->master_user != NULL) {
 			auth_stream_reply_add(reply, "master_user",
 					      request->master_user);
 		}
 		str_printfa(str, "USER\t%u\t", request->id);
 		str_append(str, auth_stream_reply_export(reply));
+		break;
 	}
 	handler->master_callback(str_c(str), request->master);
 
--- a/src/auth/auth-request.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/auth-request.c	Sat Dec 09 17:11:48 2006 +0200
@@ -564,24 +564,34 @@
 	}
 }
 
-void auth_request_userdb_callback(struct auth_stream_reply *reply,
+void auth_request_userdb_callback(enum userdb_result result,
+				  struct auth_stream_reply *reply,
 				  struct auth_request *request)
 {
-	if (reply == NULL && request->userdb->next != NULL) {
+	if (result != USERDB_RESULT_OK && request->userdb->next != NULL) {
 		/* try next userdb. */
+		if (result == USERDB_RESULT_INTERNAL_FAILURE)
+			request->userdb_internal_failure = TRUE;
+
 		request->userdb = request->userdb->next;
 		auth_request_lookup_user(request,
 					 request->private_callback.userdb);
 		return;
 	}
 
-	if (reply == NULL && request->client_pid != 0) {
-		/* this was actual login attempt */
+	if (request->userdb_internal_failure && result != USERDB_RESULT_OK) {
+		/* one of the userdb lookups failed. the user might have been
+		   in there, so this is an internal failure */
+		result = USERDB_RESULT_INTERNAL_FAILURE;
+	} else if (result == USERDB_RESULT_USER_UNKNOWN &&
+		   request->client_pid != 0) {
+		/* this was an actual login attempt, the user should
+		   have been found. */
 		auth_request_log_error(request, "userdb",
 				       "user not found from userdb");
 	}
 
-        request->private_callback.userdb(reply, request);
+        request->private_callback.userdb(result, reply, request);
 }
 
 void auth_request_lookup_user(struct auth_request *request,
--- a/src/auth/auth-request.h	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/auth-request.h	Sat Dec 09 17:11:48 2006 +0200
@@ -72,6 +72,7 @@
 	unsigned int passdb_failure:1;
 	unsigned int internal_failure:1;
 	unsigned int passdb_internal_failure:1;
+	unsigned int userdb_internal_failure:1;
 	unsigned int delayed_failure:1;
 	unsigned int accept_input:1;
 	unsigned int no_failure_delay:1;
@@ -154,7 +155,8 @@
 				  enum passdb_credentials credentials,
 				  const char *data,
 				  set_credentials_callback_t *callback);
-void auth_request_userdb_callback(struct auth_stream_reply *reply,
+void auth_request_userdb_callback(enum userdb_result result,
+				  struct auth_stream_reply *reply,
 				  struct auth_request *request);
 
 #endif
--- a/src/auth/auth-worker-client.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/auth-worker-client.c	Sat Dec 09 17:11:48 2006 +0200
@@ -298,16 +298,27 @@
 }
 
 static void
-lookup_user_callback(struct auth_stream_reply *reply,
+lookup_user_callback(enum userdb_result result,
+		     struct auth_stream_reply *reply,
 		     struct auth_request *auth_request)
 {
 	struct auth_worker_client *client = auth_request->context;
 	string_t *str;
 
-	str = t_str_new(64);
+	str = t_str_new(128);
 	str_printfa(str, "%u\t", auth_request->id);
-	if (reply != NULL)
+	switch (result) {
+	case USERDB_RESULT_INTERNAL_FAILURE:
+		str_append(str, "FAIL\t");
+		break;
+	case USERDB_RESULT_USER_UNKNOWN:
+		str_append(str, "NOTFOUND\t");
+		break;
+	case USERDB_RESULT_OK:
+		str_append(str, "OK\t");
 		str_append(str, auth_stream_reply_export(reply));
+		break;
+	}
 	str_append_c(str, '\n');
 
 	o_stream_send(client->output, str_data(str), str_len(str));
--- a/src/auth/userdb-blocking.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/userdb-blocking.c	Sat Dec 09 17:11:48 2006 +0200
@@ -10,16 +10,23 @@
 
 static void user_callback(struct auth_request *request, const char *reply)
 {
-	struct auth_stream_reply *stream_reply;
+	struct auth_stream_reply *stream_reply = NULL;
+	enum userdb_result result;
 
-	if (*reply == '\0')
-		stream_reply = NULL;
-	else {
+	if (strncmp(reply, "FAIL\t", 5) == 0)
+		result = USERDB_RESULT_INTERNAL_FAILURE;
+	else if (strncmp(reply, "NOTFOUND\t", 9) == 0)
+		result = USERDB_RESULT_USER_UNKNOWN;
+	else if (strncmp(reply, "OK\t", 3) == 0) {
+		result = USERDB_RESULT_OK;
 		stream_reply = auth_stream_reply_init(request);
 		auth_stream_reply_import(stream_reply, reply);
+	} else {
+		result = USERDB_RESULT_INTERNAL_FAILURE;
+		i_error("BUG: auth-worker sent invalid user reply");
 	}
 
-        auth_request_userdb_callback(stream_reply, request);
+        auth_request_userdb_callback(result, stream_reply, request);
 }
 
 void userdb_blocking_lookup(struct auth_request *request)
--- a/src/auth/userdb-ldap.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/userdb-ldap.c	Sat Dec 09 17:11:48 2006 +0200
@@ -138,32 +138,36 @@
 	struct auth_request *auth_request = urequest->auth_request;
 	LDAPMessage *entry;
 	struct auth_stream_reply *reply = NULL;
+	enum userdb_result result = USERDB_RESULT_INTERNAL_FAILURE;
 	int ret;
 
 	ret = ldap_result2error(conn->ld, res, 0);
 	if (ret != LDAP_SUCCESS) {
 		auth_request_log_error(auth_request, "ldap",
 			"ldap_search() failed: %s", ldap_err2string(ret));
-		urequest->userdb_callback(NULL, auth_request);
+		urequest->userdb_callback(result, NULL, auth_request);
 		return;
 	}
 
 	entry = res == NULL ? NULL : ldap_first_entry(conn->ld, res);
 	if (entry == NULL) {
 		if (res != NULL) {
+			result = USERDB_RESULT_USER_UNKNOWN;
 			auth_request_log_error(auth_request, "ldap",
 					       "Authenticated user not found");
 		}
 	} else {
 		reply = ldap_query_get_result(conn, entry, auth_request);
-		if (ldap_next_entry(conn->ld, entry) != NULL) {
+		if (ldap_next_entry(conn->ld, entry) == NULL)
+			result = USERDB_RESULT_OK;
+		else {
 			auth_request_log_error(auth_request, "ldap",
 				"Multiple replies found for user");
 			reply = NULL;
 		}
 	}
 
-	urequest->userdb_callback(reply, auth_request);
+	urequest->userdb_callback(result, reply, auth_request);
 	auth_request_unref(&auth_request);
 }
 
--- a/src/auth/userdb-passwd-file.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/userdb-passwd-file.c	Sat Dec 09 17:11:48 2006 +0200
@@ -31,7 +31,7 @@
 
 	pu = db_passwd_file_lookup(module->pwf, auth_request);
 	if (pu == NULL) {
-		callback(NULL, auth_request);
+		callback(USERDB_RESULT_USER_UNKNOWN, NULL, auth_request);
 		return;
 	}
 
@@ -65,7 +65,7 @@
 		t_pop();
 	}
 
-	callback(reply, auth_request);
+	callback(USERDB_RESULT_OK, reply, auth_request);
 }
 
 static struct userdb_module *
--- a/src/auth/userdb-passwd.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/userdb-passwd.c	Sat Dec 09 17:11:48 2006 +0200
@@ -17,7 +17,7 @@
 	pw = getpwnam(auth_request->user);
 	if (pw == NULL) {
 		auth_request_log_info(auth_request, "passwd", "unknown user");
-		callback(NULL, auth_request);
+		callback(USERDB_RESULT_USER_UNKNOWN, NULL, auth_request);
 		return;
 	}
 
@@ -36,7 +36,7 @@
 	auth_stream_reply_add(reply, "gid", dec2str(pw->pw_gid));
 	auth_stream_reply_add(reply, "home", pw->pw_dir);
 
-	callback(reply, auth_request);
+	callback(USERDB_RESULT_OK, reply, auth_request);
 }
 
 struct userdb_module_interface userdb_passwd = {
--- a/src/auth/userdb-prefetch.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/userdb-prefetch.c	Sat Dec 09 17:11:48 2006 +0200
@@ -29,7 +29,7 @@
 			auth_request_log_info(auth_request, "prefetch",
 				"passdb didn't return userdb entries");
 		}
-		callback(NULL, auth_request);
+		callback(USERDB_RESULT_USER_UNKNOWN, NULL, auth_request);
 		return;
 	}
 
@@ -84,7 +84,7 @@
 	}
 
 	if (uid == (uid_t)-1 || gid == (gid_t)-1)
-		callback(NULL, auth_request);
+		callback(USERDB_RESULT_USER_UNKNOWN, NULL, auth_request);
 	else {
 		struct auth_stream_reply *reply;
 
@@ -92,7 +92,7 @@
 		   exported they are already in escaped form in the string. */
 		reply = auth_stream_reply_init(auth_request);
 		auth_stream_reply_import(reply, str_c(str));
-		callback(reply, auth_request);
+		callback(USERDB_RESULT_OK, reply, auth_request);
 	}
 	t_pop();
 }
--- a/src/auth/userdb-sql.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/userdb-sql.c	Sat Dec 09 17:11:48 2006 +0200
@@ -78,24 +78,29 @@
 	return reply;
 }
 
-static void sql_query_callback(struct sql_result *result, void *context)
+static void sql_query_callback(struct sql_result *sql_result, void *context)
 {
 	struct userdb_sql_request *sql_request = context;
 	struct auth_request *auth_request = sql_request->auth_request;
 	struct auth_stream_reply *reply = NULL;
+	enum userdb_result result = USERDB_RESULT_INTERNAL_FAILURE;
 	int ret;
 
-	ret = sql_result_next_row(result);
+	ret = sql_result_next_row(sql_result);
 	if (ret < 0) {
 		auth_request_log_error(auth_request, "sql",
-			"User query failed: %s", sql_result_get_error(result));
+				       "User query failed: %s",
+				       sql_result_get_error(sql_result));
 	} else if (ret == 0) {
+		result = USERDB_RESULT_USER_UNKNOWN;
 		auth_request_log_info(auth_request, "sql", "User not found");
 	} else {
-                reply = sql_query_get_result(result, auth_request);
+		reply = sql_query_get_result(sql_result, auth_request);
+		if (reply != NULL)
+			result = USERDB_RESULT_OK;
 	}
 
-	sql_request->callback(reply, auth_request);
+	sql_request->callback(result, reply, auth_request);
 	auth_request_unref(&auth_request);
 	i_free(sql_request);
 }
--- a/src/auth/userdb-static.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/userdb-static.c	Sat Dec 09 17:11:48 2006 +0200
@@ -49,7 +49,7 @@
 		auth_stream_reply_add(reply, args[i], value);
 	}
 
-	callback(reply, auth_request);
+	callback(USERDB_RESULT_OK, reply, auth_request);
 	t_pop();
 }
 
--- a/src/auth/userdb-vpopmail.c	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/userdb-vpopmail.c	Sat Dec 09 17:11:48 2006 +0200
@@ -50,7 +50,7 @@
 
 	vpw = vpopmail_lookup_vqp(auth_request, vpop_user, vpop_domain);
 	if (vpw == NULL) {
-		callback(NULL, auth_request);
+		callback(USERDB_RESULT_USER_UNKNOWN, NULL, auth_request);
 		return;
 	}
 
@@ -59,7 +59,7 @@
 	if (vget_assign(vpop_domain, NULL, 0, &uid, &gid) == NULL) {
 		auth_request_log_info(auth_request, "vpopmail",
 				      "vget_assign(%s) failed", vpop_domain);
-		callback(NULL, auth_request);
+		callback(USERDB_RESULT_INTERNAL_FAILURE, NULL, auth_request);
 		return;
 	}
 
@@ -72,14 +72,16 @@
 			auth_request_log_error(auth_request, "vpopmail",
 					       "make_user_dir(%s, %s) failed",
 					       vpop_user, vpop_domain);
-			callback(NULL, auth_request);
+			callback(USERDB_RESULT_INTERNAL_FAILURE,
+				 NULL, auth_request);
 			return;
 		}
 
 		/* get the user again so pw_dir is visible */
 		vpw = vauth_getpw(vpop_user, vpop_domain);
 		if (vpw == NULL) {
-			callback(NULL, auth_request);
+			callback(USERDB_RESULT_INTERNAL_FAILURE,
+				 NULL, auth_request);
 			return;
 		}
 	}
@@ -90,7 +92,7 @@
 	auth_stream_reply_add(reply, "gid", dec2str(gid));
 	auth_stream_reply_add(reply, "home", vpw->pw_dir);
 
-	callback(reply, auth_request);
+	callback(USERDB_RESULT_OK, reply, auth_request);
 }
 
 struct userdb_module_interface userdb_vpopmail = {
--- a/src/auth/userdb.h	Thu Dec 07 01:43:15 2006 +0200
+++ b/src/auth/userdb.h	Sat Dec 09 17:11:48 2006 +0200
@@ -5,7 +5,15 @@
 
 struct auth_request;
 
-typedef void userdb_callback_t(struct auth_stream_reply *reply,
+enum userdb_result {
+	USERDB_RESULT_INTERNAL_FAILURE = -1,
+	USERDB_RESULT_USER_UNKNOWN = -2,
+
+	USERDB_RESULT_OK = 1
+};
+
+typedef void userdb_callback_t(enum userdb_result result,
+			       struct auth_stream_reply *reply,
 			       struct auth_request *request);
 
 struct userdb_module {