summaryrefslogtreecommitdiffstats
path: root/src/auth/userdb-dict.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/auth/userdb-dict.c')
-rw-r--r--src/auth/userdb-dict.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/src/auth/userdb-dict.c b/src/auth/userdb-dict.c
new file mode 100644
index 0000000..51e618e
--- /dev/null
+++ b/src/auth/userdb-dict.c
@@ -0,0 +1,205 @@
+/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
+
+#include "auth-common.h"
+#include "userdb.h"
+
+#include "ioloop.h"
+#include "array.h"
+#include "str.h"
+#include "auth-cache.h"
+#include "db-dict.h"
+
+#include <dict.h>
+
+struct dict_userdb_module {
+ struct userdb_module module;
+
+ struct dict_connection *conn;
+};
+
+struct dict_userdb_iterate_context {
+ struct userdb_iterate_context ctx;
+
+ userdb_callback_t *userdb_callback;
+ const char *key_prefix;
+ size_t key_prefix_len;
+ struct dict_iterate_context *iter;
+};
+
+static int
+dict_query_save_results(struct auth_request *auth_request,
+ struct db_dict_value_iter *iter)
+{
+ const char *key, *value, *error;
+
+ while (db_dict_value_iter_next(iter, &key, &value)) {
+ if (value != NULL)
+ auth_request_set_userdb_field(auth_request, key, value);
+ }
+ if (db_dict_value_iter_deinit(&iter, &error) < 0) {
+ e_error(authdb_event(auth_request), "%s", error);
+ return -1;
+ }
+ return 0;
+}
+
+static void userdb_dict_lookup(struct auth_request *auth_request,
+ userdb_callback_t *callback)
+{
+ struct userdb_module *_module = auth_request->userdb->userdb;
+ struct dict_userdb_module *module =
+ (struct dict_userdb_module *)_module;
+ struct db_dict_value_iter *iter;
+ enum userdb_result userdb_result;
+ int ret;
+
+ if (array_count(&module->conn->set.userdb_fields) == 0 &&
+ array_count(&module->conn->set.parsed_userdb_objects) == 0) {
+ e_error(authdb_event(auth_request),
+ "No userdb_objects or userdb_fields specified");
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
+ return;
+ }
+
+ ret = db_dict_value_iter_init(module->conn, auth_request,
+ &module->conn->set.userdb_fields,
+ &module->conn->set.parsed_userdb_objects,
+ &iter);
+ if (ret < 0)
+ userdb_result = USERDB_RESULT_INTERNAL_FAILURE;
+ else if (ret == 0) {
+ auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB);
+ userdb_result = USERDB_RESULT_USER_UNKNOWN;
+ } else {
+ if (dict_query_save_results(auth_request, iter) < 0)
+ userdb_result = USERDB_RESULT_INTERNAL_FAILURE;
+ else
+ userdb_result = USERDB_RESULT_OK;
+ }
+ callback(userdb_result, auth_request);
+}
+
+static struct userdb_iterate_context *
+userdb_dict_iterate_init(struct auth_request *auth_request,
+ userdb_iter_callback_t *callback, void *context)
+{
+ struct userdb_module *_module = auth_request->userdb->userdb;
+ struct dict_userdb_module *module =
+ (struct dict_userdb_module *)_module;
+ struct dict_userdb_iterate_context *ctx;
+ string_t *path;
+ const char *error;
+
+ ctx = i_new(struct dict_userdb_iterate_context, 1);
+ ctx->ctx.auth_request = auth_request;
+ ctx->ctx.callback = callback;
+ ctx->ctx.context = context;
+ auth_request_ref(auth_request);
+
+ if (*module->conn->set.iterate_prefix == '\0') {
+ if (!module->conn->set.iterate_disable) {
+ e_error(authdb_event(auth_request),
+ "iterate: iterate_prefix not set");
+ ctx->ctx.failed = TRUE;
+ }
+ return &ctx->ctx;
+ }
+
+ path = t_str_new(128);
+ str_append(path, DICT_PATH_SHARED);
+ if (auth_request_var_expand(path, module->conn->set.iterate_prefix,
+ auth_request, NULL, &error) <= 0) {
+ e_error(authdb_event(auth_request),
+ "Failed to expand iterate_prefix=%s: %s",
+ module->conn->set.iterate_prefix, error);
+ ctx->ctx.failed = TRUE;
+ return &ctx->ctx;
+ }
+ ctx->key_prefix = p_strdup(auth_request->pool, str_c(path));
+ ctx->key_prefix_len = strlen(ctx->key_prefix);
+
+ struct dict_op_settings set = {
+ .username = auth_request->fields.user,
+ };
+ ctx->iter = dict_iterate_init(module->conn->dict, &set, ctx->key_prefix, 0);
+ e_debug(authdb_event(auth_request),
+ "iterate: prefix=%s", ctx->key_prefix);
+ return &ctx->ctx;
+}
+
+static const char *
+userdb_dict_get_user(struct dict_userdb_iterate_context *ctx, const char *key)
+{
+ i_assert(strncmp(key, ctx->key_prefix, ctx->key_prefix_len) == 0);
+
+ return key + ctx->key_prefix_len;
+}
+
+static void userdb_dict_iterate_next(struct userdb_iterate_context *_ctx)
+{
+ struct dict_userdb_iterate_context *ctx =
+ (struct dict_userdb_iterate_context *)_ctx;
+ const char *key, *value;
+
+ if (ctx->iter != NULL && dict_iterate(ctx->iter, &key, &value))
+ _ctx->callback(userdb_dict_get_user(ctx, key), _ctx->context);
+ else
+ _ctx->callback(NULL, _ctx->context);
+}
+
+static int userdb_dict_iterate_deinit(struct userdb_iterate_context *_ctx)
+{
+ struct dict_userdb_iterate_context *ctx =
+ (struct dict_userdb_iterate_context *)_ctx;
+ const char *error;
+ int ret = _ctx->failed ? -1 : 0;
+
+ if (dict_iterate_deinit(&ctx->iter, &error) < 0) {
+ e_error(authdb_event(_ctx->auth_request),
+ "dict_iterate(%s) failed: %s",
+ ctx->key_prefix, error);
+ ret = -1;
+ }
+ auth_request_unref(&ctx->ctx.auth_request);
+ i_free(ctx);
+ return ret;
+}
+
+static struct userdb_module *
+userdb_dict_preinit(pool_t pool, const char *args)
+{
+ struct dict_userdb_module *module;
+ struct dict_connection *conn;
+
+ module = p_new(pool, struct dict_userdb_module, 1);
+ module->conn = conn = db_dict_init(args);
+
+ module->module.blocking = TRUE;
+ module->module.default_cache_key = auth_cache_parse_key(pool,
+ db_dict_parse_cache_key(&conn->set.keys, &conn->set.userdb_fields,
+ &conn->set.parsed_userdb_objects));
+ return &module->module;
+}
+
+static void userdb_dict_deinit(struct userdb_module *_module)
+{
+ struct dict_userdb_module *module =
+ (struct dict_userdb_module *)_module;
+
+ db_dict_unref(&module->conn);
+}
+
+struct userdb_module_interface userdb_dict =
+{
+ "dict",
+
+ userdb_dict_preinit,
+ NULL,
+ userdb_dict_deinit,
+
+ userdb_dict_lookup,
+
+ userdb_dict_iterate_init,
+ userdb_dict_iterate_next,
+ userdb_dict_iterate_deinit
+};