/* client_session.c -- Handles eurephia session in admin clients * * GPLv2 only - Copyright (C) 2008 - 2015 * 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. * */ /** * @file client_session.c * @author David Sommerseth * @date 2008-12-01 * * @brief Functions for working on eurephiaSESSIONs outside the openvpn plug-in * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "client_config.h" /** * Get a file name to a session file. This file can be found in either EUREPHIADM_SESSION * environment variable, in the users ~/.eurephia or the directory defined by the EUREPHIA_DIR * environment variable. * * @return Returns a full path to the session file on success, otherwise NULL. */ char *get_session_file() { char *fname = NULL; fname = get_config_filename("EUREPHIADM_SESSION","/session"); if( fname == NULL ) { // If even default ~/.eurephia dir failed, create one in /tmp snprintf(fname, 1024, "/tmp/.eurepia-%i.sess", getuid()); return fname; } return fname; } /** * Reads the session key and does a quick validation of it. * * @param ctx eurephiaCTX * * @return Returns a string (char *) containing the session key on success, otherwise NULL. */ char *read_session_file(eurephiaCTX *ctx) { char *sesskey = NULL, *fname = NULL; FILE *sfp = NULL; fname = get_session_file(); assert(fname != NULL); if( (sfp = fopen(fname, "r")) == NULL ) { return NULL; } sesskey = (char *) malloc_nullsafe(ctx, 256); assert( sesskey != NULL ); if( (fgets(sesskey, 254, sfp) == NULL) || (strlen_nullsafe(sesskey) < 64) ) { eurephia_log(ctx, LOG_PANIC, 0, "Could not read session file (%s). Session value too short", fname); return NULL; } fclose(sfp); return sesskey; } /** * Writes a session key to disk, to keep session logged in over a longer time. * * @param ctx eurephiaCTX * @param sess eurephiaSESSION with session info for the current logged in user. * * @return Returns 1 on success, otherwise 0. */ int write_session_file(eurephiaCTX *ctx, eurephiaSESSION *sess) { struct stat fchk; char *fname = NULL; FILE *sfp = NULL; assert((ctx != NULL) && (sess != NULL) && (sess->sessionkey != NULL)); fname = get_session_file(); assert(fname != NULL); if( stat(fname, &fchk) != -1 ) { // session file exists, do not update it return 1; } if( (sfp = fopen(fname, "w")) == NULL ) { eurephia_log(ctx, LOG_PANIC, 0, "Could not create session file (%s). Operation aborted.", fname); return 0; } fprintf(sfp, "%s", sess->sessionkey); fclose(sfp); return 1; } /** * Removes the session file, used when logging out or the user is automatically logged out. * * @param ctx eurephiaCTX */ void remove_session_file(eurephiaCTX *ctx) { const char *fname = NULL; fname = get_session_file(); assert(fname != NULL); if( (access(fname, F_OK) != -1) && (unlink(fname) == -1) ) { eurephia_log(ctx, LOG_ERROR, 0, "Could not remove session file (%s). Following operations might fail", fname); }; } /** * Create a eurephiaSESSION. If session key is given, it will try to load that session back. * If no session key is given, it will create a brand new user session. * * @param ctx eurephiaCTX * @param sesskey session key, used for loading existing sessions back. * * @return Returns a eurephiaSESSION pointer to a session, either new or old. On failure, NULL is returned. */ eurephiaSESSION *create_session(eurephiaCTX *ctx, const char *sesskey) { eurephiaSESSION *new_sess = NULL; int loop = 0, uniqchk = 0; char *randdata = NULL; unsigned char sha_res[SHA512_HASH_SIZE+2]; SHA512Context sha; new_sess = (eurephiaSESSION *) malloc_nullsafe(ctx, sizeof(eurephiaSESSION) + 2); assert(new_sess != NULL); if( sesskey == NULL ) { // Get data for a unique session key randdata = (char *) malloc_nullsafe(ctx, 514); assert(randdata != NULL); do { char *ptr = NULL; int i = 0; if( !eurephia_randstring(ctx, randdata, 512) ) { eurephia_log(ctx, LOG_FATAL, 0, "Could not generate enough random data for session"); free_nullsafe(ctx, randdata); free_nullsafe(ctx, new_sess); return NULL; } memset(&sha, 0, sizeof(SHA512Context)); memset(&sha_res, 0, SHA512_HASH_SIZE+2); free_nullsafe(ctx, new_sess->sessionkey); new_sess->sessionkey = (char *) malloc_nullsafe(ctx, (SHA512_HASH_SIZE*2) + 3); assert(new_sess->sessionkey != NULL); SHA512Init(&sha); SHA512Update(&sha, randdata, 512); SHA512Final(&sha, sha_res); ptr = new_sess->sessionkey; for( i = 0; i < SHA512_HASH_SIZE; i++ ) { sprintf(ptr, "%02x", sha_res[i]); ptr += 2; } memset(&sha, 0, sizeof(SHA512Context)); memset(&sha_res, 0, sizeof(sha_res)); loop++; uniqchk = eDBcheck_sessionkey_uniqueness(ctx, new_sess->sessionkey); memset(randdata, 0, 514); } while( (uniqchk == 0) && (loop < 11) ); free_nullsafe(ctx, randdata); if( uniqchk == 0 ) { eurephia_log(ctx, LOG_FATAL, 0, "Did not manage to create a unique session key after %i attempts." " Aborting.", loop-1); free_nullsafe(ctx, new_sess->sessionkey); free_nullsafe(ctx, new_sess); return NULL; } } else { new_sess->sessionkey = strdup(sesskey); new_sess->sessvals = eDBload_sessiondata(ctx, new_sess->sessionkey); } // Return new session return new_sess; }