db-sql.c revision 803197abb1cc0e81abb668c026c22394bfef820d
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "auth-common.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#if defined(PASSDB_SQL) || defined(USERDB_SQL)
2fbc2a7c65d30e46803195ebb4547176b85c22c7Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "settings.h"
3c9783956dea385b322cd7fa6bf8c98c17a907a0Timo Sirainen#include "auth-request.h"
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen#include "auth-worker-client.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include "db-sql.h"
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include <stddef.h>
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#include <stdlib.h>
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen#define DEF_STR(name) DEF_STRUCT_STR(name, sql_settings)
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen#define DEF_INT(name) DEF_STRUCT_INT(name, sql_settings)
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, sql_settings)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic struct setting_def setting_defs[] = {
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(driver),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(connect),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(password_query),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(user_query),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(update_query),
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen DEF_STR(iterate_query),
a84eb0599fa1d796206eaed65c4e3239f0799276Timo Sirainen DEF_STR(default_pass_scheme),
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen DEF_BOOL(userdb_warning_disable),
e25885d4c7c4b392c66bbf26a9b892362d90f001Timo Sirainen
e25885d4c7c4b392c66bbf26a9b892362d90f001Timo Sirainen { 0, NULL, 0 }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen};
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
ab0d9eecd85f74acae18fe88529302e0776cc500Timo Sirainenstatic struct sql_settings default_sql_settings = {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .driver = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .connect = NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .password_query = "SELECT username, domain, password FROM users WHERE username = '%n' AND domain = '%d'",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .user_query = "SELECT home, uid, gid FROM users WHERE username = '%n' AND domain = '%d'",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .update_query = "UPDATE users SET password = '%w' WHERE username = '%n' AND domain = '%d'",
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .iterate_query = "SELECT username, domain FROM users",
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen .default_pass_scheme = "MD5",
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen .userdb_warning_disable = FALSE
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen};
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic struct sql_connection *connections = NULL;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic struct sql_connection *sql_conn_find(const char *config_path)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct sql_connection *conn;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen for (conn = connections; conn != NULL; conn = conn->next) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (strcmp(conn->config_path, config_path) == 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return conn;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return NULL;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainenstatic const char *parse_setting(const char *key, const char *value,
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen struct sql_connection *conn)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return parse_setting_from_defs(conn->pool, setting_defs,
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen &conn->set, key, value);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainenstruct sql_connection *db_sql_init(const char *config_path, bool userdb)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct sql_connection *conn;
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen const char *error;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen pool_t pool;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen conn = sql_conn_find(config_path);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (conn != NULL) {
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen if (userdb)
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen conn->userdb_used = TRUE;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen conn->refcount++;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return conn;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
2e1e493b248dec0127b1eabeea5a8bc330378fcdTimo Sirainen if (*config_path == '\0')
b7828b34f6d81cdea62761932a1da1a444a29bcdTimo Sirainen i_fatal("sql: Configuration file path not given");
2e1e493b248dec0127b1eabeea5a8bc330378fcdTimo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen pool = pool_alloconly_create("sql_connection", 1024);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen conn = p_new(pool, struct sql_connection, 1);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen conn->pool = pool;
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen conn->userdb_used = userdb;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen conn->refcount = 1;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen conn->config_path = p_strdup(pool, config_path);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen conn->set = default_sql_settings;
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen if (!settings_read_nosection(config_path, parse_setting, conn, &error))
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen i_fatal("sql %s: %s", config_path, error);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
48010d123abfac8cb19f33f1fe12f33a7090089eTimo Sirainen if (conn->set.password_query == default_sql_settings.password_query)
48010d123abfac8cb19f33f1fe12f33a7090089eTimo Sirainen conn->default_password_query = TRUE;
48010d123abfac8cb19f33f1fe12f33a7090089eTimo Sirainen if (conn->set.user_query == default_sql_settings.user_query)
48010d123abfac8cb19f33f1fe12f33a7090089eTimo Sirainen conn->default_user_query = TRUE;
48010d123abfac8cb19f33f1fe12f33a7090089eTimo Sirainen if (conn->set.update_query == default_sql_settings.update_query)
48010d123abfac8cb19f33f1fe12f33a7090089eTimo Sirainen conn->default_update_query = TRUE;
48010d123abfac8cb19f33f1fe12f33a7090089eTimo Sirainen if (conn->set.iterate_query == default_sql_settings.iterate_query)
48010d123abfac8cb19f33f1fe12f33a7090089eTimo Sirainen conn->default_iterate_query = TRUE;
48010d123abfac8cb19f33f1fe12f33a7090089eTimo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (conn->set.driver == NULL) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_fatal("sql: driver not set in configuration file %s",
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen config_path);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (conn->set.connect == NULL) {
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen i_fatal("sql: connect string not set in configuration file %s",
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen config_path);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen }
f8a86fdfb0048f9c87bf223373b35416ceb5856bTimo Sirainen conn->db = sql_init(conn->set.driver, conn->set.connect);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen conn->next = connections;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen connections = conn;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return conn;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid db_sql_unref(struct sql_connection **_conn)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct sql_connection *conn = *_conn;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
607f0cc7310ae7ecde7c96f67945026a128d8174Timo Sirainen /* abort all pending auth requests before setting conn to NULL,
607f0cc7310ae7ecde7c96f67945026a128d8174Timo Sirainen so that callbacks can still access it */
607f0cc7310ae7ecde7c96f67945026a128d8174Timo Sirainen sql_disconnect(conn->db);
607f0cc7310ae7ecde7c96f67945026a128d8174Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_conn = NULL;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen if (--conn->refcount > 0)
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen return;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen sql_deinit(&conn->db);
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen pool_unref(&conn->pool);
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen}
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenvoid db_sql_connect(struct sql_connection *conn)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen{
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (sql_connect(conn->db) < 0 && worker) {
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen /* auth worker's sql connection failed. we can't do anything
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen useful until the connection works. there's no point in
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen having tons of worker processes all logging failures,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen so tell the auth master to stop creating new workers (and
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen maybe close old ones). this handling is especially useful if
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen we reach the max. number of connections for sql server. */
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen auth_worker_client_send_error();
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen }
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen}
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenvoid db_sql_success(struct sql_connection *conn ATTR_UNUSED)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen{
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (worker)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen auth_worker_client_send_success();
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen}
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainenvoid db_sql_check_userdb_warning(struct sql_connection *conn)
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen{
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen if (worker || conn->userdb_used || conn->set.userdb_warning_disable)
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen return;
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen if (strcmp(conn->set.user_query,
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen default_sql_settings.user_query) != 0) {
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen i_warning("sql: Ignoring changed user_query in %s, "
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen "because userdb sql not used. "
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen "(If this is intentional, set userdb_warning_disable=yes)",
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen conn->config_path);
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen } else if (strcmp(conn->set.iterate_query,
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen default_sql_settings.iterate_query) != 0) {
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen i_warning("sql: Ignoring changed iterate_query in %s, "
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen "because userdb sql not used. "
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen "(If this is intentional, set userdb_warning_disable=yes)",
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen conn->config_path);
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen }
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen}
e665999b757e60bfb98e5a84a78b05f061453140Timo Sirainen
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen#endif