]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: passdb/userdb sql - Convert to new settings
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sun, 3 Mar 2024 15:00:32 +0000 (17:00 +0200)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 12 Feb 2025 10:34:12 +0000 (12:34 +0200)
sql_drivers_deinit() needed to be moved earlier, because the sql_db is
now kept in cache until it's called. In the earlier code the sql_db was
deinitialized when the passdb/userdb sql was deinitialized. If the
sql_db deinit happens too late, it's late in aborting requests and that
causes crashes.

src/auth/db-sql.c
src/auth/db-sql.h
src/auth/passdb-sql.c
src/auth/userdb-sql.c

index 953dd32b1a8d76af697987ec7b1cee3b35942615..a3a23fdfab25c554c18d4fd4832eb4e0585299cb 100644 (file)
 
 #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,
@@ -134,7 +21,7 @@ void db_sql_connect(struct db_sql_connection *conn)
        }
 }
 
-void db_sql_success(struct db_sql_connection *conn ATTR_UNUSED)
+void db_sql_success(void)
 {
        if (worker)
                auth_worker_server_send_success();
index 81e5401da341e09e1acba8f021925f9f8758a095..d3c786f293b31a38526878368f5f27ad5c2ca6c1 100644 (file)
@@ -3,31 +3,7 @@
 
 #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
index 0658ba0723b084afc1269168e19c94244bb80741..aab83459e04726d3bb32c6e51ddf5c820d5c2679 100644 (file)
@@ -6,6 +6,8 @@
 #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"
@@ -15,7 +17,7 @@
 struct sql_passdb_module {
        struct passdb_module module;
 
-       struct db_sql_connection *conn;
+       struct sql_db *db;
 };
 
 struct passdb_sql_request {
@@ -27,12 +29,40 @@ 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;
 
@@ -47,7 +77,7 @@ static void sql_query_save_results(struct sql_result *result,
                        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);
                }
        }
 }
@@ -56,8 +86,6 @@ static void sql_query_callback(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;
        enum passdb_result passdb_result;
        const char *password, *scheme;
        char *dup_password = NULL;
@@ -68,7 +96,7 @@ static void sql_query_callback(struct sql_result *result,
 
        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));
@@ -133,39 +161,41 @@ static void sql_query_callback(struct sql_result *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, &params,
+                               &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,
@@ -213,19 +243,18 @@ static void sql_set_credentials(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;
        }
@@ -234,52 +263,69 @@ static void sql_set_credentials(struct auth_request *request,
        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,
 
index 5c59c7d2f197e2722c10eea159605fe9374d4820..ffba715e28e53a93d9f76febd3685348d0b49852 100644 (file)
@@ -5,6 +5,8 @@
 
 #ifdef USERDB_SQL
 
+#include "settings.h"
+#include "settings-parser.h"
 #include "auth-cache.h"
 #include "db-sql.h"
 
@@ -13,7 +15,7 @@
 struct sql_userdb_module {
        struct userdb_module module;
 
-       struct db_sql_connection *conn;
+       struct sql_db *db;
 };
 
 struct userdb_sql_request {
@@ -28,6 +30,34 @@ struct sql_userdb_iterate_context {
        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);
 
@@ -54,15 +84,12 @@ static void sql_query_callback(struct sql_result *sql_result,
                               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));
@@ -79,14 +106,10 @@ static void sql_query_callback(struct sql_result *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,
@@ -94,16 +117,19 @@ 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, &params,
+                               &set, &error) < 0) {
+               e_error(authdb_event(auth_request), "%s", error);
                callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
                return;
        }
@@ -113,10 +139,10 @@ static void userdb_sql_lookup(struct auth_request *auth_request,
        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,
@@ -137,9 +163,10 @@ userdb_sql_iterate_init(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 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;
@@ -147,19 +174,17 @@ userdb_sql_iterate_init(struct 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;
 }
 
@@ -196,9 +221,7 @@ static int userdb_sql_iterate_get_user(struct sql_userdb_iterate_context *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;
 
@@ -214,7 +237,7 @@ static void userdb_sql_iterate_next(struct userdb_iterate_context *_ctx)
 
        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),
@@ -239,7 +262,7 @@ static void userdb_sql_iterate_next(struct userdb_iterate_context *_ctx)
 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);
@@ -254,44 +277,60 @@ static int userdb_sql_iterate_deinit(struct userdb_iterate_context *_ctx)
        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,