changeset 13760:acfe332f9aeb

auth: Support passing regular %variables to sql/ldap iterate queries.
author Timo Sirainen <tss@iki.fi>
date Wed, 23 Nov 2011 22:07:08 +0200
parents 35764175dc92
children 59e25ebc976f
files 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
diffstat 10 files changed, 130 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/auth-master-connection.c	Wed Nov 23 21:40:04 2011 +0200
+++ b/src/auth/auth-master-connection.c	Wed Nov 23 22:07:08 2011 +0200
@@ -29,15 +29,13 @@
 
 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 @@
 	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 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 @@
 			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 @@
 		}
 
 		/* 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 @@
 	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 @@
 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 @@
 		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;
 }
--- a/src/auth/auth-settings.c	Wed Nov 23 21:40:04 2011 +0200
+++ b/src/auth/auth-settings.c	Wed Nov 23 22:07:08 2011 +0200
@@ -349,6 +349,7 @@
 	};
  	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 @@
 					 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;
 }
--- a/src/auth/auth-worker-client.c	Wed Nov 23 21:40:04 2011 +0200
+++ b/src/auth/auth-worker-client.c	Wed Nov 23 22:07:08 2011 +0200
@@ -31,9 +31,8 @@
 
 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 @@
 	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 @@
 
 	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 @@
 	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 @@
 		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 @@
 
 	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;
 }
 
--- a/src/auth/userdb-blocking.c	Wed Nov 23 21:40:04 2011 +0200
+++ b/src/auth/userdb-blocking.c	Wed Nov 23 22:07:08 2011 +0200
@@ -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 @@
 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 @@
 		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 @@
 
 	*_ctx = NULL;
 
+	/* iter_callback() may still be called */
 	ctx->destroyed = TRUE;
-	pool_unref(&ctx->pool);
 	return ret;
 }
--- a/src/auth/userdb-blocking.h	Wed Nov 23 21:40:04 2011 +0200
+++ b/src/auth/userdb-blocking.h	Wed Nov 23 22:07:08 2011 +0200
@@ -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);
--- a/src/auth/userdb-ldap.c	Wed Nov 23 21:40:04 2011 +0200
+++ b/src/auth/userdb-ldap.c	Wed Nov 23 22:07:08 2011 +0200
@@ -185,37 +185,39 @@
 }
 
 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) {
--- a/src/auth/userdb-passwd-file.c	Wed Nov 23 21:40:04 2011 +0200
+++ b/src/auth/userdb-passwd-file.c	Wed Nov 23 22:07:08 2011 +0200
@@ -85,16 +85,17 @@
 }
 
 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) {
--- a/src/auth/userdb-passwd.c	Wed Nov 23 21:40:04 2011 +0200
+++ b/src/auth/userdb-passwd.c	Wed Nov 23 22:07:08 2011 +0200
@@ -19,7 +19,6 @@
 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 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 @@
 {
 	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 @@
 	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;
 		}
--- a/src/auth/userdb-sql.c	Wed Nov 23 21:40:04 2011 +0200
+++ b/src/auth/userdb-sql.c	Wed Nov 23 22:07:08 2011 +0200
@@ -140,28 +140,29 @@
 }
 
 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 @@
 {
 	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 @@
 		(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;
--- a/src/auth/userdb.h	Wed Nov 23 21:40:04 2011 +0200
+++ b/src/auth/userdb.h	Wed Nov 23 22:07:08 2011 +0200
@@ -41,7 +41,7 @@
 };
 
 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 @@
 		       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);