/* eurephiadb_session.c -- Functions for handling sessions from eurephia-auth * * GPLv2 - Copyright (C) 2008 David Sommerseth * * 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 #include #include #include #define EUREPHIA_FWINTF #include #include #include "eurephia_nullsafe.h" #include "eurephia_log.h" #include "eurephiadb_session.h" #include #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); // 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( !eDBsessionGetRandString(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; }