db-dict.c revision 2454dfa32c93c20a8522c6ed42fe057baaac9f9a
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose unsigned int field_idx;
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose const char *error;
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher#define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_settings)
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, db_dict_settings)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct db_dict_settings default_dict_settings = {
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher#define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_key)
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagherstatic struct setting_def key_setting_defs[] = {
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozekstatic struct db_dict_key default_key_settings = {
054b5d4bb98973698f74d66b14ccd14394b53f10Lukas Slebodnikstatic struct dict_connection *connections = NULL;
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidekstatic struct dict_connection *dict_conn_find(const char *config_path)
4f6931e854c698dcb1c09f99eb330ce2fb97e7c6Lukas Slebodnik for (conn = connections; conn != NULL; conn = conn->next) {
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher if (strcmp(conn->config_path, config_path) == 0)
558998ce664055a75595371118f818084d8f2b23Jan Cholastaparse_obsolete_setting(const char *key, const char *value,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* key passdb { key=<value> format=json }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher passdb_objects = passdb */
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny ctx->cur_key = array_append_space(&ctx->conn->set.keys);
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina ctx->cur_key->parsed_format = DB_DICT_VALUE_FORMAT_JSON;
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina ctx->cur_key->key = p_strdup(ctx->conn->pool, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_append(&ctx->conn->set.parsed_passdb_objects, &dbkey, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* key userdb { key=<value> format=json }
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek userdb_objects = userdb */
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek ctx->cur_key = array_append_space(&ctx->conn->set.keys);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina ctx->cur_key->parsed_format = DB_DICT_VALUE_FORMAT_JSON;
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek ctx->cur_key->key = p_strdup(ctx->conn->pool, value);
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta array_append(&ctx->conn->set.parsed_userdb_objects, &dbkey, 1);
19d3aba12c70528708be9440aca66038a291f29eYassir Elley *error_r = "Deprecated value_format must be 'json'";
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic const char *parse_setting(const char *key, const char *value,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (parse_obsolete_setting(key, value, ctx, &error))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return parse_setting_from_defs(ctx->conn->pool, setting_defs,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return parse_setting_from_defs(ctx->conn->pool, key_setting_defs,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher field = array_append_space(&ctx->conn->set.passdb_fields);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher field->name = p_strdup(ctx->conn->pool, key);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher field->value = p_strdup(ctx->conn->pool, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher field = array_append_space(&ctx->conn->set.userdb_fields);
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher field->value = p_strdup(ctx->conn->pool, value);
2d257ccf620ce1b611f89cec8f0a94c88c2f2881Sumit Bose return t_strconcat("Unknown setting: ", key, NULL);
e5e8252ec48bfdd4e7529debc705c8e090264b9aSumit Bosestatic bool parse_section(const char *type, const char *name,
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina if (strcmp(ctx->cur_key->format, "value") == 0) {
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina } else if (strcmp(ctx->cur_key->format, "json") == 0) {
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek *errormsg = t_strconcat("Unknown key format: ",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (ctx->section != DICT_SETTINGS_SECTION_ROOT) {
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek *errormsg = "Key section names must not contain '.'";
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek ctx->cur_key = array_append_space(&ctx->conn->set.keys);
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek ctx->cur_key->name = p_strdup(ctx->conn->pool, name);
89ddc9ed474e9ac2b1e7bccb0a58610babf26cf8Jakub Hrozekdb_dict_settings_parse(struct db_dict_settings *set)
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose const char *const *tmp;
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek tmp = t_strsplit_spaces(set->passdb_objects, " ");
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_fatal("dict: passdb_objects refers to key %s, "
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek if (key->parsed_format == DB_DICT_VALUE_FORMAT_VALUE) {
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek i_fatal("dict: passdb_objects refers to key %s, "
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnik array_append(&set->parsed_passdb_objects, &key, 1);
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik tmp = t_strsplit_spaces(set->userdb_objects, " ");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("dict: userdb_objects refers to key %s, "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (key->parsed_format == DB_DICT_VALUE_FORMAT_VALUE) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("dict: userdb_objects refers to key %s, "
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek array_append(&set->parsed_userdb_objects, &key, 1);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnikstruct dict_connection *db_dict_init(const char *config_path)
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher i_fatal("dict: Configuration file path not given");
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov pool = pool_alloconly_create("dict_connection", 1024);
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov conn = p_new(pool, struct dict_connection, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->config_path = p_strdup(pool, config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher p_array_init(&conn->set.passdb_fields, pool, 8);
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik p_array_init(&conn->set.userdb_fields, pool, 8);
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik p_array_init(&conn->set.parsed_passdb_objects, pool, 2);
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik p_array_init(&conn->set.parsed_userdb_objects, pool, 2);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!settings_read(config_path, NULL, parse_setting,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("dict %s: %s", config_path, error);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("dict %s: Empty uri setting", config_path);
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose dict_set.base_dir = global_auth_settings->base_dir;
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose if (dict_init(conn->set.uri, &dict_set, &conn->dict, &error) < 0)
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose i_fatal("dict %s: Failed to init dict: %s", config_path, error);
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzkevoid db_dict_unref(struct dict_connection **_conn)
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnikdb_dict_iter_find_key(struct db_dict_value_iter *iter, const char *name)
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik array_foreach_modifiable(&iter->keys, key) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_dict_iter_find_used_keys(struct db_dict_value_iter *iter)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *p, *name;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (*p != '%') {
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov /* broken %variable ending too early */
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (size > 5 && memcmp(p, "dict:", 5) == 0) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik name = t_strcut(t_strndup(p+5, size-5), ':');
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_dict_iter_find_used_objects(struct db_dict_value_iter *iter)
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov key = db_dict_iter_find_key(iter, (*keyp)->name);
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov i_assert(key != NULL); /* checked at init */
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov i_assert(key->key->parsed_format != DB_DICT_VALUE_FORMAT_VALUE);
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bosedb_dict_iter_key_cmp(const struct db_dict_iter_key *k1,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return null_strcmp(k1->key->default_value, k2->key->default_value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int db_dict_iter_lookup_key_values(struct db_dict_value_iter *iter)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* sort the keys so that we'll first lookup the keys without
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher default value. if their lookup fails, the user doesn't exist. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_sort(&iter->keys, db_dict_iter_key_cmp);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_foreach_modifiable(&iter->keys, key) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_truncate(path, strlen(DICT_PATH_SHARED));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = var_expand(path, key->key->key, iter->var_expand_table, &error);
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose auth_request_log_error(iter->auth_request, AUTH_SUBSYS_DB,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher "Failed to expand key %s: %s", key->key->key, error);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = dict_lookup(iter->conn->dict, iter->pool,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_debug(iter->auth_request, AUTH_SUBSYS_DB,
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce } else if (ret < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_error(iter->auth_request, AUTH_SUBSYS_DB,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Failed to lookup key %s: %s", str_c(path), error);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (key->key->default_value != NULL) {
0ef783e186ef1c9f60e61a4e8e54c44cb366fdfePavel Březina auth_request_log_debug(iter->auth_request, AUTH_SUBSYS_DB,
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek "Lookup: %s not found, using default value %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherint db_dict_value_iter_init(struct dict_connection *conn,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool = pool_alloconly_create(MEMPOOL_GROWING"auth dict lookup", 1024);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter = p_new(pool, struct db_dict_value_iter, 1);
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek iter->var_expand_table = auth_request_get_var_expand_table(auth_request, NULL);
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek /* figure out what keys we need to lookup, and lookup them */
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek p_array_init(&iter->keys, pool, array_count(&conn->set.keys));
ca261795ce61c41d7e62217ccb2ee913923040ffPavel Březina struct db_dict_key *new_key = p_new(iter->pool, struct db_dict_key, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher memcpy(new_key, key, sizeof(struct db_dict_key));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher string_t *expanded_key = str_new(iter->pool, strlen(key->key));
77d165f0629966db65753a3aee84a8b4971673afPavel Březina if (auth_request_var_expand_with_table(expanded_key, key->key, auth_request,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_error(iter->auth_request, AUTH_SUBSYS_DB,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Failed to expand key %s: %s", key->key, error);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdb_dict_value_iter_json_next(struct db_dict_value_iter *iter,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (json_parse_next(iter->json_parser, &type, &value) < 0)
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose if (json_parse_next(iter->json_parser, &type, &value) < 0) {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagherdb_dict_value_iter_json_init(struct db_dict_value_iter *iter, const char *data)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher input = i_stream_create_from_data(data, strlen(data));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter->json_parser = json_parser_init(input);
918b2a5a91f1c551d48f4bffed2a28c36fdb4be1Simo Sorcedb_dict_value_iter_object_next(struct db_dict_value_iter *iter,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return db_dict_value_iter_json_next(iter, iter->tmpstr, key_r, value_r);
e850be1ff2e13bba9812c94c3d102c0a0b570820Jakub Hrozek if (iter->object_idx == array_count(iter->objects))
d844aab866ae237844360cea70e2dccdc90c783dStephen Gallagher keyp = array_idx(iter->objects, iter->object_idx);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher key = db_dict_iter_find_key(iter, (*keyp)->name);
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher i_assert(key != NULL); /* checked at init */
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina db_dict_value_iter_json_init(iter, key->value);
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek return db_dict_value_iter_json_next(iter, iter->tmpstr, key_r, value_r);
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březinadb_dict_field_find(const char *data, void *context,
d3c82d0170d6d7407549afdadd08aa7e11aeb9a2Pavel Březina const char **value_r,
df4e1db5d41c903ae57fd880acc76a0ad84aa7b2Pavel Březina const char *name, *value, *dotname = strchr(data, '.');
f9961e5f82e0ef474d6492371bfdf9e74e208a99Pavel Březina db_dict_value_iter_json_init(iter, key->value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher while (db_dict_value_iter_json_next(iter, tmpstr, &name, &value)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (void)json_parser_deinit(&iter->json_parser, &iter->error);
e9eeb4302e0e426c6cc1a4e65b95a6f7066e80b9Pavel Březinabool db_dict_value_iter_next(struct db_dict_value_iter *iter,
65e8f538ad35ba7d86cd9e60a3d86aec34537027Stephen Gallagher static struct var_expand_func_table var_funcs_table[] = {
213ce2a78b1abe3921d8dc13c949a28130d00aecJan Zeleny if (iter->field_idx == array_count(iter->fields))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return db_dict_value_iter_object_next(iter, key_r, value_r);
38e2ec1c757955ab557fd95807afa58042d09482Jan Zeleny field = array_idx(iter->fields, iter->field_idx++);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (var_expand_with_funcs(iter->tmpstr, field->value,
1a7d1977037864e52858058777af8ff8401547ddJan Cholasta "Failed to expand %s=%s: %s",
4139a7a731f2831963a42b26aac111422be28792Jakub Hrozekint db_dict_value_iter_deinit(struct db_dict_value_iter **_iter,