db-dict.c revision 803197abb1cc0e81abb668c026c22394bfef820d
/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
#include "auth-common.h"
#include "settings.h"
#include "dict.h"
#include "json-parser.h"
#include "str.h"
#include "auth-request.h"
#include "auth-worker-client.h"
#include "db-dict.h"
#include <stddef.h>
#include <stdlib.h>
#define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_settings)
#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, db_dict_settings)
static struct setting_def setting_defs[] = {
DEF_STR(uri),
DEF_STR(password_key),
DEF_STR(user_key),
DEF_STR(iterate_prefix),
DEF_STR(value_format),
DEF_BOOL(iterate_disable),
DEF_STR(default_pass_scheme),
{ 0, NULL, 0 }
};
static struct db_dict_settings default_dict_settings = {
.uri = NULL,
.password_key = "",
.user_key = "",
.iterate_prefix = "",
.iterate_disable = FALSE,
.value_format = "json",
.default_pass_scheme = "MD5"
};
static struct dict_connection *connections = NULL;
static struct dict_connection *dict_conn_find(const char *config_path)
{
struct dict_connection *conn;
for (conn = connections; conn != NULL; conn = conn->next) {
if (strcmp(conn->config_path, config_path) == 0)
return conn;
}
return NULL;
}
static const char *parse_setting(const char *key, const char *value,
struct dict_connection *conn)
{
return parse_setting_from_defs(conn->pool, setting_defs,
&conn->set, key, value);
}
struct dict_connection *db_dict_init(const char *config_path)
{
struct dict_connection *conn;
const char *error;
pool_t pool;
conn = dict_conn_find(config_path);
if (conn != NULL) {
conn->refcount++;
return conn;
}
if (*config_path == '\0')
i_fatal("dict: Configuration file path not given");
pool = pool_alloconly_create("dict_connection", 1024);
conn = p_new(pool, struct dict_connection, 1);
conn->pool = pool;
conn->refcount = 1;
conn->config_path = p_strdup(pool, config_path);
conn->set = default_dict_settings;
if (!settings_read_nosection(config_path, parse_setting, conn, &error))
i_fatal("dict %s: %s", config_path, error);
if (conn->set.uri == NULL)
i_fatal("dict %s: Empty uri setting", config_path);
if (strcmp(conn->set.value_format, "json") != 0) {
i_fatal("dict %s: Unsupported value_format %s in ",
config_path, conn->set.value_format);
}
if (dict_init(conn->set.uri, DICT_DATA_TYPE_STRING, "",
global_auth_settings->base_dir, &conn->dict) < 0)
i_fatal("dict %s: Failed to init dict", config_path);
conn->next = connections;
connections = conn;
return conn;
}
void db_dict_unref(struct dict_connection **_conn)
{
struct dict_connection *conn = *_conn;
*_conn = NULL;
if (--conn->refcount > 0)
return;
dict_deinit(&conn->dict);
pool_unref(&conn->pool);
}
struct db_dict_value_iter {
struct json_parser *parser;
string_t *key;
const char *error;
};
struct db_dict_value_iter *
db_dict_value_iter_init(struct dict_connection *conn, const char *value)
{
struct db_dict_value_iter *iter;
i_assert(strcmp(conn->set.value_format, "json") == 0);
/* hardcoded for now for JSON value. make it more modular when other
value types are supported. */
iter = i_new(struct db_dict_value_iter, 1);
iter->key = str_new(default_pool, 64);
iter->parser = json_parser_init((const void *)value, strlen(value));
return iter;
}
bool db_dict_value_iter_next(struct db_dict_value_iter *iter,
const char **key_r, const char **value_r)
{
enum json_type type;
const char *value;
if (!json_parse_next(iter->parser, &type, &value))
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(iter->key, 0);
str_append(iter->key, value);
if (!json_parse_next(iter->parser, &type, &value)) {
iter->error = "Missing value";
return FALSE;
}
*key_r = str_c(iter->key);
*value_r = value;
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 (json_parser_deinit(&iter->parser, &iter->error) < 0 &&
*error_r == NULL)
*error_r = iter->error;
str_free(&iter->key);
i_free(iter);
return *error_r != NULL ? -1 : 0;
}