summaryrefslogtreecommitdiffstats
path: root/plugin/eurephiadb_session.c
diff options
context:
space:
mode:
authorDavid Sommerseth <dazo@users.sourceforge.net>2008-10-15 00:39:53 +0200
committerDavid Sommerseth <dazo@users.sourceforge.net>2008-10-15 00:39:53 +0200
commit0ea1a3e2e6a10300388e01ac89504abe3624ae56 (patch)
treefff59c70d4db431c2114e89d0819af8921aff463 /plugin/eurephiadb_session.c
parentb65b0802ead5e863ca8cb41fff77528735a1466c (diff)
downloadeurephia-0ea1a3e2e6a10300388e01ac89504abe3624ae56.tar.gz
eurephia-0ea1a3e2e6a10300388e01ac89504abe3624ae56.tar.xz
eurephia-0ea1a3e2e6a10300388e01ac89504abe3624ae56.zip
Reorganised the source code
Moved all OpenVPN plug-in related things into ./plugins, including firewall Moved all shared code into ./common and moved the generic part of the database files into ./database Updated all CMakeLists.txt files and created a new one for the root directory
Diffstat (limited to 'plugin/eurephiadb_session.c')
-rw-r--r--plugin/eurephiadb_session.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/plugin/eurephiadb_session.c b/plugin/eurephiadb_session.c
new file mode 100644
index 0000000..cb314ee
--- /dev/null
+++ b/plugin/eurephiadb_session.c
@@ -0,0 +1,352 @@
+/* eurephiadb_session.c -- Global API for handling eurephia sessions
+ *
+ * GPLv2 - Copyright (C) 2008 David Sommerseth <dazo@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <openssl/rand.h>
+
+#include "eurephia_struct.h"
+#include "eurephia_nullsafe.h"
+#include "eurephia_log.h"
+#include "eurephiadb_session.h"
+#include "eurephia_values.h"
+#include "sha512.h"
+
+
+// Also defined in the eurephiadb_driver.h, but not as extern.
+extern char *(*eDBget_sessionkey_seed) (eurephiaCTX *ctx, const char *sessionseed);
+extern char *(*eDBget_sessionkey_macaddr) (eurephiaCTX *ctx, const char *macaddr);
+
+extern int (*eDBcheck_sessionkey_uniqueness) (eurephiaCTX *ctx, const char *seskey);
+
+extern int (*eDBregister_sessionkey) (eurephiaCTX *ctx, const char *seed, const char *seskey);
+
+extern eurephiaVALUES *(*eDBload_sessiondata) (eurephiaCTX *ctx, const char *sesskey);
+
+extern int eDBstore_session_value(eurephiaCTX *ctx, eurephiaSESSION *session, int mode,
+ const char *key, const char *val);
+
+
+// Adds or updates a key in the eurephiaVALUES stack. Database is updated before the stack is updated.
+// If database fails, the stack is not updated.
+int eDBset_session_value(eurephiaCTX *ctx, eurephiaSESSION *session, const char *key, const char *val) {
+ eurephiaVALUES *svals = NULL;
+
+ if( (session == NULL) || (key == NULL) ) {
+ return 0;
+ }
+
+ DEBUG(ctx, 30, "Function call: eDBset_session_value(ctx, '%s','%s','%s')",
+ session->sessionkey, key, val);
+
+ // Create a new session value buffer if it does not exist
+ if( session->sessvals == NULL ) {
+ session->sessvals = eCreate_value_space(ctx, 10);
+ if( session->sessvals == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for session values");
+ return 0;
+ }
+ }
+
+ // Check if the session value exists already. If it does update it, or else add it
+ svals = eGet_valuestruct(session->sessvals, key);
+ if( (svals == NULL) && (val != NULL) ) {
+ DEBUG(ctx, 32, "eDBset_session_value ... New session value: %s = '%s'", key, val);
+ // Add a new session value
+ if( eDBstore_session_value(ctx, session, SESSVAL_NEW, key, val) ) {
+ DEBUG(ctx, 32, "eDBset_session_value ... Adding value to value stack: %s = '%s'",
+ key, val);
+ // Add value to the stack
+ eAdd_value(ctx, session->sessvals, key, val);
+
+ DEBUG(ctx, 32, "Registered session variable to session '%s': %s = %s",
+ session->sessionkey, key, val);
+ }
+ } else if( svals != NULL ) {
+ if( (val != NULL) && (strcmp(svals->val, val) == 0) ) {
+ DEBUG(ctx, 32, "Session value not changed('%s','%s','%s)",
+ session->sessionkey, key, val);
+ return 1;
+ }
+ // Update the value in the stack if database is updated without errors
+ if( eDBstore_session_value(ctx, session,(val != NULL ? SESSVAL_UPDATE : SESSVAL_DELETE), key,val)){
+ free_nullsafe(svals->val);
+ svals->val = strdup_nullsafe(val);
+ DEBUG(ctx, 32, "Session variable updated in session '%s': %s = %s",
+ session->sessionkey, key, val);
+ }
+ } else if( (svals == NULL) && (val == NULL ) ) {
+ DEBUG(ctx, 32, "Ignoring saving new session value '%s' == NULL", key);
+ }
+ return 1;
+}
+
+
+// Generate some random data and return a string.
+static int rand_init = 0;
+int get_randstring(eurephiaCTX *ctx, char *rndstr, int len) {
+ int attempts = 0;
+ do {
+ if( !rand_init ) {
+ if( !RAND_load_file("/dev/urandom", 64) ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not load random data from /dev/urandom");
+ return 0;
+ }
+ rand_init = 1;
+ }
+
+ if( RAND_pseudo_bytes((unsigned char *) rndstr, len) ) {
+ return 1;
+ }
+ sleep(1);
+ rand_init = 0;
+ } while( attempts++ < 11 );
+ eurephia_log(ctx, LOG_FATAL, 0, "RAND_pseudo_bytes() could not generate enough random data");
+ return 0;
+}
+
+
+
+// Generates a new session structure. Session key will be created if session seed (input params) are not known.
+// If session seed is known, the already generated session key will be used.
+eurephiaSESSION *eDBopen_session_seed(eurephiaCTX *ctx, const char *digest,
+ const char *cname, const char *username,
+ const char *vpnipaddr, const char *vpnipmask,
+ const char *remipaddr, const char *remport)
+{
+ eurephiaSESSION *new_session = NULL;
+ char *seeddata = NULL, *seed = NULL, *ptr = NULL;
+ SHA512Context sha;
+ uint8_t sha_res[SHA512_HASH_SIZE];
+ int totlen = 0, i = 0;
+
+ DEBUG(ctx, 12, "Function call: eDBopen_session_seed(ctx, '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
+ digest, cname, username, vpnipaddr, vpnipmask, remipaddr, remport);
+
+ new_session = (eurephiaSESSION *) malloc(sizeof(eurephiaSESSION) + 2);
+ if( new_session == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for a new session");
+ return NULL;
+ }
+ memset(new_session, 0, sizeof(eurephiaSESSION) + 2);
+
+ // Build up a string containing all elements for the session seed
+ totlen = strlen_nullsafe(digest) + strlen_nullsafe(cname) + strlen_nullsafe(username)
+ + strlen_nullsafe(vpnipaddr) + strlen_nullsafe(vpnipmask) + strlen_nullsafe(remipaddr)
+ + strlen_nullsafe(remport) + 5; // +5 == len(pid)
+
+ seeddata = (char *) malloc((totlen * 2) + 4);
+ if( seeddata == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for a new session key (1)");
+ free_nullsafe(new_session);
+ return NULL;
+ }
+ memset(seeddata, 0, (totlen * 2) + 4);
+ snprintf((char *)seeddata, totlen,
+ "%s%s%s%s%s%s%s%i", digest, cname, username, vpnipaddr, vpnipmask, remipaddr, remport,getpid());
+
+ // Generate a SHA512 version of session seed
+ memset(&sha, 0, sizeof(SHA512Context));
+ memset(&sha_res, 0, sizeof(sha_res));
+ SHA512Init(&sha);
+ SHA512Update(&sha, seeddata, totlen);
+ SHA512Final(&sha, sha_res);
+
+ seed = (char *) malloc((SHA512_HASH_SIZE*2)+3);
+ if( seed == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for session seed");
+ free_nullsafe(seeddata);
+ free_nullsafe(new_session);
+ return NULL;
+ }
+ memset(seed, 0, (SHA512_HASH_SIZE*2)+2);
+ ptr = seed;
+
+ for( i = 0; i < SHA512_HASH_SIZE; i++ ) {
+ sprintf(ptr, "%02x", sha_res[i]);
+ ptr++;
+ }
+ memset(&sha, 0, sizeof(SHA512Context));
+ memset(&sha_res, 0, sizeof(sha_res));
+
+ DEBUG(ctx, 13, "Using session seed '%s'", seed);
+
+ // Try to retrieve the sessionkey from the database, based on the session seed
+ new_session->sessionkey = eDBget_sessionkey_seed(ctx, seed);
+ if( new_session->sessionkey == NULL ) {
+ // ... if we do not find a sessionkey ... lets generate one
+ int rndlen = 0;
+ char *rndstr = NULL;
+ char *skeydata = NULL;
+ int loop = 0, uniqcheck = 0;
+
+ DEBUG(ctx, 13, "Unknown session seed, creating new session key");
+
+ // Loop until we get a unique sessionkey - don't loop more than 10 times
+ skeydata = (char *) malloc((totlen*2)+4);
+ if( skeydata == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for new session key data");
+ free_nullsafe(new_session->sessionkey);
+ free_nullsafe(new_session);
+ free_nullsafe(seeddata);
+ free_nullsafe(seed);
+ return NULL;
+ }
+ do {
+ memset(skeydata, 0, (totlen*2)+4);
+
+ // FIXME: Validate that we have enough random data for the session key
+
+ // Append some random data to our session seed
+ rndstr = (char *) malloc((totlen * 2));
+ if( rndstr == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0,
+ "Could not allocate memory for new session key data (2)");
+ free_nullsafe(new_session->sessionkey);
+ free_nullsafe(new_session);
+ free_nullsafe(seeddata);
+ free_nullsafe(seed);
+ return NULL;
+ }
+ memset(rndstr, 0, (totlen * 2));
+ rndlen = ((totlen * 2) - strlen_nullsafe(seed) - 2);
+
+ if( !get_randstring(ctx, rndstr, rndlen) ) {
+ eurephia_log(ctx, LOG_PANIC, 0,
+ "Could not generate enough random data for session key");
+ free_nullsafe(new_session->sessionkey);
+ free_nullsafe(new_session);
+ free_nullsafe(seeddata);
+ free_nullsafe(seed);
+ return NULL;
+ }
+
+ // Generate SHA512 version of the session data
+ SHA512Init(&sha);
+ SHA512Update(&sha, rndstr, rndlen);
+ SHA512Final(&sha, sha_res);
+
+ free_nullsafe(new_session->sessionkey);
+ new_session->sessionkey = (char *) malloc((SHA512_HASH_SIZE*2)+3);
+ if( new_session->sessionkey == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0,
+ "Could not allocate memory for new session key");
+ free_nullsafe(new_session);
+ free_nullsafe(seeddata);
+ free_nullsafe(seed);
+ return NULL;
+ }
+ memset(new_session->sessionkey, 0, (SHA512_HASH_SIZE*2)+3);
+
+ ptr = new_session->sessionkey;
+ for( i = 0; i < SHA512_HASH_SIZE; i++ ) {
+ sprintf(ptr, "%02x", sha_res[i]);
+ ptr++;
+ }
+ memset(&sha, 0, sizeof(SHA512Context));
+ memset(&sha_res, 0, sizeof(sha_res));
+ free_nullsafe(rndstr);
+
+ loop++;
+ uniqcheck = eDBcheck_sessionkey_uniqueness(ctx, new_session->sessionkey);
+ } while( (uniqcheck == 0) && loop < 11 );
+ free_nullsafe(skeydata);
+
+ // If we did not manage to create a unique session key (random data collection must have failed!)
+ if( uniqcheck == 0 ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "Did not manage to create a unique sessionkey after %i attempts", loop-1);
+ free_nullsafe(new_session->sessionkey);
+ free_nullsafe(new_session);
+ free_nullsafe(seeddata);
+ free_nullsafe(seed);
+ return NULL;
+ }
+
+ // Save this session key in the database and connect it to this session seed
+ if( eDBregister_sessionkey(ctx, seed, new_session->sessionkey) == 0) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not register sessionkey");
+ free_nullsafe(new_session->sessionkey);
+ free_nullsafe(new_session);
+ free_nullsafe(seeddata);
+ free_nullsafe(seed);
+ return NULL;
+ };
+ new_session->sessionstatus = SESSION_NEW;
+ } else {
+ new_session->sessionstatus = SESSION_EXISTING;
+ DEBUG(ctx, 13, "Session seed found, using sessionkey '%s'", new_session->sessionkey);
+ }
+ free_nullsafe(seed);
+ free_nullsafe(seeddata);
+
+ // Load session values from the database
+ new_session->sessvals = eDBload_sessiondata(ctx, new_session->sessionkey);
+
+ // Return struct which contains session key and session variables
+ return new_session;
+}
+
+// Open an existing session based on a MAC address
+eurephiaSESSION *eDBopen_session_macaddr(eurephiaCTX *ctx, const char *macaddr) {
+ eurephiaSESSION *new_session = NULL;
+
+ DEBUG(ctx, 12, "Function call: eDBopen_session_mac(ctx, '%s')", macaddr);
+
+ new_session = (eurephiaSESSION *) malloc(sizeof(eurephiaSESSION) + 2);
+ if( new_session == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not allocate memory for a new session");
+ return NULL;
+ }
+ memset(new_session, 0, sizeof(eurephiaSESSION) + 2);
+
+ // Get the sessionkey from the database
+ new_session->sessionkey = eDBget_sessionkey_macaddr(ctx, macaddr);
+ if( new_session->sessionkey == NULL ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "Could not find an active session for MAC address '%s'",
+ macaddr);
+ free_nullsafe(new_session);
+ return NULL;
+ }
+ DEBUG(ctx, 13, "Session seed found, using sessionkey '%s'", new_session->sessionkey);
+
+ // Load session values from the database
+ new_session->sessvals = eDBload_sessiondata(ctx, new_session->sessionkey);
+
+ // Return struct which contains the current session
+ return new_session;
+}
+
+
+// Free up the memory used by a session structure
+void eDBfree_session_func(eurephiaCTX *ctx, eurephiaSESSION *session) {
+ if( session == NULL ) {
+ return;
+ }
+ DEBUG(ctx, 12, "Function call: eDBfree_session(ctx, '%s')", session->sessionkey);
+ eFree_values(ctx, session->sessvals);
+ free_nullsafe(session->sessionkey);
+ free_nullsafe(session);
+}