changeset 20840:1b4a57403aef

*-login: Store user_* passdb fields to client->alt_usernames.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Wed, 05 Oct 2016 23:22:56 +0300
parents 78d312e6abdc
children c3cc30b7eda6
files src/login-common/client-common-auth.c src/login-common/client-common.h src/login-common/login-common.h src/login-common/main.c
diffstat 4 files changed, 66 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/login-common/client-common-auth.c	Mon Oct 10 17:37:27 2016 +0300
+++ b/src/login-common/client-common-auth.c	Wed Oct 05 23:22:56 2016 +0300
@@ -2,6 +2,7 @@
 
 #include "hostpid.h"
 #include "login-common.h"
+#include "array.h"
 #include "iostream.h"
 #include "istream.h"
 #include "ostream.h"
@@ -59,12 +60,45 @@
 			    client_auth_waiting_timeout, client);
 }
 
-static void client_auth_parse_args(struct client *client,
+static void alt_username_set(ARRAY_TYPE(const_string) *alt_usernames, pool_t pool,
+			     const char *key, const char *value)
+{
+	char *const *fields;
+	unsigned int i, count;
+
+	fields = array_get(&global_alt_usernames, &count);
+	for (i = 0; i < count; i++) {
+		if (strcmp(fields[i], key) == 0)
+			break;
+	}
+	if (i == count) {
+		char *new_key = i_strdup(key);
+		array_append(&global_alt_usernames, &new_key, 1);
+	}
+
+	value = p_strdup(pool, value);
+	if (i < array_count(alt_usernames)) {
+		array_idx_set(alt_usernames, i, &value);
+		return;
+	}
+
+	/* array is NULL-terminated, so if there are unused fields in
+	   the middle set them as "" */
+	while (array_count(alt_usernames) < i) {
+		const char *empty_str = "";
+		array_append(alt_usernames, &empty_str, 1);
+	}
+	array_append(alt_usernames, &value, 1);
+}
+
+static void client_auth_parse_args(struct client *client, bool success,
 				   const char *const *args,
 				   struct client_auth_reply *reply_r)
 {
 	const char *key, *value, *p;
+	ARRAY_TYPE(const_string) alt_usernames;
 
+	t_array_init(&alt_usernames, 4);
 	memset(reply_r, 0, sizeof(*reply_r));
 
 	for (; *args != NULL; args++) {
@@ -136,9 +170,23 @@
 		} else if (strcmp(key, "user") == 0 ||
 			   strcmp(key, "postlogin_socket") == 0) {
 			/* already handled in sasl-server.c */
+		} else if (strncmp(key, "user_", 5) == 0) {
+			if (success) {
+				alt_username_set(&alt_usernames, client->pool,
+						 key, value);
+			}
 		} else if (client->set->auth_debug)
 			i_debug("Ignoring unknown passdb extra field: %s", key);
 	}
+	if (array_count(&alt_usernames) > 0) {
+		const char **alt;
+
+		alt = p_new(client->pool, const char *,
+			    array_count(&alt_usernames) + 1);
+		memcpy(alt, array_idx(&alt_usernames, 0),
+		       sizeof(*alt) * array_count(&alt_usernames));
+		client->alt_usernames = alt;
+	}
 	if (reply_r->port == 0)
 		reply_r->port = login_binary->default_port;
 
@@ -564,7 +612,7 @@
 		if (client->to_auth_waiting != NULL)
 			timeout_remove(&client->to_auth_waiting);
 		if (args != NULL) {
-			client_auth_parse_args(client, args, &reply);
+			client_auth_parse_args(client, TRUE, args, &reply);
 			reply.all_fields = args;
 			if (client_auth_handle_reply(client, &reply, TRUE))
 				break;
@@ -578,7 +626,7 @@
 		if (client->to_auth_waiting != NULL)
 			timeout_remove(&client->to_auth_waiting);
 		if (args != NULL) {
-			client_auth_parse_args(client, args, &reply);
+			client_auth_parse_args(client, FALSE, args, &reply);
 			reply.nologin = TRUE;
 			reply.all_fields = args;
 			if (client_auth_handle_reply(client, &reply, FALSE))
--- a/src/login-common/client-common.h	Mon Oct 10 17:37:27 2016 +0300
+++ b/src/login-common/client-common.h	Wed Oct 05 23:22:56 2016 +0300
@@ -154,6 +154,11 @@
 	ARRAY(union login_client_module_context *) module_contexts;
 
 	char *virtual_user, *virtual_user_orig, *virtual_auth_user;
+	/* passdb user_* fields are set here after a successful auth.
+	   This is a NULL-terminated array where fields are in the same order
+	   as in global_alt_usernames. If some field doesn't exist, it's "".
+	   Can also be NULL if there are no user_* fields. */
+	const char **alt_usernames;
 	unsigned int destroyed:1;
 	unsigned int input_blocked:1;
 	unsigned int login_success:1;
--- a/src/login-common/login-common.h	Mon Oct 10 17:37:27 2016 +0300
+++ b/src/login-common/login-common.h	Wed Oct 05 23:22:56 2016 +0300
@@ -50,6 +50,9 @@
 extern struct anvil_client *anvil;
 extern const char *login_rawlog_dir;
 extern unsigned int initial_service_count;
+/* NULL-terminated array of all alt_usernames seen so far. Existing fields are
+   never removed. */
+extern ARRAY_TYPE(string) global_alt_usernames;
 
 extern const struct login_settings *global_login_settings;
 extern const struct master_service_ssl_settings *global_ssl_settings;
--- a/src/login-common/main.c	Mon Oct 10 17:37:27 2016 +0300
+++ b/src/login-common/main.c	Wed Oct 05 23:22:56 2016 +0300
@@ -41,6 +41,7 @@
 const char *login_rawlog_dir = NULL;
 unsigned int initial_service_count;
 struct login_module_register login_module_register;
+ARRAY_TYPE(string) global_alt_usernames;
 
 const struct login_settings *global_login_settings;
 const struct master_service_ssl_settings *global_ssl_settings;
@@ -397,6 +398,7 @@
 	/* make sure we can't fork() */
 	restrict_process_count(1);
 
+	i_array_init(&global_alt_usernames, 4);
 	master_service_set_avail_overflow_callback(master_service,
 						   client_destroy_oldest);
 	master_service_set_die_callback(master_service, login_die);
@@ -419,6 +421,11 @@
 	auth_client_deinit(&auth_client);
 	master_auth_deinit(&master_auth);
 
+	char **strp;
+	array_foreach_modifiable(&global_alt_usernames, strp)
+		i_free(*strp);
+	array_free(&global_alt_usernames);
+
 	if (anvil != NULL)
 		anvil_client_deinit(&anvil);
 	if (auth_client_to != NULL)