2 * Copyright (c) 2010-2013 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * March 1, 2010 Christophe Allie <callie@apple.com>
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
44 #include <SystemConfiguration/VPNConfiguration.h>
46 #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
47 #include <MobileInstallation/MobileInstallation.h>
48 #endif // TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
52 CFStringRef username
= NULL
;
53 CFStringRef password
= NULL
;
54 CFStringRef sharedsecret
= NULL
;
56 static Boolean ondemandwatch
= FALSE
;
57 static CFStringRef ondemand_nodename
= NULL
;
59 static SCNetworkConnectionRef connection
= NULL
;
60 static int n_callback
= 0;
63 /* -----------------------------------------------------------------------------
64 ----------------------------------------------------------------------------- */
68 void * * obj
= (void * *)t
;
76 /* -----------------------------------------------------------------------------
77 ----------------------------------------------------------------------------- */
79 nc_get_service_type_and_subtype(SCNetworkServiceRef service
, CFStringRef
*iftype
, CFStringRef
*ifsubtype
) {
80 SCNetworkInterfaceRef interface
= SCNetworkServiceGetInterface(service
);
81 SCNetworkInterfaceRef child
= SCNetworkInterfaceGetInterface(interface
);
83 *iftype
= SCNetworkInterfaceGetInterfaceType(interface
);
85 if (CFEqual(*iftype
, kSCNetworkInterfaceTypePPP
) ||
86 CFEqual(*iftype
, kSCNetworkInterfaceTypeVPN
)) {
87 *ifsubtype
= (child
!= NULL
) ? SCNetworkInterfaceGetInterfaceType(child
) : NULL
;
91 /* -----------------------------------------------------------------------------
92 ----------------------------------------------------------------------------- */
93 static SCNetworkServiceRef
94 nc_copy_service(SCNetworkSetRef set
, CFStringRef identifier
)
98 SCNetworkServiceRef selected
= NULL
;
101 services
= SCNetworkConnectionCopyAvailableServices(set
);
102 if (services
== NULL
) {
106 n
= CFArrayGetCount(services
);
108 // try to select the service by its serviceID
109 for (i
= 0; i
< n
; i
++) {
110 SCNetworkServiceRef service
= NULL
;
111 CFStringRef serviceID
;
113 service
= CFArrayGetValueAtIndex(services
, i
);
114 serviceID
= SCNetworkServiceGetServiceID(service
);
115 if (CFEqual(identifier
, serviceID
)) {
121 // try to select the service by service name
122 for (i
= 0; i
< n
; i
++) {
123 SCNetworkServiceRef service
= NULL
;
124 CFStringRef serviceName
;
126 service
= CFArrayGetValueAtIndex(services
, i
);
127 serviceName
= SCNetworkServiceGetName(service
);
128 if ((serviceName
!= NULL
) && CFEqual(identifier
, serviceName
)) {
129 if (selected
== NULL
) {
132 // if multiple services match
134 SCPrint(TRUE
, stderr
, CFSTR("Multiple services match\n"));
142 if (selected
!= NULL
) CFRetain(selected
);
143 if (services
!= NULL
) CFRelease(services
);
147 /* -----------------------------------------------------------------------------
148 ----------------------------------------------------------------------------- */
149 static SCNetworkServiceRef
150 nc_copy_service_from_arguments(int argc
, char **argv
, SCNetworkSetRef set
) {
151 CFStringRef serviceID
= NULL
;
152 SCNetworkServiceRef service
= NULL
;
155 serviceID
= _copyStringFromSTDIN(CFSTR("Service"), NULL
);
157 serviceID
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
159 if (serviceID
== NULL
) {
160 SCPrint(TRUE
, stderr
, CFSTR("No service ID specified\n"));
163 service
= nc_copy_service(set
, serviceID
);
164 my_CFRelease(&serviceID
);
169 /* -----------------------------------------------------------------------------
170 ----------------------------------------------------------------------------- */
172 nc_status_string(SCNetworkConnectionStatus status
)
175 case kSCNetworkConnectionInvalid
:
177 case kSCNetworkConnectionDisconnected
:
178 return "Disconnected";
179 case kSCNetworkConnectionConnecting
:
181 case kSCNetworkConnectionConnected
:
183 case kSCNetworkConnectionDisconnecting
:
184 return "Disconnecting";
190 nc_callback(SCNetworkConnectionRef connection
, SCNetworkConnectionStatus status
, void *info
)
192 int *n
= (int *)info
;
193 CFDictionaryRef status_dict
;
198 SCPrint(TRUE
, stdout
, CFSTR("Current status = "));
201 struct timeval tv_now
;
203 (void)gettimeofday(&tv_now
, NULL
);
204 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
206 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
210 tv_now
.tv_usec
/ 1000);
211 SCPrint(TRUE
, stdout
, CFSTR("Callback (%d) status = "), *n
);
215 SCPrint(TRUE
, stdout
, CFSTR("%s%s%s\n"),
216 nc_status_string(status
),
217 (status
== kSCNetworkConnectionInvalid
) ? ": " : "",
218 (status
== kSCNetworkConnectionInvalid
) ? SCErrorString(SCError()) : "");
220 // report extended status
221 status_dict
= SCNetworkConnectionCopyExtendedStatus(connection
);
223 SCPrint(TRUE
, stdout
, CFSTR("Extended Status %@\n"), status_dict
);
224 CFRelease(status_dict
);
231 nc_create_connection(int argc
, char **argv
, Boolean exit_on_failure
)
233 SCNetworkConnectionContext context
= { 0, &n_callback
, NULL
, NULL
, NULL
};
234 SCNetworkServiceRef service
;
236 service
= nc_copy_service_from_arguments(argc
, argv
, NULL
);
237 if (service
== NULL
) {
238 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
244 connection
= SCNetworkConnectionCreateWithService(NULL
, service
, nc_callback
, &context
);
246 if (connection
== NULL
) {
247 SCPrint(TRUE
, stderr
, CFSTR("Could not create connection: %s\n"), SCErrorString(SCError()));
254 /* -----------------------------------------------------------------------------
255 ----------------------------------------------------------------------------- */
258 nc_trigger(int argc
, char **argv
)
260 Boolean background
= FALSE
;
262 CFStringRef hostName
= NULL
;
265 for (i
= 0; i
< 3 && i
< argc
; i
++) {
266 /* Parse host name. Must be first arg. */
268 hostName
= CFStringCreateWithCString(NULL
, argv
[i
], kCFStringEncodingUTF8
);
272 /* Check for optional background flag */
273 if (strcmp(argv
[i
], "background") == 0) {
278 /* Parse optional port number */
279 CFStringRef str
= CFStringCreateWithCString(NULL
, argv
[i
], kCFStringEncodingUTF8
);
281 int num
= CFStringGetIntValue(str
);
290 CFReadStreamRef readStream
= NULL
;
291 CFWriteStreamRef writeStream
= NULL
;
293 CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault
, hostName
, port
, &readStream
, &writeStream
);
296 CFReadStreamSetProperty(readStream
, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground"));
297 CFWriteStreamSetProperty(writeStream
, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground"));
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" : "");
307 my_CFRelease(&readStream
);
308 my_CFRelease(&writeStream
);
310 SCPrint(TRUE
, stderr
, CFSTR("Invalid or missing host name\n"));
313 my_CFRelease(&hostName
);
318 /* -----------------------------------------------------------------------------
319 ----------------------------------------------------------------------------- */
321 nc_release_connection()
323 my_CFRelease(&connection
);
326 /* -----------------------------------------------------------------------------
327 ----------------------------------------------------------------------------- */
329 nc_start(int argc
, char **argv
)
331 CFMutableDictionaryRef userOptions
= NULL
;
332 CFStringRef iftype
= NULL
;
333 CFStringRef ifsubtype
= NULL
;
334 SCNetworkServiceRef service
= NULL
;
336 nc_create_connection(argc
, argv
, TRUE
);
338 service
= SCNetworkConnectionGetService(connection
);
339 nc_get_service_type_and_subtype(service
, &iftype
, &ifsubtype
);
341 userOptions
= CFDictionaryCreateMutable(NULL
, 0,
342 &kCFTypeDictionaryKeyCallBacks
,
343 &kCFTypeDictionaryValueCallBacks
);
345 Boolean isL2TP
= (CFEqual(iftype
, kSCEntNetPPP
) &&
346 (ifsubtype
!= NULL
) && CFEqual(ifsubtype
, kSCValNetInterfaceSubTypeL2TP
));
348 if (CFEqual(iftype
, kSCEntNetPPP
)) {
349 CFMutableDictionaryRef pppEntity
= CFDictionaryCreateMutable(NULL
, 0,
350 &kCFTypeDictionaryKeyCallBacks
,
351 &kCFTypeDictionaryValueCallBacks
);
353 if (username
!= NULL
) {
354 CFDictionarySetValue(pppEntity
, kSCPropNetPPPAuthName
, username
);
356 if (password
!= NULL
) {
357 CFDictionarySetValue(pppEntity
, kSCPropNetPPPAuthPassword
, password
);
359 CFDictionarySetValue(userOptions
, kSCEntNetPPP
, pppEntity
);
360 my_CFRelease(&pppEntity
);
362 if (CFEqual(iftype
, kSCEntNetIPSec
) || isL2TP
) {
363 CFMutableDictionaryRef ipsecEntity
= CFDictionaryCreateMutable(NULL
, 0,
364 &kCFTypeDictionaryKeyCallBacks
,
365 &kCFTypeDictionaryValueCallBacks
);
367 if (username
!= NULL
) {
368 CFDictionarySetValue(ipsecEntity
, kSCPropNetIPSecXAuthName
, username
);
370 if (password
!= NULL
) {
371 CFDictionarySetValue(ipsecEntity
, kSCPropNetIPSecXAuthPassword
, password
);
374 if (sharedsecret
!= NULL
) {
375 CFDictionarySetValue(ipsecEntity
, kSCPropNetIPSecSharedSecret
, sharedsecret
);
377 CFDictionarySetValue(userOptions
, kSCEntNetIPSec
, ipsecEntity
);
378 my_CFRelease(&ipsecEntity
);
380 if (CFEqual(iftype
, kSCEntNetVPN
)) {
381 CFMutableDictionaryRef vpnEntity
= CFDictionaryCreateMutable(NULL
, 0,
382 &kCFTypeDictionaryKeyCallBacks
,
383 &kCFTypeDictionaryValueCallBacks
);
384 if (username
!= NULL
) {
385 CFDictionarySetValue(vpnEntity
, kSCPropNetVPNAuthName
, username
);
387 if (password
!= NULL
) {
388 CFDictionarySetValue(vpnEntity
, kSCPropNetVPNAuthPassword
, password
);
390 CFDictionarySetValue(userOptions
, kSCEntNetVPN
, vpnEntity
);
391 my_CFRelease(&vpnEntity
);
393 // If it doesn't match any VPN type, fail silently
395 if (!SCNetworkConnectionStart(connection
, userOptions
, TRUE
)) {
396 SCPrint(TRUE
, stderr
, CFSTR("Could not start connection: %s\n"), SCErrorString(SCError()));
400 CFRelease(userOptions
);
401 nc_release_connection();
405 /* -----------------------------------------------------------------------------
406 ----------------------------------------------------------------------------- */
408 nc_stop(int argc
, char **argv
)
410 nc_create_connection(argc
, argv
, TRUE
);
412 if (!SCNetworkConnectionStop(connection
, TRUE
)) {
413 SCPrint(TRUE
, stderr
, CFSTR("Could not stop connection: %s\n"), SCErrorString(SCError()));
417 nc_release_connection();
421 /* -----------------------------------------------------------------------------
422 ----------------------------------------------------------------------------- */
424 nc_suspend(int argc
, char **argv
)
426 nc_create_connection(argc
, argv
, TRUE
);
428 SCNetworkConnectionSuspend(connection
);
430 nc_release_connection();
434 /* -----------------------------------------------------------------------------
435 ----------------------------------------------------------------------------- */
437 nc_resume(int argc
, char **argv
)
439 nc_create_connection(argc
, argv
, TRUE
);
441 SCNetworkConnectionResume(connection
);
443 nc_release_connection();
447 /* -----------------------------------------------------------------------------
448 ----------------------------------------------------------------------------- */
450 nc_status(int argc
, char **argv
)
452 SCNetworkConnectionStatus status
;
454 nc_create_connection(argc
, argv
, TRUE
);
456 status
= SCNetworkConnectionGetStatus(connection
);
457 nc_callback(connection
, status
, NULL
);
459 nc_release_connection();
464 nc_watch(int argc
, char **argv
)
466 SCNetworkConnectionStatus status
;
468 nc_create_connection(argc
, argv
, TRUE
);
470 status
= SCNetworkConnectionGetStatus(connection
);
472 // report initial status
474 nc_callback(connection
, status
, &n_callback
);
478 if (!SCNetworkConnectionSetDispatchQueue(connection
, dispatch_get_main_queue())) {
479 SCPrint(TRUE
, stderr
, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError()));
483 if (!SCNetworkConnectionScheduleWithRunLoop(connection
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
484 SCPrint(TRUE
, stderr
, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError()));
492 nc_release_connection();
496 /* -----------------------------------------------------------------------------
497 ----------------------------------------------------------------------------- */
499 nc_statistics(int argc
, char **argv
)
501 CFDictionaryRef stats_dict
;
503 nc_create_connection(argc
, argv
, TRUE
);
505 stats_dict
= SCNetworkConnectionCopyStatistics(connection
);
508 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), stats_dict
);
510 SCPrint(TRUE
, stdout
, CFSTR("No statistics available\n"));
513 my_CFRelease(&stats_dict
);
515 nc_release_connection();
519 /* -----------------------------------------------------------------------------
520 ----------------------------------------------------------------------------- */
522 checkOnDemandHost(SCDynamicStoreRef store
, CFStringRef nodeName
, Boolean retry
)
525 CFStringRef connectionServiceID
= NULL
;
526 SCNetworkConnectionStatus connectionStatus
= 0;
527 CFStringRef vpnRemoteAddress
= NULL
;
529 SCPrint(TRUE
, stdout
, CFSTR("OnDemand host/domain check (%sretry)\n"), retry
? "" : "no ");
531 ok
= __SCNetworkConnectionCopyOnDemandInfoWithName(&store
,
534 &connectionServiceID
,
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()));
547 SCPrint(TRUE
, stdout
, CFSTR(" no match\n"));
550 if (connectionServiceID
!= NULL
) {
551 CFRelease(connectionServiceID
);
552 connectionServiceID
= NULL
;
554 if (vpnRemoteAddress
!= NULL
) {
555 CFRelease(vpnRemoteAddress
);
556 vpnRemoteAddress
= NULL
;
563 nc_ondemand_callback(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
)
565 CFStringRef key
= NULL
;
566 CFDictionaryRef ondemand_dict
= NULL
;
568 struct timeval tv_now
;
570 if (CFArrayGetCount(changedKeys
) < 1) {
574 (void)gettimeofday(&tv_now
, NULL
);
575 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
577 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
581 tv_now
.tv_usec
/ 1000);
583 if (ondemand_nodename
) {
584 checkOnDemandHost(store
, ondemand_nodename
, FALSE
);
585 checkOnDemandHost(store
, ondemand_nodename
, TRUE
);
587 key
= CFArrayGetValueAtIndex(changedKeys
, 0);
589 ondemand_dict
= SCDynamicStoreCopyValue(store
, key
);
591 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), kSCEntNetOnDemand
, ondemand_dict
);
593 SCPrint(TRUE
, stdout
, CFSTR("%@ not configured\n"), kSCEntNetOnDemand
);
596 my_CFRelease(&ondemand_dict
);
601 nc_ondemand(int argc
, char **argv
)
604 CFStringRef key
= NULL
;
605 CFDictionaryRef ondemand_dict
= NULL
;
606 SCDynamicStoreRef store
;
608 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil --nc"), nc_ondemand_callback
, NULL
);
610 SCPrint(TRUE
, stderr
, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError()));
615 #if !TARGET_IPHONE_SIMULATOR
616 if (strcmp("--refresh", argv
[0]) == 0) {
617 SCNetworkConnectionRef connection
= NULL
;
619 connection
= SCNetworkConnectionCreate(kCFAllocatorDefault
, NULL
, NULL
);
620 if (connection
&& SCNetworkConnectionRefreshOnDemandState(connection
)) {
625 SCPrint(TRUE
, stderr
, CFSTR("Unable to refresh OnDemand state: %s\n"), SCErrorString(SCError()));
628 my_CFRelease(&connection
);
631 #endif // !TARGET_IPHONE_SIMULATOR
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"));
640 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetOnDemand
);
642 if (ondemand_nodename
) {
643 checkOnDemandHost(store
, ondemand_nodename
, FALSE
);
644 checkOnDemandHost(store
, ondemand_nodename
, TRUE
);
646 ondemand_dict
= SCDynamicStoreCopyValue(store
, key
);
648 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), kSCEntNetOnDemand
, ondemand_dict
);
650 SCPrint(TRUE
, stdout
, CFSTR("%@ not configured\n"), kSCEntNetOnDemand
);
655 CFMutableArrayRef keys
= NULL
;
657 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
658 CFArrayAppendValue(keys
, key
);
659 SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
663 SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue());
670 my_CFRelease(&ondemand_dict
);
672 my_CFRelease(&store
);
673 my_CFRelease(&ondemand_nodename
);
678 /* -----------------------------------------------------------------------------
679 ----------------------------------------------------------------------------- */
681 copy_padded_string(CFStringRef original
, int width
, CFStringRef prefix
, CFStringRef suffix
)
683 CFMutableStringRef padded
;
685 padded
= CFStringCreateMutable(NULL
, 0);
686 if (prefix
!= NULL
) {
687 CFStringAppend(padded
, prefix
);
689 if (original
!= NULL
) {
690 CFStringAppend(padded
, original
);
692 if (suffix
!= NULL
) {
693 CFStringAppend(padded
, suffix
);
695 CFStringPad(padded
, CFSTR(" "), MAX(CFStringGetLength(original
), width
), 0);
700 copy_VPN_status(SCNetworkServiceRef service
)
702 CFStringRef output
= NULL
;
703 SCNetworkConnectionStatus status
= kSCNetworkConnectionInvalid
;
704 SCNetworkConnectionRef service_connection
= NULL
;
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
);
713 output
= CFStringCreateWithCString(NULL
, nc_status_string(status
), kCFStringEncodingUTF8
);
716 my_CFRelease(&service_connection
);
721 nc_print_VPN_service(SCNetworkServiceRef service
)
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
;
734 nc_get_service_type_and_subtype(service
, &type
, &sub_type
);
736 service_name
= SCNetworkServiceGetName(service
);
737 service_name_padded
= copy_padded_string(service_name
, 32, CFSTR("\""), CFSTR("\""));
739 service_id
= SCNetworkServiceGetServiceID(service
);
741 interface
= SCNetworkServiceGetInterface(service
);
742 display_name
= SCNetworkInterfaceGetLocalizedDisplayName(interface
);
743 display_name_padded
= copy_padded_string(display_name
, 18, NULL
, NULL
);
745 service_status
= copy_VPN_status(service
);
746 service_status_padded
= copy_padded_string(service_status
, 16, CFSTR("("), CFSTR(")"));
750 CFSTR("%@ %@ %@ %@ %@ [%@%@%@]\n"),
751 SCNetworkServiceGetEnabled(service
) ? CFSTR("*") : CFSTR(" "),
752 service_status_padded
,
757 (sub_type
== NULL
) ? CFSTR("") : CFSTR(":"),
758 (sub_type
== NULL
) ? CFSTR("") : sub_type
);
760 CFRelease(display_name_padded
);
761 CFRelease(service_name_padded
);
762 CFRelease(service_status_padded
);
763 my_CFRelease(&service_status
);
767 /* -----------------------------------------------------------------------------
768 ----------------------------------------------------------------------------- */
770 nc_list(int argc
, char **argv
)
774 CFArrayRef services
= NULL
;
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
);
781 for (i
= 0; i
< count
; i
++) {
782 SCNetworkServiceRef service
;
784 service
= CFArrayGetValueAtIndex(services
, i
);
785 nc_print_VPN_service(service
);
789 my_CFRelease(&services
);
793 /* -----------------------------------------------------------------------------
794 ----------------------------------------------------------------------------- */
796 nc_enable_vpntype(CFStringRef vpnType
)
798 Boolean is_enabled
= FALSE
;
799 Boolean success
= FALSE
;
801 if (vpnType
== NULL
) {
802 SCPrint(TRUE
, stderr
, CFSTR("No VPN type provided\n"));
806 is_enabled
= VPNConfigurationIsVPNTypeEnabled(vpnType
);
809 SCPrint(TRUE
, stdout
, CFSTR("VPN is already enabled\n"));
811 #if !TARGET_OS_IPHONE
812 AuthorizationRef authorization
;
814 authorization
= _prefs_AuthorizationCreate();
815 if ((authorization
== NULL
) ||
816 !VPNConfigurationSetAuthorization(authorization
)) {
817 SCPrint(TRUE
, stderr
, CFSTR("VPNConfigurationSetAuthorization failed: %s\n"), SCErrorString(SCError()));
820 #endif // !TARGET_OS_IPHONE
822 if (!VPNConfigurationEnableVPNType(vpnType
)) {
823 SCPrint(TRUE
, stderr
, CFSTR("VPN could not be enabled: %s\n"), SCErrorString(SCError()));
827 #if !TARGET_OS_IPHONE
828 _prefs_AuthorizationFree(authorization
);
829 #endif // !TARGET_OS_IPHONE
831 SCPrint(TRUE
, stdout
, CFSTR("VPN enabled\n"));
839 /* Turns a service ID or name into a vendor type, or preserves type */
841 nc_copy_vendor_type (CFStringRef input
)
843 SCNetworkInterfaceRef child
;
844 SCNetworkInterfaceRef interface
;
845 CFStringRef output_name
= input
;
846 SCNetworkServiceRef service
= NULL
;
853 service
= nc_copy_service(NULL
, input
);
854 if (service
!= NULL
) {
855 interface
= SCNetworkServiceGetInterface(service
);
856 child
= SCNetworkInterfaceGetInterface(interface
);
857 type
= SCNetworkInterfaceGetInterfaceType(interface
);
859 /* Must be of type VPN */
860 if (!CFEqual(type
, kSCNetworkInterfaceTypeVPN
)) {
864 output_name
= SCNetworkInterfaceGetInterfaceType(child
);
869 if (output_name
!= NULL
) CFRetain(output_name
);
870 my_CFRelease(&service
);
874 /* -----------------------------------------------------------------------------
875 ----------------------------------------------------------------------------- */
876 #if !TARGET_OS_IPHONE
877 static const CFStringRef PREF_PREFIX
= CFSTR("VPN-");
878 static const CFStringRef PREF_SUFFIX
= CFSTR(".plist");
880 nc_set_application_url(CFStringRef subtype
, CFStringRef directory
)
882 CFURLRef directory_url
= NULL
;
883 CFDataRef directory_url_data
= NULL
;
884 CFStringRef vpnprefpath
= NULL
;
886 CFIndex path_len
= 0;
888 if (subtype
== NULL
|| directory
== NULL
) {
892 directory_url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
,
894 kCFURLPOSIXPathStyle
,
896 if (directory_url
== NULL
) {
897 SCPrint(TRUE
, stderr
, CFSTR("CFURLCreateWithFileSystemPath failed\n"));
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"));
907 vpnprefpath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@"), PREF_PREFIX
, subtype
, PREF_SUFFIX
);
908 if (vpnprefpath
== NULL
) {
909 SCPrint(TRUE
, stderr
, CFSTR("CFStringCreateWithFormat failed\n"));
913 path_len
= CFStringGetLength(vpnprefpath
) + 1;
914 path
= malloc(path_len
);
919 if (!CFStringGetCString(vpnprefpath
, path
, path_len
, kCFStringEncodingASCII
)) {
920 SCPrint(TRUE
, stderr
, CFSTR("CFStringGetCString failed\n"));
924 do_prefs_init(); /* initialization */
925 do_prefs_open(1, &path
); /* open prefs */
927 if (!SCPreferencesSetValue(prefs
, CFSTR("ApplicationURL"), directory_url_data
)) {
928 SCPrint(TRUE
, stderr
,
929 CFSTR("SCPreferencesSetValue ApplicationURL failed, %s\n"),
930 SCErrorString(SCError()));
937 my_CFRelease(&directory_url
);
938 my_CFRelease(&directory_url_data
);
939 my_CFRelease(&vpnprefpath
);
949 /* -----------------------------------------------------------------------------
950 ----------------------------------------------------------------------------- */
952 nc_enablevpn(int argc
, char **argv
)
954 CFStringRef argument
= NULL
;
955 CFStringRef vendorType
= NULL
;
959 SCPrint(TRUE
, stderr
, CFSTR("No service type or ID\n"));
961 argument
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
962 vendorType
= nc_copy_vendor_type(argument
);
963 my_CFRelease(&argument
);
965 if (!nc_enable_vpntype(vendorType
)) {
968 #if !TARGET_OS_IPHONE
970 argument
= CFStringCreateWithCString(NULL
, argv
[1], kCFStringEncodingUTF8
);
971 nc_set_application_url(vendorType
, argument
);
972 my_CFRelease(&argument
);
980 my_CFRelease(&vendorType
);
985 #if TARGET_OS_EMBEDDED
987 nc_print_VPN_app_info(CFStringRef appInfo
, CFDictionaryRef appInfoDict
)
989 CFStringRef appName
= NULL
;
990 Boolean isEnabled
= FALSE
;
991 CFStringRef paddedAppInfo
= NULL
;
992 CFStringRef paddedAppName
= NULL
;
994 if (appInfo
== NULL
) {
998 isEnabled
= VPNConfigurationIsVPNTypeEnabled(appInfo
);
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
);
1004 SCPrint(TRUE
, stdout
, CFSTR("%@ %@ [%@]\n"),
1005 isEnabled
? CFSTR("(Enabled) ") : CFSTR("(Disabled)"),
1009 my_CFRelease(&paddedAppName
);
1010 my_CFRelease(&paddedAppInfo
);
1014 /* -----------------------------------------------------------------------------
1015 ----------------------------------------------------------------------------- */
1016 #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
1018 nc_listvpn(int argc
, char **argv
)
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
;
1029 optionsDict
= CFDictionaryCreateMutable(NULL
, 0,
1030 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1031 CFDictionarySetValue(optionsDict
, kLookupApplicationTypeKey
, kApplicationTypeUser
);
1032 CFDictionarySetValue(optionsDict
, kLookupAttributeKey
, CFSTR("UIVPNPlugin"));
1034 appDict
= MobileInstallationLookup(optionsDict
);
1035 if (!isA_CFDictionary(appDict
))
1038 count
= CFDictionaryGetCount(appDict
);
1040 keys
= (const void * *)malloc(sizeof(CFTypeRef
) * count
);
1041 values
= (const void * *)malloc(sizeof(CFTypeRef
) * count
);
1043 CFDictionaryGetKeysAndValues(appDict
, keys
, values
);
1044 for (i
=0; i
<count
; i
++) {
1045 appinfo
= CFDictionaryGetValue(values
[i
], CFSTR("UIVPNPlugin"));
1050 if (isA_CFString(appinfo
)) {
1051 nc_print_VPN_app_info((CFStringRef
)appinfo
, (CFDictionaryRef
)values
[i
]);
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
]);
1064 if (keys
) free(keys
);
1065 if (values
) free(values
);
1066 my_CFRelease(&optionsDict
);
1067 my_CFRelease(&appDict
);
1071 #endif // TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
1073 /* -----------------------------------------------------------------------------
1074 ----------------------------------------------------------------------------- */
1076 nc_show(int argc
, char **argv
)
1078 SCNetworkServiceRef service
= NULL
;
1079 SCDynamicStoreRef store
= NULL
;
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
;
1094 CFIndex path_len
= 0;
1097 service
= nc_copy_service_from_arguments(argc
, argv
, NULL
);
1098 if (service
== NULL
) {
1099 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
1103 serviceID
= SCNetworkServiceGetServiceID(service
);
1105 nc_get_service_type_and_subtype(service
, &iftype
, &ifsubtype
);
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
);
1114 type_entity_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceID
, iftype
);
1116 nc_print_VPN_service(service
);
1118 #if !TARGET_OS_IPHONE
1119 vpnprefpath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@"), PREF_PREFIX
, ifsubtype
, PREF_SUFFIX
);
1120 if (vpnprefpath
== NULL
) {
1124 path_len
= CFStringGetLength(vpnprefpath
) + 1;
1125 path
= malloc(path_len
);
1130 if (!CFStringGetCString(vpnprefpath
, path
, path_len
, kCFStringEncodingASCII
)) {
1131 SCPrint(TRUE
, stderr
, CFSTR("CFStringGetCString failed\n"));
1135 do_prefs_init(); /* initialization */
1136 do_prefs_open(1, &path
); /* open prefs */
1138 bookmarkData
= SCPreferencesGetValue(prefs
, CFSTR("ApplicationURL"));
1139 if (bookmarkData
== NULL
) {
1143 directory
= CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault
, bookmarkData
, 0, NULL
, NULL
, &isStale
, NULL
);
1144 if (directory
== NULL
) {
1148 SCPrint(TRUE
, stdout
, CFSTR("ApplicationURL: %@\n"), directory
);
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()));
1157 type_entity_dict
= SCDynamicStoreCopyValue(store
, type_entity_key
);
1159 if (!type_entity_dict
) {
1160 SCPrint(TRUE
, stderr
, CFSTR("No \"%@\" configuration available\n"), iftype
);
1162 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), iftype
, type_entity_dict
);
1166 subtype_entity_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceID
, ifsubtype
);
1167 subtype_entity_dict
= SCDynamicStoreCopyValue(store
, subtype_entity_key
);
1168 if (!subtype_entity_dict
) {
1172 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), ifsubtype
, subtype_entity_dict
);
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
);
1190 /* -----------------------------------------------------------------------------
1191 ----------------------------------------------------------------------------- */
1193 nc_select(int argc
, char **argv
)
1195 SCNetworkSetRef current_set
;
1197 SCNetworkServiceRef service
= NULL
;
1200 do_prefs_init(); /* initialization */
1201 do_prefs_open(0, NULL
); /* open default prefs */
1203 current_set
= SCNetworkSetCopyCurrent(prefs
);
1204 if (current_set
== NULL
) {
1205 SCPrint(TRUE
, stderr
, CFSTR("No current location\n"), SCErrorString(SCError()));
1209 service
= nc_copy_service_from_arguments(argc
, argv
, current_set
);
1210 if (service
== NULL
) {
1211 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
1215 #if !TARGET_OS_IPHONE
1216 status
= SCNetworkServiceSetEnabled(service
, TRUE
);
1218 SCPrint(TRUE
, stderr
, CFSTR("Unable to enable service: %s\n"), SCErrorString(SCError()));
1222 status
= SCNetworkSetSetSelectedVPNService(current_set
, service
);
1224 SCPrint(TRUE
, stderr
, CFSTR("Unable to select service: %s\n"), SCErrorString(SCError()));
1232 my_CFRelease(&service
);
1233 my_CFRelease(¤t_set
);
1238 /* -----------------------------------------------------------------------------
1239 ----------------------------------------------------------------------------- */
1241 nc_help(int argc
, char **argv
)
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"));
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"));
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"));
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"));
1303 /* -----------------------------------------------------------------------------
1304 ----------------------------------------------------------------------------- */
1305 typedef void (*nc_func
) (int argc
, char **argv
);
1307 static const struct {
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
},
1328 #define N_NC_CMNDS (sizeof(nc_cmds) / sizeof(nc_cmds[0]))
1331 /* -----------------------------------------------------------------------------
1332 ----------------------------------------------------------------------------- */
1334 find_nc_cmd(char *cmd
)
1338 for (i
= 0; i
< (int)N_NC_CMNDS
; i
++) {
1339 if (strcmp(cmd
, nc_cmds
[i
].cmd
) == 0) {
1348 /* -----------------------------------------------------------------------------
1349 ----------------------------------------------------------------------------- */
1351 do_nc_cmd(char *cmd
, int argc
, char **argv
, Boolean watch
)
1355 i
= find_nc_cmd(cmd
);
1359 func
= nc_cmds
[i
].func
;
1361 if (func
== nc_status
) {
1363 } else if (func
== nc_ondemand
) {
1364 ondemandwatch
= TRUE
;
1367 (*func
)(argc
, argv
);