1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25#include <stdio.h> 26#include <ctype.h> 27#include <stdlib.h> 28#include <string.h> 29#include <unistd.h> 30#include <signal.h> 31#include <errno.h> 32#include <fcntl.h> 33#include <syslog.h> 34#include <netdb.h> 35#include <paths.h> 36#include <sys/queue.h> 37 38#include <sys/param.h> 39#include <sys/types.h> 40#include <sys/wait.h> 41#include <sys/time.h> 42#include <sys/resource.h> 43#include <sys/stat.h> 44#include <sys/socket.h> 45#include <netinet/in.h> 46#include <arpa/inet.h> 47#include <sys/sysctl.h> 48#include <pthread.h> 49#include <net/if.h> 50 51#include <CoreFoundation/CoreFoundation.h> 52#include <SystemConfiguration/SystemConfiguration.h> 53 54#include "vpnd.h" 55#include "cf_utils.h" 56#include "ipsec_utils.h" 57#include "vpnoptions.h" 58#include "vpnplugins.h" 59#include "RASSchemaDefinitions.h" 60 61extern int got_terminate(void); 62 63static int secure_transport = 0; 64static int key_preference = -1; 65 66static CFMutableDictionaryRef ipsec_conf = NULL; 67 68static struct vpn_params *current_params = 0; 69 70static pthread_t resolverthread = 0; 71static struct in_addr peer_address; 72static char remoteaddress[255]; 73static int resolverfds[2]; 74 75static int plugin_listen(); 76static void plugin_close(); 77static int plugin_get_args(struct vpn_params *params, int reload); 78 79//----------------------------------------------------------------------------- 80// process_options 81//----------------------------------------------------------------------------- 82void ipsec_process_options(struct vpn_params *params) 83{ 84 85} 86 87/* ----------------------------------------------------------------------------- 88----------------------------------------------------------------------------- */ 89void *ipsec_resolver_thread(void *arg) 90{ 91 struct hostent *host; 92 char result = -1; 93 int count, fd; 94 u_int8_t rd8; 95 96 if (pthread_detach(pthread_self()) == 0) { 97 98 // try to resolve the name 99 if ((host = gethostbyname(remoteaddress))) { 100 101 for (count = 0; host->h_addr_list[count]; count++); 102 103 rd8 = 0; 104 fd = open("/dev/random", O_RDONLY); 105 if (fd) { 106 read(fd, &rd8, sizeof(rd8)); 107 close(fd); 108 } 109 110 if (count) { 111 peer_address = *(struct in_addr *)host->h_addr_list[rd8 % count]; 112 } else { 113 bzero(&peer_address, sizeof(peer_address)); 114 } 115 result = 0; 116 } 117 } 118 119 write(resolverfds[1], &result, 1); 120 return 0; 121} 122 123// ---------------------------------------------------------------------------- 124// process_prefs 125// ---------------------------------------------------------------------------- 126int ipsec_process_prefs(struct vpn_params *params) 127{ 128 char *errstr, c; 129 CFStringRef string; 130 131 if (ipsec_conf) { 132 CFRelease(ipsec_conf); 133 ipsec_conf = NULL; 134 } 135 136 ipsec_conf = (CFMutableDictionaryRef)CFDictionaryGetValue(params->serverRef, kRASEntIPSec); 137 if (ipsec_conf == NULL) { 138 vpnlog(LOG_ERR, "IPSec plugin: IPSec dictionary not present\n"); 139 goto fail; 140 } 141 142 ipsec_conf = CFDictionaryCreateMutableCopy(NULL, 0, ipsec_conf); 143 144 remoteaddress[0] = 0; 145 string = CFDictionaryGetValue(ipsec_conf, kRASPropIPSecRemoteAddress); 146 if (isString(string)) 147 CFStringGetCString(string, remoteaddress, sizeof(remoteaddress), kCFStringEncodingUTF8); 148 149 if (inet_aton(remoteaddress, &peer_address) == 0) { 150 151 if (pipe(resolverfds) < 0) { 152 vpnlog(LOG_ERR, "IPSec plugin: failed to create pipe for gethostbyname\n"); 153 goto fail; 154 } 155 156 if (pthread_create(&resolverthread, NULL, ipsec_resolver_thread, NULL)) { 157 vpnlog(LOG_ERR, "IPSec plugin: failed to create thread for gethostbyname...\n"); 158 close(resolverfds[0]); 159 close(resolverfds[1]); 160 goto fail; 161 } 162 163 while (read(resolverfds[0], &c, 1) != 1) { 164 if (got_terminate()) { 165 pthread_cancel(resolverthread); 166 break; 167 } 168 } 169 170 close(resolverfds[0]); 171 close(resolverfds[1]); 172 173 if (got_terminate()) 174 goto fail; 175 176 if (c) { 177 vpnlog(LOG_ERR, "IPSec plugin: Host '%s' not found...\n", remoteaddress); 178 goto fail; 179 } 180 181 string = CFStringCreateWithCString(0, addr2ascii(AF_INET, &peer_address, sizeof(peer_address), 0), kCFStringEncodingASCII); 182 CFDictionarySetValue(ipsec_conf, kRASPropIPSecRemoteAddress, string); 183 CFRelease(string); 184 } 185 186 // verify the dictionary 187 if (IPSecValidateConfiguration(ipsec_conf, &errstr)) { 188 189 vpnlog(LOG_ERR, "IPSec plugin: Incorrect preferences (%s)\n", errstr); 190 goto fail; 191 } 192 193 return 0; 194 195fail: 196 if (ipsec_conf) { 197 CFRelease(ipsec_conf); 198 ipsec_conf = NULL; 199 } 200 return -1; 201} 202 203#if 0 204//----------------------------------------------------------------------------- 205// convert a mask to a prefix 206//----------------------------------------------------------------------------- 207static int mask_to_prefix (in_addr_t mask) 208{ 209 u_int32_t prefix = 0; 210 int i; 211 212#define IS_SET(field, bit) (field & (1 << bit)) 213 214 /* count the bits set to 1 */ 215 for (i = 31; i >= 0 && IS_SET(mask, i); i--) 216 prefix++; 217 218 /* verify the other bits are set to 0 */ 219 for (; i >= 0 && !IS_SET(mask, i); i--); 220 221 /* check for incorrect prefix */ 222 if (i >= 0) 223 return 0; 224 225 return prefix; 226} 227#endif 228 229//----------------------------------------------------------------------------- 230// add_builtin_plugin for non plugin based connection 231//----------------------------------------------------------------------------- 232int ipsec_add_builtin_plugin(struct vpn_params* params, void *channel) 233{ 234 struct vpn_channel *chan = (struct vpn_channel *)channel; 235 236 bzero(chan, sizeof(struct vpn_channel)); 237 chan->get_pppd_args = plugin_get_args; 238 chan->listen = plugin_listen; 239 chan->close = plugin_close; 240 241 return 0; 242} 243 244/* ----------------------------------------------------------------------------- 245 builtin ipsec get args: FIX ME 246----------------------------------------------------------------------------- */ 247int plugin_get_args(struct vpn_params *params, int reload) 248{ 249 current_params = params; 250 return 0; 251} 252 253//----------------------------------------------------------------------------- 254// builtin ipsec listen 255//----------------------------------------------------------------------------- 256static int plugin_listen() 257{ 258 int err; 259 char *errstr; 260 261 /* add security policies */ 262 err = IPSecApplyConfiguration(ipsec_conf, &errstr); 263 if (err) { 264 vpnlog(LOG_ERR, "IPSec plugin: cannot configure racoon files (%s)...\n", errstr); 265 return -1; 266 } 267 268 err = IPSecInstallPolicies(ipsec_conf, -1, &errstr); 269 if (err) { 270 vpnlog(LOG_ERR, "IPSec plugin: cannot configure kernel policies (%s)...\n", errstr); 271 IPSecRemoveConfiguration(ipsec_conf, &errstr); 272 return -1; 273 } 274 275 /* set IPSec Key management to prefer most recent key */ 276 if (IPSecSetSecurityAssociationsPreference(&key_preference, 0)) 277 vpnlog(LOG_ERR, "IPSec plugin: cannot set IPSec Key management preference (error %d)\n", errno); 278 279 280 secure_transport = 1; 281 282 return 0; 283} 284 285//----------------------------------------------------------------------------- 286// builtin ipsec close 287//----------------------------------------------------------------------------- 288static void plugin_close() 289{ 290 int err; 291 char *errstr; 292 293 /* remove security policies */ 294 if (secure_transport) { 295 err = IPSecRemoveConfiguration(ipsec_conf, &errstr); 296 if (err) 297 vpnlog(LOG_ERR, "IPSec plugin: cannot remove IPSec configuration (%s)...\n", errstr); 298 err = IPSecRemovePolicies(ipsec_conf, -1, &errstr); 299 if (err) 300 vpnlog(LOG_ERR, "IPSec plugin: cannot delete kernel policies (%s)...\n", errstr); 301 /* restore IPSec Key management preference */ 302 if (IPSecSetSecurityAssociationsPreference(0, key_preference)) 303 vpnlog(LOG_ERR, "L2TP plugin: cannot reset IPSec Key management preference (error %d)\n", errno); 304 } 305} 306 307