]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Whops, forgot to add.
authorTimo Sirainen <tss@iki.fi>
Fri, 14 Mar 2003 19:28:59 +0000 (21:28 +0200)
committerTimo Sirainen <tss@iki.fi>
Fri, 14 Mar 2003 19:28:59 +0000 (21:28 +0200)
--HG--
branch : HEAD

src/auth/db-pgsql.c [new file with mode: 0644]
src/auth/db-pgsql.h [new file with mode: 0644]
src/auth/passdb-pgsql.c [new file with mode: 0644]
src/auth/userdb-pgsql.c [new file with mode: 0644]

diff --git a/src/auth/db-pgsql.c b/src/auth/db-pgsql.c
new file mode 100644 (file)
index 0000000..63c4b26
--- /dev/null
@@ -0,0 +1,173 @@
+/* Copyright (C) 2003 Alex Howansky, Timo Sirainen */
+
+#include "config.h"
+#undef HAVE_CONFIG_H
+
+#if defined(PASSDB_PGSQL) || defined(USERDB_PGSQL)
+
+#include "common.h"
+#include "network.h"
+#include "str.h"
+#include "settings.h"
+#include "db-pgsql.h"
+
+#include <stddef.h>
+
+#define DEF(type, name) { type, #name, offsetof(struct pgsql_settings, name) }
+
+static struct setting_def setting_defs[] = {
+       DEF(SET_STR, connect),
+       DEF(SET_STR, password_query),
+       DEF(SET_STR, user_query),
+       DEF(SET_STR, allowed_chars),
+       DEF(SET_STR, default_pass_scheme)
+};
+
+struct pgsql_settings default_pgsql_settings = {
+       MEMBER(connect) "dbname=virtual user=virtual",
+       MEMBER(password_query) "SELECT password FROM users WHERE userid = '%u'",
+       MEMBER(user_query) "SELECT home, uid, gid FROM users WHERE userid = '%u'",
+       MEMBER(allowed_chars) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-@",
+       MEMBER(default_pass_scheme) "PLAIN-MD5"
+};
+
+static struct pgsql_connection *pgsql_connections = NULL;
+
+static int pgsql_conn_open(struct pgsql_connection *conn);
+static void pgsql_conn_close(struct pgsql_connection *conn);
+
+int db_pgsql_is_valid_username(struct pgsql_connection *conn,
+                              const char *username)
+{
+       const char *p;
+
+       for (p = username; *p != '\0'; p++) {
+               if (strchr(conn->set.allowed_chars, *p) == NULL)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+void db_pgsql_query(struct pgsql_connection *conn, const char *query,
+                   struct pgsql_request *request)
+{
+       PGresult *res;
+       int failed;
+
+       if (!conn->connected) {
+               if (!pgsql_conn_open(conn)) {
+                       request->callback(conn, request, NULL);
+                       return;
+               }
+       }
+
+       if (verbose_debug)
+               i_info("PGSQL: Performing query: %s", query);
+
+       res = PQexec(conn->pg, query);
+
+       if (PQresultStatus(res) != PGRES_TUPLES_OK) {
+               i_error("PGSQL: Query \"%s\" failed: %s",
+                       query, PQresultErrorMessage(res));
+               failed = TRUE;
+       } else if (PQntuples(res) != 1) {
+               i_error("PGSQL: Query \"%s\" returned %d rows",
+                       query, PQntuples(res));
+               failed = TRUE;
+       } else {
+               failed = FALSE;
+       }
+
+       request->callback(conn, request, failed ? NULL : res);
+       PQclear(res);
+
+}
+
+static int pgsql_conn_open(struct pgsql_connection *conn)
+{
+       if (conn->connected)
+               return TRUE;
+
+       if (conn->pg == NULL) {
+               conn->pg = PQconnectdb(conn->set.connect);
+               if (PQstatus(conn->pg) != CONNECTION_OK) {
+                       i_error("PGSQL: Can't connect to database %s",
+                               conn->set.connect);
+                       return FALSE;
+               }
+       }
+
+       conn->connected = TRUE;
+       return TRUE;
+}
+
+static void pgsql_conn_close(struct pgsql_connection *conn)
+{
+       conn->connected = FALSE;
+
+       if (conn->pg != NULL) {
+               PQfinish(conn->pg);
+               conn->pg = NULL;
+       }
+}
+
+static struct pgsql_connection *pgsql_conn_find(const char *config_path)
+{
+       struct pgsql_connection *conn;
+
+       for (conn = pgsql_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 pgsql_connection *conn = context;
+
+       return parse_setting_from_defs(conn->pool, setting_defs,
+                                      &conn->set, key, value);
+}
+
+struct pgsql_connection *db_pgsql_init(const char *config_path)
+{
+       struct pgsql_connection *conn;
+       pool_t pool;
+
+       conn = pgsql_conn_find(config_path);
+       if (conn != NULL) {
+               conn->refcount++;
+               return conn;
+       }
+
+       pool = pool_alloconly_create("pgsql_connection", 1024);
+       conn = p_new(pool, struct pgsql_connection, 1);
+       conn->pool = pool;
+
+       conn->refcount = 1;
+
+       conn->config_path = p_strdup(pool, config_path);
+       conn->set = default_pgsql_settings;
+       settings_read(config_path, parse_setting, conn);
+
+       (void)pgsql_conn_open(conn);
+
+       conn->next = pgsql_connections;
+       pgsql_connections = conn;
+       return conn;
+}
+
+void db_pgsql_unref(struct pgsql_connection *conn)
+{
+       if (--conn->refcount > 0)
+               return;
+
+       pgsql_conn_close(conn);
+       pool_unref(conn->pool);
+}
+
+#endif
diff --git a/src/auth/db-pgsql.h b/src/auth/db-pgsql.h
new file mode 100644 (file)
index 0000000..08196d8
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef __DB_PGSQL_H
+#define __DB_PGSQL_H
+
+#include <libpq-fe.h>
+
+struct pgsql_connection;
+struct pgsql_request;
+
+typedef void pgqsl_query_callback_t(struct pgsql_connection *conn,
+                                   struct pgsql_request *request,
+                                   PGresult *res);
+
+struct pgsql_settings {
+       const char *connect;
+       const char *password_query;
+       const char *user_query;
+       const char *allowed_chars;
+       const char *default_pass_scheme;
+};
+
+struct pgsql_connection {
+       struct pgsql_connection *next;
+
+       pool_t pool;
+       int refcount;
+
+       char *config_path;
+       struct pgsql_settings set;
+
+       PGconn *pg;
+
+       unsigned int connected:1;
+};
+
+struct pgsql_request {
+       pgqsl_query_callback_t *callback;
+       void *context;
+};
+
+int db_pgsql_is_valid_username(struct pgsql_connection *conn,
+                              const char *username);
+
+void db_pgsql_query(struct pgsql_connection *conn, const char *query,
+                   struct pgsql_request *request);
+
+struct pgsql_connection *db_pgsql_init(const char *config_path);
+void db_pgsql_unref(struct pgsql_connection *conn);
+
+#endif
diff --git a/src/auth/passdb-pgsql.c b/src/auth/passdb-pgsql.c
new file mode 100644 (file)
index 0000000..75206d2
--- /dev/null
@@ -0,0 +1,173 @@
+/* Copyright (C) 2003 Alex Howansky, Timo Sirainen */
+
+#include "config.h"
+#undef HAVE_CONFIG_H
+
+#ifdef PASSDB_PGSQL
+
+#include "common.h"
+#include "str.h"
+#include "var-expand.h"
+#include "password-scheme.h"
+#include "db-pgsql.h"
+#include "passdb.h"
+
+#include <libpq-fe.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct passdb_pgsql_connection {
+       struct pgsql_connection *conn;
+};
+
+struct passdb_pgsql_request {
+       struct pgsql_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_pgsql_connection *passdb_pgsql_conn;
+
+static void pgsql_handle_request(struct pgsql_connection *conn,
+                                struct pgsql_request *request, PGresult *res)
+{
+       struct passdb_pgsql_request *pgsql_request =
+               (struct passdb_pgsql_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 (PQntuples(res) == 0) {
+                       if (verbose)
+                               i_info("pgsql(%s): Unknown user", user);
+               } else if (PQntuples(res) > 1) {
+                       i_error("pgsql(%s): Multiple matches for user", user);
+               } else if (PQnfields(res) != 1) {
+                       i_error("pgsql(%s): Password query returned "
+                               "more than one field", user);
+               } else {
+                       password = t_strdup(PQgetvalue(res, 0, 0));
+               }
+       }
+
+       scheme = password_get_scheme(&password);
+       if (scheme == NULL) {
+               scheme = conn->set.default_pass_scheme;
+               i_assert(scheme != NULL);
+       }
+
+       if (pgsql_request->credentials != -1) {
+               passdb_handle_credentials(pgsql_request->credentials,
+                       user, password, scheme,
+                       pgsql_request->callback.lookup_credentials,
+                       auth_request);
+               return;
+       }
+
+       /* verify plain */
+       if (password == NULL) {
+               pgsql_request->callback.verify_plain(PASSDB_RESULT_USER_UNKNOWN,
+                                                    auth_request);
+               return;
+       }
+
+       ret = password_verify(pgsql_request->password, password,
+                             scheme, user);
+       if (ret < 0)
+               i_error("pgsql(%s): Unknown password scheme %s", user, scheme);
+       else if (ret == 0) {
+               if (verbose)
+                       i_info("pgsql(%s): Password mismatch", user);
+       }
+
+       pgsql_request->callback.verify_plain(ret > 0 ? PASSDB_RESULT_OK :
+                                            PASSDB_RESULT_PASSWORD_MISMATCH,
+                                            auth_request);
+}
+
+static void pgsql_lookup_pass(struct auth_request *auth_request,
+                             struct pgsql_request *pgsql_request)
+{
+       struct pgsql_connection *conn = passdb_pgsql_conn->conn;
+       const char *query;
+       string_t *str;
+
+       str = t_str_new(512);
+       var_expand(str, conn->set.password_query, auth_request->user, NULL);
+       query = str_c(str);
+
+       pgsql_request->callback = pgsql_handle_request;
+       pgsql_request->context = auth_request;
+
+       if (db_pgsql_is_valid_username(conn, auth_request->user))
+               db_pgsql_query(conn, query, pgsql_request);
+       else {
+               if (verbose) {
+                       i_error("pgsql(%s): Invalid username",
+                               auth_request->user);
+               }
+               pgsql_handle_request(conn, pgsql_request, NULL);
+       }
+}
+
+static void
+pgsql_verify_plain(struct auth_request *request, const char *password,
+                  verify_plain_callback_t *callback)
+{
+       struct passdb_pgsql_request *pgsql_request;
+
+       pgsql_request = i_malloc(sizeof(struct passdb_pgsql_request) +
+                                strlen(password));
+       pgsql_request->credentials = -1;
+       pgsql_request->callback.verify_plain = callback;
+       strcpy(pgsql_request->password, password);
+
+       pgsql_lookup_pass(request, &pgsql_request->request);
+}
+
+static void pgsql_lookup_credentials(struct auth_request *request,
+                                    enum passdb_credentials credentials,
+                                    lookup_credentials_callback_t *callback)
+{
+       struct passdb_pgsql_request *pgsql_request;
+
+       pgsql_request = i_new(struct passdb_pgsql_request, 1);
+       pgsql_request->credentials = credentials;
+       pgsql_request->callback.lookup_credentials = callback;
+
+        pgsql_lookup_pass(request, &pgsql_request->request);
+}
+
+static void passdb_pgsql_init(const char *args)
+{
+       struct pgsql_connection *conn;
+
+       passdb_pgsql_conn = i_new(struct passdb_pgsql_connection, 1);
+       passdb_pgsql_conn->conn = conn = db_pgsql_init(args);
+}
+
+static void passdb_pgsql_deinit(void)
+{
+       db_pgsql_unref(passdb_pgsql_conn->conn);
+       i_free(passdb_pgsql_conn);
+}
+
+struct passdb_module passdb_pgsql = {
+       passdb_pgsql_init,
+       passdb_pgsql_deinit,
+
+       pgsql_verify_plain,
+       pgsql_lookup_credentials
+};
+
+#endif
diff --git a/src/auth/userdb-pgsql.c b/src/auth/userdb-pgsql.c
new file mode 100644 (file)
index 0000000..7676166
--- /dev/null
@@ -0,0 +1,125 @@
+/* Copyright (C) 2003 Alex Howansky, Timo Sirainen */
+
+#include "config.h"
+#undef HAVE_CONFIG_H
+
+#ifdef USERDB_PGSQL
+
+#include "common.h"
+#include "str.h"
+#include "var-expand.h"
+#include "db-pgsql.h"
+#include "userdb.h"
+
+#include <libpq-fe.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct userdb_pgsql_connection {
+       struct pgsql_connection *conn;
+};
+
+struct userdb_pgsql_request {
+       struct pgsql_request request;
+       userdb_callback_t *userdb_callback;
+};
+
+static struct userdb_pgsql_connection *userdb_pgsql_conn;
+
+static int is_result_valid(PGresult *res)
+{
+       if (PQresultStatus(res) != PGRES_TUPLES_OK) {
+               i_error("PGSQL: Query failed");
+               return FALSE;
+       }
+
+       if (PQntuples(res) == 0) {
+               if (verbose)
+                       i_error("PGSQL: Authenticated user not found");
+               return FALSE;
+       }
+
+       if (PQfnumber(res, "home") == -1) {
+               i_error("PGSQL: User query did not return 'home' field");
+               return FALSE;
+       }
+
+       if (PQfnumber(res, "uid") == -1) {
+               i_error("PGSQL: User query did not return 'uid' field");
+               return FALSE;
+       }
+
+       if (PQfnumber(res, "gid") == -1) {
+               i_error("PGSQL: User query did not return 'gid' field");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void pgsql_handle_request(struct pgsql_connection *conn __attr_unused__,
+                                struct pgsql_request *request, PGresult *res)
+{
+       struct userdb_pgsql_request *urequest =
+               (struct userdb_pgsql_request *) request;
+       struct user_data user;
+
+       if (res != NULL && is_result_valid(res)) {
+               memset(&user, 0, sizeof(user));
+               user.home = PQgetvalue(res, 0, PQfnumber(res, "home"));
+               user.uid = atoi(PQgetvalue(res, 0, PQfnumber(res, "uid")));
+               user.gid = atoi(PQgetvalue(res, 0, PQfnumber(res, "gid")));
+               urequest->userdb_callback(&user, request->context);
+       } else {
+               urequest->userdb_callback(NULL, request->context);
+       }
+}
+
+static void userdb_pgsql_lookup(const char *user, userdb_callback_t *callback,
+                               void *context)
+{
+       struct pgsql_connection *conn = userdb_pgsql_conn->conn;
+       struct userdb_pgsql_request *request;
+       const char *query;
+       string_t *str;
+
+       str = t_str_new(512);
+       var_expand(str, conn->set.user_query, user, NULL);
+       query = str_c(str);
+
+       request = i_new(struct userdb_pgsql_request, 1);
+       request->request.callback = pgsql_handle_request;
+       request->request.context = context;
+       request->userdb_callback = callback;
+
+       if (db_pgsql_is_valid_username(conn, user))
+               db_pgsql_query(conn, query, &request->request);
+       else {
+               if (verbose)
+                       i_info("pgsql(%s): Invalid username", user);
+               pgsql_handle_request(conn, &request->request, NULL);
+       }
+}
+
+static void userdb_pgsql_init(const char *args)
+{
+       struct pgsql_connection *conn;
+
+       userdb_pgsql_conn = i_new(struct userdb_pgsql_connection, 1);
+       userdb_pgsql_conn->conn = conn = db_pgsql_init(args);
+}
+
+static void userdb_pgsql_deinit(void)
+{
+       db_pgsql_unref(userdb_pgsql_conn->conn);
+       i_free(userdb_pgsql_conn);
+}
+
+struct userdb_module userdb_pgsql = {
+       userdb_pgsql_init,
+       userdb_pgsql_deinit,
+
+       userdb_pgsql_lookup
+};
+
+#endif