[dovecot-cvs] dovecot/src/auth db-pgsql.c,NONE,1.1 db-pgsql.h,NONE,1.1 passdb-pgsql.c,NONE,1.1 userdb-pgsql.c,NONE,1.1

cras at procontrol.fi cras at procontrol.fi
Fri Mar 14 21:29:02 EET 2003


Update of /home/cvs/dovecot/src/auth
In directory danu:/tmp/cvs-serv6744

Added Files:
	db-pgsql.c db-pgsql.h passdb-pgsql.c userdb-pgsql.c 
Log Message:
Whops, forgot to add.



--- NEW FILE: db-pgsql.c ---
/* 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

--- NEW FILE: db-pgsql.h ---
#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

--- NEW FILE: passdb-pgsql.c ---
/* 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

--- NEW FILE: userdb-pgsql.c ---
/* 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




More information about the dovecot-cvs mailing list