view src/auth/db-mysql.c @ 2371:d216ff496d01 HEAD

whops, removed debugging
author Timo Sirainen <tss@iki.fi>
date Mon, 26 Jul 2004 20:11:15 +0300
parents 189a6de6b166
children cc2e39912eb3
line wrap: on
line source

/* Copyright (C) 2003 Alex Howansky, Timo Sirainen */

#include "config.h"
#undef HAVE_CONFIG_H

#if defined(PASSDB_MYSQL) || defined(USERDB_MYSQL)
#include "common.h"
#include "network.h"
#include "str.h"
#include "settings.h"
#include "db-mysql.h"

#include <limits.h>
#include <stddef.h>
#include <stdlib.h>

#define DEF(type, name) { type, #name, offsetof(struct mysql_settings, name) }

static struct setting_def setting_defs[] = {
	DEF(SET_STR, db_host),
	DEF(SET_INT, db_port),
	DEF(SET_STR, db_unix_socket),
	DEF(SET_STR, db),
	DEF(SET_STR, db_user),
	DEF(SET_STR, db_passwd),
	DEF(SET_INT, db_client_flags),
	DEF(SET_STR, ssl_key),
	DEF(SET_STR, ssl_cert),
	DEF(SET_STR, ssl_ca),
	DEF(SET_STR, ssl_ca_path),
	DEF(SET_STR, ssl_cipher),
	DEF(SET_STR, password_query),
	DEF(SET_STR, user_query),
	DEF(SET_STR, default_pass_scheme)
};

struct mysql_settings default_mysql_settings = {
	MEMBER(db_host) "localhost",
	MEMBER(db_port) 0,
	MEMBER(db_unix_socket) NULL,
	MEMBER(db) NULL,
	MEMBER(db_user) NULL,
	MEMBER(db_passwd) NULL,
	MEMBER(db_client_flags) 0,
	MEMBER(ssl_key) NULL,
	MEMBER(ssl_cert) NULL,
	MEMBER(ssl_ca) NULL,
	MEMBER(ssl_ca_path) NULL,
	MEMBER(ssl_cipher) "HIGH",
	MEMBER(password_query) "SELECT password FROM users WHERE userid = '%u'",
	MEMBER(user_query) "SELECT home, uid, gid FROM users WHERE userid = '%u'",
	MEMBER(default_pass_scheme) "PLAIN-MD5"
};

static struct mysql_connection *mysql_connections = NULL;

static int mysql_conn_open(struct mysql_connection *conn);
static void mysql_conn_close(struct mysql_connection *conn);

void db_mysql_query(struct mysql_connection *conn, const char *query,
		    struct mysql_request *request)
{
	MYSQL_RES *res = NULL;
	int failed;

	if (verbose_debug)
		i_info("MySQL: Performing query: %s", query);

	if (!conn->connected) {
		if (!mysql_conn_open(conn)) {
			request->callback(conn, request, NULL);
			return;
		}
	}

	failed = mysql_query(conn->mysql, query) != 0;
	if (failed) {
		/* query failed */
		switch (mysql_errno(conn->mysql)) {
		case CR_SERVER_GONE_ERROR:
		case CR_SERVER_LOST:
			/* connection lost - try immediate reconnect */
			if (!mysql_conn_open(conn))
				break;
			if (mysql_query(conn->mysql, query) == 0) {
				failed = FALSE;
				break;
			}
			/* query failed, fallback to error handler */
		default:
			i_error("MySQL: Error executing query \"%s\": %s",
				query, mysql_error(conn->mysql));
			break;
		}
	}

	if (!failed) {
		/* query succeeded */
		if ((res = mysql_store_result(conn->mysql)) == NULL) {
			/* something went wrong on storing result */
			failed = TRUE;
			i_error("MySQL: Error retrieving results: %s",
				mysql_error(conn->mysql));
		}
	}

	request->callback(conn, request, res);
	if (!failed)
		mysql_free_result(res);
	i_free(request);
}

static int mysql_conn_open(struct mysql_connection *conn)
{
	int use_ssl = FALSE;

	if (conn->connected)
		return TRUE;

	if (conn->mysql == NULL) {
		conn->mysql = mysql_init(NULL);
		if (conn->mysql == NULL) {
			i_error("MySQL: mysql_init failed");
			return FALSE;
		}
	}

#ifdef HAVE_MYSQL_SSL
	if (conn->set.ssl_ca != NULL || conn->set.ssl_ca_path != NULL) {
		mysql_ssl_set(conn->mysql, conn->set.ssl_key,
			      conn->set.ssl_cert,
			      conn->set.ssl_ca,
			      conn->set.ssl_ca_path
#ifdef HAVE_MYSQL_SSL_CIPHER
			      ,conn->set.ssl_cipher
#endif
			     );
		use_ssl = TRUE;
	}
#endif

	if (mysql_real_connect(conn->mysql, conn->set.db_host,
			       conn->set.db_user, conn->set.db_passwd,
			       conn->set.db,
			       conn->set.db_port,
			       conn->set.db_unix_socket,
			       conn->set.db_client_flags) == NULL) {
		i_error("MySQL: Can't connect to database %s: %s",
			conn->set.db, mysql_error(conn->mysql));
	} else {
		conn->connected = TRUE;
		i_info("MySQL: connected to %s%s", conn->set.db_host,
		       use_ssl ? "using SSL" : "");
	}
	
	return conn->connected;
}

static void mysql_conn_close(struct mysql_connection *conn)
{
	conn->connected = FALSE;

	if (conn->mysql != NULL) {
		mysql_close(conn->mysql);
		conn->mysql = NULL;
	}
}

static struct mysql_connection *mysql_conn_find(const char *config_path)
{
	struct mysql_connection *conn;

	for (conn = mysql_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,
				 void *context)
{
	struct mysql_connection *conn = context;

	return parse_setting_from_defs(conn->pool, setting_defs,
				       &conn->set, key, value);
}

struct mysql_connection *db_mysql_init(const char *config_path)
{
	struct mysql_connection *conn;
	pool_t pool;

	conn = mysql_conn_find(config_path);
	if (conn != NULL) {
		conn->refcount++;
		return conn;
	}

	pool = pool_alloconly_create("mysql_connection", 1024);
	conn = p_new(pool, struct mysql_connection, 1);
	conn->pool = pool;

	conn->refcount = 1;

	conn->config_path = p_strdup(pool, config_path);
	conn->set = default_mysql_settings;
	if (!settings_read(config_path, NULL, parse_setting, NULL, conn))
		exit(FATAL_DEFAULT);

	if (conn->set.db == NULL)
		i_fatal("MySQL: db variable isn't set in config file");
	if (conn->set.db_user == NULL)
		i_fatal("MySQL: db_user variable isn't set in config file");

	(void)mysql_conn_open(conn);

	conn->next = mysql_connections;
	mysql_connections = conn;
	return conn;
}

void db_mysql_unref(struct mysql_connection *conn)
{
	if (--conn->refcount > 0)
		return;

	mysql_conn_close(conn);
	pool_unref(conn->pool);
}

#endif