summaryrefslogtreecommitdiffstats
path: root/database/postgresql/edb-pgsql.c
diff options
context:
space:
mode:
Diffstat (limited to 'database/postgresql/edb-pgsql.c')
-rw-r--r--database/postgresql/edb-pgsql.c1124
1 files changed, 1124 insertions, 0 deletions
diff --git a/database/postgresql/edb-pgsql.c b/database/postgresql/edb-pgsql.c
new file mode 100644
index 0000000..1ea7367
--- /dev/null
+++ b/database/postgresql/edb-pgsql.c
@@ -0,0 +1,1124 @@
+/* edb-pgsql.c -- PostgreSQL database driver for eurephia
+ *
+ * GPLv2 only - Copyright (C) 2011
+ * David Sommerseth <dazo@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/**
+ * @file edb-pgsql.c
+ * @author David Sommerseth <dazo@users.sourceforge.net>
+ * @date 2011-01-15
+ *
+ * @brief eurephia database driver for the PostgreSQL database.
+ * This file is the main API for the driver.
+ *
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <libpq-fe.h>
+
+#define DRIVERVERSION "1.0"
+#ifndef DRIVERAPIVERSION
+# define DRIVERAPIVERSION 1
+#endif
+
+#include <eurephiadb_driver.h>
+#include <eurephia_nullsafe.h>
+#include <eurephia_log.h>
+#include <eurephia_values.h>
+#include <eurephia_cfgfile.h>
+#include <eurephiadb_session_common.h>
+#include <eurephiadb_session_struct.h>
+#include <passwd.h>
+
+/**
+ * Mapping struct - maps attempt types (attempt_IPADDR, attempt_CERTIFICATE, attempt_USERNAME)
+ * to database field names, configuration options (with default values) and description
+ */
+typedef struct {
+ char *colname; /**< Field when doing look up in blacklist and attempts tables */
+ char *colname_where; /**< Field when using column name in WHERE section of SQL queries */
+ char *allow_cfg; /**< Configure parameter for the attempt limits */
+ char *descr; /**< Description, used to give more readable output for users */
+ char *default_value; /**< Default value, if config option is not found */
+ char *value_func; /**< If not NULL, the value will be passed through the given SQL function */
+} eDBattempt_types_t;
+
+
+/**
+ * Static mapping table with the needed values. Uses the eDBattempt_types_t struct.
+ */
+static const eDBattempt_types_t eDBattempt_types[] = {
+ {NULL, NULL, NULL, NULL},
+ {"remoteip\0", "remoteip\0", "allow_ipaddr_attempts\0", "IP Address\0", "10\0", NULL},
+ {"digest\0", "lower(digest)\0", "allow_cert_attempts\0", "Certificate\0", "5\0", "lower\0"},
+ {"username\0", "username\0", "allow_username_attempts\0", "Username\0", "5\0", NULL},
+ {NULL, NULL, NULL, NULL}
+};
+
+
+static inline char *PGgetValue(PGresult *res, int row, int col) {
+ if( (res == NULL) || (PQgetisnull(res, row, col) == 1) ) {
+ return NULL;
+ } else {
+ return PQgetvalue(res, row, col);
+ }
+}
+
+#define PREPSQL_TLS_AUTH "eurephia_tls_auth"
+#define PREPSQL_USERPWD_AUTH "eurephia_userpwd_auth"
+#define PREPSQL_BLACKLIST_ATTEMPTUPD "eurephia_blacklist_attupd"
+#define PREPSQL_USERS_LASTACC_UPD "eurephia_users_lastacc_upd"
+#define PREPSQL_USERS_GETUID "eurephia_getuid"
+#define PREPSQL_BLACKLIST_CHECK "eurephia_blacklist_check"
+#define PREPSQL_ATTEMPTS_CHECK "eurephia_attempts_check"
+#define PREPSQL_BLACKLIST_REGISTER "eurephia_blacklist_reg"
+
+/**
+ * @copydoc eDB_DriverVersion()
+ */
+const char *eDB_DriverVersion(void) {
+ return "edb-pgsql (v"DRIVERVERSION") David Sommerseth 2011 (C) GPLv2";
+}
+
+
+/**
+ * @copydoc eDB_DriverAPIVersion()
+ */
+int eDB_DriverAPIVersion() {
+ return DRIVERAPIVERSION;
+}
+
+
+
+/**
+ * Internal driver function for simplifying update of the blacklist table. It will simply just
+ * update the 'last_accessed' field in the blacklist table.
+ *
+ * @param ctx eurephiaCTX
+ * @param blid Blacklist ID, integer value corresponding to the record in the database
+ */
+static inline void update_blacklist_attempt(eurephiaCTX *ctx, const char *blid) {
+ if( blid != NULL ) {
+ PGresult *dbr = NULL;
+
+ const char ** qry_args = NULL;
+
+ dbr = PQprepare(ctx->dbc->dbhandle, PREPSQL_BLACKLIST_ATTEMPTUPD,
+ "UPDATE blacklist "
+ " SET last_accessed = CURRENT_TIMESTAMP WHERE blid = $1", 1, NULL);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not prepare blacklist last attempt update query: %s",
+ (dbr == NULL ? PQresultErrorMessage(dbr)
+ : PQerrorMessage(ctx->dbc->dbhandle)));
+ goto exit;
+ }
+ PQclear(dbr);
+
+ qry_args = calloc(1, sizeof(char *));
+ qry_args[0] = blid;
+ dbr = PQexecPrepared(ctx->dbc->dbhandle, PREPSQL_BLACKLIST_ATTEMPTUPD, 1,
+ qry_args, NULL, NULL, 0);
+ free_nullsafe(ctx, qry_args);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Failed to update blaclist.last_access timestamp for blid %s (%s)",
+ blid,
+ (dbr ? PQresultErrorMessage(dbr)
+ : PQerrorMessage(ctx->dbc->dbhandle)));
+ }
+ exit:
+ if( dbr ) {
+ PQclear(dbr);
+ }
+ }
+ return;
+}
+
+
+
+/**
+ * @copydoc eDBconnect()
+ * Connect to the database ... connection is stored in the eurephiaCTX context
+ */
+int eDBconnect(eurephiaCTX *ctx, const int argc, const char **argv)
+{
+ char *dbname = NULL, *dbhost = NULL, *dbport = NULL, *dbuser = NULL, *dbpwd = NULL;
+ eDBconn *dbc = NULL;
+ PGresult *res = NULL;
+
+ DEBUG(ctx, 20, "Function call: eDBconnect(ctx, %i, '%s')", argc, argv[0]);
+ if( (ctx == NULL) || (argc != 1) || (argv[0] == NULL) || (strlen(argv[0]) < 1) ) {
+ eurephia_log(ctx, LOG_PANIC, 0,
+ "edb-pgsql: Missing configuration file argument. "
+ "No database configured.");
+ return 0;
+ }
+
+ // Parse the config file with PostgreSQL connection information
+ dbc = (eDBconn *) malloc_nullsafe(ctx, sizeof(eDBconn)+2);
+ assert( dbc != NULL );
+ dbc->dbparams = ecfg_ReadConfig(ctx, argv[0]);
+ if( dbc->dbparams == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "edb-pgsql: Failed to parse the edb-pgsql configuration file (%s)",
+ argv[0]);
+ free_nullsafe(ctx, dbc);
+ return 0;
+ }
+ dbname = eGet_value(dbc->dbparams, "database");
+ dbhost = eGet_value(dbc->dbparams, "host");
+ dbport = eGet_value(dbc->dbparams, "port");
+ dbuser = eGet_value(dbc->dbparams, "user");
+ dbpwd = eGet_value(dbc->dbparams, "password");
+ if( dbname == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "edb-pgsql: Missing required database name");
+ return 0;
+ }
+
+ dbc->dbhandle = PQsetdbLogin(dbhost, dbport, NULL, NULL, dbname, dbuser, dbpwd);
+ if( dbc->dbhandle == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed to connect to the PostgreSQL database: Unknown error");
+ free_nullsafe(ctx, dbc);
+ return 0;
+ }
+
+ if( PQstatus(dbc->dbhandle) != CONNECTION_OK ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Failed to connect to the PostgreSQL database: %s",
+ PQerrorMessage(dbc->dbhandle));
+ free_nullsafe(ctx, dbc);
+ return 0;
+ }
+ dbc->dbname = strdup(dbname);
+
+ eurephia_log(ctx, LOG_INFO, 1, "Reading config from database");
+ dbc->config = NULL;
+ res = PQexec(dbc->dbhandle, "SELECT datakey, dataval FROM configuration");
+ if( res && (PQresultStatus(res) == PGRES_TUPLES_OK) ) {
+ int i = 0;
+ eurephiaVALUES *cfg = NULL;
+
+ cfg = eCreate_value_space(ctx, 11);
+ if( cfg == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Could not allocate memory for config variables");
+ PQclear(res);
+ PQfinish(dbc->dbhandle);
+ free_nullsafe(ctx, dbc);
+ return 0;
+ }
+ for( i = 0; i < PQntuples(res); i++ ) {
+ eAdd_value(ctx, cfg, PGgetValue(res, i, 0), PGgetValue(res, i, 1));
+ }
+ dbc->config = cfg;
+ PQclear(res);
+ } else {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed to query the eurephia configuration from the database: %s",
+ (res ? PQresultErrorMessage(res)
+ : PQerrorMessage(ctx->dbc->dbhandle)));
+ PQclear(res);
+ PQfinish(dbc->dbhandle);
+ eFree_values(ctx, dbc->dbparams);
+ free_nullsafe(ctx, dbc);
+
+ }
+ ctx->dbc = dbc;
+ return 1;
+}
+
+
+void eDBdisconnect(eurephiaCTX *ctx)
+{
+ eDBconn *dbc = NULL;
+
+ DEBUG(ctx, 20, "Function call: eDBdisconnect(ctx)");
+
+ if( ctx->dbc == NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "Database not open, cannot close database.");
+ return;
+ }
+
+ dbc = ctx->dbc;
+ eurephia_log(ctx, LOG_INFO, 1, "Closing database '%s'", dbc->dbname);
+
+ // Close database connection
+ PQfinish((PGconn *) dbc->dbhandle);
+ free_nullsafe(ctx, dbc->dbname);
+ dbc->dbhandle = NULL;
+
+ // Free up config memory
+ eFree_values(ctx, dbc->dbparams);
+ eFree_values(ctx, dbc->config);
+ free_nullsafe(ctx, dbc);
+ ctx->dbc = NULL;
+}
+
+
+/**
+ * @copydoc eDBauth_TLS()
+ */
+int eDBauth_TLS(eurephiaCTX *ctx, const char *org, const char *cname, const char *email,
+ const char *digest, const unsigned int depth)
+{
+ int certid = 0;
+ PGresult *dbr = NULL;
+ char *blid = NULL;
+ char depth_str[5];
+ const char **qry_args = NULL;
+
+ DEBUG(ctx, 20, "Function call: eDBauth_TLS(ctx, '%s', '%s', '%s', '%s', %i)",
+ org, cname, email, digest, depth);
+
+ if( !ctx || !ctx->dbc || !ctx->dbc->dbhandle ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "System error in eDBauth_TLS()");
+ return 0;
+ }
+
+ dbr = PQprepare(ctx->dbc->dbhandle, PREPSQL_TLS_AUTH,
+ "SELECT cert.certid, blid "
+ " FROM certificates cert"
+ " LEFT JOIN blacklist bl USING(digest)"
+ " WHERE organisation=$1::varchar AND common_name=$2::varchar "
+ " AND email=$3::varchar AND depth=$4::varchar "
+ " AND lower(cert.digest)=lower($5::varchar)\0",
+ 5, NULL);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Failed to prepare " PREPSQL_TLS_AUTH " SQL query: %s",
+ (dbr ? PQresultErrorMessage(dbr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ if( dbr ) {
+ PQclear(dbr);
+ }
+ return 0;
+ }
+ PQclear(dbr);
+
+ // Check if certificate is valid, and not too many attempts has been tried with
+ // the given certificate
+ snprintf(depth_str, 4, "%3i%c", depth, 0);
+ qry_args = calloc(5, sizeof(char *));
+ qry_args[0] = org;
+ qry_args[1] = cname;
+ qry_args[2] = email;
+ qry_args[3] = depth_str;
+ qry_args[4] = digest;
+ dbr = PQexecPrepared(ctx->dbc->dbhandle, PREPSQL_TLS_AUTH, 5, qry_args, NULL, NULL, 0);
+ free_nullsafe(ctx, qry_args);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not lookup certificate information: %s",
+ (dbr ? PQresultErrorMessage(dbr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ if( dbr ) {
+ PQclear(dbr);
+ }
+ return 0;
+ }
+
+ certid = atoi_nullsafe(PGgetValue(dbr, 0, 0));
+ blid = strdup_nullsafe(PGgetValue(dbr, 0, 1));
+
+ if( blid != NULL ) {
+ // If the certificate is blacklisted, update last access status and deny access.
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "Attempt with BLACKLISTED certificate (certid %i)", certid);
+ update_blacklist_attempt(ctx, blid);
+ certid = -1;
+ }
+ PQclear(dbr);
+ free_nullsafe(ctx, blid);
+
+ DEBUG(ctx, 20, "Result function call: eDBauth_TLS(ctx, '%s', '%s', '%s', '%s', %i) - %i",
+ org, cname, email, digest, depth, certid);
+
+ return certid;
+}
+
+
+/**
+ * @copydoc eDBauth_user()
+ */
+int eDBauth_user(eurephiaCTX *ctx, const int certid, const char *username, const char *passwd)
+{
+ int uicid = 0, pwdok = 0;
+ PGresult *dbr = NULL;
+ char certid_str[10];
+ char *crpwd = NULL, *activated = NULL, *deactivated = NULL;
+ char *blid_uname = NULL, *blid_cert = NULL;
+ char *dbpwd = NULL, *uid = NULL;
+ const char **qry_args = NULL;
+
+ DEBUG(ctx, 20, "Function call: eDBauth_user(ctx, %i, '%s','xxxxxxxx')", certid, username);
+
+ if( !ctx || !ctx->dbc || !ctx->dbc->dbhandle ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "System error in eDBauth_user()");
+ return 0;
+ }
+
+ dbr = PQprepare(ctx->dbc->dbhandle, PREPSQL_USERPWD_AUTH,
+ "SELECT uicid, ou.uid, activated, deactivated, bl1.blid, bl2.blid, password "
+ " FROM users ou"
+ " JOIN usercerts uc USING(uid) "
+ " LEFT JOIN blacklist bl1 ON( ou.username = bl1.username) "
+ " LEFT JOIN (SELECT blid, certid "
+ " FROM certificates "
+ " JOIN blacklist USING(digest)) bl2 ON(uc.certid = bl2.certid)"
+ " WHERE uc.certid = $1::INTEGER AND ou.username = $2::VARCHAR", 2, NULL);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed to prepare " PREPSQL_USERPWD_AUTH " SQL query: %s",
+ (dbr ? PQresultErrorMessage(dbr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ uicid = 0;
+ goto exit;
+ }
+ PQclear(dbr);
+
+
+ // Look up the user in the database
+ snprintf(certid_str, 9, "%8i%c", certid, 0);
+ qry_args = calloc(2, sizeof(char *));
+ qry_args[0] = certid_str;
+ qry_args[1] = username;
+ dbr = PQexecPrepared(ctx->dbc->dbhandle, PREPSQL_USERPWD_AUTH, 2, qry_args, NULL, NULL, 0);
+ free_nullsafe(ctx, qry_args);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not lookup user account information: %s",
+ (dbr ? PQresultErrorMessage(dbr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ uicid = 0;
+ goto exit;
+ }
+
+ if( PQntuples(dbr) != 1 ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "Authentication failed for user '%s'. "
+ "Could not find user or user-certificate link.", username);
+ sleep(2);
+ uicid = 0;
+ goto exit;
+ }
+
+ // Check if the user account is valid and that the password is correct
+ uid = PGgetValue(dbr, 0, 1);
+ activated = PGgetValue(dbr, 0, 2);
+ deactivated = PGgetValue(dbr, 0, 3);
+ blid_uname = PGgetValue(dbr, 0, 4);
+ blid_cert = PGgetValue(dbr, 0, 5);
+ dbpwd = PGgetValue(dbr, 0, 6);
+
+ if( dbpwd == NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0,"Authentication failed for user '%s'. DB error.",
+ username);
+ pwdok = 0;
+ } else {
+ crpwd = eurephia_pwd_crypt(ctx, passwd, dbpwd);
+ pwdok = ((crpwd != NULL) && (strcmp(crpwd, dbpwd) == 0) ? 1 : 0);
+ memset(crpwd, 0, strlen_nullsafe(crpwd));
+ memset(dbpwd, 0, strlen_nullsafe(dbpwd));
+ free_nullsafe(ctx, crpwd);
+ }
+
+ if( blid_uname != NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "User account is BLACKLISTED (uid: %s, %s)",
+ uid, username);
+ uicid = -1;
+ } else if( blid_cert != NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "User account linked with a BLACKLISTED certificate "
+ "(uid: %s, %s) - certid: %s",
+ uid, username, certid);
+ uicid = -1;
+ } else if( activated == NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "User account is not activated (uid: %s, %s)",
+ uid, username);
+ uicid = -1;
+ } else if( deactivated != NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "User account is deactivated (uid: %s, %s)",
+ uid, username);
+ uicid = -1;
+ } else if( pwdok != 1 ) {
+ eurephia_log(ctx, LOG_WARNING, 0,"Authentication failed for user '%s'. Wrong password.",
+ username);
+ sleep(2);
+ uicid = -1;
+ } else {
+ PGresult *upd = NULL;
+
+ uicid = atoi_nullsafe(PGgetValue(dbr, 0, 0));
+
+ // Update last accessed status
+ upd = PQprepare(ctx->dbc->dbhandle, PREPSQL_USERS_LASTACC_UPD,
+ "UPDATE users SET last_accessed = CURRENT_TIMESTAMP"
+ " WHERE uid = $1::INTEGER", 1, NULL);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed to prepare " PREPSQL_USERS_LASTACC_UPD " SQL query: %s",
+ (dbr ? PQresultErrorMessage(dbr)
+ : PQerrorMessage(ctx->dbc->dbhandle)));
+ } else if( dbr ) {
+ PQclear(upd);
+
+ qry_args = calloc(1, sizeof(char *));
+ qry_args[0] = uid;
+ upd = PQexecPrepared(ctx->dbc->dbhandle, PREPSQL_USERS_LASTACC_UPD,
+ 1, qry_args, NULL, NULL, 0);
+ free_nullsafe(ctx, qry_args);
+ if( !upd || (PQresultStatus(upd) != PGRES_TUPLES_OK) ) {
+ eurephia_log(ctx, LOG_ERROR, 0,
+ "Could not update last access status for uid %s", uid);
+ }
+ if( upd ) {
+ PQclear(upd);
+ }
+ }
+ }
+
+ exit:
+ if( dbr ) {
+ PQclear(dbr);
+ }
+ DEBUG(ctx, 20, "Result function call: eDBauth_user(ctx, %i, '%s','xxxxxxxx') - %i",
+ certid, username, uicid);
+
+ return uicid;
+}
+
+
+/**
+ * @copydoc eDBget_uid()
+ */
+int eDBget_uid(eurephiaCTX *ctx, const int certid, const char *username)
+{
+ int ret = 0;
+ PGresult *dbr = NULL;
+ const char **qry_args = NULL;
+ char certid_str[10];
+
+ DEBUG(ctx, 20, "Function call: eDBget_uid(ctx, %i, '%s')", certid, username);
+
+ if( !ctx || !ctx->dbc || !ctx->dbc->dbhandle ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "System error in eDBget_uid()");
+ return 0;
+ }
+
+ dbr = PQprepare(ctx->dbc->dbhandle, PREPSQL_USERS_GETUID,
+ "SELECT uid "
+ " FROM usercerts "
+ " JOIN users USING (uid) "
+ " WHERE certid = $1::INTEGER AND username = $1::VARCHAR",
+ 2, NULL);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed to prepare " PREPSQL_USERS_GETUID " SQL query: %s",
+ (dbr ? PQresultErrorMessage(dbr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ ret = -1;
+ goto exit;
+ }
+ PQclear(dbr);
+
+ snprintf(certid_str, 9, "%8i%c", certid, 0);
+ qry_args = calloc(2, sizeof(char *));
+ qry_args[0] = certid_str;
+ qry_args[1] = username;
+ dbr = PQexecPrepared(ctx->dbc->dbhandle, PREPSQL_USERPWD_AUTH, 2, qry_args, NULL, NULL, 0);
+ free_nullsafe(ctx, qry_args);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Failed to lookup userid for user '%s': %s",
+ username,
+ (dbr ? PQresultErrorMessage(dbr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ ret = -1;
+ goto exit;
+ }
+
+ switch( PQntuples(dbr) > 1 ) {
+ case 0:
+ eurephia_log(ctx, LOG_WARNING,0, "Failed to find userid for certid %i and username '%s'",
+ certid, username);
+ ret = 0;
+ break;
+
+ case 1:
+ ret = atoi_nullsafe(PGgetValue(dbr,0, 0));
+ break;
+ default:
+ eurephia_log(ctx, LOG_FATAL, 0, "Failed to lookup userid for user '%s'",
+ username);
+ ret = -1;
+ break;
+ }
+
+ exit:
+ if( dbr ) {
+ PQclear(dbr);
+ }
+
+ DEBUG(ctx, 20, "Result function call: eDBget_uid(ctx, %i, '%s') - %i", certid, username, ret);
+ return ret;
+}
+
+
+/**
+ * @copydoc eDBblacklist_check()
+ */
+int eDBblacklist_check(eurephiaCTX *ctx, const int type, const char *val)
+{
+ int blacklisted = 0;
+ char sql[4098], *blid = NULL;
+ const char **qry_args = NULL;
+ PGresult *dbr = NULL;
+
+ DEBUG(ctx, 20, "Function call: eDBblacklist_check(ctx, '%s', '%s')",
+ eDBattempt_types[type].descr, val);
+
+ qry_args = calloc(1, sizeof(char *));
+ qry_args[0] = val;
+
+ snprintf(sql, 4096,
+ "SELECT blid"
+ " FROM blacklist"
+ " WHERE %s = %s%s$1%s%c",
+ eDBattempt_types[type].colname_where,
+ defaultValue(eDBattempt_types[type].value_func, ""),
+ (strlen_nullsafe(eDBattempt_types[type].value_func) > 0 ? "(" : ""),
+ (strlen_nullsafe(eDBattempt_types[type].value_func) > 0 ? ")" : ""), 0);
+
+ dbr = PQprepare(ctx->dbc->dbhandle, PREPSQL_BLACKLIST_CHECK, sql, 1, NULL);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed to prepare " PREPSQL_BLACKLIST_CHECK " SQL query: %s",
+ (dbr ? PQresultErrorMessage(dbr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ blacklisted = -1;
+ goto exit;
+ }
+ PQclear(dbr);
+
+ dbr = PQexecPrepared(ctx->dbc->dbhandle, PREPSQL_BLACKLIST_CHECK, 2, qry_args, NULL, NULL, 0);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Failed to lookup %s in the blacklist for '%s': %s",
+ eDBattempt_types[type].descr, val,
+ (dbr ? PQresultErrorMessage(dbr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ blacklisted = -1;
+ goto exit;
+ }
+
+ if( dbr && PQntuples(dbr) > 0 ) {
+ blid = PQgetvalue(dbr, 0, 0);
+ if( blid != NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "Attempt from blacklisted %s: %s",
+ eDBattempt_types[type].descr, val);
+ blacklisted = 1; // [type] is blacklisted
+ }
+ update_blacklist_attempt(ctx, blid);
+ } else {
+ eurephia_log(ctx, LOG_FATAL, 0, "Querying blacklist for %s failed",
+ eDBattempt_types[type].descr);
+ };
+ PQclear(dbr);
+
+ // Check if this [type] have been tried before and consider if it should be blacklisted
+ if( blacklisted == 0) {
+ char *atpid = NULL;
+ int atpexceed = -1;
+
+ snprintf(sql, 4096,
+ "SELECT atpid, attempts >= '%s' "
+ " FROM attempts "
+ " WHERE %s = $1",
+ defaultValue(eGet_value(ctx->dbc->config, eDBattempt_types[type].allow_cfg),
+ eDBattempt_types[type].default_value),
+ eDBattempt_types[type].colname_where);
+ dbr = PQprepare(ctx->dbc->dbhandle, PREPSQL_ATTEMPTS_CHECK, sql, 1, NULL);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed to prepare " PREPSQL_ATTEMPTS_CHECK " SQL query: %s",
+ (dbr ? PQresultErrorMessage(dbr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ blacklisted = -1;
+ goto exit;
+ }
+ PQclear(dbr);
+
+ dbr = PQexecPrepared(ctx->dbc->dbhandle, PREPSQL_BLACKLIST_CHECK, 1, qry_args, NULL, NULL, 0);
+ if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed look up attempts counter for %s in the blacklist check on '%s': %s",
+ eDBattempt_types[type].descr, val,
+ (dbr ? PQresultErrorMessage(dbr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ blacklisted = -1;
+ goto exit;
+ }
+
+ if( dbr && (PQntuples(dbr) > 0) ) {
+ atpid = PQgetvalue(dbr, 0, 0);
+ atpexceed = atoi_nullsafe(PQgetvalue(dbr, 0, 1));
+
+ // If [type] has reached attempt limit and it is not black listed, black list it
+ if( (atpexceed > 0) && (blid == NULL) ) {
+ PGresult *blr = NULL;
+
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "%s got BLACKLISTED due to too many failed attempts: %s",
+ eDBattempt_types[type].descr, val);
+
+ snprintf(sql, 4096, "INSERT INTO blacklist (%s) VALUES ($1)",
+ eDBattempt_types[type].colname);
+ blr = PQprepare(ctx->dbc->dbhandle, PREPSQL_BLACKLIST_REGISTER, sql, 1, NULL);
+ if( !blr || (PQresultStatus(blr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed to prepare " PREPSQL_ATTEMPTS_CHECK " SQL query: %s",
+ (blr ? PQresultErrorMessage(blr) : PQerrorMessage(ctx->dbc->dbhandle)));
+ } else {
+ PQclear(blr);
+ blr = PQexecPrepared(ctx->dbc->dbhandle, PREPSQL_BLACKLIST_REGISTER, 1, qry_args,
+ NULL, NULL, 0);
+ if( !blr || (PQresultStatus(blr) != PGRES_COMMAND_OK) ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Failed to register %s value '%s' in the blacklist: %s",
+ eDBattempt_types[type].descr, val,
+ (blr ? PQresultErrorMessage(blr)
+ : PQerrorMessage(ctx->dbc->dbhandle)));
+ }
+ }
+ PQclear(blr);
+ blacklisted = 1; // [type] is blacklisted
+ }
+ atpid = NULL;
+ } else {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Querying attempts counts for blacklisted %s failed",
+ eDBattempt_types[type].descr);
+ }
+ }
+ DEBUG(ctx, 20, "Result - function call: eDBblacklist_check(ctx, '%s', '%s') - %i",
+ eDBattempt_types[type].descr, val, blacklisted);
+
+ exit:
+ blid = NULL;
+ PQclear(dbr);
+ free_nullsafe(ctx, qry_args);
+
+ return blacklisted;
+}
+
+
+/**
+ * @copydoc eDBregister_attempt()
+ */
+void eDBregister_attempt(eurephiaCTX *ctx, int type, int mode, const char *value)
+{
+ DEBUG(ctx, 20, "Function call: eDBregister_attempt(ctx, %s, %s, '%s')",
+ eDBattempt_types[type].colname,
+ (mode == ATTEMPT_RESET ? "ATTEMPT_RESET" : "ATTEMPT_REGISTER"),
+ value);
+
+ /*
+ "SELECT atpid, attempts > %s, blid, attempts "
+ " FROM attempts "
+ " LEFT JOIN blacklist USING(%s)"
+ " WHERE %s = %s%s'%q'%s",
+ defaultValue(eGet_value(ctx->dbc->config, eDBattempt_types[type].allow_cfg),
+ eDBattempt_types[type].default_value),
+ eDBattempt_types[type].colname,
+ eDBattempt_types[type].colname_where,
+ defaultValue(eDBattempt_types[type].value_func, ""),
+ (strlen_nullsafe(eDBattempt_types[type].value_func) > 0 ? "(" : ""),
+ value,
+ (strlen_nullsafe(eDBattempt_types[type].value_func) > 0 ? ")" : "")
+ );
+ */
+}
+
+/**
+ * @copydoc eDBregister_login()
+ */
+int eDBregister_login(eurephiaCTX *ctx, eurephiaSESSION *skey, const int certid, const int uid,
+ const char *proto, const char *remipaddr, const char *remport,
+ const char *vpnipaddr, const char *vpnipmask)
+{
+ DEBUG(ctx, 20, "Function call: eDBregister_login(ctx, '%s', %i, %i, '%s','%s','%s','%s','%s')",
+ skey->sessionkey, certid, uid, proto, remipaddr, remport, vpnipaddr, vpnipmask);
+
+ /*
+ "INSERT INTO lastlog (uid, certid, "
+ " protocol, remotehost, remoteport,"
+ " vpnipaddr, vpnipmask,"
+ " sessionstatus, sessionkey, login) "
+ "VALUES (%i, %i, '%q','%q','%q','%q','%q', 1,'%q', CURRENT_TIMESTAMP)",
+ uid, certid, proto, remipaddr, remport, vpnipaddr, vpnipmask, skey->sessionke
+ */
+ return 0;
+}
+
+
+/**
+ * @copydoc eDBregister_vpnmacaddr()
+ */
+int eDBregister_vpnmacaddr(eurephiaCTX *ctx, eurephiaSESSION *session, const char *macaddr)
+{
+ DEBUG(ctx, 20, "Function call: eDBregister_vpnmacaddr(ctx, '%s', '%s')",
+ session->sessionkey, macaddr);
+
+ /*
+ "INSERT INTO macaddr_history (sessionkey, macaddr) VALUES ('%q','%q')",
+ session->sessionkey, macaddr);
+
+ "UPDATE lastlog SET sessionstatus = 2, macaddr = '%q' "
+ " WHERE sessionkey = '%q' AND sessionstatus = 1", macaddr, session->sessionkey);
+
+ */
+
+ // Save the MAC address in the session values register - needed for the destroy session
+ if( eDBset_session_value(ctx, session, "macaddr", macaddr) == 0 ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not save MAC address into session variables");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/**
+ * @copydoc eDBregister_logout()
+ */
+int eDBregister_logout(eurephiaCTX *ctx, eurephiaSESSION *skey,
+ const char *bytes_sent, const char *bytes_received, const char *duration)
+{
+ DEBUG(ctx, 20, "Function call: eDBregister_logout(ctx, '%s', %s, %s)",
+ skey->sessionkey, bytes_sent, bytes_received);
+
+ /*
+ "UPDATE lastlog "
+ " SET sessionstatus = 3, logout = CURRENT_TIMESTAMP, "
+ " bytes_sent = '%i', bytes_received = '%i', session_duration = '%i' "
+ " WHERE sessionkey = '%q' AND sessionstatus = 2",
+ atoi_nullsafe(bytes_sent), atoi_nullsafe(bytes_received),
+ atoi_nullsafe(duration), skey->sessionkey);
+ */
+
+ skey->sessionstatus = SESSION_LOGGEDOUT;
+ return 1;
+}
+
+
+/**
+ * @copydoc eDBget_sessionkey_seed()
+ */
+char *eDBget_sessionkey_seed(eurephiaCTX *ctx, sessionType type, const char *sessionseed)
+{
+ char *skey = NULL;
+
+ DEBUG(ctx, 20, "eDBget_sessionkey_seed(ctx, %i, '%s')", type, sessionseed);
+
+ if( sessionseed == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 1,
+ "eDBget_sessionkey: No session seed given - cannot locate sessionkey");
+ return NULL;
+ }
+
+ switch( type ) {
+ case stSESSION:
+ /*
+ "SELECT sessionkey "
+ " FROM sessionkeys "
+ " JOIN lastlog USING (sessionkey)"
+ " WHERE sessionstatus IN (1,2)"
+ " AND sessionseed = '%q'",
+ sessionseed);
+ */
+ break;
+
+ case stAUTHENTICATION:
+ /*
+ "SELECT sessionkey"
+ " FROM sessionkeys"
+ " LEFT JOIN lastlog USING(sessionkey)"
+ " WHERE sessionstatus IS NULL"
+ " AND sessionseed = '%q'",
+ sessionseed);
+ */
+ break;
+
+ default:
+ eurephia_log(ctx, LOG_ERROR, 0, "Invalid session type: %i", type);
+ return NULL;
+ }
+
+ return skey;
+}
+
+
+/**
+ * @copydoc eDBget_sessionkey_macaddr()
+ */
+char *eDBget_sessionkey_macaddr(eurephiaCTX *ctx, const char *macaddr)
+{
+ char *skey = NULL;
+
+ DEBUG(ctx, 20, "eDBget_sessionkey_macaddr(ctx, '%s')", macaddr);
+
+ // Find sessionkey from MAC address
+ /*
+ "SELECT sessionkey "
+ " FROM sessions "
+ " JOIN lastlog USING (sessionkey)"
+ " WHERE sessionstatus = 3 "
+ " AND datakey = 'macaddr'"
+ " AND dataval = '%q'", macaddr);
+ */
+
+ return skey;
+}
+
+
+/**
+ * @copydoc eDBcheck_sessionkey_uniqueness()
+ */
+int eDBcheck_sessionkey_uniqueness(eurephiaCTX *ctx, const char *seskey)
+{
+ int uniq = 0;
+
+ DEBUG(ctx, 20, "eDBcheck_sessionkey_uniqueness(ctx, '%s')", seskey);
+ if( seskey == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 1,
+ "eDBcheck_sessionkey_uniqness: Invalid session key given");
+ return 0;
+ }
+
+ switch( ctx->context_type ) {
+ case ECTX_NO_PRIVILEGES:
+ return 0;
+ break;
+
+ case ECTX_ADMIN_CONSOLE:
+ case ECTX_ADMIN_WEB:
+ /*
+ "SELECT count(sessionkey) = 0 "
+ "FROM eurephia_adminlog WHERE sessionkey = '%q'", seskey);
+ */
+ break;
+
+ case ECTX_PLUGIN_AUTH:
+ default:
+ /*
+ "SELECT count(sessionkey) = 0 "
+ "FROM lastlog WHERE sessionkey = '%q'", seskey);
+ */
+ break;
+ }
+ return uniq;
+
+}
+
+
+/**
+ * @copydoc eDBregister_sessionkey()
+ */
+int eDBregister_sessionkey(eurephiaCTX *ctx, const char *seed, const char *seskey) {
+ // dbresult *res;
+
+ DEBUG(ctx, 20, "eDBregister_sessionkey(ctx, '%s', '%s')", seed, seskey);
+ if( (seed == NULL) || (seskey == NULL) ) {
+ eurephia_log(ctx, LOG_FATAL, 1,
+ "eDBregister_sessionkey: Invalid session seed or session key given");
+ return 0;
+ }
+
+ /*
+ * "INSERT INTO openvpn_sessionkeys (sessionseed, sessionkey) VALUES('%q','%q')",
+
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "eDBregister_sessionkey: Error registering sessionkey into 'sessionkeys'");
+ return 0;
+ }
+ */
+ return 1;
+}
+
+/**
+ * Removes a session key reference to a short time session seed conversion table
+ *
+ * @param ctx eurephiaCTX
+ * @param seskey String containing the session key reference to remove
+ *
+ * @return Returns 1 on success, otherwise 0.
+ *
+ */
+int eDBremove_sessionkey(eurephiaCTX *ctx, const char *seskey) {
+ // dbresult *res;
+
+ DEBUG(ctx, 20, "eDBremove_sessionkey(ctx, '%s')", seskey);
+ if( seskey == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 1,
+ "eDBremove_sessionkey: Invalid session key given");
+ return 0;
+ }
+
+ /*
+ * "DELETE FROM openvpn_sessionkeys WHERE sessionkey = '%q'", seskey);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "eDBremove_sessionkey: Error removing sessionkey from openvpn_sessionkeys");
+ return 0;
+ }
+ */
+ return 1;
+}
+
+
+/**
+ * @copydoc eDBload_sessiondata()
+ */
+eurephiaVALUES *eDBload_sessiondata(eurephiaCTX *ctx, const char *sesskey)
+{
+ eurephiaVALUES *sessvals = NULL;
+
+
+ DEBUG(ctx, 20, "Function call: eDBload_sessiondata(ctx, '%s')", sesskey);
+
+ sessvals = eCreate_value_space(ctx, 10);
+
+ /*
+ "SELECT datakey, dataval FROM sessions WHERE sessionkey = '%q'",
+ sesskey
+ */
+
+ return sessvals;
+}
+
+
+/**
+ * @copydoc eDBstore_session_value()
+ */
+int eDBstore_session_value(eurephiaCTX *ctx, eurephiaSESSION *session, int mode,
+ const char *key, const char *val)
+{
+ if( session == NULL ) {
+ DEBUG(ctx, 20,
+ "Function call failed to eDBstore_session_value(ctx, ...): Non-existing session key");
+ return 0;
+ }
+
+ DEBUG(ctx, 20, "Function call: eDBstore_session_value(ctx, '%s', %i, '%s', '%s')",
+ session->sessionkey, mode, key, val);
+
+ switch( mode ) {
+ case SESSVAL_NEW:
+ /*
+ "INSERT INTO sessions (sessionkey, datakey, dataval) "
+ "VALUES ('%q','%q','%q')", session->sessionkey, key, val);
+ */
+ break;
+
+ case SESSVAL_UPDATE:
+ /*
+ "UPDATE sessions SET dataval = '%q' "
+ " WHERE sessionkey = '%q' AND datakey = '%q'",
+ val, session->sessionkey, key);
+ */
+
+ case SESSVAL_DELETE:
+ /*
+ "DELETE FROM sessions "
+ " WHERE sessionkey = '%q' AND datakey = '%q'",
+ session->sessionkey, key);
+ */
+ break;
+
+ default:
+ eurephia_log(ctx, LOG_FATAL, 0, "Unknown eDBstore_session_value mode '%i'", mode);
+ return 0;
+ }
+ return 1;
+}
+
+
+/**
+ * @copydoc eDBdestroy_session()
+ */
+int eDBdestroy_session(eurephiaCTX *ctx, eurephiaSESSION *session)
+{
+ DEBUG(ctx, 20, "Function call: eDBdestroy_session(ctx, '%s')", session->sessionkey);
+
+ if( (session == NULL) || (session->sessionkey == NULL) ) {
+ eurephia_log(ctx, LOG_WARNING, 1, "No active session given to be destroyed");
+ return 1;
+ }
+
+ // Update session status - if we have a "real" session (not auth-session)
+ if( session->type == stSESSION ) {
+ /*
+ "UPDATE lastlog "
+ " SET sessionstatus = 4, session_deleted = CURRENT_TIMESTAMP "
+ " WHERE sessionkey = '%q' AND sessionstatus = 3", session->sessionkey);
+ */
+ }
+
+ // Delete session variables
+ /*
+ "DELETE FROM sessions WHERE sessionkey = '%q'", session->sessionkey);
+ */
+
+ // Delete the session key
+ /*
+ "DELETE FROM sessionkeys WHERE sessionkey = '%q'", seskey);
+ */
+ return 0;
+}
+
+
+/**
+ * @copydoc eDBget_firewall_profile()
+ */
+char *eDBget_firewall_profile(eurephiaCTX *ctx, eurephiaSESSION *session)
+{
+ char *ret = NULL;
+
+
+ DEBUG(ctx, 20, "Function call: eDBget_firewall_profile(ctx, {session}'%s')",
+ session->sessionkey);
+
+ /*
+ "SELECT fw_profile "
+ " FROM lastlog "
+ " JOIN usercerts USING(certid, uid)"
+ " JOIN accesses USING(accessprofile)"
+ " WHERE sessionkey = '%q'", session->sessionkey);
+ */
+
+ return ret;
+}
+
+
+/**
+ * @copydoc eDBget_blacklisted_ip()
+ */
+eurephiaVALUES *eDBget_blacklisted_ip(eurephiaCTX *ctx)
+{
+ eurephiaVALUES *ret = NULL;
+
+ DEBUG(ctx, 20, "Function call: eDBget_blacklisted_ip(ctx)");
+
+ /*
+ "SELECT remoteip FROM blacklist WHERE remoteip IS NOT NULL");
+ */
+
+ ret = eCreate_value_space(ctx, 21);
+ // copy SQL result into eurephiaVALUES chain
+
+ return ret;
+
+}