userdb-dict.c revision cd75c360f244c96b9ee10e01ee3a66fad13183c8
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include "auth-common.h"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include "userdb.h"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include "ioloop.h"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include "array.h"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include "str.h"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include "var-expand.h"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include "auth-cache.h"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include "db-dict.h"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include <dict.h>
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk#include <stdlib.h>
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenkstruct dict_userdb_module {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct userdb_module module;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk struct dict_connection *conn;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk};
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstruct dict_userdb_iterate_context {
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk struct userdb_iterate_context ctx;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_callback_t *userdb_callback;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk const char *key_prefix;
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk unsigned int key_prefix_len;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct dict_iterate_context *iter;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk};
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenkstatic int
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdict_query_save_results(struct auth_request *auth_request,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct db_dict_value_iter *iter)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk const char *key, *value, *error;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk while (db_dict_value_iter_next(iter, &key, &value)) {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (value != NULL)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk auth_request_set_userdb_field(auth_request, key, value);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (db_dict_value_iter_deinit(&iter, &error) < 0) {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk auth_request_log_error(auth_request, "dict", "%s", error);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return -1;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenkstatic void userdb_dict_lookup(struct auth_request *auth_request,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_callback_t *callback)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct userdb_module *_module = auth_request->userdb->userdb;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct dict_userdb_module *module =
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk (struct dict_userdb_module *)_module;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct db_dict_value_iter *iter;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk enum userdb_result userdb_result;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk int ret;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk if (array_count(&module->conn->set.userdb_fields) == 0 &&
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk array_count(&module->conn->set.parsed_userdb_objects) == 0) {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk auth_request_log_error(auth_request, "dict",
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "No userdb_objects or userdb_fields specified");
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ret = db_dict_value_iter_init(module->conn, auth_request,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk &module->conn->set.userdb_fields,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk &module->conn->set.parsed_userdb_objects,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk &iter);
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk if (ret < 0)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_result = USERDB_RESULT_INTERNAL_FAILURE;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk else if (ret == 0) {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk auth_request_log_unknown_user(auth_request, "dict");
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_result = USERDB_RESULT_USER_UNKNOWN;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk } else {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (dict_query_save_results(auth_request, iter) < 0)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_result = USERDB_RESULT_INTERNAL_FAILURE;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk else
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_result = USERDB_RESULT_OK;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk callback(userdb_result, auth_request);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstatic struct userdb_iterate_context *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkuserdb_dict_iterate_init(struct auth_request *auth_request,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_iter_callback_t *callback, void *context)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct userdb_module *_module = auth_request->userdb->userdb;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct dict_userdb_module *module =
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk (struct dict_userdb_module *)_module;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct dict_userdb_iterate_context *ctx;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk const struct var_expand_table *vars;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk string_t *path;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ctx = i_new(struct dict_userdb_iterate_context, 1);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ctx->ctx.auth_request = auth_request;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ctx->ctx.callback = callback;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ctx->ctx.context = context;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk auth_request_ref(auth_request);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (*module->conn->set.iterate_prefix == '\0') {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (!module->conn->set.iterate_disable) {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk auth_request_log_error(auth_request, "dict",
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "iterate: iterate_prefix not set");
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ctx->ctx.failed = TRUE;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return &ctx->ctx;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk path = t_str_new(128);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk str_append(path, DICT_PATH_SHARED);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk vars = auth_request_get_var_expand_table(auth_request, NULL);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk var_expand(path, module->conn->set.iterate_prefix, vars);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ctx->key_prefix = p_strdup(auth_request->pool, str_c(path));
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ctx->key_prefix_len = strlen(ctx->key_prefix);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ctx->iter = dict_iterate_init(module->conn->dict, ctx->key_prefix, 0);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk auth_request_log_debug(auth_request, "dict", "iterate: prefix=%s",
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ctx->key_prefix);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return &ctx->ctx;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenkstatic const char *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkuserdb_dict_get_user(struct dict_userdb_iterate_context *ctx, const char *key)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk i_assert(strncmp(key, ctx->key_prefix, ctx->key_prefix_len) == 0);
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return key + ctx->key_prefix_len;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstatic void userdb_dict_iterate_next(struct userdb_iterate_context *_ctx)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct dict_userdb_iterate_context *ctx =
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk (struct dict_userdb_iterate_context *)_ctx;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk const char *key, *value;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (ctx->iter != NULL && dict_iterate(ctx->iter, &key, &value))
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk _ctx->callback(userdb_dict_get_user(ctx, key), _ctx->context);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk else
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk _ctx->callback(NULL, _ctx->context);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstatic int userdb_dict_iterate_deinit(struct userdb_iterate_context *_ctx)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct dict_userdb_iterate_context *ctx =
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk (struct dict_userdb_iterate_context *)_ctx;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk int ret = _ctx->failed ? -1 : 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (ctx->iter != NULL) {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (dict_iterate_deinit(&ctx->iter) < 0)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ret = -1;
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk auth_request_unref(&ctx->ctx.auth_request);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk i_free(ctx);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return ret;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstatic struct userdb_module *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkuserdb_dict_preinit(pool_t pool, const char *args)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct dict_userdb_module *module;
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk struct dict_connection *conn;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk module = p_new(pool, struct dict_userdb_module, 1);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk module->conn = conn = db_dict_init(args);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk module->module.blocking = TRUE;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk module->module.cache_key = auth_cache_parse_key(pool,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk db_dict_parse_cache_key(&conn->set.keys, &conn->set.userdb_fields,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk &conn->set.parsed_userdb_objects));
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return &module->module;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstatic void userdb_dict_deinit(struct userdb_module *_module)
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk struct dict_userdb_module *module =
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk (struct dict_userdb_module *)_module;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk db_dict_unref(&module->conn);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstruct userdb_module_interface userdb_dict =
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "dict",
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_dict_preinit,
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk NULL,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_dict_deinit,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_dict_lookup,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_dict_iterate_init,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_dict_iterate_next,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk userdb_dict_iterate_deinit
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk};
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk