diff options
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | utils/CMakeLists.txt | 29 | ||||
-rw-r--r-- | utils/eurephia_init.c | 538 |
3 files changed, 570 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b635f1..a8a9e9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,8 @@ PROJECT(eurephia C) cmake_minimum_required(VERSION 2.6) +ADD_DEFINITIONS(-DEUREPHIAVERSION="0.9.4_beta") + OPTION(DEBUG "Add more verbose debug information" OFF) OPTION(SHOW_SECRETS "Show passwords as clear text in logs." OFF) OPTION(SQLITE3 "Build database driver for SQLite3" OFF) @@ -67,7 +69,7 @@ IF(PLUGIN) message(FATAL_ERROR "Missing openvpn-plugin.h ... Is the OpenVPN source code really located here? ${OPENVPN_SRC}") ENDIF(NOT EXISTS ${CHECK_INCL_FILE}) INCLUDE_DIRECTORIES(BEFORE ${OPENVPN_SRC} .) - SET(subdirs ${subdirs} plugin) + SET(subdirs ${subdirs} plugin utils) ENDIF(PLUGIN) INCLUDE(CheckIncludeFile) diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt new file mode 100644 index 0000000..bcaed05 --- /dev/null +++ b/utils/CMakeLists.txt @@ -0,0 +1,29 @@ +PROJECT(eurephia_init C) +cmake_minimum_required(VERSION 2.6) + +IF(EUREPHIADM) + SET(e_init_SRC + eurephia_init.c + benchmark.c + ../common/eurephia_values.c + ../common/eurephia_log.c + ../common/eurephia_getsym.c + ../common/eurephia_xml.c + ../common/passwd.c + ../common/sha512.c + ../common/randstr.c + ../database/eurephiadb.c + ../eurephiadm/get_console_input.c + ../eurephiadm/argparser.c + ../eurephiadm/client_context.c + ) + + ADD_DEFINITIONS(-DBENCHMARK -DINSTALL_PREFIX="${PREFIX}") + IF(FW_IPTABLES) + ADD_DEFINITIONS(-DFW_IPTABLES) + ENDIF(FW_IPTABLES) + + INCLUDE_DIRECTORIES(../common ../database ../eurephiadm) + ADD_EXECUTABLE(eurephia_init ${e_init_SRC}) + TARGET_LINK_LIBRARIES(eurephia_init dl crypto ${EXTRA_LIBS}) +ENDIF(EUREPHIADM) diff --git a/utils/eurephia_init.c b/utils/eurephia_init.c new file mode 100644 index 0000000..3d604e8 --- /dev/null +++ b/utils/eurephia_init.c @@ -0,0 +1,538 @@ +/* eurephia_init.c -- program which initialises the eurephia database. + * It will add a administrator account, setting + * a passoword for it and set other needed + * configuration settings. + * + * GPLv2 - Copyright (C) 2009 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 <getopt.h> +#include <libgen.h> +#include <assert.h> + +#ifdef HAVE_LIBXML2 +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xmlstring.h> +#endif + +#include <eurephia_nullsafe.h> +#include <eurephia_context.h> +#include <eurephiadb.h> +#include <eurephiadb_driver.h> +#include <eurephia_values.h> +#include <eurephia_xml.h> + +#define MODULE "eurephia_init" +#include <client_context.h> +#include <argparser.h> +#include <get_console_input.h> + +int benchmark(int *min, int *max, int thr_min, int thr_max); + +char *print_version(char *fprg) { + char *prg = basename(fprg); + + fprintf(stdout, "%s (v%s) - eurephia initialisation utility\n" + "Copyright (C) 2009 David Sommerseth <dazo@users.sourceforge.net>\n", + prg, EUREPHIAVERSION); + return prg; +} + +void print_help(char *fprg) { + print_version(fprg); + + printf("\n This utility is only supposed to be used when installing eurephia. The\n" + " purpose is to initialise the database eurephia will use, by setting up\n" + " some standard configuration values and create an administrator account\n\n"); + + printf(" Valid arguments:\n" + " -V | --version : Show version information\n" + " -h | --help : This help screen\n" + " -l | --log <filename> : Log file for debugging\n" + " -L | --log-level <log level> : Sets the log level\n" + " -N | --hash-threshold-min <ms> : Benchmarking parameter, see below. Default 95ms\n" + " -N | --hash-threshold-max <ms> : Benchmarking parameter, see below. Default 200ms\n" + " -D | --database-driver <path> : Full path to the database driver\n" + " -d | --database-args <args> : Required database arguments for the driver\n\n"); + + printf("* Benchmarking\n" + " During the initialisation this utility will benchmark the CPU power by doing\n" + " multiple SHA512 hash calculations. This is to determinate the optimal rounds\n" + " the password hashes should use on the current computer. To make it more difficult\n" + " to brute force passwords, eurephia implements dynamic password hash rounds, based\n" + " on a random number within in a given range. This benchmark will suggest an optimal\n" + " range. To do this, two limits are defined, the shortest time and the longest time\n" + " to be used for calculating a hash. The default values are 95ms and 200ms.\n" + "\n" + " If you want to modify those thresolds, you can do so with the --hash-threshold-min\n" + " and --hash-threshold-max options. By increasing these numbers, you will allow the\n" + " number of rounds to be increased.\n\n"); +} + +int eurephia_ConnectDB(eurephiaCTX *ctx, eurephiaVALUES *cfg) { + char *delims = " "; + char *cp = NULL; + const char *dbargv[MAX_ARGUMENTS]; + int dbargc = 0; + char *argstr = NULL; + + argstr = eGet_value(cfg, "database_params"); + if( (argstr == NULL) || (strlen(argstr) < 1) ) { + eurephia_log(ctx, LOG_FATAL, 0, "No database connection string given"); + return 0; + } + + // Split up argstr into separate arguments + cp = strdup(argstr); + assert(cp != NULL); + + dbargc = 0; + dbargv[dbargc] = strtok(cp, delims); + while( (dbargv[dbargc] != NULL) && (dbargc <= MAX_ARGUMENTS) ) { + dbargv[++dbargc] = strtok(NULL, delims); + } + + if( !eDBconnect(ctx, dbargc, dbargv) ) { + eurephia_log(ctx, LOG_PANIC, 0, "Could not connect to the database"); + eDBlink_close(ctx); + return 0; + } + free_nullsafe(cp); + + return 1; +} + +int setup_admin_account(eurephiaCTX *ctx) { + xmlDoc *xmldoc = NULL; + xmlNode *node = NULL, *node2 = NULL; + int uid = 0, i; + char uname[66], pwd1[66], pwd2[66]; + + printf("------------------------------------------------------------------------------\n"); + printf(" eurephia :: ADMINISTRATOR ACCOUNT\n"); + printf("------------------------------------------------------------------------------\n\n"); + printf("Checking database for user accounts ... "); + + xmldoc = eDBadminGetUserList(ctx, NULL); + node = eurephiaXML_getRoot(ctx, xmldoc, "userlist", 1); + if( node == NULL ) { + fprintf(stderr, "Could not retrieve valid data\n"); + xmlFreeDoc(xmldoc); + return 0; + } + + if( node->children != NULL ) { + printf("User accounts found, aborting. eurephia is already initialised\n"); + xmlFreeDoc(xmldoc); + return 0; + } + xmlFreeDoc(xmldoc); xmldoc = NULL; + printf("None found. Good!\n"); + + get_console_input(uname, 64, "Admin username: ", 0); + if( strlen_nullsafe(uname) < 4 ) { + fprintf(stderr, "Username is too short. Minimum 4 characters\n"); + return 0; + } + get_console_input(pwd1, 64, "Password: ", 1); + if( strlen_nullsafe(pwd1) < 5 ) { + fprintf(stderr, "Password is too short\n"); + return 0; + } + get_console_input(pwd2, 64, "Confirm password: ", 1); + if( strcmp(pwd1, pwd2) != 0 ) { + fprintf(stderr, "Passwords do not match\n"); + return 0; + } + memset(pwd2, 0, 66); + + eurephiaXML_CreateDoc(ctx, 1, "add_user", &xmldoc, &node); + node = xmlNewChild(node, NULL, (xmlChar *) "fieldMapping", NULL); + xmlNewProp(node, (xmlChar *) "table", (xmlChar *) "users"); + + xmlNewChild(node, NULL, (xmlChar *) "username", (xmlChar *) uname); + node2 = xmlNewChild(node, NULL, (xmlChar *) "password", (xmlChar *) pwd1); + xmlNewProp(node2, (xmlChar *) "pwhash", (xmlChar *) "none"); + + // Add the user + uid = eDBadminAddUser(ctx, xmldoc); + memset(pwd1, 0, 66); + + if( uid > 0 ) { + fprintf(stdout, "Admin user account registered successfully (user id %i)\n", uid); + } else { + fprintf(stderr, "Failed to register user\n"); + xmlFreeDoc(xmldoc); + return 0; + } + xmlFreeDoc(xmldoc); + + + // Grant all available access levels to the admin account + static char *grants[] = { "config", "useradmin", "certadmin", NULL }; + + printf("Granting access to user account:"); + + eurephiaXML_CreateDoc(ctx, 1, "edit_admin_access", &xmldoc, &node); + xmlNewProp(node, (xmlChar *) "mode", (xmlChar *) "grant"); + + node = xmlNewChild(node, NULL, (xmlChar *) "fieldMapping", NULL); + xmlNewProp(node, (xmlChar *) "table", (xmlChar *) "eurephia_adminaccess"); + + snprintf(uname, 64, "%i", uid); // borrow uname variable for uid int -> string + xmlNewChild(node, NULL, (xmlChar *) "uid", (xmlChar *) uname); + xmlNewChild(node, NULL, (xmlChar *) "interface", (xmlChar *) "C"); + node2 = xmlNewChild(node, NULL, (xmlChar *) "accesslevel", (xmlChar *)""); + + for( i = 0; grants[i] != NULL; i++ ) { + xmlNode *new_n = NULL; + + new_n = xmlNewChild(node, NULL, (xmlChar *) "accesslevel", (xmlChar *)grants[i]); + xmlReplaceNode(node2, new_n); + node2 = new_n; + printf(" %s", grants[i]); + if( !eDBadminEditAdminAccess(ctx, xmldoc) ) { + fprintf(stderr, "\n** ERROR: Could not grant %s access. Initialisation failed\n", + grants[i]); + xmlFreeDoc(xmldoc); + return 0; + } + } + xmlFreeDoc(xmldoc); + node = NULL; node2 = NULL; + printf("\n"); + + + // Activate the user account + printf("Activating the user account ... "); + eurephiaXML_CreateDoc(ctx, 1, "update_user", &xmldoc, &node); + xmlNewProp(node, (xmlChar *) "uid", (xmlChar *) uname); // uid should still be in uname as string + + // Add fieldMapping - to correctly map eurephia fields into the database fields + node2 = xmlNewChild(node, NULL, (xmlChar *) "fieldMapping", NULL); + xmlNewProp(node2, (xmlChar *) "table", (xmlChar *) "users"); + xmlNewChild(node2, NULL, (xmlChar *) "activated", (xmlChar *) "CURRENT_TIMESTAMP"); + + if( !eDBadminUpdateUser(ctx, uid, xmldoc) ) { + printf("FAILED\n"); + xmlFreeDoc(xmldoc); + return 0; + } + printf("Done"); + xmlFreeDoc(xmldoc); + + printf("\n==============================================================================\n\n"); + return 1; +} + +int setup_password_params(eurephiaCTX *ctx, const int hash_thr_min, const int hash_thr_max) { + int rounds_min = 0, rounds_max = 0; + char buffer[22], prompt[80], value[22]; + + memset(&buffer, 0, 22); + + printf("------------------------------------------------------------------------------\n"); + printf(" eurephia :: PASSWORD PARAMETERS\n"); + printf("------------------------------------------------------------------------------\n\n"); + + get_console_input(buffer, 3, "Salt length for password hashes [32] ", 0); + memset(&value, 0, 22); + snprintf(value, 20, "%i", (atoi_nullsafe(buffer) > 0 ? atoi_nullsafe(buffer) : 32)); + if( !eDBadminConfigSet(ctx, "passwordhash_salt_length", value) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + + printf("\n** Preparing for SHA512 performance benchmark.\n"); + printf("Aiming for minimum hashing calculation time: %ims\n", hash_thr_min); + printf("Aiming for maximum hashing calculation time: %ims\n", hash_thr_max); + if( !benchmark(&rounds_min, &rounds_max, hash_thr_min, hash_thr_max) ) { + fprintf(stderr, "Failed to meassure SHA512 hash performance\n"); + return 0; + } + printf("\n"); + snprintf(prompt, 78, "Minimum hashing rounds: [%i] ", rounds_min); + get_console_input(buffer, 20, prompt, 0); + memset(&value, 0, 22); + snprintf(value, 20, "%i", (atoi_nullsafe(buffer) > 1 ? atoi_nullsafe(buffer) : rounds_min)); + if( !eDBadminConfigSet(ctx, "passwordhash_rounds_min", value) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + + snprintf(prompt, 78, "Maximum hashing rounds: [%i] ", rounds_max); + get_console_input(buffer, 20, prompt, 0); + memset(&value, 0, 22); + snprintf(value, 20, "%i", (atoi_nullsafe(buffer) > 1 ? atoi_nullsafe(buffer) : rounds_max)); + if( !eDBadminConfigSet(ctx, "passwordhash_rounds_max", value) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + + printf("\n==============================================================================\n\n"); + + return 1; +} + + +int setup_attempt_limits(eurephiaCTX *ctx) { + char buffer[22], value[22]; + memset(&buffer, 0, 22); + + printf("------------------------------------------------------------------------------\n"); + printf(" eurephia :: ATTEMPTS LIMITS\n"); + printf("------------------------------------------------------------------------------\n\n"); + printf("These parameters here will decide when eurephia should block access, based on\n" + "how many registered failed attempts. Normally, you should be strict regarding\n" + "number of attempts on usernames, less strict on certificates and even less on\n" + "IP addresses. Remember that the user might connect via a proxy or a firewall\n" + "with NAT enabled.\n\n"); + + get_console_input(buffer, 4, "How many failed attempts will you allow per user name? [3]", 0); + memset(&value, 0, 22); + snprintf(value, 20, "%i", (atoi_nullsafe(buffer) > 0 ? atoi_nullsafe(buffer) : 3)); + if( !eDBadminConfigSet(ctx, "allow_username_attempts", value) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + + get_console_input(buffer, 4, "How many failed attempts will you allow per certificate? [5]", 0); + memset(&value, 0, 22); + snprintf(value, 20, "%i", (atoi_nullsafe(buffer) > 0 ? atoi_nullsafe(buffer) : 5)); + if( !eDBadminConfigSet(ctx, "allow_cert_attempts", value) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + + get_console_input(buffer, 4, "How many failed attempts will you allow per IP address? [10]", 0); + memset(&value, 0, 22); + snprintf(value, 20, "%i", (atoi_nullsafe(buffer) > 0 ? atoi_nullsafe(buffer) : 10)); + if( !eDBadminConfigSet(ctx, "allow_ipaddr_attempts", value) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + printf("\n==============================================================================\n\n"); + return 1; +} + +int setup_session_params(eurephiaCTX *ctx) { + char buffer[20], value[20]; + memset(&buffer, 0, 20); + + printf("------------------------------------------------------------------------------\n"); + printf(" eurephia :: SESSION PARAMETERS\n"); + printf("------------------------------------------------------------------------------\n\n"); + + get_console_input(buffer, 5, + "eurephiadmin: How many minutes before a session is auto logged out: [10]", 0); + memset(&value, 0, 22); + snprintf(value, 20, "%i", (atoi_nullsafe(buffer) > 0 ? atoi_nullsafe(buffer) : 10)); + if( !eDBadminConfigSet(ctx, "eurephiadmin_autologout", value) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + printf("\n==============================================================================\n\n"); + + return 1; +} + +#ifdef FW_IPTABLES +int setup_iptables(eurephiaCTX *ctx) { + char buffer[1026], value[1026], prompt[180]; + memset(&buffer, 0, 1026); + memset(&value, 0, 1026); + + printf("------------------------------------------------------------------------------\n"); + printf(" eurephia :: FIREWALL SUPPORT - iptables\n"); + printf("------------------------------------------------------------------------------\n\n"); + + get_console_input(buffer, 8, "Do you want to load the iptables module? [No]", 0); + if( (strlen_nullsafe(buffer) > 0) && ((buffer[0] != 'y') && (buffer[0] != 'Y')) ) { + printf("\niptables firewall support is not configured\n"); + goto ipt_done; + } + + snprintf(value, 1024, "%s/efw-iptables.so", INSTALL_PREFIX); + snprintf(prompt, 178, "\nFull path to the efw-iptables.so library:\n[%s]", value); + get_console_input(buffer, 1024, prompt, 0); + if( !eDBadminConfigSet(ctx, "firewall_interface", (strlen_nullsafe(buffer) > 1 ? buffer : value)) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + + snprintf(value, 1024, "/sbin/iptables"); + snprintf(prompt, 78, "\nFull path to the iptables command: [%s]", value); + get_console_input(buffer, 1024, prompt, 0); + if( !eDBadminConfigSet(ctx, "firewall_command", (strlen_nullsafe(buffer) > 1 ? buffer : value)) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + + snprintf(value, 1024, "vpn_users"); + snprintf(prompt, 78, "\nWhich iptables chain should eurephia use? [%s]", value); + get_console_input(buffer, 1024, prompt, 0); + if( !eDBadminConfigSet(ctx, "firewall_destination", (strlen_nullsafe(buffer) > 1 ? buffer : value)) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + + get_console_input(buffer, 8, "\nDo you want you eurephia to block blacklisted IP addresses\n" + "in iptables too? [No]", 0); + if( (strlen_nullsafe(buffer) < 1) || (buffer[0] == 'y') || (buffer[0] == 'Y') ) { + snprintf(value, 1024, "vpn_blacklist"); + snprintf(prompt, 178, "\nWhich iptables chain should eurephia use for" + "\nblacklisted IP addresses? [%s]", value); + get_console_input(buffer, 1024, prompt, 0); + if( !eDBadminConfigSet(ctx, "firewall_blacklist_destination", + (strlen_nullsafe(buffer) > 1 ? buffer : value)) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + + memset(&value, 0, 1024); + snprintf(prompt, 178, "\nWhich iptables chain should eurephia send blacklisted" + "\nIP addresses too (iptables '-j' argument) ? [DROP]"); + get_console_input(buffer, 1024, prompt, 0); + if( (strlen_nullsafe(buffer) > 1) + && !eDBadminConfigSet(ctx, "firewall_blacklist_send_to", buffer) ) { + fprintf(stderr, "Failed to set configuration settings in database\n"); + return 0; + } + } + ipt_done: + printf("\n==============================================================================\n\n"); + + return 1; +} +#endif + +int main(int argc, char **argv) { + // Default hash calculation thresholds for benchmarking + int hash_thr_min = 95; // 95ms + int hash_thr_max = 200; // 200ms + int argi = 0; + eurephiaVALUES *cfg = NULL; + eurephiaCTX *ctx = NULL; + + static e_options argopts[] = { + {"--version", "-V", 0}, + {"--help", "-h", 0}, + {"--log", "-l", 1}, + {"--log-level", "-L", 1}, + {"--hash-threshold-min", "-N", 1}, + {"--hash-threshold-max", "-X", 1}, + {"--database-driver", "-D", 1}, + {"--database-args", "-d", 1}, + {NULL, NULL, 0} + }; + + + cfg = eCreate_value_space(NULL, 30); + for( argi = 1; argi < argc; argi++ ) { + switch( eurephia_getopt(&argi, argc, argv, argopts) ) { + case 'V': + print_version(argv[0]); + return 0; + case 'h': + print_help(argv[0]); + return 0; + + case 'l': + eAdd_value(NULL, cfg, "log", optargs[0]); + break; + + case 'L': + eAdd_value(NULL, cfg, "log_level", optargs[0]); + break; + + case 'D': + eAdd_value(NULL, cfg, "database_driver", optargs[0]); + break; + + case 'd': + eAdd_value(NULL, cfg, "database_params", optargs[0]); + break; + + case 'N': + hash_thr_min = atoi_nullsafe(optargs[0]); + break; + + case 'X': + hash_thr_max = atoi_nullsafe(optargs[0]); + break; + + default: + return 1; + } + } + + if( eGet_value(cfg, "database_driver") == NULL ) { + fprintf(stderr, "Missing required database driver (--database-driver)\n"); + return 2; + + } + + if( eGet_value(cfg, "database_params") == NULL ) { + fprintf(stderr, "Missing required database driver parameteres (--database-args)\n"); + return 2; + + } + + ctx = eurephiaCTX_init(NULL, 0, cfg); + if( ctx == NULL ) { + fprintf(stderr, "Failed to initialise an eurephia context.\n"); + return 3; + } + + if( !eurephia_ConnectDB(ctx, cfg) ) { + fprintf(stderr, "Failed to access the database.\n"); + return 4; + } + + if( !setup_password_params(ctx, hash_thr_min, hash_thr_max) ) { + return 11; + } + + if( !setup_admin_account(ctx) ) { + return 12; + } + + if( !setup_session_params(ctx) ) { + return 13; + } + + if( !setup_attempt_limits(ctx) ) { + return 14; + } + +#ifdef FW_IPTABLES + if( !setup_iptables(ctx) ){ + return 15; + } +#endif + + printf("\neurephia is now configured. For further changes, please use the eurephiadm utility.\n\n"); + eFree_values(ctx, cfg); + eurephiaCTX_destroy(ctx); + return 0; +} |