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