1/* 2 * Copyright (c) 2010-2013 Apple 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 * Modification History 26 * 27 * March 1, 2010 Christophe Allie <callie@apple.com> 28 * - initial revision 29 * February 8, 2011 Kevin Wells <kcw@apple.com> 30 * - added "select" command 31 * January 2012 Kevin Wells <kcw@apple.com> 32 * - added arguments to "start" command to pass authentication credentials 33 * - "show" now takes a service name as an alternative to a service ID 34 * - fixes a bug whereby "IPv4" was being displayed as a subtype to IPsec services 35 * - improved format of "list" output 36 * - general cleanup of error messages and some variable names 37 */ 38 39 40#include "scutil.h" 41#include "nc.h" 42#include "prefs.h" 43 44#include <SystemConfiguration/VPNConfiguration.h> 45 46#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR 47#include <MobileInstallation/MobileInstallation.h> 48#endif // TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR 49 50#include <sys/time.h> 51 52CFStringRef username = NULL; 53CFStringRef password = NULL; 54CFStringRef sharedsecret = NULL; 55 56static Boolean ondemandwatch = FALSE; 57static CFStringRef ondemand_nodename = NULL; 58 59static SCNetworkConnectionRef connection = NULL; 60static int n_callback = 0; 61 62 63/* ----------------------------------------------------------------------------- 64----------------------------------------------------------------------------- */ 65static void 66my_CFRelease(void *t) 67{ 68 void * * obj = (void * *)t; 69 if (obj && *obj) { 70 CFRelease(*obj); 71 *obj = NULL; 72 } 73 return; 74} 75 76/* ----------------------------------------------------------------------------- 77 ----------------------------------------------------------------------------- */ 78static void 79nc_get_service_type_and_subtype(SCNetworkServiceRef service, CFStringRef *iftype, CFStringRef *ifsubtype) { 80 SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface(service); 81 SCNetworkInterfaceRef child = SCNetworkInterfaceGetInterface(interface); 82 83 *iftype = SCNetworkInterfaceGetInterfaceType(interface); 84 *ifsubtype = NULL; 85 if (CFEqual(*iftype, kSCNetworkInterfaceTypePPP) || 86 CFEqual(*iftype, kSCNetworkInterfaceTypeVPN)) { 87 *ifsubtype = (child != NULL) ? SCNetworkInterfaceGetInterfaceType(child) : NULL; 88 } 89} 90 91/* ----------------------------------------------------------------------------- 92 ----------------------------------------------------------------------------- */ 93static SCNetworkServiceRef 94nc_copy_service(SCNetworkSetRef set, CFStringRef identifier) 95{ 96 CFIndex i; 97 CFIndex n; 98 SCNetworkServiceRef selected = NULL; 99 CFArrayRef services; 100 101 services = SCNetworkConnectionCopyAvailableServices(set); 102 if (services == NULL) { 103 goto done; 104 } 105 106 n = CFArrayGetCount(services); 107 108 // try to select the service by its serviceID 109 for (i = 0; i < n; i++) { 110 SCNetworkServiceRef service = NULL; 111 CFStringRef serviceID; 112 113 service = CFArrayGetValueAtIndex(services, i); 114 serviceID = SCNetworkServiceGetServiceID(service); 115 if (CFEqual(identifier, serviceID)) { 116 selected = service; 117 goto done; 118 } 119 } 120 121 // try to select the service by service name 122 for (i = 0; i < n; i++) { 123 SCNetworkServiceRef service = NULL; 124 CFStringRef serviceName; 125 126 service = CFArrayGetValueAtIndex(services, i); 127 serviceName = SCNetworkServiceGetName(service); 128 if ((serviceName != NULL) && CFEqual(identifier, serviceName)) { 129 if (selected == NULL) { 130 selected = service; 131 } else { 132 // if multiple services match 133 selected = NULL; 134 SCPrint(TRUE, stderr, CFSTR("Multiple services match\n")); 135 goto done; 136 } 137 } 138 } 139 140done : 141 142 if (selected != NULL) CFRetain(selected); 143 if (services != NULL) CFRelease(services); 144 return selected; 145} 146 147/* ----------------------------------------------------------------------------- 148 ----------------------------------------------------------------------------- */ 149static SCNetworkServiceRef 150nc_copy_service_from_arguments(int argc, char **argv, SCNetworkSetRef set) { 151 CFStringRef serviceID = NULL; 152 SCNetworkServiceRef service = NULL; 153 154 if (argc == 0) { 155 serviceID = _copyStringFromSTDIN(CFSTR("Service"), NULL); 156 } else { 157 serviceID = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); 158 } 159 if (serviceID == NULL) { 160 SCPrint(TRUE, stderr, CFSTR("No service ID specified\n")); 161 return NULL; 162 } 163 service = nc_copy_service(set, serviceID); 164 my_CFRelease(&serviceID); 165 return service; 166} 167 168 169/* ----------------------------------------------------------------------------- 170----------------------------------------------------------------------------- */ 171static char * 172nc_status_string(SCNetworkConnectionStatus status) 173{ 174 switch (status) { 175 case kSCNetworkConnectionInvalid: 176 return "Invalid"; 177 case kSCNetworkConnectionDisconnected: 178 return "Disconnected"; 179 case kSCNetworkConnectionConnecting: 180 return "Connecting"; 181 case kSCNetworkConnectionConnected: 182 return "Connected"; 183 case kSCNetworkConnectionDisconnecting: 184 return "Disconnecting"; 185 } 186 return "Unknown"; 187} 188 189static void 190nc_callback(SCNetworkConnectionRef connection, SCNetworkConnectionStatus status, void *info) 191{ 192 int *n = (int *)info; 193 CFDictionaryRef status_dict; 194 195 // report status 196 if (n != NULL) { 197 if (*n == 0) { 198 SCPrint(TRUE, stdout, CFSTR("Current status = ")); 199 } else { 200 struct tm tm_now; 201 struct timeval tv_now; 202 203 (void)gettimeofday(&tv_now, NULL); 204 (void)localtime_r(&tv_now.tv_sec, &tm_now); 205 206 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"), 207 tm_now.tm_hour, 208 tm_now.tm_min, 209 tm_now.tm_sec, 210 tv_now.tv_usec / 1000); 211 SCPrint(TRUE, stdout, CFSTR("Callback (%d) status = "), *n); 212 } 213 *n = *n + 1; 214 } 215 SCPrint(TRUE, stdout, CFSTR("%s%s%s\n"), 216 nc_status_string(status), 217 (status == kSCNetworkConnectionInvalid) ? ": " : "", 218 (status == kSCNetworkConnectionInvalid) ? SCErrorString(SCError()) : ""); 219 220 // report extended status 221 status_dict = SCNetworkConnectionCopyExtendedStatus(connection); 222 if (status_dict) { 223 SCPrint(TRUE, stdout, CFSTR("Extended Status %@\n"), status_dict); 224 CFRelease(status_dict); 225 } 226 227 return; 228} 229 230static void 231nc_create_connection(int argc, char **argv, Boolean exit_on_failure) 232{ 233 SCNetworkConnectionContext context = { 0, &n_callback, NULL, NULL, NULL }; 234 SCNetworkServiceRef service; 235 236 service = nc_copy_service_from_arguments(argc, argv, NULL); 237 if (service == NULL) { 238 SCPrint(TRUE, stderr, CFSTR("No service\n")); 239 if (exit_on_failure) 240 exit(1); 241 return; 242 } 243 244 connection = SCNetworkConnectionCreateWithService(NULL, service, nc_callback, &context); 245 CFRelease(service); 246 if (connection == NULL) { 247 SCPrint(TRUE, stderr, CFSTR("Could not create connection: %s\n"), SCErrorString(SCError())); 248 if (exit_on_failure) 249 exit(1); 250 return; 251 } 252} 253 254/* ----------------------------------------------------------------------------- 255 ----------------------------------------------------------------------------- */ 256 257static void 258nc_trigger(int argc, char **argv) 259{ 260 Boolean background = FALSE; 261 int i; 262 CFStringRef hostName = NULL; 263 int port = 80; 264 265 for (i = 0; i < 3 && i < argc; i++) { 266 /* Parse host name. Must be first arg. */ 267 if (i == 0) { 268 hostName = CFStringCreateWithCString(NULL, argv[i], kCFStringEncodingUTF8); 269 continue; 270 } 271 272 /* Check for optional background flag */ 273 if (strcmp(argv[i], "background") == 0) { 274 background = TRUE; 275 continue; 276 } 277 278 /* Parse optional port number */ 279 CFStringRef str = CFStringCreateWithCString(NULL, argv[i], kCFStringEncodingUTF8); 280 if (str) { 281 int num = CFStringGetIntValue(str); 282 if (num) { 283 port = num; 284 } 285 my_CFRelease(&str); 286 } 287 } 288 289 if (hostName) { 290 CFReadStreamRef readStream = NULL; 291 CFWriteStreamRef writeStream = NULL; 292 293 CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, hostName, port, &readStream, &writeStream); 294 295 if (background) { 296 CFReadStreamSetProperty(readStream, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground")); 297 CFWriteStreamSetProperty(writeStream, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground")); 298 } 299 300 if (readStream && writeStream) { 301 CFReadStreamOpen(readStream); 302 CFWriteStreamOpen(writeStream); 303 SCPrint(TRUE, stdout, CFSTR("Opened stream to %@, port %d%s\n"), hostName, port, background ? ", background traffic class" : ""); 304 sleep(1); 305 } 306 307 my_CFRelease(&readStream); 308 my_CFRelease(&writeStream); 309 } else { 310 SCPrint(TRUE, stderr, CFSTR("Invalid or missing host name\n")); 311 } 312 313 my_CFRelease(&hostName); 314 315 exit(0); 316} 317 318/* ----------------------------------------------------------------------------- 319----------------------------------------------------------------------------- */ 320static void 321nc_release_connection() 322{ 323 my_CFRelease(&connection); 324} 325 326/* ----------------------------------------------------------------------------- 327----------------------------------------------------------------------------- */ 328static void 329nc_start(int argc, char **argv) 330{ 331 CFMutableDictionaryRef userOptions = NULL; 332 CFStringRef iftype = NULL; 333 CFStringRef ifsubtype = NULL; 334 SCNetworkServiceRef service = NULL; 335 336 nc_create_connection(argc, argv, TRUE); 337 338 service = SCNetworkConnectionGetService(connection); 339 nc_get_service_type_and_subtype(service, &iftype, &ifsubtype); 340 341 userOptions = CFDictionaryCreateMutable(NULL, 0, 342 &kCFTypeDictionaryKeyCallBacks, 343 &kCFTypeDictionaryValueCallBacks); 344 345 Boolean isL2TP = (CFEqual(iftype, kSCEntNetPPP) && 346 (ifsubtype != NULL) && CFEqual(ifsubtype, kSCValNetInterfaceSubTypeL2TP)); 347 348 if (CFEqual(iftype, kSCEntNetPPP)) { 349 CFMutableDictionaryRef pppEntity = CFDictionaryCreateMutable(NULL, 0, 350 &kCFTypeDictionaryKeyCallBacks, 351 &kCFTypeDictionaryValueCallBacks); 352 353 if (username != NULL) { 354 CFDictionarySetValue(pppEntity, kSCPropNetPPPAuthName, username); 355 } 356 if (password != NULL) { 357 CFDictionarySetValue(pppEntity, kSCPropNetPPPAuthPassword, password); 358 } 359 CFDictionarySetValue(userOptions, kSCEntNetPPP, pppEntity); 360 my_CFRelease(&pppEntity); 361 } 362 if (CFEqual(iftype, kSCEntNetIPSec) || isL2TP) { 363 CFMutableDictionaryRef ipsecEntity = CFDictionaryCreateMutable(NULL, 0, 364 &kCFTypeDictionaryKeyCallBacks, 365 &kCFTypeDictionaryValueCallBacks); 366 if (!isL2TP) { 367 if (username != NULL) { 368 CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecXAuthName, username); 369 } 370 if (password != NULL) { 371 CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecXAuthPassword, password); 372 } 373 } 374 if (sharedsecret != NULL) { 375 CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecSharedSecret, sharedsecret); 376 } 377 CFDictionarySetValue(userOptions, kSCEntNetIPSec, ipsecEntity); 378 my_CFRelease(&ipsecEntity); 379 } 380 if (CFEqual(iftype, kSCEntNetVPN)) { 381 CFMutableDictionaryRef vpnEntity = CFDictionaryCreateMutable(NULL, 0, 382 &kCFTypeDictionaryKeyCallBacks, 383 &kCFTypeDictionaryValueCallBacks); 384 if (username != NULL) { 385 CFDictionarySetValue(vpnEntity, kSCPropNetVPNAuthName, username); 386 } 387 if (password != NULL) { 388 CFDictionarySetValue(vpnEntity, kSCPropNetVPNAuthPassword, password); 389 } 390 CFDictionarySetValue(userOptions, kSCEntNetVPN, vpnEntity); 391 my_CFRelease(&vpnEntity); 392 } 393 // If it doesn't match any VPN type, fail silently 394 395 if (!SCNetworkConnectionStart(connection, userOptions, TRUE)) { 396 SCPrint(TRUE, stderr, CFSTR("Could not start connection: %s\n"), SCErrorString(SCError())); 397 exit(1); 398 }; 399 400 CFRelease(userOptions); 401 nc_release_connection(); 402 exit(0); 403} 404 405/* ----------------------------------------------------------------------------- 406----------------------------------------------------------------------------- */ 407static void 408nc_stop(int argc, char **argv) 409{ 410 nc_create_connection(argc, argv, TRUE); 411 412 if (!SCNetworkConnectionStop(connection, TRUE)) { 413 SCPrint(TRUE, stderr, CFSTR("Could not stop connection: %s\n"), SCErrorString(SCError())); 414 exit(1); 415 }; 416 417 nc_release_connection(); 418 exit(0); 419} 420 421/* ----------------------------------------------------------------------------- 422 ----------------------------------------------------------------------------- */ 423static void 424nc_suspend(int argc, char **argv) 425{ 426 nc_create_connection(argc, argv, TRUE); 427 428 SCNetworkConnectionSuspend(connection); 429 430 nc_release_connection(); 431 exit(0); 432} 433 434/* ----------------------------------------------------------------------------- 435 ----------------------------------------------------------------------------- */ 436static void 437nc_resume(int argc, char **argv) 438{ 439 nc_create_connection(argc, argv, TRUE); 440 441 SCNetworkConnectionResume(connection); 442 443 nc_release_connection(); 444 exit(0); 445} 446 447/* ----------------------------------------------------------------------------- 448----------------------------------------------------------------------------- */ 449static void 450nc_status(int argc, char **argv) 451{ 452 SCNetworkConnectionStatus status; 453 454 nc_create_connection(argc, argv, TRUE); 455 456 status = SCNetworkConnectionGetStatus(connection); 457 nc_callback(connection, status, NULL); 458 459 nc_release_connection(); 460 exit(0); 461} 462 463static void 464nc_watch(int argc, char **argv) 465{ 466 SCNetworkConnectionStatus status; 467 468 nc_create_connection(argc, argv, TRUE); 469 470 status = SCNetworkConnectionGetStatus(connection); 471 472 // report initial status 473 n_callback = 0; 474 nc_callback(connection, status, &n_callback); 475 476 // setup watcher 477 if (doDispatch) { 478 if (!SCNetworkConnectionSetDispatchQueue(connection, dispatch_get_main_queue())) { 479 SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError())); 480 exit(1); 481 } 482 } else { 483 if (!SCNetworkConnectionScheduleWithRunLoop(connection, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { 484 SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError())); 485 exit(1); 486 } 487 } 488 489 // wait for changes 490 CFRunLoopRun(); 491 492 nc_release_connection(); 493 exit(0); 494} 495 496/* ----------------------------------------------------------------------------- 497----------------------------------------------------------------------------- */ 498static void 499nc_statistics(int argc, char **argv) 500{ 501 CFDictionaryRef stats_dict; 502 503 nc_create_connection(argc, argv, TRUE); 504 505 stats_dict = SCNetworkConnectionCopyStatistics(connection); 506 507 if (stats_dict) { 508 SCPrint(TRUE, stdout, CFSTR("%@\n"), stats_dict); 509 } else { 510 SCPrint(TRUE, stdout, CFSTR("No statistics available\n")); 511 } 512 513 my_CFRelease(&stats_dict); 514 515 nc_release_connection(); 516 exit(0); 517} 518 519/* ----------------------------------------------------------------------------- 520----------------------------------------------------------------------------- */ 521static void 522checkOnDemandHost(SCDynamicStoreRef store, CFStringRef nodeName, Boolean retry) 523{ 524 Boolean ok; 525 CFStringRef connectionServiceID = NULL; 526 SCNetworkConnectionStatus connectionStatus = 0; 527 CFStringRef vpnRemoteAddress = NULL; 528 529 SCPrint(TRUE, stdout, CFSTR("OnDemand host/domain check (%sretry)\n"), retry ? "" : "no "); 530 531 ok = __SCNetworkConnectionCopyOnDemandInfoWithName(&store, 532 nodeName, 533 retry, 534 &connectionServiceID, 535 &connectionStatus, 536 &vpnRemoteAddress); 537 538 if (ok) { 539 SCPrint(TRUE, stdout, CFSTR(" serviceID = %@\n"), connectionServiceID); 540 SCPrint(TRUE, stdout, CFSTR(" remote address = %@\n"), vpnRemoteAddress); 541 } else if (SCError() != kSCStatusOK) { 542 SCPrint(TRUE, stdout, CFSTR("%sretry\n"), retry ? "" : "no "); 543 SCPrint(TRUE, stdout, 544 CFSTR(" Unable to copy OnDemand information for connection: %s\n"), 545 SCErrorString(SCError())); 546 } else { 547 SCPrint(TRUE, stdout, CFSTR(" no match\n")); 548 } 549 550 if (connectionServiceID != NULL) { 551 CFRelease(connectionServiceID); 552 connectionServiceID = NULL; 553 } 554 if (vpnRemoteAddress != NULL) { 555 CFRelease(vpnRemoteAddress); 556 vpnRemoteAddress = NULL; 557 } 558 559 return; 560} 561 562static void 563nc_ondemand_callback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) 564{ 565 CFStringRef key = NULL; 566 CFDictionaryRef ondemand_dict = NULL; 567 struct tm tm_now; 568 struct timeval tv_now; 569 570 if (CFArrayGetCount(changedKeys) < 1) { 571 return; 572 } 573 574 (void)gettimeofday(&tv_now, NULL); 575 (void)localtime_r(&tv_now.tv_sec, &tm_now); 576 577 SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"), 578 tm_now.tm_hour, 579 tm_now.tm_min, 580 tm_now.tm_sec, 581 tv_now.tv_usec / 1000); 582 583 if (ondemand_nodename) { 584 checkOnDemandHost(store, ondemand_nodename, FALSE); 585 checkOnDemandHost(store, ondemand_nodename, TRUE); 586 } else { 587 key = CFArrayGetValueAtIndex(changedKeys, 0); 588 589 ondemand_dict = SCDynamicStoreCopyValue(store, key); 590 if (ondemand_dict) { 591 SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), kSCEntNetOnDemand, ondemand_dict); 592 } else { 593 SCPrint(TRUE, stdout, CFSTR("%@ not configured\n"), kSCEntNetOnDemand); 594 } 595 596 my_CFRelease(&ondemand_dict); 597 } 598} 599 600static void 601nc_ondemand(int argc, char **argv) 602{ 603 int exit_code = 1; 604 CFStringRef key = NULL; 605 CFDictionaryRef ondemand_dict = NULL; 606 SCDynamicStoreRef store; 607 608 store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), nc_ondemand_callback, NULL); 609 if (store == NULL) { 610 SCPrint(TRUE, stderr, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError())); 611 goto done; 612 } 613 614 if (argc == 1) { 615#if !TARGET_IPHONE_SIMULATOR 616 if (strcmp("--refresh", argv[0]) == 0) { 617 SCNetworkConnectionRef connection = NULL; 618 619 connection = SCNetworkConnectionCreate(kCFAllocatorDefault, NULL, NULL); 620 if (connection && SCNetworkConnectionRefreshOnDemandState(connection)) { 621 exit_code = 0; 622 } 623 624 if (exit_code) { 625 SCPrint(TRUE, stderr, CFSTR("Unable to refresh OnDemand state: %s\n"), SCErrorString(SCError())); 626 } 627 628 my_CFRelease(&connection); 629 goto done; 630 } 631#endif // !TARGET_IPHONE_SIMULATOR 632 633 ondemand_nodename = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); 634 } else if (argc != 0) { 635 SCPrint(TRUE, stderr, CFSTR("Usage: scutil --nc ondemand [-W] [hostname]\n" 636 " scutil --nc ondemand -- --refresh\n")); 637 goto done; 638 } 639 640 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetOnDemand); 641 642 if (ondemand_nodename) { 643 checkOnDemandHost(store, ondemand_nodename, FALSE); 644 checkOnDemandHost(store, ondemand_nodename, TRUE); 645 } else { 646 ondemand_dict = SCDynamicStoreCopyValue(store, key); 647 if (ondemand_dict) { 648 SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), kSCEntNetOnDemand, ondemand_dict); 649 } else { 650 SCPrint(TRUE, stdout, CFSTR("%@ not configured\n"), kSCEntNetOnDemand); 651 } 652 } 653 654 if (ondemandwatch) { 655 CFMutableArrayRef keys = NULL; 656 657 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 658 CFArrayAppendValue(keys, key); 659 SCDynamicStoreSetNotificationKeys(store, keys, NULL); 660 661 my_CFRelease(&keys); 662 663 SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()); 664 665 CFRunLoopRun(); 666 } 667 668 exit_code = 0; 669done: 670 my_CFRelease(&ondemand_dict); 671 my_CFRelease(&key); 672 my_CFRelease(&store); 673 my_CFRelease(&ondemand_nodename); 674 exit(exit_code); 675} 676 677 678/* ----------------------------------------------------------------------------- 679 ----------------------------------------------------------------------------- */ 680CFStringRef 681copy_padded_string(CFStringRef original, int width, CFStringRef prefix, CFStringRef suffix) 682{ 683 CFMutableStringRef padded; 684 685 padded = CFStringCreateMutable(NULL, 0); 686 if (prefix != NULL) { 687 CFStringAppend(padded, prefix); 688 } 689 if (original != NULL) { 690 CFStringAppend(padded, original); 691 } 692 if (suffix != NULL) { 693 CFStringAppend(padded, suffix); 694 } 695 CFStringPad(padded, CFSTR(" "), MAX(CFStringGetLength(original), width), 0); 696 return padded; 697} 698 699CFStringRef 700copy_VPN_status(SCNetworkServiceRef service) 701{ 702 CFStringRef output = NULL; 703 SCNetworkConnectionStatus status = kSCNetworkConnectionInvalid; 704 SCNetworkConnectionRef service_connection = NULL; 705 706 /* Only calculate status is the service is enabled. Default is invalid. */ 707 if (SCNetworkServiceGetEnabled(service)) { 708 service_connection = SCNetworkConnectionCreateWithService(NULL, service, NULL, NULL); 709 if (service_connection == NULL) goto done; 710 status = SCNetworkConnectionGetStatus(service_connection); 711 } 712 713 output = CFStringCreateWithCString(NULL, nc_status_string(status), kCFStringEncodingUTF8); 714 715done: 716 my_CFRelease(&service_connection); 717 return output; 718} 719 720static void 721nc_print_VPN_service(SCNetworkServiceRef service) 722{ 723 SCNetworkInterfaceRef interface = NULL; 724 CFStringRef display_name = NULL; 725 CFStringRef display_name_padded = NULL; 726 CFStringRef service_id = NULL; 727 CFStringRef service_name = NULL; 728 CFStringRef service_name_padded = NULL; 729 CFStringRef service_status = NULL; 730 CFStringRef service_status_padded = NULL; 731 CFStringRef sub_type = NULL; 732 CFStringRef type = NULL; 733 734 nc_get_service_type_and_subtype(service, &type, &sub_type); 735 736 service_name = SCNetworkServiceGetName(service); 737 service_name_padded = copy_padded_string(service_name, 32, CFSTR("\""), CFSTR("\"")); 738 739 service_id = SCNetworkServiceGetServiceID(service); 740 741 interface = SCNetworkServiceGetInterface(service); 742 display_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); 743 display_name_padded = copy_padded_string(display_name, 18, NULL, NULL); 744 745 service_status = copy_VPN_status(service); 746 service_status_padded = copy_padded_string(service_status, 16, CFSTR("("), CFSTR(")")); 747 748 SCPrint(TRUE, 749 stdout, 750 CFSTR("%@ %@ %@ %@ %@ [%@%@%@]\n"), 751 SCNetworkServiceGetEnabled(service) ? CFSTR("*") : CFSTR(" "), 752 service_status_padded, 753 service_id, 754 display_name_padded, 755 service_name_padded, 756 type, 757 (sub_type == NULL) ? CFSTR("") : CFSTR(":"), 758 (sub_type == NULL) ? CFSTR("") : sub_type); 759 760 CFRelease(display_name_padded); 761 CFRelease(service_name_padded); 762 CFRelease(service_status_padded); 763 my_CFRelease(&service_status); 764} 765 766 767/* ----------------------------------------------------------------------------- 768----------------------------------------------------------------------------- */ 769static void 770nc_list(int argc, char **argv) 771{ 772 int count; 773 int i; 774 CFArrayRef services = NULL; 775 776 SCPrint(TRUE, stdout, CFSTR("Available network connection services in the current set (*=enabled):\n")); 777 services = SCNetworkConnectionCopyAvailableServices(NULL); 778 if (services != NULL) { 779 count = CFArrayGetCount(services); 780 781 for (i = 0; i < count; i++) { 782 SCNetworkServiceRef service; 783 784 service = CFArrayGetValueAtIndex(services, i); 785 nc_print_VPN_service(service); 786 } 787 788 } 789 my_CFRelease(&services); 790 exit(0); 791} 792 793/* ----------------------------------------------------------------------------- 794 ----------------------------------------------------------------------------- */ 795static Boolean 796nc_enable_vpntype(CFStringRef vpnType) 797{ 798 Boolean is_enabled = FALSE; 799 Boolean success = FALSE; 800 801 if (vpnType == NULL) { 802 SCPrint(TRUE, stderr, CFSTR("No VPN type provided\n")); 803 goto done; 804 } 805 806 is_enabled = VPNConfigurationIsVPNTypeEnabled(vpnType); 807 808 if (is_enabled) { 809 SCPrint(TRUE, stdout, CFSTR("VPN is already enabled\n")); 810 } else { 811#if !TARGET_OS_IPHONE 812 AuthorizationRef authorization; 813 814 authorization = _prefs_AuthorizationCreate(); 815 if ((authorization == NULL) || 816 !VPNConfigurationSetAuthorization(authorization)) { 817 SCPrint(TRUE, stderr, CFSTR("VPNConfigurationSetAuthorization failed: %s\n"), SCErrorString(SCError())); 818 goto done; 819 } 820#endif // !TARGET_OS_IPHONE 821 822 if (!VPNConfigurationEnableVPNType(vpnType)) { 823 SCPrint(TRUE, stderr, CFSTR("VPN could not be enabled: %s\n"), SCErrorString(SCError())); 824 goto done; 825 } 826 827#if !TARGET_OS_IPHONE 828 _prefs_AuthorizationFree(authorization); 829#endif // !TARGET_OS_IPHONE 830 831 SCPrint(TRUE, stdout, CFSTR("VPN enabled\n")); 832 } 833 success = TRUE; 834 835done: 836 return success; 837} 838 839/* Turns a service ID or name into a vendor type, or preserves type */ 840static CFStringRef 841nc_copy_vendor_type (CFStringRef input) 842{ 843 SCNetworkInterfaceRef child; 844 SCNetworkInterfaceRef interface; 845 CFStringRef output_name = input; 846 SCNetworkServiceRef service = NULL; 847 CFStringRef type; 848 849 if (input == NULL) { 850 goto done; 851 } 852 853 service = nc_copy_service(NULL, input); 854 if (service != NULL) { 855 interface = SCNetworkServiceGetInterface(service); 856 child = SCNetworkInterfaceGetInterface(interface); 857 type = SCNetworkInterfaceGetInterfaceType(interface); 858 859 /* Must be of type VPN */ 860 if (!CFEqual(type, kSCNetworkInterfaceTypeVPN)) { 861 output_name = NULL; 862 goto done; 863 } 864 output_name = SCNetworkInterfaceGetInterfaceType(child); 865 goto done; 866 } 867 868done : 869 if (output_name != NULL) CFRetain(output_name); 870 my_CFRelease(&service); 871 return output_name; 872} 873 874/* ----------------------------------------------------------------------------- 875 ----------------------------------------------------------------------------- */ 876#if !TARGET_OS_IPHONE 877static const CFStringRef PREF_PREFIX = CFSTR("VPN-"); 878static const CFStringRef PREF_SUFFIX = CFSTR(".plist"); 879static void 880nc_set_application_url(CFStringRef subtype, CFStringRef directory) 881{ 882 CFURLRef directory_url = NULL; 883 CFDataRef directory_url_data = NULL; 884 CFStringRef vpnprefpath = NULL; 885 char *path = NULL; 886 CFIndex path_len = 0; 887 888 if (subtype == NULL || directory == NULL) { 889 goto done; 890 } 891 892 directory_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 893 directory, 894 kCFURLPOSIXPathStyle, 895 FALSE); 896 if (directory_url == NULL) { 897 SCPrint(TRUE, stderr, CFSTR("CFURLCreateWithFileSystemPath failed\n")); 898 goto done; 899 } 900 901 directory_url_data = CFURLCreateBookmarkData(NULL, directory_url, 0, 0, 0, 0); 902 if (directory_url_data == NULL) { 903 SCPrint(TRUE, stderr, CFSTR("CFURLCreateBookmarkData failed\n")); 904 goto done; 905 } 906 907 vpnprefpath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@"), PREF_PREFIX, subtype, PREF_SUFFIX ); 908 if (vpnprefpath == NULL) { 909 SCPrint(TRUE, stderr, CFSTR("CFStringCreateWithFormat failed\n")); 910 goto done; 911 } 912 913 path_len = CFStringGetLength(vpnprefpath) + 1; 914 path = malloc(path_len); 915 if (path == NULL) { 916 goto done; 917 } 918 919 if (!CFStringGetCString(vpnprefpath, path, path_len, kCFStringEncodingASCII)) { 920 SCPrint(TRUE, stderr, CFSTR("CFStringGetCString failed\n")); 921 goto done; 922 } 923 924 do_prefs_init(); /* initialization */ 925 do_prefs_open(1, &path); /* open prefs */ 926 927 if (!SCPreferencesSetValue(prefs, CFSTR("ApplicationURL"), directory_url_data)) { 928 SCPrint(TRUE, stderr, 929 CFSTR("SCPreferencesSetValue ApplicationURL failed, %s\n"), 930 SCErrorString(SCError())); 931 goto done; 932 } 933 934 _prefs_save(); 935 936done: 937 my_CFRelease(&directory_url); 938 my_CFRelease(&directory_url_data); 939 my_CFRelease(&vpnprefpath); 940 if (path) { 941 free(path); 942 } 943 _prefs_close(); 944 945 exit(0); 946} 947#endif 948 949/* ----------------------------------------------------------------------------- 950 ----------------------------------------------------------------------------- */ 951static void 952nc_enablevpn(int argc, char **argv) 953{ 954 CFStringRef argument = NULL; 955 CFStringRef vendorType = NULL; 956 int exit_code = 1; 957 958 if (argc == 0) { 959 SCPrint(TRUE, stderr, CFSTR("No service type or ID\n")); 960 } else { 961 argument = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); 962 vendorType = nc_copy_vendor_type(argument); 963 my_CFRelease(&argument); 964 965 if (!nc_enable_vpntype(vendorType)) { 966 goto done; 967 } 968#if !TARGET_OS_IPHONE 969 if (argc >= 2) { 970 argument = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8); 971 nc_set_application_url(vendorType, argument); 972 my_CFRelease(&argument); 973 } 974#endif 975 } 976 977 exit_code = 0; 978 979done: 980 my_CFRelease(&vendorType); 981 exit(exit_code); 982} 983 984 985#if TARGET_OS_EMBEDDED 986static void 987nc_print_VPN_app_info(CFStringRef appInfo, CFDictionaryRef appInfoDict) 988{ 989 CFStringRef appName = NULL; 990 Boolean isEnabled = FALSE; 991 CFStringRef paddedAppInfo = NULL; 992 CFStringRef paddedAppName = NULL; 993 994 if (appInfo == NULL) { 995 return; 996 } 997 998 isEnabled = VPNConfigurationIsVPNTypeEnabled(appInfo); 999 1000 CFDictionaryGetValueIfPresent(appInfoDict, CFSTR("CFBundleDisplayName"), (const void **)&appName); 1001 paddedAppName = copy_padded_string((appName == NULL) ? CFSTR("") : appName, 12, NULL, NULL); 1002 paddedAppInfo = copy_padded_string(appInfo, 30, NULL, NULL); 1003 1004 SCPrint(TRUE, stdout, CFSTR("%@ %@ [%@]\n"), 1005 isEnabled ? CFSTR("(Enabled) ") : CFSTR("(Disabled)"), 1006 paddedAppName, 1007 appInfo); 1008 1009 my_CFRelease(&paddedAppName); 1010 my_CFRelease(&paddedAppInfo); 1011} 1012#endif 1013 1014/* ----------------------------------------------------------------------------- 1015 ----------------------------------------------------------------------------- */ 1016#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR 1017static void 1018nc_listvpn(int argc, char **argv) 1019{ 1020 1021 CFDictionaryRef appDict = NULL; 1022 CFArrayRef appinfo = NULL; 1023 int i, j, count, subtypecount; 1024 const void * * keys = NULL; 1025 CFMutableDictionaryRef optionsDict = NULL; 1026 const void * * values = NULL; 1027 CFStringRef vpntype = NULL; 1028 1029 optionsDict = CFDictionaryCreateMutable(NULL, 0, 1030 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1031 CFDictionarySetValue(optionsDict, kLookupApplicationTypeKey, kApplicationTypeUser); 1032 CFDictionarySetValue(optionsDict, kLookupAttributeKey, CFSTR("UIVPNPlugin")); 1033 1034 appDict = MobileInstallationLookup(optionsDict); 1035 if (!isA_CFDictionary(appDict)) 1036 goto done; 1037 1038 count = CFDictionaryGetCount(appDict); 1039 if (count > 0) { 1040 keys = (const void * *)malloc(sizeof(CFTypeRef) * count); 1041 values = (const void * *)malloc(sizeof(CFTypeRef) * count); 1042 1043 CFDictionaryGetKeysAndValues(appDict, keys, values); 1044 for (i=0; i<count; i++) { 1045 appinfo = CFDictionaryGetValue(values[i], CFSTR("UIVPNPlugin")); 1046 if (appinfo) { 1047 1048 1049 1050 if (isA_CFString(appinfo)) { 1051 nc_print_VPN_app_info((CFStringRef)appinfo, (CFDictionaryRef)values[i]); 1052 } 1053 else if (isA_CFArray(appinfo)) { 1054 subtypecount = CFArrayGetCount((CFArrayRef)appinfo); 1055 for(j=0; j<subtypecount; j++) { 1056 vpntype = (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)appinfo, j); 1057 nc_print_VPN_app_info(vpntype, (CFDictionaryRef)values[i]); 1058 } 1059 } 1060 } 1061 } 1062 } 1063done: 1064 if (keys) free(keys); 1065 if (values) free(values); 1066 my_CFRelease(&optionsDict); 1067 my_CFRelease(&appDict); 1068 1069 exit(0); 1070} 1071#endif // TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR 1072 1073/* ----------------------------------------------------------------------------- 1074----------------------------------------------------------------------------- */ 1075static void 1076nc_show(int argc, char **argv) 1077{ 1078 SCNetworkServiceRef service = NULL; 1079 SCDynamicStoreRef store = NULL; 1080 int exit_code = 1; 1081 CFStringRef serviceID = NULL; 1082 CFStringRef iftype = NULL; 1083 CFStringRef ifsubtype = NULL; 1084 CFStringRef type_entity_key = NULL; 1085 CFStringRef subtype_entity_key = NULL; 1086 CFDictionaryRef type_entity_dict = NULL; 1087 CFDictionaryRef subtype_entity_dict = NULL; 1088 CFStringRef vpnprefpath = NULL; 1089#if !TARGET_OS_IPHONE 1090 CFDataRef bookmarkData = NULL; 1091 CFURLRef directory = NULL; 1092 Boolean isStale = FALSE; 1093 char *path = NULL; 1094 CFIndex path_len = 0; 1095#endif 1096 1097 service = nc_copy_service_from_arguments(argc, argv, NULL); 1098 if (service == NULL) { 1099 SCPrint(TRUE, stderr, CFSTR("No service\n")); 1100 exit(exit_code); 1101 } 1102 1103 serviceID = SCNetworkServiceGetServiceID(service); 1104 1105 nc_get_service_type_and_subtype(service, &iftype, &ifsubtype); 1106 1107 if (!CFEqual(iftype, kSCEntNetPPP) && 1108 !CFEqual(iftype, kSCEntNetIPSec) && 1109 !CFEqual(iftype, kSCEntNetVPN)) { 1110 SCPrint(TRUE, stderr, CFSTR("Not a connection oriented service: %@\n"), serviceID); 1111 goto done; 1112 } 1113 1114 type_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, iftype); 1115 1116 nc_print_VPN_service(service); 1117 1118#if !TARGET_OS_IPHONE 1119 vpnprefpath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@"), PREF_PREFIX, ifsubtype, PREF_SUFFIX); 1120 if (vpnprefpath == NULL) { 1121 goto skipURL; 1122 } 1123 1124 path_len = CFStringGetLength(vpnprefpath) + 1; 1125 path = malloc(path_len); 1126 if (path == NULL) { 1127 goto skipURL; 1128 } 1129 1130 if (!CFStringGetCString(vpnprefpath, path, path_len, kCFStringEncodingASCII)) { 1131 SCPrint(TRUE, stderr, CFSTR("CFStringGetCString failed\n")); 1132 goto done; 1133 } 1134 1135 do_prefs_init(); /* initialization */ 1136 do_prefs_open(1, &path); /* open prefs */ 1137 1138 bookmarkData = SCPreferencesGetValue(prefs, CFSTR("ApplicationURL")); 1139 if (bookmarkData == NULL) { 1140 goto skipURL; 1141 } 1142 1143 directory = CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault, bookmarkData, 0, NULL, NULL, &isStale, NULL); 1144 if (directory == NULL) { 1145 goto skipURL; 1146 } 1147 1148 SCPrint(TRUE, stdout, CFSTR("ApplicationURL: %@\n"), directory); 1149skipURL: 1150#endif 1151 1152 store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL); 1153 if (store == NULL) { 1154 SCPrint(TRUE, stderr, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError())); 1155 goto done; 1156 } 1157 type_entity_dict = SCDynamicStoreCopyValue(store, type_entity_key); 1158 1159 if (!type_entity_dict) { 1160 SCPrint(TRUE, stderr, CFSTR("No \"%@\" configuration available\n"), iftype); 1161 } else { 1162 SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), iftype, type_entity_dict); 1163 } 1164 1165 if (ifsubtype) { 1166 subtype_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, ifsubtype); 1167 subtype_entity_dict = SCDynamicStoreCopyValue(store, subtype_entity_key); 1168 if (!subtype_entity_dict) { 1169 // 1170 } 1171 else { 1172 SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), ifsubtype, subtype_entity_dict); 1173 } 1174 } 1175 1176 exit_code = 0; 1177 1178done: 1179 my_CFRelease(&type_entity_key); 1180 my_CFRelease(&type_entity_dict); 1181 my_CFRelease(&subtype_entity_key); 1182 my_CFRelease(&subtype_entity_dict); 1183 my_CFRelease(&store); 1184 my_CFRelease(&service); 1185 my_CFRelease(&vpnprefpath); 1186 _prefs_close(); 1187 exit(exit_code); 1188} 1189 1190/* ----------------------------------------------------------------------------- 1191 ----------------------------------------------------------------------------- */ 1192static void 1193nc_select(int argc, char **argv) 1194{ 1195 SCNetworkSetRef current_set; 1196 int exit_code = 1; 1197 SCNetworkServiceRef service = NULL; 1198 Boolean status; 1199 1200 do_prefs_init(); /* initialization */ 1201 do_prefs_open(0, NULL); /* open default prefs */ 1202 1203 current_set = SCNetworkSetCopyCurrent(prefs); 1204 if (current_set == NULL) { 1205 SCPrint(TRUE, stderr, CFSTR("No current location\n"), SCErrorString(SCError())); 1206 goto done; 1207 } 1208 1209 service = nc_copy_service_from_arguments(argc, argv, current_set); 1210 if (service == NULL) { 1211 SCPrint(TRUE, stderr, CFSTR("No service\n")); 1212 goto done; 1213 } 1214 1215#if !TARGET_OS_IPHONE 1216 status = SCNetworkServiceSetEnabled(service, TRUE); 1217 if (!status) { 1218 SCPrint(TRUE, stderr, CFSTR("Unable to enable service: %s\n"), SCErrorString(SCError())); 1219 goto done; 1220 } 1221#else 1222 status = SCNetworkSetSetSelectedVPNService(current_set, service); 1223 if (!status) { 1224 SCPrint(TRUE, stderr, CFSTR("Unable to select service: %s\n"), SCErrorString(SCError())); 1225 goto done; 1226 } 1227#endif 1228 1229 _prefs_save(); 1230 exit_code = 0; 1231done: 1232 my_CFRelease(&service); 1233 my_CFRelease(¤t_set); 1234 _prefs_close(); 1235 exit(exit_code); 1236} 1237 1238/* ----------------------------------------------------------------------------- 1239 ----------------------------------------------------------------------------- */ 1240static void 1241nc_help(int argc, char **argv) 1242{ 1243 SCPrint(TRUE, stderr, CFSTR("Valid commands for scutil --nc (VPN connections)\n")); 1244 SCPrint(TRUE, stderr, CFSTR("Usage: scutil --nc [command]\n")); 1245 SCPrint(TRUE, stderr, CFSTR("\n")); 1246 SCPrint(TRUE, stderr, CFSTR("\tlist\n")); 1247 SCPrint(TRUE, stderr, CFSTR("\t\tList available network connection services in the current set\n")); 1248 SCPrint(TRUE, stderr, CFSTR("\n")); 1249 SCPrint(TRUE, stderr, CFSTR("\tstatus <service>\n")); 1250 SCPrint(TRUE, stderr, CFSTR("\t\tIndicate whether a given service is connected, as well as extended status information for the service\n")); 1251 SCPrint(TRUE, stderr, CFSTR("\n")); 1252 SCPrint(TRUE, stderr, CFSTR("\tshow <service>\n")); 1253 SCPrint(TRUE, stderr, CFSTR("\t\tDisplay configuration information for a given service\n")); 1254 SCPrint(TRUE, stderr, CFSTR("\n")); 1255 SCPrint(TRUE, stderr, CFSTR("\tstatistics <service>\n")); 1256 SCPrint(TRUE, stderr, CFSTR("\t\tProvide statistics on bytes, packets, and errors for a given service\n")); 1257 SCPrint(TRUE, stderr, CFSTR("\n")); 1258 SCPrint(TRUE, stderr, CFSTR("\tselect <service>\n")); 1259 SCPrint(TRUE, stderr, CFSTR("\t\tMake the given service active in the current set. This allows it to be started\n")); 1260 SCPrint(TRUE, stderr, CFSTR("\n")); 1261 SCPrint(TRUE, stderr, CFSTR("\tstart <service> [--user user] [--password password] [--secret secret]\n")); 1262 SCPrint(TRUE, stderr, CFSTR("\t\tStart a given service. Can take optional arguments for user, password, and secret\n")); 1263 SCPrint(TRUE, stderr, CFSTR("\n")); 1264 SCPrint(TRUE, stderr, CFSTR("\tstop <service>\n")); 1265 SCPrint(TRUE, stderr, CFSTR("\t\tStop a given service\n")); 1266 SCPrint(TRUE, stderr, CFSTR("\n")); 1267 SCPrint(TRUE, stderr, CFSTR("\tsuspend <service>\n")); 1268 SCPrint(TRUE, stderr, CFSTR("\t\tSuspend a given service (PPP, Modem on Hold)\n")); 1269 SCPrint(TRUE, stderr, CFSTR("\n")); 1270 SCPrint(TRUE, stderr, CFSTR("\tresume <service>\n")); 1271 SCPrint(TRUE, stderr, CFSTR("\t\tResume a given service (PPP, Modem on Hold)\n")); 1272 SCPrint(TRUE, stderr, CFSTR("\n")); 1273 SCPrint(TRUE, stderr, CFSTR("\tondemand [-W] [hostname]\n")); 1274 SCPrint(TRUE, stderr, CFSTR("\tondemand -- --refresh\n")); 1275 SCPrint(TRUE, stderr, CFSTR("\t\tDisplay VPN on-demand information\n")); 1276 SCPrint(TRUE, stderr, CFSTR("\n")); 1277 SCPrint(TRUE, stderr, CFSTR("\ttrigger <hostname> [background] [port]\n")); 1278 SCPrint(TRUE, stderr, CFSTR("\t\tTrigger VPN on-demand with specified hostname, and optional port and background flag\n")); 1279 SCPrint(TRUE, stderr, CFSTR("\n")); 1280#if TARGET_OS_EMBEDDED 1281 SCPrint(TRUE, stderr, CFSTR("\tlistvpn\n")); 1282 SCPrint(TRUE, stderr, CFSTR("\t\tDisplay the installed VPN applications\n")); 1283 SCPrint(TRUE, stderr, CFSTR("\n")); 1284#endif 1285#if !TARGET_OS_IPHONE 1286 SCPrint(TRUE, stderr, CFSTR("\tenablevpn <service or vpn type> [path]\n")); 1287 SCPrint(TRUE, stderr, CFSTR("\t\tEnables the given VPN application type. Takes either a service or VPN type. Pass a path to set ApplicationURL\n")); 1288 SCPrint(TRUE, stderr, CFSTR("\n")); 1289#else 1290 SCPrint(TRUE, stderr, CFSTR("\tenablevpn <service or vpn type>\n")); 1291 SCPrint(TRUE, stderr, CFSTR("\t\tEnables the given VPN application type. Takes either a service or VPN type\n")); 1292 SCPrint(TRUE, stderr, CFSTR("\n")); 1293#endif 1294 SCPrint(TRUE, stderr, CFSTR("\tdisablevpn <service or vpn type>\n")); 1295 SCPrint(TRUE, stderr, CFSTR("\t\tDisables the given VPN application type. Takes either a service or VPN type\n")); 1296 SCPrint(TRUE, stderr, CFSTR("\n")); 1297 SCPrint(TRUE, stderr, CFSTR("\thelp\n")); 1298 SCPrint(TRUE, stderr, CFSTR("\t\tDisplay available commands for --nc\n")); 1299 SCPrint(TRUE, stderr, CFSTR("\n")); 1300 exit(0); 1301} 1302 1303/* ----------------------------------------------------------------------------- 1304----------------------------------------------------------------------------- */ 1305typedef void (*nc_func) (int argc, char **argv); 1306 1307static const struct { 1308 char *cmd; 1309 nc_func func; 1310} nc_cmds[] = { 1311 { "enablevpn", nc_enablevpn }, 1312 { "help", nc_help }, 1313 { "list", nc_list }, 1314#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR 1315 { "listvpn", nc_listvpn }, 1316#endif // TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR 1317 { "ondemand", nc_ondemand }, 1318 { "resume", nc_resume }, 1319 { "select", nc_select }, 1320 { "show", nc_show }, 1321 { "start", nc_start }, 1322 { "statistics", nc_statistics }, 1323 { "status", nc_status }, 1324 { "stop", nc_stop }, 1325 { "suspend", nc_suspend }, 1326 { "trigger", nc_trigger }, 1327}; 1328#define N_NC_CMNDS (sizeof(nc_cmds) / sizeof(nc_cmds[0])) 1329 1330 1331/* ----------------------------------------------------------------------------- 1332----------------------------------------------------------------------------- */ 1333int 1334find_nc_cmd(char *cmd) 1335{ 1336 int i; 1337 1338 for (i = 0; i < (int)N_NC_CMNDS; i++) { 1339 if (strcmp(cmd, nc_cmds[i].cmd) == 0) { 1340 return i; 1341 } 1342 } 1343 1344 return -1; 1345} 1346 1347 1348/* ----------------------------------------------------------------------------- 1349----------------------------------------------------------------------------- */ 1350void 1351do_nc_cmd(char *cmd, int argc, char **argv, Boolean watch) 1352{ 1353 int i; 1354 1355 i = find_nc_cmd(cmd); 1356 if (i >= 0) { 1357 nc_func func; 1358 1359 func = nc_cmds[i].func; 1360 if (watch) { 1361 if (func == nc_status) { 1362 func = nc_watch; 1363 } else if (func == nc_ondemand) { 1364 ondemandwatch = TRUE; 1365 } 1366 } 1367 (*func)(argc, argv); 1368 } 1369 return; 1370} 1371 1372