diff options
author | David Sommerseth <dazo@users.sourceforge.net> | 2008-10-15 00:39:53 +0200 |
---|---|---|
committer | David Sommerseth <dazo@users.sourceforge.net> | 2008-10-15 00:39:53 +0200 |
commit | 0ea1a3e2e6a10300388e01ac89504abe3624ae56 (patch) | |
tree | fff59c70d4db431c2114e89d0819af8921aff463 /plugin/eurephiadb_session.c | |
parent | b65b0802ead5e863ca8cb41fff77528735a1466c (diff) | |
download | eurephia-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.c | 352 |
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); +} |