passdb-sql.c revision f8a86fdfb0048f9c87bf223373b35416ceb5856b
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (C) 2004 Timo Sirainen, Alex Howansky */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "config.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#undef HAVE_CONFIG_H
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#ifdef PASSDB_SQL
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "common.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "str.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "strescape.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "var-expand.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "password-scheme.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "auth-cache.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "db-sql.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "passdb.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
e9c433c5b8ef9a1b4246ebe10beb90fa01e05cafPhil Carmody#include <stdlib.h>
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include <string.h>
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschextern struct passdb_module passdb_sql;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstruct passdb_sql_request {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct auth_request *auth_request;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch enum passdb_credentials credentials;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch union {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch verify_plain_callback_t *verify_plain;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch lookup_credentials_callback_t *lookup_credentials;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } callback;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch};
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic struct sql_connection *passdb_sql_conn;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic char *passdb_sql_cache_key;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void sql_query_save_results(struct sql_result *result,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct passdb_sql_request *sql_request)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct auth_request *auth_request = sql_request->auth_request;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i, fields_count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *name, *value;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch fields_count = sql_result_get_fields_count(result);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (i = 0; i < fields_count; i++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch name = sql_result_get_field_name(result, i);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch value = sql_result_get_field_value(result, i);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (value != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_request_set_field(auth_request, name, value,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_sql_conn->set.default_pass_scheme);
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void sql_query_callback(struct sql_result *result, void *context)
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch{
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch struct passdb_sql_request *sql_request = context;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct auth_request *auth_request = sql_request->auth_request;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch enum passdb_result passdb_result;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *user, *password, *scheme;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch int ret;
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch user = auth_request->user;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch password = NULL;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ret = sql_result_next_row(result);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ret < 0) {
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch auth_request_log_error(auth_request, "sql",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Password query failed: %s",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_result_get_error(result));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else if (ret == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_request_log_info(auth_request, "sql", "unknown user");
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_result = PASSDB_RESULT_USER_UNKNOWN;
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_query_save_results(result, sql_request);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* Note that we really want to check if the password field is
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch found. Just checking if password is set isn't enough,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch because with proxies we might want to return NULL as
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch password. */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (sql_result_find_field(result, "password") < 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_request_log_error(auth_request, "sql",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Password query must return a field named "
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "'password'");
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else if (sql_result_next_row(result) > 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_request_log_error(auth_request, "sql",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Password query returned multiple matches");
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch password = auth_request->passdb_password;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_result = PASSDB_RESULT_OK;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch scheme = password_get_scheme(&password);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* auth_request_set_field() sets scheme */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert(password == NULL || scheme != NULL);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (sql_request->credentials != -1) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_handle_credentials(passdb_result,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_request->credentials, password, scheme,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_request->callback.lookup_credentials,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_request);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* verify plain */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (password == NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_request->callback.verify_plain(passdb_result, auth_request);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ret = password_verify(auth_request->mech_password, password,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch scheme, user);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ret < 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch auth_request_log_error(auth_request, "sql",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Unknown password scheme %s", scheme);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else if (ret == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_request_log_info(auth_request, "sql", "Password mismatch");
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch sql_request->callback.verify_plain(ret > 0 ? PASSDB_RESULT_OK :
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch PASSDB_RESULT_PASSWORD_MISMATCH,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_request);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void sql_lookup_pass(struct passdb_sql_request *sql_request)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch string_t *query;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch query = t_str_new(512);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch var_expand(query, passdb_sql_conn->set.password_query,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_request_get_var_expand_table(sql_request->auth_request,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch str_escape));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_request_log_debug(sql_request->auth_request, "sql",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "query: %s", str_c(query));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_query(passdb_sql_conn->db, str_c(query),
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_query_callback, sql_request);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void sql_verify_plain(struct auth_request *request,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *password __attr_unused__,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch verify_plain_callback_t *callback)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct passdb_sql_request *sql_request;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_request = p_new(request->pool, struct passdb_sql_request, 1);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_request->auth_request = request;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_request->credentials = -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch sql_request->callback.verify_plain = callback;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_lookup_pass(sql_request);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void sql_lookup_credentials(struct auth_request *request,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch enum passdb_credentials credentials,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch lookup_credentials_callback_t *callback)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct passdb_sql_request *sql_request;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_request = p_new(request->pool, struct passdb_sql_request, 1);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_request->auth_request = request;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_request->credentials = credentials;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_request->callback.lookup_credentials = callback;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_lookup_pass(sql_request);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void passdb_sql_preinit(const char *args)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_sql_conn = db_sql_init(args);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_sql.cache_key = passdb_sql_cache_key =
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth_cache_parse_key(passdb_sql_conn->set.password_query);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_sql.default_pass_scheme =
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch passdb_sql_conn->set.default_pass_scheme;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void passdb_sql_init(const char *args __attr_unused__)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch enum sql_db_flags flags;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch flags = sql_get_flags(passdb_sql_conn->db);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_sql.blocking = (flags & SQL_DB_FLAG_BLOCKING) != 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!passdb_sql.blocking || worker)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_connect(passdb_sql_conn->db);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void passdb_sql_deinit(void)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch db_sql_unref(passdb_sql_conn);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_free(passdb_sql_cache_key);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstruct passdb_module passdb_sql = {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "sql",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch NULL, NULL, FALSE,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_sql_preinit,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_sql_init,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch passdb_sql_deinit,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_verify_plain,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sql_lookup_credentials
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch};
17c29e3e2246972c3d988e05d91b9286398a624fStephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#endif
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch