[dovecot-cvs] dovecot/src/auth db-mysql.c, NONE, 1.1 db-mysql.h, NONE, 1.1 passdb-mysql.c, NONE, 1.1 userdb-mysql.c, NONE, 1.1 Makefile.am, 1.23, 1.24 passdb.c, 1.13, 1.14 passdb.h, 1.8, 1.9 userdb.c, 1.7, 1.8 userdb.h, 1.7, 1.8

cras at procontrol.fi cras at procontrol.fi
Mon May 10 04:47:11 EEST 2004


Update of /home/cvs/dovecot/src/auth
In directory talvi:/tmp/cvs-serv31516/src/auth

Modified Files:
	Makefile.am passdb.c passdb.h userdb.c userdb.h 
Added Files:
	db-mysql.c db-mysql.h passdb-mysql.c userdb-mysql.c 
Log Message:
MySQL authentication patch by Matther Reimer



--- NEW FILE: db-mysql.c ---
/* 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_STR, db_port),
	DEF(SET_STR, db_unix_socket),
	DEF(SET_STR, db),
	DEF(SET_STR, db_user),
	DEF(SET_STR, db_passwd),
	DEF(SET_STR, db_client_flags),
	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) "/var/tmp/mysql.sock",
	MEMBER(db) "email_accounts",
	MEMBER(db_user) "dovecot",
	MEMBER(db_passwd) "changeme",
	MEMBER(db_client_flags) "0",
	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;
	int failed;

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

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

	if (mysql_query(conn->mysql, query))
		i_info("MYSQL: Error executing query \"%s\": %s", query,
		       mysql_error(conn->mysql));

	if ((res = mysql_store_result(conn->mysql)))
		failed = FALSE;
	else {
		i_info("MYSQL: Error retrieving results: %s",
		       mysql_error(conn->mysql));
		failed = TRUE;
	}

	request->callback(conn, request, failed ? NULL : res);
	mysql_free_result(res);
	i_free(request);
}

static int mysql_conn_open(struct mysql_connection *conn)
{
	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;
		}

		if (!mysql_real_connect(conn->mysql, conn->set.db_host,
					conn->set.db_user, conn->set.db_passwd,
					conn->set.db,
					atoi(conn->set.db_port),
					conn->set.db_unix_socket,
					strtoul(conn->set.db_client_flags,
						NULL, 10))) {
			i_error("MYSQL: Can't connect to database %s: %s",
				conn->set.db, mysql_error(conn->mysql));
			return FALSE;
		}
	}

	conn->connected = TRUE;
	return TRUE;
}

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);

	(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

--- NEW FILE: db-mysql.h ---
#ifndef __DB_MYSQL_H
#define __DB_MYSQL_H

#ifdef HAVE_MYSQL_MYSQL_H
#  include <mysql/mysql.h>
#else
#  include <mysql.h>
#endif

struct mysql_connection;
struct mysql_request;

typedef void mysql_query_callback_t(struct mysql_connection *conn,
				    struct mysql_request *request,
				    MYSQL_RES *res);

struct mysql_settings {
	const char *db_host;
	const char *db_port;
	const char *db_unix_socket;
	const char *db;
	const char *db_user;
	const char *db_passwd;
	const char *db_client_flags;
	const char *password_query;
	const char *user_query;
	const char *default_pass_scheme;
};

struct mysql_connection {
	struct mysql_connection *next;

	pool_t pool;
	int refcount;

	char *config_path;
	struct mysql_settings set;

	MYSQL *mysql;

	unsigned int connected:1;
};

struct mysql_request {
	mysql_query_callback_t *callback;
	void *context;
};

void db_mysql_query(struct mysql_connection *conn, const char *query,
		    struct mysql_request *request);

struct mysql_connection *db_mysql_init(const char *config_path);
void db_mysql_unref(struct mysql_connection *conn);

#endif

--- NEW FILE: passdb-mysql.c ---
/* Copyright (C) 2003 Alex Howansky, Timo Sirainen */

#include "config.h"
#undef HAVE_CONFIG_H

#ifdef PASSDB_MYSQL

#include "common.h"
#include "str.h"
#include "strescape.h"
#include "var-expand.h"
#include "password-scheme.h"
#include "db-mysql.h"
#include "passdb.h"

#include <stdlib.h>
#include <string.h>

struct passdb_mysql_connection {
	struct mysql_connection *conn;
};

struct passdb_mysql_request {
	struct mysql_request request;

	enum passdb_credentials credentials;
	union {
		verify_plain_callback_t *verify_plain;
                lookup_credentials_callback_t *lookup_credentials;
	} callback;

	char password[1];
};

static struct passdb_mysql_connection *passdb_mysql_conn;

static void mysql_handle_request(struct mysql_connection *conn,
				 struct mysql_request *request, MYSQL_RES *res)
{
	struct passdb_mysql_request *mysql_request =
		(struct passdb_mysql_request *) request;
	struct auth_request *auth_request = request->context;
	const char *user, *password, *scheme;
	int ret = 0;

	user = auth_request->user;
	password = NULL;

	if (res != NULL) {
		if (mysql_num_rows(res) == 0) {
			if (verbose)
				i_info("mysql(%s): Unknown user", user);
		} else if (mysql_num_rows(res) > 1) {
			i_error("mysql(%s): Multiple matches for user", user);
		} else if (mysql_num_fields(res) != 1) {
			i_error("mysql(%s): Password query returned "
				"more than one field", user);
		} else {
			MYSQL_ROW row;

			row = mysql_fetch_row(res);
			if (row)
				password = t_strdup(row[0]);
		}
	}

	scheme = password_get_scheme(&password);
	if (scheme == NULL) {
		scheme = conn->set.default_pass_scheme;
		i_assert(scheme != NULL);
	}

	if (mysql_request->credentials != -1) {
		passdb_handle_credentials(mysql_request->credentials,
			user, password, scheme,
			mysql_request->callback.lookup_credentials,
			auth_request);
		return;
	}

	/* verify plain */
	if (password == NULL) {
		mysql_request->callback.verify_plain(PASSDB_RESULT_USER_UNKNOWN,
						     auth_request);
		return;
	}

	ret = password_verify(mysql_request->password, password,
			      scheme, user);
	if (ret < 0)
		i_error("mysql(%s): Unknown password scheme %s", user, scheme);
	else if (ret == 0) {
		if (verbose)
			i_info("mysql(%s): Password mismatch", user);
	}

	mysql_request->callback.verify_plain(ret > 0 ? PASSDB_RESULT_OK :
					     PASSDB_RESULT_PASSWORD_MISMATCH,
					     auth_request);
}

static void mysql_lookup_pass(struct auth_request *auth_request,
			      struct mysql_request *mysql_request)
{
	struct mysql_connection *conn = passdb_mysql_conn->conn;
	const char *query;
	string_t *str;

	str = t_str_new(512);
	var_expand(str, conn->set.password_query,
		   str_escape(auth_request->user), NULL);
	query = str_c(str);

	mysql_request->callback = mysql_handle_request;
	mysql_request->context = auth_request;

	db_mysql_query(conn, query, mysql_request);
}

static void
mysql_verify_plain(struct auth_request *request, const char *password,
		   verify_plain_callback_t *callback)
{
	struct passdb_mysql_request *mysql_request;

	mysql_request = i_malloc(sizeof(struct passdb_mysql_request) +
				 strlen(password));
	mysql_request->credentials = -1;
	mysql_request->callback.verify_plain = callback;
	strcpy(mysql_request->password, password);

	mysql_lookup_pass(request, &mysql_request->request);
}

static void mysql_lookup_credentials(struct auth_request *request,
				     enum passdb_credentials credentials,
				     lookup_credentials_callback_t *callback)
{
	struct passdb_mysql_request *mysql_request;

	mysql_request = i_new(struct passdb_mysql_request, 1);
	mysql_request->credentials = credentials;
	mysql_request->callback.lookup_credentials = callback;

        mysql_lookup_pass(request, &mysql_request->request);
}

static void passdb_mysql_init(const char *args)
{
	struct mysql_connection *conn;

	passdb_mysql_conn = i_new(struct passdb_mysql_connection, 1);
	passdb_mysql_conn->conn = conn = db_mysql_init(args);
}

static void passdb_mysql_deinit(void)
{
	db_mysql_unref(passdb_mysql_conn->conn);
	i_free(passdb_mysql_conn);
}

struct passdb_module passdb_mysql = {
	passdb_mysql_init,
	passdb_mysql_deinit,

	mysql_verify_plain,
	mysql_lookup_credentials
};

#endif

--- NEW FILE: userdb-mysql.c ---
/* Copyright (C) 2003 Alex Howansky, Timo Sirainen */

#include "config.h"
#undef HAVE_CONFIG_H

#ifdef USERDB_MYSQL

#include "common.h"
#include "str.h"
#include "strescape.h"
#include "var-expand.h"
#include "db-mysql.h"
#include "userdb.h"

#include <stdlib.h>
#include <string.h>

struct userdb_mysql_connection {
	struct mysql_connection *conn;
};

struct userdb_mysql_request {
	struct mysql_request request;
	userdb_callback_t *userdb_callback;

	char username[1]; /* variable width */
};

static struct userdb_mysql_connection *userdb_mysql_conn;

static int is_result_valid(MYSQL_RES *res)
{
	int i, n_fields, found;
	MYSQL_FIELD *fields;

	if (res == NULL) {
		i_error("MYSQL: Query failed");
		return FALSE;
	}

	if (mysql_num_rows(res) == 0) {
		if (verbose)
			i_error("MYSQL: Authenticated user not found");
		return FALSE;
	}

	n_fields = mysql_num_fields(res);
	fields = mysql_fetch_fields(res);

	/* Make sure the 'uid' field exists. */
	for (found = 0, i = 0; i < n_fields; i++)
		if (strcmp("uid", fields[i].name) == 0) {
			found = 1;
			break;
		}

	if (!found) {
		i_error("MYSQL: User query did not return 'uid' field");
		return FALSE;
	}

	/* Make sure the 'gid' field exists. */
	for (found = 0, i = 0; i < n_fields; i++)
		if (strcmp("gid", fields[i].name) == 0) {
			found = 1;
			break;
		}

	if (!found) {
		i_error("MYSQL: User query did not return 'gid' field");
		return FALSE;
	}

	return TRUE;
}

static const char *my_get_str(MYSQL_RES *res, MYSQL_ROW row, const char *field)
{
	int i, n_fields;
	unsigned long *lengths;
	MYSQL_FIELD *fields;

	n_fields = mysql_num_fields(res);
	lengths = mysql_fetch_lengths(res);
	fields = mysql_fetch_fields(res);
	for (i = 0; i < n_fields; i++) {
		if (strcmp(field, fields[i].name) == 0)
			return lengths[i] == 0 ? NULL : t_strdup(row[i]);
	}

	return NULL;
}

static void mysql_handle_request(struct mysql_connection *conn __attr_unused__,
				 struct mysql_request *request, MYSQL_RES *res)
{
	struct userdb_mysql_request *urequest =
		(struct userdb_mysql_request *) request;
	struct user_data user;
	MYSQL_ROW row;

	if (res != NULL && is_result_valid(res) &&
	    (row = mysql_fetch_row(res))) {
		memset(&user, 0, sizeof(user));
		user.virtual_user = urequest->username;
		user.system_user = my_get_str(res, row, "system_user");
		user.home = my_get_str(res, row, "home");
		user.mail = my_get_str(res, row, "mail");
		user.uid = atoi(my_get_str(res, row, "uid"));
		user.gid = atoi(my_get_str(res, row, "gid"));
		urequest->userdb_callback(&user, request->context);
	} else {
		urequest->userdb_callback(NULL, request->context);
	}
}

static void userdb_mysql_lookup(const char *user, userdb_callback_t *callback,
				void *context)
{
	struct mysql_connection *conn = userdb_mysql_conn->conn;
	struct userdb_mysql_request *request;
	const char *query;
	string_t *str;

	str = t_str_new(512);
	var_expand(str, conn->set.user_query, str_escape(user), NULL);
	query = str_c(str);

	request = i_malloc(sizeof(struct userdb_mysql_request) + strlen(user));
	request->request.callback = mysql_handle_request;
	request->request.context = context;
	request->userdb_callback = callback;
	strcpy(request->username, user);

	db_mysql_query(conn, query, &request->request);
}

static void userdb_mysql_init(const char *args)
{
	struct mysql_connection *conn;

	userdb_mysql_conn = i_new(struct userdb_mysql_connection, 1);
	userdb_mysql_conn->conn = conn = db_mysql_init(args);
}

static void userdb_mysql_deinit(void)
{
	db_mysql_unref(userdb_mysql_conn->conn);
	i_free(userdb_mysql_conn);
}

struct userdb_module userdb_mysql = {
	userdb_mysql_init,
	userdb_mysql_deinit,

	userdb_mysql_lookup
};

#endif

Index: Makefile.am
===================================================================
RCS file: /home/cvs/dovecot/src/auth/Makefile.am,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- Makefile.am	10 Nov 2003 20:36:02 -0000	1.23
+++ Makefile.am	10 May 2004 01:47:09 -0000	1.24
@@ -20,6 +20,7 @@
 	auth-master-connection.c \
 	auth-module.c \
 	db-ldap.c \
+	db-mysql.c \
 	db-pgsql.c \
 	db-passwd-file.c \
 	main.c \
@@ -38,6 +39,7 @@
 	passdb-pam.c \
 	passdb-shadow.c \
 	passdb-vpopmail.c \
+	passdb-mysql.c \
 	passdb-pgsql.c \
 	password-scheme.c \
 	password-scheme-md5crypt.c \
@@ -48,6 +50,7 @@
 	userdb-passwd-file.c \
 	userdb-static.c \
 	userdb-vpopmail.c \
+	userdb-mysql.c \
 	userdb-pgsql.c
 
 noinst_HEADERS = \
@@ -58,6 +61,7 @@
 	auth-mech-desc.h \
 	auth-module.h \
 	db-ldap.h \
+	db-mysql.h \
 	db-pgsql.h \
 	db-passwd-file.h \
 	common.h \

Index: passdb.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/passdb.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- passdb.c	11 Nov 2003 09:59:27 -0000	1.13
+++ passdb.c	10 May 2004 01:47:09 -0000	1.14
@@ -116,6 +116,10 @@
 	if (strcasecmp(name, "pgsql") == 0)
 		passdb = &passdb_pgsql;
 #endif
+#ifdef PASSDB_MYSQL
+	if (strcasecmp(name, "mysql") == 0)
+		passdb = &passdb_mysql;
+#endif
 #ifdef HAVE_MODULES
 	passdb_module = passdb != NULL ? NULL : auth_module_open(name);
 	if (passdb_module != NULL) {

Index: passdb.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/passdb.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- passdb.h	10 Nov 2003 20:36:02 -0000	1.8
+++ passdb.h	10 May 2004 01:47:09 -0000	1.9
@@ -60,6 +60,7 @@
 extern struct passdb_module passdb_vpopmail;
 extern struct passdb_module passdb_ldap;
 extern struct passdb_module passdb_pgsql;
+extern struct passdb_module passdb_mysql;
 
 void passdb_init(void);
 void passdb_deinit(void);

Index: userdb.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/userdb.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- userdb.c	14 May 2003 18:31:02 -0000	1.7
+++ userdb.c	10 May 2004 01:47:09 -0000	1.8
@@ -49,6 +49,10 @@
 	if (strcasecmp(name, "pgsql") == 0)
 		userdb = &userdb_pgsql;
 #endif
+#ifdef USERDB_MYSQL
+	if (strcasecmp(name, "mysql") == 0)
+		userdb = &userdb_mysql;
+#endif
 #ifdef HAVE_MODULES
 	userdb_module = userdb != NULL ? NULL : auth_module_open(name);
 	if (userdb_module != NULL) {

Index: userdb.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/userdb.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- userdb.h	8 May 2003 04:28:30 -0000	1.7
+++ userdb.h	10 May 2004 01:47:09 -0000	1.8
@@ -29,6 +29,7 @@
 extern struct userdb_module userdb_vpopmail;
 extern struct userdb_module userdb_ldap;
 extern struct userdb_module userdb_pgsql;
+extern struct userdb_module userdb_mysql;
 
 void userdb_init(void);
 void userdb_deinit(void);



More information about the dovecot-cvs mailing list