/* eurephia.c -- Main functions for the eurephia authentication module * * GPLv2 - Copyright (C) 2008 David Sommerseth * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; version 2 * of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include #define MAX_ARGUMENTS 25 // Get value of a environment variable const char *get_env(eurephiaCTX *ctx, 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 == '=') { if( ctx != NULL ) { eurephia_log(ctx, LOG_DEBUG, 23, "Function call: get_env(envp, '%s') == '%s'", key, cp + 1); } return cp + 1; } } } if( ctx != NULL ) { eurephia_log(ctx, LOG_DEBUG, 23, "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) { eurephiaCTX *ctx = NULL; int argc = 0, error=0; const char *dbargs[MAX_ARGUMENTS]; // Count how many arguments we have, and copy // db arguments from argc >= 3 while( argv[argc] != NULL ) { argc++; if( (argc > 2) ) { // Make a copy to the argument table // when we have gotten our three first // arguments for logging. // These arguments in dbargs, will // be sent directly to the // eDBconnect(...) function dbargs[argc-3] = argv[argc]; } } // We need at least 3 arguments - logfile, loglevel and db driver if( argc < 3 ) { return NULL; } ctx = (eurephiaCTX *) malloc(sizeof(eurephiaCTX)+2); memset(ctx, 0, sizeof(eurephiaCTX)+2); // Open a log file if( strlen_nullsafe(argv[1]) > 0) { if( strcmp(argv[1], "none") != 0 ) { ctx->log = fopen(argv[1], "aw"); if( ctx->log == NULL ) { fprintf(stderr, "Could not open eurephia log file: %s\n", argv[1]); return NULL; } } } else { ctx->log = fopen("/var/log/eurephia.log", "aw"); error = (ctx->log == NULL); } // Set log verbosity ctx->loglevel = atoi_nullsafe(argv[2]); // Load the database driver if( (error == 0) && eDBlink_init(ctx, argv[3]) ) { if( !eDBconnect(ctx, argc-4, dbargs) ) { 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); ctx = NULL; } else { eurephia_log(ctx, LOG_INFO, 1, "eurehia-auth is initialised"); } return ctx; } int eurephiaShutdown(eurephiaCTX *ctx) { if( ctx == NULL ) { return 0; } if( (ctx->dbc != NULL) && (ctx->dbc->dbhandle != NULL) ) { eDBdisconnect(ctx); } if( ctx->eurephia_driver != NULL ) { eDBlink_close(ctx); } if( ctx->log != NULL ) { eurephia_log(ctx, LOG_INFO, 2, "Closing log file"); fflush(ctx->log); 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; eurephia_log(ctx, LOG_DEBUG, 21, "Function call: eurephia_tlsverify(...)"); // Check if IP address is blacklisted ipaddr = (char *) get_env(ctx, 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, 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, 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); } free_certinfo(ci); if( result > 0 ) { // Reset attempt counter for certificate if it is okey eDBregister_attempt(ctx, attempt_CERTIFICATE, ATTEMPT_RESET, tls_digest); } eurephia_log(ctx, LOG_DEBUG, 21, "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; eurephia_log(ctx, LOG_DEBUG, 21, "Function call: eurephia_userauth(...)"); // Check if IP address is blacklisted ipaddr = (char *) get_env(ctx, 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, 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, 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, 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, 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); } 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; eurephia_log(ctx, LOG_DEBUG, 21, "Function call: eurephia_connect(...)"); // Fetch needed info digest = get_env(ctx, env, "tls_digest_0"); tlsid = get_env(ctx, env, "tls_id_0"); cname = get_env(ctx, env, "common_name"); uname = get_env(ctx, env, "username"); vpnipaddr = get_env(ctx, env, "ifconfig_pool_remote_ip"); vpnipmask = get_env(ctx, env, "ifconfig_pool_netmask"); remipaddr = get_env(ctx, env, "trusted_ip"); remport = get_env(ctx, env, "trusted_port"); proto = get_env(ctx, env, "proto"); // Get a session ticket session = eDBopen_session(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(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(session); 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; int ret = 0; eurephia_log(ctx, LOG_DEBUG, 21, "Function call: eurephia_disconnect(...)"); // Fetch needed info digest = get_env(ctx, env, "tls_digest_0"); cname = get_env(ctx, env, "common_name"); uname = get_env(ctx, env, "username"); vpnipaddr = get_env(ctx, env, "ifconfig_pool_remote_ip"); vpnipmask = get_env(ctx, env, "ifconfig_pool_netmask"); remipaddr = get_env(ctx, env, "trusted_ip"); remport = get_env(ctx, env, "trusted_port"); bytes_sent= get_env(ctx, env, "bytes_sent"); bytes_rec = get_env(ctx, env, "bytes_received"); // Get a session ticket session = eDBopen_session(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); eDBfree_session(session); 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; int ret = 0, fw_enabled = 0; eurephia_log(ctx, LOG_DEBUG, 21, "Function call: eurephia_learn_address(ctx, '%s', '%s', ...)", mode, macaddr); fw_enabled = (atoi_nullsafe(eGet_value(ctx->dbc->config, "firewall_enabled")) == 1); if( strncmp(mode, "add", 3) == 0 ) { // Fetch needed info digest = get_env(ctx, env, "tls_digest_0"); cname = get_env(ctx, env, "common_name"); uname = get_env(ctx, env, "username"); vpnipaddr = get_env(ctx, env, "ifconfig_pool_remote_ip"); vpnipmask = get_env(ctx, env, "ifconfig_pool_netmask"); remipaddr = get_env(ctx, env, "trusted_ip"); remport = get_env(ctx, env, "trusted_port"); // Get a session ticket session = eDBopen_session(ctx, digest, cname, uname, vpnipaddr, vpnipmask, remipaddr, remport); if( session == NULL ) { return 0; } // Update openvpn_lastlog with the active MAC address, and save it as a session variable ret = eDBregister_vpnmacaddr(ctx, session, macaddr); // FIXME: FIREWALL UPDATE if( fw_enabled ) { // 1. Lookup firewall profile for user: eDBget_firewall_profile(ctx, session) // 2. Update firewall with eurephia_firewall(ctx, FWRULE_ADD, profileid) } eDBfree_session(session); } else if( strncmp(mode, "delete", 6) == 0 ) { // FIXME: FIREWALL UPDATE - remove rule for the current MAC address if( fw_enabled ) { // 1. Update firewall with eurephia_firewall(ctx, FWRULE_DELETE, macaddr) } ret = eDBdestroy_session(ctx, macaddr); } return ret; }