diff options
| author | David Sommerseth <dazo@users.sourceforge.net> | 2008-08-06 14:45:14 +0200 |
|---|---|---|
| committer | David Sommerseth <dazo@users.sourceforge.net> | 2008-08-06 14:45:14 +0200 |
| commit | e51f1c49f9c1745012514dac79aaf8250ca1c036 (patch) | |
| tree | 46017fb7c25dc9a60926173c543d7a7592208aca /database/sqlite | |
Imported eurephia into git
Diffstat (limited to 'database/sqlite')
| -rw-r--r-- | database/sqlite/Makefile | 43 | ||||
| -rw-r--r-- | database/sqlite/eurephiadb-sqlite.c | 842 | ||||
| -rw-r--r-- | database/sqlite/sql-schema.sql | 105 | ||||
| -rw-r--r-- | database/sqlite/sqlite.c | 325 | ||||
| -rw-r--r-- | database/sqlite/sqlite.h | 58 |
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_ */ |
