diff options
author | David Sommerseth <dazo@users.sourceforge.net> | 2008-10-15 00:39:53 +0200 |
---|---|---|
committer | David Sommerseth <dazo@users.sourceforge.net> | 2008-10-15 00:39:53 +0200 |
commit | 0ea1a3e2e6a10300388e01ac89504abe3624ae56 (patch) | |
tree | fff59c70d4db431c2114e89d0819af8921aff463 /plugin/eurephia.c | |
parent | b65b0802ead5e863ca8cb41fff77528735a1466c (diff) | |
download | eurephia-0ea1a3e2e6a10300388e01ac89504abe3624ae56.tar.gz eurephia-0ea1a3e2e6a10300388e01ac89504abe3624ae56.tar.xz eurephia-0ea1a3e2e6a10300388e01ac89504abe3624ae56.zip |
Reorganised the source code
Moved all OpenVPN plug-in related things into ./plugins, including firewall
Moved all shared code into ./common and moved the generic part of the
database files into ./database
Updated all CMakeLists.txt files and created a new one for the root directory
Diffstat (limited to 'plugin/eurephia.c')
-rw-r--r-- | plugin/eurephia.c | 527 |
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; +} + |