db-dict.c revision a3783f8a3c9cd816b51e77a922f82301512fcf22
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2013-2016 Dovecot authors, see the included COPYING file */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "auth-common.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "array.h"
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen#include "istream.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "str.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "json-parser.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "settings.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "dict.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "auth-request.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "auth-worker-client.h"
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen#include "db-dict.h"
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen#include <stddef.h>
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenenum dict_settings_section {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen DICT_SETTINGS_SECTION_ROOT = 0,
daa7e7459749ae8f82cd3eed9c44522d81c609a3Timo Sirainen DICT_SETTINGS_SECTION_KEY,
46ec5983bf4519ea42dbfcae3d7c62be0d8ef95fTimo Sirainen DICT_SETTINGS_SECTION_PASSDB,
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen DICT_SETTINGS_SECTION_USERDB
6523f54d1521edf894880f2d45e75cef5dd31c3dTimo Sirainen};
72f5f2c5c6905b5d3f389b424313e2c450dfad96Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstruct dict_settings_parser_ctx {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct dict_connection *conn;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen enum dict_settings_section section;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct db_dict_key *cur_key;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen};
373492be949e159fda651807b3acda2c5c077027Timo Sirainen
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainenstruct db_dict_iter_key {
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch const struct db_dict_key *key;
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch bool used;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen const char *value;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen};
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstruct db_dict_value_iter {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen pool_t pool;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct auth_request *auth_request;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct dict_connection *conn;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const struct var_expand_table *var_expand_table;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen ARRAY(struct db_dict_iter_key) keys;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const ARRAY_TYPE(db_dict_field) *fields;
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen const ARRAY_TYPE(db_dict_key_p) *objects;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen unsigned int field_idx;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen unsigned int object_idx;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct json_parser *json_parser;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen string_t *tmpstr;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const char *error;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen};
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen#define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_settings)
51fb710488efa419a2964335c30451c62b9633b1Timo Sirainen#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, db_dict_settings)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic struct setting_def setting_defs[] = {
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen DEF_STR(uri),
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainen DEF_STR(default_pass_scheme),
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen DEF_STR(iterate_prefix),
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen DEF_BOOL(iterate_disable),
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen DEF_STR(passdb_objects),
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen DEF_STR(userdb_objects),
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen { 0, NULL, 0 }
35fcdde46a71ac151c2518d48c841019f1181bb2Timo Sirainen};
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic struct db_dict_settings default_dict_settings = {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen .uri = NULL,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen .default_pass_scheme = "MD5",
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen .iterate_prefix = "",
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen .iterate_disable = FALSE,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen .passdb_objects = "",
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen .userdb_objects = ""
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen};
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#undef DEF_STR
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_key)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic struct setting_def key_setting_defs[] = {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen DEF_STR(name),
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen DEF_STR(key),
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen DEF_STR(format),
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen DEF_STR(default_value),
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen { 0, NULL, 0 }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen};
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic struct db_dict_key default_key_settings = {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .name = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .key = "",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .format = "value",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .default_value = NULL
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen};
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic struct dict_connection *connections = NULL;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
ba8498efbf886ca8b69fdb20c0ba2f5dba9416e3Timo Sirainenstatic struct dict_connection *dict_conn_find(const char *config_path)
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen{
f7f25f9e1a38678d0e97d2e609beac16285fac6bTimo Sirainen struct dict_connection *conn;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen for (conn = connections; conn != NULL; conn = conn->next) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (strcmp(conn->config_path, config_path) == 0)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return conn;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen return NULL;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic bool
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenparse_obsolete_setting(const char *key, const char *value,
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen struct dict_settings_parser_ctx *ctx,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char **error_r)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen const struct db_dict_key *dbkey;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen if (strcmp(key, "password_key") == 0) {
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen /* key passdb { key=<value> format=json }
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen passdb_objects = passdb */
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen ctx->cur_key = array_append_space(&ctx->conn->set.keys);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *ctx->cur_key = default_key_settings;
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen ctx->cur_key->name = "passdb";
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen ctx->cur_key->format = "json";
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->cur_key->parsed_format = DB_DICT_VALUE_FORMAT_JSON;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->cur_key->key = p_strdup(ctx->conn->pool, value);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen dbkey = ctx->cur_key;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen array_append(&ctx->conn->set.parsed_passdb_objects, &dbkey, 1);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen return TRUE;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen }
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen if (strcmp(key, "user_key") == 0) {
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen /* key userdb { key=<value> format=json }
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen userdb_objects = userdb */
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen ctx->cur_key = array_append_space(&ctx->conn->set.keys);
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen *ctx->cur_key = default_key_settings;
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen ctx->cur_key->name = "userdb";
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen ctx->cur_key->format = "json";
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen ctx->cur_key->parsed_format = DB_DICT_VALUE_FORMAT_JSON;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen ctx->cur_key->key = p_strdup(ctx->conn->pool, value);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen dbkey = ctx->cur_key;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen array_append(&ctx->conn->set.parsed_userdb_objects, &dbkey, 1);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return TRUE;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (strcmp(key, "value_format") == 0) {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (strcmp(value, "json") == 0)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *error_r = "Deprecated value_format must be 'json'";
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return FALSE;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen }
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen return FALSE;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic const char *parse_setting(const char *key, const char *value,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct dict_settings_parser_ctx *ctx)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct db_dict_field *field;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *error = NULL;
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen switch (ctx->section) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen case DICT_SETTINGS_SECTION_ROOT:
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen if (parse_obsolete_setting(key, value, ctx, &error))
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen return NULL;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (error != NULL)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return error;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return parse_setting_from_defs(ctx->conn->pool, setting_defs,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen &ctx->conn->set, key, value);
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen case DICT_SETTINGS_SECTION_KEY:
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen return parse_setting_from_defs(ctx->conn->pool, key_setting_defs,
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen ctx->cur_key, key, value);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen case DICT_SETTINGS_SECTION_PASSDB:
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen field = array_append_space(&ctx->conn->set.passdb_fields);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen field->name = p_strdup(ctx->conn->pool, key);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen field->value = p_strdup(ctx->conn->pool, value);
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen return NULL;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen case DICT_SETTINGS_SECTION_USERDB:
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen field = array_append_space(&ctx->conn->set.userdb_fields);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen field->name = p_strdup(ctx->conn->pool, key);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen field->value = p_strdup(ctx->conn->pool, value);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return NULL;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen return t_strconcat("Unknown setting: ", key, NULL);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen}
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainenstatic bool parse_section(const char *type, const char *name,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct dict_settings_parser_ctx *ctx,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char **errormsg)
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (type == NULL) {
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen ctx->section = DICT_SETTINGS_SECTION_ROOT;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (ctx->cur_key != NULL) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (strcmp(ctx->cur_key->format, "value") == 0) {
57d2429fae575e96ca276355af675deb66b76d00Timo Sirainen ctx->cur_key->parsed_format =
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen DB_DICT_VALUE_FORMAT_VALUE;
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen } else if (strcmp(ctx->cur_key->format, "json") == 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->cur_key->parsed_format =
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen DB_DICT_VALUE_FORMAT_JSON;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen } else {
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen *errormsg = t_strconcat("Unknown key format: ",
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->cur_key->format, NULL);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return FALSE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen }
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen ctx->cur_key = NULL;
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen return TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (ctx->section != DICT_SETTINGS_SECTION_ROOT) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *errormsg = "Nested sections not supported";
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return FALSE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (strcmp(type, "key") == 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (name == NULL) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *errormsg = "Key section is missing name";
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen return FALSE;
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (strchr(name, '.') != NULL) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *errormsg = "Key section names must not contain '.'";
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return FALSE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
c6f894e1522f7b0b6068c228900914073c145175Timo Sirainen ctx->section = DICT_SETTINGS_SECTION_KEY;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->cur_key = array_append_space(&ctx->conn->set.keys);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen *ctx->cur_key = default_key_settings;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->cur_key->name = p_strdup(ctx->conn->pool, name);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (strcmp(type, "passdb_fields") == 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->section = DICT_SETTINGS_SECTION_PASSDB;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen if (strcmp(type, "userdb_fields") == 0) {
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen ctx->section = DICT_SETTINGS_SECTION_USERDB;
f01eb1f51d618633c0189be9ab60a774f47fb7dfTimo Sirainen return TRUE;
f01eb1f51d618633c0189be9ab60a774f47fb7dfTimo Sirainen }
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen *errormsg = "Unknown section";
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return FALSE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainenstatic void
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainendb_dict_settings_parse(struct db_dict_settings *set)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const struct db_dict_key *key;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const char *const *tmp;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
f2df3069766c747cbf020fea5d3a4261949064b0Timo Sirainen tmp = t_strsplit_spaces(set->passdb_objects, " ");
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen for (; *tmp != NULL; tmp++) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen key = db_dict_set_key_find(&set->keys, *tmp);
062ea54b7775d0c92ed67b9b1f4d93fa8ec80c84Timo Sirainen if (key == NULL) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_fatal("dict: passdb_objects refers to key %s, "
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen "which doesn't exist", *tmp);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (key->parsed_format == DB_DICT_VALUE_FORMAT_VALUE) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_fatal("dict: passdb_objects refers to key %s, "
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen "but it's in value-only format", *tmp);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen array_append(&set->parsed_passdb_objects, &key, 1);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen tmp = t_strsplit_spaces(set->userdb_objects, " ");
c6f894e1522f7b0b6068c228900914073c145175Timo Sirainen for (; *tmp != NULL; tmp++) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen key = db_dict_set_key_find(&set->keys, *tmp);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (key == NULL) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_fatal("dict: userdb_objects refers to key %s, "
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen "which doesn't exist", *tmp);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (key->parsed_format == DB_DICT_VALUE_FORMAT_VALUE) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_fatal("dict: userdb_objects refers to key %s, "
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen "but it's in value-only format", *tmp);
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen }
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen array_append(&set->parsed_userdb_objects, &key, 1);
f01eb1f51d618633c0189be9ab60a774f47fb7dfTimo Sirainen }
f01eb1f51d618633c0189be9ab60a774f47fb7dfTimo Sirainen}
f01eb1f51d618633c0189be9ab60a774f47fb7dfTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstruct dict_connection *db_dict_init(const char *config_path)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen struct dict_settings dict_set;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct dict_settings_parser_ctx ctx;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct dict_connection *conn;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen const char *error;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen pool_t pool;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen conn = dict_conn_find(config_path);
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen if (conn != NULL) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen conn->refcount++;
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen return conn;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (*config_path == '\0')
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen i_fatal("dict: Configuration file path not given");
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen pool = pool_alloconly_create("dict_connection", 1024);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen conn = p_new(pool, struct dict_connection, 1);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen conn->pool = pool;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen conn->refcount = 1;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen conn->config_path = p_strdup(pool, config_path);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen conn->set = default_dict_settings;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen p_array_init(&conn->set.keys, pool, 8);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen p_array_init(&conn->set.passdb_fields, pool, 8);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen p_array_init(&conn->set.userdb_fields, pool, 8);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen p_array_init(&conn->set.parsed_passdb_objects, pool, 2);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen p_array_init(&conn->set.parsed_userdb_objects, pool, 2);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen memset(&ctx, 0, sizeof(ctx));
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen ctx.conn = conn;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (!settings_read(config_path, NULL, parse_setting,
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen parse_section, &ctx, &error))
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen i_fatal("dict %s: %s", config_path, error);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen db_dict_settings_parse(&conn->set);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (conn->set.uri == NULL)
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen i_fatal("dict %s: Empty uri setting", config_path);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen memset(&dict_set, 0, sizeof(dict_set));
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen dict_set.username = "";
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen dict_set.base_dir = global_auth_settings->base_dir;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if (dict_init(conn->set.uri, &dict_set, &conn->dict, &error) < 0)
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen i_fatal("dict %s: Failed to init dict: %s", config_path, error);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen conn->next = connections;
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen connections = conn;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen return conn;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen}
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainenvoid db_dict_unref(struct dict_connection **_conn)
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen{
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen struct dict_connection *conn = *_conn;
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen *_conn = NULL;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen if (--conn->refcount > 0)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen return;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen dict_deinit(&conn->dict);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen pool_unref(&conn->pool);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen}
6bd263caf006edc75205f446fa0283c6f364941bTimo Sirainen
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainenstatic struct db_dict_iter_key *
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainendb_dict_iter_find_key(struct db_dict_value_iter *iter, const char *name)
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen{
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen struct db_dict_iter_key *key;
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen array_foreach_modifiable(&iter->keys, key) {
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen if (strcmp(key->key->name, name) == 0)
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen return key;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen }
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return NULL;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen}
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainenstatic void db_dict_iter_find_used_keys(struct db_dict_value_iter *iter)
0f62889d833767acf9c2ad010c3269806b4cfae3Timo Sirainen{
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen const struct db_dict_field *field;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen struct db_dict_iter_key *key;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen const char *p, *name;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen unsigned int idx, size;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen array_foreach(iter->fields, field) {
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen for (p = field->value; *p != '\0'; ) {
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen if (*p != '%') {
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen p++;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen continue;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen }
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen var_get_key_range(++p, &idx, &size);
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen if (size == 0) {
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen /* broken %variable ending too early */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen break;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen }
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen p += idx;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (size > 5 && memcmp(p, "dict:", 5) == 0) {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen name = t_strcut(t_strndup(p+5, size-5), ':');
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen key = db_dict_iter_find_key(iter, name);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (key != NULL)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen key->used = TRUE;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen }
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen p += size;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen }
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen }
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen}
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainenstatic void db_dict_iter_find_used_objects(struct db_dict_value_iter *iter)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen{
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen const struct db_dict_key *const *keyp;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen struct db_dict_iter_key *key;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen array_foreach(iter->objects, keyp) {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen key = db_dict_iter_find_key(iter, (*keyp)->name);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen i_assert(key != NULL); /* checked at init */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen i_assert(key->key->parsed_format != DB_DICT_VALUE_FORMAT_VALUE);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen key->used = TRUE;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen }
272aca0a772140d3a45a425a3fd67854ae2ccec2Timo Sirainen}
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainenstatic int
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainendb_dict_iter_key_cmp(const struct db_dict_iter_key *k1,
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen const struct db_dict_iter_key *k2)
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen{
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen return null_strcmp(k1->key->default_value, k2->key->default_value);
1d22eaac93de41319918a1fc6de42bb302e25c1aTimo Sirainen}
1d22eaac93de41319918a1fc6de42bb302e25c1aTimo Sirainen
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainenstatic int db_dict_iter_lookup_key_values(struct db_dict_value_iter *iter)
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen{
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen struct db_dict_iter_key *key;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen string_t *path;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *error;
2024157e8de36edd31f5fd72f5ea7364a0955fa7Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* sort the keys so that we'll first lookup the keys without
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen default value. if their lookup fails, the user doesn't exist. */
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen array_sort(&iter->keys, db_dict_iter_key_cmp);
b215a8a123623782554a83f3025ef4e771bd8f01Timo Sirainen
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen path = t_str_new(128);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen str_append(path, DICT_PATH_SHARED);
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen array_foreach_modifiable(&iter->keys, key) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen if (!key->used)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen continue;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen str_truncate(path, strlen(DICT_PATH_SHARED));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen var_expand(path, key->key->key, iter->var_expand_table);
b215a8a123623782554a83f3025ef4e771bd8f01Timo Sirainen ret = dict_lookup(iter->conn->dict, iter->pool,
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen str_c(path), &key->value, &error);
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen if (ret > 0) {
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen auth_request_log_debug(iter->auth_request, AUTH_SUBSYS_DB,
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen "Lookup: %s = %s", str_c(path),
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen key->value);
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen } else if (ret < 0) {
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen auth_request_log_error(iter->auth_request, AUTH_SUBSYS_DB,
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen "Failed to lookup key %s: %s", str_c(path), error);
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen return -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen } else if (key->key->default_value != NULL) {
auth_request_log_debug(iter->auth_request, AUTH_SUBSYS_DB,
"Lookup: %s not found, using default value %s",
str_c(path), key->key->default_value);
key->value = key->key->default_value;
} else {
return 0;
}
}
return 1;
}
int db_dict_value_iter_init(struct dict_connection *conn,
struct auth_request *auth_request,
const ARRAY_TYPE(db_dict_field) *fields,
const ARRAY_TYPE(db_dict_key_p) *objects,
struct db_dict_value_iter **iter_r)
{
struct db_dict_value_iter *iter;
struct db_dict_iter_key *iterkey;
const struct db_dict_key *key;
pool_t pool;
int ret;
pool = pool_alloconly_create(MEMPOOL_GROWING"auth dict lookup", 1024);
iter = p_new(pool, struct db_dict_value_iter, 1);
iter->pool = pool;
iter->conn = conn;
iter->fields = fields;
iter->objects = objects;
iter->tmpstr = str_new(pool, 128);
iter->auth_request = auth_request;
iter->var_expand_table = auth_request_get_var_expand_table(auth_request, NULL);
/* figure out what keys we need to lookup, and lookup them */
p_array_init(&iter->keys, pool, array_count(&conn->set.keys));
array_foreach(&conn->set.keys, key) {
iterkey = array_append_space(&iter->keys);
struct db_dict_key *new_key = p_new(iter->pool, struct db_dict_key, 1);
memcpy(new_key, key, sizeof(struct db_dict_key));
string_t *expanded_key = str_new(iter->pool, strlen(key->key));
auth_request_var_expand_with_table(expanded_key, key->key, auth_request,
iter->var_expand_table,
NULL);
new_key->key = str_c(expanded_key);
iterkey->key = new_key;
}
T_BEGIN {
db_dict_iter_find_used_keys(iter);
db_dict_iter_find_used_objects(iter);
ret = db_dict_iter_lookup_key_values(iter);
} T_END;
if (ret <= 0) {
pool_unref(&pool);
return ret;
}
*iter_r = iter;
return 1;
}
static bool
db_dict_value_iter_json_next(struct db_dict_value_iter *iter,
string_t *tmpstr,
const char **key_r, const char **value_r)
{
enum json_type type;
const char *value;
if (json_parse_next(iter->json_parser, &type, &value) < 0)
return FALSE;
if (type != JSON_TYPE_OBJECT_KEY) {
iter->error = "Object expected";
return FALSE;
}
if (*value == '\0') {
iter->error = "Empty object key";
return FALSE;
}
str_truncate(tmpstr, 0);
str_append(tmpstr, value);
if (json_parse_next(iter->json_parser, &type, &value) < 0) {
iter->error = "Missing value";
return FALSE;
}
if (type == JSON_TYPE_OBJECT) {
iter->error = "Nested objects not supported";
return FALSE;
}
*key_r = str_c(tmpstr);
*value_r = value;
return TRUE;
}
static void
db_dict_value_iter_json_init(struct db_dict_value_iter *iter, const char *data)
{
struct istream *input;
i_assert(iter->json_parser == NULL);
input = i_stream_create_from_data(data, strlen(data));
iter->json_parser = json_parser_init(input);
i_stream_unref(&input);
}
static bool
db_dict_value_iter_object_next(struct db_dict_value_iter *iter,
const char **key_r, const char **value_r)
{
const struct db_dict_key *const *keyp;
struct db_dict_iter_key *key;
if (iter->json_parser != NULL)
return db_dict_value_iter_json_next(iter, iter->tmpstr, key_r, value_r);
if (iter->object_idx == array_count(iter->objects))
return FALSE;
keyp = array_idx(iter->objects, iter->object_idx);
key = db_dict_iter_find_key(iter, (*keyp)->name);
i_assert(key != NULL); /* checked at init */
switch (key->key->parsed_format) {
case DB_DICT_VALUE_FORMAT_VALUE:
i_unreached();
case DB_DICT_VALUE_FORMAT_JSON:
db_dict_value_iter_json_init(iter, key->value);
return db_dict_value_iter_json_next(iter, iter->tmpstr, key_r, value_r);
}
i_unreached();
}
static const char *
db_dict_field_find(const char *data, void *context)
{
struct db_dict_value_iter *iter = context;
struct db_dict_iter_key *key;
const char *name, *value, *ret, *dotname = strchr(data, '.');
string_t *tmpstr;
if (dotname != NULL)
data = t_strdup_until(data, dotname++);
key = db_dict_iter_find_key(iter, data);
if (key == NULL)
return NULL;
switch (key->key->parsed_format) {
case DB_DICT_VALUE_FORMAT_VALUE:
return dotname != NULL ? NULL :
(key->value == NULL ? "" : key->value);
case DB_DICT_VALUE_FORMAT_JSON:
if (dotname == NULL)
return NULL;
db_dict_value_iter_json_init(iter, key->value);
ret = "";
tmpstr = t_str_new(64);
while (db_dict_value_iter_json_next(iter, tmpstr, &name, &value)) {
if (strcmp(name, dotname) == 0) {
ret = t_strdup(value);
break;
}
}
(void)json_parser_deinit(&iter->json_parser, &iter->error);
return ret;
}
i_unreached();
}
bool db_dict_value_iter_next(struct db_dict_value_iter *iter,
const char **key_r, const char **value_r)
{
static struct var_expand_func_table var_funcs_table[] = {
{ "dict", db_dict_field_find },
{ NULL, NULL }
};
const struct db_dict_field *field;
if (iter->field_idx == array_count(iter->fields))
return db_dict_value_iter_object_next(iter, key_r, value_r);
field = array_idx(iter->fields, iter->field_idx++);
str_truncate(iter->tmpstr, 0);
var_expand_with_funcs(iter->tmpstr, field->value,
iter->var_expand_table, var_funcs_table, iter);
*key_r = field->name;
*value_r = str_c(iter->tmpstr);
return TRUE;
}
int db_dict_value_iter_deinit(struct db_dict_value_iter **_iter,
const char **error_r)
{
struct db_dict_value_iter *iter = *_iter;
*_iter = NULL;
*error_r = iter->error;
if (iter->json_parser != NULL) {
if (json_parser_deinit(&iter->json_parser, &iter->error) < 0 &&
*error_r == NULL)
*error_r = iter->error;
}
pool_unref(&iter->pool);
return *error_r != NULL ? -1 : 0;
}