userdb-dict.c revision 79042f8c2ec1778528584c064b164d1ebcdde16b
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "auth-common.h"
e7ca5f820d6a1a8fe549a2966ac707a60e055ef4Timo Sirainen#include "userdb.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "ioloop.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "array.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "str.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "var-expand.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "auth-cache.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "db-dict.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include <dict.h>
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include <stdlib.h>
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct dict_userdb_module {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct userdb_module module;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct dict_connection *conn;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen};
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct dict_userdb_iterate_context {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct userdb_iterate_context ctx;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen userdb_callback_t *userdb_callback;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen const char *key_prefix;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int key_prefix_len;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct dict_iterate_context *iter;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen};
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic int
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainendict_query_save_results(struct auth_request *auth_request,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct db_dict_value_iter *iter)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen const char *key, *value, *error;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen auth_request_init_userdb_reply(auth_request);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen while (db_dict_value_iter_next(iter, &key, &value)) {
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen if (value != NULL)
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen auth_request_set_userdb_field(auth_request, key, value);
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (db_dict_value_iter_deinit(&iter, &error) < 0) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen auth_request_log_error(auth_request, "dict", "%s", error);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return -1;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return 0;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic void userdb_dict_lookup(struct auth_request *auth_request,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen userdb_callback_t *callback)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct userdb_module *_module = auth_request->userdb->userdb;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct dict_userdb_module *module =
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen (struct dict_userdb_module *)_module;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct db_dict_value_iter *iter;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen enum userdb_result userdb_result;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen int ret;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (array_count(&module->conn->set.userdb_fields) == 0 &&
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen array_count(&module->conn->set.parsed_userdb_objects) == 0) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen auth_request_log_error(auth_request, "dict",
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen "No userdb_objects or userdb_fields specified");
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ret = db_dict_value_iter_init(module->conn, auth_request,
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen &module->conn->set.userdb_fields,
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen &module->conn->set.parsed_userdb_objects,
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen &iter);
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen if (ret < 0)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen userdb_result = USERDB_RESULT_INTERNAL_FAILURE;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen else if (ret == 0) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen auth_request_log_unknown_user(auth_request, "dict");
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen userdb_result = USERDB_RESULT_USER_UNKNOWN;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen } else {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (dict_query_save_results(auth_request, iter) < 0)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen userdb_result = USERDB_RESULT_INTERNAL_FAILURE;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen else
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen userdb_result = USERDB_RESULT_OK;
e7ca5f820d6a1a8fe549a2966ac707a60e055ef4Timo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen callback(userdb_result, auth_request);
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen}
e622f05170aecc10e71f117d4d7baf55c5d12b77Timo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic struct userdb_iterate_context *
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenuserdb_dict_iterate_init(struct auth_request *auth_request,
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen userdb_iter_callback_t *callback, void *context)
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct userdb_module *_module = auth_request->userdb->userdb;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct dict_userdb_module *module =
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen (struct dict_userdb_module *)_module;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct dict_userdb_iterate_context *ctx;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen const struct var_expand_table *vars;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen string_t *path;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ctx = i_new(struct dict_userdb_iterate_context, 1);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ctx->ctx.auth_request = auth_request;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ctx->ctx.callback = callback;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen ctx->ctx.context = context;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen auth_request_ref(auth_request);
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen if (*module->conn->set.iterate_prefix == '\0') {
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen if (!module->conn->set.iterate_disable) {
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen auth_request_log_error(auth_request, "dict",
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen "iterate: iterate_prefix not set");
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen ctx->ctx.failed = TRUE;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
e7ca5f820d6a1a8fe549a2966ac707a60e055ef4Timo Sirainen return &ctx->ctx;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen path = t_str_new(128);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen str_append(path, DICT_PATH_SHARED);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen vars = auth_request_get_var_expand_table(auth_request, NULL);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen var_expand(path, module->conn->set.iterate_prefix, vars);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ctx->key_prefix = p_strdup(auth_request->pool, str_c(path));
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ctx->key_prefix_len = strlen(ctx->key_prefix);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ctx->iter = dict_iterate_init(module->conn->dict, ctx->key_prefix, 0);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen auth_request_log_debug(auth_request, "dict", "iterate: prefix=%s",
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ctx->key_prefix);
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen return &ctx->ctx;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic const char *
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenuserdb_dict_get_user(struct dict_userdb_iterate_context *ctx, const char *key)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
1b21ddb1b3f7f916627db312046bcded07627ee8Timo Sirainen i_assert(strncmp(key, ctx->key_prefix, ctx->key_prefix_len) == 0);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen 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;
int ret = _ctx->failed ? -1 : 0;
if (ctx->iter != NULL) {
if (dict_iterate_deinit(&ctx->iter) < 0)
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.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
};