/* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vpnd.h" #include "cf_utils.h" #include "ipsec_utils.h" #include "vpnoptions.h" #include "vpnplugins.h" #include "RASSchemaDefinitions.h" extern int got_terminate(void); static int secure_transport = 0; static int key_preference = -1; static CFMutableDictionaryRef ipsec_conf = NULL; static struct vpn_params *current_params = 0; static pthread_t resolverthread = 0; static struct in_addr peer_address; static char remoteaddress[255]; static int resolverfds[2]; static int plugin_listen(); static void plugin_close(); static int plugin_get_args(struct vpn_params *params, int reload); //----------------------------------------------------------------------------- // process_options //----------------------------------------------------------------------------- void ipsec_process_options(struct vpn_params *params) { } /* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ void *ipsec_resolver_thread(void *arg) { struct hostent *host; char result = -1; int count, fd; u_int8_t rd8; if (pthread_detach(pthread_self()) == 0) { // try to resolve the name if (host = gethostbyname(remoteaddress)) { for (count = 0; host->h_addr_list[count]; count++); rd8 = 0; fd = open("/dev/random", O_RDONLY); if (fd) { read(fd, &rd8, sizeof(rd8)); close(fd); } peer_address = *(struct in_addr *)host->h_addr_list[rd8 % count]; result = 0; } } write(resolverfds[1], &result, 1); return 0; } // ---------------------------------------------------------------------------- // process_prefs // ---------------------------------------------------------------------------- int ipsec_process_prefs(struct vpn_params *params) { char *errstr, c; CFStringRef string; if (ipsec_conf) { CFRelease(ipsec_conf); ipsec_conf = NULL; } ipsec_conf = (CFMutableDictionaryRef)CFDictionaryGetValue(params->serverRef, kRASEntIPSec); if (ipsec_conf == NULL) { vpnlog(LOG_ERR, "IPSec plugin: IPSec dictionary not present\n"); goto fail; } ipsec_conf = CFDictionaryCreateMutableCopy(NULL, 0, ipsec_conf); remoteaddress[0] = 0; string = CFDictionaryGetValue(ipsec_conf, kRASPropIPSecRemoteAddress); if (isString(string)) CFStringGetCString(string, remoteaddress, sizeof(remoteaddress), kCFStringEncodingUTF8); if (inet_aton(remoteaddress, &peer_address) == 0) { if (pipe(resolverfds) < 0) { vpnlog(LOG_ERR, "IPSec plugin: failed to create pipe for gethostbyname\n"); goto fail; } if (pthread_create(&resolverthread, NULL, ipsec_resolver_thread, NULL)) { vpnlog(LOG_ERR, "IPSec plugin: failed to create thread for gethostbyname...\n"); close(resolverfds[0]); close(resolverfds[1]); goto fail; } while (read(resolverfds[0], &c, 1) != 1) { if (got_terminate()) { pthread_cancel(resolverthread); break; } } close(resolverfds[0]); close(resolverfds[1]); if (got_terminate()) goto fail; if (c) { vpnlog(LOG_ERR, "IPSec plugin: Host '%s' not found...\n", remoteaddress); goto fail; } string = CFStringCreateWithCString(0, addr2ascii(AF_INET, &peer_address, sizeof(peer_address), 0), kCFStringEncodingASCII); CFDictionarySetValue(ipsec_conf, kRASPropIPSecRemoteAddress, string); CFRelease(string); } // verify the dictionary if (IPSecValidateConfiguration(ipsec_conf, &errstr)) { vpnlog(LOG_ERR, "IPSec plugin: Incorrect preferences (%s)\n", errstr); goto fail; } return 0; fail: if (ipsec_conf) { CFRelease(ipsec_conf); ipsec_conf = NULL; } return -1; } #if 0 //----------------------------------------------------------------------------- // convert a mask to a prefix //----------------------------------------------------------------------------- static int mask_to_prefix (in_addr_t mask) { u_int32_t prefix = 0; int i; #define IS_SET(field, bit) (field & (1 << bit)) /* count the bits set to 1 */ for (i = 31; i >= 0 && IS_SET(mask, i); i--) prefix++; /* verify the other bits are set to 0 */ for (; i >= 0 && !IS_SET(mask, i); i--); /* check for incorrect prefix */ if (i >= 0) return 0; return prefix; } #endif //----------------------------------------------------------------------------- // add_builtin_plugin for non plugin based connection //----------------------------------------------------------------------------- int ipsec_add_builtin_plugin(struct vpn_params* params, void *channel) { struct vpn_channel *chan = (struct vpn_channel *)channel; bzero(chan, sizeof(struct vpn_channel)); chan->get_pppd_args = plugin_get_args; chan->listen = plugin_listen; chan->close = plugin_close; return 0; } /* ----------------------------------------------------------------------------- builtin ipsec get args: FIX ME ----------------------------------------------------------------------------- */ int plugin_get_args(struct vpn_params *params, int reload) { current_params = params; return 0; } //----------------------------------------------------------------------------- // builtin ipsec listen //----------------------------------------------------------------------------- static int plugin_listen() { int err; char *errstr; /* add security policies */ err = IPSecApplyConfiguration(ipsec_conf, &errstr); if (err) { vpnlog(LOG_ERR, "IPSec plugin: cannot configure racoon files (%s)...\n", errstr); return -1; } err = IPSecInstallPolicies(ipsec_conf, -1, &errstr); if (err) { vpnlog(LOG_ERR, "IPSec plugin: cannot configure kernel policies (%s)...\n", errstr); IPSecRemoveConfiguration(ipsec_conf, &errstr); return -1; } /* set IPSec Key management to prefer most recent key */ if (IPSecSetSecurityAssociationsPreference(&key_preference, 0)) vpnlog(LOG_ERR, "IPSec plugin: cannot set IPSec Key management preference (error %d)\n", errno); secure_transport = 1; return 0; } //----------------------------------------------------------------------------- // builtin ipsec close //----------------------------------------------------------------------------- static void plugin_close() { int err; char *errstr; /* remove security policies */ if (secure_transport) { err = IPSecRemoveConfiguration(ipsec_conf, &errstr); if (err) vpnlog(LOG_ERR, "IPSec plugin: cannot remove IPSec configuration (%s)...\n", errstr); err = IPSecRemovePolicies(ipsec_conf, -1, &errstr); if (err) vpnlog(LOG_ERR, "IPSec plugin: cannot delete kernel policies (%s)...\n", errstr); /* restore IPSec Key management preference */ if (IPSecSetSecurityAssociationsPreference(0, key_preference)) vpnlog(LOG_ERR, "L2TP plugin: cannot reset IPSec Key management preference (error %d)\n", errno); } }