db-dict.c revision 2454dfa32c93c20a8522c6ed42fe057baaac9f9a
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#include "auth-common.h"
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#include "array.h"
c252d148fa8ab50aaaa8bbae7beb4d208025171dNikolai Kondrashov#include "istream.h"
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include "str.h"
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include "json-parser.h"
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include "settings.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include "dict.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include "auth-request.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include "auth-worker-client.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include "db-dict.h"
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov
fd5a4eacd56700ffb08a73121aeacdc806cb0132Sumit Bose#include <stddef.h>
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagherenum dict_settings_section {
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher DICT_SETTINGS_SECTION_ROOT = 0,
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher DICT_SETTINGS_SECTION_KEY,
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher DICT_SETTINGS_SECTION_PASSDB,
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher DICT_SETTINGS_SECTION_USERDB
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov};
428db8a58c0c149d5efccc6d788f70916c1d34d7Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct dict_settings_parser_ctx {
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher struct dict_connection *conn;
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher enum dict_settings_section section;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct db_dict_key *cur_key;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct db_dict_iter_key {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const struct db_dict_key *key;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher bool used;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *value;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct db_dict_value_iter {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool_t pool;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct auth_request *auth_request;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct dict_connection *conn;
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose const struct var_expand_table *var_expand_table;
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose ARRAY(struct db_dict_iter_key) keys;
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose const ARRAY_TYPE(db_dict_field) *fields;
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose const ARRAY_TYPE(db_dict_key_p) *objects;
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose unsigned int field_idx;
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke unsigned int object_idx;
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke struct json_parser *json_parser;
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose string_t *tmpstr;
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose const char *error;
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
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)
8214510f125879c3b1d247f2ce981ee20b5375d1Jakub Hrozekstatic struct setting_def setting_defs[] = {
1a59af8245f183f22d87d067a90197d8e2ea958dJakub Hrozek DEF_STR(uri),
a5bb518446d5ce565d7ba819590a009cabb0b0b4Jakub Hrozek DEF_STR(default_pass_scheme),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(iterate_prefix),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_BOOL(iterate_disable),
d921c1eba437662437847279f251a0a5d8f70127Maxim
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek DEF_STR(passdb_objects),
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer DEF_STR(userdb_objects),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { 0, NULL, 0 }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct db_dict_settings default_dict_settings = {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher .uri = NULL,
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce .default_pass_scheme = "MD5",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher .iterate_prefix = "",
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek .iterate_disable = FALSE,
5377441d7a846461c2d9a7a870cea711360a529aNikolai Kondrashov .passdb_objects = "",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher .userdb_objects = ""
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
32381402a4a9afc003782c9e2301fc59c9bda2a9Yassir Elley
dbfc407eef1d9ba2469687c3ffbe7fd8bb111d94Jakub Hrozek#undef DEF_STR
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher#define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_key)
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagherstatic struct setting_def key_setting_defs[] = {
e124844907ed6973915e4d56f5442ecd07535a12Jakub Hrozek DEF_STR(name),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher DEF_STR(key),
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher DEF_STR(format),
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher DEF_STR(default_value),
87d3b47abba6a40fcf809c85a2b138bc1013d9c5Jakub Hrozek
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek { 0, NULL, 0 }
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek};
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozekstatic struct db_dict_key default_key_settings = {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher .name = NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher .key = "",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher .format = "value",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher .default_value = NULL
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
054b5d4bb98973698f74d66b14ccd14394b53f10Lukas Slebodnikstatic struct dict_connection *connections = NULL;
054b5d4bb98973698f74d66b14ccd14394b53f10Lukas Slebodnik
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidekstatic struct dict_connection *dict_conn_find(const char *config_path)
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidek{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct dict_connection *conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
4f6931e854c698dcb1c09f99eb330ce2fb97e7c6Lukas Slebodnik for (conn = connections; conn != NULL; conn = conn->next) {
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher if (strcmp(conn->config_path, config_path) == 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
558998ce664055a75595371118f818084d8f2b23Jan Cholasta
558998ce664055a75595371118f818084d8f2b23Jan Cholasta return NULL;
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta}
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta
558998ce664055a75595371118f818084d8f2b23Jan Cholastastatic bool
558998ce664055a75595371118f818084d8f2b23Jan Cholastaparse_obsolete_setting(const char *key, const char *value,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct dict_settings_parser_ctx *ctx,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char **error_r)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const struct db_dict_key *dbkey;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcmp(key, "password_key") == 0) {
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);
f1828234a850dd28465425248a83a993f262918fPavel Březina *ctx->cur_key = default_key_settings;
6ea6ec5cb7d9985e2730fb9d4657624d10aed4d8Nick Guay ctx->cur_key->name = "passdb";
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina ctx->cur_key->format = "json";
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
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher dbkey = ctx->cur_key;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_append(&ctx->conn->set.parsed_passdb_objects, &dbkey, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcmp(key, "user_key") == 0) {
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);
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek *ctx->cur_key = default_key_settings;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina ctx->cur_key->name = "userdb";
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina ctx->cur_key->format = "json";
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);
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek dbkey = ctx->cur_key;
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta array_append(&ctx->conn->set.parsed_userdb_objects, &dbkey, 1);
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta return TRUE;
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta }
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek if (strcmp(key, "value_format") == 0) {
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek if (strcmp(value, "json") == 0)
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek return TRUE;
19d3aba12c70528708be9440aca66038a291f29eYassir Elley *error_r = "Deprecated value_format must be 'json'";
19d3aba12c70528708be9440aca66038a291f29eYassir Elley return FALSE;
19d3aba12c70528708be9440aca66038a291f29eYassir Elley }
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek return FALSE;
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek}
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic const char *parse_setting(const char *key, const char *value,
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct dict_settings_parser_ctx *ctx)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct db_dict_field *field;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose const char *error = NULL;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose switch (ctx->section) {
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose case DICT_SETTINGS_SECTION_ROOT:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (parse_obsolete_setting(key, value, ctx, &error))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return NULL;
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce if (error != NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return error;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return parse_setting_from_defs(ctx->conn->pool, setting_defs,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher &ctx->conn->set, key, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case DICT_SETTINGS_SECTION_KEY:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return parse_setting_from_defs(ctx->conn->pool, key_setting_defs,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->cur_key, key, value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case DICT_SETTINGS_SECTION_PASSDB:
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 return NULL;
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher case DICT_SETTINGS_SECTION_USERDB:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher field = array_append_space(&ctx->conn->set.userdb_fields);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek field->name = p_strdup(ctx->conn->pool, key);
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher field->value = p_strdup(ctx->conn->pool, value);
fe60346714a73ac3987f786731389320633dd245Pavel Březina return NULL;
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose }
2d257ccf620ce1b611f89cec8f0a94c88c2f2881Sumit Bose return t_strconcat("Unknown setting: ", key, NULL);
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter}
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek
e5e8252ec48bfdd4e7529debc705c8e090264b9aSumit Bosestatic bool parse_section(const char *type, const char *name,
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina struct dict_settings_parser_ctx *ctx,
8359bf07a2e6c0181251ce8d5d9160dc57546c55Stephen Gallagher const char **errormsg)
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina{
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina if (type == NULL) {
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina ctx->section = DICT_SETTINGS_SECTION_ROOT;
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina if (ctx->cur_key != NULL) {
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina if (strcmp(ctx->cur_key->format, "value") == 0) {
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina ctx->cur_key->parsed_format =
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina DB_DICT_VALUE_FORMAT_VALUE;
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina } else if (strcmp(ctx->cur_key->format, "json") == 0) {
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek ctx->cur_key->parsed_format =
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek DB_DICT_VALUE_FORMAT_JSON;
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek } else {
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek *errormsg = t_strconcat("Unknown key format: ",
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek ctx->cur_key->format, NULL);
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek return FALSE;
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek ctx->cur_key = NULL;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek return TRUE;
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singh }
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh if (ctx->section != DICT_SETTINGS_SECTION_ROOT) {
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose *errormsg = "Nested sections not supported";
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jha return FALSE;
461da2984c747708e8badd27fa55ef879f40e712Pallavi Jha }
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek if (strcmp(type, "key") == 0) {
777374243e15c53e7b0a7345e190c1018920be18Jakub Hrozek if (name == NULL) {
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose *errormsg = "Key section is missing name";
e046ae03d0f55b1c8b0ec2fa6139bf86a3449adfPavel Březina return FALSE;
939246537b0b9a4af6862c513d3919501ad57d92Sumit Bose }
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose if (strchr(name, '.') != NULL) {
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek *errormsg = "Key section names must not contain '.'";
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek return FALSE;
90afedb00608547ae1f32aa7aafd552c4b306909Jakub Hrozek }
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek ctx->section = DICT_SETTINGS_SECTION_KEY;
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek ctx->cur_key = array_append_space(&ctx->conn->set.keys);
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina *ctx->cur_key = default_key_settings;
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek ctx->cur_key->name = p_strdup(ctx->conn->pool, name);
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl return TRUE;
e2e334b2f51118cb14c7391c4e4e44ff247ef638Pavel Reichl }
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl if (strcmp(type, "passdb_fields") == 0) {
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek ctx->section = DICT_SETTINGS_SECTION_PASSDB;
a524965fbe0551f1b3a68f1e5c7a5689a652998fSumit Bose return TRUE;
526a15438525417cd701f837d7085b7f8c8a6325Jakub Hrozek }
1d93029624d708119bbf803e6647a2cbb271f001Sumit Bose if (strcmp(type, "userdb_fields") == 0) {
a5623363d6042290fe652a1ca5ce5a85a821236fPavel Březina ctx->section = DICT_SETTINGS_SECTION_USERDB;
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose return TRUE;
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose }
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek *errormsg = "Unknown section";
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina return FALSE;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina}
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek
ea422c7061072c125eb53b40d7f3ca444d886913Sumit Bosestatic void
89ddc9ed474e9ac2b1e7bccb0a58610babf26cf8Jakub Hrozekdb_dict_settings_parse(struct db_dict_settings *set)
f4025ea817b3467be1c2e6092014a11fe4547c0dJakub Hrozek{
01ec08efd0e166ac6f390f8627c6d08dcc63ccc4Jakub Hrozek const struct db_dict_key *key;
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose const char *const *tmp;
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek tmp = t_strsplit_spaces(set->passdb_objects, " ");
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek for (; *tmp != NULL; tmp++) {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek key = db_dict_set_key_find(&set->keys, *tmp);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek if (key == NULL) {
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek i_fatal("dict: passdb_objects refers to key %s, "
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek "which doesn't exist", *tmp);
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek }
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek if (key->parsed_format == DB_DICT_VALUE_FORMAT_VALUE) {
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek i_fatal("dict: passdb_objects refers to key %s, "
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik "but it's in value-only format", *tmp);
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnik }
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnik array_append(&set->parsed_passdb_objects, &key, 1);
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnik }
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik tmp = t_strsplit_spaces(set->userdb_objects, " ");
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek for (; *tmp != NULL; tmp++) {
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek key = db_dict_set_key_find(&set->keys, *tmp);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (key == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("dict: userdb_objects refers to key %s, "
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek "which doesn't exist", *tmp);
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (key->parsed_format == DB_DICT_VALUE_FORMAT_VALUE) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("dict: userdb_objects refers to key %s, "
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek "but it's in value-only format", *tmp);
fb3c5cdfcda069a5fbeb7b9d200c0881911364b8Jakub Hrozek }
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek array_append(&set->parsed_userdb_objects, &key, 1);
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek }
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher}
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnikstruct dict_connection *db_dict_init(const char *config_path)
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik{
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik struct dict_settings dict_set;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik struct dict_settings_parser_ctx ctx;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik struct dict_connection *conn;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik const char *error;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik pool_t pool;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik conn = dict_conn_find(config_path);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (conn != NULL) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik conn->refcount++;
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher return conn;
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher }
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*config_path == '\0')
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher i_fatal("dict: Configuration file path not given");
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov pool = pool_alloconly_create("dict_connection", 1024);
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov conn = p_new(pool, struct dict_connection, 1);
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov conn->pool = pool;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->refcount = 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->config_path = p_strdup(pool, config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher conn->set = default_dict_settings;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher p_array_init(&conn->set.keys, pool, 8);
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);
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik i_zero(&ctx);
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik ctx.conn = conn;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!settings_read(config_path, NULL, parse_setting,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher parse_section, &ctx, &error))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("dict %s: %s", config_path, error);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_dict_settings_parse(&conn->set);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (conn->set.uri == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("dict %s: Empty uri setting", config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose i_zero(&dict_set);
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose dict_set.username = "";
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);
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose conn->next = connections;
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose connections = conn;
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose return conn;
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose}
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzkevoid db_dict_unref(struct dict_connection **_conn)
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke{
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke struct dict_connection *conn = *_conn;
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher *_conn = NULL;
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher if (--conn->refcount > 0)
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik return;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik dict_deinit(&conn->dict);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik pool_unref(&conn->pool);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik}
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnikstatic struct db_dict_iter_key *
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnikdb_dict_iter_find_key(struct db_dict_value_iter *iter, const char *name)
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik{
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik struct db_dict_iter_key *key;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik array_foreach_modifiable(&iter->keys, key) {
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik if (strcmp(key->key->name, name) == 0)
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik return key;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik }
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik return NULL;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik}
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_dict_iter_find_used_keys(struct db_dict_value_iter *iter)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const struct db_dict_field *field;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct db_dict_iter_key *key;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *p, *name;
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher unsigned int idx, size;
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher
15b266d9f14dad26da8678a79019749d0f69532eStephen Gallagher array_foreach(iter->fields, field) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik for (p = field->value; *p != '\0'; ) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (*p != '%') {
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher p++;
b97595ae059c69b1960a6e7e56d74660388a683bJan Zeleny continue;
6a6a821866091e0f722808566c25b951aa346d7cStephen Gallagher }
48d7840cae22c5ff4d786149b0d8ecee7efb8306Lukas Slebodnik
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov var_get_key_range(++p, &idx, &size);
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov if (size == 0) {
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov /* broken %variable ending too early */
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov break;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov }
60e51fd2764291df2332f36ff478777627d92b57Sumit Bose p += idx;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (size > 5 && memcmp(p, "dict:", 5) == 0) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik name = t_strcut(t_strndup(p+5, size-5), ':');
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozek key = db_dict_iter_find_key(iter, name);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (key != NULL)
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik key->used = TRUE;
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozek }
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov p += size;
7bb9ba8688ec1ca930d693eea05e936bc38f6d1bSumit Bose }
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozek }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void db_dict_iter_find_used_objects(struct db_dict_value_iter *iter)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const struct db_dict_key *const *keyp;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct db_dict_iter_key *key;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
17f08cbd0f909181536b93d6c12c7cd69995f09eSumit Bose array_foreach(iter->objects, keyp) {
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);
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov key->used = TRUE;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov }
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov}
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bosestatic int
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bosedb_dict_iter_key_cmp(const struct db_dict_iter_key *k1,
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov const struct db_dict_iter_key *k2)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return null_strcmp(k1->key->default_value, k2->key->default_value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int db_dict_iter_lookup_key_values(struct db_dict_value_iter *iter)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct db_dict_iter_key *key;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher string_t *path;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *error;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
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
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher path = t_str_new(128);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append(path, DICT_PATH_SHARED);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_foreach_modifiable(&iter->keys, key) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!key->used)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher continue;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_truncate(path, strlen(DICT_PATH_SHARED));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = var_expand(path, key->key->key, iter->var_expand_table, &error);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret <= 0) {
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose auth_request_log_error(iter->auth_request, AUTH_SUBSYS_DB,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher "Failed to expand key %s: %s", key->key->key, error);
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = dict_lookup(iter->conn->dict, iter->pool,
a5bb518446d5ce565d7ba819590a009cabb0b0b4Jakub Hrozek str_c(path), &key->value, &error);
eaaeaa7e00c3d4bfa792cc4d3c6770dc1e28ef0cSumit Bose if (ret > 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_debug(iter->auth_request, AUTH_SUBSYS_DB,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Lookup: %s = %s", str_c(path),
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher key->value);
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);
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose return -1;
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",
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta str_c(path), key->key->default_value);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher key->value = key->key->default_value;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else {
b3b6189850d50c656d62efbd498789124c033b00Lukas Slebodnik return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherint db_dict_value_iter_init(struct dict_connection *conn,
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny struct auth_request *auth_request,
769347ad4d35d43488eb98f980143495b0db415dStef Walter const ARRAY_TYPE(db_dict_field) *fields,
115de6d50f0d0bdd5745a5d8eb0d067be9128528Sumit Bose const ARRAY_TYPE(db_dict_key_p) *objects,
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina struct db_dict_value_iter **iter_r)
769347ad4d35d43488eb98f980143495b0db415dStef Walter{
769347ad4d35d43488eb98f980143495b0db415dStef Walter struct db_dict_value_iter *iter;
769347ad4d35d43488eb98f980143495b0db415dStef Walter struct db_dict_iter_key *iterkey;
769347ad4d35d43488eb98f980143495b0db415dStef Walter const struct db_dict_key *key;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool_t pool;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool = pool_alloconly_create(MEMPOOL_GROWING"auth dict lookup", 1024);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter = p_new(pool, struct db_dict_value_iter, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter->pool = pool;
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina iter->conn = conn;
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina iter->fields = fields;
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina iter->objects = objects;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter->tmpstr = str_new(pool, 128);
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek iter->auth_request = auth_request;
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek iter->var_expand_table = auth_request_get_var_expand_table(auth_request, NULL);
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek
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));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_foreach(&conn->set.keys, key) {
ca261795ce61c41d7e62217ccb2ee913923040ffPavel Březina iterkey = array_append_space(&iter->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));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *error;
77d165f0629966db65753a3aee84a8b4971673afPavel Březina if (auth_request_var_expand_with_table(expanded_key, key->key, auth_request,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter->var_expand_table,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher NULL, &error) <= 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_error(iter->auth_request, AUTH_SUBSYS_DB,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Failed to expand key %s: %s", key->key, error);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool_unref(&pool);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher new_key->key = str_c(expanded_key);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iterkey->key = new_key;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher T_BEGIN {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_dict_iter_find_used_keys(iter);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher db_dict_iter_find_used_objects(iter);
126c9338cf12a3e4404c36bbe4ec14b18f23537cMaxim ret = db_dict_iter_lookup_key_values(iter);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher } T_END;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret <= 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher pool_unref(&pool);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *iter_r = iter;
4e0404ca1b19830dc0f729e59efd5bbd0a9d6103Lukas Slebodnik return 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
eaa723b4d06b4c1e588df67bef44a84bbfaebf1aLukas Slebodnikstatic bool
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdb_dict_value_iter_json_next(struct db_dict_value_iter *iter,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher string_t *tmpstr,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char **key_r, const char **value_r)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher enum json_type type;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *value;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (json_parse_next(iter->json_parser, &type, &value) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose if (type != JSON_TYPE_OBJECT_KEY) {
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher iter->error = "Object expected";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek if (*value == '\0') {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter->error = "Empty object key";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_truncate(tmpstr, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str_append(tmpstr, value);
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose if (json_parse_next(iter->json_parser, &type, &value) < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter->error = "Missing value";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
3a4186ae40d0c3b7be46a4c973166f6048fcfe38Lukas Slebodnik }
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce if (type == JSON_TYPE_OBJECT) {
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter iter->error = "Nested objects not supported";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
46e36286953de4e5af5e4289b90a529929bdd17cPetr Cech }
1658c567191c35beaddffafdb079abe33248037bLukas Slebodnik *key_r = str_c(tmpstr);
29be7d76c949b82350c7603cfd362a1fcb47eb1bJan Zeleny *value_r = value;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067Jakub Hrozek}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
823a5b3f4375f12b6edae4dd5169ee01771baebeJan Zelenystatic void
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagherdb_dict_value_iter_json_init(struct db_dict_value_iter *iter, const char *data)
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta{
7de6e3534fd61c7619ed34a6b1afe7230b5e6504Ondrej Kos struct istream *input;
701f13b5c8e27bcbfc79e77ce7c76d9f768a448cLukas Slebodnik
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina i_assert(iter->json_parser == NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher input = i_stream_create_from_data(data, strlen(data));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter->json_parser = json_parser_init(input);
5a70b84cb66fb8c7a3fce0e3f2e4b61e0b2ea9d4Simo Sorce i_stream_unref(&input);
5f90993426fa2bdc3b3d994c9e85e0805bb92bbcSimo Sorce}
9959c512ac3ba36f7a0db7614f0357ce0bae748fJakub Hrozek
7452f1b637276ce582b120f8f5482ae7f3b6bd47Jakub Hrozekstatic bool
918b2a5a91f1c551d48f4bffed2a28c36fdb4be1Simo Sorcedb_dict_value_iter_object_next(struct db_dict_value_iter *iter,
bc052ea17d858c19f9cb9c9e2bc602e754f68831Sumit Bose const char **key_r, const char **value_r)
2fa8d6655ac37f9bdeb34420000052d921f4a543Michal Zidek{
a473fb88e6015cf0ccbd2e9005c7e6acca18f452Pavel Březina const struct db_dict_key *const *keyp;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct db_dict_iter_key *key;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (iter->json_parser != NULL)
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))
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
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 */
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher
8c3a4809b3420657289b42f028a1c9019b112991Stephen Gallagher switch (key->key->parsed_format) {
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce case DB_DICT_VALUE_FORMAT_VALUE:
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose i_unreached();
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case DB_DICT_VALUE_FORMAT_JSON:
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);
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta }
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek i_unreached();
590582be38cdbfde387fcc57df92903d48c5a083Jakub Hrozek}
8a1fd0633e85221da1fb63451516a70d66c0af31Pavel Březina
c747b0c875785ce693f70b50bdda0237c4b04e35Pavel Březinastatic int
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březinadb_dict_field_find(const char *data, void *context,
d3c82d0170d6d7407549afdadd08aa7e11aeb9a2Pavel Březina const char **value_r,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char **error_r ATTR_UNUSED)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter struct db_dict_value_iter *iter = context;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct db_dict_iter_key *key;
df4e1db5d41c903ae57fd880acc76a0ad84aa7b2Pavel Březina const char *name, *value, *dotname = strchr(data, '.');
364b3572bab5a9649e8f2d4da835d05d3c8ca7a9Pavel Březina string_t *tmpstr;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
3f98cdc011bb4e8cd22c088f288b0bcdb6452492Jakub Hrozek *value_r = NULL;
1f1e6cbc59868f06dee3ab4b3df660fcb77ce1c8Jakub Hrozek
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny if (dotname != NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher data = t_strdup_until(data, dotname++);
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher key = db_dict_iter_find_key(iter, data);
1a7d1977037864e52858058777af8ff8401547ddJan Cholasta if (key == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher switch (key->key->parsed_format) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher case DB_DICT_VALUE_FORMAT_VALUE:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *value_r = dotname != NULL ? NULL :
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek (key->value == NULL ? "" : key->value);
fa70db6004a099afb7cb55031cd7bacb9e78202ePavel Březina return 1;
ac47e8854f3bc404f2a35c6682faf621673d6b32Pavel Březina case DB_DICT_VALUE_FORMAT_JSON:
b79e0e50a935d108173ca3062f2afe16103fcb1dPavel Březina if (dotname == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 1;
f9961e5f82e0ef474d6492371bfdf9e74e208a99Pavel Březina db_dict_value_iter_json_init(iter, key->value);
87c07559af5cfcd2752295ef7c425bd3205f426fStephen Gallagher *value_r = "";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher tmpstr = t_str_new(64);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher while (db_dict_value_iter_json_next(iter, tmpstr, &name, &value)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcmp(name, dotname) == 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *value_r = t_strdup(value);
3441d0c2d11aea0c39b009751a1898333c009674Stephen Gallagher break;
65e8f538ad35ba7d86cd9e60a3d86aec34537027Stephen Gallagher }
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (void)json_parser_deinit(&iter->json_parser, &iter->error);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_unreached();
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
4af1d1869d659fec84c518c26844132fa1df8f64Jakub Hrozek
e9eeb4302e0e426c6cc1a4e65b95a6f7066e80b9Pavel Březinabool db_dict_value_iter_next(struct db_dict_value_iter *iter,
cc84fd46f356c4a36a721ab135a33ec77c93e34dJakub Hrozek const char **key_r, const char **value_r)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
65e8f538ad35ba7d86cd9e60a3d86aec34537027Stephen Gallagher static struct var_expand_func_table var_funcs_table[] = {
cdaa29d2c5724a4c72bfa0f42284ccfac3d5a464Pavel Reichl { "dict", db_dict_field_find },
ae8d047122c7ba8123f72b2eac68944868ac37d4Stephen Gallagher { NULL, NULL }
fae99bfe4bfc8b4a12e9c2a0ad01b3684c22f934Simo Sorce };
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek const struct db_dict_field *field;
8ca73915a3bf60331468fed6b3b38652c979f95dJakub Hrozek const char *error;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
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++);
ad07ed37b6b51ef134d4524edaf2259e19ac984fJan Zeleny
1a853121ca2ba8ede6df429ee76942131ffb0f65Jan Zeleny str_truncate(iter->tmpstr, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (var_expand_with_funcs(iter->tmpstr, field->value,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher iter->var_expand_table, var_funcs_table,
81165faf5d951aca69f410713730c26ff048ec44Sumit Bose iter, &error) <= 0) {
3a62a99faf8e12965100d0b26fc9e07752bd3e2dStephen Gallagher iter->error = p_strdup_printf(iter->pool,
1a7d1977037864e52858058777af8ff8401547ddJan Cholasta "Failed to expand %s=%s: %s",
65e8f538ad35ba7d86cd9e60a3d86aec34537027Stephen Gallagher field->name, field->value, error);
88275cccddf39892e01682b39b02292eb74729bdPavel Březina return FALSE;
a679f0167b646cffdae86546ed77e105576991b0Pavel Březina }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *key_r = field->name;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *value_r = str_c(iter->tmpstr);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
347f7c4d1e8e83fc7ffcaf9524a67e8b3ad5d7c5Jan Cholasta
4139a7a731f2831963a42b26aac111422be28792Jakub Hrozekint db_dict_value_iter_deinit(struct db_dict_value_iter **_iter,
50fe3d79ab12b795a687b676761bef265701626aStephen Gallagher const char **error_r)
50fe3d79ab12b795a687b676761bef265701626aStephen Gallagher{
3f32406640d89face5e79244b4d8dab34adb6c7cPavel Březina struct db_dict_value_iter *iter = *_iter;
17d37aecdf397fcb7a1d0c75adebdb25d7be112ePavel Březina
b1a822a16e3ef97e31d167f9e97efec06fc121dcJakub Hrozek *_iter = NULL;
d43c9d18fb263b1ea4071b20e93ce4994583f62fJakub Hrozek
077f8c9ca849ec895da3f0a25d15484ead08e99eLukas Slebodnik *error_r = iter->error;
bf6c3f07d653d474da9e43b2b7cced57fc4ea069Sumit Bose if (iter->json_parser != NULL) {
b6dfbf81c61d4431aaa81687ec53e892f8b71edbSumit Bose if (json_parser_deinit(&iter->json_parser, &iter->error) < 0 &&
e293fba4f5459f3c2dad254dcc966407d8fc3312Jakub Hrozek *error_r == NULL)
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose *error_r = iter->error;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose }
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose pool_unref(&iter->pool);
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer return *error_r != NULL ? -1 : 0;
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina}
462db32918a05097652f8232cd6c8d78a826e63cLukas Slebodnik