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 <net/if.h> 48 49#include <CoreFoundation/CoreFoundation.h> 50#include <SystemConfiguration/SystemConfiguration.h> 51#include "../../Family/if_ppplink.h" 52 53#include "vpnd.h" 54#include "vpnoptions.h" 55#include "cf_utils.h" 56#include "vpnplugins.h" 57#include "pppoptions.h" 58#include "ipsecoptions.h" 59#include "ipsec_utils.h" 60#include "RASSchemaDefinitions.h" 61 62static char* default_log_path = "/var/log/" DAEMON_NAME ".log"; 63static u_char* empty_str = (u_char*)""; 64 65 66static void usage(FILE *fp, const char *argv0); 67static int process_server_prefs(struct vpn_params *params); 68static int process_interface_prefs(struct vpn_params *params); 69 70 71//----------------------------------------------------------------------------- 72// process_options 73//----------------------------------------------------------------------------- 74int process_options(struct vpn_params *params, int argc, char *argv[]) 75{ 76 77 char* argv0 = argv[0]; 78 char* args = "dhnxi:"; 79 char c; 80 81 /* initialize generic portion */ 82 params->max_sessions = 0; 83 params->debug = 0; 84 params->log_verbose = 0; 85 params->daemonize = 1; 86 params->serverIDRef = 0; 87 params->serverRef = 0; 88 params->server_id = 0; 89 params->server_type = -1; 90 params->storeRef = 0; 91 params->next_arg_index = 0; 92 params->log_path[0] = 0; 93 94 // Process command line arguments, if any 95 while ((opterr == 1) && (c = getopt(argc, argv, args)) != EOF) { 96 switch (c) { 97 case 'h': 98 usage (stdout, argv0); 99 exit (0); 100 101 case 'n': 102 set_terminate(); 103 /* FALLTHRU */ 104 105 case 'd': 106 params->debug = 1; 107 break; 108 109 case 'x': 110 params->daemonize = 0; 111 break ; 112 113 case 'i': 114 params->server_id = optarg; 115 break ; 116 117 default: 118 usage(stderr, argv0); 119 return -1; 120 } 121 } 122 123 /* init ppp portion */ 124 ppp_process_options(params); 125 126 /* init ipsec portion */ 127 ipsec_process_options(params); 128 129 return 0; 130} 131 132// ---------------------------------------------------------------------------- 133// get_active_server 134// ---------------------------------------------------------------------------- 135CFArrayRef get_active_servers(struct vpn_params *params) 136{ 137 SCPreferencesRef prefs = 0; 138 CFPropertyListRef active_servers; 139 CFArrayRef arrayCopy = 0; 140 char pathStr[MAXPATHLEN]; 141 142 // open the prefs file 143 prefs = SCPreferencesCreate(0, CFSTR("vpnd"), kRASServerPrefsFileName); 144 if (prefs == NULL) { 145 CFStringGetCString(kRASServerPrefsFileName, pathStr, MAXPATHLEN, kCFStringEncodingMacRoman); 146 vpnlog(LOG_ERR, "Unable to read vpnd prefs file '%s'\n", pathStr); 147 return 0; 148 } 149 // get active servers list from the plist 150 active_servers = SCPreferencesGetValue(prefs, kRASActiveServers); 151 if (active_servers && isArray(active_servers)) 152 if (CFArrayGetCount(active_servers) > 0) 153 arrayCopy = CFArrayCreateCopy(0, active_servers); 154 CFRelease(prefs); 155 return arrayCopy; 156} 157 158// ---------------------------------------------------------------------------- 159// process_prefs 160// ---------------------------------------------------------------------------- 161int process_prefs(struct vpn_params *params) 162{ 163 164 char pathStr[MAXPATHLEN]; 165 SCPreferencesRef prefs = 0; 166 CFPropertyListRef servers_list; 167 168 char text[512] = ""; 169 170 // open the prefs file 171 prefs = SCPreferencesCreate(0, CFSTR("vpnd"), kRASServerPrefsFileName); 172 if (prefs == NULL) { 173 CFStringGetCString(kRASServerPrefsFileName, pathStr, MAXPATHLEN, kCFStringEncodingMacRoman); 174 snprintf(text, sizeof(text), "Unable to read vpnd prefs file '%s'\n", pathStr); 175 goto fail; 176 } 177 // get servers list from the plist 178 servers_list = SCPreferencesGetValue(prefs, kRASServers); 179 if (servers_list == NULL) { 180 snprintf(text, sizeof(text), "Could not get servers dictionary\n"); 181 goto fail; 182 } 183 // retrieve the information for the given Server ID 184 params->serverIDRef = CFStringCreateWithCString(0, params->server_id, kCFStringEncodingMacRoman); 185 if (params->serverIDRef == NULL) { 186 snprintf(text, sizeof(text), "Could not create CFString for server ID\n"); 187 goto fail; 188 } 189 params->serverRef = CFDictionaryGetValue(servers_list, params->serverIDRef); 190 if (params->serverRef == NULL || isDictionary(params->serverRef) == 0) { 191 snprintf(text, sizeof(text), "Server ID '%.64s' invalid\n", params->server_id); 192 params->serverRef = 0; 193 goto fail; 194 } 195 CFRetain(params->serverRef); 196 CFRelease(prefs); 197 prefs = 0; 198 199 // process the dictionaries 200 if (process_server_prefs(params)) 201 goto fail; 202 if (process_interface_prefs(params)) 203 goto fail; 204 205 switch (params->server_type) { 206 case SERVER_TYPE_PPP: 207 if (ppp_process_prefs(params)) { 208 snprintf(text, sizeof(text), "Error while reading PPP preferences\n"); 209 goto fail; 210 } 211 break; 212 case SERVER_TYPE_IPSEC: 213 if (ipsec_process_prefs(params)) { 214 snprintf(text, sizeof(text), "Error while reading IPSec preferences\n"); 215 goto fail; 216 } 217 break; 218 } 219 220 return 0; 221 222fail: 223 vpnlog(LOG_ERR, text[0] ? text : "Error while reading preferences\n"); 224 if (params->serverIDRef) { 225 CFRelease(params->serverIDRef); 226 params->serverIDRef = 0; 227 } 228 if (params->serverRef) { 229 CFRelease(params->serverRef); 230 params->serverRef = 0; 231 } 232 if (prefs) 233 CFRelease(prefs); 234 return -1; 235} 236 237 238 239//----------------------------------------------------------------------------- 240// process_server_prefs 241//----------------------------------------------------------------------------- 242static int process_server_prefs(struct vpn_params *params) 243{ 244 u_int32_t lval, len; 245 u_char str[MAXPATHLEN]; 246 int err ; 247 struct hostent *hostent; 248 249 get_int_option(params->serverRef, kRASEntServer, kRASPropServerMaximumSessions, &lval, 0); 250 if (lval) 251 params->max_sessions = lval; 252 len = sizeof(str); 253 get_str_option(params->serverRef, kRASEntServer, kRASPropServerLogfile, str, sizeof(str), &len, (u_char*)default_log_path); 254 if (str[0]) 255 memcpy(params->log_path, str, len + 1); 256 257 get_int_option(params->serverRef, kRASEntServer, kRASPropServerVerboseLogging, &lval, 0); 258 if (lval) 259 params->log_verbose = lval; 260 261 // Load balancing parameters 262 get_int_option(params->serverRef, kRASEntServer, kRASPropServerLoadBalancingEnabled, &lval, 0); 263 if (lval) { 264 params->lb_enable = 1; 265 266 // will determine the interface from the cluster address 267 //len = sizeof(str); 268 //get_str_option(params->serverRef, kRASEntServer, kRASPropServerLoadBalancingInterface, str, sizeof(str), &len, "en1"); 269 //strncpy(params->lb_interface, str, sizeof(params->lb_interface)); 270 271 // is priority really useful ? 272 //get_int_option(params->serverRef, kRASEntServer, kRASPropServerLoadBalancingPriority, &lval, 5); 273 //if (lval < 1) lval = 1; 274 //else if (lval > LB_MAX_PRIORITY) lval = LB_MAX_PRIORITY; 275 //params->lb_priority = lval; 276 277 get_int_option(params->serverRef, kRASEntServer, kRASPropServerLoadBalancingPort, &lval, LB_DEFAULT_PORT); 278 params->lb_port = htons(lval); 279 len = sizeof(str); 280 get_str_option(params->serverRef, kRASEntServer, kRASPropServerLoadBalancingAddress, str, sizeof(str), &len, empty_str); 281 // ask the system to look up the given name. 282 hostent = getipnodebyname ((char*)str, AF_INET, 0, &err); 283 if (!hostent) { 284 vpnlog(LOG_ERR, "Incorrect Load Balancing address found '%s'\n", str); 285 params->lb_enable = 0; 286 287 } 288 else { 289 struct sockaddr_in src, dst; 290 291 params->lb_cluster_address = *(struct in_addr *)hostent->h_addr_list[0]; 292 freehostent(hostent); 293 294 bzero(&dst, sizeof(dst)); 295 dst.sin_family = PF_INET; 296 dst.sin_len = sizeof(dst); 297 dst.sin_addr = params->lb_cluster_address; 298 299 // look for the interface and primary address of the cluster address 300 if (get_route_interface((struct sockaddr *)&src, (struct sockaddr *)&dst, params->lb_interface)) { 301 302 vpnlog(LOG_ERR, "Cannot get load balancing redirect address and interface (errno = %d)\n", errno); 303 params->lb_enable = 0; 304 } 305 306 params->lb_redirect_address = src.sin_addr; 307 308 309 } 310 } 311 312 return 0; 313} 314 315//----------------------------------------------------------------------------- 316// process_interface_prefs 317//----------------------------------------------------------------------------- 318static int process_interface_prefs(struct vpn_params *params) 319{ 320 CFStringRef str = 0; 321 CFDictionaryRef dict; 322 323 // get type/subtype of server 324 dict = CFDictionaryGetValue(params->serverRef, kRASEntInterface); 325 if (!isDictionary(dict)) { 326 vpnlog(LOG_ERR, "No Interface dictionary found\n"); 327 return -1; 328 } 329 330 str = CFDictionaryGetValue(dict, kRASPropInterfaceType); 331 if (!isString(str)) { 332 vpnlog(LOG_ERR, "No Interface type found\n"); 333 return -1; 334 } 335 336 if (CFStringCompare(str, kRASValInterfaceTypePPP, 0) == kCFCompareEqualTo) 337 params->server_type = SERVER_TYPE_PPP; 338 else if (CFStringCompare(str, kRASValInterfaceTypeIPSec, 0) == kCFCompareEqualTo) 339 params->server_type = SERVER_TYPE_IPSEC; 340 else { 341 vpnlog(LOG_ERR, "Incorrect server type found\n"); 342 return -1; 343 } 344 345 return 0; 346} 347 348//----------------------------------------------------------------------------- 349// publish_state 350//----------------------------------------------------------------------------- 351int publish_state(struct vpn_params* params) 352{ 353 CFMutableDictionaryRef dict; 354 CFStringRef key; 355 int val; 356 CFNumberRef num; 357 358 if (params->storeRef == 0) 359 return 0; 360 361 /* Interface information */ 362 key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@/%s"), 363 kSCDynamicStoreDomainState, 364 kSCCompNetwork, kRASRemoteAccessServer, params->serverIDRef, "Interface"); 365 if (key) { 366 dict = CFDictionaryCreateMutable(0, 0, 367 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 368 if (dict) { 369 switch (params->server_type) { 370 case SERVER_TYPE_PPP: 371 CFDictionarySetValue(dict, kRASPropInterfaceType, kRASValInterfaceTypePPP); 372 CFDictionarySetValue(dict, kRASPropInterfaceSubType, params->serverSubTypeRef); 373 break; 374 case SERVER_TYPE_IPSEC: 375 CFDictionarySetValue(dict, kRASPropInterfaceType, kRASValInterfaceTypeIPSec); 376 break; 377 } 378 SCDynamicStoreAddTemporaryValue(params->storeRef, key, dict); 379 CFRelease(dict); 380 } 381 CFRelease(key); 382 } 383 384 /* Server information */ 385 key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@/%s"), 386 kSCDynamicStoreDomainState, 387 kSCCompNetwork, kRASRemoteAccessServer, params->serverIDRef, "Server"); 388 if (key) { 389 dict = CFDictionaryCreateMutable(0, 0, 390 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 391 if (dict) { 392 val = getpid(); 393 num = CFNumberCreate(0, kCFNumberIntType, &val); 394 if (num) { 395 CFDictionarySetValue(dict, CFSTR("pid"), num); 396 SCDynamicStoreAddTemporaryValue(params->storeRef, key, dict); 397 CFRelease(num); 398 } 399 CFRelease(dict); 400 } 401 CFRelease(key); 402 } 403 404 return 1; 405} 406 407//----------------------------------------------------------------------------- 408// open_dynamic_store 409//----------------------------------------------------------------------------- 410void open_dynamic_store(struct vpn_params* params) 411{ 412 params->storeRef = SCDynamicStoreCreate(0, CFSTR("vpnd"), 0, 0); 413} 414 415//----------------------------------------------------------------------------- 416// close_dynamic_store 417//----------------------------------------------------------------------------- 418void close_dynamic_store(struct vpn_params* params) 419{ 420 if (params->storeRef) { 421 CFRelease(params->storeRef); 422 params->storeRef = NULL; 423 } 424 425} 426 427//----------------------------------------------------------------------------- 428// check_conflicts 429//----------------------------------------------------------------------------- 430int check_conflicts(struct vpn_params *params) 431{ 432 433 if (params->storeRef == 0) 434 return 0; 435 436 switch (params->server_type) { 437 case SERVER_TYPE_PPP: 438 return ppp_check_conflicts(params); 439 440 case SERVER_TYPE_IPSEC: 441 return 0; 442 } 443 444 return 0; 445} 446 447//----------------------------------------------------------------------------- 448// kill_orphans 449//----------------------------------------------------------------------------- 450int kill_orphans(struct vpn_params* params) 451{ 452 453 if (params->storeRef == 0) 454 return 0; 455 456 switch (params->server_type) { 457 case SERVER_TYPE_PPP: 458 return ppp_kill_orphans(params); 459 460 case SERVER_TYPE_IPSEC: 461 return 0; 462 } 463 464 return 0; 465} 466 467//----------------------------------------------------------------------------- 468// add_builtin_plugin for non plugin based connection 469//----------------------------------------------------------------------------- 470int add_builtin_plugin(struct vpn_params* params, void *channel) 471{ 472 473 switch (params->server_type) { 474 case SERVER_TYPE_PPP: 475 /* ppp connection are plugin based */ 476 return -1; 477 478 case SERVER_TYPE_IPSEC: 479 return ipsec_add_builtin_plugin(params, channel); 480 } 481 482 return -1; 483} 484 485// ---------------------------------------------------------------------------- 486// usage 487// ---------------------------------------------------------------------------- 488static void usage(FILE *fp, const char *argv0) 489{ 490 static const char* szpUsage = 491 "Usage:\t%s [-dhnx] [-i serverID]\n" 492 " -h this message\n" 493 " -x does not move to background\n" 494 " -d enable debug mode\n" 495 " -n same as -d but terminates after validation\n" 496 " -i server ID for this server (ex: com.apple.ppp.l2tp)\n" 497 ; 498 fprintf (fp, szpUsage, argv0); 499} 500 501//----------------------------------------------------------------------------- 502// plugin_exists - checks to see if the given plugin exists. 503//----------------------------------------------------------------------------- 504int plugin_exists(const char *inPath) 505{ 506 struct stat sbTemp, *sbpTemp = &sbTemp; 507 char path[MAXPATHLEN]; 508 509 path[0] = 0; 510 if (inPath[0] != '/') 511 strlcpy(path, PLUGINS_DIR, sizeof(path)); 512 strlcat(path, inPath, sizeof(path)); 513 514 if (stat(path, sbpTemp)) 515 return 0; 516 //if (!S_ISREG (sbpTemp->st_mode)) { 517 // errno = ENOENT; 518 // return-1; 519 // } 520 return 1; 521} 522 523//----------------------------------------------------------------------------- 524// validate_ipstring 525//----------------------------------------------------------------------------- 526char* validate_ip_string(const char *inIPString, char *outIPString, size_t outSize) 527{ 528 529 int nErr ; 530 char* outIP; 531 532 if (!inIPString) 533 return 0; 534 if (!*inIPString) 535 return 0; 536 if (outSize < 16) 537 return 0; 538 539 // First, ask the system to look up the given name. 540 struct hostent *hesp = getipnodebyname (inIPString, AF_INET, 0, &nErr); 541 if (hesp == NULL) 542 return 0; 543 // Convert the returned info to dotted decimal string. 544 outIP = (char*)inet_ntop(AF_INET, hesp->h_addr_list[0], outIPString, outSize); 545 freehostent (hesp); 546 return outIP; 547} 548 549// ---------------------------------------------------------------------------- 550// addparam 551// ---------------------------------------------------------------------------- 552 553void addparam(char **arg, u_int32_t *argi, char *param) 554{ 555 int len = strlen(param); 556 557 if (len && (arg[*argi] = malloc(len + 1))) { 558 strlcpy(arg[*argi], param, (len + 1)); 559 (*argi)++; 560 } 561} 562 563// ---------------------------------------------------------------------------- 564// addintparam 565// ---------------------------------------------------------------------------- 566void addintparam(char **arg, u_int32_t *argi, char *param, u_int32_t val) 567{ 568 char str[32]; 569 570 addparam(arg, argi, param); 571 snprintf(str, sizeof(str), "%d", val); 572 addparam(arg, argi, str); 573} 574 575// ---------------------------------------------------------------------------- 576// addstrparam 577// ---------------------------------------------------------------------------- 578void addstrparam(char **arg, u_int32_t *argi, char *param, char *val) 579{ 580 581 addparam(arg, argi, param); 582 addparam(arg, argi, val); 583} 584 585