dovecot-2.0: doveadm: Added "director map" command to list user ...

dovecot at dovecot.org dovecot at dovecot.org
Thu Jul 15 17:28:35 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/4138737f41e6
changeset: 11823:4138737f41e6
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Jul 15 15:28:32 2010 +0100
description:
doveadm: Added "director map" command to list user -> host mappings.

diffstat:

 src/director/doveadm-connection.c |   36 +++++++++
 src/doveadm/doveadm-director.c    |  144 +++++++++++++++++++++++++++++++++--
 2 files changed, 169 insertions(+), 11 deletions(-)

diffs (293 lines):

diff -r 7a6cf8dae9bf -r 4138737f41e6 src/director/doveadm-connection.c
--- a/src/director/doveadm-connection.c	Thu Jul 15 13:42:33 2010 +0100
+++ b/src/director/doveadm-connection.c	Thu Jul 15 15:28:32 2010 +0100
@@ -195,6 +195,40 @@
 	return TRUE;
 }
 
+static bool
+doveadm_cmd_user_list(struct doveadm_connection *conn, const char *line)
+{
+	struct user_directory_iter *iter;
+	struct user *user;
+	struct ip_addr ip;
+
+	if (*line != '\0') {
+		if (net_addr2ip(line, &ip) < 0) {
+			i_error("doveadm sent invalid USER-LIST parameters");
+			return FALSE;
+		}
+	} else {
+		ip.family = 0;
+	}
+
+	iter = user_directory_iter_init(conn->dir->users);
+	while ((user = user_directory_iter_next(iter)) != NULL) {
+		if (ip.family == 0 ||
+		    net_ip_compare(&ip, &user->host->ip)) T_BEGIN {
+			unsigned int expire_time = user->timestamp +
+				conn->dir->set->director_user_expire;
+
+			o_stream_send_str(conn->output, t_strdup_printf(
+				"%u\t%u\t%s\n",
+				user->username_hash, expire_time,
+				net_ip2addr(&user->host->ip)));
+		} T_END;
+	}
+	user_directory_iter_deinit(&iter);
+	o_stream_send(conn->output, "\n", 1);
+	return TRUE;
+}
+
 static void doveadm_connection_input(struct doveadm_connection *conn)
 {
 	const char *line, *cmd, *args;
@@ -236,6 +270,8 @@
 			ret = doveadm_cmd_host_flush(conn, args);
 		else if (strcmp(cmd, "USER-LOOKUP") == 0)
 			ret = doveadm_cmd_user_lookup(conn, args);
+		else if (strcmp(cmd, "USER-LIST") == 0)
+			ret = doveadm_cmd_user_list(conn, args);
 		else {
 			i_error("doveadm sent unknown command: %s", line);
 			ret = FALSE;
diff -r 7a6cf8dae9bf -r 4138737f41e6 src/doveadm/doveadm-director.c
--- a/src/doveadm/doveadm-director.c	Thu Jul 15 13:42:33 2010 +0100
+++ b/src/doveadm/doveadm-director.c	Thu Jul 15 15:28:32 2010 +0100
@@ -1,10 +1,13 @@
 /* Copyright (c) 2009-2010 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "md5.h"
+#include "hash.h"
 #include "network.h"
 #include "istream.h"
 #include "write-full.h"
 #include "master-service.h"
+#include "auth-master.h"
 #include "doveadm.h"
 #include "doveadm-print.h"
 
@@ -17,8 +20,15 @@
 	struct istream *input;
 };
 
+struct user_list {
+	struct user_list *next;
+	const char *name;
+};
+
 extern struct doveadm_cmd doveadm_cmd_director[];
 
+static void director_cmd_help(doveadm_command_t *cmd);
+
 static void
 director_send(struct director_context *ctx, const char *data)
 {
@@ -55,7 +65,7 @@
 }
 
 static struct director_context *
-cmd_director_init(int argc, char *argv[], unsigned int cmd_idx)
+cmd_director_init(int argc, char *argv[], doveadm_command_t *cmd)
 {
 	struct director_context *ctx;
 	int c;
@@ -70,7 +80,7 @@
 			ctx->socket_path = optarg;
 			break;
 		default:
-			help(&doveadm_cmd_director[cmd_idx]);
+			director_cmd_help(cmd);
 		}
 	}
 	director_connect(ctx);
@@ -113,7 +123,7 @@
 	struct director_context *ctx;
 	const char *line, *const *args;
 
-	ctx = cmd_director_init(argc, argv, 0);
+	ctx = cmd_director_init(argc, argv, cmd_director_status);
 	if (argv[optind] != NULL) {
 		cmd_director_status_user(ctx, argv[optind]);
 		return;
@@ -142,6 +152,106 @@
 	director_disconnect(ctx);
 }
 
+static unsigned int director_username_hash(const char *username)
+{
+	unsigned char md5[MD5_RESULTLEN];
+	unsigned int i, hash = 0;
+
+	md5_get_digest(username, strlen(username), md5);
+	for (i = 0; i < sizeof(hash); i++)
+		hash = (hash << CHAR_BIT) | md5[i];
+	return hash;
+}
+
+static void
+get_user_list(const char *auth_socket_path, pool_t pool,
+	      struct hash_table *users)
+{
+	struct auth_master_user_list_ctx *ctx;
+	struct auth_master_connection *conn;
+	const char *username;
+	struct user_list *user, *old_user;
+	unsigned int user_hash;
+
+	if (auth_socket_path == NULL) {
+		auth_socket_path = t_strconcat(doveadm_settings->base_dir,
+					       "/auth-userdb", NULL);
+	}
+
+	conn = auth_master_init(auth_socket_path, 0);
+	ctx = auth_master_user_list_init(conn);
+	while ((username = auth_master_user_list_next(ctx)) != NULL) {
+		user = p_new(pool, struct user_list, 1);
+		user->name = p_strdup(pool, username);
+		user_hash = director_username_hash(username);
+
+		old_user = hash_table_lookup(users, POINTER_CAST(user_hash));
+		if (old_user != NULL)
+			user->next = old_user;
+		hash_table_insert(users, POINTER_CAST(user_hash), user);
+	}
+	if (auth_master_user_list_deinit(&ctx) < 0) {
+		i_error("user listing failed");
+		exit(1);
+	}
+	auth_master_deinit(&conn);
+}
+
+static void cmd_director_map(int argc, char *argv[])
+{
+	struct director_context *ctx;
+	const char *line, *const *args, *username;
+	struct ip_addr ip, user_ip;
+	pool_t pool;
+	struct hash_table *users;
+	struct user_list *user;
+	unsigned int user_hash, expires;
+
+	ctx = cmd_director_init(argc, argv, cmd_director_map);
+	if (argv[optind] == NULL)
+		ip.family = 0;
+	else if (!net_addr2ip(argv[optind], &ip) < 0 || argv[optind+1] != NULL)
+		director_cmd_help(cmd_director_map);
+
+	pool = pool_alloconly_create("director map users", 1024*128);
+	users = hash_table_create(default_pool, pool, 0, NULL, NULL);
+	get_user_list(NULL, pool, users);
+
+	doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
+	doveadm_print_header_simple("user");
+	doveadm_print_header_simple("mail server ip");
+	doveadm_print_header_simple("expire time");
+
+	director_send(ctx, "USER-LIST\n");
+	while ((line = i_stream_read_next_line(ctx->input)) != NULL) {
+		if (*line == '\0')
+			break;
+		T_BEGIN {
+			args = t_strsplit(line, "\t");
+			if (str_array_length(args) < 3 ||
+			    str_to_uint(args[0], &user_hash) < 0 ||
+			    str_to_uint(args[1], &expires) < 0 ||
+			    net_addr2ip(args[2], &user_ip) < 0)
+				i_error("Invalid USER-LIST reply: %s", line);
+			else if (ip.family == 0 ||
+				 net_ip_compare(&ip, &user_ip)) {
+				user = hash_table_lookup(users,
+						POINTER_CAST(user_hash));
+				if (user == NULL)
+					username = "<unknown>";
+				for (; user != NULL; user = user->next) {
+					doveadm_print(user->name);
+					doveadm_print(args[2]);
+					doveadm_print(unixdate2str(expires));
+				}
+			}
+		} T_END;
+	}
+	director_disconnect(ctx);
+	hash_table_destroy(&users);
+	pool_unref(&pool);
+}
+
 static void cmd_director_add(int argc, char *argv[])
 {
 	struct director_context *ctx;
@@ -150,16 +260,16 @@
 	struct ip_addr ip;
 	const char *host, *cmd, *line;
 
-	ctx = cmd_director_init(argc, argv, 0);
+	ctx = cmd_director_init(argc, argv, cmd_director_add);
 	host = argv[optind++];
 	if (host == NULL)
-		help(&doveadm_cmd_director[1]);
+		director_cmd_help(cmd_director_add);
 	if (argv[optind] != NULL) {
 		if (str_to_uint(argv[optind++], &vhost_count) < 0)
-			help(&doveadm_cmd_director[1]);
+			director_cmd_help(cmd_director_add);
 	}
 	if (argv[optind] != NULL)
-		help(&doveadm_cmd_director[1]);
+		director_cmd_help(cmd_director_add);
 
 	if (net_addr2ip(host, &ip) == 0) {
 		ips = &ip;
@@ -199,10 +309,10 @@
 	struct ip_addr ip;
 	const char *host, *line;
 
-	ctx = cmd_director_init(argc, argv, 0);
+	ctx = cmd_director_init(argc, argv, cmd_director_remove);
 	host = argv[optind++];
 	if (host == NULL || argv[optind] != NULL)
-		help(&doveadm_cmd_director[2]);
+		director_cmd_help(cmd_director_remove);
 
 	if (net_addr2ip(host, &ip) == 0) {
 		ips = &ip;
@@ -256,10 +366,10 @@
 	struct ip_addr ip;
 	const char *host, *line;
 
-	ctx = cmd_director_init(argc, argv, 0);
+	ctx = cmd_director_init(argc, argv, cmd_director_flush);
 	host = argv[optind++];
 	if (host == NULL || argv[optind] != NULL)
-		help(&doveadm_cmd_director[3]);
+		director_cmd_help(cmd_director_flush);
 
 	if (strcmp(host, "all") == 0) {
 		cmd_director_flush_all(ctx);
@@ -296,6 +406,8 @@
 struct doveadm_cmd doveadm_cmd_director[] = {
 	{ cmd_director_status, "director status",
 	  "[-a <director socket path>] [<user>]", NULL },
+	{ cmd_director_map, "director map",
+	  "[-a <director socket path>] [<ip>]", NULL },
 	{ cmd_director_add, "director add",
 	  "[-a <director socket path>] <host> [<vhost count>]", NULL },
 	{ cmd_director_remove, "director remove",
@@ -304,6 +416,16 @@
 	  "[-a <director socket path>] <host>|all", NULL }
 };
 
+static void director_cmd_help(doveadm_command_t *cmd)
+{
+	unsigned int i;
+
+	for (i = 0; i < N_ELEMENTS(doveadm_cmd_director); i++) {
+		if (doveadm_cmd_director[i].cmd == cmd)
+			help(&doveadm_cmd_director[i]);
+	}
+	i_unreached();
+}
 
 void doveadm_register_director_commands(void)
 {


More information about the dovecot-cvs mailing list