2 * Copyright (c) 2010-2015, 2017-2019 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>
47 #if !TARGET_OS_SIMULATOR
48 #include <NEHelperClient.h>
49 #endif // !TARGET_OS_SIMULATOR
51 CFStringRef username
= NULL
;
52 CFStringRef password
= NULL
;
53 CFStringRef sharedsecret
= NULL
;
55 static Boolean ondemandwatch
= FALSE
;
56 static CFStringRef ondemand_nodename
= NULL
;
58 static SCNetworkConnectionRef connection
= NULL
;
59 static int n_callback
= 0;
62 /* -----------------------------------------------------------------------------
63 ----------------------------------------------------------------------------- */
67 void * * obj
= (void * *)t
;
75 /* -----------------------------------------------------------------------------
76 ----------------------------------------------------------------------------- */
78 nc_get_service_type_and_subtype(SCNetworkServiceRef service
, CFStringRef
*iftype
, CFStringRef
*ifsubtype
) {
79 SCNetworkInterfaceRef interface
= SCNetworkServiceGetInterface(service
);
80 SCNetworkInterfaceRef child
= SCNetworkInterfaceGetInterface(interface
);
82 *iftype
= SCNetworkInterfaceGetInterfaceType(interface
);
84 if (CFEqual(*iftype
, kSCNetworkInterfaceTypePPP
) ||
85 CFEqual(*iftype
, kSCNetworkInterfaceTypeVPN
)) {
86 *ifsubtype
= (child
!= NULL
) ? SCNetworkInterfaceGetInterfaceType(child
) : NULL
;
90 /* -----------------------------------------------------------------------------
91 ----------------------------------------------------------------------------- */
92 static SCNetworkServiceRef
93 nc_copy_service(SCNetworkSetRef set
, CFStringRef identifier
)
97 SCNetworkServiceRef selected
= NULL
;
100 services
= SCNetworkConnectionCopyAvailableServices(set
);
101 if (services
== NULL
) {
105 n
= CFArrayGetCount(services
);
107 // try to select the service by its serviceID
108 for (i
= 0; i
< n
; i
++) {
109 SCNetworkServiceRef service
= NULL
;
110 CFStringRef serviceID
;
112 service
= CFArrayGetValueAtIndex(services
, i
);
113 serviceID
= SCNetworkServiceGetServiceID(service
);
114 if (CFEqual(identifier
, serviceID
)) {
120 // try to select the service by service name
121 for (i
= 0; i
< n
; i
++) {
122 SCNetworkServiceRef service
= NULL
;
123 CFStringRef serviceName
;
125 service
= CFArrayGetValueAtIndex(services
, i
);
126 serviceName
= SCNetworkServiceGetName(service
);
127 if ((serviceName
!= NULL
) && CFEqual(identifier
, serviceName
)) {
128 if (selected
== NULL
) {
131 // if multiple services match
133 SCPrint(TRUE
, stderr
, CFSTR("Multiple services match\n"));
141 if (selected
!= NULL
) CFRetain(selected
);
142 if (services
!= NULL
) CFRelease(services
);
146 /* -----------------------------------------------------------------------------
147 ----------------------------------------------------------------------------- */
148 static SCNetworkServiceRef
149 nc_copy_service_from_arguments(int argc
, char **argv
, SCNetworkSetRef set
) {
150 CFStringRef serviceID
= NULL
;
151 SCNetworkServiceRef service
= NULL
;
154 serviceID
= _copyStringFromSTDIN(CFSTR("Service"), NULL
);
156 serviceID
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
158 if (serviceID
== NULL
) {
159 SCPrint(TRUE
, stderr
, CFSTR("No service ID specified\n"));
162 service
= nc_copy_service(set
, serviceID
);
163 my_CFRelease(&serviceID
);
168 /* -----------------------------------------------------------------------------
169 ----------------------------------------------------------------------------- */
171 nc_status_string(SCNetworkConnectionStatus status
)
174 case kSCNetworkConnectionInvalid
:
176 case kSCNetworkConnectionDisconnected
:
177 return "Disconnected";
178 case kSCNetworkConnectionConnecting
:
180 case kSCNetworkConnectionConnected
:
182 case kSCNetworkConnectionDisconnecting
:
183 return "Disconnecting";
189 nc_callback(SCNetworkConnectionRef connection
, SCNetworkConnectionStatus status
, void *info
)
191 int *n
= (int *)info
;
192 CFDictionaryRef status_dict
;
197 SCPrint(TRUE
, stdout
, CFSTR("Current status = "));
200 struct timeval tv_now
;
202 (void)gettimeofday(&tv_now
, NULL
);
203 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
205 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
209 tv_now
.tv_usec
/ 1000);
210 SCPrint(TRUE
, stdout
, CFSTR("Callback (%d) status = "), *n
);
214 SCPrint(TRUE
, stdout
, CFSTR("%s%s%s\n"),
215 nc_status_string(status
),
216 (status
== kSCNetworkConnectionInvalid
) ? ": " : "",
217 (status
== kSCNetworkConnectionInvalid
) ? SCErrorString(SCError()) : "");
219 // report extended status
220 status_dict
= SCNetworkConnectionCopyExtendedStatus(connection
);
222 SCPrint(TRUE
, stdout
, CFSTR("Extended Status %@\n"), status_dict
);
223 CFRelease(status_dict
);
230 nc_create_connection(int argc
, char **argv
, Boolean exit_on_failure
)
232 SCNetworkConnectionContext context
= { 0, &n_callback
, NULL
, NULL
, NULL
};
233 SCNetworkServiceRef service
;
235 service
= nc_copy_service_from_arguments(argc
, argv
, NULL
);
236 if (service
== NULL
) {
237 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
243 connection
= SCNetworkConnectionCreateWithService(NULL
, service
, nc_callback
, &context
);
245 if (connection
== NULL
) {
246 SCPrint(TRUE
, stderr
, CFSTR("Could not create connection: %s\n"), SCErrorString(SCError()));
253 /* -----------------------------------------------------------------------------
254 ----------------------------------------------------------------------------- */
257 nc_trigger(int argc
, char **argv
)
259 Boolean background
= FALSE
;
261 CFStringRef hostName
= NULL
;
264 for (i
= 0; i
< 3 && i
< argc
; i
++) {
265 /* Parse host name. Must be first arg. */
267 hostName
= CFStringCreateWithCString(NULL
, argv
[i
], kCFStringEncodingUTF8
);
271 /* Check for optional background flag */
272 if (strcmp(argv
[i
], "background") == 0) {
277 /* Parse optional port number */
278 CFStringRef str
= CFStringCreateWithCString(NULL
, argv
[i
], kCFStringEncodingUTF8
);
280 int num
= CFStringGetIntValue(str
);
289 CFReadStreamRef readStream
= NULL
;
290 CFWriteStreamRef writeStream
= NULL
;
292 CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault
, hostName
, port
, &readStream
, &writeStream
);
295 CFReadStreamSetProperty(readStream
, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground"));
296 CFWriteStreamSetProperty(writeStream
, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground"));
299 if (readStream
&& writeStream
) {
300 CFReadStreamOpen(readStream
);
301 CFWriteStreamOpen(writeStream
);
302 SCPrint(TRUE
, stdout
, CFSTR("Opened stream to %@, port %d%s\n"), hostName
, port
, background
? ", background traffic class" : "");
306 my_CFRelease(&readStream
);
307 my_CFRelease(&writeStream
);
309 SCPrint(TRUE
, stderr
, CFSTR("Invalid or missing host name\n"));
312 my_CFRelease(&hostName
);
317 /* -----------------------------------------------------------------------------
318 ----------------------------------------------------------------------------- */
320 nc_release_connection()
322 my_CFRelease(&connection
);
325 /* -----------------------------------------------------------------------------
326 ----------------------------------------------------------------------------- */
328 nc_start(int argc
, char **argv
)
330 CFMutableDictionaryRef userOptions
= NULL
;
331 CFStringRef iftype
= NULL
;
332 CFStringRef ifsubtype
= NULL
;
333 SCNetworkServiceRef service
= NULL
;
335 nc_create_connection(argc
, argv
, TRUE
);
337 service
= SCNetworkConnectionGetService(connection
);
338 nc_get_service_type_and_subtype(service
, &iftype
, &ifsubtype
);
340 userOptions
= CFDictionaryCreateMutable(NULL
, 0,
341 &kCFTypeDictionaryKeyCallBacks
,
342 &kCFTypeDictionaryValueCallBacks
);
344 Boolean isL2TP
= (CFEqual(iftype
, kSCEntNetPPP
) &&
345 (ifsubtype
!= NULL
) && CFEqual(ifsubtype
, kSCValNetInterfaceSubTypeL2TP
));
347 if (CFEqual(iftype
, kSCEntNetPPP
)) {
348 CFMutableDictionaryRef pppEntity
= CFDictionaryCreateMutable(NULL
, 0,
349 &kCFTypeDictionaryKeyCallBacks
,
350 &kCFTypeDictionaryValueCallBacks
);
352 if (username
!= NULL
) {
353 CFDictionarySetValue(pppEntity
, kSCPropNetPPPAuthName
, username
);
355 if (password
!= NULL
) {
356 CFDictionarySetValue(pppEntity
, kSCPropNetPPPAuthPassword
, password
);
358 CFDictionarySetValue(userOptions
, kSCEntNetPPP
, pppEntity
);
359 my_CFRelease(&pppEntity
);
361 if (CFEqual(iftype
, kSCEntNetIPSec
) || isL2TP
) {
362 CFMutableDictionaryRef ipsecEntity
= CFDictionaryCreateMutable(NULL
, 0,
363 &kCFTypeDictionaryKeyCallBacks
,
364 &kCFTypeDictionaryValueCallBacks
);
366 if (username
!= NULL
) {
367 CFDictionarySetValue(ipsecEntity
, kSCPropNetIPSecXAuthName
, username
);
369 if (password
!= NULL
) {
370 CFDictionarySetValue(ipsecEntity
, kSCPropNetIPSecXAuthPassword
, password
);
373 if (sharedsecret
!= NULL
) {
374 CFDictionarySetValue(ipsecEntity
, kSCPropNetIPSecSharedSecret
, sharedsecret
);
376 CFDictionarySetValue(userOptions
, kSCEntNetIPSec
, ipsecEntity
);
377 my_CFRelease(&ipsecEntity
);
379 if (CFEqual(iftype
, kSCEntNetVPN
)) {
380 CFMutableDictionaryRef vpnEntity
= CFDictionaryCreateMutable(NULL
, 0,
381 &kCFTypeDictionaryKeyCallBacks
,
382 &kCFTypeDictionaryValueCallBacks
);
383 if (username
!= NULL
) {
384 CFDictionarySetValue(vpnEntity
, kSCPropNetVPNAuthName
, username
);
386 if (password
!= NULL
) {
387 CFDictionarySetValue(vpnEntity
, kSCPropNetVPNAuthPassword
, password
);
389 CFDictionarySetValue(userOptions
, kSCEntNetVPN
, vpnEntity
);
390 my_CFRelease(&vpnEntity
);
392 // If it doesn't match any VPN type, fail silently
394 if (!SCNetworkConnectionStart(connection
, userOptions
, TRUE
)) {
395 SCPrint(TRUE
, stderr
, CFSTR("Could not start connection: %s\n"), SCErrorString(SCError()));
399 CFRelease(userOptions
);
400 nc_release_connection();
404 /* -----------------------------------------------------------------------------
405 ----------------------------------------------------------------------------- */
407 nc_stop(int argc
, char **argv
)
409 nc_create_connection(argc
, argv
, TRUE
);
411 if (!SCNetworkConnectionStop(connection
, TRUE
)) {
412 SCPrint(TRUE
, stderr
, CFSTR("Could not stop connection: %s\n"), SCErrorString(SCError()));
416 nc_release_connection();
420 /* -----------------------------------------------------------------------------
421 ----------------------------------------------------------------------------- */
423 nc_suspend(int argc
, char **argv
)
425 nc_create_connection(argc
, argv
, TRUE
);
427 SCNetworkConnectionSuspend(connection
);
429 nc_release_connection();
433 /* -----------------------------------------------------------------------------
434 ----------------------------------------------------------------------------- */
436 nc_resume(int argc
, char **argv
)
438 nc_create_connection(argc
, argv
, TRUE
);
440 SCNetworkConnectionResume(connection
);
442 nc_release_connection();
446 /* -----------------------------------------------------------------------------
447 ----------------------------------------------------------------------------- */
449 nc_status(int argc
, char **argv
)
451 SCNetworkConnectionStatus status
;
453 nc_create_connection(argc
, argv
, TRUE
);
455 status
= SCNetworkConnectionGetStatus(connection
);
456 nc_callback(connection
, status
, NULL
);
458 nc_release_connection();
463 nc_watch(int argc
, char **argv
)
465 SCNetworkConnectionStatus status
;
467 nc_create_connection(argc
, argv
, TRUE
);
469 status
= SCNetworkConnectionGetStatus(connection
);
471 // report initial status
473 nc_callback(connection
, status
, &n_callback
);
477 if (!SCNetworkConnectionSetDispatchQueue(connection
, dispatch_get_main_queue())) {
478 SCPrint(TRUE
, stderr
, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError()));
482 if (!SCNetworkConnectionScheduleWithRunLoop(connection
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
483 SCPrint(TRUE
, stderr
, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError()));
491 nc_release_connection();
495 /* -----------------------------------------------------------------------------
496 ----------------------------------------------------------------------------- */
498 nc_statistics(int argc
, char **argv
)
500 CFDictionaryRef stats_dict
;
502 nc_create_connection(argc
, argv
, TRUE
);
504 stats_dict
= SCNetworkConnectionCopyStatistics(connection
);
507 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), stats_dict
);
509 SCPrint(TRUE
, stdout
, CFSTR("No statistics available\n"));
512 my_CFRelease(&stats_dict
);
514 nc_release_connection();
518 /* -----------------------------------------------------------------------------
519 ----------------------------------------------------------------------------- */
521 checkOnDemandHost(SCDynamicStoreRef store
, CFStringRef nodeName
, Boolean retry
)
524 CFStringRef connectionServiceID
= NULL
;
525 SCNetworkConnectionStatus connectionStatus
= 0;
526 CFStringRef vpnRemoteAddress
= NULL
;
528 SCPrint(TRUE
, stdout
, CFSTR("OnDemand host/domain check (%sretry)\n"), retry
? "" : "no ");
530 ok
= __SCNetworkConnectionCopyOnDemandInfoWithName(&store
,
533 &connectionServiceID
,
538 SCPrint(TRUE
, stdout
, CFSTR(" serviceID = %@\n"), connectionServiceID
);
539 SCPrint(TRUE
, stdout
, CFSTR(" remote address = %@\n"), vpnRemoteAddress
);
540 } else if (SCError() != kSCStatusOK
) {
541 SCPrint(TRUE
, stdout
, CFSTR("%sretry\n"), retry
? "" : "no ");
542 SCPrint(TRUE
, stdout
,
543 CFSTR(" Unable to copy OnDemand information for connection: %s\n"),
544 SCErrorString(SCError()));
546 SCPrint(TRUE
, stdout
, CFSTR(" no match\n"));
549 if (connectionServiceID
!= NULL
) {
550 CFRelease(connectionServiceID
);
551 connectionServiceID
= NULL
;
553 if (vpnRemoteAddress
!= NULL
) {
554 CFRelease(vpnRemoteAddress
);
555 vpnRemoteAddress
= NULL
;
562 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_OS_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_OS_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
)
776 CFArrayRef services
= NULL
;
778 SCPrint(TRUE
, stdout
, CFSTR("Available network connection services in the current set (*=enabled):\n"));
779 services
= SCNetworkConnectionCopyAvailableServices(NULL
);
780 if (services
!= NULL
) {
781 count
= CFArrayGetCount(services
);
782 for (i
= 0; i
< count
; i
++) {
783 SCNetworkServiceRef service
;
785 service
= CFArrayGetValueAtIndex(services
, i
);
786 nc_print_VPN_service(service
);
790 my_CFRelease(&services
);
794 /* -----------------------------------------------------------------------------
795 ----------------------------------------------------------------------------- */
797 nc_enable_vpntype(CFStringRef vpnType
)
799 Boolean is_enabled
= FALSE
;
800 Boolean success
= FALSE
;
802 if (vpnType
== NULL
) {
803 SCPrint(TRUE
, stderr
, CFSTR("No VPN type provided\n"));
807 is_enabled
= VPNConfigurationIsVPNTypeEnabled(vpnType
);
810 SCPrint(TRUE
, stdout
, CFSTR("VPN is already enabled\n"));
812 #if !TARGET_OS_IPHONE
813 AuthorizationRef authorization
;
815 authorization
= _prefs_AuthorizationCreate();
816 if ((authorization
== NULL
) ||
817 !VPNConfigurationSetAuthorization(authorization
)) {
818 SCPrint(TRUE
, stderr
, CFSTR("VPNConfigurationSetAuthorization failed: %s\n"), SCErrorString(SCError()));
821 #endif // !TARGET_OS_IPHONE
823 if (!VPNConfigurationEnableVPNType(vpnType
)) {
824 SCPrint(TRUE
, stderr
, CFSTR("VPN could not be enabled: %s\n"), SCErrorString(SCError()));
828 #if !TARGET_OS_IPHONE
829 _prefs_AuthorizationFree(authorization
);
830 #endif // !TARGET_OS_IPHONE
832 SCPrint(TRUE
, stdout
, CFSTR("VPN enabled\n"));
840 /* Turns a service ID or name into a vendor type, or preserves type */
842 nc_copy_vendor_type (CFStringRef input
)
844 SCNetworkInterfaceRef child
;
845 SCNetworkInterfaceRef interface
;
846 CFStringRef output_name
= input
;
847 SCNetworkServiceRef service
= NULL
;
854 service
= nc_copy_service(NULL
, input
);
855 if (service
!= NULL
) {
856 interface
= SCNetworkServiceGetInterface(service
);
857 child
= SCNetworkInterfaceGetInterface(interface
);
858 type
= SCNetworkInterfaceGetInterfaceType(interface
);
860 /* Must be of type VPN */
861 if (!CFEqual(type
, kSCNetworkInterfaceTypeVPN
)) {
865 output_name
= SCNetworkInterfaceGetInterfaceType(child
);
870 if (output_name
!= NULL
) CFRetain(output_name
);
871 my_CFRelease(&service
);
875 /* -----------------------------------------------------------------------------
876 ----------------------------------------------------------------------------- */
877 #if !TARGET_OS_IPHONE
878 static const CFStringRef PREF_PREFIX
= CFSTR("VPN-");
879 static const CFStringRef PREF_SUFFIX
= CFSTR(".plist");
881 nc_set_application_url(CFStringRef subtype
, CFStringRef directory
)
883 CFURLRef directory_url
= NULL
;
884 CFDataRef directory_url_data
= NULL
;
885 CFStringRef vpnprefpath
= NULL
;
887 CFIndex path_len
= 0;
889 if (subtype
== NULL
|| directory
== NULL
) {
893 directory_url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
,
895 kCFURLPOSIXPathStyle
,
897 if (directory_url
== NULL
) {
898 SCPrint(TRUE
, stderr
, CFSTR("CFURLCreateWithFileSystemPath failed\n"));
902 directory_url_data
= CFURLCreateBookmarkData(NULL
, directory_url
, 0, 0, 0, 0);
903 if (directory_url_data
== NULL
) {
904 SCPrint(TRUE
, stderr
, CFSTR("CFURLCreateBookmarkData failed\n"));
908 vpnprefpath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@"), PREF_PREFIX
, subtype
, PREF_SUFFIX
);
909 if (vpnprefpath
== NULL
) {
910 SCPrint(TRUE
, stderr
, CFSTR("CFStringCreateWithFormat failed\n"));
914 path_len
= CFStringGetLength(vpnprefpath
) + 1;
915 path
= malloc(path_len
);
920 if (!CFStringGetCString(vpnprefpath
, path
, path_len
, kCFStringEncodingASCII
)) {
921 SCPrint(TRUE
, stderr
, CFSTR("CFStringGetCString failed\n"));
925 do_prefs_init(); /* initialization */
926 do_prefs_open(1, &path
); /* open prefs */
928 SCPreferencesSetValue(prefs
, CFSTR("ApplicationURL"), directory_url_data
);
933 my_CFRelease(&directory_url
);
934 my_CFRelease(&directory_url_data
);
935 my_CFRelease(&vpnprefpath
);
943 #endif // !TARGET_OS_IPHONE
945 /* -----------------------------------------------------------------------------
946 ----------------------------------------------------------------------------- */
948 nc_enablevpn(int argc
, char **argv
)
950 CFStringRef argument
= NULL
;
951 CFStringRef vendorType
= NULL
;
955 SCPrint(TRUE
, stderr
, CFSTR("No service type or ID\n"));
957 argument
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
958 vendorType
= nc_copy_vendor_type(argument
);
959 my_CFRelease(&argument
);
961 if (!nc_enable_vpntype(vendorType
)) {
964 #if !TARGET_OS_IPHONE
966 argument
= CFStringCreateWithCString(NULL
, argv
[1], kCFStringEncodingUTF8
);
967 nc_set_application_url(vendorType
, argument
);
968 my_CFRelease(&argument
);
970 #endif // !TARGET_OS_IPHONE
976 my_CFRelease(&vendorType
);
980 /* -----------------------------------------------------------------------------
981 ----------------------------------------------------------------------------- */
983 nc_show(int argc
, char **argv
)
985 SCNetworkServiceRef service
= NULL
;
986 SCDynamicStoreRef store
= NULL
;
988 CFStringRef serviceID
= NULL
;
989 CFStringRef iftype
= NULL
;
990 CFStringRef ifsubtype
= NULL
;
991 CFStringRef type_entity_key
= NULL
;
992 CFStringRef subtype_entity_key
= NULL
;
993 CFDictionaryRef type_entity_dict
= NULL
;
994 CFDictionaryRef subtype_entity_dict
= NULL
;
995 CFStringRef vpnprefpath
= NULL
;
996 #if !TARGET_OS_IPHONE
997 CFDataRef bookmarkData
= NULL
;
998 CFURLRef directory
= NULL
;
999 Boolean isStale
= FALSE
;
1001 CFIndex path_len
= 0;
1002 #endif // !TARGET_OS_IPHONE
1004 service
= nc_copy_service_from_arguments(argc
, argv
, NULL
);
1005 if (service
== NULL
) {
1006 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
1010 if (!_SCNetworkServiceIsVPN(service
)) {
1011 SCPrint(TRUE
, stderr
, CFSTR("Not a connection oriented service: %@\n"), serviceID
);
1015 serviceID
= SCNetworkServiceGetServiceID(service
);
1017 nc_get_service_type_and_subtype(service
, &iftype
, &ifsubtype
);
1019 type_entity_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceID
, iftype
);
1021 nc_print_VPN_service(service
);
1023 #if !TARGET_OS_IPHONE
1024 vpnprefpath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@"), PREF_PREFIX
, ifsubtype
, PREF_SUFFIX
);
1025 if (vpnprefpath
== NULL
) {
1029 path_len
= CFStringGetLength(vpnprefpath
) + 1;
1030 path
= malloc(path_len
);
1035 if (!CFStringGetCString(vpnprefpath
, path
, path_len
, kCFStringEncodingASCII
)) {
1036 SCPrint(TRUE
, stderr
, CFSTR("CFStringGetCString failed\n"));
1040 do_prefs_init(); /* initialization */
1041 do_prefs_open(1, &path
); /* open prefs */
1043 bookmarkData
= SCPreferencesGetValue(prefs
, CFSTR("ApplicationURL"));
1044 if (bookmarkData
== NULL
) {
1048 directory
= CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault
, bookmarkData
, 0, NULL
, NULL
, &isStale
, NULL
);
1049 if (directory
== NULL
) {
1053 SCPrint(TRUE
, stdout
, CFSTR("ApplicationURL: %@\n"), directory
);
1055 #endif // !TARGET_OS_IPHONE
1057 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil --nc"), NULL
, NULL
);
1058 if (store
== NULL
) {
1059 SCPrint(TRUE
, stderr
, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError()));
1062 type_entity_dict
= SCDynamicStoreCopyValue(store
, type_entity_key
);
1064 if (!type_entity_dict
) {
1065 SCPrint(TRUE
, stderr
, CFSTR("No \"%@\" configuration available\n"), iftype
);
1067 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), iftype
, type_entity_dict
);
1071 subtype_entity_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceID
, ifsubtype
);
1072 subtype_entity_dict
= SCDynamicStoreCopyValue(store
, subtype_entity_key
);
1073 if (!subtype_entity_dict
) {
1077 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), ifsubtype
, subtype_entity_dict
);
1084 my_CFRelease(&type_entity_key
);
1085 my_CFRelease(&type_entity_dict
);
1086 my_CFRelease(&subtype_entity_key
);
1087 my_CFRelease(&subtype_entity_dict
);
1088 my_CFRelease(&store
);
1089 my_CFRelease(&service
);
1090 my_CFRelease(&vpnprefpath
);
1095 /* -----------------------------------------------------------------------------
1096 ----------------------------------------------------------------------------- */
1098 nc_select(int argc
, char **argv
)
1100 SCNetworkSetRef current_set
;
1102 SCNetworkServiceRef service
= NULL
;
1103 #if NE_HAS_ENABLE_VPN
1104 uuid_string_t config_id_string
;
1106 #else // NE_HAS_ENABLE_VPN
1108 #endif // NE_HAS_ENABLE_VPN
1110 do_prefs_init(); /* initialization */
1111 do_prefs_open(0, NULL
); /* open default prefs */
1113 current_set
= SCNetworkSetCopyCurrent(prefs
);
1114 if (current_set
== NULL
) {
1115 SCPrint(TRUE
, stderr
, CFSTR("No current location\n"));
1119 service
= nc_copy_service_from_arguments(argc
, argv
, current_set
);
1120 if (service
== NULL
) {
1121 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
1125 #if NE_HAS_ENABLE_VPN
1126 memset(config_id_string
, 0, sizeof(config_id_string
));
1127 if (_SC_cfstring_to_cstring(SCNetworkServiceGetServiceID(service
), config_id_string
, sizeof(config_id_string
), kCFStringEncodingUTF8
) != NULL
&&
1128 uuid_parse(config_id_string
, config_id
) == 0)
1130 if (!NEHelperVPNSetEnabled(config_id
, true)) {
1131 SCPrint(TRUE
, stderr
, CFSTR("Unable to enable service\n"));
1134 SCPrint(TRUE
, stderr
, CFSTR("Invalid service ID: %@\n"), SCNetworkServiceGetServiceID(service
));
1136 #else // NE_HAS_ENABLE_VPN
1137 #if !TARGET_OS_IPHONE
1138 status
= SCNetworkServiceSetEnabled(service
, TRUE
);
1140 SCPrint(TRUE
, stderr
, CFSTR("Unable to enable service: %s\n"), SCErrorString(SCError()));
1143 #else // !TARGET_OS_IPHONE
1144 status
= SCNetworkSetSetSelectedVPNService(current_set
, service
);
1146 SCPrint(TRUE
, stderr
, CFSTR("Unable to select service: %s\n"), SCErrorString(SCError()));
1149 #endif // !TARGET_OS_IPHONE
1152 #endif // NE_HAS_ENABLE_VPN
1155 my_CFRelease(&service
);
1156 my_CFRelease(¤t_set
);
1161 /* -----------------------------------------------------------------------------
1162 ----------------------------------------------------------------------------- */
1164 nc_help(int argc
, char **argv
)
1166 #pragma unused(argc)
1167 #pragma unused(argv)
1168 SCPrint(TRUE
, stderr
, CFSTR("Valid commands for scutil --nc (VPN connections)\n"));
1169 SCPrint(TRUE
, stderr
, CFSTR("Usage: scutil --nc [command]\n"));
1170 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1171 SCPrint(TRUE
, stderr
, CFSTR("\tlist\n"));
1172 SCPrint(TRUE
, stderr
, CFSTR("\t\tList available network connection services in the current set\n"));
1173 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1174 SCPrint(TRUE
, stderr
, CFSTR("\tstatus <service>\n"));
1175 SCPrint(TRUE
, stderr
, CFSTR("\t\tIndicate whether a given service is connected, as well as extended status information for the service\n"));
1176 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1177 SCPrint(TRUE
, stderr
, CFSTR("\tshow <service>\n"));
1178 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisplay configuration information for a given service\n"));
1179 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1180 SCPrint(TRUE
, stderr
, CFSTR("\tstatistics <service>\n"));
1181 SCPrint(TRUE
, stderr
, CFSTR("\t\tProvide statistics on bytes, packets, and errors for a given service\n"));
1182 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1183 SCPrint(TRUE
, stderr
, CFSTR("\tselect <service>\n"));
1184 SCPrint(TRUE
, stderr
, CFSTR("\t\tMake the given service active in the current set. This allows it to be started\n"));
1185 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1186 SCPrint(TRUE
, stderr
, CFSTR("\tstart <service> [--user user] [--password password] [--secret secret]\n"));
1187 SCPrint(TRUE
, stderr
, CFSTR("\t\tStart a given service. Can take optional arguments for user, password, and secret\n"));
1188 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1189 SCPrint(TRUE
, stderr
, CFSTR("\tstop <service>\n"));
1190 SCPrint(TRUE
, stderr
, CFSTR("\t\tStop a given service\n"));
1191 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1192 SCPrint(TRUE
, stderr
, CFSTR("\tsuspend <service>\n"));
1193 SCPrint(TRUE
, stderr
, CFSTR("\t\tSuspend a given service (PPP, Modem on Hold)\n"));
1194 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1195 SCPrint(TRUE
, stderr
, CFSTR("\tresume <service>\n"));
1196 SCPrint(TRUE
, stderr
, CFSTR("\t\tResume a given service (PPP, Modem on Hold)\n"));
1197 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1198 SCPrint(TRUE
, stderr
, CFSTR("\tondemand [-W] [hostname]\n"));
1199 SCPrint(TRUE
, stderr
, CFSTR("\tondemand -- --refresh\n"));
1200 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisplay VPN on-demand information\n"));
1201 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1202 SCPrint(TRUE
, stderr
, CFSTR("\ttrigger <hostname> [background] [port]\n"));
1203 SCPrint(TRUE
, stderr
, CFSTR("\t\tTrigger VPN on-demand with specified hostname, and optional port and background flag\n"));
1204 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1205 #if !TARGET_OS_IPHONE
1206 SCPrint(TRUE
, stderr
, CFSTR("\tenablevpn <service or vpn type> [path]\n"));
1207 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"));
1208 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1209 #else // !TARGET_OS_IPHONE
1210 SCPrint(TRUE
, stderr
, CFSTR("\tenablevpn <service or vpn type>\n"));
1211 SCPrint(TRUE
, stderr
, CFSTR("\t\tEnables the given VPN application type. Takes either a service or VPN type\n"));
1212 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1213 #endif // !TARGET_OS_IPHONE
1214 SCPrint(TRUE
, stderr
, CFSTR("\tdisablevpn <service or vpn type>\n"));
1215 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisables the given VPN application type. Takes either a service or VPN type\n"));
1216 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1217 SCPrint(TRUE
, stderr
, CFSTR("\thelp\n"));
1218 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisplay available commands for --nc\n"));
1219 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1223 /* -----------------------------------------------------------------------------
1224 ----------------------------------------------------------------------------- */
1225 typedef void (*nc_func
) (int argc
, char **argv
);
1227 static const struct {
1231 { "enablevpn", nc_enablevpn
},
1232 { "help", nc_help
},
1233 { "list", nc_list
},
1234 { "ondemand", nc_ondemand
},
1235 { "resume", nc_resume
},
1236 { "select", nc_select
},
1237 { "show", nc_show
},
1238 { "start", nc_start
},
1239 { "statistics", nc_statistics
},
1240 { "status", nc_status
},
1241 { "stop", nc_stop
},
1242 { "suspend", nc_suspend
},
1243 { "trigger", nc_trigger
},
1245 #define N_NC_CMNDS (sizeof(nc_cmds) / sizeof(nc_cmds[0]))
1248 /* -----------------------------------------------------------------------------
1249 ----------------------------------------------------------------------------- */
1251 find_nc_cmd(char *cmd
)
1255 for (i
= 0; i
< (int)N_NC_CMNDS
; i
++) {
1256 if (strcmp(cmd
, nc_cmds
[i
].cmd
) == 0) {
1265 /* -----------------------------------------------------------------------------
1266 ----------------------------------------------------------------------------- */
1268 do_nc_cmd(char *cmd
, int argc
, char **argv
, Boolean watch
)
1272 i
= find_nc_cmd(cmd
);
1276 func
= nc_cmds
[i
].func
;
1278 if (func
== nc_status
) {
1280 } else if (func
== nc_ondemand
) {
1281 ondemandwatch
= TRUE
;
1284 (*func
)(argc
, argv
);