summaryrefslogtreecommitdiffstats
path: root/database/sqlite
diff options
context:
space:
mode:
authorDavid Sommerseth <dazo@users.sourceforge.net>2008-08-06 14:45:14 +0200
committerDavid Sommerseth <dazo@users.sourceforge.net>2008-08-06 14:45:14 +0200
commite51f1c49f9c1745012514dac79aaf8250ca1c036 (patch)
tree46017fb7c25dc9a60926173c543d7a7592208aca /database/sqlite
Imported eurephia into git
Diffstat (limited to 'database/sqlite')
-rw-r--r--database/sqlite/Makefile43
-rw-r--r--database/sqlite/eurephiadb-sqlite.c842
-rw-r--r--database/sqlite/sql-schema.sql105
-rw-r--r--database/sqlite/sqlite.c325
-rw-r--r--database/sqlite/sqlite.h58
5 files changed, 1373 insertions, 0 deletions
diff --git a/database/sqlite/Makefile b/database/sqlite/Makefile
new file mode 100644
index 0000000..5844ed9
--- /dev/null
+++ b/database/sqlite/Makefile
@@ -0,0 +1,43 @@
+topdir = ../..
+
+DRIVERVERSION=1.0
+DRIVERAPIVERSION=1
+
+objs = eurephiadb-sqlite.o ../../eurephia_log.o ../../eurephiadb_session.o ../../eurephia_values.o ../../passwd.o ../../sha1.o sqlite.o
+
+driver=eurephiadb-sqlite.so
+
+include ${topdir}/Makefile.global
+
+LDFLAGS += -lsqlite3
+CFLAGS += -DDRIVERVERSION="\"${DRIVERVERSION}\"" -DDRIVERAPIVERSION=${DRIVERAPIVERSION}
+
+ifeq (${DRIVERMW},enabled)
+ objs += ${topdir}/memwatch.o
+ CFLAGS += -DMEMWATCH
+endif
+
+
+all : ${driver} ${DATABASE_NAME}
+
+sqlite :
+ ${CC} -o $@ sqlite.c ../../eurephia_log.o -DSQLITE_DEBUG=1 -DMEMWATCH ../../memwatch.c -lsqlite3 -g -Wall -I. -I../..
+
+${driver} : ${objs}
+ ${CC} -fPIC -g -shared ${LDFLAGS} -o $@ $^
+
+${DATABASE_NAME} :
+ rm -f eurephiadb
+ cat sql-schema.sql | sqlite3 $@
+
+
+install : all
+ mkdir -p -m 755 ${DRIVER_DIR}
+ install -m 755 ${driver} ${DRIVER_DIR}/
+ if [ ! -f ${DATABASE_DIR}/${DATABASE_NAME} ]; then \
+ install -m 644 ${DATABASE_NAME} ${DATABASE_DIR}/; \
+ fi
+
+clean :
+ rm -f *.so *.o *~ memwatch.log ${DATABASE_NAME}
+
diff --git a/database/sqlite/eurephiadb-sqlite.c b/database/sqlite/eurephiadb-sqlite.c
new file mode 100644
index 0000000..53ad8e1
--- /dev/null
+++ b/database/sqlite/eurephiadb-sqlite.c
@@ -0,0 +1,842 @@
+/* eurephia-sqlite.c -- Main driver for eurephia authentication plugin for OpenVPN
+ * This is the SQLite database driver
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#include <sqlite3.h>
+
+#define EUREPHIADB_DRIVER 1
+#include <eurephiadb_driver.h>
+#include <eurephia_nullsafe.h>
+#include <eurephia_log.h>
+#include <eurephia_values.h>
+#include <eurephiadb_session.h>
+#include <passwd.h>
+#include "sqlite.h"
+
+#ifdef MEMWATCH
+#include <memwatch.h>
+#endif
+
+
+// Mapping table - mapping attempt types from .... to sqlite table fields
+typedef struct {
+ char *colname;
+ char *allow_cfg;
+ char *descr;
+} eDBattempt_types_t;
+
+
+static const eDBattempt_types_t eDBattempt_types[] = {
+ {NULL, NULL, NULL},
+ {"remoteip\0", "allow_ipaddr_attempts\0", "IP Address\0"},
+ {"digest\0", "allow_cert_attempts\0", "Certificate\0"},
+ {"username\0", "allow_username_attempts\0", "Username\0"},
+ {NULL, NULL, NULL}
+};
+
+/*
+ * Driver info
+ */
+
+const char *eDB_DriverVersion() {
+ return "eurephiadb-sqlite (v"DRIVERVERSION") David Sommerseth 2008 (C) GPLv2";
+}
+
+
+int eDB_DriverAPIVersion() {
+ return DRIVERAPIVERSION;
+}
+
+
+/*
+ * local functions
+ */
+
+
+// Function for simplifying update of openvpn_blacklist
+void update_attempts(eurephiaCTX *ctx, const char *blid) {
+ dbresult *res = NULL;
+
+ if( blid != NULL ) {
+ res = sqlite_query(ctx,
+ "UPDATE openvpn_blacklist "
+ " SET last_accessed = CURRENT_TIMESTAMP WHERE blid = %s", blid);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not update openvpn_blacklist.last_accessed for blid=%s", blid);
+ }
+ sqlite_free_results(res);
+ }
+}
+
+/*
+ * Public driver functions
+ */
+
+// Connect to the database ... connection is stored in the eurephiaCTX context
+int eDBconnect(eurephiaCTX *ctx, const int argc, const char **argv)
+{
+ eDBconn *dbc = NULL;
+ dbresult *res = NULL;
+ int rc;
+
+#ifdef MEMWATCH
+ mwStatistics(3);
+#endif
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Function call: eDBconnect(ctx, %i, '%s')", argc, argv[1]);
+
+ if( (argc != 1) || (argv[0] == NULL) || (strlen(argv[0]) < 1) ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Wrong parameters to dblink-sqlite. Cannot open database.");
+ return 0;
+ }
+
+ // Connect to the database
+ dbc = (eDBconn *) malloc(sizeof(eDBconn)+2);
+ memset(dbc, 1, sizeof(eDBconn)+2);
+ dbc->dbname = strdup(argv[1]);
+
+ eurephia_log(ctx, LOG_INFO, 1, "Opening database '%s'", dbc->dbname);
+
+ rc = sqlite3_open(argv[1], (void *) &dbc->dbhandle);
+ if( rc ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not open database '%s'", dbc->dbname);
+ free_nullsafe(dbc->dbname);
+ free_nullsafe(dbc);
+ return 0;
+ }
+
+ dbc->config = NULL;
+ ctx->dbc = dbc;
+
+ // Load configuration parameters into memory
+ eurephia_log(ctx, LOG_INFO, 1, "Reading config from database (openvpn_config)");
+ res = sqlite_query(ctx, "SELECT datakey, dataval FROM openvpn_config");
+ if( res != NULL ) {
+ 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");
+ sqlite_free_results(res);
+ return 0;
+ }
+ for( i = 0; i < sqlite_get_numtuples(res); i++ ) {
+ eAdd_value(ctx, cfg, sqlite_get_value(res, i, 0), sqlite_get_value(res, i, 1));
+ }
+ sqlite_free_results(res);
+ ctx->dbc->config = cfg;
+ }
+ return 1;
+}
+
+// Disconnect from the database
+void eDBdisconnect(eurephiaCTX *ctx)
+{
+ eDBconn *dbc = NULL;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "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, 2, "Closing database '%s'", dbc->dbname);
+
+ // Close database connection
+ sqlite3_close((sqlite3 *) dbc->dbhandle);
+ free_nullsafe(dbc->dbname);
+ dbc->dbhandle = NULL;
+
+ // Free up config memory
+ eFree_values(ctx, dbc->config);
+ free_nullsafe(dbc);
+ ctx->dbc = NULL;
+}
+
+
+// Authenticate certificate ... returns certid (certificate ID) on success,
+// 0 if not found or -1 if certificate is blacklisted
+int eDBauth_TLS(eurephiaCTX *ctx, const char *org, const char *cname, const char *email,
+ const char *digest, const char *depth)
+{
+ dbresult *res = NULL;
+ int certid = 0;
+ char *blid = NULL;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Function call: eDBauth_TLS(ctx, '%s', '%s', '%s', '%s', %s)",
+ org, cname, email, digest, depth);
+
+ // Check if certificate is valid, and not too many attempts has been tried with the given certificate
+ res = sqlite_query(ctx,
+ "SELECT cert.certid, blid "
+ " FROM openvpn_certificates cert"
+ " LEFT JOIN openvpn_blacklist bl USING(digest)"
+ " WHERE organisation='%s' AND common_name='%s' "
+ " AND email='%s' AND depth='%s' AND cert.digest='%s'%c",
+ org, cname, email, depth, digest, 0);
+
+ if( res != NULL ) {
+ certid = atoi_nullsafe(sqlite_get_value(res, 0, 0));
+ blid = strdup_nullsafe(sqlite_get_value(res, 0, 1));
+ sqlite_free_results(res);
+
+ // Check if we found certificate to be blacklisted or not. blid == NULL when NOT blacklisted
+ if( blid == NULL ) {
+ if( certid > 0 ) {
+ eurephia_log(ctx, LOG_INFO, 0,
+ "Found certid %i for user: %s/%s/%s",
+ certid, org, cname, email);
+ } else {
+ eurephia_log(ctx, LOG_INFO, 1,
+ "Unknown certificate for: %s/%s/%s (depth %s, digest: %s)",
+ org, cname, email, depth, digest);
+ }
+ // Certificate is okay, certid contains the certificate ID
+ } else {
+ // If the certificate or IP is blacklisted, update status and deny access.
+ eurephia_log(ctx, LOG_WARNING, 1,
+ "Attempt with BLACKLISTED certificate (certid %i)", certid);
+ update_attempts(ctx, blid);
+ certid = -1;
+ }
+ free_nullsafe(blid);
+ } else {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not look up certificate information");
+ }
+
+ eurephia_log(ctx, LOG_DEBUG, 10,
+ "Result function call: eDBauth_TLS(ctx, '%s', '%s', '%s', '%s', %s) - %i",
+ org, cname, email, digest, depth, certid);
+
+ return certid;
+}
+
+// Authenticate user, using username, password and certid as authentication parameters
+// returns -1 if authentication fails. Returns 0 if user account is not found.
+int eDBauth_user(eurephiaCTX *ctx, const int certid, const char *username, const char *passwd)
+{
+ dbresult *res = NULL;
+ char *crpwd = NULL, *activated = NULL, *deactivated = NULL, *blid_uname = NULL, *blid_cert;
+ int uicid = 0, uid = 0, pwdok = 0;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Function call: eDBauth_user(ctx, %i, '%s','xxxxxxxx')",
+ certid, username);
+
+
+ // Generate SHA1 hash of password, used for password auth
+ crpwd = passwdhash(passwd);
+
+ res = sqlite_query(ctx,
+ "SELECT uicid, ou.uid, activated, deactivated, bl1.blid, bl2.blid, "
+ " (password = '%s') AS pwdok"
+ " FROM openvpn_users ou"
+ " JOIN openvpn_usercerts uc USING(uid) "
+ " LEFT JOIN openvpn_blacklist bl1 ON( ou.username = bl1.username) "
+ " LEFT JOIN (SELECT blid, certid "
+ " FROM openvpn_certificates "
+ " JOIN openvpn_blacklist USING(digest)) bl2 ON(uc.certid = bl2.certid)"
+ " WHERE uc.certid = '%i' AND ou.username = '%s'",
+ crpwd, certid, username);
+ free_nullsafe(crpwd);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not lookup user in database (certid %i, username '%s'", certid, username);
+ return 0;
+ }
+
+ if( sqlite_get_numtuples(res) == 1 ) {
+ uid = atoi_nullsafe(sqlite_get_value(res, 0, 1));
+ activated = sqlite_get_value(res, 0, 2);
+ deactivated = sqlite_get_value(res, 0, 3);
+ blid_uname = sqlite_get_value(res, 0, 4);
+ blid_cert = sqlite_get_value(res, 0, 5);
+ pwdok = atoi_nullsafe(sqlite_get_value(res, 0, 6));
+
+ if( blid_uname != NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "User account is BLACKLISTED (uid: %i, %s)",
+ uid, username);
+ uicid = -1;
+ } else if( blid_cert != NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "User account linked with a BLACKLISTED certificate "
+ "(uid: %i, %s) - certid: %s",
+ uid, username, certid);
+ uicid = -1;
+ } else if( activated == NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "User account is not activated (uid: %i, %s)",
+ uid, username);
+ uicid = -1;
+ } else if( deactivated != NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "User account is deactivated (uid: %i, %s)",
+ uid, username);
+ uicid = -1;
+ } else if( pwdok != 1 ) {
+ eurephia_log(ctx, LOG_WARNING, 0,"Authentication failed for user '%s'. Wrong password.",
+ username);
+ uicid = -1;
+
+ } else {
+ uicid = atoi_nullsafe(sqlite_get_value(res, 0, 0));
+ }
+ } else {
+ eurephia_log(ctx, LOG_WARNING, 0, "Authentication failed for user '%s'. "
+ "Could not find user or user-certificate link.", username);
+ uicid = 0;
+ }
+ sqlite_free_results(res);
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Result function call: eDBauth_user(ctx, %i, '%s','xxxxxxxx') - %i",
+ certid, username, uicid);
+
+ return uicid;
+}
+
+// Retrieve the user id from openvpn_usercerts, based on certid and username
+int eDBget_uid(eurephiaCTX *ctx, const int certid, const char *username)
+{
+ dbresult *res = NULL;
+ int ret = 0;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Function call: eDBget_uid(ctx, %i, '%s')", certid, username);
+
+ res = sqlite_query(ctx,
+ "SELECT uid "
+ " FROM openvpn_usercerts "
+ " JOIN openvpn_users USING (uid) "
+ " WHERE certid = '%i' AND username = '%s'",
+ certid, username);
+ if( (res == NULL) || (sqlite_get_numtuples(res) != 1) ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Could not lookup userid for user '%s'", username);
+ ret = -1;
+ } else {
+ ret = atoi_nullsafe(sqlite_get_value(res, 0, 0));
+ }
+ sqlite_free_results(res);
+
+ return ret;
+}
+
+
+// If function returns true(1) this control marks it as blacklisted
+int eDBblacklist_check(eurephiaCTX *ctx, const int type, const char *val)
+{
+ dbresult *blr = NULL, *atpr = NULL;
+ int atpexceed = -1, blacklisted = 0;
+ char *atpid = NULL, *blid = NULL;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Function call: eDBblacklist_check(ctx, '%s', '%s')",
+ eDBattempt_types[type].descr, val);
+
+ blr = sqlite_query(ctx, "SELECT blid FROM openvpn_blacklist WHERE %s = '%s'",
+ eDBattempt_types[type].colname, val);
+ if( blr != NULL ) {
+ blid = strdup_nullsafe(sqlite_get_value(blr, 0, 0));
+ sqlite_free_results(blr);
+ blr = NULL;
+
+ if( blid != NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 1, "Attempt from blacklisted %s: %s",
+ eDBattempt_types[type].descr, val);
+ blacklisted = 1; // [type] is blacklisted
+ }
+ // Update attempt information
+ update_attempts(ctx, blid);
+ } else {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Quering openvpn_blacklist for blacklisted %s",
+ eDBattempt_types[type].descr);
+ }
+
+ if( blacklisted == 0 ) {
+ // Check if this [type] has been attempted earlier - if it has reaced the maximum
+ // attempt limit, blacklist it
+ atpr = sqlite_query(ctx,
+ "SELECT atpid, attempts >= %s FROM openvpn_attempts WHERE %s= '%s'",
+ eGet_value(ctx->dbc->config, eDBattempt_types[type].allow_cfg),
+ eDBattempt_types[type].colname, val);
+ if( atpr != NULL ) {
+ atpid = strdup_nullsafe(sqlite_get_value(atpr, 0, 0));
+ atpexceed = atoi_nullsafe(sqlite_get_value(atpr, 0, 1));
+ sqlite_free_results(atpr);
+ atpr = NULL;
+
+ // If [type] has reached attempt limit and it is not black listed, black list it
+ if( (atpexceed > 0) && (blid == NULL) ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "%s got BLACKLISTED due to too many failed attempts: %s",
+ eDBattempt_types[type].descr, val);
+ blr = sqlite_query(ctx,
+ "INSERT INTO openvpn_blacklist (%s) VALUES ('%s')",
+ eDBattempt_types[type].colname, val);
+ if( blr == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not blacklist %s (%s)",
+ eDBattempt_types[type].descr, val);
+ }
+ sqlite_free_results(blr);
+ blacklisted = 1; // [type] is blacklisted
+ }
+ free_nullsafe(atpid);
+ } else {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Quering openvpn_attempts for blacklisted %s failed",
+ eDBattempt_types[type].descr);
+ }
+ free_nullsafe(atpr);
+ }
+ free_nullsafe(blid);
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Result - function call: eDBblacklist_check(ctx, '%s', '%s') - %i",
+ eDBattempt_types[type].descr, val, blacklisted);
+
+ return blacklisted;
+}
+
+// Register a failed attempt of authentication or IP address has been tried to many times
+void eDBregister_attempt(eurephiaCTX *ctx, int type, int mode, const char *value) {
+ dbresult *res;
+ char *id = NULL, *atmpt_block = NULL, *blid = NULL;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Function call: eDBregister_attempt(ctx, %s, %s, '%s')",
+ eDBattempt_types[type].colname,
+ (mode == ATTEMPT_RESET ? "ATTEMPT_RESET" : "ATTEMPT_REGISTER"),
+ value);
+
+ //
+ // openvpn_attempts
+ //
+ res = sqlite_query(ctx,
+ "SELECT atpid, attempts > %s, blid "
+ " FROM openvpn_attempts "
+ " LEFT JOIN openvpn_blacklist USING(%s)"
+ " WHERE %s = '%s'",
+ eGet_value(ctx->dbc->config, eDBattempt_types[type].allow_cfg),
+ eDBattempt_types[type].colname,
+ eDBattempt_types[type].colname, value);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Could not look up atpid in openvpn_attempts");
+ return;
+ }
+
+ if( (mode == ATTEMPT_RESET) && (sqlite_get_numtuples(res) == 0) ) {
+ // If we are asked to reset the attempt counter and we do not find any attempts, exit here
+ sqlite_free_results(res);
+ return;
+ }
+
+ id = strdup_nullsafe(sqlite_get_value(res, 0, 0));
+ atmpt_block = strdup_nullsafe(sqlite_get_value(res, 0, 1));
+ blid = strdup_nullsafe(sqlite_get_value(res, 0, 1));
+
+ sqlite_free_results(res);
+
+ if( (id == NULL) && (mode == ATTEMPT_REGISTER) ) {
+ // Only insert record when we are in registering mode
+ res = sqlite_query(ctx, "INSERT INTO openvpn_attempts (%s, attempts) VALUES ('%s', 1)",
+ eDBattempt_types[type].colname, value);
+ } else if( id != NULL ){
+ // if a attempt record exists, update it according to mode
+ res = sqlite_query(ctx,
+ "UPDATE openvpn_attempts "
+ " SET last_attempt = CURRENT_TIMESTAMP, attempts = %s"
+ " WHERE atpid = %s",
+ (mode == ATTEMPT_RESET ? "0" : "attempts + 1"),
+ id);
+ }
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not update openvpn_attempts for %s = %s",
+ eDBattempt_types[type].colname, value);
+ }
+ sqlite_free_results(res);
+
+ // If attempts have exceeded attempt limit, blacklist it immediately if not already registered
+ if( (mode == ATTEMPT_REGISTER)
+ && (blid == NULL) && (atmpt_block != NULL) && (atoi_nullsafe(atmpt_block) > 0) ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "Blacklisting %s due to too many attempts: %s",
+ eDBattempt_types[type].descr, value);
+ res = sqlite_query(ctx, "INSERT INTO openvpn_blacklist (%s) VALUES ('%s')",
+ eDBattempt_types[type].colname, value);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not blacklist %s: %s",
+ eDBattempt_types[type].descr, value);
+ }
+ sqlite_free_results(res);
+ }
+ free_nullsafe(id);
+ free_nullsafe(atmpt_block);
+ free_nullsafe(blid);
+}
+
+
+// Register a successful authentication
+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)
+{
+ dbresult *res = NULL;
+
+ eurephia_log(ctx, LOG_DEBUG, 10,
+ "Function call: eDBregister_login(ctx, '%s', %i, %i, '%s','%s','%s','%s','%s')",
+ skey->sessionkey, certid, uid, proto, remipaddr, remport, vpnipaddr, vpnipmask);
+
+ if( skey->sessionstatus != SESSION_NEW ) {
+ eurephia_log(ctx, LOG_WARNING, 10, "Not a new session, will not register it again");
+ return 1;
+ }
+
+ res = sqlite_query(ctx,
+ "INSERT INTO openvpn_lastlog (uid, certid, "
+ " protocol, remotehost, remoteport,"
+ " vpnipaddr, vpnipmask,"
+ " sessionstatus, sesskey, login) "
+ "VALUES (%i, %i, '%s','%s','%s','%s','%s', 1,'%s', CURRENT_TIMESTAMP)",
+ uid, certid, proto, remipaddr, remport, vpnipaddr, vpnipmask, skey->sessionkey);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Could not insert new session into openvpn_lastlog");
+ return 0;
+ }
+ sqlite_free_results(res);
+ skey->sessionstatus = SESSION_REGISTERED;
+ return 1;
+}
+
+// Register the MAC address of the VPN adapter of the user.
+int eDBregister_vpnmacaddr(eurephiaCTX *ctx, eurephiaSESSION *session, const char *macaddr)
+{
+ dbresult *res = NULL;
+
+ eurephia_log(ctx, LOG_DEBUG, 10,
+ "Function call: eDBregister_vpnmacaddr(ctx, '%s', '%s')",
+ session->sessionkey, macaddr);
+
+ if( macaddr == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "No MAC address was given to save");
+ return 0;
+ }
+
+ res = sqlite_query(ctx,
+ "UPDATE openvpn_lastlog SET sessionstatus = 2, macaddr = '%s' "
+ " WHERE sesskey = '%s' AND sessionstatus = 1", macaddr, session->sessionkey);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Could not update lastlog with new MAC address for session");
+ return 0;
+
+ }
+ sqlite_free_results(res);
+
+ // 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_CRITICAL, 0, "Could not save MAC address into session variables");
+ return 0;
+ }
+
+ return 1;
+}
+
+// Register the user as logged out
+int eDBregister_logout(eurephiaCTX *ctx, eurephiaSESSION *skey,
+ const char *bytes_sent, const char *bytes_received)
+{
+ dbresult *res = NULL;
+
+ eurephia_log(ctx, LOG_DEBUG, 10,
+ "Function call: eDBregister_logout(ctx, '%s', %s, %s)",
+ skey->sessionkey, bytes_sent, bytes_received);
+
+ res = sqlite_query(ctx,
+ "UPDATE openvpn_lastlog "
+ " SET sessionstatus = 3, logout = CURRENT_TIMESTAMP, "
+ " bytes_sent = '%i', bytes_received = '%i' "
+ " WHERE sesskey = '%s' AND sessionstatus = 2",
+ atoi_nullsafe(bytes_sent), atoi_nullsafe(bytes_received), skey->sessionkey);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Could not update lastlog with logout information (%s)",
+ skey->sessionkey);
+ return 0;
+ }
+ sqlite_free_results(res);
+ skey->sessionstatus = SESSION_LOGGEDOUT;
+ return 1;
+}
+
+// Retrieve a session key from openvpn_sessionkeys if it is a current session. Session seed is used
+// as criteria
+char *eDBget_sessionkey(eurephiaCTX *ctx, const char *sessionseed) {
+ dbresult *res = NULL;
+ char *skey = NULL;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "eDBget_sessionkey(ctx, '%s')", sessionseed);
+
+ if( sessionseed == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 1,
+ "eDBget_sessionkey: No session seed given - cannot locate sessionkey");
+ return NULL;
+ }
+ res = sqlite_query(ctx, "SELECT sessionkey FROM openvpn_sessionkeys WHERE sessionseed = '%s'",
+ sessionseed);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,"Could not retrieve sessionkey from openvpn_sessionkeys (%s)",
+ sessionseed);
+ return NULL;
+ }
+ if( sqlite_get_numtuples(res) == 1 ) {
+ skey = strdup_nullsafe(sqlite_get_value(res, 0, 0));
+ } else {
+ skey = NULL;
+ }
+ sqlite_free_results(res);
+ return skey;
+}
+
+
+// Function returns true(1) if session key is unique
+int eDBcheck_sessionkey_uniqueness(eurephiaCTX *ctx, const char *seskey) {
+ dbresult *res;
+ int uniq = 0;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "eDBcheck_sessionkey_uniqueness(ctx, '%s')", seskey);
+ if( seskey == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 1,
+ "eDBcheck_sessionkey_uniqness: Invalid session key given");
+ return 0;
+ }
+
+ res = sqlite_query(ctx, "SELECT count(sesskey) = 0 FROM openvpn_lastlog WHERE sesskey = '%s'", seskey);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "eDBcheck_sessionkey_uniqness: Could not check uniqueness of sessionkey");
+ return 0;
+ }
+ uniq = atoi_nullsafe(sqlite_get_value(res, 0, 0));
+ sqlite_free_results(res);
+
+ return uniq;
+}
+
+// register a link between a short-term session seed and a long-term session key
+int eDBregister_sessionkey(eurephiaCTX *ctx, const char *seed, const char *seskey) {
+ dbresult *res;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "eDBregister_sessionkey(ctx, '%s', '%s')", seed, seskey);
+ if( (seed == NULL) || (seskey == NULL) ) {
+ eurephia_log(ctx, LOG_CRITICAL, 1,
+ "eDBregister_sessionkey: Invalid session seed or session key given");
+ return 0;
+ }
+
+ res = sqlite_query(ctx,
+ "INSERT INTO openvpn_sessionkeys (sessionseed, sessionkey) VALUES('%s','%s')",
+ seed, seskey);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "eDBregister_sessionkey: Error registering sessionkey into openvpn_sessionkeys");
+ return 0;
+ }
+ sqlite_free_results(res);
+ return 1;
+}
+
+// remove a session seed/session key link from openvpn_sessionkeys
+int eDBremove_sessionkey(eurephiaCTX *ctx, const char *seskey) {
+ dbresult *res;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "eDBremove_sessionkey(ctx, '%s')", seskey);
+ if( seskey == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 1,
+ "eDBremove_sessionkey: Invalid session key given");
+ return 0;
+ }
+
+ res = sqlite_query(ctx, "DELETE FROM openvpn_sessionkeys WHERE sessionkey = '%s'", seskey);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "eDBremove_sessionkey: Error removing sessionkey from openvpn_sessionkeys");
+ return 0;
+ }
+ sqlite_free_results(res);
+ return 1;
+}
+
+// Load session values stored in the database into a eurephiaVALUES struct (session values)
+eurephiaVALUES *eDBload_sessiondata(eurephiaCTX *ctx, const char *sesskey) {
+ dbresult *res = NULL;
+ eurephiaVALUES *sessvals = NULL;
+ int i;
+
+ if( (ctx == NULL) || (sesskey == NULL) ) {
+ return NULL;
+ }
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Function call: eDBload_sessiondata(ctx, '%s')", sesskey);
+
+ res = sqlite_query(ctx, "SELECT datakey, dataval FROM openvpn_sessions WHERE sesskey = '%s'",
+ sesskey);
+ if( (res != NULL) || (sqlite_get_numtuples(res) > 0) ) {
+ for( i = 0; i < sqlite_get_numtuples(res); i++ ) {
+ sessvals = eDBadd_session_value(sessvals,
+ sqlite_get_value(res, i, 0),
+ sqlite_get_value(res, i, 1));
+ }
+ sqlite_free_results(res);
+ } else {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not load session values for session '%s'", sesskey);
+
+ }
+ return sessvals;
+}
+
+
+// Store a new, update or delete a sessionvalue in the database
+int eDBstore_session_value(eurephiaCTX *ctx, eurephiaSESSION *session, int mode, const char *key, const char *val)
+{
+ dbresult *res = NULL;
+
+ if( session == NULL ) {
+ eurephia_log(ctx, LOG_DEBUG, 10,
+ "Function call failed to eDBstore_session_value(ctx, ...): Non-existing session key");
+ return 0;
+ }
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Function call: eDBstore_session_value(ctx, '%s', %i, '%s', '%s')",
+ session->sessionkey, mode, key, val);
+
+ switch( mode ) {
+ case SESSVAL_NEW:
+ res = sqlite_query(ctx,
+ "INSERT INTO openvpn_sessions (sesskey, datakey, dataval) "
+ "VALUES ('%s','%s','%s')", session->sessionkey, key, val);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not register new session variable into database: [%s] %s = %s",
+ session->sessionkey, key, val);
+ return 0;
+ }
+ break;
+
+ case SESSVAL_UPDATE:
+ res = sqlite_query(ctx,
+ "UPDATE openvpn_sessions SET dataval = '%s' "
+ " WHERE sesskey = '%s' AND datakey = '%s'", val, session->sessionkey, key);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Could not update session variable: [%s] %s = %s ",
+ session->sessionkey, key, val);
+ return 0;
+ }
+ break;
+
+ case SESSVAL_DELETE:
+ res = sqlite_query(ctx, "DELETE FROM openvpn_sessions WHERE sesskey = '%s' AND datakey = '%s'",
+ session->sessionkey, key);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Could not delete session variable: [%s] %s",
+ session->sessionkey, key);
+ return 0;
+ }
+ break;
+
+ default:
+ eurephia_log(ctx, LOG_FATAL, 0, "Unknown eDBstore_session_value mode '%i'", mode);
+ return 1;
+ }
+ sqlite_free_results(res);
+ return 1;
+}
+
+
+// Delete session information from openvpn_sessions and update openvpn_lastlog with status
+int eDBdestroy_session(eurephiaCTX *ctx, const char *macaddr)
+{
+ dbresult *res = NULL;
+ char *skey = NULL;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Function call: eDBdestroy_session(ctx, '%s')", macaddr);
+
+ // Find sessionkey from MAC address
+ res = sqlite_query(ctx,
+ "SELECT sesskey "
+ " FROM openvpn_sessions "
+ " WHERE datakey = 'macaddr' AND dataval = '%'s'", macaddr);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not remove session from database (MAC addr: %s)", macaddr);
+ return 0;
+ }
+
+ skey = strdup_nullsafe(sqlite_get_value(res, 0, 0));
+ sqlite_free_results(res);
+
+ if( skey == NULL ) {
+ eurephia_log(ctx, LOG_INFO, 0,
+ "Could not find any sessions connected to MAC addr '%s')", macaddr);
+ return 1;
+ }
+
+ // Update session status
+ res = sqlite_query(ctx,
+ "UPDATE openvpn_lastlog "
+ " SET sessionstatus = 4, session_del = CURRENT_TIMESTAMP "
+ " WHERE sesskey = '%s' AND sessionstatus = 3", skey);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not update session status in lastlog (%s/%s))", skey, macaddr);
+ free_nullsafe(skey);
+ return 0;
+ }
+ sqlite_free_results(res);
+
+ // Delete session variables
+ res = sqlite_query(ctx, "DELETE FROM openvpn_sessions WHERE sesskey = '%s'", skey);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not delete session variables (%s/%s))", skey, macaddr);
+ free_nullsafe(skey);
+ return 0;
+ }
+ sqlite_free_results(res);
+
+ // Remove the sessionkey from openvpn_sessions
+ if( eDBremove_sessionkey(ctx, skey) == 0 ) {
+ free_nullsafe(skey);
+ return 0;
+ }
+
+ free_nullsafe(skey);
+ return 1;
+}
+
+
+char *eDBget_fw_profile(eurephiaCTX *ctx, eurephiaSESSION *session)
+{
+ char *ret = NULL;
+ dbresult *res = NULL;
+
+ eurephia_log(ctx, LOG_DEBUG, 10, "Function call: eDBget_fw_profile(ctx, {session}'%s')",
+ session->sessionkey);
+
+ res = sqlite_query(ctx,
+ "SELECT fw_profile "
+ " FROM openvpn_lastlog "
+ " JOIN openvpn_usercerts USING(certid, uid)"
+ " JOIN openvpn_accesses USING(accessprofile)"
+ " WHERE sesskey = '%s'", session->sessionkey);
+ if( res == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Could not retrieve firewall profile for session '%s'",
+ session->sessionkey);
+ return NULL;
+ }
+ ret = strdup_nullsafe(sqlite_get_value(res, 0, 0));
+ sqlite_free_results(res);
+ return ret;
+}
+
diff --git a/database/sqlite/sql-schema.sql b/database/sqlite/sql-schema.sql
new file mode 100644
index 0000000..d387d02
--- /dev/null
+++ b/database/sqlite/sql-schema.sql
@@ -0,0 +1,105 @@
+CREATE TABLE openvpn_certificates (
+ depth integer NOT NULL,
+ digest varchar(64) NOT NULL,
+ common_name varchar(64) NOT NULL,
+ organisation varchar(64) NOT NULL,
+ email varchar(256) NOT NULL,
+ registered timestamp DEFAULT CURRENT_TIMESTAMP,
+ certid integer PRIMARY KEY AUTOINCREMENT
+);
+CREATE UNIQUE INDEX opevpn_certificates_digest ON openvpn_certificates(digest);
+
+CREATE TABLE openvpn_users (
+ username varchar(32) NOT NULL,
+ password varchar(64) NOT NULL,
+ activated timestamp ,
+ deactivated timestamp ,
+ last_accessed timestamp ,
+ uid integer PRIMARY KEY AUTOINCREMENT
+);
+CREATE UNIQUE INDEX openvpn_users_uname ON openvpn_users(username);
+
+CREATE TABLE openvpn_usercerts (
+ uid integer NOT NULL,
+ certid integer NOT NULL,
+ accessprofile integer ,
+ registered timestamp DEFAULT CURRENT_TIMESTAMP,
+ uicid integer PRIMARY KEY AUTOINCREMENT
+);
+CREATE INDEX openvpn_usercerts_uid ON openvpn_usercerts(uid);
+CREATE INDEX openvpn_usercerts_certid ON openvpn_usercerts(certid);
+
+CREATE TABLE openvpn_accesses (
+ access_descr varchar(128) ,
+ fw_profile varchar(64) NOT NULL,
+ accessprofile integer PRIMARY KEY AUTOINCREMENT
+);
+
+CREATE TABLE openvpn_lastlog (
+ uid integer ,
+ certid integer ,
+ protocol varchar(4) NOT NULL,
+ remotehost varchar(128) NOT NULL,
+ remoteport integer NOT NULL,
+ macaddr varchar(20) ,
+ vpnipaddr varchar(32) NOT NULL,
+ vpnipmask varchar(32) NOT NULL,
+ sessionstatus integer NOT NULL DEFAULT 0,
+ sesskey varchar(128) ,
+ login timestamp ,
+ logout timestamp ,
+ session_del timestamp ,
+ bytes_sent integer ,
+ bytes_received integer ,
+ llid integer PRIMARY KEY AUTOINCREMENT
+);
+CREATE UNIQUE INDEX openvpn_lastlog_sesskey ON openvpn_lastlog(sesskey);
+
+CREATE TABLE openvpn_sessions (
+ sesskey varchar(128) NOT NULL,
+ datakey varchar(256) NOT NULL,
+ dataval text ,
+ registered timestamp DEFAULT CURRENT_TIMESTAMP,
+ sessid integer PRIMARY KEY AUTOINCREMENT
+);
+CREATE INDEX openvpn_sessions_sesskey ON openvpn_sessions(sesskey);
+CREATE UNIQUE INDEX openvpn_sessions_sess_datakey ON openvpn_sessions(sesskey, datakey);
+
+CREATE TABLE openvpn_blacklist (
+ digest varchar(64) ,
+ username varchar(32) ,
+ remoteip varchar(32) ,
+ registered timestamp DEFAULT CURRENT_TIMESTAMP,
+ last_accessed timestamp ,
+ blid integer PRIMARY KEY AUTOINCREMENT
+);
+CREATE UNIQUE INDEX openvpn_blacklist_digest ON openvpn_blacklist(digest);
+CREATE UNIQUE INDEX openvpn_blacklist_username ON openvpn_blacklist(username);
+CREATE UNIQUE INDEX openvpn_blacklist_remoteip ON openvpn_blacklist(remoteip);
+
+CREATE TABLE openvpn_attempts (
+ username varchar(32) ,
+ digest varchar(64) ,
+ remoteip varchar(32) ,
+ attempts integer DEFAULT 0,
+ registered timestamp DEFAULT CURRENT_TIMESTAMP,
+ last_attempt timestamp ,
+ atpid integer PRIMARY KEY AUTOINCREMENT
+);
+CREATE UNIQUE INDEX openvpn_attempts_username ON openvpn_attempts(username);
+CREATE UNIQUE INDEX openvpn_attempts_digest ON openvpn_attempts(digest);
+CREATE UNIQUE INDEX openvpn_attempts_remoteip ON openvpn_attempts(remoteip);
+
+CREATE TABLE openvpn_sessionkeys (
+ sessionseed varchar(64) NOT NULL,
+ sessionkey varchar(64) NOT NULL,
+ PRIMARY KEY(sessionseed)
+);
+
+CREATE TABLE openvpn_config (
+ datakey varchar(64) NOT NULL,
+ dataval text ,
+ cfgid integer PRIMARY KEY AUTOINCREMENT
+);
+CREATE UNIQUE INDEX openvpn_config_key ON openvpn_config(datakey);
+
diff --git a/database/sqlite/sqlite.c b/database/sqlite/sqlite.c
new file mode 100644
index 0000000..8c2e31e
--- /dev/null
+++ b/database/sqlite/sqlite.c
@@ -0,0 +1,325 @@
+/* sqlite.c -- Generic functions to simplify SQLite3 queries
+ *
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sqlite3.h>
+
+#include <eurephia_log.h>
+#include <eurephia_nullsafe.h>
+#include <eurephia_directions.h>
+
+#define SQLITE_C
+#include "./sqlite.h"
+
+#ifdef MEMWATCH
+#include <memwatch.h>
+#endif
+
+
+dbresult *glob_results = NULL;
+
+// Free up a dbresult structure
+void _sqlite_free_results(dbresult *inres)
+{
+ _sqlite_tuples *tup = NULL, *fld = NULL;
+ _sqlite_header *hdr = NULL;
+
+ if( inres == NULL ) {
+ return;
+ }
+
+ // Remove all tuples from memory
+ if( inres->tuples != NULL ) {
+ tup = inres->tuples;
+ do {
+ fld = tup->nextfield;
+ // Remove all fields from the current tuple recird
+ do {
+ if( fld != fld->prevfield ) {
+ fld = fld->nextfield;
+ free_nullsafe(fld->prevfield->value);
+ free_nullsafe(fld->prevfield);
+ }
+ } while( fld != tup );
+ tup = tup->nexttuple;
+ free_nullsafe(fld->value);
+ free_nullsafe(fld);
+ } while( tup != inres->tuples );
+ }
+
+ // Remove all header information
+ if( inres->headerrec != NULL ) {
+ hdr = inres->headerrec->next;
+ do {
+ if( hdr != hdr->prev ) {
+ hdr = hdr->next;
+ free_nullsafe(hdr->prev->name);
+ free_nullsafe(hdr->prev);
+ }
+ } while( hdr != inres->headerrec );
+ free_nullsafe(hdr->name);
+ free_nullsafe(hdr);
+ }
+ free_nullsafe(inres);
+}
+
+
+// Callback function used by sqlite3_exec - populates a global variable glob_results.
+// The glob_results structure is allocated with a new address on each sqlite_query call
+static int _cb_parse_result(void *NotUsed, int argc, char **argv, char **colName)
+{
+ // This callback function is called for each row returned by the query
+ _sqlite_header *hrec = NULL;
+ _sqlite_tuples *trec = NULL, *new_frec = NULL;
+ int i;
+
+ if( glob_results == NULL ) {
+ return 1;
+ }
+
+ // If no header records are found, populate this structure
+ if( glob_results->headerrec == NULL ) {
+ for( i = 0; i < argc; i++ ) {
+ hrec = (_sqlite_header *) malloc(sizeof(_sqlite_header)+2);
+ memset(hrec, 0, sizeof(_sqlite_header)+2);
+
+ hrec->fieldid = i;
+ hrec->name = strdup_nullsafe(colName[i]);
+ hrec->namelength = strlen_nullsafe(hrec->name);
+
+ // Append the new record to the "end" of the
+ // circular pointer chain for header info
+ if( glob_results->headerrec == NULL ) {
+ glob_results->headerrec = hrec;
+ hrec->next = hrec;
+ hrec->prev = hrec;
+ } else {
+ hrec->next = glob_results->headerrec;
+ hrec->prev = glob_results->headerrec->prev;
+ glob_results->headerrec->prev->next = hrec;
+ glob_results->headerrec->prev = hrec;
+ }
+ }
+ glob_results->num_fields = argc;
+ }
+
+ // Add all data fields for this record into a tuple structure
+ hrec = glob_results->headerrec;
+ for( i = 0; i < argc; i++ ) {
+ new_frec = (_sqlite_tuples *) malloc(sizeof(_sqlite_tuples)+2);
+ memset(new_frec, 0, sizeof(_sqlite_tuples)+2);
+
+ // trec contains the head of a new record set with fields
+ if( trec == NULL ) {
+ // Pointer to the first record in the tupleset
+ trec = new_frec;
+
+ // Add this header to the "end" of the
+ // circular pointer chain for tuples
+ //
+ // These pointers directs you to the next or previous
+ // record set of data fields
+ if( glob_results->tuples == NULL ) {
+ glob_results->tuples = trec;
+ trec->nexttuple = trec;
+ trec->prevtuple = trec;
+ } else {
+ trec->nexttuple = glob_results->tuples;
+ trec->prevtuple = glob_results->tuples->prevtuple;
+ glob_results->tuples->prevtuple->nexttuple = trec;
+ glob_results->tuples->prevtuple = trec;
+ }
+ }
+
+ new_frec->tupleid = glob_results->num_tuples;
+ new_frec->fieldid = i;
+ new_frec->value = strdup_nullsafe(argv[i]);
+ new_frec->length = strlen_nullsafe(trec->value);
+
+ new_frec->nexttuple = trec->nexttuple;
+ new_frec->prevtuple = trec->prevtuple;
+
+ // Add a pointer to the header structure as well, but only
+ // if we are on the same ID with with header structure as
+ // in the data field structure
+ if( hrec->fieldid == i ) {
+ new_frec->header = hrec;
+ }
+
+ if( new_frec->length > hrec->maxvaluelength ) {
+ hrec->maxvaluelength = new_frec->length;
+ }
+
+ // These pointers directs you to the next or previous
+ // field in this record set
+ if( trec->nextfield == NULL ) {
+ trec->nextfield = new_frec;
+ trec->prevfield = new_frec;
+ } else {
+ new_frec->nextfield = trec;
+ new_frec->prevfield = trec->prevfield;
+ trec->prevfield->nextfield = new_frec;
+ trec->prevfield = new_frec;
+ }
+
+ // Get ready for the next field - find the next header record.
+ hrec = hrec->next;
+ }
+ // Increase the tuple counter
+ glob_results->num_tuples++;
+
+ return 0;
+}
+
+
+// A simpler way to fetch data from SQLite than to use sqlite3_exec with callback
+// each time you want to do a query
+dbresult *sqlite_query(eurephiaCTX *ctx, char *fmt, ... ) {
+ int rc;
+ va_list ap;
+ char *errMsg = NULL, sql[65538];
+ eDBconn *dbc = ctx->dbc;
+
+ if( ctx->dbc == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "No open database connection to perfom SQL query to");
+ return NULL;
+ }
+
+
+ // prepare a new (global) result set ...
+ // do not delete the old ones, since we return this "global"
+ // result as a new individual result
+ glob_results = malloc(sizeof(dbresult)+2);
+ memset(glob_results, 0, sizeof(dbresult)+2);
+ glob_results->num_tuples = 0;
+
+ // prepare SQL query
+ memset(&sql, 0, 65538);
+ va_start(ap, fmt);
+ vsnprintf(sql, 65535, fmt, ap);
+ va_end(ap);
+
+ eurephia_log(ctx, LOG_DEBUG, 11, "Doing SQL Query: %s", sql);
+ rc = sqlite3_exec( (sqlite3 *) dbc->dbhandle, sql, _cb_parse_result, 0, &errMsg );
+ if( rc != SQLITE_OK ) {
+ eurephia_log(ctx, LOG_ERROR, 0, "SQL Error: %s", errMsg);
+ return NULL;
+ }
+
+ glob_results->srch_tuples = glob_results->tuples;
+ glob_results->srch_headerrec = glob_results->headerrec;
+
+ return glob_results;
+}
+
+// Simple line-by-line result dumper
+void sqlite_dump_result(FILE *dmp, dbresult *res) {
+ _sqlite_tuples *row = NULL, *field = NULL;
+
+ if( res == NULL ) {
+ fprintf(dmp, "(No records found)");
+ }
+
+ /*
+ hdr = (char *) malloc( ((res->maxlen_colname + res->maxlen_colvalue - 6) / 2) + 2 );
+ memset(hdr, 0, ((res->maxlen_colname + res->maxlen_colvalue - 6) / 2) + 2 );
+ memset(hdr, '-', ((res->maxlen_colname + res->maxlen_colvalue - 6) / 2));
+ */
+
+ row = res->tuples;
+ do {
+ fprintf(dmp, "** Record %i\n", row->tupleid);
+ field = row;
+ do {
+ fprintf(dmp, "(%i) %s | %s\n", field->fieldid, field->header->name, field->value);
+ field = field->nextfield;
+ } while ( field != row);
+ row = row->nexttuple;
+ fprintf(dmp, "-----------------------------------------------------\n");
+ } while( row != res->tuples);
+ fprintf(dmp, "-----------------------------------------------------\n(%i records found)\n",
+ (int) res->num_tuples);
+ // fprintf(dmp, "%s----------%s\n(%i records found)\n\n", hdr, hdr, res->num_tuples);
+ // free(hdr);
+}
+
+// Retrieve a specific value from a dbresult structure
+char *sqlite_get_value(dbresult *res, int row, int col) {
+ _sqlite_tuples *ptr = res->srch_tuples;
+
+ if( (ptr == NULL) || (row > res->num_tuples) || (col > res->num_fields) ) {
+ return NULL;
+ }
+
+ do {
+ if( ptr->tupleid == row ) {
+ do {
+ if( ptr->fieldid == col ) {
+ res->srch_tuples = ptr;
+ return ptr->value;
+ }
+ ptr = (DIRECTION(ptr->fieldid, col, res->num_fields) == DIR_R
+ ? ptr->nextfield : ptr->prevfield);
+ } while( ptr != res->srch_tuples ) ;
+ }
+ ptr = (DIRECTION(ptr->tupleid, row, res->num_tuples) == DIR_R ? ptr->nexttuple : ptr->prevtuple);
+ } while( ptr != res->srch_tuples );
+ return NULL;
+}
+
+// Retrieve number of tuples in current dbresult structure
+int sqlite_get_numtuples(dbresult *res) {
+ return (res != NULL ? res->num_tuples : 0);
+}
+
+#ifdef SQLITE_DEBUG
+// Just a simple test program ... to debug this sqlite wrapper
+int main() {
+ int rc;
+ dbresult *res = NULL, *res2 = NULL;
+ eurephiaCTX *ctx;
+
+#ifdef MEMWATCH
+ mwStatistics(3);
+#endif
+
+ ctx = malloc(sizeof(eurephiaCTX)+2);
+ memset(ctx, 0, sizeof(eurephiaCTX)+2);
+
+ ctx->dbc = malloc(sizeof(eDBconn)+2);
+ memset(ctx->dbc, 0, sizeof(eDBconn)+2);
+
+ rc = sqlite3_open("./vpnaccess", (void *) &ctx->dbc->dbhandle);
+ if( rc ) {
+ fprintf(stderr, "Could not open db\n");
+ return 1;
+ }
+
+ ctx->log = stderr;
+ ctx->loglevel = 5;
+
+
+ res = sqlite_query(ctx, "SELECT * FROM openvpn_access");
+ res2 = sqlite_query(ctx, "SELECT CURRENT_TIMESTAMP");
+ if( res != NULL ) {
+ sqlite_dump_result(stdout, res);
+ sqlite_dump_result(stdout, res2);
+
+ fprintf(stderr, "--> %s - %s\n", sqlite_get_value(res, 3, 2), sqlite_get_value(res, 1, 4));
+ fprintf(stderr, "--> %s - %s\n", sqlite_get_value(res2, 0, 0), sqlite_get_value(res2, 0, 4));
+
+ sqlite_free_results(res);
+ sqlite_free_results(res2);
+ }
+ sqlite3_close(ctx->dbc->dbhandle);
+ free(ctx->dbc);
+ free(ctx);
+ return 0;
+}
+#endif
diff --git a/database/sqlite/sqlite.h b/database/sqlite/sqlite.h
new file mode 100644
index 0000000..82b1464
--- /dev/null
+++ b/database/sqlite/sqlite.h
@@ -0,0 +1,58 @@
+/* sqlite.c -- Generic functions to simplify SQLite3 queries
+ *
+ *
+ *
+ */
+
+#ifndef SQLITE_H_
+# define SQLITE_H_
+
+#include <stdarg.h>
+
+
+typedef struct __sqlite_header {
+ unsigned int fieldid;
+ char *name;
+ // char *type;
+ size_t namelength;
+ size_t maxvaluelength;
+ struct __sqlite_header *next;
+ struct __sqlite_header *prev;
+} _sqlite_header;
+
+
+typedef struct __sqlite_tuples {
+ unsigned int tupleid;
+ unsigned int fieldid;
+ char *value;
+ size_t length;
+ _sqlite_header *header;
+ struct __sqlite_tuples *nextfield;
+ struct __sqlite_tuples *prevfield;
+ struct __sqlite_tuples *nexttuple;
+ struct __sqlite_tuples *prevtuple;
+} _sqlite_tuples;
+
+
+typedef struct __sqlite_dbresult {
+ // start of the chains
+ _sqlite_tuples *tuples;
+ _sqlite_header *headerrec;
+ size_t num_tuples;
+ size_t num_fields;
+
+ // Used for search functions
+ _sqlite_tuples *srch_tuples;
+ _sqlite_header *srch_headerrec;
+} dbresult;
+
+#ifndef SQLITE_C
+#define sqlite_free_results(r) { _sqlite_free_results(r); r = NULL; }
+void _sqlite_free_results(dbresult *);
+dbresult *sqlite_query(eurephiaCTX *ctx, const char *, ...);
+char *sqlite_get_value(dbresult *res, int, int);
+void sqlite_dump_result(FILE *, dbresult *);
+int sqlite_get_numtuples(dbresult *);
+#endif
+
+#endif /* !SQLITE_H_ */