summaryrefslogtreecommitdiffstats
path: root/plugin/eurephia.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/eurephia.c')
-rw-r--r--plugin/eurephia.c527
1 files changed, 527 insertions, 0 deletions
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;
+}
+