summaryrefslogtreecommitdiffstats
path: root/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'plugin')
-rw-r--r--plugin/CMakeLists.txt43
-rw-r--r--plugin/eurephia-auth.c179
-rw-r--r--plugin/eurephia.c527
-rw-r--r--plugin/eurephia.h36
-rw-r--r--plugin/eurephia_struct.h98
-rw-r--r--plugin/eurephiadb_session.c352
-rw-r--r--plugin/eurephiadb_session.h44
-rw-r--r--plugin/firewall/eurephiafw.c288
-rw-r--r--plugin/firewall/eurephiafw.h34
-rw-r--r--plugin/firewall/eurephiafw_helpers.c97
-rw-r--r--plugin/firewall/eurephiafw_helpers.h36
-rw-r--r--plugin/firewall/eurephiafw_intf.h30
-rw-r--r--plugin/firewall/iptables/CMakeLists.txt12
-rw-r--r--plugin/firewall/iptables/efw_iptables.c234
14 files changed, 2010 insertions, 0 deletions
diff --git a/plugin/CMakeLists.txt b/plugin/CMakeLists.txt
new file mode 100644
index 0000000..d2b922f
--- /dev/null
+++ b/plugin/CMakeLists.txt
@@ -0,0 +1,43 @@
+PROJECT(eurephia-auth C)
+cmake_minimum_required(VERSION 2.6)
+SET(eurephia_auth_SRC
+ ../common/certinfo.c
+ eurephia-auth.c
+ eurephia.c
+ ../database/eurephiadb.c
+ eurephiadb_session.c
+ firewall/eurephiafw.c
+ firewall/eurephiafw_helpers.c
+ ../common/eurephia_getsym.c
+ ../common/eurephia_log.c
+ ../common/eurephia_values.c
+ ../common/passwd.c
+ ../common/sha512.c
+)
+SET(subdirs "")
+IF(FW_IPTABLES)
+ message(STATUS "Will build iptables firewall module")
+ SET(subdirs firewall/iptables)
+ENDIF(FW_IPTABLES)
+
+CHECK_LIBRARY_EXISTS(rt sem_wait "" HAVE_RT_SEM_WAIT)
+CHECK_LIBRARY_EXISTS(rt sem_post "" HAVE_RT_SEM_POST)
+CHECK_LIBRARY_EXISTS(rt mq_open "" HAVE_RT_MQ_OPEN)
+CHECK_LIBRARY_EXISTS(rt mq_close "" HAVE_RT_MQ_CLOSE)
+CHECK_LIBRARY_EXISTS(rt mq_unlink "" HAVE_RT_MQ_UNLINK)
+CHECK_LIBRARY_EXISTS(rt mq_send "" HAVE_RT_MQ_SEND)
+CHECK_LIBRARY_EXISTS(rt mq_receive "" HAVE_RT_MQ_RECEIVE)
+CHECK_LIBRARY_EXISTS(rt mq_getattr "" HAVE_RT_MQ_GETATTR)
+IF(NOT HAVE_RT_SEM_WAIT OR NOT HAVE_RT_SEM_POST)
+ message(FATAL_ERROR "Missing proper pthread semaphore support")
+ENDIF(NOT HAVE_RT_SEM_WAIT OR NOT HAVE_RT_SEM_POST)
+IF(NOT HAVE_RT_MQ_OPEN OR NOT HAVE_RT_MQ_CLOSE OR NOT HAVE_RT_MQ_UNLINK OR NOT HAVE_RT_MQ_SEND OR NOT HAVE_RT_MQ_RECEIVE OR NOT HAVE_RT_MQ_GETATTR)
+ message(FATAL_ERROR "Missing proper pthread message queue support")
+ENDIF(NOT HAVE_RT_MQ_OPEN OR NOT HAVE_RT_MQ_CLOSE OR NOT HAVE_RT_MQ_UNLINK OR NOT HAVE_RT_MQ_SEND OR NOT HAVE_RT_MQ_RECEIVE OR NOT HAVE_RT_MQ_GETATTR)
+
+INCLUDE_DIRECTORIES(../common ../database ./firewall .)
+ADD_LIBRARY(eurephia-auth MODULE ${eurephia_auth_SRC})
+TARGET_LINK_LIBRARIES(eurephia-auth dl pthread rt crypto)
+SET_TARGET_PROPERTIES(eurephia-auth PROPERTIES OUTPUT_NAME eurephia-auth PREFIX "")
+
+SUBDIRS(${subdirs})
diff --git a/plugin/eurephia-auth.c b/plugin/eurephia-auth.c
new file mode 100644
index 0000000..98658c3
--- /dev/null
+++ b/plugin/eurephia-auth.c
@@ -0,0 +1,179 @@
+/* eurephia-auth.c -- Main OpenVPN plugin functions. The API level between OpenVPN and eurephia-auth
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sqlite3.h>
+
+#include "openvpn-plugin.h"
+#include <eurephiadb.h>
+#include <eurephia.h>
+
+
+#ifdef ENABLE_DEBUG // To avoid compiler warnings when ENABLE_DEBUG is not defined
+static const char *plugin_type_name(const int type)
+{
+ switch (type)
+ {
+ case OPENVPN_PLUGIN_UP:
+ return "PLUGIN_UP";
+ case OPENVPN_PLUGIN_DOWN:
+ return "PLUGIN_DOWN";
+ case OPENVPN_PLUGIN_ROUTE_UP:
+ return "PLUGIN_ROUTE_UP";
+ case OPENVPN_PLUGIN_IPCHANGE:
+ return "PLUGIN_IPCHANGE";
+ case OPENVPN_PLUGIN_TLS_VERIFY:
+ return "PLUGIN_TLS_VERIFY";
+ case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
+ return "PLUGIN_AUTH_USER_PASS_VERIFY";
+ case OPENVPN_PLUGIN_CLIENT_CONNECT:
+ return "PLUGIN_CLIENT_CONNECT";
+ case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
+ return "PLUGIN_CLIENT_DISCONNECT";
+ case OPENVPN_PLUGIN_LEARN_ADDRESS:
+ return "PLUGIN_LEARN_ADDRESS";
+ default:
+ return "(UNKNOWN PLUGIN CODE)";
+ }
+}
+
+static void dump_env(FILE *f, const char *prefix, const char *envp[]) {
+ int i;
+ for (i = 0; envp[i]; i++) {
+#ifdef SHOW_SECRETS
+ fprintf(f, "%s%s\n", prefix, envp[i]);
+#else
+ fprintf(f, "%s%s\n", prefix ,
+ (strncmp(envp[i], "password=", 9) == 0) ? "password=xxxxxxx" : envp[i]);
+#endif // SHOW_SECRETS
+ }
+}
+#endif // ENABLE_DEBUG
+
+
+// daemonize if "daemon" environment variable is set.
+// preserves stderr access after being daemonized, but
+// only if "daemon_log_direct" enviroment variable is set.
+//
+static void daemonize(const char *envp[])
+{
+ const char *daemon_string = get_env(NULL, 0, envp, "daemon");
+ if( daemon_string && daemon_string[0] == '1' ) {
+ const char *log_redirect = get_env(NULL, 0, envp, "daemon_log_redirect");
+ int fd = -1;
+ if( log_redirect && log_redirect[0] == '1' ) {
+ fd = dup (2);
+ }
+ if( daemon(0, 0) < 0 ) {
+ fprintf(stderr, "eurephia-auth: daemonization failed\n");
+ } else if( fd >= 3 ) {
+ dup2(fd, 2);
+ close(fd);
+ }
+ }
+}
+
+
+OPENVPN_EXPORT openvpn_plugin_handle_t openvpn_plugin_open_v1(unsigned int *type_mask,
+ const char *argv[], const char *envp[])
+{
+ eurephiaCTX *context = NULL;
+
+#ifdef MEMWATCH
+ mwStatistics(3);
+#warning MEMWATCH enabled
+#endif
+
+ // Define what will trigger eurephia
+ *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
+ | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY)
+ | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT)
+ | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
+ | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS);
+
+ // Setup a eurephia context
+ context = eurephiaInit(argv);
+ // Daemonize if requested
+ daemonize(envp);
+
+ return (openvpn_plugin_handle_t) context;
+}
+
+
+OPENVPN_EXPORT int openvpn_plugin_func_v1(openvpn_plugin_handle_t handle,
+ const int type,
+ const char *argv[], const char *envp[])
+{
+ eurephiaCTX *ctx = (eurephiaCTX *) handle;
+ int result = 0;
+
+
+ if( (ctx == NULL) || (ctx->dbc == NULL) || (ctx->dbc->dbhandle == NULL) ) {
+ return OPENVPN_PLUGIN_FUNC_ERROR;
+ }
+
+ DEBUG(ctx, 10, "openvpn_plugin_func_v1(ctx, %s, ...)", plugin_type_name(type));
+
+#ifdef ENABLE_DEBUG
+ if( ctx->loglevel >= 30 ) {
+ dump_env(ctx->log, "ENV: ", envp);
+ dump_env(ctx->log, "ARG: ", argv);
+ }
+#endif
+
+ switch( type ) {
+ case OPENVPN_PLUGIN_TLS_VERIFY:
+ result = eurephia_tlsverify(ctx, envp, argv[1]);
+ break;
+
+ case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
+ result = eurephia_userauth(ctx, envp);
+ break;
+
+ case OPENVPN_PLUGIN_CLIENT_CONNECT:
+ result = eurephia_connect(ctx, envp);
+ break;
+
+ case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
+ result = eurephia_disconnect(ctx, envp);
+ break;
+
+ case OPENVPN_PLUGIN_LEARN_ADDRESS:
+ result = eurephia_learn_address(ctx, argv[1], argv[2], envp);
+ break;
+
+ default:
+ eurephia_log(ctx, LOG_FATAL, 0, "Unknown OPENVPN_PLUGIN type: %i", type);
+ break;
+ }
+ return (result == 1 ? OPENVPN_PLUGIN_FUNC_SUCCESS : OPENVPN_PLUGIN_FUNC_ERROR);
+}
+
+
+OPENVPN_EXPORT void openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
+{
+ eurephiaCTX *ctx = (eurephiaCTX *) handle;
+
+ eurephiaShutdown(ctx);
+}
+
diff --git a/plugin/eurephia.c b/plugin/eurephia.c
new file mode 100644
index 0000000..7454b1f
--- /dev/null
+++ b/plugin/eurephia.c
@@ -0,0 +1,527 @@
+/* eurephia.c -- Main functions for the eurephia authentication module
+ *
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <eurephiadb.h>
+#include <eurephiadb_driver.h>
+#include <eurephiafw.h>
+#include <eurephia_nullsafe.h>
+#include <eurephia_values.h>
+#include <certinfo.h>
+
+#define MAX_ARGUMENTS 64
+
+
+// Get value of a environment variable
+const char *get_env(eurephiaCTX *ctx, int logmasking, const char *envp[], const char *fmt, ... )
+{
+ if (envp) {
+ va_list ap;
+ char key[384];
+ int keylen = 0;
+ int i;
+
+ // Build up the key we are looking for
+ memset(&key, 0, 384);
+ va_start(ap, fmt);
+ vsnprintf(key, 382, fmt, ap);
+
+ // Find the key
+ keylen = strlen (key);
+ for (i = 0; envp[i]; ++i) {
+ if (!strncmp (envp[i], key, keylen)) {
+ const char *cp = envp[i] + keylen;
+ if (*cp == '=') {
+#ifdef ENABLE_DEBUG
+ int do_mask = 0;
+#ifndef SHOW_SECRETS
+ do_mask = logmasking;
+#endif
+ if( ctx != NULL ) {
+ DEBUG(ctx, 30, "Function call: get_env(envp, '%s') == '%s'",
+ key, (do_mask == 0 ? cp + 1 : "xxxxxxxxxxxxxx"));
+ }
+#endif
+
+ return cp + 1;
+ }
+ }
+ }
+ if( ctx != NULL ) {
+ DEBUG(ctx, 15, "Function call: get_env(envp, '%s') -- environment variable not found",
+ key);
+ }
+ va_end(ap);
+ }
+ return NULL;
+}
+
+
+// arguments: logfile loglevel eDB_driver [eurephiaDB arguments]
+// 1 2 3 4.....
+eurephiaCTX *eurephiaInit(const char **argv)
+{
+ static struct option eurephia_opts[] = {
+ {"log-destination", required_argument, 0, 'l'},
+ {"log-level", required_argument, 0, 'L'},
+ {"database-interface", required_argument, 0, 'i'},
+ {0, 0, 0 ,0}
+ };
+ int argc = 0, error = 0, loglvl = 0, dbargc = 0;
+ const char *dbargv[MAX_ARGUMENTS];
+ const char *fwintf = NULL, *logfile = NULL, *dbi = NULL;
+ eurephiaCTX *ctx = NULL;
+
+ //
+ // Parse input arguments
+ //
+
+ // Count arguments
+ for( argc = 0; argv[argc] != NULL; argc++ ) {}
+
+ while(1) {
+ int opt_idx = 0;
+ int c = 0;
+
+ c = getopt_long(argc, (char **)argv, "l:L:i:", eurephia_opts, &opt_idx);
+ if( c == -1 ) {
+ break;
+ }
+
+ switch( c ) {
+ case 'l':
+ logfile = optarg;
+ break;
+
+ case 'L':
+ loglvl = atoi_nullsafe(optarg);
+ break;
+
+ case 'i':
+ dbi = optarg;
+ break;
+
+ default:
+ fprintf(stderr, "Error parsing eurephia-auth arguments.\n");
+ return NULL;
+ break;
+ }
+ }
+
+ // Put the rest of the arguments into an own array which will be the db module arguments
+ if( optind < argc ) {
+ // copy arguments, but make sure we do not exceed our limit
+ while( (optind < argc) && (dbargc < MAX_ARGUMENTS) ) {
+ dbargv[dbargc] = argv[optind++];
+ dbargc++;
+ dbargv[dbargc] = NULL;
+ }
+ }
+ // End of argument parsing
+
+ // Prepare a context area for eurephia-auth
+ ctx = (eurephiaCTX *) malloc(sizeof(eurephiaCTX)+2);
+ memset(ctx, 0, sizeof(eurephiaCTX)+2);
+
+ // Open a log file
+ if( logfile != NULL ) {
+ if( strcmp(logfile, "openvpn:") == 0 ) { // Let openvpn do the logging
+ ctx->log = stderr;
+ } else if( strcmp(logfile, "none:") == 0 ) { // Do not perform any logging
+ ctx->log = NULL;
+ } else { // if no hit on these ones,open a file with given name
+ ctx->log = fopen(logfile, "aw");
+ if( ctx->log == NULL ) {
+ fprintf(stderr, "Could not open eurephia log file: %s\n", argv[1]);
+ return NULL;
+ }
+ }
+ } else {
+ // If no logging is given ... log to openvpn:
+ ctx->log = stderr;
+ }
+
+ // Set log verbosity
+ ctx->loglevel = loglvl;
+
+ // Load the database driver
+ if( (error == 0) && eDBlink_init(ctx, dbi) ) {
+ // Connect to the database
+ if( !eDBconnect(ctx, dbargc, dbargv) ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not connect to the database");
+ error = 1;
+ eDBlink_close(ctx);
+ }
+ } else {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not load the database driver");
+ error = 1;
+ }
+
+ if( error > 0 ) {
+ if( ctx->log != NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "eurephia-auth is not available");
+ fclose(ctx->log);
+ }
+ free_nullsafe(ctx);
+ return NULL;
+ }
+
+ // Check if firewall functionality is enabled, load module if given
+ fwintf = eGet_value(ctx->dbc->config, "firewall_interface");
+ if( fwintf != NULL ) {
+ if( eFW_load(ctx, fwintf) ) {
+ eurephia_log(ctx, LOG_INFO, 0, "Loaded firewall interface: %s", fwintf);
+ eFW_StartFirewall(ctx);
+ } else {
+ eurephia_log(ctx, LOG_FATAL, 0, "Loading of firewall interface failed (%s)", fwintf);
+ ctx->eurephia_fw_intf = NULL;
+ }
+ } else {
+ ctx->eurephia_fw_intf = NULL;
+ }
+
+ eurephia_log(ctx, LOG_INFO, 1, "eurehia-auth is initialised");
+ return ctx;
+}
+
+
+int eurephiaShutdown(eurephiaCTX *ctx)
+{
+ if( ctx == NULL ) {
+ return 0;
+ }
+
+ if( ctx->eurephia_fw_intf != NULL ) {
+ if( ctx->fwcfg != NULL ) {
+ eFW_StopFirewall(ctx);
+ }
+ eFW_unload(ctx);
+ }
+
+ if( (ctx->dbc != NULL) && (ctx->dbc->dbhandle != NULL) ) {
+ eDBdisconnect(ctx);
+ }
+
+ if( ctx->eurephia_driver != NULL ) {
+ eDBlink_close(ctx);
+ }
+
+ if( ctx->log != NULL ) {
+ fflush(ctx->log);
+
+ // Do not close log file if we're on stdout or stderr
+ if( (ctx->log != stderr) && (ctx->log != stdout) ) {
+ eurephia_log(ctx, LOG_INFO, 2, "Closing log file");
+ fclose(ctx->log);
+ }
+
+ ctx->log = NULL;
+ ctx->loglevel = 0;
+ }
+ free_nullsafe(ctx);
+ return 1;
+}
+
+
+int eurephia_tlsverify(eurephiaCTX *ctx, const char **env, const char *depth)
+{
+ int result = 0;
+ char *ipaddr;
+ char *tls_digest, *tls_id;
+ certinfo *ci = NULL;
+
+ DEBUG(ctx, 10, "** Function call: eurephia_tlsverify(...)");
+
+ // Check if IP address is blacklisted
+ ipaddr = (char *) get_env(ctx, 0, env, "untrusted_ip");
+ if( eDBblacklist_check(ctx, attempt_IPADDR, ipaddr) == 1 ) {
+ eDBregister_attempt(ctx, attempt_IPADDR, ATTEMPT_REGISTER, ipaddr);
+ return 0;
+ }
+
+ // Check if certificate digest is blacklisted
+ tls_digest = (char *) get_env(ctx, 0, env, "tls_digest_%s", depth);
+ if( eDBblacklist_check(ctx, attempt_CERTIFICATE, tls_digest) == 1 ) {
+ eDBregister_attempt(ctx, attempt_IPADDR, ATTEMPT_REGISTER, ipaddr);
+ eDBregister_attempt(ctx, attempt_CERTIFICATE, ATTEMPT_REGISTER, tls_digest);
+ return 0;
+ }
+
+ // Check if certificate is registered and allowed
+ tls_id = (char *) get_env(ctx, 0, env, "tls_id_%s", depth);
+ ci = parse_tlsid(tls_id);
+ result = eDBauth_TLS(ctx, ci->org, ci->common_name, ci->email, tls_digest, depth);
+ if( result < 1 ) {
+ eDBregister_attempt(ctx, attempt_IPADDR, ATTEMPT_REGISTER, ipaddr);
+ eDBregister_attempt(ctx, attempt_CERTIFICATE, ATTEMPT_REGISTER, tls_digest);
+ }
+
+ if( result > 0 ) {
+ // Certificate is okay, result contains the certificate ID
+ eurephia_log(ctx, LOG_INFO, (depth == 0 ? 0 : 1),
+ "Found certid %i for user: %s/%s/%s",
+ result, ci->org, ci->common_name, ci->email);
+
+ // Reset attempt counter for certificate if it is okey
+ eDBregister_attempt(ctx, attempt_CERTIFICATE, ATTEMPT_RESET, tls_digest);
+ } else {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "Unknown certificate for: %s/%s/%s (depth %s, digest: %s)",
+ ci->org, ci->common_name, ci->email, depth, tls_digest);
+ }
+ free_certinfo(ci);
+ DEBUG(ctx, 10, "** Function result: eurephia_tlsverify(...) == %i", result > 0);
+
+ return (result > 0);
+}
+
+
+int eurephia_userauth(eurephiaCTX *ctx, const char **env)
+{
+ int result = 0, certid = 0;
+ char *ipaddr;
+ char *tls_digest, *tls_id, *username, *passwd;
+ certinfo *ci = NULL;
+
+ DEBUG(ctx, 10, "** Function call: eurephia_userauth(...)");
+
+
+ // Check if IP address is blacklisted
+ ipaddr = (char *) get_env(ctx, 0, env, "untrusted_ip");
+ if( eDBblacklist_check(ctx, attempt_IPADDR, ipaddr) == 1 ) {
+ eDBregister_attempt(ctx, attempt_IPADDR, ATTEMPT_REGISTER, ipaddr);
+ return 0;
+ }
+
+ // Check if certificate digest is blacklisted
+ tls_digest = (char *) get_env(ctx, 0, env, "tls_digest_0");
+ if( eDBblacklist_check(ctx, attempt_CERTIFICATE, tls_digest) == 1 ) {
+ eDBregister_attempt(ctx, attempt_IPADDR, ATTEMPT_REGISTER, ipaddr);
+ eDBregister_attempt(ctx, attempt_CERTIFICATE, ATTEMPT_REGISTER, tls_digest);
+ return 0;
+ }
+
+ // Check if username is blacklisted
+ username = (char *) get_env(ctx, 0, env, "username");
+ if( eDBblacklist_check(ctx, attempt_USERNAME, username) == 1 ) {
+ eDBregister_attempt(ctx, attempt_IPADDR, ATTEMPT_REGISTER, ipaddr);
+ eDBregister_attempt(ctx, attempt_CERTIFICATE, ATTEMPT_REGISTER, tls_digest);
+ eDBregister_attempt(ctx, attempt_USERNAME, ATTEMPT_REGISTER, username);
+ return 0;
+ }
+
+ // Get certificate ID
+ tls_id = (char *) get_env(ctx, 0, env, "tls_id_0");
+ ci = parse_tlsid(tls_id);
+ certid = eDBauth_TLS(ctx, ci->org, ci->common_name, ci->email, tls_digest, "0");
+ if( certid < 1 ) {
+ eDBregister_attempt(ctx, attempt_IPADDR, ATTEMPT_REGISTER, ipaddr);
+ eDBregister_attempt(ctx, attempt_CERTIFICATE, ATTEMPT_REGISTER, tls_digest);
+ eDBregister_attempt(ctx, attempt_USERNAME, ATTEMPT_REGISTER, username);
+ free_certinfo(ci);
+ return 0;
+ }
+ free_certinfo(ci);
+
+ // Do username/password/certificate authentication
+ passwd = (char *)get_env(ctx, 1, env, "password");
+ result = eDBauth_user(ctx, certid, username, passwd);
+ if( result < 1 ) {
+ eDBregister_attempt(ctx, attempt_IPADDR, ATTEMPT_REGISTER, ipaddr);
+ eDBregister_attempt(ctx, attempt_CERTIFICATE, ATTEMPT_REGISTER, tls_digest);
+ eDBregister_attempt(ctx, attempt_USERNAME, ATTEMPT_REGISTER, username);
+ }
+
+
+ if( result > 0 ) {
+ // If we have a valid result, reset all attempt counters.
+ eDBregister_attempt(ctx, attempt_IPADDR, ATTEMPT_RESET, ipaddr);
+ eDBregister_attempt(ctx, attempt_CERTIFICATE, ATTEMPT_RESET, tls_digest);
+ eDBregister_attempt(ctx, attempt_USERNAME, ATTEMPT_RESET, username);
+
+ eurephia_log(ctx, LOG_INFO, 0, "User '%s' authenticated", username);
+ }
+ DEBUG(ctx, 10, "** Function result: eurephia_userauth(...) = %i", (result>0));
+ return (result > 0);
+}
+
+
+int eurephia_connect(eurephiaCTX *ctx, const char **env) {
+ eurephiaSESSION *session = NULL;
+ const char *digest, *cname, *uname, *vpnipaddr, *vpnipmask, *remipaddr, *remport, *proto, *tlsid;
+ int certid = 0, uid = 0, ret = 0;
+ certinfo *ci = NULL;
+
+ DEBUG(ctx, 10, "** Function call: eurephia_connect(...)");
+
+ // Fetch needed info
+ digest = get_env(ctx, 0, env, "tls_digest_0");
+ tlsid = get_env(ctx, 0, env, "tls_id_0");
+ cname = get_env(ctx, 0, env, "common_name");
+ uname = get_env(ctx, 0, env, "username");
+ vpnipaddr = get_env(ctx, 0, env, "ifconfig_pool_remote_ip");
+ vpnipmask = get_env(ctx, 0, env, "ifconfig_pool_netmask");
+ remipaddr = get_env(ctx, 0, env, "trusted_ip");
+ remport = get_env(ctx, 0, env, "trusted_port");
+ proto = get_env(ctx, 0, env, "proto_1");
+
+ // Get a session ticket
+ session = eDBopen_session_seed(ctx, digest, cname, uname, vpnipaddr, vpnipmask, remipaddr, remport);
+ if( session == NULL ) {
+ return 0;
+ }
+
+ // Get certificate info
+ ci = parse_tlsid(tlsid);
+ if( ci == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 1, "Could not parse the TLS ID string");
+ eDBfree_session(ctx, session);
+ return 0;
+ }
+ certid = eDBauth_TLS(ctx, ci->org, ci->common_name, ci->email, digest, "0");
+ uid = eDBget_uid(ctx, certid, uname);
+ free_certinfo(ci);
+
+ // Register the session login
+ ret = eDBregister_login(ctx, session, certid, uid, proto, remipaddr, remport, vpnipaddr, vpnipmask);
+ eDBfree_session(ctx, session);
+
+ DEBUG(ctx, 10, "** Function result: eurephia_connect(...) = %i", ret);
+ return ret;
+}
+
+
+int eurephia_disconnect(eurephiaCTX *ctx, const char **env) {
+ eurephiaSESSION *session = NULL;
+ const char *digest, *cname, *uname, *vpnipaddr, *vpnipmask, *remipaddr, *remport;
+ const char *bytes_sent, *bytes_rec, *duration;
+ int ret = 0;
+
+ DEBUG(ctx, 10, "** Function call: eurephia_disconnect(...)");
+
+ // Fetch needed info
+ digest = get_env(ctx, 0, env, "tls_digest_0");
+ cname = get_env(ctx, 0, env, "common_name");
+ uname = get_env(ctx, 0, env, "username");
+ vpnipaddr = get_env(ctx, 0, env, "ifconfig_pool_remote_ip");
+ vpnipmask = get_env(ctx, 0, env, "ifconfig_pool_netmask");
+ remipaddr = get_env(ctx, 0, env, "trusted_ip");
+ remport = get_env(ctx, 0, env, "trusted_port");
+ bytes_sent= get_env(ctx, 0, env, "bytes_sent");
+ bytes_rec = get_env(ctx, 0, env, "bytes_received");
+ duration = get_env(ctx, 0, env, "time_duration");
+
+ // Get a session ticket
+ session = eDBopen_session_seed(ctx, digest, cname, uname, vpnipaddr, vpnipmask, remipaddr, remport);
+ if( session == NULL ) {
+ return 0;
+ }
+
+ // 2. eDBregister_logout(ctx, session, env[bytes_sent], env[bytes_received])
+ ret = eDBregister_logout(ctx, session, bytes_sent, bytes_rec, duration);
+ eDBfree_session(ctx, session);
+
+ DEBUG(ctx, 10, "** Function result: eurephia_disconnect(...) = %i", ret);
+ return ret;
+}
+
+
+int eurephia_learn_address(eurephiaCTX *ctx, const char *mode, const char *macaddr, const char **env) {
+ eurephiaSESSION *session = NULL;
+ const char *digest, *cname, *uname, *vpnipaddr, *vpnipmask, *remipaddr, *remport;
+ char *fwprofile = NULL, *fwdest = NULL;
+ int ret = 0, fw_enabled = 0;
+
+ DEBUG(ctx, 10, "** Function call: eurephia_learn_address(ctx, '%s', '%s', ...)",
+ mode, macaddr);
+
+ // Get firewall information
+ fw_enabled = (eGet_value(ctx->dbc->config, "firewall_interface") != NULL);
+ fwdest = eGet_value(ctx->dbc->config, "firewall_destination");
+ if( fw_enabled && (fwdest == NULL) ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "No firewall destination defined in the config.");
+ }
+
+ if( strncmp(mode, "add", 3) == 0 ) {
+ // Fetch needed info
+ digest = get_env(ctx, 0, env, "tls_digest_0");
+ cname = get_env(ctx, 0, env, "common_name");
+ uname = get_env(ctx, 0, env, "username");
+ vpnipaddr = get_env(ctx, 0, env, "ifconfig_pool_remote_ip");
+ vpnipmask = get_env(ctx, 0, env, "ifconfig_pool_netmask");
+ remipaddr = get_env(ctx, 0, env, "trusted_ip");
+ remport = get_env(ctx, 0, env, "trusted_port");
+
+ // Get a session ticket
+ session = eDBopen_session_seed(ctx, digest, cname, uname, vpnipaddr, vpnipmask,
+ remipaddr, remport);
+ if( session == NULL ) {
+ ret = 0;
+ goto exit;
+ }
+
+ // Update openvpn_lastlog with the active MAC address, and save it as a session variable
+ ret = eDBregister_vpnmacaddr(ctx, session, macaddr);
+
+ if( (fw_enabled) && (fwdest != NULL) ) {
+ // 1. Lookup firewall profile for user: eDBget_firewall_profile(ctx, session)
+ fwprofile = eDBget_firewall_profile(ctx, session);
+ // 2. Update firewall with eurephia_firewall(ctx, FWRULE_ADD, profileid)
+ if( fwprofile != NULL ) {
+ eFW_UpdateFirewall(ctx, FWRULE_ADD, macaddr, fwdest, fwprofile);
+ free_nullsafe(fwprofile);
+ }
+ }
+ eDBfree_session(ctx, session);
+
+ } else if( strncmp(mode, "delete", 6) == 0 ) {
+
+ // Load the session, based on MAC address
+ session = eDBopen_session_macaddr(ctx, macaddr);
+ if( session == NULL ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "Could not find any session connected to this MAC address: %s",
+ macaddr);
+ ret = 0;
+ goto exit;
+ }
+
+ if( (fw_enabled) && (fwdest != NULL) ) {
+ fwprofile = eDBget_firewall_profile(ctx, session);
+ if( fwprofile != NULL ) {
+ // 1. Update firewall with eurephia_firewall(ctx, FWRULE_DELETE, macaddr)
+ eFW_UpdateFirewall(ctx, FWRULE_DELETE, macaddr, fwdest, fwprofile);
+ free_nullsafe(fwprofile);
+ }
+ }
+ ret = eDBdestroy_session(ctx, session);
+ }
+
+ exit:
+ DEBUG(ctx, 10, "** Function result: eurephia_learn_address(ctx, '%s', '%s', ...) = %i",
+ mode, macaddr, ret);
+
+ return ret;
+}
+
diff --git a/plugin/eurephia.h b/plugin/eurephia.h
new file mode 100644
index 0000000..5e2dfb9
--- /dev/null
+++ b/plugin/eurephia.h
@@ -0,0 +1,36 @@
+/* eurephia.h -- Main API for the eurephia authentication module
+ *
+ * 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.
+ *
+ */
+
+#ifndef EUREPHIA_H_
+#define EUREPHIA_H_
+
+#include <stdarg.h>
+
+const char *get_env(eurephiaCTX *ctx, const int mask, const char **envp, const char *fmt, ...);
+eurephiaCTX *eurephiaInit(const char **argv);
+int eurephiaShutdown(eurephiaCTX *ctx);
+
+int eurephia_tlsverify(eurephiaCTX *ctx, const char **argv, const char *depth);
+int eurephia_userauth(eurephiaCTX *ctx, const char **env);
+int eurephia_connect(eurephiaCTX *ctx, const char **env);
+int eurephia_disconnect(eurephiaCTX *ctx, const char **env);
+int eurephia_learn_address(eurephiaCTX *ctx, const char *mode, const char *macaddr, const char **env);
+
+#endif /* !EUREPHIA_H_ */
diff --git a/plugin/eurephia_struct.h b/plugin/eurephia_struct.h
new file mode 100644
index 0000000..cdb8403
--- /dev/null
+++ b/plugin/eurephia_struct.h
@@ -0,0 +1,98 @@
+/* eurephia_struct.h -- Structures and defines used by the eurephia module
+ *
+ * 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.
+ *
+*/
+
+
+/*** Structures used by the eurphia module ***/
+
+#include <mqueue.h>
+#include <semaphore.h>
+
+#ifndef EUREPHIASTRUCT_H_
+#define EUREPHIASTRUCT_H_
+
+#define SESSION_NEW 1
+#define SESSION_EXISTING 2
+#define SESSION_REGISTERED 3
+#define SESSION_LOGGEDOUT 4
+
+typedef struct __eurephiaVALUES {
+ unsigned int evgid;
+ unsigned int evid;
+ char *key;
+ char *val;
+ struct __eurephiaVALUES *next;
+} eurephiaVALUES;
+
+
+//
+// Struct which contains session unique data
+//
+typedef struct {
+ char *sessionkey;
+ int sessionstatus;
+ eurephiaVALUES *sessvals;
+} eurephiaSESSION;
+
+
+//
+// Struct containing connection to the database we are using
+//
+typedef struct {
+ void *dbhandle;
+ char *dbname;
+ eurephiaVALUES *config;
+} eDBconn;
+
+
+
+//
+// structs used by the firewall interface
+//
+typedef struct {
+ mqd_t msgq;
+ sem_t *semp_worker;
+ sem_t *semp_master;
+ char *fw_command;
+ void *ctx;
+} efw_threaddata;
+
+typedef struct {
+ efw_threaddata thrdata;
+ pid_t fwproc_pid;
+} eurephiaFWINTF;
+
+
+//
+// main structure for the eurephia module context
+// - the same context structure is used for all OpenVPN sessions
+//
+typedef struct {
+ void *eurephia_driver;
+ void *eurephia_fw_intf;
+ eDBconn *dbc;
+ eurephiaFWINTF *fwcfg;
+ FILE *log;
+ int loglevel;
+ int fatal_error;
+} eurephiaCTX;
+
+
+
+#endif
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);
+}
diff --git a/plugin/eurephiadb_session.h b/plugin/eurephiadb_session.h
new file mode 100644
index 0000000..47f0049
--- /dev/null
+++ b/plugin/eurephiadb_session.h
@@ -0,0 +1,44 @@
+/* eurephia_session.h -- Internal API to provide storing of variables connected to a session
+ *
+ * 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.
+ *
+ */
+
+#ifndef EUREPHIADB_SESSION_H_
+# define EUREPHIADB_SESSION_H_
+
+#define SESSVAL_NEW 10
+#define SESSVAL_UPDATE 11
+#define SESSVAL_DELETE 12
+
+eurephiaVALUES *eDBfind_session_value(eurephiaCTX *ctx, eurephiaSESSION *seskey, const char *key);
+
+int eDBset_session_value(eurephiaCTX *ctx, eurephiaSESSION *sesskey, const char *key, const char *val);
+
+char *eDBget_session_value(eurephiaCTX *ctx, eurephiaSESSION *sesskey, const char *key);
+
+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 *eDBopen_session_macaddr(eurephiaCTX *ctx, const char *macaddr);
+
+#define eDBfree_session(c, s) { eDBfree_session_func(c, s); s = NULL;}
+void eDBfree_session_func(eurephiaCTX *ctx, eurephiaSESSION *sk);
+
+#endif /* !EUREPHIADB_SESSION_H_ */
diff --git a/plugin/firewall/eurephiafw.c b/plugin/firewall/eurephiafw.c
new file mode 100644
index 0000000..9fed02e
--- /dev/null
+++ b/plugin/firewall/eurephiafw.c
@@ -0,0 +1,288 @@
+/* eurephiafw.c -- Firewall interface loader for the eurephia module
+ *
+ * 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 <dlfcn.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "eurephia_struct.h"
+#include "eurephia_log.h"
+#include "eurephiafw.h"
+#include "eurephiafw_intf.h"
+#include "eurephia_getsym.h"
+#include "eurephia_nullsafe.h"
+#include "eurephia_values.h"
+#include "eurephiafw_helpers.h"
+
+int eFW_unload(eurephiaCTX *ctx) {
+ if( ctx == NULL ) {
+ return 1;
+ }
+
+ if( ctx->eurephia_fw_intf != NULL ) {
+ eurephia_log(ctx, LOG_INFO, 3, "Unloading eurephia firewall interface");
+ dlclose(ctx->eurephia_fw_intf);
+ ctx->eurephia_fw_intf = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+
+int eFW_load(eurephiaCTX *ctx, const char *intf) {
+ if( (intf == NULL) || (strlen(intf) == 0) ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "No valid eurephia firewall interface indicated");
+ return 0;
+ }
+ eurephia_log(ctx, LOG_INFO, 2, "Loading eurephia firewall interface: %s", intf);
+
+ ctx->eurephia_fw_intf = dlopen(intf, RTLD_NOW);
+ if( ctx->eurephia_fw_intf == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not open the eurephia firewall interface (%s)", intf);
+ eurephia_log(ctx, LOG_FATAL, 1, "dlopen error: %s", dlerror());
+ return 0;
+ }
+
+ // Mandatory functions
+ eFWinterfaceVersion = eGetSym(ctx, ctx->eurephia_fw_intf, "eFWinterfaceVersion");
+ eFWinterfaceAPIversion = eGetSym(ctx, ctx->eurephia_fw_intf, "eFWinterfaceAPIversion");
+
+ eurephia_log(ctx, LOG_INFO, 1, "Firewall interface loaded: %s (API version %i)",
+ eFWinterfaceVersion(), eFWinterfaceAPIversion());
+
+ // Configure firewall interface functions
+ switch( eFWinterfaceAPIversion() ) {
+ default:
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "eurephia Firewall interface API is newer than what the running eurephia version is "
+ "familiar with. Please consider to upgrade eurphia to take advantage of newer "
+ "features in the eurephiaDB driver.");
+
+ case 1:
+ eFW_RunFirewall = eGetSym(ctx, ctx->eurephia_fw_intf, "eFW_RunFirewall");
+ break;
+
+ }
+
+ if( ctx->fatal_error > 0 ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "eurephia Firewall interface is not correctly initialised. "
+ "eurephia authentication will not be available");
+ eFW_unload(ctx);
+ return 0;
+ }
+ return 1;
+}
+
+void eFW_StartFirewall(eurephiaCTX *ctx) {
+ struct mq_attr mqattr;
+ eurephiaCTX *shadowctx = NULL;
+ char buf[1026], *fwdest = NULL;
+ unsigned int prio;
+
+ ctx->fwcfg = (eurephiaFWINTF *) malloc(sizeof(eurephiaFWINTF)+2);
+ memset(ctx->fwcfg, 0, sizeof(eurephiaFWINTF)+2);
+
+ // Create a fake eurephia context, just for logging
+ shadowctx = (eurephiaCTX *) malloc(sizeof(eurephiaCTX)+2);
+ memset(shadowctx, 0, sizeof(eurephiaCTX)+2);
+ shadowctx->loglevel = ctx->loglevel;
+ shadowctx->log = ctx->log;
+ (*ctx->fwcfg).thrdata.ctx = shadowctx;
+
+ (*ctx->fwcfg).thrdata.fw_command = strdup_nullsafe(eGet_value(ctx->dbc->config, "firewall_command"));
+ if( (*ctx->fwcfg).thrdata.fw_command == NULL) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not find firewall_command in configuration. "
+ "Firewall updates will not be available.");
+ return;
+ } else {
+ eurephia_log(ctx, LOG_INFO, 1, "Using %s to update the firewall rules.",
+ (*ctx->fwcfg).thrdata.fw_command );
+ }
+
+ fwdest = eGet_value(ctx->dbc->config, "firewall_destination");
+ if( fwdest == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not find firewall_destination in configuration. "
+ "Firewall updates will not be available.");
+ return;
+ } else {
+ eurephia_log(ctx, LOG_INFO, 1, "Using '%s' as firewall rule for VPN accesses", fwdest);
+ }
+
+ eurephia_log(ctx, LOG_INFO, 3, "Starting eurephia firewall interface");
+
+ // Setup semaphores we need
+ if( efwSetupSemaphores(ctx, &(*ctx->fwcfg).thrdata) == 0 ) {
+ free_nullsafe(ctx->fwcfg->thrdata.fw_command);
+ return;
+ };
+
+ // Setup a message queue
+ if( efwSetupMessageQueue(ctx, &(*ctx->fwcfg).thrdata) == 0 ) {
+ free_nullsafe(ctx->fwcfg);
+ return;
+ }
+
+ // Make sure that these variables are not available in the child
+ madvise(ctx, sizeof(eurephiaCTX), MADV_DONTFORK);
+
+ // Start a new process (should run with root permissions) - which will do the firewall work
+ if( (ctx->fwcfg->fwproc_pid = fork()) < 0 ) {
+ eurephia_log(ctx, LOG_PANIC, 0,
+ "Could not fork out a child process for the firewall interface (%s)",
+ strerror(errno));
+ return;
+ }
+ switch( ctx->fwcfg->fwproc_pid ) {
+ case 0: // Child process
+ eFW_RunFirewall(&(*ctx->fwcfg).thrdata);
+ exit(-1); // If our child process exits abnormally.
+
+ default: // Main process
+ eurephia_log(ctx, LOG_INFO, 2, "Firewall updater process started (pid %i)",
+ ctx->fwcfg->fwproc_pid);
+ }
+
+ // Flush the message queue for old messages
+ if( mq_getattr((*ctx->fwcfg).thrdata.msgq, &mqattr) == 0 ) {
+ long i;
+
+ memset(&buf, 0, 1026);
+ if( mqattr.mq_curmsgs > 0 ) {
+ for( i = 0; i < mqattr.mq_curmsgs; i++ ) {
+ if( mq_receive((*ctx->fwcfg).thrdata.msgq, &buf[0], 1024, &prio) == -1 ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Error while emptying messages from queue: %s",
+ strerror(errno));
+ } else {
+ DEBUG(ctx, 28, "Removed message on queue: %s", buf);
+ }
+ }
+ }
+ eurephia_log(ctx, LOG_INFO, 3, "Message queue for firewall updates is ready");
+ } else {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not retrieve message queue attributes (%s)",
+ strerror(errno));
+ }
+
+ // Indicate for the FW module that we are ready
+ sem_post(ctx->fwcfg->thrdata.semp_master);
+
+ // Waiting for the FW module to get ready
+ DEBUG(ctx, 28, "eFW master is ready, waiting for the eFW worker to get ready");
+ sem_wait(ctx->fwcfg->thrdata.semp_worker);
+ eurephia_log(ctx, LOG_INFO, 2, "eFW interface initialised.");
+
+ // Initialise the chain
+ memset(&buf, 0, 1026);
+ snprintf(buf, 1024, "I %s", fwdest);
+ if( mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1) == -1 ) {
+ eurephia_log(ctx, LOG_ERROR, 0, "Could not request firewall initialisation of the %s chain: %s",
+ fwdest, strerror(errno));
+ };
+}
+
+void eFW_StopFirewall(eurephiaCTX *ctx) {
+ char buf[520], *fwdest = NULL;
+ int childret = -1;
+
+ if( ctx->fwcfg == NULL ) {
+ return;
+ }
+
+ eurephia_log(ctx, LOG_INFO, 2, "Stopping eurephia firewall interface");
+
+ // Flush the firewall chain before shutting down, to make sure
+ // we don't unintentionally some accesses open
+ fwdest = eGet_value(ctx->dbc->config, "firewall_destination");
+ if( fwdest != NULL ) {
+ memset(&buf, 0, 520);
+ snprintf(buf, 512, "F %s", fwdest);
+ if( mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1) == -1 ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not request firewall flushing of the %s chain: %s",
+ fwdest, strerror(errno));
+ };
+ } else {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "firewall_destination not set in config. Will not flush "
+ "firewall before shutting down the firewall interface.");
+ }
+
+
+ // Send shutdown message to the firewall module process
+ memset(&buf, 0, 520);
+ snprintf(buf, 512, "FWSHUTDOWN%c", 0);
+ if( mq_send((*ctx->fwcfg).thrdata.msgq, buf, 11, 1) == -1 ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not initiate shutdown on eFW module: %s", strerror(errno));
+ kill(ctx->fwcfg->fwproc_pid, SIGABRT);
+ }
+
+ // Wait for the firewall module process to finish
+ if( waitpid(ctx->fwcfg->fwproc_pid, &childret, 0) != ctx->fwcfg->fwproc_pid ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Failed to wait for eFW module process to quit: %s",
+ strerror(errno));
+ kill(ctx->fwcfg->fwproc_pid, SIGABRT);
+ }
+
+ free_nullsafe((*ctx->fwcfg).thrdata.fw_command);
+ free_nullsafe(ctx->fwcfg);
+ eurephia_log(ctx, LOG_INFO, 2, "eurephia firewall interface is stopped");
+}
+
+
+int eFW_UpdateFirewall(eurephiaCTX *ctx, int mode,
+ const char *macaddr, const char *fwdest, const char *fwprofile) {
+ char buf[1026];
+
+ if( (*ctx->fwcfg).thrdata.fw_command == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Function call: eFW_UpdateFirewall() -- "
+ "firewall_command is not configured. Firewall rules was not updated.");
+ return 0;
+ }
+
+ memset(&buf, 0, 1026);
+ switch( mode ) {
+ case FWRULE_ADD:
+ eurephia_log(ctx, LOG_INFO, 3, "Function call: eFW_UpdateFirewall(ctx, %s, '%s', '%s', '%s')",
+ "ADD", macaddr, fwdest, fwprofile);
+ snprintf(buf, 1024, "A %s %s %s", macaddr, fwdest, fwprofile);
+ mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1);
+ return 1;
+
+ case FWRULE_DELETE:
+ eurephia_log(ctx, LOG_INFO, 3, "Function call: eFW_UpdateFirewall(ctx, %s, '%s', '%s', '%s')",
+ "DELETE", macaddr, fwdest, fwprofile);
+ snprintf(buf, 1024, "D %s %s %s", macaddr, fwdest, fwprofile);
+ mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1);
+ return 1;
+
+ default:
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Function call: eFW_UpdateFirewall(ctx, %s, '%s') - UNKNOWN MODE", "(unknown)",
+ macaddr);
+ return 0;
+ }
+}
diff --git a/plugin/firewall/eurephiafw.h b/plugin/firewall/eurephiafw.h
new file mode 100644
index 0000000..0c82b30
--- /dev/null
+++ b/plugin/firewall/eurephiafw.h
@@ -0,0 +1,34 @@
+/* eurephiafw.h -- Firewall interface loader for the eurephia module
+ *
+ * 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.
+ *
+ */
+
+#ifndef EUREPHIAFW_H_
+#define EUREPHIAFW_H_
+
+#define FWRULE_ADD 0x101
+#define FWRULE_DELETE 0x102
+
+int eFW_load(eurephiaCTX *ctx, const char *intf);
+int eFW_unload(eurephiaCTX *ctx);
+
+void eFW_StartFirewall(eurephiaCTX *ctx);
+void eFW_StopFirewall(eurephiaCTX *ctx);
+int eFW_UpdateFirewall(eurephiaCTX *ctx, int mode, const char *macaddr, const char *fwdest, const char *fwprofile);
+
+#endif /* !EUREPHIAFW_H_ */
diff --git a/plugin/firewall/eurephiafw_helpers.c b/plugin/firewall/eurephiafw_helpers.c
new file mode 100644
index 0000000..ceb6d25
--- /dev/null
+++ b/plugin/firewall/eurephiafw_helpers.c
@@ -0,0 +1,97 @@
+/* eurephiafw_helpers.c -- Helper functions, shared between main module and
+ * firewall module. Setting up Posix MQ and semaphores
+ *
+ * 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 <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <mqueue.h>
+
+#include "eurephia_struct.h"
+#include "eurephia_log.h"
+#include "eurephiafw.h"
+#include "eurephiafw_helpers.h"
+
+
+int efwSetupSemaphores(eurephiaCTX *ctx, efw_threaddata *cfg) {
+ // Initialise the main process' semaphore
+ cfg->semp_master = sem_open(SEMPH_MASTER, O_CREAT, 0666, 0);
+ if( cfg->semp_master == SEM_FAILED ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not setup semaphore for eFW master: %s", strerror(errno));
+ return 0;
+ }
+
+ // Initialise the worker process' semaphore
+ cfg->semp_worker = sem_open(SEMPH_WORKER, O_CREAT, 0666, 0);
+ if( cfg->semp_worker == SEM_FAILED ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not setup semaphore for eFW worker: %s", strerror(errno));
+ return 0;
+ }
+ return 1;
+}
+
+int efwRemoveSemaphores(eurephiaCTX *ctx, efw_threaddata *cfg) {
+ if( sem_close(cfg->semp_worker) != 0 ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "eFW: Could not destroy semaphore for worker: %s", strerror(errno));
+ }
+ sem_unlink(SEMPH_WORKER);
+
+ if( sem_close(cfg->semp_master) != 0 ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "eFW: Could not destroy semaphore for master: %s", strerror(errno));
+ }
+ sem_unlink(SEMPH_MASTER);
+ return 1;
+}
+
+int efwSetupMessageQueue(eurephiaCTX *ctx, efw_threaddata *cfg) {
+ struct mq_attr mqattr;
+
+ // Prepare a POSIX Message Queue
+ mqattr.mq_maxmsg = 10;
+ mqattr.mq_msgsize = EFW_MSG_SIZE;
+ mqattr.mq_flags = 0;
+ cfg->msgq = mq_open(MQUEUE_NAME, O_RDWR | O_CREAT, 0600, &mqattr);
+ if( cfg->msgq < 0 ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not open message queue: %s", strerror(errno));
+ return 0;
+ }
+ return 1;
+}
+
+int efwRemoveMessageQueue(eurephiaCTX *ctx, efw_threaddata *cfg) {
+ // Close and remove the message queue used
+ if( mq_close((*cfg).msgq) != 0 ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "Could not do close the message queue used for eFW: %s",
+ strerror(errno));
+ }
+
+ if( mq_unlink(MQUEUE_NAME) != 0 ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "Could not do close the message queue used for eFW: %s",
+ strerror(errno));
+ }
+ return 1;
+}
+
diff --git a/plugin/firewall/eurephiafw_helpers.h b/plugin/firewall/eurephiafw_helpers.h
new file mode 100644
index 0000000..9c21a2f
--- /dev/null
+++ b/plugin/firewall/eurephiafw_helpers.h
@@ -0,0 +1,36 @@
+/* eurephiafw_helpers.h -- Helper functions, shared between main module and
+ * firewall module. Setting up Posix MQ and semaphores
+ *
+ * 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.
+ *
+ */
+
+#ifndef EUREPHIAFW_HELPERS_H_
+#define EUREPHIAFW_HELPERS_H_
+
+#define EFW_MSG_SIZE 1024
+#define MQUEUE_NAME "/eurephiaFW"
+#define SEMPH_MASTER "eurephiafw_master"
+#define SEMPH_WORKER "eurephiafw_worker"
+
+int efwSetupSemaphores(eurephiaCTX *, efw_threaddata *);
+int efwRemoveSemaphores(eurephiaCTX *, efw_threaddata *);
+
+int efwSetupMessageQueue(eurephiaCTX *, efw_threaddata *);
+int efwRemoveMessageQueue(eurephiaCTX *, efw_threaddata *);
+
+#endif /* !EUREPHIAFW_HELPERS_H_ */
diff --git a/plugin/firewall/eurephiafw_intf.h b/plugin/firewall/eurephiafw_intf.h
new file mode 100644
index 0000000..0f18cc2
--- /dev/null
+++ b/plugin/firewall/eurephiafw_intf.h
@@ -0,0 +1,30 @@
+/* eurephiafw_intf.h --
+ *
+ * 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.
+ *
+ */
+
+#ifndef EUREPHIAFW_INTF_H_
+#define EUREPHIAFW_INTF_H_
+
+// Mandatory functions for all FW interfaces
+const char *(*eFWinterfaceVersion) (void);
+int (*eFWinterfaceAPIversion) (void);
+
+void (*eFW_RunFirewall) (void *);
+
+#endif /* !EUREPHIAFW_INTF_H_ */
diff --git a/plugin/firewall/iptables/CMakeLists.txt b/plugin/firewall/iptables/CMakeLists.txt
new file mode 100644
index 0000000..0f77a1b
--- /dev/null
+++ b/plugin/firewall/iptables/CMakeLists.txt
@@ -0,0 +1,12 @@
+PROJECT(eurephiafw-iptables C)
+cmake_minimum_required(VERSION 2.6)
+SET(efw_ipt_SRC
+ efw_iptables.c
+ ../eurephiafw_helpers.c
+ ../../../common/eurephia_log.c
+)
+
+INCLUDE_DIRECTORIES(BEFORE ../..)
+ADD_LIBRARY(efw_iptables MODULE ${efw_ipt_SRC})
+TARGET_LINK_LIBRARIES(efw_iptables pthread rt gcc_s)
+SET_TARGET_PROPERTIES(efw_iptables PROPERTIES PREFIX "")
diff --git a/plugin/firewall/iptables/efw_iptables.c b/plugin/firewall/iptables/efw_iptables.c
new file mode 100644
index 0000000..9e0aaa4
--- /dev/null
+++ b/plugin/firewall/iptables/efw_iptables.c
@@ -0,0 +1,234 @@
+/* efw_iptables.c -- iptables implementation - updates Linux iptables
+ *
+ * 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 <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <eurephia_nullsafe.h>
+#include <eurephia_log.h>
+#include <eurephia_struct.h>
+#include <eurephiafw_helpers.h>
+
+#define INTERFACEVER "1.0"
+#define INTERFACEAPIVER 1
+
+
+const char *eFWinterfaceVersion() {
+ return "eFW-iptables (v"INTERFACEVER") David Sommerseth 2008 (C) GPLv2";
+}
+
+int eFWinterfaceAPIversion() {
+ return INTERFACEAPIVER;
+}
+
+
+int process_input(eurephiaCTX *ctx, const char *fwcmd, const char *msg);
+int call_iptables(eurephiaCTX *ctx, const char *fwcmd, char **ipt_args);
+
+void eFW_RunFirewall(void *fwargs) {
+ efw_threaddata *cfg = (efw_threaddata *) fwargs;
+ eurephiaCTX *ctx = (eurephiaCTX *) cfg->ctx;
+ int quit = 0;
+ unsigned int prio;
+ char buf[EFW_MSG_SIZE+2];
+
+ DEBUG(ctx, 28, "eFW_RunFirewall: Waiting for eFW master to get ready");
+ sem_wait(cfg->semp_master);
+ DEBUG(ctx, 28, "eFW_RunFirewall: Telling eFW master that the worker process is ready");
+ sem_post(cfg->semp_worker);
+
+ if( cfg->fw_command == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "eFW_RunFirewall: firewall_command is not configured. "
+ "iptables will not be updated.");
+ exit(3);
+ }
+
+ // Main loop ... grab messages of the messague queue until shutdown command is sent, or a failure happens
+ while( quit == 0 ) {
+ memset(buf, 0, EFW_MSG_SIZE+2);
+ if( mq_receive(cfg->msgq, &buf[0], EFW_MSG_SIZE, &prio) == -1 ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "eFW_RunFirewall: Error while reading messages from queue: %s",
+ strerror(errno));
+ exit(2);
+ }
+ quit = (strncmp(buf, "FWSHUTDOWN", 10) == 0 );
+ if( !quit ) {
+ int res = 0;
+
+ DEBUG(ctx, 20, "eFW_RunFirewall: Received '%s'", buf);
+
+ res = process_input(ctx, cfg->fw_command, buf);
+ if( ! res ) {
+ quit = 1;
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "eFW_RunFirewall: Failed updating iptables");
+ }
+ }
+ }
+
+ efwRemoveSemaphores(ctx, fwargs);
+ efwRemoveMessageQueue(ctx, fwargs);
+ exit(0);
+}
+
+
+int process_input(eurephiaCTX *ctx, const char *fwcmd, const char *input) {
+ char mode[3], *macaddr = NULL, *destchain = NULL, *jump = NULL;
+ char *msg = NULL, *orig_msg = NULL;
+ char *iptables_args[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+ int ret = 0;
+
+ orig_msg = strdup_nullsafe(input);
+ msg = orig_msg;
+ DEBUG(ctx, 36, "eFW_RunFirewall::process_input(ctx, '%s')", msg);
+
+ //
+ // Simple parsing of the input string
+ //
+ mode[0] = '-';
+ mode[1] = *msg;
+ mode[2] = 0;
+ msg += 2;
+
+ iptables_args[0] = (char *)fwcmd;
+
+ switch( mode[1] ) {
+ case 'A':
+ case 'D':
+ iptables_args[1] = mode;
+ macaddr = msg; // start of string for macaddr
+
+ // Search for end of macaddr and NULL terminate it
+ destchain = macaddr+1;
+ while( (*destchain != 0x20) || (*destchain == 0) ) {
+ destchain++;
+ }
+ if( *destchain == 0 ) {
+ return 0;
+ }
+ *destchain = 0; // end of string for macaddr
+ destchain++; // start of string for destchain
+ // Search for end of destchain and NULL terminate it
+ jump = destchain+1;
+ while( (*jump != 0x20) || (*jump == 0) ) {
+ jump++;
+ }
+ *jump = 0; // end of string for destchain
+ jump++; // start of string for jump
+
+ // Prepare iptables arguments
+ iptables_args[2] = destchain;
+ iptables_args[3] = "-m\0";
+ iptables_args[4] = "mac\0";
+ iptables_args[5] = "--mac-source\0";
+ iptables_args[6] = macaddr;
+ iptables_args[7] = "-m\0";
+ iptables_args[8] = "state\0";
+ iptables_args[9] = "--state\0";
+ iptables_args[10] = "NEW\0";
+ iptables_args[11] = "-j\0";
+ iptables_args[12] = jump;
+ iptables_args[13] = NULL;
+
+ eurephia_log(ctx, LOG_INFO, 3, "eFW_RunFirewall - updating iptables rules "
+ "==> mode: %s macaddr: '%s' destchain: '%s' jump: '%s'",
+ (mode[1] == 'A' ? "ADD":"DELETE"), macaddr, destchain, jump);
+ ret = call_iptables(ctx, fwcmd, iptables_args);
+ break;
+
+ case 'F':
+ iptables_args[1] = mode;
+ destchain = msg;
+ iptables_args[2] = destchain;
+ iptables_args[3] = NULL;
+ eurephia_log(ctx, LOG_INFO, 3, "eFW_RunFirewall - updating iptables rules "
+ "==> mode: FLUSH destchain: '%s'", destchain);
+ ret = call_iptables(ctx, fwcmd, iptables_args);
+ break;
+
+ case 'I':
+ // Init chain - flush it and then add needed rule for stateful inspection
+ destchain = msg;
+
+ eurephia_log(ctx, LOG_INFO, 3, "eFW_RunFirewall - Initialising iptables chain '%s'",
+ destchain);
+
+ // Flush phase
+ iptables_args[1] = "-F";
+ destchain = msg;
+ iptables_args[2] = destchain;
+ iptables_args[3] = NULL;
+ ret = call_iptables(ctx, fwcmd, iptables_args);
+
+ // Add stateful inspection
+ iptables_args[1] = "-I\0";
+ iptables_args[2] = destchain;
+ iptables_args[3] = "-m\0";
+ iptables_args[4] = "state\0";
+ iptables_args[5] = "--state\0";
+ iptables_args[6] = "ESTABLISHED,RELATED\0";
+ iptables_args[7] = "-j\0";
+ iptables_args[8] = "ACCEPT\0";
+ ret &= call_iptables(ctx, fwcmd, iptables_args);
+ break;
+
+ default:
+ eurephia_log(ctx, LOG_CRITICAL, 0, "eFW_RunFirewall::process_input: Malformed update request");
+ ret = 1;
+ }
+ free_nullsafe(orig_msg);
+ return ret;
+}
+
+int call_iptables(eurephiaCTX *ctx, const char *fwcmd, char **ipt_args) {
+ pid_t pid;
+ int cmdret = -1;
+
+ // Fork out a child process which will run the iptables command. Since the execve replaces
+ // the current process, we need to do the forking first.
+ if( (pid = fork()) < 0) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "eFW_RunFirewall::process_input: Failed to fork process for %s", fwcmd);
+ return 0;
+ }
+
+ switch( pid ) {
+ case 0: // child process - execute the program and exit
+ execve(fwcmd, ipt_args, NULL);
+ exit(1); // execve should replace the process, but if it fails to do so, make sure we exit
+
+ default: // parent process
+ if( waitpid(pid, &cmdret, 0) != pid ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "eFW_RunFirewall::process_input: Failed to wait for process for %s"
+ " to complete (%s)", fwcmd, strerror(errno));
+ }
+ eurephia_log(ctx, LOG_INFO, 4, "eFW_RunFirewall - iptables exited with code: %i ", cmdret);
+ }
+ return 1;
+}