dovecot-2.2: doveconf: Added -H parameter to check for hostname ...

dovecot at dovecot.org dovecot at dovecot.org
Mon Feb 18 08:46:15 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/62a930eb22b5
changeset: 15831:62a930eb22b5
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Feb 18 08:46:06 2013 +0200
description:
doveconf: Added -H parameter to check for hostname hash duplicates.

diffstat:

 src/config/doveconf.c |  118 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 116 insertions(+), 2 deletions(-)

diffs (170 lines):

diff -r 80344aedd8fd -r 62a930eb22b5 src/config/doveconf.c
--- a/src/config/doveconf.c	Mon Feb 18 08:45:54 2013 +0200
+++ b/src/config/doveconf.c	Mon Feb 18 08:46:06 2013 +0200
@@ -5,6 +5,9 @@
 #include "abspath.h"
 #include "module-dir.h"
 #include "env-util.h"
+#include "guid.h"
+#include "hash.h"
+#include "hostpid.h"
 #include "ostream.h"
 #include "str.h"
 #include "strescape.h"
@@ -19,6 +22,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <ctype.h>
 #include <unistd.h>
 #include <sysexits.h>
 
@@ -564,6 +568,110 @@
 	}
 }
 
+struct hostname_format {
+	const char *prefix, *suffix;
+	unsigned int numcount;
+	bool zeropadding;
+};
+
+static void
+hostname_format_write(string_t *str, const struct hostname_format *fmt,
+		      unsigned int num)
+{
+	str_truncate(str, 0);
+	str_append(str, fmt->prefix);
+	if (!fmt->zeropadding)
+		str_printfa(str, "%d", num);
+	else
+		str_printfa(str, "%0*d", fmt->numcount, num);
+	str_append(str, fmt->suffix);
+}
+
+static void hostname_verify_format(const char *arg)
+{
+	struct hostname_format fmt;
+	const char *p;
+	unsigned char hash[GUID_128_HOST_HASH_SIZE];
+	unsigned int len, n, limit;
+	HASH_TABLE(void *, void *) hosts;
+	void *key, *value;
+	string_t *host;
+	const char *host2;
+	bool duplicates = FALSE;
+
+	memset(&fmt, 0, sizeof(fmt));
+	if (arg != NULL) {
+		/* host%d, host%2d, host%02d */
+		p = strchr(arg, '%');
+		if (p == NULL)
+			i_fatal("Host parameter missing %%d");
+		fmt.prefix = t_strdup_until(arg, p++);
+		if (*p == '0') {
+			fmt.zeropadding = TRUE;
+			p++;
+		}
+		if (!i_isdigit(*p))
+			fmt.numcount = 1;
+		else
+			fmt.numcount = *p++ - '0';
+		if (*p++ != 'd')
+			i_fatal("Host parameter missing %%d");
+		fmt.suffix = p;
+	} else {
+		/* detect host1[suffix] vs host01[suffix] */
+		len = strlen(my_hostname);
+		while (len > 0 && !i_isdigit(my_hostname[len-1]))
+			len--;
+		fmt.suffix = my_hostname + len;
+		fmt.numcount = 0;
+		while (len > 0 && i_isdigit(my_hostname[len-1])) {
+			len--;
+			fmt.numcount++;
+		}
+		if (my_hostname[len] == '0')
+			fmt.zeropadding = TRUE;
+		fmt.prefix = t_strndup(my_hostname, len);
+		if (fmt.numcount == 0) {
+			i_fatal("Hostname '%s' has no digits, can't verify",
+				my_hostname);
+		}
+	}
+	for (n = 0, limit = 1; n < fmt.numcount; n++)
+		limit *= 10;
+	host = t_str_new(128);
+	hash_table_create_direct(&hosts, default_pool, limit);
+	for (n = 0; n < limit; n++) {
+		hostname_format_write(host, &fmt, n);
+
+		guid_128_host_hash_get(str_c(host), hash);
+		i_assert(sizeof(key) >= sizeof(hash));
+		key = NULL; memcpy(&key, hash, sizeof(hash));
+
+		value = hash_table_lookup(hosts, key);
+		if (value != NULL) {
+			host2 = t_strdup(str_c(host));
+			hostname_format_write(host, &fmt,
+				POINTER_CAST_TO(value, unsigned int)-1);
+			i_error("Duplicate host hashes: %s and %s",
+				str_c(host), host2);
+			duplicates = TRUE;
+		} else {
+			hash_table_insert(hosts, key, POINTER_CAST(n+1));
+		}
+	}
+	hash_table_destroy(&hosts);
+
+	if (duplicates)
+		exit(EX_CONFIG);
+	else {
+		host2 = t_strdup(str_c(host));
+		hostname_format_write(host, &fmt, 0);
+		printf("No duplicate host hashes in %s .. %s\n",
+		       str_c(host), host2);
+		exit(0);
+	}
+}
+
 static void check_wrong_config(const char *config_path)
 {
 	const char *base_dir, *symlink_path, *prev_path;
@@ -598,7 +706,7 @@
 	int c, ret, ret2;
 	bool config_path_specified, expand_vars = FALSE, hide_key = FALSE;
 	bool parse_full_config = FALSE, simple_output = FALSE;
-	bool dump_defaults = FALSE;
+	bool dump_defaults = FALSE, host_verify = FALSE;
 
 	if (getenv("USE_SYSEXITS") != NULL) {
 		/* we're coming from (e.g.) LDA */
@@ -608,7 +716,7 @@
 	memset(&filter, 0, sizeof(filter));
 	master_service = master_service_init("config",
 					     MASTER_SERVICE_FLAG_STANDALONE,
-					     &argc, &argv, "adf:hm:nNpexS");
+					     &argc, &argv, "adf:hHm:nNpexS");
 	orig_config_path = master_service_get_config_path(master_service);
 
 	i_set_failure_prefix("doveconf: ");
@@ -630,6 +738,9 @@
 		case 'h':
 			hide_key = TRUE;
 			break;
+		case 'H':
+			host_verify = TRUE;
+			break;
 		case 'm':
 			module = t_strdup(optarg);
 			array_append(&module_names, &module, 1);
@@ -662,6 +773,9 @@
 	   -c parameter */
 	config_path_specified = strcmp(config_path, orig_config_path) != 0;
 
+	if (host_verify)
+		hostname_verify_format(argv[optind]);
+
 	if (c == 'e') {
 		if (argv[optind] == NULL)
 			i_fatal("Missing command for -e");


More information about the dovecot-cvs mailing list