]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: Support passing regular %variables to sql/ldap iterate queries.
authorTimo Sirainen <tss@iki.fi>
Wed, 23 Nov 2011 20:07:08 +0000 (22:07 +0200)
committerTimo Sirainen <tss@iki.fi>
Wed, 23 Nov 2011 20:07:08 +0000 (22:07 +0200)
src/auth/auth-master-connection.c
src/auth/auth-settings.c
src/auth/auth-worker-client.c
src/auth/userdb-blocking.c
src/auth/userdb-blocking.h
src/auth/userdb-ldap.c
src/auth/userdb-passwd-file.c
src/auth/userdb-passwd.c
src/auth/userdb-sql.c
src/auth/userdb.h

index f639b9edf15de4ec86058aa03a74bc67f54298d4..e1cb70f1ea77de90140027b2e6d0cd10de87f077 100644 (file)
 
 struct master_userdb_request {
        struct auth_master_connection *conn;
-       unsigned int id;
        struct auth_request *auth_request;
 };
 
 struct master_list_iter_ctx {
        struct auth_master_connection *conn;
-       struct auth_userdb *userdb;
        struct userdb_iterate_context *iter;
-       unsigned int id;
+       struct auth_request *auth_request;
        bool failed;
 };
 
@@ -383,6 +381,8 @@ static void master_input_list_finish(struct master_list_iter_ctx *ctx)
        if (ctx->iter != NULL)
                (void)userdb_blocking_iter_deinit(&ctx->iter);
        o_stream_unset_flush_callback(ctx->conn->output);
+       auth_request_unref(&ctx->auth_request);
+       auth_master_connection_unref(&ctx->conn);
        i_free(ctx);
 }
 
@@ -402,6 +402,7 @@ static int master_output_list(struct master_list_iter_ctx *ctx)
 static void master_input_list_callback(const char *user, void *context)
 {
        struct master_list_iter_ctx *ctx = context;
+       struct auth_userdb *userdb = ctx->auth_request->userdb;
        int ret;
 
        if (user == NULL) {
@@ -409,14 +410,15 @@ static void master_input_list_callback(const char *user, void *context)
                        ctx->failed = TRUE;
 
                do {
-                       ctx->userdb = ctx->userdb->next;
-               } while (ctx->userdb != NULL &&
-                        ctx->userdb->userdb->iface->iterate_init == NULL);
-               if (ctx->userdb == NULL) {
+                       userdb = userdb->next;
+               } while (userdb != NULL &&
+                        userdb->userdb->iface->iterate_init == NULL);
+               if (userdb == NULL) {
                        /* iteration is finished */
                        const char *str;
 
-                       str = t_strdup_printf("DONE\t%u\t%s\n", ctx->id,
+                       str = t_strdup_printf("DONE\t%u\t%s\n",
+                                             ctx->auth_request->id,
                                              ctx->failed ? "fail" : "");
                        (void)o_stream_send_str(ctx->conn->output, str);
                        master_input_list_finish(ctx);
@@ -424,7 +426,8 @@ static void master_input_list_callback(const char *user, void *context)
                }
 
                /* continue iterating next userdb */
-               ctx->iter = userdb_blocking_iter_init(ctx->userdb->userdb,
+               ctx->auth_request->userdb = userdb;
+               ctx->iter = userdb_blocking_iter_init(ctx->auth_request,
                                        master_input_list_callback, ctx);
                userdb_blocking_iter_next(ctx->iter);
                return;
@@ -433,7 +436,7 @@ static void master_input_list_callback(const char *user, void *context)
        T_BEGIN {
                const char *str;
 
-               str = t_strdup_printf("LIST\t%u\t%s\n", ctx->id,
+               str = t_strdup_printf("LIST\t%u\t%s\n", ctx->auth_request->id,
                                      str_tabescape(user));
                ret = o_stream_send_str(ctx->conn->output, str);
        } T_END;
@@ -450,15 +453,18 @@ static bool
 master_input_list(struct auth_master_connection *conn, const char *args)
 {
        struct auth_userdb *userdb = conn->auth->userdbs;
+       struct auth_request *auth_request;
        struct master_list_iter_ctx *ctx;
-       const char *str;
+       const char *str, *name, *arg, *const *list;
        unsigned int id;
 
-       /* <id> */
-       if (str_to_uint(args, &id) < 0) {
+       /* <id> [<parameters>] */
+       list = t_strsplit(args, "\t");
+       if (list[0] == NULL || str_to_uint(list[0], &id) < 0) {
                i_error("BUG: Master sent broken LIST");
-               return FALSE;
+               return -1;
        }
+       list++;
 
        if (conn->userdb_restricted_uid != 0) {
                i_error("Auth client doesn't have permissions to list users: %s",
@@ -477,14 +483,42 @@ master_input_list(struct auth_master_connection *conn, const char *args)
                return TRUE;
        }
 
+       auth_request = auth_request_new_dummy();
+       auth_request->id = id;
+       auth_request->master = conn;
+       auth_master_connection_ref(conn);
+
+       for (; *list != NULL; list++) {
+               arg = strchr(*list, '=');
+               if (arg == NULL) {
+                       name = *list;
+                       arg = "";
+               } else {
+                       name = t_strdup_until(*list, arg);
+                       arg++;
+               }
+
+               if (!auth_request_import_info(auth_request, name, arg) &&
+                   strcmp(name, "user") == 0) {
+                       /* username mask */
+                       auth_request->user = p_strdup(auth_request->pool, arg);
+               }
+       }
+
+       /* rest of the code doesn't like NULL user or service */
+       if (auth_request->user == NULL)
+               auth_request->user = "";
+       if (auth_request->service == NULL)
+               auth_request->service = "";
+
        ctx = i_new(struct master_list_iter_ctx, 1);
        ctx->conn = conn;
-       ctx->userdb = userdb;
-       ctx->id = id;
+       ctx->auth_request = auth_request;
+       ctx->auth_request->userdb = userdb;
 
        io_remove(&conn->io);
        o_stream_set_flush_callback(conn->output, master_output_list, ctx);
-       ctx->iter = userdb_blocking_iter_init(ctx->userdb->userdb,
+       ctx->iter = userdb_blocking_iter_init(auth_request,
                                              master_input_list_callback, ctx);
        return TRUE;
 }
index f71c52b923b0a5fd1ca1f5ccff1bc3a6a1379a69..03f906a60d5a9e9bdcd914432626f51b5e57bc0f 100644 (file)
@@ -349,6 +349,7 @@ auth_settings_read(const char *service, pool_t pool,
        };
        struct master_service_settings_input input;
        struct setting_parser_context *set_parser;
+       struct auth_settings *set;
        const char *error;
 
        memset(&input, 0, sizeof(input));
@@ -359,9 +360,12 @@ auth_settings_read(const char *service, pool_t pool,
                                         output_r, &error) < 0)
                i_fatal("Error reading configuration: %s", error);
 
+       pool_ref(pool);
        set_parser = settings_parser_dup(master_service->set_parser, pool);
        if (!settings_parser_check(set_parser, pool, &error))
                i_unreached();
 
-       return settings_parser_get_list(set_parser)[1];
+       set = settings_parser_get_list(set_parser)[1];
+       settings_parser_deinit(&set_parser);
+       return set;
 }
index 89b7c8524bdcfbe4fabb71dc3edb65f6ce91fb2b..bdca413cc5d5d4e41287fa5b85a4832fecd3b503 100644 (file)
@@ -31,9 +31,8 @@ struct auth_worker_client {
 
 struct auth_worker_list_context {
        struct auth_worker_client *client;
-       struct userdb_module *userdb;
+       struct auth_request *auth_request;
        struct userdb_iterate_context *iter;
-       unsigned int id;
        bool sending, sent, done;
 };
 
@@ -415,14 +414,16 @@ static void list_iter_deinit(struct auth_worker_list_context *ctx)
        i_assert(client->io == NULL);
 
        str = t_str_new(32);
-       if (ctx->userdb->iface->iterate_deinit(ctx->iter) < 0)
-               str_printfa(str, "%u\tFAIL\n", ctx->id);
+       if (ctx->auth_request->userdb->userdb->iface->
+                       iterate_deinit(ctx->iter) < 0)
+               str_printfa(str, "%u\tFAIL\n", ctx->auth_request->id);
        else
-               str_printfa(str, "%u\tOK\n", ctx->id);
+               str_printfa(str, "%u\tOK\n", ctx->auth_request->id);
        auth_worker_send_reply(client, str);
 
        client->io = io_add(client->fd, IO_READ, auth_worker_input, client);
        o_stream_set_flush_callback(client->output, auth_worker_output, client);
+       auth_request_unref(&ctx->auth_request);
        auth_worker_client_unref(&client);
        i_free(ctx);
 }
@@ -442,7 +443,7 @@ static void list_iter_callback(const char *user, void *context)
 
        T_BEGIN {
                str = t_str_new(128);
-               str_printfa(str, "%u\t*\t%s\n", ctx->id, user);
+               str_printfa(str, "%u\t*\t%s\n", ctx->auth_request->id, user);
                o_stream_send(ctx->client->output, str_data(str), str_len(str));
        } T_END;
 
@@ -455,7 +456,8 @@ static void list_iter_callback(const char *user, void *context)
        do {
                ctx->sending = TRUE;
                ctx->sent = FALSE;
-               ctx->userdb->iface->iterate_next(ctx->iter);
+               ctx->auth_request->userdb->userdb->iface->
+                       iterate_next(ctx->iter);
        } while (ctx->sent &&
                 o_stream_get_buffer_used_size(ctx->client->output) == 0);
        ctx->sending = FALSE;
@@ -471,8 +473,10 @@ static int auth_worker_list_output(struct auth_worker_list_context *ctx)
                list_iter_deinit(ctx);
                return 1;
        }
-       if (ret > 0)
-               ctx->userdb->iface->iterate_next(ctx->iter);
+       if (ret > 0) {
+               ctx->auth_request->userdb->userdb->iface->
+                       iterate_next(ctx->iter);
+       }
        return 1;
 }
 
@@ -497,16 +501,22 @@ auth_worker_handle_list(struct auth_worker_client *client,
 
        ctx = i_new(struct auth_worker_list_context, 1);
        ctx->client = client;
-       ctx->id = id;
-       ctx->userdb = userdb->userdb;
+       ctx->auth_request = worker_auth_request_new(client, id, args + 1);
+       ctx->auth_request->userdb = userdb;
+       if (ctx->auth_request->user == NULL ||
+           ctx->auth_request->service == NULL) {
+               i_error("BUG: LIST had missing parameters");
+               auth_request_unref(&ctx->auth_request);
+               i_free(ctx);
+               return FALSE;
+       }
 
        io_remove(&ctx->client->io);
        o_stream_set_flush_callback(ctx->client->output,
                                    auth_worker_list_output, ctx);
-       client->refcount++;
-       ctx->iter = ctx->userdb->iface->
-               iterate_init(userdb->userdb, list_iter_callback, ctx);
-       ctx->userdb->iface->iterate_next(ctx->iter);
+       ctx->iter = ctx->auth_request->userdb->userdb->iface->
+               iterate_init(ctx->auth_request, list_iter_callback, ctx);
+       ctx->auth_request->userdb->userdb->iface->iterate_next(ctx->iter);
        return TRUE;
 }
 
index e0a06364173f0362820a78fb907af127d8e1e7a0..5769237fc2e2ccc1c749ed9b5ac7dea71f32ec85 100644 (file)
@@ -10,7 +10,6 @@
 
 struct blocking_userdb_iterate_context {
        struct userdb_iterate_context ctx;
-       pool_t pool;
        struct auth_worker_connection *conn;
        bool next;
        bool destroyed;
@@ -66,7 +65,6 @@ void userdb_blocking_lookup(struct auth_request *request)
 static bool iter_callback(const char *reply, void *context)
 {
        struct blocking_userdb_iterate_context *ctx = context;
-       pool_t pool = ctx->pool;
 
        if (strncmp(reply, "*\t", 2) == 0) {
                ctx->next = FALSE;
@@ -78,31 +76,30 @@ static bool iter_callback(const char *reply, void *context)
                ctx->ctx.failed = TRUE;
        if (!ctx->destroyed)
                ctx->ctx.callback(NULL, ctx->ctx.context);
-       pool_unref(&pool);
+       auth_request_unref(&ctx->ctx.auth_request);
        return TRUE;
 }
 
 struct userdb_iterate_context *
-userdb_blocking_iter_init(struct userdb_module *userdb,
+userdb_blocking_iter_init(struct auth_request *request,
                          userdb_iter_callback_t *callback, void *context)
 {
        struct blocking_userdb_iterate_context *ctx;
        struct auth_stream_reply *reply;
-       pool_t pool;
 
        reply = auth_stream_reply_init(pool_datastack_create());
        auth_stream_reply_add(reply, "LIST", NULL);
-       auth_stream_reply_add(reply, NULL, dec2str(userdb->id));
+       auth_stream_reply_add(reply, NULL,
+                             dec2str(request->userdb->userdb->id));
+       auth_request_export(request, reply);
 
-       pool = pool_alloconly_create("userdb iter", 512);
-       ctx = p_new(pool, struct blocking_userdb_iterate_context, 1);
-       ctx->ctx.userdb = userdb;
+       ctx = p_new(request->pool, struct blocking_userdb_iterate_context, 1);
+       ctx->ctx.auth_request = request;
        ctx->ctx.callback = callback;
        ctx->ctx.context = context;
-       ctx->pool = pool;
 
-       pool_ref(pool);
-       ctx->conn = auth_worker_call(pool, reply, iter_callback, ctx);
+       auth_request_ref(request);
+       ctx->conn = auth_worker_call(request->pool, reply, iter_callback, ctx);
        return &ctx->ctx;
 }
 
@@ -123,7 +120,7 @@ int userdb_blocking_iter_deinit(struct userdb_iterate_context **_ctx)
 
        *_ctx = NULL;
 
+       /* iter_callback() may still be called */
        ctx->destroyed = TRUE;
-       pool_unref(&ctx->pool);
        return ret;
 }
index 9818762570c83f46d12fff477944bd5cc8fa66e7..2bbf0759ae0b86a788d4d5c5997e8a450bfc5875 100644 (file)
@@ -4,7 +4,7 @@
 void userdb_blocking_lookup(struct auth_request *request);
 
 struct userdb_iterate_context *
-userdb_blocking_iter_init(struct userdb_module *userdb,
+userdb_blocking_iter_init(struct auth_request *request,
                          userdb_iter_callback_t *callback, void *context);
 void userdb_blocking_iter_next(struct userdb_iterate_context *ctx);
 int userdb_blocking_iter_deinit(struct userdb_iterate_context **ctx);
index 31830f5f1162cb9c2cf29d7ff6d2ddaedee7f013..bb64bbadab0d3a43e232bd49489331c5a3a02967 100644 (file)
@@ -185,37 +185,39 @@ static void userdb_ldap_iterate_callback(struct ldap_connection *conn,
 }
 
 static struct userdb_iterate_context *
-userdb_ldap_iterate_init(struct userdb_module *userdb,
+userdb_ldap_iterate_init(struct auth_request *auth_request,
                         userdb_iter_callback_t *callback, void *context)
 {
-       static struct var_expand_table static_tab[] = {
-               /* nothing for now, but e.g. %{hostname} can be used */
-               { '\0', NULL, NULL }
-       };
+       struct userdb_module *_module = auth_request->userdb->userdb;
        struct ldap_userdb_module *module =
-               (struct ldap_userdb_module *)userdb;
+               (struct ldap_userdb_module *)_module;
        struct ldap_connection *conn = module->conn;
        struct ldap_userdb_iterate_context *ctx;
        struct userdb_iter_ldap_request *request;
+        const struct var_expand_table *vars;
        const char **attr_names = (const char **)conn->iterate_attr_names;
        string_t *str;
 
        ctx = i_new(struct ldap_userdb_iterate_context, 1);
-       ctx->ctx.userdb = userdb;
+       ctx->ctx.auth_request = auth_request;
        ctx->ctx.callback = callback;
        ctx->ctx.context = context;
        ctx->conn = conn;
        request = &ctx->request;
        request->ctx = ctx;
 
-       request->request.request.auth_request = auth_request_new_dummy();
-       request->request.base = conn->set.base;
+       auth_request_ref(auth_request);
+       request->request.request.auth_request = auth_request;
+
+       vars = auth_request_get_var_expand_table(auth_request, ldap_escape);
 
        str = t_str_new(512);
-       var_expand(str, conn->set.iterate_filter, static_tab);
-       request->request.filter =
-               p_strdup(request->request.request.auth_request->pool,
-                        str_c(str));
+       var_expand(str, conn->set.base, vars);
+       request->request.base = p_strdup(auth_request->pool, str_c(str));
+
+       str_truncate(str, 0);
+       var_expand(str, conn->set.iterate_filter, vars);
+       request->request.filter = p_strdup(auth_request->pool, str_c(str));
        request->request.attributes = conn->iterate_attr_names;
 
        if (global_auth_settings->debug) {
index 984e6eb6ca016e71eae6c2ab7ec3e2dbde8a5c79..429999797c7fc0002620eeb3c82da75bf307cea6 100644 (file)
@@ -85,16 +85,17 @@ static void passwd_file_lookup(struct auth_request *auth_request,
 }
 
 static struct userdb_iterate_context *
-passwd_file_iterate_init(struct userdb_module *userdb,
+passwd_file_iterate_init(struct auth_request *auth_request,
                         userdb_iter_callback_t *callback, void *context)
 {
+       struct userdb_module *_module = auth_request->userdb->userdb;
        struct passwd_file_userdb_module *module =
-               (struct passwd_file_userdb_module *)userdb;
+               (struct passwd_file_userdb_module *)_module;
        struct passwd_file_userdb_iterate_context *ctx;
        int fd;
 
        ctx = i_new(struct passwd_file_userdb_iterate_context, 1);
-       ctx->ctx.userdb = userdb;
+       ctx->ctx.auth_request = auth_request;
        ctx->ctx.callback = callback;
        ctx->ctx.context = context;
        if (module->pwf->default_file == NULL) {
index ce02d6546dd7c5229b6024fabf8692004317a8bf..707c093563ea4f673b83ed180c07357305bf08b7 100644 (file)
@@ -19,7 +19,6 @@ struct passwd_userdb_module {
 struct passwd_userdb_iterate_context {
        struct userdb_iterate_context ctx;
        struct passwd_userdb_iterate_context *next_waiting;
-       const struct auth_settings *set;
 };
 
 static struct passwd_userdb_iterate_context *cur_userdb_iter = NULL;
@@ -62,16 +61,15 @@ static void passwd_lookup(struct auth_request *auth_request,
 }
 
 static struct userdb_iterate_context *
-passwd_iterate_init(struct userdb_module *userdb,
+passwd_iterate_init(struct auth_request *auth_request,
                    userdb_iter_callback_t *callback, void *context)
 {
        struct passwd_userdb_iterate_context *ctx;
 
        ctx = i_new(struct passwd_userdb_iterate_context, 1);
-       ctx->ctx.userdb = userdb;
+       ctx->ctx.auth_request = auth_request;
        ctx->ctx.callback = callback;
        ctx->ctx.context = context;
-       ctx->set = auth_find_service("")->set;
        setpwent();
 
        if (cur_userdb_iter == NULL)
@@ -83,6 +81,7 @@ static void passwd_iterate_next(struct userdb_iterate_context *_ctx)
 {
        struct passwd_userdb_iterate_context *ctx =
                (struct passwd_userdb_iterate_context *)_ctx;
+       const struct auth_settings *set = _ctx->auth_request->set;
        struct passwd *pw;
 
        if (cur_userdb_iter != NULL && cur_userdb_iter != ctx) {
@@ -97,9 +96,9 @@ static void passwd_iterate_next(struct userdb_iterate_context *_ctx)
        while ((pw = getpwent()) != NULL) {
                /* skip entries not in valid UID range.
                   they're users for daemons and such. */
-               if (pw->pw_uid >= (uid_t)ctx->set->first_valid_uid &&
-                   (ctx->set->last_valid_uid == 0 ||
-                    pw->pw_uid <= (uid_t)ctx->set->last_valid_uid)) {
+               if (pw->pw_uid >= (uid_t)set->first_valid_uid &&
+                   (set->last_valid_uid == 0 ||
+                    pw->pw_uid <= (uid_t)set->last_valid_uid)) {
                        _ctx->callback(pw->pw_name, _ctx->context);
                        return;
                }
index 89def7ea138c755b0f3ffe5e4614129ed5c87b1e..fef4c6b29d01dbfb453b6ef7553768f4fd71a8a8 100644 (file)
@@ -140,28 +140,29 @@ static void sql_iter_query_callback(struct sql_result *sql_result,
 }
 
 static struct userdb_iterate_context *
-userdb_sql_iterate_init(struct userdb_module *userdb,
+userdb_sql_iterate_init(struct auth_request *auth_request,
                        userdb_iter_callback_t *callback, void *context)
 {
-       static struct var_expand_table static_tab[] = {
-               /* nothing for now, but e.g. %{hostname} can be used */
-               { '\0', NULL, NULL }
-       };
+       struct userdb_module *_module = auth_request->userdb->userdb;
        struct sql_userdb_module *module =
-               (struct sql_userdb_module *)userdb;
+               (struct sql_userdb_module *)_module;
        struct sql_userdb_iterate_context *ctx;
        string_t *query;
 
        query = t_str_new(512);
-       var_expand(query, module->conn->set.iterate_query, static_tab);
+       var_expand(query, module->conn->set.iterate_query,
+                  auth_request_get_var_expand_table(auth_request,
+                                                    userdb_sql_escape));
 
        ctx = i_new(struct sql_userdb_iterate_context, 1);
-       ctx->ctx.userdb = userdb;
+       ctx->ctx.auth_request = auth_request;
        ctx->ctx.callback = callback;
        ctx->ctx.context = context;
+       auth_request_ref(auth_request);
 
        sql_query(module->conn->db, str_c(query),
                  sql_iter_query_callback, ctx);
+       auth_request_log_debug(auth_request, "sql", "%s", str_c(query));
        return &ctx->ctx;
 }
 
@@ -199,7 +200,7 @@ static void userdb_sql_iterate_next(struct userdb_iterate_context *_ctx)
 {
        struct sql_userdb_iterate_context *ctx =
                (struct sql_userdb_iterate_context *)_ctx;
-       struct userdb_module *_module = _ctx->userdb;
+       struct userdb_module *_module = _ctx->auth_request->userdb->userdb;
        struct sql_userdb_module *module = (struct sql_userdb_module *)_module;
        const char *user;
        int ret;
@@ -242,6 +243,7 @@ static int userdb_sql_iterate_deinit(struct userdb_iterate_context *_ctx)
                (struct sql_userdb_iterate_context *)_ctx;
        int ret = _ctx->failed ? -1 : 0;
 
+       auth_request_unref(&_ctx->auth_request);
        if (ctx->result == NULL) {
                /* sql query hasn't finished yet */
                ctx->freed = TRUE;
index 0946824af85c9d2f2a287d8c2c8f7decf93b4978..0e9412f692b8757cbaec7920ae5d4088f80a5543 100644 (file)
@@ -41,7 +41,7 @@ struct userdb_module {
 };
 
 struct userdb_iterate_context {
-       struct userdb_module *userdb;
+       struct auth_request *auth_request;
        userdb_iter_callback_t *callback;
        void *context;
        bool failed;
@@ -58,7 +58,7 @@ struct userdb_module_interface {
                       userdb_callback_t *callback);
 
        struct userdb_iterate_context *
-               (*iterate_init)(struct userdb_module *userdb,
+               (*iterate_init)(struct auth_request *auth_request,
                                userdb_iter_callback_t *callback,
                                void *context);
        void (*iterate_next)(struct userdb_iterate_context *ctx);