dovecot-2.2: auth: Fixed auth cache key generation to support %{...

dovecot at dovecot.org dovecot at dovecot.org
Sun May 20 03:26:27 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/a090cbbe3008
changeset: 14340:a090cbbe3008
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Mar 14 14:55:25 2012 +0200
description:
auth: Fixed auth cache key generation to support %{long} variables

diffstat:

 src/auth/Makefile.am       |  20 +++++++++++++
 src/auth/auth-cache.c      |  70 ++++++++++++++++++++++++++++++++++++++-------
 src/auth/auth-request.c    |  48 ++++++++++++++++---------------
 src/auth/auth-request.h    |   2 +
 src/auth/test-auth-cache.c |  57 +++++++++++++++++++++++++++++++++++++
 5 files changed, 162 insertions(+), 35 deletions(-)

diffs (272 lines):

diff -r 13d4c4f91622 -r a090cbbe3008 src/auth/Makefile.am
--- a/src/auth/Makefile.am	Wed Mar 14 13:42:08 2012 +0200
+++ b/src/auth/Makefile.am	Wed Mar 14 14:55:25 2012 +0200
@@ -24,6 +24,7 @@
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-auth \
+	-I$(top_srcdir)/src/lib-test \
 	-I$(top_srcdir)/src/lib-dns \
 	-I$(top_srcdir)/src/lib-sql \
 	-I$(top_srcdir)/src/lib-settings \
@@ -182,3 +183,22 @@
 
 checkpassword_reply_sources = \
 	checkpassword-reply.c
+
+test_programs = \
+	test-auth-cache
+
+noinst_PROGRAMS = $(test_programs)
+
+test_libs = \
+	../lib-test/libtest.la \
+	../lib/liblib.la
+
+test_auth_cache_SOURCES = test-auth-cache.c
+test_auth_cache_LDADD = auth-cache.o $(test_libs)
+test_auth_cache_DEPENDENCIES = auth-cache.o $(test_libs)
+
+check: check-am check-test
+check-test: all-am
+	for bin in $(test_programs); do \
+	  if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
+	done
diff -r 13d4c4f91622 -r a090cbbe3008 src/auth/auth-cache.c
--- a/src/auth/auth-cache.c	Wed Mar 14 13:42:08 2012 +0200
+++ b/src/auth/auth-cache.c	Wed Mar 14 14:55:25 2012 +0200
@@ -23,29 +23,75 @@
 	unsigned long long pos_size, neg_size;
 };
 
+static const struct var_expand_table *
+auth_request_var_expand_tab_find(const char *key, unsigned int size)
+{
+	const struct var_expand_table *tab = auth_request_var_expand_static_tab;
+	unsigned int i;
+
+	for (i = 0; tab[i].key != '\0' || tab[i].long_key != NULL; i++) {
+		if (size == 1) {
+			if (key[0] == tab[i].key)
+				return &tab[i];
+		} else if (tab[i].long_key != NULL) {
+			if (strncmp(key, tab[i].long_key, size) == 0 &&
+			    tab[i].long_key[size] == '\0')
+				return &tab[i];
+		}
+	}
+	return NULL;
+}
+
 char *auth_cache_parse_key(pool_t pool, const char *query)
 {
+	const struct var_expand_table *tab;
 	string_t *str;
-	char key_seen[256];
-	uint8_t key;
+	bool key_seen[100];
+	unsigned int idx, size, tab_idx;
+	bool add_key;
 
 	memset(key_seen, 0, sizeof(key_seen));
 
 	str = str_new(pool, 32);
-	for (; *query != '\0'; query++) {
-		if (*query == '%' && query[1] != '\0') {
+	for (; *query != '\0'; ) {
+		if (*query != '%') {
 			query++;
-                        key = var_get_key(query);
-			if (key != '\0' && key != '%' && !key_seen[key]) {
-				if (str_len(str) != 0)
-					str_append_c(str, '\t');
-				str_append_c(str, '%');
-				str_append_c(str, key);
+			continue;
+		}
 
-				/* @UNSAFE */
-                                key_seen[key] = 1;
+		var_get_key_range(++query, &idx, &size);
+		if (size == 0) {
+			/* broken %variable ending too early */
+			break;
+		}
+		query += idx;
+
+		tab = auth_request_var_expand_tab_find(query, size);
+		if (tab == NULL) {
+			/* just add the key. it would be nice to prevent
+			   duplicates here as well, but that's just too
+			   much trouble and probably very rare. */
+			add_key = TRUE;
+		} else {
+			tab_idx = tab - auth_request_var_expand_static_tab;
+			i_assert(tab_idx < N_ELEMENTS(key_seen));
+			/* @UNSAFE */
+			add_key = !key_seen[tab_idx];
+			key_seen[tab_idx] = TRUE;
+		}
+		if (add_key) {
+			if (str_len(str) != 0)
+				str_append_c(str, '\t');
+			str_append_c(str, '%');
+			if (size == 1)
+				str_append_c(str, query[0]);
+			else {
+				str_append_c(str, '{');
+				str_append_n(str, query, size);
+				str_append_c(str, '}');
 			}
 		}
+		query += size;
 	}
 	return str_free_without_data(&str);
 }
diff -r 13d4c4f91622 -r a090cbbe3008 src/auth/auth-request.c
--- a/src/auth/auth-request.c	Wed Mar 14 13:42:08 2012 +0200
+++ b/src/auth/auth-request.c	Wed Mar 14 14:55:25 2012 +0200
@@ -1741,38 +1741,40 @@
 	return str_escape(string);
 }
 
+const struct var_expand_table auth_request_var_expand_static_tab[] = {
+	{ 'u', NULL, "user" },
+	{ 'n', NULL, "username" },
+	{ 'd', NULL, "domain" },
+	{ 's', NULL, "service" },
+	{ 'h', NULL, "home" },
+	{ 'l', NULL, "lip" },
+	{ 'r', NULL, "rip" },
+	{ 'p', NULL, "pid" },
+	{ 'w', NULL, "password" },
+	{ '!', NULL, NULL },
+	{ 'm', NULL, "mech" },
+	{ 'c', NULL, "secured" },
+	{ 'a', NULL, "lport" },
+	{ 'b', NULL, "rport" },
+	{ 'k', NULL, "cert" },
+	{ '\0', NULL, "login_user" },
+	{ '\0', NULL, "login_username" },
+	{ '\0', NULL, "login_domain" },
+	{ '\0', NULL, NULL }
+};
+
 const struct var_expand_table *
 auth_request_get_var_expand_table(const struct auth_request *auth_request,
 				  auth_request_escape_func_t *escape_func)
 {
-	static struct var_expand_table static_tab[] = {
-		{ 'u', NULL, "user" },
-		{ 'n', NULL, "username" },
-		{ 'd', NULL, "domain" },
-		{ 's', NULL, "service" },
-		{ 'h', NULL, "home" },
-		{ 'l', NULL, "lip" },
-		{ 'r', NULL, "rip" },
-		{ 'p', NULL, "pid" },
-		{ 'w', NULL, "password" },
-		{ '!', NULL, NULL },
-		{ 'm', NULL, "mech" },
-		{ 'c', NULL, "secured" },
-		{ 'a', NULL, "lport" },
-		{ 'b', NULL, "rport" },
-		{ 'k', NULL, "cert" },
-		{ '\0', NULL, "login_user" },
-		{ '\0', NULL, "login_username" },
-		{ '\0', NULL, "login_domain" },
-		{ '\0', NULL, NULL }
-	};
 	struct var_expand_table *tab;
 
 	if (escape_func == NULL)
 		escape_func = escape_none;
 
-	tab = t_malloc(sizeof(static_tab));
-	memcpy(tab, static_tab, sizeof(static_tab));
+	tab = t_malloc(sizeof(auth_request_var_expand_static_tab));
+	memcpy(tab, auth_request_var_expand_static_tab,
+	       sizeof(auth_request_var_expand_static_tab));
 
 	tab[0].value = escape_func(auth_request->user, auth_request);
 	tab[1].value = escape_func(t_strcut(auth_request->user, '@'),
diff -r 13d4c4f91622 -r a090cbbe3008 src/auth/auth-request.h
--- a/src/auth/auth-request.h	Wed Mar 14 13:42:08 2012 +0200
+++ b/src/auth/auth-request.h	Wed Mar 14 14:55:25 2012 +0200
@@ -2,6 +2,7 @@
 #define AUTH_REQUEST_H
 
 #include "network.h"
+#include "var-expand.h"
 #include "mech.h"
 #include "userdb.h"
 #include "passdb.h"
@@ -122,6 +123,7 @@
 typedef void auth_request_proxy_cb_t(bool success, struct auth_request *);
 
 extern unsigned int auth_request_state_count[AUTH_REQUEST_STATE_MAX];
+extern const struct var_expand_table auth_request_var_expand_static_tab[];
 
 struct auth_request *
 auth_request_new(const struct mech_module *mech);
diff -r 13d4c4f91622 -r a090cbbe3008 src/auth/test-auth-cache.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/auth/test-auth-cache.c	Wed Mar 14 14:55:25 2012 +0200
@@ -0,0 +1,57 @@
+/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "auth-request.h"
+#include "auth-cache.h"
+#include "test-common.h"
+
+const struct var_expand_table auth_request_var_expand_static_tab[] = {
+	{ 'a', NULL, NULL },
+	{ '\0', NULL, "longb" },
+	{ 'c', NULL, "longc" },
+	{ '\0', NULL, NULL }
+};
+
+const struct var_expand_table *
+auth_request_get_var_expand_table(const struct auth_request *auth_request ATTR_UNUSED,
+				  auth_request_escape_func_t *escape_func ATTR_UNUSED)
+{
+	return auth_request_var_expand_static_tab;
+}
+
+static void test_auth_cache_parse_key(void)
+{
+	struct {
+		const char *in, *out;
+	} tests[] = {
+		{ "foo%5.5Mabar", "%a" },
+		{ "foo%5.5M{longb}bar", "%{longb}" },
+		{ "foo%5.5Mcbar", "%c" },
+		{ "foo%5.5M{longc}bar", "%{longc}" },
+		{ "%a%b", "%a\t%b" },
+		{ "%a%{longb}%a", "%a\t%{longb}" },
+		{ "%{longc}%c", "%{longc}" },
+		{ "%c%a%{longc}%c", "%c\t%a" },
+		{ "%a%{env:foo}%{env:foo}%a", "%a\t%{env:foo}\t%{env:foo}" }
+	};
+	const char *cache_key;
+	unsigned int i;
+
+	test_begin("auth cache parse key");
+
+	for (i = 0; i < N_ELEMENTS(tests); i++) {
+		cache_key = auth_cache_parse_key(pool_datastack_create(),
+						 tests[i].in);
+		test_assert(strcmp(cache_key, tests[i].out) == 0);
+	}
+	test_end();
+}
+
+int main(void)
+{
+	static void (*test_functions[])(void) = {
+		test_auth_cache_parse_key,
+		NULL
+	};
+	return test_run(test_functions);
+}


More information about the dovecot-cvs mailing list