#if defined(PASSDB_SQL) || defined(USERDB_SQL)
-#include "settings-legacy.h"
#include "auth-request.h"
#include "auth-worker-server.h"
-#include "auth-common.h"
#include "db-sql.h"
-#define DEF_STR(name) DEF_STRUCT_STR(name, db_sql_settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, db_sql_settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, db_sql_settings)
-
-static struct setting_def setting_defs[] = {
- DEF_STR(driver),
- DEF_STR(connect),
- DEF_STR(password_query),
- DEF_STR(user_query),
- DEF_STR(update_query),
- DEF_STR(iterate_query),
- DEF_STR(default_pass_scheme),
-
- { 0, NULL, 0 }
-};
-
-static struct db_sql_settings default_db_sql_settings = {
- .driver = NULL,
- .connect = NULL,
- .password_query = "",
- .user_query = "",
- .update_query = "",
- .iterate_query = "",
- .default_pass_scheme = "MD5",
-};
-
-static struct db_sql_connection *connections = NULL;
-
-static struct db_sql_connection *sql_conn_find(const char *config_path)
-{
- struct db_sql_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 db_sql_connection *conn)
-{
- return parse_setting_from_defs(conn->pool, setting_defs,
- &conn->set, key, value);
-}
-
-struct db_sql_connection *db_sql_init(const char *config_path)
-{
- struct db_sql_connection *conn;
- struct sql_legacy_settings set;
- const char *error;
- pool_t pool;
-
- conn = sql_conn_find(config_path);
- if (conn != NULL) {
- conn->refcount++;
- return conn;
- }
-
- if (*config_path == '\0')
- i_fatal("sql: Configuration file path not given");
-
- pool = pool_alloconly_create("db_sql_connection", 1024);
- conn = p_new(pool, struct db_sql_connection, 1);
- conn->pool = pool;
-
- conn->refcount = 1;
-
- conn->config_path = p_strdup(pool, config_path);
- conn->set = default_db_sql_settings;
- if (!settings_read_nosection(config_path, parse_setting, conn, &error))
- i_fatal("sql %s: %s", config_path, error);
-
- if (conn->set.driver == NULL) {
- i_fatal("sql: driver not set in configuration file %s",
- config_path);
- }
- if (conn->set.connect == NULL) {
- i_fatal("sql: connect string not set in configuration file %s",
- config_path);
- }
- i_zero(&set);
- set.driver = conn->set.driver;
- set.connect_string = conn->set.connect;
- set.event_parent = auth_event;
- if (sql_init_legacy_full(&set, &conn->db, &error) < 0) {
- i_fatal("sql: %s", error);
- }
-
- conn->next = connections;
- connections = conn;
- return conn;
-}
-
-void db_sql_unref(struct db_sql_connection **_conn)
-{
- struct db_sql_connection *conn = *_conn;
-
- /* abort all pending auth requests before setting conn to NULL,
- so that callbacks can still access it */
- sql_disconnect(conn->db);
-
- *_conn = NULL;
- if (--conn->refcount > 0)
- return;
-
- sql_unref(&conn->db);
- pool_unref(&conn->pool);
-}
-
-void db_sql_connect(struct db_sql_connection *conn)
+void db_sql_connect(struct sql_db *db)
{
- if (sql_connect(conn->db) < 0 && worker) {
+ if (sql_connect(db) < 0 && worker) {
/* auth worker's sql connection failed. we can't do anything
useful until the connection works. there's no point in
having tons of worker processes all logging failures,
}
}
-void db_sql_success(struct db_sql_connection *conn ATTR_UNUSED)
+void db_sql_success(void)
{
if (worker)
auth_worker_server_send_success();
#include "sql-api.h"
-struct db_sql_settings {
- const char *driver;
- const char *connect;
- const char *password_query;
- const char *user_query;
- const char *update_query;
- const char *iterate_query;
- const char *default_pass_scheme;
-};
-
-struct db_sql_connection {
- struct db_sql_connection *next;
-
- pool_t pool;
- int refcount;
-
- char *config_path;
- struct db_sql_settings set;
- struct sql_db *db;
-};
-
-struct db_sql_connection *db_sql_init(const char *config_path);
-void db_sql_unref(struct db_sql_connection **conn);
-
-void db_sql_connect(struct db_sql_connection *conn);
-void db_sql_success(struct db_sql_connection *conn);
+void db_sql_connect(struct sql_db *db);
+void db_sql_success(void);
#endif
#ifdef PASSDB_SQL
#include "safe-memset.h"
+#include "settings.h"
+#include "settings-parser.h"
#include "password-scheme.h"
#include "auth-cache.h"
#include "db-sql.h"
struct sql_passdb_module {
struct passdb_module module;
- struct db_sql_connection *conn;
+ struct sql_db *db;
};
struct passdb_sql_request {
} callback;
};
+struct passdb_sql_settings {
+ pool_t pool;
+ const char *query;
+ const char *update_query;
+};
+#undef DEF
+#define DEF(type, name) \
+ SETTING_DEFINE_STRUCT_##type("passdb_sql_"#name, name, struct passdb_sql_settings)
+static const struct setting_define passdb_sql_setting_defines[] = {
+ DEF(STR, query),
+ DEF(STR, update_query),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static const struct passdb_sql_settings passdb_sql_default_settings = {
+ .query = "",
+ .update_query = "",
+};
+const struct setting_parser_info passdb_sql_setting_parser_info = {
+ .name = "passdb_sql",
+
+ .defines = passdb_sql_setting_defines,
+ .defaults = &passdb_sql_default_settings,
+
+ .struct_size = sizeof(struct passdb_sql_settings),
+ .pool_offset1 = 1 + offsetof(struct passdb_sql_settings, pool),
+};
+
static void sql_query_save_results(struct sql_result *result,
struct passdb_sql_request *sql_request)
{
struct auth_request *auth_request = sql_request->auth_request;
struct passdb_module *_module = auth_request->passdb->passdb;
- struct sql_passdb_module *module = (struct sql_passdb_module *)_module;
unsigned int i, fields_count;
const char *name, *value;
auth_request_set_null_field(auth_request, name);
else {
auth_request_set_field(auth_request, name, value,
- module->conn->set.default_pass_scheme);
+ _module->default_pass_scheme);
}
}
}
struct passdb_sql_request *sql_request)
{
struct auth_request *auth_request = sql_request->auth_request;
- struct passdb_module *_module = auth_request->passdb->passdb;
- struct sql_passdb_module *module = (struct sql_passdb_module *)_module;
enum passdb_result passdb_result;
const char *password, *scheme;
char *dup_password = NULL;
ret = sql_result_next_row(result);
if (ret >= 0)
- db_sql_success(module->conn);
+ db_sql_success();
if (ret < 0) {
e_error(authdb_event(auth_request), "Password query failed: %s",
sql_result_get_error(result));
auth_request_unref(&auth_request);
}
-static const char *
-passdb_sql_escape(const char *str, const struct auth_request *auth_request)
+static const char *passdb_sql_escape(const char *str, void *context)
{
- struct passdb_module *_module = auth_request->passdb->passdb;
- struct sql_passdb_module *module = (struct sql_passdb_module *)_module;
-
- return sql_escape_string(module->conn->db, str);
+ struct sql_db *db = context;
+ return sql_escape_string(db, str);
}
static void sql_lookup_pass(struct passdb_sql_request *sql_request)
{
struct passdb_module *_module =
sql_request->auth_request->passdb->passdb;
- struct sql_passdb_module *module = (struct sql_passdb_module *)_module;
- const char *query, *error;
-
- if (t_auth_request_var_expand(module->conn->set.password_query,
- sql_request->auth_request,
- passdb_sql_escape, &query, &error) <= 0) {
- e_debug(authdb_event(sql_request->auth_request),
- "Failed to expand password_query=%s: %s",
- module->conn->set.password_query, error);
- sql_request->callback.verify_plain(PASSDB_RESULT_INTERNAL_FAILURE,
- sql_request->auth_request);
+ struct sql_passdb_module *module =
+ container_of(_module, struct sql_passdb_module, module);
+ const struct passdb_sql_settings *set;
+ const char *error;
+
+ struct settings_get_params params = {
+ .escape_func = passdb_sql_escape,
+ .escape_context = module->db,
+ };
+ if (settings_get_params(authdb_event(sql_request->auth_request),
+ &passdb_sql_setting_parser_info, ¶ms,
+ &set, &error) < 0) {
+ e_error(authdb_event(sql_request->auth_request), "%s", error);
+ sql_request->callback.verify_plain(
+ PASSDB_RESULT_INTERNAL_FAILURE,
+ sql_request->auth_request);
return;
}
e_debug(authdb_event(sql_request->auth_request),
- "query: %s", query);
+ "query: %s", set->query);
auth_request_ref(sql_request->auth_request);
- sql_query(module->conn->db, query,
- sql_query_callback, sql_request);
+ sql_query(module->db, set->query, sql_query_callback, sql_request);
+ settings_free(set);
}
static void sql_verify_plain(struct auth_request *request,
set_credentials_callback_t *callback)
{
struct sql_passdb_module *module =
- (struct sql_passdb_module *) request->passdb->passdb;
+ container_of(request->passdb->passdb,
+ struct sql_passdb_module, module);
struct sql_transaction_context *transaction;
struct passdb_sql_request *sql_request;
- const char *query, *error;
+ const struct passdb_sql_settings *set;
+ const char *error;
request->mech_password = p_strdup(request->pool, new_credentials);
- if (t_auth_request_var_expand(module->conn->set.update_query,
- request, passdb_sql_escape,
- &query, &error) <= 0) {
- e_error(authdb_event(request),
- "Failed to expand update_query=%s: %s",
- module->conn->set.update_query, error);
+ if (settings_get(authdb_event(request), &passdb_sql_setting_parser_info, 0,
+ &set, &error) < 0) {
+ e_error(authdb_event(request), "%s", error);
callback(FALSE, request);
return;
}
sql_request->auth_request = request;
sql_request->callback.set_credentials = callback;
- transaction = sql_transaction_begin(module->conn->db);
- sql_update(transaction, query);
+ transaction = sql_transaction_begin(module->db);
+ sql_update(transaction, set->update_query);
sql_transaction_commit(&transaction,
sql_set_credentials_callback, sql_request);
+ settings_free(set);
}
-static struct passdb_module *
-passdb_sql_preinit(pool_t pool, const char *args)
+static int
+passdb_sql_preinit(pool_t pool, struct event *event,
+ struct passdb_module **module_r, const char **error_r)
{
struct sql_passdb_module *module;
- struct db_sql_connection *conn;
+ const struct passdb_sql_settings *set;
+
+ if (settings_get(event, &passdb_sql_setting_parser_info,
+ SETTINGS_GET_FLAG_NO_CHECK |
+ SETTINGS_GET_FLAG_NO_EXPAND,
+ &set, error_r) < 0)
+ return -1;
module = p_new(pool, struct sql_passdb_module, 1);
- module->conn = conn = db_sql_init(args);
+ if (sql_init_auto(event, &module->db, error_r) <= 0) {
+ settings_free(set);
+ return -1;
+ }
module->module.default_cache_key =
- auth_cache_parse_key(pool, conn->set.password_query);
- module->module.default_pass_scheme = conn->set.default_pass_scheme;
- return &module->module;
+ auth_cache_parse_key(pool, set->query);
+ settings_free(set);
+
+ *module_r = &module->module;
+ return 0;
}
static void passdb_sql_init(struct passdb_module *_module)
{
struct sql_passdb_module *module =
- (struct sql_passdb_module *)_module;
+ container_of(_module, struct sql_passdb_module, module);
enum sql_db_flags flags;
- flags = sql_get_flags(module->conn->db);
+ flags = sql_get_flags(module->db);
module->module.blocking = (flags & SQL_DB_FLAG_BLOCKING) != 0;
if (!module->module.blocking || worker)
- db_sql_connect(module->conn);
+ db_sql_connect(module->db);
}
static void passdb_sql_deinit(struct passdb_module *_module)
{
struct sql_passdb_module *module =
- (struct sql_passdb_module *)_module;
+ container_of(_module, struct sql_passdb_module, module);
- db_sql_unref(&module->conn);
+ /* Abort any pending requests, even if the database is still
+ kept referenced. */
+ sql_disconnect(module->db);
+ sql_unref(&module->db);
}
struct passdb_module_interface passdb_sql = {
.name = "sql",
+ .fields_supported = TRUE,
- .preinit_legacy = passdb_sql_preinit,
+ .preinit = passdb_sql_preinit,
.init = passdb_sql_init,
.deinit = passdb_sql_deinit,
#ifdef USERDB_SQL
+#include "settings.h"
+#include "settings-parser.h"
#include "auth-cache.h"
#include "db-sql.h"
struct sql_userdb_module {
struct userdb_module module;
- struct db_sql_connection *conn;
+ struct sql_db *db;
};
struct userdb_sql_request {
bool call_iter:1;
};
+struct userdb_sql_settings {
+ pool_t pool;
+ const char *query;
+ const char *iterate_query;
+};
+#undef DEF
+#define DEF(type, name) \
+ SETTING_DEFINE_STRUCT_##type("userdb_sql_"#name, name, struct userdb_sql_settings)
+static const struct setting_define userdb_sql_setting_defines[] = {
+ DEF(STR, query),
+ DEF(STR, iterate_query),
+
+ SETTING_DEFINE_LIST_END
+};
+static const struct userdb_sql_settings userdb_sql_default_settings = {
+ .query = "",
+ .iterate_query = "",
+};
+const struct setting_parser_info userdb_sql_setting_parser_info = {
+ .name = "userdb_sql",
+
+ .defines = userdb_sql_setting_defines,
+ .defaults = &userdb_sql_default_settings,
+
+ .struct_size = sizeof(struct userdb_sql_settings),
+ .pool_offset1 = 1 + offsetof(struct userdb_sql_settings, pool),
+};
+
static void userdb_sql_iterate_next(struct userdb_iterate_context *_ctx);
static int userdb_sql_iterate_deinit(struct userdb_iterate_context *_ctx);
struct userdb_sql_request *sql_request)
{
struct auth_request *auth_request = sql_request->auth_request;
- struct userdb_module *_module = auth_request->userdb->userdb;
- struct sql_userdb_module *module =
- (struct sql_userdb_module *)_module;
enum userdb_result result = USERDB_RESULT_INTERNAL_FAILURE;
int ret;
ret = sql_result_next_row(sql_result);
if (ret >= 0)
- db_sql_success(module->conn);
+ db_sql_success();
if (ret < 0) {
e_error(authdb_event(auth_request), "User query failed: %s",
sql_result_get_error(sql_result));
i_free(sql_request);
}
-static const char *
-userdb_sql_escape(const char *str, const struct auth_request *auth_request)
+static const char *userdb_sql_escape(const char *str, void *context)
{
- struct userdb_module *_module = auth_request->userdb->userdb;
- struct sql_userdb_module *module =
- (struct sql_userdb_module *)_module;
-
- return sql_escape_string(module->conn->db, str);
+ struct sql_db *db = context;
+ return sql_escape_string(db, str);
}
static void userdb_sql_lookup(struct auth_request *auth_request,
{
struct userdb_module *_module = auth_request->userdb->userdb;
struct sql_userdb_module *module =
- (struct sql_userdb_module *)_module;
+ container_of(_module, struct sql_userdb_module, module);
struct userdb_sql_request *sql_request;
- const char *query, *error;
-
- if (t_auth_request_var_expand(module->conn->set.user_query,
- auth_request, userdb_sql_escape,
- &query, &error) <= 0) {
- e_error(authdb_event(auth_request),
- "Failed to expand user_query=%s: %s",
- module->conn->set.user_query, error);
+ const struct userdb_sql_settings *set;
+ const char *error;
+
+ struct settings_get_params params = {
+ .escape_func = userdb_sql_escape,
+ .escape_context = module->db,
+ };
+ if (settings_get_params(authdb_event(auth_request),
+ &userdb_sql_setting_parser_info, ¶ms,
+ &set, &error) < 0) {
+ e_error(authdb_event(auth_request), "%s", error);
callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
return;
}
sql_request->callback = callback;
sql_request->auth_request = auth_request;
- e_debug(authdb_event(auth_request), "%s", query);
+ e_debug(authdb_event(auth_request), "%s", set->query);
- sql_query(module->conn->db, query,
- sql_query_callback, sql_request);
+ sql_query(module->db, set->query, sql_query_callback, sql_request);
+ settings_free(set);
}
static void sql_iter_query_callback(struct sql_result *sql_result,
{
struct userdb_module *_module = auth_request->userdb->userdb;
struct sql_userdb_module *module =
- (struct sql_userdb_module *)_module;
+ container_of(_module, struct sql_userdb_module, module);
struct sql_userdb_iterate_context *ctx;
- const char *query, *error;
+ const struct userdb_sql_settings *set;
+ const char *error;
ctx = i_new(struct sql_userdb_iterate_context, 1);
ctx->ctx.auth_request = auth_request;
ctx->ctx.context = context;
auth_request_ref(auth_request);
- if (t_auth_request_var_expand(module->conn->set.iterate_query,
- auth_request, userdb_sql_escape,
- &query, &error) <= 0) {
- e_error(authdb_event(auth_request),
- "Failed to expand iterate_query=%s: %s",
- module->conn->set.iterate_query, error);
+ if (settings_get(authdb_event(auth_request),
+ &userdb_sql_setting_parser_info, 0,
+ &set, &error) < 0) {
+ e_error(authdb_event(auth_request), "%s", error);
ctx->ctx.failed = TRUE;
return &ctx->ctx;
}
- sql_query(module->conn->db, query,
- sql_iter_query_callback, ctx);
- e_debug(authdb_event(auth_request), "%s", query);
+ sql_query(module->db, set->iterate_query, sql_iter_query_callback, ctx);
+ e_debug(authdb_event(auth_request), "%s", set->iterate_query);
+ settings_free(set);
return &ctx->ctx;
}
static void userdb_sql_iterate_next(struct userdb_iterate_context *_ctx)
{
struct sql_userdb_iterate_context *ctx =
- (struct sql_userdb_iterate_context *)_ctx;
- struct userdb_module *_module = _ctx->auth_request->userdb->userdb;
- struct sql_userdb_module *module = (struct sql_userdb_module *)_module;
+ container_of(_ctx, struct sql_userdb_iterate_context, ctx);
const char *user;
int ret;
ret = sql_result_next_row(ctx->result);
if (ret >= 0)
- db_sql_success(module->conn);
+ db_sql_success();
if (ret > 0) {
if (userdb_sql_iterate_get_user(ctx, &user) < 0)
e_error(authdb_event(_ctx->auth_request),
static int userdb_sql_iterate_deinit(struct userdb_iterate_context *_ctx)
{
struct sql_userdb_iterate_context *ctx =
- (struct sql_userdb_iterate_context *)_ctx;
+ container_of(_ctx, struct sql_userdb_iterate_context, ctx);
int ret = _ctx->failed ? -1 : 0;
auth_request_unref(&_ctx->auth_request);
return ret;
}
-static struct userdb_module *
-userdb_sql_preinit(pool_t pool, const char *args)
+static int
+userdb_sql_preinit(pool_t pool, struct event *event,
+ struct userdb_module **module_r, const char **error_r)
{
struct sql_userdb_module *module;
+ const struct userdb_sql_settings *set;
+
+ if (settings_get(event, &userdb_sql_setting_parser_info,
+ SETTINGS_GET_FLAG_NO_CHECK |
+ SETTINGS_GET_FLAG_NO_EXPAND,
+ &set, error_r) < 0)
+ return -1;
module = p_new(pool, struct sql_userdb_module, 1);
- module->conn = db_sql_init(args);
+ if (sql_init_auto(event, &module->db, error_r) <= 0) {
+ settings_free(set);
+ return -1;
+ }
module->module.default_cache_key =
- auth_cache_parse_key(pool, module->conn->set.user_query);
- return &module->module;
+ auth_cache_parse_key(pool, set->query);
+ settings_free(set);
+ *module_r = &module->module;
+ return 0;
}
static void userdb_sql_init(struct userdb_module *_module)
{
struct sql_userdb_module *module =
- (struct sql_userdb_module *)_module;
+ container_of(_module, struct sql_userdb_module, module);
enum sql_db_flags flags;
- flags = sql_get_flags(module->conn->db);
+ flags = sql_get_flags(module->db);
_module->blocking = (flags & SQL_DB_FLAG_BLOCKING) != 0;
if (!_module->blocking || worker)
- db_sql_connect(module->conn);
+ db_sql_connect(module->db);
}
static void userdb_sql_deinit(struct userdb_module *_module)
{
struct sql_userdb_module *module =
- (struct sql_userdb_module *)_module;
+ container_of(_module, struct sql_userdb_module, module);
- db_sql_unref(&module->conn);
+ /* Abort any pending requests, even if the database is still
+ kept referenced. */
+ sql_disconnect(module->db);
+ sql_unref(&module->db);
}
struct userdb_module_interface userdb_sql = {
.name = "sql",
- .preinit_legacy = userdb_sql_preinit,
+ .preinit = userdb_sql_preinit,
.init = userdb_sql_init,
.deinit = userdb_sql_deinit,