]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
MySQL authentication patch by Matther Reimer
authorTimo Sirainen <tss@iki.fi>
Mon, 10 May 2004 01:47:08 +0000 (04:47 +0300)
committerTimo Sirainen <tss@iki.fi>
Mon, 10 May 2004 01:47:08 +0000 (04:47 +0300)
--HG--
branch : HEAD

13 files changed:
AUTHORS
configure.in
doc/Makefile.am
doc/dovecot-mysql.conf [new file with mode: 0644]
src/auth/Makefile.am
src/auth/db-mysql.c [new file with mode: 0644]
src/auth/db-mysql.h [new file with mode: 0644]
src/auth/passdb-mysql.c [new file with mode: 0644]
src/auth/passdb.c
src/auth/passdb.h
src/auth/userdb-mysql.c [new file with mode: 0644]
src/auth/userdb.c
src/auth/userdb.h

diff --git a/AUTHORS b/AUTHORS
index 832e563aad978ff5eb97770bf7d574c562d0be05..26e915059f75d1c364be4e6e1055248342f00cb0 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,6 +6,8 @@ Damian Ivereigh <damian@cisco.com> (src/lib-index/mail-tree-redblack.c)
 
 Alex Howansky <alex@wankwood.com> (src/auth/*-pgsql.c)
 
+Matthew Reimer <mreimer@vpop.net> (src/auth/*-mysql.c)
+
 This product includes software developed by Computing Services
 at Carnegie Mellon University (http://www.cmu.edu/computing/).
 (src/lib/base64.c, src/lib/mkgmtime.c)
index 74629cf8eef2e5a8a97669fcd01c710a95d91f2d..2e0a074b3f1ab5ec4ad19d855599a21a4fbc1b17 100644 (file)
@@ -134,6 +134,15 @@ AC_ARG_WITH(pgsql,
        fi,
        want_pgsql=no)
 
+AC_ARG_WITH(mysql,
+[  --with-mysql            Build with MySQL support],
+       if test x$withval = xno; then
+               want_mysql=no
+       else
+               want_mysql=yes
+       fi,
+       want_mysql=no)
+
 AC_ARG_WITH(cyrus-sasl2,
 [  --with-cyrus-sasl2      Build with Cyrus SASL 2 library support],
        if test x$withval = xno; then
@@ -1016,6 +1025,25 @@ if test $want_pgsql = yes; then
        LIBS=$old_LIBS
 fi
 
+if test $want_mysql = yes; then
+       AC_CHECK_LIB(mysqlclient, mysql_init, [
+               AC_CHECK_HEADER(mysql.h,, [
+                       AC_CHECK_HEADER(mysql/mysql.h, [
+                               AUTH_CFLAGS="$AUTH_CFLAGS -DHAVE_MYSQL_MYSQL_H"
+                       ], want_mysql = no)
+               ])
+       ], want_mysql = no)
+
+       if test $want_mysql = yes; then
+               AUTH_LIBS="$AUTH_LIBS -lmysqlclient"
+
+               AC_DEFINE(USERDB_MYSQL,, Build with MySQL support)
+               AC_DEFINE(PASSDB_MYSQL,, Build with MySQL support)
+               userdb="$userdb mysql"
+               passdb="$passdb mysql"
+       fi
+fi
+
 if test $want_vpopmail = yes; then
        vpopmail_home="`echo ~vpopmail`"
        vpop_libdeps="$vpopmail_home/etc/lib_deps"
index 62aafce4a067f77a62ce9fe9fd56905438bc0b0b..6a8e99d4acc2e95ba3fc2ba54cbff37edcffb54d 100644 (file)
@@ -14,5 +14,6 @@ EXTRA_DIST = \
        mkcert.sh \
        dovecot-openssl.cnf \
        dovecot-ldap.conf \
+       dovecot-mysql.conf \
        dovecot-pgsql.conf \
        $(doc_DATA)
diff --git a/doc/dovecot-mysql.conf b/doc/dovecot-mysql.conf
new file mode 100644 (file)
index 0000000..1e7e87e
--- /dev/null
@@ -0,0 +1,70 @@
+# For the mysql passdb module, you'll need a database with a table that
+# contains fields for at least the userid and password. If you want to
+# use the user@domain syntax, you might want to have a separate domain
+# field as well.
+#
+# If your users all have the same uig/gid, and have predictable home
+# directories, you can use the static userdb module to generate the home
+# dir based on the userid and domain. In this case, you won't need fields
+# for home, uid, or gid in the database.
+#
+# If you prefer to use the mysql userdb module, you'll want to add fields
+# for home, uid, and gid. Here is an example table:
+#
+# CREATE TABLE users (
+#     userid VARCHAR(128) NOT NULL,
+#     password VARCHAR(64) NOT NULL,
+#     home VARCHAR(256) NOT NULL,
+#     uid INTEGER NOT NULL,
+#     gid INTEGER NOT NULL,
+#     active CHAR(1) DEFAULT 'Y' NOT NULL
+# );
+
+db_host = localhost
+db_port = 3306
+#db_unix_socket = /var/tmp/mysql.sock
+db = users
+db_user = dovecot-db
+db_passwd = opensesame
+db_client_flags = 0
+
+# Default password scheme.
+#
+# Currently supported schemes include PLAIN, PLAIN-MD5, DIGEST-MD5, and CRYPT.
+#
+#default_pass_scheme = PLAIN-MD5
+
+# Query to retrieve the password.
+#
+# The query should return one row, one column. If more than one row or column
+# is returned, authentication will automatically fail.
+#
+# Available substitutions:
+#   %u = entire userid
+#   %n = user part of user@domain
+#   %d = domain part of user@domain
+#
+# Example:
+#   password_query = SELECT password FROM users WHERE userid = '%n' AND domain = '%d'
+#   password_query = SELECT password FROM users WHERE userid = '%u' AND active = 'Y'
+#
+#password_query = SELECT password FROM users WHERE userid = '%u'
+
+# Query to retrieve the user information.
+#
+# The query must return only one row. The columns to return are:
+#   home - Home directory
+#   mail - MAIL environment
+#   system_user - System user name (for initgroups())
+#   uid - System UID
+#   gid - System GID
+#
+# Either home or mail is required. uid and gid are required. If more than one
+# row is returned or there's missing fields, login will automatically fail.
+#
+# Examples
+#   user_query = SELECT home, uid, gid FROM users WHERE userid = '%n' AND domain = '%d'
+#   user_query = SELECT dir AS home, user AS uid, group AS gid FROM users where userid = '%u'
+#   user_query = SELECT home, 501 AS uid, 501 AS gid FROM users WHERE userid = '%u'
+#
+#user_query = SELECT home, uid, gid FROM users WHERE userid = '%u'
index d47d1e1ccfaa6a63533e06b86c2b1a351af5152c..20f5d14f7e67f3da8ba19f6a68bfc350aac32e93 100644 (file)
@@ -20,6 +20,7 @@ dovecot_auth_SOURCES = \
        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 @@ dovecot_auth_SOURCES = \
        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 @@ dovecot_auth_SOURCES = \
        userdb-passwd-file.c \
        userdb-static.c \
        userdb-vpopmail.c \
+       userdb-mysql.c \
        userdb-pgsql.c
 
 noinst_HEADERS = \
@@ -58,6 +61,7 @@ noinst_HEADERS = \
        auth-mech-desc.h \
        auth-module.h \
        db-ldap.h \
+       db-mysql.h \
        db-pgsql.h \
        db-passwd-file.h \
        common.h \
diff --git a/src/auth/db-mysql.c b/src/auth/db-mysql.c
new file mode 100644 (file)
index 0000000..18b8f76
--- /dev/null
@@ -0,0 +1,182 @@
+/* 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
diff --git a/src/auth/db-mysql.h b/src/auth/db-mysql.h
new file mode 100644 (file)
index 0000000..7b25206
--- /dev/null
@@ -0,0 +1,55 @@
+#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
diff --git a/src/auth/passdb-mysql.c b/src/auth/passdb-mysql.c
new file mode 100644 (file)
index 0000000..afb4cdc
--- /dev/null
@@ -0,0 +1,170 @@
+/* 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
index 01b9c9f2685c56d86dd6692a647ead7d9bd43ef9..816187f806fb42e4f4a3c8bd979e53f25a8506d9 100644 (file)
@@ -116,6 +116,10 @@ void passdb_init(void)
        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 097b5369bffbcd71dfbad0d220a2dd65da570f7f..c613f0f2763b7b3e0c9c8ec475b92544f91373c1 100644 (file)
@@ -60,6 +60,7 @@ extern struct passdb_module passdb_pam;
 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);
diff --git a/src/auth/userdb-mysql.c b/src/auth/userdb-mysql.c
new file mode 100644 (file)
index 0000000..5847b6f
--- /dev/null
@@ -0,0 +1,159 @@
+/* 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 2e1168e7360f460c0ec3be674606d8e5f25c62fe..3ab1f1906b0003fb5360cfca7262622ca009bef6 100644 (file)
@@ -49,6 +49,10 @@ void userdb_init(void)
        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 75a5527bbe31288c398007b8ad99ced114d78d60..47ba2453192ddd05f70b49c132460ea46b9db1e3 100644 (file)
@@ -29,6 +29,7 @@ extern struct userdb_module userdb_passwd_file;
 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);