diff options
| author | David Sommerseth <dazo@users.sourceforge.net> | 2012-01-15 00:41:36 +0100 |
|---|---|---|
| committer | David Sommerseth <dazo@users.sourceforge.net> | 2013-06-13 01:01:55 +0200 |
| commit | 6c1f8ff4f7966f0d1f9cb1b2ff447f0dfc5f8aeb (patch) | |
| tree | e9b40635448f01df14975fad66c0b41c6b645364 | |
| parent | a2b54da7ebec0883fcc812ae86033a6d5fa36c5d (diff) | |
| download | eurephia-6c1f8ff4f7966f0d1f9cb1b2ff447f0dfc5f8aeb.tar.gz eurephia-6c1f8ff4f7966f0d1f9cb1b2ff447f0dfc5f8aeb.tar.xz eurephia-6c1f8ff4f7966f0d1f9cb1b2ff447f0dfc5f8aeb.zip | |
edb-pgsql: First implementation of all OpenVPN auth related functions
This is a working implementation of the PostgreSQL driver, where only the
driver functions needed by OpenVPN for authentication are implemented.
There are still more enhancements to be done, but this is usable.
Signed-off-by: David Sommerseth <dazo@users.sourceforge.net>
| -rw-r--r-- | database/postgresql/edb-pgsql.c | 1386 |
1 files changed, 1043 insertions, 343 deletions
diff --git a/database/postgresql/edb-pgsql.c b/database/postgresql/edb-pgsql.c index e1330b5..eabe4fe 100644 --- a/database/postgresql/edb-pgsql.c +++ b/database/postgresql/edb-pgsql.c @@ -1,6 +1,6 @@ /* edb-pgsql.c -- PostgreSQL database driver for eurephia * - * GPLv2 only - Copyright (C) 2011 + * GPLv2 only - Copyright (C) 2011, 2012 * David Sommerseth <dazo@users.sourceforge.net> * * This program is free software; you can redistribute it and/or @@ -49,29 +49,155 @@ #include <eurephiadb_session_struct.h> #include <passwd.h> +typedef enum { PREPSQL_NONE = 0, PREPSQL_TLS_AUTH, PREPSQL_USERPWD_AUTH, + PREPSQL_BLACKLIST_ATTEMPTUPD, PREPSQL_USERS_LASTACC_UPD, + PREPSQL_USERS_GETUID, PREPSQL_ATTEMPTS_RESET, PREPSQL_ATTEMPTS_INCR, + PREPSQL_ATTEMPTS_REG_CERT, PREPSQL_ATTEMPTS_REG_USERNAME, + PREPSQL_ATTEMPTS_REG_IPADDR, + PREPSQL_BLACKLIST_CHECK_CERT, PREPSQL_BLACKLIST_CHECK_USERNAME, + PREPSQL_BLACKLIST_CHECK_IPADDR, + PREPSQL_BLACKLIST_REG_CERT, PREPSQL_BLACKLIST_REG_USERNAME, + PREPSQL_BLACKLIST_REG_IPADDR, + PREPSQL_SESSIONKEY_GETSEED_SESSION, PREPSQL_SESSIONKEY_GETSEED_AUTH, + PREPSQL_SESSIONKEY_GETMAC, + PREPSQL_SESSIONKEY_UNIQ_ADMIN, PREPSQL_SESSIONKEY_UNIQ_PLAUTH, + PREPSQL_SESSIONKEY_REGISTER, PREPSQL_SESSIONKEY_REMOVE, + PREPSQL_SESSIONVARS_LOAD, PREPSQL_SESSIONVARS_STORE_NEW, + PREPSQL_SESSIONVARS_STORE_UPDATE, PREPSQL_SESSIONVARS_STORE_DELETE, + PREPSQL_SESSIONS_DESTROY_LASTLOG, PREPSQL_SESSIONS_DESTROY_SESS, + PREPSQL_REGISTER_LOGIN, PREPSQL_REGISTER_LOGOUT, + PREPSQL_MACHISTORY_REGISTER, PREPSQL_MACHISTORY_LASTLOG, + PREPSQL_FIREWALL_GETPROFILE +} _ePG_prepID; + +typedef struct { + _ePG_prepID prepid; + const char *name; + unsigned int numargs; + unsigned int prepared; +} _ePGprepStatements_t; + +static _ePGprepStatements_t _ePGprepStatements[] = { + {.prepid = PREPSQL_TLS_AUTH, + .name = "eurephia_tls_auth", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_USERPWD_AUTH, + .name = "eurephia_userpwd_auth", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_BLACKLIST_ATTEMPTUPD, + .name ="eurephia_blacklist_attupd" , .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_USERS_LASTACC_UPD, + .name = "eurephia_users_lastacc_upd", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_USERS_GETUID, + .name = "eurephia_getuid", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_ATTEMPTS_RESET, + .name = "eurephia_attempts_reset", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_ATTEMPTS_INCR, + .name = "eurephia_attempts_increment", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_ATTEMPTS_REG_CERT, + .name = "eurephia_attempts_reg_cert", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_ATTEMPTS_REG_USERNAME, + .name = "eurephia_attempts_reg_username", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_ATTEMPTS_REG_IPADDR, + .name = "eurephia_attempts_reg_ipaddr", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_BLACKLIST_CHECK_CERT, + .name = "eurephia_blacklist_check_cert", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_BLACKLIST_CHECK_USERNAME, + .name = "eurephia_blacklist_check_username", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_BLACKLIST_CHECK_IPADDR, + .name = "eurephia_blacklist_check_cert_ipaddr", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_BLACKLIST_REG_CERT, + .name = "eurephia_blacklist_reg_cert", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_BLACKLIST_REG_USERNAME, + .name = "eurephia_blacklist_reg_username", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_BLACKLIST_REG_IPADDR, + .name = "eurephia_blacklist_reg_ipaddr", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONKEY_GETSEED_SESSION, + .name = "eurephia_sessionkey_getseed_session", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONKEY_GETSEED_AUTH, + .name = "eurephia_sessionkey_getseed_auth", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONKEY_GETMAC, + .name = "eurephia_sessionkey_getmac", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONKEY_UNIQ_ADMIN, + .name = "eurephia_sessionkey_uniq_admin", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONKEY_UNIQ_PLAUTH, + .name = "eurephia_sessionkey_uniq_plauth", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONKEY_REGISTER, + .name = "eurephia_sessionkey_register", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONKEY_REMOVE, + .name = "eurephia_sessionkey_remove", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONVARS_LOAD, + .name = "eurephia_sessionvars_load", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONVARS_STORE_NEW, + .name = "eurephia_sessionvars_store_new", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONVARS_STORE_UPDATE, + .name = "eurephia_sessionvars_store_upd", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONVARS_STORE_DELETE, + .name = "eurephia_sessionvars_store_del", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONS_DESTROY_LASTLOG, + .name = "eurephia_sessions_destr_lastlogupd", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_SESSIONS_DESTROY_SESS, + .name = "eurephia_sessions_destr_sessions", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_REGISTER_LOGIN, + .name = "eurephia_register_login", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_REGISTER_LOGOUT, + .name = "eurephia_register_logout", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_MACHISTORY_REGISTER, + .name = "eurephia_machistory_reg", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_MACHISTORY_LASTLOG, + .name = "eurephia_machistory_lastlog_upd", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_FIREWALL_GETPROFILE, + .name = "eurephia_firewall_getprofile", .numargs = 0, .prepared = 0}, + {.prepid = PREPSQL_NONE, + .name = NULL, .numargs = 0, .prepared = 0}, +}; + +/* FIXME: Go through the code and place all ePGprepStatement() in a function called from eDBconnect() + * Let the SQL be declared in _ePGprepStatements_t ... the prep-function will just loop _ePGprepStatements[] + */ + /** * 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 */ + 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, value will be passed through given SQL function */ + _ePG_prepID sql_blacklist_check; /** Prepared SQL ID reference for blacklist check queries */ + _ePG_prepID sql_blacklist_reg; /** Prepared SQL ID reference for blacklist register queries */ + _ePG_prepID sql_attempts_reg; /** Prepared SQL ID reference for attempts register queries */ } 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} + {NULL}, + {.colname = "remoteip", .colname_where = "remoteip", + .allow_cfg = "allow_ipaddr_attempts", .descr = "IP Address", + .default_value = "10", .value_func = NULL, + .sql_blacklist_check = PREPSQL_BLACKLIST_CHECK_IPADDR, + .sql_blacklist_reg = PREPSQL_BLACKLIST_REG_IPADDR, + .sql_attempts_reg = PREPSQL_ATTEMPTS_REG_IPADDR + }, + {.colname = "digest", .colname_where = "lower(digest)", + .allow_cfg = "allow_cert_attempts", .descr = "Certificate", + .default_value = "5", .value_func = "lower", + .sql_blacklist_check = PREPSQL_BLACKLIST_CHECK_CERT, + .sql_blacklist_reg = PREPSQL_BLACKLIST_REG_CERT, + .sql_attempts_reg = PREPSQL_ATTEMPTS_REG_CERT + }, + {.colname = "username", .colname_where = "username", + .allow_cfg = "allow_username_attempts", .descr = "Username", + .default_value = "3", .value_func = NULL, + .sql_blacklist_check = PREPSQL_BLACKLIST_CHECK_USERNAME, + .sql_blacklist_reg = PREPSQL_BLACKLIST_REG_USERNAME, + .sql_attempts_reg = PREPSQL_ATTEMPTS_REG_USERNAME + }, + {NULL} }; @@ -84,43 +210,122 @@ static inline char *ePGgetValue(PGresult *res, int row, int col) { } -static void ePGerrorMessage(eurephiaCTX *ctx, PGresult *dbr, int logdst, int loglvl, - const char *prepsql, const char *fmt, ...) +int ePGprepStatementGetID(_ePG_prepID prepid) +{ + int i; + for( i = 0; _ePGprepStatements[i].prepid != PREPSQL_NONE; i++ ) { + if( _ePGprepStatements[i].prepid == prepid ) { + return i; + } + } + return -1; +} + + +#define ePGerrorMessage(ctx, dbr, logdst, loglvl, prepid, fmt...) __ePGerrorMessage(ctx, dbr, logdst,loglvl, prepid, __FILE__, __LINE__, ## fmt) +static void __ePGerrorMessage(eurephiaCTX *ctx, PGresult *dbr, int logdst, int loglvl, + _ePG_prepID prepid, const char *errfile, const long errline, + const char *fmt, ...) { char msgfmt[514]; va_list ap; - + int id = -1; + + if( prepid != PREPSQL_NONE ) { + id = ePGprepStatementGetID(prepid); + if( id < 0 ) { + eurephia_log(ctx, LOG_ERROR, 0, + "Failed to map prepared statement ID %i to " + "a valid statement", prepid); + return; + } + } memset(&msgfmt, 0, 514); va_start(ap, fmt); - snprintf(msgfmt, 512, "[%s] SQL query failed: %s: %s", - prepsql, fmt, - (dbr != NULL ? PQresultErrorMessage(dbr) - : (ctx->dbc != NULL ? PQerrorMessage(ctx->dbc->dbhandle) : "[unknown error]") - )); + if( prepid != PREPSQL_NONE ) { + snprintf(msgfmt, 512, "[%s] SQL query failed: %s %s: %s", + _ePGprepStatements[id].name, + (dbr != NULL ? PQresStatus(PQresultStatus(dbr)) : ""), fmt, + (dbr != NULL ? PQresultErrorMessage(dbr) + : (ctx->dbc != NULL ? PQerrorMessage(ctx->dbc->dbhandle) + : "[unknown error]") + )); + } else { + snprintf(msgfmt, 512, "SQL query failed: %s %s: %s", + (dbr != NULL ? PQresStatus(PQresultStatus(dbr)) : ""), + fmt, + (dbr != NULL ? PQresultErrorMessage(dbr) + : (ctx->dbc != NULL ? PQerrorMessage(ctx->dbc->dbhandle) + : "[unknown error]") + )); + } +#ifdef ENABLE_DEBUG + _veurephia_log_func(ctx, logdst, loglvl, errfile, errline, ap, msgfmt); +#else veurephia_log(ctx, logdst, loglvl, ap, msgfmt); +#endif va_end(ap); memset(&msgfmt, 0, 514); - PQclear(dbr); - if( (loglvl == LOG_EMERG) && (ctx->dbc != NULL) ) { + if( dbr ) { + PQclear(dbr); + } + if( (loglvl == LOG_EMERG) && (ctx->dbc != NULL) + && (PQstatus(ctx->dbc->dbhandle) != CONNECTION_OK) ) { PQfinish(ctx->dbc->dbhandle); } } -#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" +int ePGprepStatement(eurephiaCTX *ctx, _ePG_prepID prepid, const char *sql, int argc) +{ + int id; + + /* Check if this statement is already prepared */ + id = ePGprepStatementGetID(prepid); + if( _ePGprepStatements[id].prepid == prepid ) { + PGresult *dbr = NULL; + _ePGprepStatements_t *prep = &_ePGprepStatements[id]; + + if( prep->prepared == 1 ) { + /* statement found, and was already prepared */ + return id; + } + + /* statement found in lookup table, but not prepared in database */ + dbr = PQprepare(ctx->dbc->dbhandle, + prep->name, sql, argc, NULL); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, prepid, + "Failed to prepare SQL query: %s", sql); + return -2; + } + PQclear(dbr); + _ePGprepStatements[id].numargs = argc; + _ePGprepStatements[id].prepared = 1; /* Flag statement as prepared */ + return id; + } + return -1; +}; + + +PGresult * ePGprepExec(eurephiaCTX *ctx, int prepid, const char **qry_args) { + if( prepid < 0 ) { + eurephia_log(ctx, LOG_ERROR, 0, + "Invalid prepared statement ID %i", prepid); + return NULL; + } + return PQexecPrepared(ctx->dbc->dbhandle, + _ePGprepStatements[prepid].name, + _ePGprepStatements[prepid].numargs, + qry_args, NULL, NULL, 0); +} + /** * @copydoc eDB_DriverVersion() */ const char *eDB_DriverVersion(void) { - return "edb-pgsql (v"DRIVERVERSION") David Sommerseth 2011 (C) GPLv2"; + return "edb-pgsql (v"DRIVERVERSION") David Sommerseth 2012 (C) GPLv2"; } @@ -132,7 +337,6 @@ int eDB_DriverAPIVersion() { } - /** * Internal driver function for simplifying update of the blacklist table. It will simply just * update the 'last_accessed' field in the blacklist table. @@ -143,23 +347,23 @@ int eDB_DriverAPIVersion() { static inline void update_blacklist_attempt(eurephiaCTX *ctx, const char *blid) { if( blid != NULL ) { PGresult *dbr = NULL; + int prepid = -1; 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) ) { + prepid = ePGprepStatement(ctx, PREPSQL_BLACKLIST_ATTEMPTUPD, + "UPDATE blacklist" + " SET last_accessed = CURRENT_TIMESTAMP" + " WHERE blid = $1", 1); + if( prepid < 0 ) { ePGerrorMessage(ctx, dbr, LOG_CRITICAL, 0, PREPSQL_BLACKLIST_ATTEMPTUPD, "Preparing last attempt query update failed"); return; } - 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); + dbr = ePGprepExec(ctx, prepid, qry_args); free_nullsafe(ctx, qry_args); if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { ePGerrorMessage(ctx, dbr, LOG_CRITICAL, 0, PREPSQL_BLACKLIST_ATTEMPTUPD, @@ -172,7 +376,6 @@ static inline void update_blacklist_attempt(eurephiaCTX *ctx, const char *blid) } - /** * @copydoc eDBconnect() * Connect to the database ... connection is stored in the eurephiaCTX context @@ -223,8 +426,8 @@ int eDBconnect(eurephiaCTX *ctx, const int argc, const char **argv) } if( PQstatus(dbc->dbhandle) != CONNECTION_OK ) { - ePGerrorMessage(ctx, NULL, LOG_EMERG, 0, "DB-INIT", - "Failed to connect to the PostgreSQL database '%s'", + ePGerrorMessage(ctx, NULL, LOG_EMERG, 0, PREPSQL_NONE, + "[DB-INIT] Failed to connect to the PostgreSQL database '%s'", dbname); ctx->dbc = NULL; free_nullsafe(ctx, dbc); @@ -254,8 +457,8 @@ int eDBconnect(eurephiaCTX *ctx, const int argc, const char **argv) dbc->config = cfg; PQclear(res); } else { - ePGerrorMessage(ctx, res, LOG_EMERG, 0, "DB-INIT", - "Failed to the configuration from the database"); + ePGerrorMessage(ctx, res, LOG_EMERG, 0, PREPSQL_NONE, + "[DB-INIT] Failed to the configuration from the database"); eFree_values(ctx, dbc->dbparams); free_nullsafe(ctx, dbc); return 0; @@ -264,6 +467,9 @@ int eDBconnect(eurephiaCTX *ctx, const int argc, const char **argv) } +/** + * @copydoc eDBdisconnect() + */ void eDBdisconnect(eurephiaCTX *ctx) { eDBconn *dbc = NULL; @@ -292,12 +498,27 @@ void eDBdisconnect(eurephiaCTX *ctx) /** + * @copydoc eDBdisconnect_firewall() + */ +void eDBdisconnect_firewall(eurephiaCTX *ctx) { + DEBUG(ctx, 20, "Function call: eDBdisconnect_firewall(ctx)"); + DEBUG(ctx, 21, "Closing PostgreSQL file descriptor (%ld) for firewall thread", + PQsocket(ctx->dbc->dbhandle)); + /* Is there a better way how to avoid the firewall thread to close the inherited + * PostgreSQL connection? ... this is pretty brute force, but seems to work + */ + close(PQsocket(ctx->dbc->dbhandle)); + ctx->dbc->dbhandle = 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; + int certid = 0, prepid = -1; PGresult *dbr = NULL; char *blid = NULL; char depth_str[5]; @@ -311,19 +532,20 @@ int eDBauth_TLS(eurephiaCTX *ctx, const char *org, const char *cname, const char 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) ) { - ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_TLS_AUTH, "Failed to prepare SQL query"); + prepid = ePGprepStatement(ctx, 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::INTEGER" + " AND lower(cert.digest)=lower($5::VARCHAR)\0", + 5); + if( prepid < 0 ) { + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_TLS_AUTH, + "Failed to prepare SQL query"); return 0; } - PQclear(dbr); // Check if certificate is valid, and not too many attempts has been tried with // the given certificate @@ -334,7 +556,7 @@ int eDBauth_TLS(eurephiaCTX *ctx, const char *org, const char *cname, const char 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); + dbr = ePGprepExec(ctx, prepid, qry_args); free_nullsafe(ctx, qry_args); if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) { ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_TLS_AUTH, @@ -369,7 +591,7 @@ int eDBauth_TLS(eurephiaCTX *ctx, const char *org, const char *cname, const char */ int eDBauth_user(eurephiaCTX *ctx, const int certid, const char *username, const char *passwd) { - int uicid = 0, pwdok = 0; + int uicid = 0, pwdok = 0, prepid = -1; PGresult *dbr = NULL; char certid_str[10]; char *crpwd = NULL, *activated = NULL, *deactivated = NULL; @@ -384,35 +606,37 @@ int eDBauth_user(eurephiaCTX *ctx, const int certid, const char *username, const 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) ) { + prepid = ePGprepStatement(ctx, 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); + if( prepid < 0 ) { ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_USERPWD_AUTH, "Failed to prepare SQL query"); 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); + dbr = ePGprepExec(ctx, prepid, qry_args); free_nullsafe(ctx, qry_args); if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) { - ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, - "Failed to lookup user account information [username=%s, certid=%s]", - username, certid_str); + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_NONE, + "Failed to lookup user account information " + "[username=%s, certid=%s]", + username, certid_str); uicid = 0; goto exit; } @@ -470,30 +694,33 @@ int eDBauth_user(eurephiaCTX *ctx, const int certid, const char *username, const uicid = -1; } else { PGresult *upd = NULL; + int prepid = -1; uicid = atoi_nullsafe(ePGgetValue(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(upd) != PGRES_COMMAND_OK) ) { - ePGerrorMessage(ctx, upd, LOG_FATAL, 0, PREPSQL_USERS_LASTACC_UPD, - "Failed to prepare SQL query"); - } else if( dbr ) { + prepid = ePGprepStatement(ctx, PREPSQL_USERS_LASTACC_UPD, + "UPDATE users_last_access SET last_accessed = NULL" + " WHERE uid = $1::INTEGER", 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_USERS_LASTACC_UPD, + "Failed to prepare SQL query"); + } else { 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); + upd = ePGprepExec(ctx, prepid, qry_args); free_nullsafe(ctx, qry_args); - if( !upd || (PQresultStatus(upd) != PGRES_TUPLES_OK) ) { - ePGerrorMessage(ctx, upd, LOG_FATAL, 0, PREPSQL_USERS_LASTACC_UPD - "Failed to update last access status for uid %s", uid); - } - if( upd ) { - PQclear(upd); + if( !upd || (PQresultStatus(upd) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, upd, LOG_FATAL, 0, + PREPSQL_USERS_LASTACC_UPD, + "Failed to update last access status " + "for uid %s", uid); + } else { + if( upd ) { + PQclear(upd); + } } } } @@ -514,7 +741,7 @@ int eDBauth_user(eurephiaCTX *ctx, const int certid, const char *username, const */ int eDBget_uid(eurephiaCTX *ctx, const int certid, const char *username) { - int ret = 0; + int ret = 0, prepid = -1; PGresult *dbr = NULL; const char **qry_args = NULL; char certid_str[10]; @@ -526,34 +753,33 @@ int eDBget_uid(eurephiaCTX *ctx, const int certid, const char *username) 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) ) { + prepid = ePGprepStatement(ctx, PREPSQL_USERS_GETUID, + "SELECT uid " + " FROM usercerts " + " JOIN users USING (uid) " + " WHERE certid = $1::INTEGER AND username = $2::VARCHAR", + 2); + if( prepid < 0 ) { ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_USERS_GETUID, - "Failed to prepare SQL query"); + "Failed to prepare SQL query"); 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); + dbr = ePGprepExec(ctx, prepid, qry_args); free_nullsafe(ctx, qry_args); if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) { - ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_USERPWD_AUTH, - "Failed to lookup userid for user '%s'", username); + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_USERS_GETUID, + "Failed to lookup userid for user '%s'", username); ret = -1; goto exit; } - switch( PQntuples(dbr) > 1 ) { + switch(PQntuples(dbr)) { case 0: eurephia_log(ctx, LOG_WARNING,0, "Failed to find userid for certid %i and username '%s'", certid, username); @@ -584,135 +810,102 @@ int eDBget_uid(eurephiaCTX *ctx, const int certid, const char *username) */ int eDBblacklist_check(eurephiaCTX *ctx, const int type, const char *val) { - int blacklisted = 0; + int blacklisted = 0, prepid = -1; char sql[4098], *blid = NULL; const char **qry_args = NULL; PGresult *dbr = NULL; + const eDBattempt_types_t *atmptype = &eDBattempt_types[type]; DEBUG(ctx, 20, "Function call: eDBblacklist_check(ctx, '%s', '%s')", - eDBattempt_types[type].descr, val); + atmptype->descr, val); - qry_args = calloc(1, sizeof(char *)); - qry_args[0] = val; + qry_args = calloc(1, sizeof(char *)); + qry_args[0] = val; snprintf(sql, 4096, - "SELECT blid" - " FROM blacklist" - " WHERE %s = %s%s$1%s", - eDBattempt_types[type].colname_where, - defaultValue(eDBattempt_types[type].value_func, ""), - (eDBattempt_types[type].value_func ? "(" : ""), - (eDBattempt_types[type].value_func ? ")" : "")); - - dbr = PQprepare(ctx->dbc->dbhandle, PREPSQL_BLACKLIST_CHECK, sql, 1, NULL); - if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { - ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_BLACKLIST_CHECK, + "SELECT atpid, attempts >= %s, blid, attempts " + " FROM attempts " + " LEFT JOIN blacklist USING(%s)" + " WHERE %s = %s%s$1::VARCHAR%s", + defaultValue(eGet_value(ctx->dbc->config, atmptype->allow_cfg), + atmptype->default_value), + atmptype->colname, atmptype->colname_where, + defaultValue(atmptype->value_func, ""), + (atmptype->value_func ? "(" : ""), + (atmptype->value_func ? ")" : "")); + + prepid = ePGprepStatement(ctx, atmptype->sql_blacklist_check, sql, 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, atmptype->sql_blacklist_check, "Failed to prepare SQL query"); blacklisted = -1; - goto exit; + goto error; } - PQclear(dbr); - - dbr = PQexecPrepared(ctx->dbc->dbhandle, PREPSQL_BLACKLIST_CHECK, 2, qry_args, NULL, NULL, 0); + + dbr = ePGprepExec(ctx, prepid, qry_args); if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) { - ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_BLACKLIST_CHECK, - "Failed to lookup %s in the blacklist for '%s'", - eDBattempt_types[type].descr, val); + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, atmptype->sql_blacklist_check, + "Failed to lookup %s in the attempts/blacklist table for '%s'", + atmptype->descr, val); blacklisted = -1; - goto exit; + goto error; } if( dbr && PQntuples(dbr) > 0 ) { - blid = ePGgetValue(dbr, 0, 0); + char *atpid = NULL; + int atpexceed = -1, atpcount = 0; + + blid = ePGgetValue(dbr, 0, 2); if( blid != NULL ) { eurephia_log(ctx, LOG_WARNING, 0, "Attempt from blacklisted %s: %s", - eDBattempt_types[type].descr, val); + atmptype->descr, val); blacklisted = 1; // [type] is blacklisted - } - update_blacklist_attempt(ctx, blid); - PQclear(dbr); - } else { - ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_BLACKLIST_CHECK, - "Blacklist query for %s failed (%s)", - eDBattempt_types[type].descr, val); - }; - - // 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) ) { - ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_ATTEMPTS_CHECK, - "Failed to prepare SQL query"); - 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) ) { - ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_BLACKLIST_CHECK, - "Failed look up attempts counter for %s in the blacklist check on '%s'", - eDBattempt_types[type].descr, val); - blacklisted = -1; + update_blacklist_attempt(ctx, blid); goto exit; } - if( dbr && (PQntuples(dbr) > 0) ) { - atpid = ePGgetValue(dbr, 0, 0); - atpexceed = atoi_nullsafe(ePGgetValue(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) ) { - ePGerrorMessage(ctx, blr, LOG_FATAL, 0, PREPSQL_BLACKLIST_REGISTER, - "Failed to prepare SQL query"); - } else { - PQclear(blr); - blr = PQexecPrepared(ctx->dbc->dbhandle, - PREPSQL_BLACKLIST_REGISTER, 1, qry_args, - NULL, NULL, 0); - if( !blr || (PQresultStatus(blr) != PGRES_COMMAND_OK) ) { - ePGerrorMessage(ctx, blr, LOG_FATAL, 0, - PREPSQL_BLACKLIST_REGISTER, - "Failed to register %s value '%s' in the " - "blacklist:", - eDBattempt_types[type].descr, val); - } + // Check if this [type] have been tried before and consider if it should be blacklisted + atpid = ePGgetValue(dbr, 0, 0); + atpexceed = atoi_nullsafe(ePGgetValue(dbr, 0, 1)); + atpcount = atoi_nullsafe(ePGgetValue(dbr, 0, 3)); + + // 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 (%i) failed attempts: %s", + atmptype->descr, atpcount, val); + + snprintf(sql, 4096, "INSERT INTO blacklist (%s) VALUES ($1)", + atmptype->colname); + prepid = ePGprepStatement(ctx, atmptype->sql_blacklist_reg, sql, 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, atmptype->sql_blacklist_reg, + "Failed to prepare SQL query"); + } else { + blr = ePGprepExec(ctx, prepid, qry_args); + if( !blr + || (PQresultStatus(blr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, blr, LOG_FATAL, 0, + atmptype->sql_blacklist_reg, + "Failed to register %s value " + "'%s' in the blacklist:", + atmptype->descr, + val); } PQclear(blr); - blacklisted = 1; // [type] is blacklisted } - atpid = NULL; - PQclear(dbr); - } else { - ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_BLACKLIST_CHECK, - "Querying attempts counts for blacklisted %s failed (%s)", - eDBattempt_types[type].descr, val); + blacklisted = 1; // [type] is blacklisted } + atpid = NULL; + PQclear(dbr); } + exit: DEBUG(ctx, 20, "Result - function call: eDBblacklist_check(ctx, '%s', '%s') - %i", - eDBattempt_types[type].descr, val, blacklisted); + atmptype->descr, val, blacklisted); - exit: + error: blid = NULL; free_nullsafe(ctx, qry_args); @@ -725,26 +918,159 @@ int eDBblacklist_check(eurephiaCTX *ctx, const int type, const char *val) */ void eDBregister_attempt(eurephiaCTX *ctx, int type, int mode, const char *value) { + const eDBattempt_types_t *atmptype = &eDBattempt_types[type]; + const char **qry_args = NULL; + char sql[4098]; + char *id = NULL, *atmpt_block = NULL, *blid = NULL; + int prepid = -1, attempts = 0; + PGresult *dbr = NULL; + DEBUG(ctx, 20, "Function call: eDBregister_attempt(ctx, %s, %s, '%s')", - eDBattempt_types[type].colname, + atmptype->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 ? ")" : "") - ); - */ + qry_args = calloc(1, sizeof(char *)); + qry_args[0] = value; + + snprintf(sql, 4096, + "SELECT atpid, attempts > %s, blid, attempts " + " FROM attempts " + " LEFT JOIN blacklist USING(%s)" + " WHERE %s = %s%s$1::VARCHAR%s", + defaultValue(eGet_value(ctx->dbc->config, atmptype->allow_cfg), + atmptype->default_value), + atmptype->colname, atmptype->colname_where, + defaultValue(atmptype->value_func, ""), + (atmptype->value_func ? "(" : ""), + (atmptype->value_func ? ")" : "")); + prepid = ePGprepStatement(ctx, atmptype->sql_blacklist_check, sql, 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, atmptype->sql_blacklist_check, + "Failed to prepare SQL query"); + } + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, atmptype->sql_blacklist_check, + "Failed to lookup %s in the attempts/blacklist table for '%s'", + atmptype->descr, value); + return; + } + + attempts = atoi_nullsafe(ePGgetValue(dbr, 0, 3)); + // If we are asked to reset the attempt counter and we do not find any attempts, exit here + if( (mode == ATTEMPT_RESET) && ((PQntuples(dbr) == 0) || (attempts == 0))) { + PQclear(dbr); + return; + } + + id = strdup_nullsafe(ePGgetValue(dbr, 0, 0)); + atmpt_block = strdup_nullsafe(ePGgetValue(dbr, 0, 1)); + blid = strdup_nullsafe(ePGgetValue(dbr, 0, 2)); + PQclear(dbr); + + if( (id == NULL) && (mode == ATTEMPT_REGISTER) ) { + // Only insert record when we are in registering mode + snprintf(sql, 4096, "INSERT INTO attempts (%s, attempts) VALUES ($1::VARCHAR, 1)", + atmptype->colname); + prepid = ePGprepStatement(ctx, atmptype->sql_attempts_reg, sql, 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, atmptype->sql_attempts_reg, + "Failed to prepare SQL query"); + goto error; + } + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, atmptype->sql_attempts_reg, + "Failed to register failed attempt for %s '%s'", + atmptype->descr, value); + goto error; + } + PQclear(dbr); + } else if( id != NULL ){ + // if a attempt record exists, update it according to mode + qry_args[0] = id; + switch( mode ) { + case ATTEMPT_RESET: + prepid = ePGprepStatement(ctx, PREPSQL_ATTEMPTS_RESET, + "UPDATE attempts" + " SET attempts = 0 " + " WHERE atpid = $1::INTEGER", 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_ATTEMPTS_RESET, + "Failed to prepare SQL query"); + goto error; + } + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_ATTEMPTS_RESET, + "Failed to reset attempts counter for atpid '%s' (%s %s)", + id, atmptype->descr, value); + goto error; + } + PQclear(dbr); + break; + default: + prepid = ePGprepStatement(ctx, PREPSQL_ATTEMPTS_INCR, + "UPDATE attempts" + " SET last_attempt = CURRENT_TIMESTAMP, " + " attempts = attempts + 1" + " WHERE atpid = $1::INTEGER", 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_ATTEMPTS_INCR, + "Failed to prepare SQL query"); + goto error; + } + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_ATTEMPTS_INCR, + "Failed to increment attempts counter for atpid '%s' (%s %s)", + id, atmptype->descr, value); + goto error; + } + PQclear(dbr); + break; + } + } + + // If attempts have exceeded attempt limit, blacklist it immediately if not already registered + if( (mode == ATTEMPT_REGISTER) + && (blid == NULL) && (atmpt_block != NULL) && (atmpt_block[0] == 't') ) { + eurephia_log(ctx, LOG_WARNING, 0, "Blacklisting %s due to too many attempts: %s", + eDBattempt_types[type].descr, value); + + snprintf(sql, 4096, "INSERT INTO blacklist (%s) VALUES ($1)", + atmptype->colname); + prepid = ePGprepStatement(ctx, atmptype->sql_blacklist_reg, sql, 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, atmptype->sql_blacklist_reg, + "Failed to prepare SQL query"); + } else { + qry_args[0] = value; + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr + || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, + atmptype->sql_blacklist_reg, + "Failed to blacklist %s value " + "'%s':", + atmptype->descr, + value); + goto error; + } + PQclear(dbr); + } + } + + error: + free_nullsafe(ctx, id); + free_nullsafe(ctx, atmpt_block); + free_nullsafe(ctx, blid); + } /** @@ -754,18 +1080,51 @@ int eDBregister_login(eurephiaCTX *ctx, eurephiaSESSION *skey, const int certid, const char *proto, const char *remipaddr, const char *remport, const char *vpnipaddr, const char *vpnipmask) { + char uidstr[10], certidstr[10]; + const char **qry_args = NULL; + int prepid = -1, ret = 0; + PGresult *dbr = NULL; + 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; + prepid = ePGprepStatement(ctx, PREPSQL_REGISTER_LOGIN, + "INSERT INTO lastlog (uid, certid, " + " protocol, remotehost, remoteport," + " vpnipaddr, vpnipmask," + " sessionstatus, sessionkey, login) " + "VALUES ($1::INTEGER, $2::INTEGER, " + " $3::VARCHAR, $4::VARCHAR, $5::INTEGER," + " $6::VARCHAR, $7::VARCHAR," + " 1, $8::VARCHAR, CURRENT_TIMESTAMP)", 8); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_REGISTER_LOGIN, + "Failed to prepare query"); + return 0; + } + + qry_args = calloc(8, sizeof(char *)); + snprintf(uidstr, 8, "%i", uid); qry_args[0] = uidstr; + snprintf(certidstr, 8, "%i", certid); qry_args[1] = certidstr; + qry_args[2] = proto; + qry_args[3] = remipaddr; + qry_args[4] = remport; + qry_args[5] = vpnipaddr; + qry_args[6] = vpnipmask; + qry_args[7] = skey->sessionkey; + + dbr = ePGprepExec(ctx, prepid, qry_args); + free_nullsafe(ctx, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_CRITICAL, 0, PREPSQL_REGISTER_LOGIN, + "Failed to register session login for session key '%s'", + skey->sessionkey); + ret = 0; + } else { + ret = 1; + PQclear(dbr); + } + return ret; } @@ -774,17 +1133,63 @@ int eDBregister_login(eurephiaCTX *ctx, eurephiaSESSION *skey, const int certid, */ int eDBregister_vpnmacaddr(eurephiaCTX *ctx, eurephiaSESSION *session, const char *macaddr) { + const char **qry_args = NULL; + int prepid_reg = -1, prepid_ll = -1, ret = 0; + PGresult *dbr = NULL; + 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); + /* TODO: Use transaction */ + + prepid_reg = ePGprepStatement(ctx, PREPSQL_MACHISTORY_REGISTER, + "INSERT INTO macaddr_history (sessionkey, macaddr)" + " VALUES ($1::VARCHAR, $2::VARCHAR)", 2); + if( prepid_reg < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_MACHISTORY_REGISTER, + "Failed to prepare SQL query"); + return 0; + } + + prepid_ll = ePGprepStatement(ctx, PREPSQL_MACHISTORY_LASTLOG, + "UPDATE lastlog_update " + " SET sessionstatus = 2,macaddr = $2::VARCHAR" + " WHERE sessionkey = $1::VARCHAR AND sessionstatus = 1", 2); + if( prepid_ll < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_MACHISTORY_LASTLOG, + "Failed to prepare SQL query"); + return 0; + } - "UPDATE lastlog SET sessionstatus = 2, macaddr = '%q' " - " WHERE sessionkey = '%q' AND sessionstatus = 1", macaddr, session->sessionkey); + qry_args = calloc(2, sizeof(const char *)); + qry_args[0] = session->sessionkey; + qry_args[1] = macaddr; - */ + // Register the MAC address into the macaddr_history table + dbr = ePGprepExec(ctx, prepid_reg, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_CRITICAL, 0, + PREPSQL_MACHISTORY_REGISTER, + "eDBregister_vpnmacaddr: Failed to register VPN client " + "MAC address (%s/%s)", + session->sessionkey, macaddr); + ret = 0; + goto exit; + } + PQclear(dbr); + + // Update lastlog table with the latest used MAC address + dbr = ePGprepExec(ctx, prepid_ll, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_CRITICAL, 0, + PREPSQL_MACHISTORY_LASTLOG, + "eDBregister_vpnmacaddr: Failed to update " + "lastlog with MAC address info (%s/%s)", + session->sessionkey, macaddr); + ret = 0; + goto exit; + } + PQclear(dbr); // Save the MAC address in the session values register - needed for the destroy session if( eDBset_session_value(ctx, session, "macaddr", macaddr) == 0 ) { @@ -792,6 +1197,8 @@ int eDBregister_vpnmacaddr(eurephiaCTX *ctx, eurephiaSESSION *session, const cha return 0; } + exit: + free_nullsafe(ctx, qry_args); return 1; } @@ -802,18 +1209,40 @@ int eDBregister_vpnmacaddr(eurephiaCTX *ctx, eurephiaSESSION *session, const cha int eDBregister_logout(eurephiaCTX *ctx, eurephiaSESSION *skey, const char *bytes_sent, const char *bytes_received, const char *duration) { + const char **qry_args = NULL; + int prepid = -1; + PGresult *dbr = NULL; + 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); - */ + prepid = ePGprepStatement(ctx, PREPSQL_REGISTER_LOGOUT, + "UPDATE lastlog_update " + " SET sessionstatus = 3, logout = CURRENT_TIMESTAMP, " + " bytes_sent=$2::INTEGER, bytes_received=$3::INTEGER," + " session_duration = $4::INTERVAL " + " WHERE sessionkey = $1::VARCHAR AND sessionstatus = 2", 4); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_REGISTER_LOGOUT, + "Failed to prepare SQL query"); + } + + qry_args = calloc(4, sizeof(char *)); + qry_args[0] = skey->sessionkey; + qry_args[1] = bytes_sent; + qry_args[2] = bytes_received; + qry_args[3] = duration; + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_CRITICAL, 0, PREPSQL_REGISTER_LOGOUT, + "Failed to lastlog with logout info (%s)", + skey->sessionkey); + free_nullsafe(ctx, qry_args); + return 0; + } + PQclear(dbr); + free_nullsafe(ctx, qry_args); skey->sessionstatus = SESSION_LOGGEDOUT; return 1; } @@ -824,7 +1253,11 @@ int eDBregister_logout(eurephiaCTX *ctx, eurephiaSESSION *skey, */ char *eDBget_sessionkey_seed(eurephiaCTX *ctx, sessionType type, const char *sessionseed) { + const char **qry_args = NULL; char *skey = NULL; + _ePG_prepID preptype = PREPSQL_NONE; + int prepid = -1; + PGresult *dbr = NULL; DEBUG(ctx, 20, "eDBget_sessionkey_seed(ctx, %i, '%s')", type, sessionseed); @@ -834,35 +1267,57 @@ char *eDBget_sessionkey_seed(eurephiaCTX *ctx, sessionType type, const char *ses return NULL; } + qry_args = calloc(1, sizeof(char *)); + qry_args[0] = sessionseed; + switch( type ) { case stSESSION: - /* - "SELECT sessionkey " - " FROM sessionkeys " - " JOIN lastlog USING (sessionkey)" - " WHERE sessionstatus IN (1,2)" - " AND sessionseed = '%q'", - sessionseed); - */ + preptype = PREPSQL_SESSIONKEY_GETSEED_SESSION; + prepid = ePGprepStatement(ctx, preptype, + "SELECT sessionkey " + " FROM sessionkeys " + " JOIN lastlog USING (sessionkey)" + " WHERE sessionstatus IN (1,2)" + " AND sessionseed = $1::VARCHAR", 1); break; case stAUTHENTICATION: - /* - "SELECT sessionkey" - " FROM sessionkeys" - " LEFT JOIN lastlog USING(sessionkey)" - " WHERE sessionstatus IS NULL" - " AND sessionseed = '%q'", - sessionseed); - */ + preptype = PREPSQL_SESSIONKEY_GETSEED_AUTH; + prepid = ePGprepStatement(ctx, preptype, + "SELECT sessionkey " + " FROM sessionkeys " + " LEFT JOIN lastlog USING (sessionkey)" + " WHERE sessionstatus IS NULL" + " AND sessionseed = $1::VARCHAR", 1); break; default: eurephia_log(ctx, LOG_ERROR, 0, "Invalid session type: %i", type); - return NULL; + goto exit; + } + + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, preptype, + "Failed to prepare SQL query"); + skey = NULL; + goto exit; + } + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, preptype, + "Failed to lookup session key from session seed '%s'", + sessionseed); + skey = NULL; + goto exit; } + skey = (PQntuples(dbr) == 1 ? strdup_nullsafe(PQgetvalue(dbr, 0, 0)) : NULL); + PQclear(dbr); + exit: + free_nullsafe(ctx, qry_args); return skey; + } @@ -872,19 +1327,43 @@ char *eDBget_sessionkey_seed(eurephiaCTX *ctx, sessionType type, const char *ses char *eDBget_sessionkey_macaddr(eurephiaCTX *ctx, const char *macaddr) { char *skey = NULL; + const char **qry_args = NULL; + int prepid = -1; + PGresult *dbr = 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); - */ + prepid = ePGprepStatement(ctx, PREPSQL_SESSIONKEY_GETMAC, + "SELECT sessionkey " + " FROM sessions " + " JOIN lastlog USING (sessionkey)" + " WHERE sessionstatus = 3 " + " AND datakey = 'macaddr'" + " AND dataval = $1::VARCHAR", 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_SESSIONKEY_GETMAC, + "Failed to prepare SQL query"); + return NULL; + } + qry_args = calloc(1, sizeof(char *)); + qry_args[0] = macaddr; + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_SESSIONKEY_GETMAC, + "Failed to lookup session key from MAC address '%s'", + macaddr); + skey = NULL; + goto exit; + } + skey = (PQntuples(dbr) == 1 ? strdup_nullsafe(PQgetvalue(dbr, 0, 0)) : NULL); + PQclear(dbr); + + exit: + free_nullsafe(ctx, qry_args); return skey; } @@ -895,8 +1374,13 @@ char *eDBget_sessionkey_macaddr(eurephiaCTX *ctx, const char *macaddr) int eDBcheck_sessionkey_uniqueness(eurephiaCTX *ctx, const char *seskey) { int uniq = 0; + const char **qry_args = NULL; + int prepid = -1; + _ePG_prepID preptype; + PGresult *dbr = NULL; 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"); @@ -910,22 +1394,46 @@ int eDBcheck_sessionkey_uniqueness(eurephiaCTX *ctx, const char *seskey) case ECTX_ADMIN_CONSOLE: case ECTX_ADMIN_WEB: - /* - "SELECT count(sessionkey) = 0 " - "FROM eurephia_adminlog WHERE sessionkey = '%q'", seskey); - */ + preptype = PREPSQL_SESSIONKEY_UNIQ_ADMIN; + prepid = ePGprepStatement(ctx, preptype, + "SELECT count(sessionkey) = 0 " + "FROM eurephia_adminlog WHERE sessionkey = $1::VARCHAR", 1); break; case ECTX_PLUGIN_AUTH: default: - /* - "SELECT count(sessionkey) = 0 " - "FROM lastlog WHERE sessionkey = '%q'", seskey); - */ + preptype = PREPSQL_SESSIONKEY_UNIQ_PLAUTH; + prepid = ePGprepStatement(ctx, preptype, + "SELECT count(sessionkey) = 0 " + "FROM lastlog WHERE sessionkey = $1::VARCHAR", 1); break; } - return uniq; + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, preptype, + "Failed to prepare SQL query"); + return 0; + } + + qry_args = calloc(1, sizeof(char *)); + qry_args[0] = seskey; + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, preptype, + "Failed to check session key uniqueness for '%s'", + seskey); + uniq = 0; + goto exit; + } else if( PQntuples(dbr) == 1 ) { + char *res = PQgetvalue(dbr, 0, 0); + uniq = (*res == 't'); + } + PQclear(dbr); + + exit: + free_nullsafe(ctx, qry_args); + return uniq; } @@ -933,7 +1441,9 @@ int eDBcheck_sessionkey_uniqueness(eurephiaCTX *ctx, const char *seskey) * @copydoc eDBregister_sessionkey() */ int eDBregister_sessionkey(eurephiaCTX *ctx, const char *seed, const char *seskey) { - // dbresult *res; + const char **qry_args = NULL; + int prepid = -1, ret = 0; + PGresult *dbr = NULL; DEBUG(ctx, 20, "eDBregister_sessionkey(ctx, '%s', '%s')", seed, seskey); if( (seed == NULL) || (seskey == NULL) ) { @@ -942,16 +1452,32 @@ int eDBregister_sessionkey(eurephiaCTX *ctx, const char *seed, const char *seske 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'"); + prepid = ePGprepStatement(ctx, PREPSQL_SESSIONKEY_REGISTER, + "INSERT INTO sessionkeys (sessionseed, sessionkey) " + " VALUES($1::VARCHAR, $2::VARCHAR)", 2); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_SESSIONKEY_REGISTER, + "Failed to prepare SQL query"); return 0; } - */ - return 1; + + qry_args = calloc(2, sizeof(char *)); + qry_args[0] = seed; + qry_args[1] = seskey; + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_SESSIONKEY_REGISTER, + "eDBregister_sessionkey: Error registering sessionkey" + " into 'sessionkeys'"); + ret = 0; + goto exit; + } + PQclear(dbr); + ret = 1; + exit: + free_nullsafe(ctx, qry_args); + return ret; } /** @@ -964,7 +1490,9 @@ int eDBregister_sessionkey(eurephiaCTX *ctx, const char *seed, const char *seske * */ int eDBremove_sessionkey(eurephiaCTX *ctx, const char *seskey) { - // dbresult *res; + const char **qry_args = NULL; + int prepid = -1, ret = 0; + PGresult *dbr = NULL; DEBUG(ctx, 20, "eDBremove_sessionkey(ctx, '%s')", seskey); if( seskey == NULL ) { @@ -973,35 +1501,84 @@ int eDBremove_sessionkey(eurephiaCTX *ctx, const char *seskey) { 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"); + prepid = ePGprepStatement(ctx, PREPSQL_SESSIONKEY_REMOVE, + "DELETE FROM sessionkeys WHERE sessionkey = $1::VARCHAR", 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_SESSIONKEY_REMOVE, + "Failed to prepare SQL query"); return 0; } - */ - return 1; + + qry_args = calloc(1, sizeof(char *)); + qry_args[0] = seskey; + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_SESSIONKEY_REMOVE, + "eDBremove_sessionkey: Error removing sessionkey '%s'", + seskey); + ret = 0; + goto exit; + } + PQclear(dbr); + ret = 1; + exit: + free_nullsafe(ctx, qry_args); + return ret; } /** * @copydoc eDBload_sessiondata() */ -eurephiaVALUES *eDBload_sessiondata(eurephiaCTX *ctx, const char *sesskey) +eurephiaVALUES *eDBload_sessiondata(eurephiaCTX *ctx, const char *seskey) { eurephiaVALUES *sessvals = NULL; + const char **qry_args = NULL; + int prepid = -1, i = 0; + PGresult *dbr = NULL; + DEBUG(ctx, 20, "Function call: eDBload_sessiondata(ctx, '%s')", seskey); - DEBUG(ctx, 20, "Function call: eDBload_sessiondata(ctx, '%s')", sesskey); + prepid = ePGprepStatement(ctx, PREPSQL_SESSIONVARS_LOAD, + "SELECT datakey, dataval" + " FROM sessions" + " WHERE sessionkey = $1::VARCHAR", 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_SESSIONVARS_LOAD, + "Failed to prepare SQL query"); + return NULL; + } + + qry_args = calloc(1, sizeof(char *)); + qry_args[0] = seskey; + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_SESSIONVARS_LOAD, + "eDBload_sessiondata: Failed to load session variables for session '%s'", + seskey); + sessvals = NULL; + goto exit; + } sessvals = eCreate_value_space(ctx, 10); + if( !sessvals ) { + eurephia_log(ctx, LOG_CRITICAL, 0, + "Failed to create value storage for session variables for session '%s'", + seskey); + goto exit; + } - /* - "SELECT datakey, dataval FROM sessions WHERE sessionkey = '%q'", - sesskey - */ + for( i = 0; i < PQntuples(dbr); i++ ) { + eAdd_value(ctx, sessvals, + ePGgetValue(dbr, i, 0), + ePGgetValue(dbr, i, 1)); + } + PQclear(dbr); + exit: + free_nullsafe(ctx, qry_args); return sessvals; } @@ -1012,6 +1589,11 @@ eurephiaVALUES *eDBload_sessiondata(eurephiaCTX *ctx, const char *sesskey) int eDBstore_session_value(eurephiaCTX *ctx, eurephiaSESSION *session, int mode, const char *key, const char *val) { + const char **qry_args = NULL; + int prepid = -1, ret = 0; + _ePG_prepID preptype = PREPSQL_NONE; + PGresult *dbr = NULL; + if( session == NULL ) { DEBUG(ctx, 20, "Function call failed to eDBstore_session_value(ctx, ...): Non-existing session key"); @@ -1021,34 +1603,62 @@ int eDBstore_session_value(eurephiaCTX *ctx, eurephiaSESSION *session, int mode, DEBUG(ctx, 20, "Function call: eDBstore_session_value(ctx, '%s', %i, '%s', '%s')", session->sessionkey, mode, key, val); + /* TODO: Need testing */ + switch( mode ) { case SESSVAL_NEW: - /* - "INSERT INTO sessions (sessionkey, datakey, dataval) " - "VALUES ('%q','%q','%q')", session->sessionkey, key, val); - */ + preptype = PREPSQL_SESSIONVARS_STORE_NEW; + prepid = ePGprepStatement(ctx, preptype, + "INSERT INTO sessions (sessionkey, datakey, dataval) " + "VALUES ($1::VARCHAR,$2::VARCHAR,$3::VARCHAR)", 3); break; case SESSVAL_UPDATE: - /* - "UPDATE sessions SET dataval = '%q' " - " WHERE sessionkey = '%q' AND datakey = '%q'", - val, session->sessionkey, key); - */ + preptype = PREPSQL_SESSIONVARS_STORE_UPDATE; + prepid = ePGprepStatement(ctx, preptype, + "UPDATE sessions SET dataval = $3::VARCHAR " + " WHERE sessionkey = $1::VARCHAR" + " AND datakey = $2::VARCHAR", 2); + break; case SESSVAL_DELETE: - /* - "DELETE FROM sessions " - " WHERE sessionkey = '%q' AND datakey = '%q'", - session->sessionkey, key); - */ + preptype = PREPSQL_SESSIONVARS_STORE_DELETE; + prepid = ePGprepStatement(ctx, preptype, + "DELETE FROM sessions " + " WHERE sessionkey = $1::VARCHAR" + " AND datakey = $2::VARCHAR", 2); break; default: eurephia_log(ctx, LOG_FATAL, 0, "Unknown eDBstore_session_value mode '%i'", mode); return 0; } - return 1; + + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, preptype, + "Failed to prepare SQL query"); + return 0; + } + + qry_args = calloc(3, sizeof(char *)); + qry_args[0] = session->sessionkey; + qry_args[1] = key; + qry_args[2] = val; + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, preptype, + "eDBstore_session_value: Failed to update session value [%s] %s", + session->sessionkey, key); + ret = 0; + goto exit; + } + PQclear(dbr); + ret = 1; + + exit: + free_nullsafe(ctx, qry_args); + return ret; } @@ -1057,6 +1667,10 @@ int eDBstore_session_value(eurephiaCTX *ctx, eurephiaSESSION *session, int mode, */ int eDBdestroy_session(eurephiaCTX *ctx, eurephiaSESSION *session) { + const char **qry_args = NULL; + int prepid = -1, ret = 0; + PGresult *dbr = NULL; + DEBUG(ctx, 20, "Function call: eDBdestroy_session(ctx, '%s')", session->sessionkey); if( (session == NULL) || (session->sessionkey == NULL) ) { @@ -1064,25 +1678,73 @@ int eDBdestroy_session(eurephiaCTX *ctx, eurephiaSESSION *session) return 1; } + qry_args = calloc(1, sizeof(char *)); + qry_args[0] = session->sessionkey; + // 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); - */ - } + prepid = ePGprepStatement(ctx, PREPSQL_SESSIONS_DESTROY_LASTLOG, + "UPDATE lastlog_update " + " SET sessionstatus = 4," + " session_deleted = CURRENT_TIMESTAMP " + " WHERE sessionkey = $1::VARCHAR" + " AND sessionstatus = 3", 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, dbr, LOG_FATAL, 0, PREPSQL_SESSIONS_DESTROY_LASTLOG, + "Failed to prepare SQL query"); + ret = 0; + goto exit; + } + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_CRITICAL, 0, + PREPSQL_SESSIONS_DESTROY_LASTLOG, + "eDBdestroy_session: Failed to update " + "update lastlog with session deleted status (%s)", + session->sessionkey); + ret = 0; + goto exit; + } + PQclear(dbr); + } // Delete session variables - /* - "DELETE FROM sessions WHERE sessionkey = '%q'", session->sessionkey); - */ - - // Delete the session key - /* - "DELETE FROM sessionkeys WHERE sessionkey = '%q'", seskey); - */ - return 0; + prepid = ePGprepStatement(ctx, PREPSQL_SESSIONS_DESTROY_SESS, + "DELETE FROM sessions WHERE sessionkey = $1::VARCHAR", 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, + PREPSQL_SESSIONS_DESTROY_SESS, + "Failed to prepare SQL query"); + ret = 0; + goto exit; + } + + dbr = ePGprepExec(ctx, prepid, qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_COMMAND_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_CRITICAL, 0, + PREPSQL_SESSIONS_DESTROY_SESS, + "eDBdestroy_session: Failed to delete " + "session variables (%s)", + session->sessionkey); + ret = 0; + goto exit; + } + PQclear(dbr); + + // Delete the session seed/session key relation + if( eDBremove_sessionkey(ctx, session->sessionkey) == 0) { + eurephia_log(ctx, LOG_CRITICAL, 0, + "Failed to delete sessionkey/sessionseed relation (%s)", + session->sessionkey); + ret = 0; + } else { + ret = 1; + } + + exit: + free_nullsafe(ctx, qry_args); + return ret; } @@ -1091,19 +1753,41 @@ int eDBdestroy_session(eurephiaCTX *ctx, eurephiaSESSION *session) */ char *eDBget_firewall_profile(eurephiaCTX *ctx, eurephiaSESSION *session) { + const char **qry_args = NULL; + int prepid = -1; char *ret = NULL; - + PGresult *dbr = 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); - */ + /* TODO: Need testing */ + + prepid = ePGprepStatement(ctx, PREPSQL_FIREWALL_GETPROFILE, + "SELECT fw_profile " + " FROM lastlog " + " JOIN usercerts USING(certid, uid)" + " JOIN accesses USING(accessprofile)" + " WHERE sessionkey = $1::VARCHAR", 1); + if( prepid < 0 ) { + ePGerrorMessage(ctx, NULL, LOG_FATAL, 0, PREPSQL_FIREWALL_GETPROFILE, + "Failed to prepare SQL query"); + return NULL; + } + + qry_args = calloc(1, sizeof(char *)); + qry_args[0] = session->sessionkey; + + dbr = ePGprepExec(ctx, prepid, qry_args); + free_nullsafe(ctx,qry_args); + if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) || (PQntuples(dbr) > 1) ) { + ePGerrorMessage(ctx, dbr, LOG_WARNING, 0, PREPSQL_FIREWALL_GETPROFILE, + "Failed to retrieve the firewall profile for session '%s'", + session->sessionkey); + return NULL; + } + ret = (PQntuples(dbr) == 1 ? strdup_nullsafe(ePGgetValue(dbr, 0, 0)) : NULL); + PQclear(dbr); return ret; } @@ -1114,17 +1798,33 @@ char *eDBget_firewall_profile(eurephiaCTX *ctx, eurephiaSESSION *session) */ eurephiaVALUES *eDBget_blacklisted_ip(eurephiaCTX *ctx) { + int i = 0; + PGresult *dbr = NULL; eurephiaVALUES *ret = NULL; DEBUG(ctx, 20, "Function call: eDBget_blacklisted_ip(ctx)"); - /* - "SELECT remoteip FROM blacklist WHERE remoteip IS NOT NULL"); - */ + if( !ctx || !ctx->dbc || !ctx->dbc->dbhandle ) { + eurephia_log(ctx, LOG_FATAL, 0, "System error in eDBget_blacklisted_ip()"); + return NULL; + } + + dbr = PQexec(ctx->dbc->dbhandle, "SELECT remoteip FROM blacklist WHERE remoteip IS NOT NULL"); + if( !dbr || (PQresultStatus(dbr) != PGRES_TUPLES_OK) ) { + ePGerrorMessage(ctx, dbr, LOG_CRITICAL, 0, PREPSQL_NONE, + "eDBget_blaclisted_ip: Failed to query IP blacklist"); + return NULL; + } + // Copy blacklisted IP addresses into a eurephiaVALUES chain without key names ret = eCreate_value_space(ctx, 21); - // copy SQL result into eurephiaVALUES chain + for( i = 0; i < PQntuples(dbr); i++ ) { + char *ip = ePGgetValue(dbr, i, 0); + if( (ip != NULL) && (*ip != '\0') ) { + eAdd_value(ctx, ret, NULL, ip); + } + } + PQclear(dbr); return ret; - } |
