bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen#include "auth-common.h"
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen#include "userdb.h"
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen#include "ioloop.h"
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen#include "array.h"
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen#include "str.h"
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen#include "auth-cache.h"
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen#include "db-dict.h"
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen#include <dict.h>
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstruct dict_userdb_module {
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct userdb_module module;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct dict_connection *conn;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen};
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstruct dict_userdb_iterate_context {
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct userdb_iterate_context ctx;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_callback_t *userdb_callback;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen const char *key_prefix;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t key_prefix_len;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct dict_iterate_context *iter;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen};
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstatic int
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainendict_query_save_results(struct auth_request *auth_request,
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen struct db_dict_value_iter *iter)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen{
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen const char *key, *value, *error;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen while (db_dict_value_iter_next(iter, &key, &value)) {
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen if (value != NULL)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen auth_request_set_userdb_field(auth_request, key, value);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen }
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen if (db_dict_value_iter_deinit(&iter, &error) < 0) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(auth_request, AUTH_SUBSYS_DB, "%s", error);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen return -1;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen }
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen return 0;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen}
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstatic void userdb_dict_lookup(struct auth_request *auth_request,
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_callback_t *callback)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen{
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct userdb_module *_module = auth_request->userdb->userdb;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct dict_userdb_module *module =
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen (struct dict_userdb_module *)_module;
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen struct db_dict_value_iter *iter;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen enum userdb_result userdb_result;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen int ret;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen if (array_count(&module->conn->set.userdb_fields) == 0 &&
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen array_count(&module->conn->set.parsed_userdb_objects) == 0) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen "No userdb_objects or userdb_fields specified");
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen return;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen }
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen ret = db_dict_value_iter_init(module->conn, auth_request,
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen &module->conn->set.userdb_fields,
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen &module->conn->set.parsed_userdb_objects,
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen &iter);
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen if (ret < 0)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_result = USERDB_RESULT_INTERNAL_FAILURE;
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen else if (ret == 0) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_result = USERDB_RESULT_USER_UNKNOWN;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen } else {
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen if (dict_query_save_results(auth_request, iter) < 0)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_result = USERDB_RESULT_INTERNAL_FAILURE;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen else
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_result = USERDB_RESULT_OK;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen }
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen callback(userdb_result, auth_request);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen}
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstatic struct userdb_iterate_context *
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenuserdb_dict_iterate_init(struct auth_request *auth_request,
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_iter_callback_t *callback, void *context)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen{
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct userdb_module *_module = auth_request->userdb->userdb;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct dict_userdb_module *module =
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen (struct dict_userdb_module *)_module;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct dict_userdb_iterate_context *ctx;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen string_t *path;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char *error;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen ctx = i_new(struct dict_userdb_iterate_context, 1);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen ctx->ctx.auth_request = auth_request;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen ctx->ctx.callback = callback;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen ctx->ctx.context = context;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen auth_request_ref(auth_request);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen if (*module->conn->set.iterate_prefix == '\0') {
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen if (!module->conn->set.iterate_disable) {
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen "iterate: iterate_prefix not set");
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen ctx->ctx.failed = TRUE;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen }
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen return &ctx->ctx;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen }
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen path = t_str_new(128);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen str_append(path, DICT_PATH_SHARED);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (auth_request_var_expand(path, module->conn->set.iterate_prefix,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen auth_request, NULL, &error) <= 0) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen "Failed to expand iterate_prefix=%s: %s",
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen module->conn->set.iterate_prefix, error);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen ctx->ctx.failed = TRUE;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return &ctx->ctx;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen ctx->key_prefix = p_strdup(auth_request->pool, str_c(path));
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen ctx->key_prefix_len = strlen(ctx->key_prefix);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen ctx->iter = dict_iterate_init(module->conn->dict, ctx->key_prefix, 0);
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen auth_request_log_debug(auth_request, AUTH_SUBSYS_DB,
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen "iterate: prefix=%s", ctx->key_prefix);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen return &ctx->ctx;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen}
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstatic const char *
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenuserdb_dict_get_user(struct dict_userdb_iterate_context *ctx, const char *key)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen{
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen i_assert(strncmp(key, ctx->key_prefix, ctx->key_prefix_len) == 0);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen return key + ctx->key_prefix_len;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen}
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstatic void userdb_dict_iterate_next(struct userdb_iterate_context *_ctx)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen{
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct dict_userdb_iterate_context *ctx =
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen (struct dict_userdb_iterate_context *)_ctx;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen const char *key, *value;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen if (ctx->iter != NULL && dict_iterate(ctx->iter, &key, &value))
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen _ctx->callback(userdb_dict_get_user(ctx, key), _ctx->context);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen else
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen _ctx->callback(NULL, _ctx->context);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen}
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstatic int userdb_dict_iterate_deinit(struct userdb_iterate_context *_ctx)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen{
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct dict_userdb_iterate_context *ctx =
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen (struct dict_userdb_iterate_context *)_ctx;
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen const char *error;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen int ret = _ctx->failed ? -1 : 0;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen if (ctx->iter != NULL) {
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen if (dict_iterate_deinit(&ctx->iter, &error) < 0) {
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen i_error("dict_iterate(%s) failed: %s",
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen ctx->key_prefix, error);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen ret = -1;
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen }
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen }
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen auth_request_unref(&ctx->ctx.auth_request);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen i_free(ctx);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen return ret;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen}
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstatic struct userdb_module *
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenuserdb_dict_preinit(pool_t pool, const char *args)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen{
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct dict_userdb_module *module;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct dict_connection *conn;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen module = p_new(pool, struct dict_userdb_module, 1);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen module->conn = conn = db_dict_init(args);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen module->module.blocking = TRUE;
74674a53a72dab535c61f455b2246ef2797844eaTimo Sirainen module->module.default_cache_key = auth_cache_parse_key(pool,
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen db_dict_parse_cache_key(&conn->set.keys, &conn->set.userdb_fields,
79042f8c2ec1778528584c064b164d1ebcdde16bTimo Sirainen &conn->set.parsed_userdb_objects));
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen return &module->module;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen}
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstatic void userdb_dict_deinit(struct userdb_module *_module)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen{
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen struct dict_userdb_module *module =
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen (struct dict_userdb_module *)_module;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen db_dict_unref(&module->conn);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen}
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainenstruct userdb_module_interface userdb_dict =
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen{
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen "dict",
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_dict_preinit,
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen NULL,
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_dict_deinit,
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_dict_lookup,
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_dict_iterate_init,
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_dict_iterate_next,
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen userdb_dict_iterate_deinit
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen};