]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
*-login: Store user_* passdb fields to client->alt_usernames.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 5 Oct 2016 20:22:56 +0000 (23:22 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 13 Oct 2016 08:26:52 +0000 (10:26 +0200)
src/login-common/client-common-auth.c
src/login-common/client-common.h
src/login-common/login-common.h
src/login-common/main.c

index 3dee6994a3f63c2c15deb16cc9d7639f4adbcf10..0a4d30b530e0cc84ef66a1e86ff121f11ded24f0 100644 (file)
@@ -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 @@ void client_set_auth_waiting(struct client *client)
                            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 @@ static void client_auth_parse_args(struct client *client,
                } 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 @@ sasl_callback(struct client *client, enum sasl_server_reply sasl_reply,
                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 @@ sasl_callback(struct client *client, enum sasl_server_reply sasl_reply,
                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))
index ba511a44fe9c8383b4f41f15331b7309c7085b8b..2978adcbae4578a7b3dde490deaf0fe4bb4f616a 100644 (file)
@@ -154,6 +154,11 @@ struct client {
        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;
index 7dca9c58321d8d32feb650f234e60bbeb3b8363c..b9f877a6eb877e635f45eb9ecc9527b4b639bc97 100644 (file)
@@ -50,6 +50,9 @@ extern bool closing_down, login_debug;
 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;
index ddeb9dd72186fae48ba87d1a647550ce963a1f43..8c6734b451da54fbec23c20d5e0d7fb77e1424aa 100644 (file)
@@ -41,6 +41,7 @@ struct anvil_client *anvil;
 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 @@ static void main_init(const char *login_socket)
        /* 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 @@ static void main_deinit(void)
        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)