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