dovecot-2.0: Implemented support for listing all users in userdb.

dovecot at dovecot.org dovecot at dovecot.org
Thu May 14 00:51:22 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/1d7965092e0e
changeset: 9273:1d7965092e0e
user:      Timo Sirainen <tss at iki.fi>
date:      Wed May 13 17:51:16 2009 -0400
description:
Implemented support for listing all users in userdb.

diffstat:

28 files changed, 1034 insertions(+), 193 deletions(-)
doc/dovecot-ldap-example.conf     |    4 
doc/dovecot-sql-example.conf      |    3 
src/auth/auth-master-connection.c |  120 +++++++++++++++++++++++++
src/auth/auth-worker-client.c     |  114 +++++++++++++++++++++++
src/auth/auth-worker-server.c     |   80 ++++++++--------
src/auth/auth-worker-server.h     |   13 +-
src/auth/db-ldap.c                |  106 ++++++++++++++++------
src/auth/db-ldap.h                |   14 ++
src/auth/db-passwd-file.h         |    1 
src/auth/db-sql.c                 |    2 
src/auth/db-sql.h                 |    1 
src/auth/main.c                   |    1 
src/auth/passdb-blocking.c        |   32 ++++--
src/auth/passdb-ldap.c            |  139 +++++++++++++++--------------
src/auth/passdb.c                 |    5 -
src/auth/userdb-blocking.c        |   78 +++++++++++++++-
src/auth/userdb-blocking.h        |    6 +
src/auth/userdb-checkpassword.c   |    4 
src/auth/userdb-ldap.c            |  177 +++++++++++++++++++++++++++++++------
src/auth/userdb-nss.c             |    6 +
src/auth/userdb-passwd-file.c     |   76 +++++++++++++++
src/auth/userdb-passwd.c          |   81 ++++++++++++++++
src/auth/userdb-prefetch.c        |    6 +
src/auth/userdb-sql.c             |  125 +++++++++++++++++++++++++-
src/auth/userdb-static.c          |    6 +
src/auth/userdb-vpopmail.c        |    6 +
src/auth/userdb.c                 |    5 -
src/auth/userdb.h                 |   16 +++

diffs (truncated from 1906 to 300 lines):

diff -r f5b6974cbee7 -r 1d7965092e0e doc/dovecot-ldap-example.conf
--- a/doc/dovecot-ldap-example.conf	Wed May 13 12:40:58 2009 -0400
+++ b/doc/dovecot-ldap-example.conf	Wed May 13 17:51:16 2009 -0400
@@ -129,6 +129,10 @@ base = uid=someone, dc=foo, dc=bar, dc=o
 # Filter for password lookups
 #pass_filter = (&(objectClass=posixAccount)(uid=%u))
 
+# Attributes and filter to get a list of all users
+#iterate_attrs = uid=user
+#iterate_filter = (objectClass=posixAccount)
+
 # Default password scheme. "{scheme}" before password overrides this.
 # List of supported schemes is in: http://wiki.dovecot.org/Authentication
 #default_pass_scheme = CRYPT
diff -r f5b6974cbee7 -r 1d7965092e0e doc/dovecot-sql-example.conf
--- a/doc/dovecot-sql-example.conf	Wed May 13 12:40:58 2009 -0400
+++ b/doc/dovecot-sql-example.conf	Wed May 13 17:51:16 2009 -0400
@@ -128,3 +128,6 @@
 #  SELECT userid AS user, password, \
 #    home AS userdb_home, uid AS userdb_uid, gid AS userdb_gid \
 #  FROM users WHERE userid = '%u'
+
+# Query to get a list of all usernames.
+#iterate_query = SELECT username AS user FROM users
diff -r f5b6974cbee7 -r 1d7965092e0e src/auth/auth-master-connection.c
--- a/src/auth/auth-master-connection.c	Wed May 13 12:40:58 2009 -0400
+++ b/src/auth/auth-master-connection.c	Wed May 13 17:51:16 2009 -0400
@@ -4,6 +4,7 @@
 #include "array.h"
 #include "hash.h"
 #include "str.h"
+#include "strescape.h"
 #include "hostpid.h"
 #include "str-sanitize.h"
 #include "ioloop.h"
@@ -12,6 +13,7 @@
 #include "ostream.h"
 #include "master-service.h"
 #include "userdb.h"
+#include "userdb-blocking.h"
 #include "auth-request-handler.h"
 #include "auth-master-interface.h"
 #include "auth-client-connection.h"
@@ -28,6 +30,16 @@ struct master_userdb_request {
 	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;
+	bool failed;
+};
+
+static void master_input(struct auth_master_connection *conn);
 
 ARRAY_TYPE(auth_master_connections) auth_master_connections;
 
@@ -162,6 +174,112 @@ master_input_user(struct auth_master_con
 	return TRUE;
 }
 
+static void master_input_list_finish(struct master_list_iter_ctx *ctx)
+{
+	ctx->conn->io = io_add(ctx->conn->fd, IO_READ, master_input, ctx->conn);
+
+	if (ctx->iter != NULL)
+		(void)userdb_blocking_iter_deinit(&ctx->iter);
+	o_stream_unset_flush_callback(ctx->conn->output);
+	i_free(ctx);
+}
+
+static int master_output_list(struct master_list_iter_ctx *ctx)
+{
+	int ret;
+
+	if ((ret = o_stream_flush(ctx->conn->output)) < 0) {
+		master_input_list_finish(ctx);
+		return 1;
+	}
+	if (ret > 0)
+		userdb_blocking_iter_next(ctx->iter);
+	return 1;
+}
+
+static void master_input_list_callback(const char *user, void *context)
+{
+	struct master_list_iter_ctx *ctx = context;
+	int ret;
+
+	if (user == NULL) {
+		if (userdb_blocking_iter_deinit(&ctx->iter) < 0)
+			ctx->failed = TRUE;
+
+		do {
+			ctx->userdb = ctx->userdb->next;
+		} while (ctx->userdb != NULL &&
+			 ctx->userdb->userdb->iface->iterate_init == NULL);
+		if (ctx->userdb == NULL) {
+			/* iteration is finished */
+			const char *str;
+
+			str = t_strdup_printf("DONE\t%u\t%s\n", ctx->id,
+					      ctx->failed ? "fail" : "");
+			(void)o_stream_send_str(ctx->conn->output, str);
+			master_input_list_finish(ctx);
+			return;
+		}
+
+		/* continue iterating next userdb */
+		userdb_blocking_iter_init(ctx->userdb,
+					  master_input_list_callback, ctx);
+		userdb_blocking_iter_next(ctx->iter);
+		return;
+	}
+
+	T_BEGIN {
+		const char *str;
+
+		str = t_strdup_printf("LIST\t%u\t%s\n", ctx->id,
+				      str_tabescape(user));
+		ret = o_stream_send_str(ctx->conn->output, str);
+	} T_END;
+	if (ret < 0) {
+		/* disconnected, don't bother finishing */
+		master_input_list_finish(ctx);
+		return;
+	}
+	if (o_stream_get_buffer_used_size(ctx->conn->output) == 0)
+		userdb_blocking_iter_next(ctx->iter);
+}
+
+static bool
+master_input_list(struct auth_master_connection *conn, const char *args)
+{
+	struct auth_userdb *userdb = conn->auth->userdbs;
+	struct master_list_iter_ctx *ctx;
+	const char *str;
+	unsigned int id;
+
+	/* <id> */
+	if (*args == '\0') {
+		i_error("BUG: Master sent broken LIST");
+		return FALSE;
+	}
+	id = strtoul(args, NULL, 10);
+
+	while (userdb != NULL && userdb->userdb->iface->iterate_init == NULL)
+		userdb = userdb->next;
+	if (userdb == NULL) {
+		i_error("Trying to iterate users, but userdbs don't suppor it");
+		str = t_strdup_printf("DONE\t%u\tfail", id);
+		(void)o_stream_send_str(conn->output, str);
+		return TRUE;
+	}
+
+	ctx = i_new(struct master_list_iter_ctx, 1);
+	ctx->conn = conn;
+	ctx->userdb = userdb;
+	ctx->id = id;
+
+	io_remove(&conn->io);
+	o_stream_set_flush_callback(conn->output, master_output_list, ctx);
+	ctx->iter = userdb_blocking_iter_init(ctx->userdb,
+					      master_input_list_callback, ctx);
+	return TRUE;
+}
+
 static bool
 auth_master_input_line(struct auth_master_connection *conn, const char *line)
 {
@@ -172,6 +290,8 @@ auth_master_input_line(struct auth_maste
 		return master_input_request(conn, line + 8);
 	else if (strncmp(line, "USER\t", 5) == 0)
 		return master_input_user(conn, line + 5);
+	else if (strncmp(line, "LIST\t", 5) == 0)
+		return master_input_list(conn, line + 5);
 	else if (strncmp(line, "CPID\t", 5) == 0) {
 		i_error("Authentication client trying to connect to "
 			"master socket");
diff -r f5b6974cbee7 -r 1d7965092e0e src/auth/auth-worker-client.c
--- a/src/auth/auth-worker-client.c	Wed May 13 12:40:58 2009 -0400
+++ b/src/auth/auth-worker-client.c	Wed May 13 17:51:16 2009 -0400
@@ -24,6 +24,17 @@ struct auth_worker_client {
 	struct istream *input;
 	struct ostream *output;
 };
+
+struct auth_worker_list_context {
+	struct auth_worker_client *client;
+	struct userdb_module *userdb;
+	struct userdb_iterate_context *iter;
+	unsigned int id;
+	bool sending, sent, done;
+};
+
+static void auth_worker_input(struct auth_worker_client *client);
+static int auth_worker_output(struct auth_worker_client *client);
 
 static void
 auth_worker_client_check_throttle(struct auth_worker_client *client)
@@ -395,6 +406,104 @@ auth_worker_handle_user(struct auth_work
 		lookup(auth_request, lookup_user_callback);
 }
 
+static void list_iter_deinit(struct auth_worker_list_context *ctx)
+{
+	struct auth_worker_client *client = ctx->client;
+	string_t *str;
+
+	str = t_str_new(32);
+	if (ctx->userdb->iface->iterate_deinit(ctx->iter) < 0)
+		str_printfa(str, "%u\tFAIL\n", ctx->id);
+	else
+		str_printfa(str, "%u\tOK\n", ctx->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_worker_client_unref(&client);
+	i_free(ctx);
+}
+
+static void list_iter_callback(const char *user, void *context)
+{
+	struct auth_worker_list_context *ctx = context;
+	string_t *str;
+
+	if (user == NULL) {
+		if (ctx->sending)
+			ctx->done = TRUE;
+		else
+			list_iter_deinit(ctx);
+		return;
+	}
+
+	T_BEGIN {
+		str = t_str_new(128);
+		str_printfa(str, "%u\t*\t%s\n", ctx->id, user);
+		o_stream_send(ctx->client->output, str_data(str), str_len(str));
+	} T_END;
+
+	if (ctx->sending) {
+		/* avoid recursively looping to this same function */
+		ctx->sent = TRUE;
+		return;
+	}
+
+	do {
+		ctx->sending = TRUE;
+		ctx->sent = FALSE;
+		ctx->userdb->iface->iterate_next(ctx->iter);
+	} while (ctx->sent &&
+		 o_stream_get_buffer_used_size(ctx->client->output) == 0);
+	ctx->sending = FALSE;
+	if (ctx->done)
+		list_iter_deinit(ctx);
+}
+
+static int auth_worker_list_output(struct auth_worker_list_context *ctx)
+{
+	int ret;
+
+	if ((ret = o_stream_flush(ctx->client->output)) < 0) {
+		list_iter_deinit(ctx);
+		return 1;
+	}
+	if (ret > 0)
+		ctx->userdb->iface->iterate_next(ctx->iter);
+	return 1;
+}
+
+static void
+auth_worker_handle_list(struct auth_worker_client *client,
+			unsigned int id, const char *args)
+{
+	struct auth_worker_list_context *ctx;
+	struct auth_userdb *userdb;
+	unsigned int num;
+
+	userdb = client->auth->userdbs;
+	for (num = atoi(args); num > 0; num--) {
+		userdb = userdb->next;
+		if (userdb == NULL) {
+			i_error("BUG: LIST had invalid userdb num");
+			return;
+		}
+	}
+
+	ctx = i_new(struct auth_worker_list_context, 1);
+	ctx->client = client;
+	ctx->id = id;
+	ctx->userdb = userdb->userdb;
+
+	io_remove(&ctx->client->io);
+	o_stream_set_flush_callback(ctx->client->output,
+				    auth_worker_list_output, ctx);
+	client->refcount++;


More information about the dovecot-cvs mailing list