dovecot-2.2: auth: passdb/userdb dict rewrite to support more co...

dovecot at dovecot.org dovecot at dovecot.org
Sun Dec 8 19:01:09 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/d2ad697ba810
changeset: 17040:d2ad697ba810
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Dec 08 19:00:31 2013 +0200
description:
auth: passdb/userdb dict rewrite to support more complex configuration.
See the new doc/example-config/dovecot-dict-auth.conf.ext for explanation
how it works. The old configuration format will also stay functional.

diffstat:

 doc/example-config/dovecot-dict-auth.conf.ext |   56 ++-
 src/auth/Makefile.am                          |    8 +-
 src/auth/db-dict-cache-key.c                  |   65 +++
 src/auth/db-dict.c                            |  526 +++++++++++++++++++++++--
 src/auth/db-dict.h                            |   57 ++-
 src/auth/passdb-dict.c                        |   49 +-
 src/auth/test-db-dict.c                       |   51 ++
 src/auth/userdb-dict.c                        |   42 +-
 8 files changed, 731 insertions(+), 123 deletions(-)

diffs (truncated from 1134 to 300 lines):

diff -r 342f6962390e -r d2ad697ba810 doc/example-config/dovecot-dict-auth.conf.ext
--- a/doc/example-config/dovecot-dict-auth.conf.ext	Tue Dec 03 21:31:59 2013 +0200
+++ b/doc/example-config/dovecot-dict-auth.conf.ext	Sun Dec 08 19:00:31 2013 +0200
@@ -1,24 +1,54 @@
-# This file is commonly accessed via dict {} section in dovecot.conf
+# This file is commonly accessed via passdb {} or userdb {} section in
+# conf.d/auth-dict.conf.ext
 
 # Dictionary URI
 #uri = 
 
-# Key for passdb lookups
-password_key = dovecot/passdb/%u
-
-# Key for userdb lookups
-user_key = dovecot/userdb/%u
-
-# How to parse the value for key=value pairs. Currently we support only JSON
-# format with { "key": "value", ... } object.
-#value_format = json
+# Default password scheme
+default_pass_scheme = MD5
 
 # Username iteration prefix. Keys under this are assumed to contain usernames.
-iterate_prefix = dovecot/userdb/
+iterate_prefix = userdb/
 
 # Should iteration be disabled for this userdb? If this userdb acts only as a
 # cache there's no reason to try to iterate the (partial & duplicate) users.
 #iterate_disable = no
 
-# Default password scheme
-default_pass_scheme = MD5
+# The example here shows how to do multiple dict lookups and merge the replies.
+# The "passdb" and "userdb" keys are JSON objects containing key/value pairs,
+# for example: { "uid": 1000, "gid": 1000, "home": "/home/user" }
+
+key passdb {
+  key = passdb/%u
+  format = json
+}
+key userdb {
+  key = userdb/%u
+  format = json
+}
+key quota {
+  key = userdb/%u/quota
+  #format = value
+  # The default_value is used if the key isn't found. If default_value setting
+  # isn't specified at all (even as empty), the passdb/userdb lookup fails with
+  # "user doesn't exist".
+  default_value = 100M
+}
+
+# Space separated list of keys whose values contain key/value paired objects.
+# All the key/value pairs inside the object are added as passdb fields.
+passdb_objects = passdb
+
+#passdb_fields {
+#}
+
+# Userdb key/value object list.
+userdb_objects = userdb
+
+userdb_fields {
+  # dict:<key> refers to key names
+  quota_rule = *:storage=%{dict:quota}
+
+  # dict:<key>.<objkey> refers to the objkey inside (JSON) object
+  mail = maildir:%{dict:userdb.home}/Maildir
+}
diff -r 342f6962390e -r d2ad697ba810 src/auth/Makefile.am
--- a/src/auth/Makefile.am	Tue Dec 03 21:31:59 2013 +0200
+++ b/src/auth/Makefile.am	Sun Dec 08 19:00:31 2013 +0200
@@ -77,6 +77,7 @@
 	auth-worker-server.c \
 	db-checkpassword.c \
 	db-dict.c \
+	db-dict-cache-key.c \
 	db-sql.c \
 	db-passwd-file.c \
 	main.c \
@@ -193,7 +194,8 @@
 	checkpassword-reply.c
 
 test_programs = \
-	test-auth-cache
+	test-auth-cache \
+	test-db-dict
 
 noinst_PROGRAMS = $(test_programs)
 
@@ -205,6 +207,10 @@
 test_auth_cache_LDADD = auth-cache.o $(test_libs)
 test_auth_cache_DEPENDENCIES = $(pkglibexec_PROGRAMS) $(test_libs)
 
+test_db_dict_SOURCES = test-db-dict.c
+test_db_dict_LDADD = db-dict-cache-key.o $(test_libs)
+test_db_dict_DEPENDENCIES = $(pkglibexec_PROGRAMS) $(test_libs)
+
 check: check-am check-test
 check-test: all-am
 	for bin in $(test_programs); do \
diff -r 342f6962390e -r d2ad697ba810 src/auth/db-dict-cache-key.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/auth/db-dict-cache-key.c	Sun Dec 08 19:00:31 2013 +0200
@@ -0,0 +1,65 @@
+/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
+
+#include "auth-common.h"
+#include "array.h"
+#include "str.h"
+#include "var-expand.h"
+#include "db-dict.h"
+
+const struct db_dict_key *
+db_dict_set_key_find(const ARRAY_TYPE(db_dict_key) *keys, const char *name)
+{
+	const struct db_dict_key *key;
+
+	array_foreach(keys, key) {
+		if (strcmp(key->name, name) == 0)
+			return key;
+	}
+	return NULL;
+}
+
+
+const char *
+db_dict_parse_cache_key(const ARRAY_TYPE(db_dict_key) *keys,
+			const ARRAY_TYPE(db_dict_field) *fields,
+			const ARRAY_TYPE(db_dict_key_p) *objects)
+{
+	const struct db_dict_field *field;
+	const struct db_dict_key *key;
+	const struct db_dict_key *const *keyp;
+	const char *p, *name;
+	unsigned int idx, size;
+	string_t *str = t_str_new(128);
+
+	array_foreach(fields, field) {
+		for (p = field->value; *p != '\0'; ) {
+			if (*p != '%') {
+				p++;
+				continue;
+			}
+
+			var_get_key_range(++p, &idx, &size);
+			if (size == 0) {
+				/* broken %variable ending too early */
+				break;
+			}
+			p += idx;
+			if (size > 5 && memcmp(p, "dict:", 5) == 0) {
+				name = t_strcut(t_strndup(p+5, size-5), ':');
+				key = db_dict_set_key_find(keys, name);
+				if (key != NULL)
+					str_printfa(str, "\t%s", key->key);
+			} else if (size == 1) {
+				str_printfa(str, "\t%%%c", p[0]);
+			} else {
+				str_append(str, "\t%{");
+				str_append_n(str, p, size);
+				str_append_c(str, '}');
+			}
+			p += size;
+		}
+	}
+	array_foreach(objects, keyp)
+		str_printfa(str, "\t%s", (*keyp)->key);
+	return str_c(str);
+}
diff -r 342f6962390e -r d2ad697ba810 src/auth/db-dict.c
--- a/src/auth/db-dict.c	Tue Dec 03 21:31:59 2013 +0200
+++ b/src/auth/db-dict.c	Sun Dec 08 19:00:31 2013 +0200
@@ -2,11 +2,12 @@
 
 #include "auth-common.h"
 
+#include "array.h"
+#include "istream.h"
+#include "str.h"
+#include "json-parser.h"
 #include "settings.h"
 #include "dict.h"
-#include "json-parser.h"
-#include "istream.h"
-#include "str.h"
 #include "auth-request.h"
 #include "auth-worker-client.h"
 #include "db-dict.h"
@@ -14,29 +15,80 @@
 #include <stddef.h>
 #include <stdlib.h>
 
+enum dict_settings_section {
+	DICT_SETTINGS_SECTION_ROOT = 0,
+	DICT_SETTINGS_SECTION_KEY,
+	DICT_SETTINGS_SECTION_PASSDB,
+	DICT_SETTINGS_SECTION_USERDB
+};
+
+struct dict_settings_parser_ctx {
+	struct dict_connection *conn;
+	enum dict_settings_section section;
+	struct db_dict_key *cur_key;
+};
+
+struct db_dict_iter_key {
+	const struct db_dict_key *key;
+	bool used;
+	const char *value;
+};
+
+struct db_dict_value_iter {
+	pool_t pool;
+	struct auth_request *auth_request;
+	struct dict_connection *conn;
+	const struct var_expand_table *var_expand_table;
+	ARRAY(struct db_dict_iter_key) keys;
+
+	const ARRAY_TYPE(db_dict_field) *fields;
+	const ARRAY_TYPE(db_dict_key_p) *objects;
+	unsigned int field_idx;
+	unsigned int object_idx;
+
+	struct json_parser *json_parser;
+	string_t *tmpstr;
+	const char *error;
+};
+
 #define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_settings)
 #define DEF_BOOL(name) DEF_STRUCT_BOOL(name, db_dict_settings)
-
 static struct setting_def setting_defs[] = {
 	DEF_STR(uri),
-	DEF_STR(password_key),
-	DEF_STR(user_key),
+	DEF_STR(default_pass_scheme),
  	DEF_STR(iterate_prefix),
- 	DEF_STR(value_format),
  	DEF_BOOL(iterate_disable),
-	DEF_STR(default_pass_scheme),
 
+ 	DEF_STR(passdb_objects),
+ 	DEF_STR(userdb_objects),
 	{ 0, NULL, 0 }
 };
 
 static struct db_dict_settings default_dict_settings = {
 	.uri = NULL,
-	.password_key = "",
-	.user_key = "",
+	.default_pass_scheme = "MD5",
 	.iterate_prefix = "",
 	.iterate_disable = FALSE,
-	.value_format = "json",
-	.default_pass_scheme = "MD5"
+	.passdb_objects = "",
+	.userdb_objects = ""
+};
+
+#undef DEF_STR
+#define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_key)
+static struct setting_def key_setting_defs[] = {
+	DEF_STR(name),
+	DEF_STR(key),
+	DEF_STR(format),
+ 	DEF_STR(default_value),
+
+	{ 0, NULL, 0 }
+};
+
+static struct db_dict_key default_key_settings = {
+	.name = NULL,
+	.key = "",
+	.format = "value",
+	.default_value = NULL
 };
 
 static struct dict_connection *connections = NULL;
@@ -53,15 +105,167 @@
 	return NULL;
 }
 
+static bool
+parse_obsolete_setting(const char *key, const char *value,
+		       struct dict_settings_parser_ctx *ctx,
+		       const char **error_r)
+{
+	const struct db_dict_key *dbkey;
+
+	if (strcmp(key, "password_key") == 0) {
+		/* key passdb { key=<value> format=json }
+		   passdb_objects = passdb */
+		ctx->cur_key = array_append_space(&ctx->conn->set.keys);
+		*ctx->cur_key = default_key_settings;
+		ctx->cur_key->name = "passdb";
+		ctx->cur_key->format = "json";
+		ctx->cur_key->parsed_format = DB_DICT_VALUE_FORMAT_JSON;


More information about the dovecot-cvs mailing list