2 * Copyright (c) 2010-2015 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>
48 CFStringRef username
= NULL
;
49 CFStringRef password
= NULL
;
50 CFStringRef sharedsecret
= NULL
;
52 static Boolean ondemandwatch
= FALSE
;
53 static CFStringRef ondemand_nodename
= NULL
;
55 static SCNetworkConnectionRef connection
= NULL
;
56 static int n_callback
= 0;
59 /* -----------------------------------------------------------------------------
60 ----------------------------------------------------------------------------- */
64 void * * obj
= (void * *)t
;
72 /* -----------------------------------------------------------------------------
73 ----------------------------------------------------------------------------- */
75 nc_get_service_type_and_subtype(SCNetworkServiceRef service
, CFStringRef
*iftype
, CFStringRef
*ifsubtype
) {
76 SCNetworkInterfaceRef interface
= SCNetworkServiceGetInterface(service
);
77 SCNetworkInterfaceRef child
= SCNetworkInterfaceGetInterface(interface
);
79 *iftype
= SCNetworkInterfaceGetInterfaceType(interface
);
81 if (CFEqual(*iftype
, kSCNetworkInterfaceTypePPP
) ||
82 CFEqual(*iftype
, kSCNetworkInterfaceTypeVPN
)) {
83 *ifsubtype
= (child
!= NULL
) ? SCNetworkInterfaceGetInterfaceType(child
) : NULL
;
87 /* -----------------------------------------------------------------------------
88 ----------------------------------------------------------------------------- */
89 static SCNetworkServiceRef
90 nc_copy_service(SCNetworkSetRef set
, CFStringRef identifier
)
94 SCNetworkServiceRef selected
= NULL
;
97 services
= SCNetworkConnectionCopyAvailableServices(set
);
98 if (services
== NULL
) {
102 n
= CFArrayGetCount(services
);
104 // try to select the service by its serviceID
105 for (i
= 0; i
< n
; i
++) {
106 SCNetworkServiceRef service
= NULL
;
107 CFStringRef serviceID
;
109 service
= CFArrayGetValueAtIndex(services
, i
);
110 serviceID
= SCNetworkServiceGetServiceID(service
);
111 if (CFEqual(identifier
, serviceID
)) {
117 // try to select the service by service name
118 for (i
= 0; i
< n
; i
++) {
119 SCNetworkServiceRef service
= NULL
;
120 CFStringRef serviceName
;
122 service
= CFArrayGetValueAtIndex(services
, i
);
123 serviceName
= SCNetworkServiceGetName(service
);
124 if ((serviceName
!= NULL
) && CFEqual(identifier
, serviceName
)) {
125 if (selected
== NULL
) {
128 // if multiple services match
130 SCPrint(TRUE
, stderr
, CFSTR("Multiple services match\n"));
138 if (selected
!= NULL
) CFRetain(selected
);
139 if (services
!= NULL
) CFRelease(services
);
143 /* -----------------------------------------------------------------------------
144 ----------------------------------------------------------------------------- */
145 static SCNetworkServiceRef
146 nc_copy_service_from_arguments(int argc
, char **argv
, SCNetworkSetRef set
) {
147 CFStringRef serviceID
= NULL
;
148 SCNetworkServiceRef service
= NULL
;
151 serviceID
= _copyStringFromSTDIN(CFSTR("Service"), NULL
);
153 serviceID
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
155 if (serviceID
== NULL
) {
156 SCPrint(TRUE
, stderr
, CFSTR("No service ID specified\n"));
159 service
= nc_copy_service(set
, serviceID
);
160 my_CFRelease(&serviceID
);
165 /* -----------------------------------------------------------------------------
166 ----------------------------------------------------------------------------- */
168 nc_status_string(SCNetworkConnectionStatus status
)
171 case kSCNetworkConnectionInvalid
:
173 case kSCNetworkConnectionDisconnected
:
174 return "Disconnected";
175 case kSCNetworkConnectionConnecting
:
177 case kSCNetworkConnectionConnected
:
179 case kSCNetworkConnectionDisconnecting
:
180 return "Disconnecting";
186 nc_callback(SCNetworkConnectionRef connection
, SCNetworkConnectionStatus status
, void *info
)
188 int *n
= (int *)info
;
189 CFDictionaryRef status_dict
;
194 SCPrint(TRUE
, stdout
, CFSTR("Current status = "));
197 struct timeval tv_now
;
199 (void)gettimeofday(&tv_now
, NULL
);
200 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
202 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
206 tv_now
.tv_usec
/ 1000);
207 SCPrint(TRUE
, stdout
, CFSTR("Callback (%d) status = "), *n
);
211 SCPrint(TRUE
, stdout
, CFSTR("%s%s%s\n"),
212 nc_status_string(status
),
213 (status
== kSCNetworkConnectionInvalid
) ? ": " : "",
214 (status
== kSCNetworkConnectionInvalid
) ? SCErrorString(SCError()) : "");
216 // report extended status
217 status_dict
= SCNetworkConnectionCopyExtendedStatus(connection
);
219 SCPrint(TRUE
, stdout
, CFSTR("Extended Status %@\n"), status_dict
);
220 CFRelease(status_dict
);
227 nc_create_connection(int argc
, char **argv
, Boolean exit_on_failure
)
229 SCNetworkConnectionContext context
= { 0, &n_callback
, NULL
, NULL
, NULL
};
230 SCNetworkServiceRef service
;
232 service
= nc_copy_service_from_arguments(argc
, argv
, NULL
);
233 if (service
== NULL
) {
234 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
240 connection
= SCNetworkConnectionCreateWithService(NULL
, service
, nc_callback
, &context
);
242 if (connection
== NULL
) {
243 SCPrint(TRUE
, stderr
, CFSTR("Could not create connection: %s\n"), SCErrorString(SCError()));
250 /* -----------------------------------------------------------------------------
251 ----------------------------------------------------------------------------- */
254 nc_trigger(int argc
, char **argv
)
256 Boolean background
= FALSE
;
258 CFStringRef hostName
= NULL
;
261 for (i
= 0; i
< 3 && i
< argc
; i
++) {
262 /* Parse host name. Must be first arg. */
264 hostName
= CFStringCreateWithCString(NULL
, argv
[i
], kCFStringEncodingUTF8
);
268 /* Check for optional background flag */
269 if (strcmp(argv
[i
], "background") == 0) {
274 /* Parse optional port number */
275 CFStringRef str
= CFStringCreateWithCString(NULL
, argv
[i
], kCFStringEncodingUTF8
);
277 int num
= CFStringGetIntValue(str
);
286 CFReadStreamRef readStream
= NULL
;
287 CFWriteStreamRef writeStream
= NULL
;
289 CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault
, hostName
, port
, &readStream
, &writeStream
);
292 CFReadStreamSetProperty(readStream
, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground"));
293 CFWriteStreamSetProperty(writeStream
, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground"));
296 if (readStream
&& writeStream
) {
297 CFReadStreamOpen(readStream
);
298 CFWriteStreamOpen(writeStream
);
299 SCPrint(TRUE
, stdout
, CFSTR("Opened stream to %@, port %d%s\n"), hostName
, port
, background
? ", background traffic class" : "");
303 my_CFRelease(&readStream
);
304 my_CFRelease(&writeStream
);
306 SCPrint(TRUE
, stderr
, CFSTR("Invalid or missing host name\n"));
309 my_CFRelease(&hostName
);
314 /* -----------------------------------------------------------------------------
315 ----------------------------------------------------------------------------- */
317 nc_release_connection()
319 my_CFRelease(&connection
);
322 /* -----------------------------------------------------------------------------
323 ----------------------------------------------------------------------------- */
325 nc_start(int argc
, char **argv
)
327 CFMutableDictionaryRef userOptions
= NULL
;
328 CFStringRef iftype
= NULL
;
329 CFStringRef ifsubtype
= NULL
;
330 SCNetworkServiceRef service
= NULL
;
332 nc_create_connection(argc
, argv
, TRUE
);
334 service
= SCNetworkConnectionGetService(connection
);
335 nc_get_service_type_and_subtype(service
, &iftype
, &ifsubtype
);
337 userOptions
= CFDictionaryCreateMutable(NULL
, 0,
338 &kCFTypeDictionaryKeyCallBacks
,
339 &kCFTypeDictionaryValueCallBacks
);
341 Boolean isL2TP
= (CFEqual(iftype
, kSCEntNetPPP
) &&
342 (ifsubtype
!= NULL
) && CFEqual(ifsubtype
, kSCValNetInterfaceSubTypeL2TP
));
344 if (CFEqual(iftype
, kSCEntNetPPP
)) {
345 CFMutableDictionaryRef pppEntity
= CFDictionaryCreateMutable(NULL
, 0,
346 &kCFTypeDictionaryKeyCallBacks
,
347 &kCFTypeDictionaryValueCallBacks
);
349 if (username
!= NULL
) {
350 CFDictionarySetValue(pppEntity
, kSCPropNetPPPAuthName
, username
);
352 if (password
!= NULL
) {
353 CFDictionarySetValue(pppEntity
, kSCPropNetPPPAuthPassword
, password
);
355 CFDictionarySetValue(userOptions
, kSCEntNetPPP
, pppEntity
);
356 my_CFRelease(&pppEntity
);
358 if (CFEqual(iftype
, kSCEntNetIPSec
) || isL2TP
) {
359 CFMutableDictionaryRef ipsecEntity
= CFDictionaryCreateMutable(NULL
, 0,
360 &kCFTypeDictionaryKeyCallBacks
,
361 &kCFTypeDictionaryValueCallBacks
);
363 if (username
!= NULL
) {
364 CFDictionarySetValue(ipsecEntity
, kSCPropNetIPSecXAuthName
, username
);
366 if (password
!= NULL
) {
367 CFDictionarySetValue(ipsecEntity
, kSCPropNetIPSecXAuthPassword
, password
);
370 if (sharedsecret
!= NULL
) {
371 CFDictionarySetValue(ipsecEntity
, kSCPropNetIPSecSharedSecret
, sharedsecret
);
373 CFDictionarySetValue(userOptions
, kSCEntNetIPSec
, ipsecEntity
);
374 my_CFRelease(&ipsecEntity
);
376 if (CFEqual(iftype
, kSCEntNetVPN
)) {
377 CFMutableDictionaryRef vpnEntity
= CFDictionaryCreateMutable(NULL
, 0,
378 &kCFTypeDictionaryKeyCallBacks
,
379 &kCFTypeDictionaryValueCallBacks
);
380 if (username
!= NULL
) {
381 CFDictionarySetValue(vpnEntity
, kSCPropNetVPNAuthName
, username
);
383 if (password
!= NULL
) {
384 CFDictionarySetValue(vpnEntity
, kSCPropNetVPNAuthPassword
, password
);
386 CFDictionarySetValue(userOptions
, kSCEntNetVPN
, vpnEntity
);
387 my_CFRelease(&vpnEntity
);
389 // If it doesn't match any VPN type, fail silently
391 if (!SCNetworkConnectionStart(connection
, userOptions
, TRUE
)) {
392 SCPrint(TRUE
, stderr
, CFSTR("Could not start connection: %s\n"), SCErrorString(SCError()));
396 CFRelease(userOptions
);
397 nc_release_connection();
401 /* -----------------------------------------------------------------------------
402 ----------------------------------------------------------------------------- */
404 nc_stop(int argc
, char **argv
)
406 nc_create_connection(argc
, argv
, TRUE
);
408 if (!SCNetworkConnectionStop(connection
, TRUE
)) {
409 SCPrint(TRUE
, stderr
, CFSTR("Could not stop connection: %s\n"), SCErrorString(SCError()));
413 nc_release_connection();
417 /* -----------------------------------------------------------------------------
418 ----------------------------------------------------------------------------- */
420 nc_suspend(int argc
, char **argv
)
422 nc_create_connection(argc
, argv
, TRUE
);
424 SCNetworkConnectionSuspend(connection
);
426 nc_release_connection();
430 /* -----------------------------------------------------------------------------
431 ----------------------------------------------------------------------------- */
433 nc_resume(int argc
, char **argv
)
435 nc_create_connection(argc
, argv
, TRUE
);
437 SCNetworkConnectionResume(connection
);
439 nc_release_connection();
443 /* -----------------------------------------------------------------------------
444 ----------------------------------------------------------------------------- */
446 nc_status(int argc
, char **argv
)
448 SCNetworkConnectionStatus status
;
450 nc_create_connection(argc
, argv
, TRUE
);
452 status
= SCNetworkConnectionGetStatus(connection
);
453 nc_callback(connection
, status
, NULL
);
455 nc_release_connection();
460 nc_watch(int argc
, char **argv
)
462 SCNetworkConnectionStatus status
;
464 nc_create_connection(argc
, argv
, TRUE
);
466 status
= SCNetworkConnectionGetStatus(connection
);
468 // report initial status
470 nc_callback(connection
, status
, &n_callback
);
474 if (!SCNetworkConnectionSetDispatchQueue(connection
, dispatch_get_main_queue())) {
475 SCPrint(TRUE
, stderr
, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError()));
479 if (!SCNetworkConnectionScheduleWithRunLoop(connection
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
480 SCPrint(TRUE
, stderr
, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError()));
488 nc_release_connection();
492 /* -----------------------------------------------------------------------------
493 ----------------------------------------------------------------------------- */
495 nc_statistics(int argc
, char **argv
)
497 CFDictionaryRef stats_dict
;
499 nc_create_connection(argc
, argv
, TRUE
);
501 stats_dict
= SCNetworkConnectionCopyStatistics(connection
);
504 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), stats_dict
);
506 SCPrint(TRUE
, stdout
, CFSTR("No statistics available\n"));
509 my_CFRelease(&stats_dict
);
511 nc_release_connection();
515 /* -----------------------------------------------------------------------------
516 ----------------------------------------------------------------------------- */
518 checkOnDemandHost(SCDynamicStoreRef store
, CFStringRef nodeName
, Boolean retry
)
521 CFStringRef connectionServiceID
= NULL
;
522 SCNetworkConnectionStatus connectionStatus
= 0;
523 CFStringRef vpnRemoteAddress
= NULL
;
525 SCPrint(TRUE
, stdout
, CFSTR("OnDemand host/domain check (%sretry)\n"), retry
? "" : "no ");
527 ok
= __SCNetworkConnectionCopyOnDemandInfoWithName(&store
,
530 &connectionServiceID
,
535 SCPrint(TRUE
, stdout
, CFSTR(" serviceID = %@\n"), connectionServiceID
);
536 SCPrint(TRUE
, stdout
, CFSTR(" remote address = %@\n"), vpnRemoteAddress
);
537 } else if (SCError() != kSCStatusOK
) {
538 SCPrint(TRUE
, stdout
, CFSTR("%sretry\n"), retry
? "" : "no ");
539 SCPrint(TRUE
, stdout
,
540 CFSTR(" Unable to copy OnDemand information for connection: %s\n"),
541 SCErrorString(SCError()));
543 SCPrint(TRUE
, stdout
, CFSTR(" no match\n"));
546 if (connectionServiceID
!= NULL
) {
547 CFRelease(connectionServiceID
);
548 connectionServiceID
= NULL
;
550 if (vpnRemoteAddress
!= NULL
) {
551 CFRelease(vpnRemoteAddress
);
552 vpnRemoteAddress
= NULL
;
559 nc_ondemand_callback(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
)
561 CFStringRef key
= NULL
;
562 CFDictionaryRef ondemand_dict
= NULL
;
564 struct timeval tv_now
;
566 if (CFArrayGetCount(changedKeys
) < 1) {
570 (void)gettimeofday(&tv_now
, NULL
);
571 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
573 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
577 tv_now
.tv_usec
/ 1000);
579 if (ondemand_nodename
) {
580 checkOnDemandHost(store
, ondemand_nodename
, FALSE
);
581 checkOnDemandHost(store
, ondemand_nodename
, TRUE
);
583 key
= CFArrayGetValueAtIndex(changedKeys
, 0);
585 ondemand_dict
= SCDynamicStoreCopyValue(store
, key
);
587 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), kSCEntNetOnDemand
, ondemand_dict
);
589 SCPrint(TRUE
, stdout
, CFSTR("%@ not configured\n"), kSCEntNetOnDemand
);
592 my_CFRelease(&ondemand_dict
);
597 nc_ondemand(int argc
, char **argv
)
600 CFStringRef key
= NULL
;
601 CFDictionaryRef ondemand_dict
= NULL
;
602 SCDynamicStoreRef store
;
604 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil --nc"), nc_ondemand_callback
, NULL
);
606 SCPrint(TRUE
, stderr
, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError()));
611 #if !TARGET_OS_SIMULATOR
612 if (strcmp("--refresh", argv
[0]) == 0) {
613 SCNetworkConnectionRef connection
= NULL
;
615 connection
= SCNetworkConnectionCreate(kCFAllocatorDefault
, NULL
, NULL
);
616 if (connection
&& SCNetworkConnectionRefreshOnDemandState(connection
)) {
621 SCPrint(TRUE
, stderr
, CFSTR("Unable to refresh OnDemand state: %s\n"), SCErrorString(SCError()));
624 my_CFRelease(&connection
);
627 #endif // !TARGET_OS_SIMULATOR
629 ondemand_nodename
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
630 } else if (argc
!= 0) {
631 SCPrint(TRUE
, stderr
, CFSTR("Usage: scutil --nc ondemand [-W] [hostname]\n"
632 " scutil --nc ondemand -- --refresh\n"));
636 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetOnDemand
);
638 if (ondemand_nodename
) {
639 checkOnDemandHost(store
, ondemand_nodename
, FALSE
);
640 checkOnDemandHost(store
, ondemand_nodename
, TRUE
);
642 ondemand_dict
= SCDynamicStoreCopyValue(store
, key
);
644 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), kSCEntNetOnDemand
, ondemand_dict
);
646 SCPrint(TRUE
, stdout
, CFSTR("%@ not configured\n"), kSCEntNetOnDemand
);
651 CFMutableArrayRef keys
= NULL
;
653 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
654 CFArrayAppendValue(keys
, key
);
655 SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
659 SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue());
666 my_CFRelease(&ondemand_dict
);
668 my_CFRelease(&store
);
669 my_CFRelease(&ondemand_nodename
);
674 /* -----------------------------------------------------------------------------
675 ----------------------------------------------------------------------------- */
677 copy_padded_string(CFStringRef original
, int width
, CFStringRef prefix
, CFStringRef suffix
)
679 CFMutableStringRef padded
;
681 padded
= CFStringCreateMutable(NULL
, 0);
682 if (prefix
!= NULL
) {
683 CFStringAppend(padded
, prefix
);
685 if (original
!= NULL
) {
686 CFStringAppend(padded
, original
);
688 if (suffix
!= NULL
) {
689 CFStringAppend(padded
, suffix
);
691 CFStringPad(padded
, CFSTR(" "), MAX(CFStringGetLength(original
), width
), 0);
696 copy_VPN_status(SCNetworkServiceRef service
)
698 CFStringRef output
= NULL
;
699 SCNetworkConnectionStatus status
= kSCNetworkConnectionInvalid
;
700 SCNetworkConnectionRef service_connection
= NULL
;
702 /* Only calculate status is the service is enabled. Default is invalid. */
703 if (SCNetworkServiceGetEnabled(service
)) {
704 service_connection
= SCNetworkConnectionCreateWithService(NULL
, service
, NULL
, NULL
);
705 if (service_connection
== NULL
) goto done
;
706 status
= SCNetworkConnectionGetStatus(service_connection
);
709 output
= CFStringCreateWithCString(NULL
, nc_status_string(status
), kCFStringEncodingUTF8
);
712 my_CFRelease(&service_connection
);
717 nc_print_VPN_service(SCNetworkServiceRef service
)
719 SCNetworkInterfaceRef interface
= NULL
;
720 CFStringRef display_name
= NULL
;
721 CFStringRef display_name_padded
= NULL
;
722 CFStringRef service_id
= NULL
;
723 CFStringRef service_name
= NULL
;
724 CFStringRef service_name_padded
= NULL
;
725 CFStringRef service_status
= NULL
;
726 CFStringRef service_status_padded
= NULL
;
727 CFStringRef sub_type
= NULL
;
728 CFStringRef type
= NULL
;
730 nc_get_service_type_and_subtype(service
, &type
, &sub_type
);
732 service_name
= SCNetworkServiceGetName(service
);
733 service_name_padded
= copy_padded_string(service_name
, 32, CFSTR("\""), CFSTR("\""));
735 service_id
= SCNetworkServiceGetServiceID(service
);
737 interface
= SCNetworkServiceGetInterface(service
);
738 display_name
= SCNetworkInterfaceGetLocalizedDisplayName(interface
);
739 display_name_padded
= copy_padded_string(display_name
, 18, NULL
, NULL
);
741 service_status
= copy_VPN_status(service
);
742 service_status_padded
= copy_padded_string(service_status
, 16, CFSTR("("), CFSTR(")"));
746 CFSTR("%@ %@ %@ %@ %@ [%@%@%@]\n"),
747 SCNetworkServiceGetEnabled(service
) ? CFSTR("*") : CFSTR(" "),
748 service_status_padded
,
753 (sub_type
== NULL
) ? CFSTR("") : CFSTR(":"),
754 (sub_type
== NULL
) ? CFSTR("") : sub_type
);
756 CFRelease(display_name_padded
);
757 CFRelease(service_name_padded
);
758 CFRelease(service_status_padded
);
759 my_CFRelease(&service_status
);
763 /* -----------------------------------------------------------------------------
764 ----------------------------------------------------------------------------- */
766 nc_list(int argc
, char **argv
)
770 CFArrayRef services
= NULL
;
772 SCPrint(TRUE
, stdout
, CFSTR("Available network connection services in the current set (*=enabled):\n"));
773 services
= SCNetworkConnectionCopyAvailableServices(NULL
);
774 if (services
!= NULL
) {
775 count
= CFArrayGetCount(services
);
776 for (i
= 0; i
< count
; i
++) {
777 SCNetworkServiceRef service
;
779 service
= CFArrayGetValueAtIndex(services
, i
);
780 nc_print_VPN_service(service
);
784 my_CFRelease(&services
);
788 /* -----------------------------------------------------------------------------
789 ----------------------------------------------------------------------------- */
791 nc_enable_vpntype(CFStringRef vpnType
)
793 Boolean is_enabled
= FALSE
;
794 Boolean success
= FALSE
;
796 if (vpnType
== NULL
) {
797 SCPrint(TRUE
, stderr
, CFSTR("No VPN type provided\n"));
801 is_enabled
= VPNConfigurationIsVPNTypeEnabled(vpnType
);
804 SCPrint(TRUE
, stdout
, CFSTR("VPN is already enabled\n"));
806 #if !TARGET_OS_IPHONE
807 AuthorizationRef authorization
;
809 authorization
= _prefs_AuthorizationCreate();
810 if ((authorization
== NULL
) ||
811 !VPNConfigurationSetAuthorization(authorization
)) {
812 SCPrint(TRUE
, stderr
, CFSTR("VPNConfigurationSetAuthorization failed: %s\n"), SCErrorString(SCError()));
815 #endif // !TARGET_OS_IPHONE
817 if (!VPNConfigurationEnableVPNType(vpnType
)) {
818 SCPrint(TRUE
, stderr
, CFSTR("VPN could not be enabled: %s\n"), SCErrorString(SCError()));
822 #if !TARGET_OS_IPHONE
823 _prefs_AuthorizationFree(authorization
);
824 #endif // !TARGET_OS_IPHONE
826 SCPrint(TRUE
, stdout
, CFSTR("VPN enabled\n"));
834 /* Turns a service ID or name into a vendor type, or preserves type */
836 nc_copy_vendor_type (CFStringRef input
)
838 SCNetworkInterfaceRef child
;
839 SCNetworkInterfaceRef interface
;
840 CFStringRef output_name
= input
;
841 SCNetworkServiceRef service
= NULL
;
848 service
= nc_copy_service(NULL
, input
);
849 if (service
!= NULL
) {
850 interface
= SCNetworkServiceGetInterface(service
);
851 child
= SCNetworkInterfaceGetInterface(interface
);
852 type
= SCNetworkInterfaceGetInterfaceType(interface
);
854 /* Must be of type VPN */
855 if (!CFEqual(type
, kSCNetworkInterfaceTypeVPN
)) {
859 output_name
= SCNetworkInterfaceGetInterfaceType(child
);
864 if (output_name
!= NULL
) CFRetain(output_name
);
865 my_CFRelease(&service
);
869 /* -----------------------------------------------------------------------------
870 ----------------------------------------------------------------------------- */
871 #if !TARGET_OS_IPHONE
872 static const CFStringRef PREF_PREFIX
= CFSTR("VPN-");
873 static const CFStringRef PREF_SUFFIX
= CFSTR(".plist");
875 nc_set_application_url(CFStringRef subtype
, CFStringRef directory
)
877 CFURLRef directory_url
= NULL
;
878 CFDataRef directory_url_data
= NULL
;
879 CFStringRef vpnprefpath
= NULL
;
881 CFIndex path_len
= 0;
883 if (subtype
== NULL
|| directory
== NULL
) {
887 directory_url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
,
889 kCFURLPOSIXPathStyle
,
891 if (directory_url
== NULL
) {
892 SCPrint(TRUE
, stderr
, CFSTR("CFURLCreateWithFileSystemPath failed\n"));
896 directory_url_data
= CFURLCreateBookmarkData(NULL
, directory_url
, 0, 0, 0, 0);
897 if (directory_url_data
== NULL
) {
898 SCPrint(TRUE
, stderr
, CFSTR("CFURLCreateBookmarkData failed\n"));
902 vpnprefpath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@"), PREF_PREFIX
, subtype
, PREF_SUFFIX
);
903 if (vpnprefpath
== NULL
) {
904 SCPrint(TRUE
, stderr
, CFSTR("CFStringCreateWithFormat failed\n"));
908 path_len
= CFStringGetLength(vpnprefpath
) + 1;
909 path
= malloc(path_len
);
914 if (!CFStringGetCString(vpnprefpath
, path
, path_len
, kCFStringEncodingASCII
)) {
915 SCPrint(TRUE
, stderr
, CFSTR("CFStringGetCString failed\n"));
919 do_prefs_init(); /* initialization */
920 do_prefs_open(1, &path
); /* open prefs */
922 SCPreferencesSetValue(prefs
, CFSTR("ApplicationURL"), directory_url_data
);
927 my_CFRelease(&directory_url
);
928 my_CFRelease(&directory_url_data
);
929 my_CFRelease(&vpnprefpath
);
939 /* -----------------------------------------------------------------------------
940 ----------------------------------------------------------------------------- */
942 nc_enablevpn(int argc
, char **argv
)
944 CFStringRef argument
= NULL
;
945 CFStringRef vendorType
= NULL
;
949 SCPrint(TRUE
, stderr
, CFSTR("No service type or ID\n"));
951 argument
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
952 vendorType
= nc_copy_vendor_type(argument
);
953 my_CFRelease(&argument
);
955 if (!nc_enable_vpntype(vendorType
)) {
958 #if !TARGET_OS_IPHONE
960 argument
= CFStringCreateWithCString(NULL
, argv
[1], kCFStringEncodingUTF8
);
961 nc_set_application_url(vendorType
, argument
);
962 my_CFRelease(&argument
);
970 my_CFRelease(&vendorType
);
974 /* -----------------------------------------------------------------------------
975 ----------------------------------------------------------------------------- */
977 nc_show(int argc
, char **argv
)
979 SCNetworkServiceRef service
= NULL
;
980 SCDynamicStoreRef store
= NULL
;
982 CFStringRef serviceID
= NULL
;
983 CFStringRef iftype
= NULL
;
984 CFStringRef ifsubtype
= NULL
;
985 CFStringRef type_entity_key
= NULL
;
986 CFStringRef subtype_entity_key
= NULL
;
987 CFDictionaryRef type_entity_dict
= NULL
;
988 CFDictionaryRef subtype_entity_dict
= NULL
;
989 CFStringRef vpnprefpath
= NULL
;
990 #if !TARGET_OS_IPHONE
991 CFDataRef bookmarkData
= NULL
;
992 CFURLRef directory
= NULL
;
993 Boolean isStale
= FALSE
;
995 CFIndex path_len
= 0;
998 service
= nc_copy_service_from_arguments(argc
, argv
, NULL
);
999 if (service
== NULL
) {
1000 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
1004 if (!_SCNetworkServiceIsVPN(service
)) {
1005 SCPrint(TRUE
, stderr
, CFSTR("Not a connection oriented service: %@\n"), serviceID
);
1009 serviceID
= SCNetworkServiceGetServiceID(service
);
1011 nc_get_service_type_and_subtype(service
, &iftype
, &ifsubtype
);
1013 type_entity_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceID
, iftype
);
1015 nc_print_VPN_service(service
);
1017 #if !TARGET_OS_IPHONE
1018 vpnprefpath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@"), PREF_PREFIX
, ifsubtype
, PREF_SUFFIX
);
1019 if (vpnprefpath
== NULL
) {
1023 path_len
= CFStringGetLength(vpnprefpath
) + 1;
1024 path
= malloc(path_len
);
1029 if (!CFStringGetCString(vpnprefpath
, path
, path_len
, kCFStringEncodingASCII
)) {
1030 SCPrint(TRUE
, stderr
, CFSTR("CFStringGetCString failed\n"));
1034 do_prefs_init(); /* initialization */
1035 do_prefs_open(1, &path
); /* open prefs */
1037 bookmarkData
= SCPreferencesGetValue(prefs
, CFSTR("ApplicationURL"));
1038 if (bookmarkData
== NULL
) {
1042 directory
= CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault
, bookmarkData
, 0, NULL
, NULL
, &isStale
, NULL
);
1043 if (directory
== NULL
) {
1047 SCPrint(TRUE
, stdout
, CFSTR("ApplicationURL: %@\n"), directory
);
1051 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil --nc"), NULL
, NULL
);
1052 if (store
== NULL
) {
1053 SCPrint(TRUE
, stderr
, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError()));
1056 type_entity_dict
= SCDynamicStoreCopyValue(store
, type_entity_key
);
1058 if (!type_entity_dict
) {
1059 SCPrint(TRUE
, stderr
, CFSTR("No \"%@\" configuration available\n"), iftype
);
1061 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), iftype
, type_entity_dict
);
1065 subtype_entity_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceID
, ifsubtype
);
1066 subtype_entity_dict
= SCDynamicStoreCopyValue(store
, subtype_entity_key
);
1067 if (!subtype_entity_dict
) {
1071 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), ifsubtype
, subtype_entity_dict
);
1078 my_CFRelease(&type_entity_key
);
1079 my_CFRelease(&type_entity_dict
);
1080 my_CFRelease(&subtype_entity_key
);
1081 my_CFRelease(&subtype_entity_dict
);
1082 my_CFRelease(&store
);
1083 my_CFRelease(&service
);
1084 my_CFRelease(&vpnprefpath
);
1089 /* -----------------------------------------------------------------------------
1090 ----------------------------------------------------------------------------- */
1092 nc_select(int argc
, char **argv
)
1094 SCNetworkSetRef current_set
;
1096 SCNetworkServiceRef service
= NULL
;
1099 do_prefs_init(); /* initialization */
1100 do_prefs_open(0, NULL
); /* open default prefs */
1102 current_set
= SCNetworkSetCopyCurrent(prefs
);
1103 if (current_set
== NULL
) {
1104 SCPrint(TRUE
, stderr
, CFSTR("No current location\n"));
1108 service
= nc_copy_service_from_arguments(argc
, argv
, current_set
);
1109 if (service
== NULL
) {
1110 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
1114 #if !TARGET_OS_IPHONE
1115 status
= SCNetworkServiceSetEnabled(service
, TRUE
);
1117 SCPrint(TRUE
, stderr
, CFSTR("Unable to enable service: %s\n"), SCErrorString(SCError()));
1121 status
= SCNetworkSetSetSelectedVPNService(current_set
, service
);
1123 SCPrint(TRUE
, stderr
, CFSTR("Unable to select service: %s\n"), SCErrorString(SCError()));
1131 my_CFRelease(&service
);
1132 my_CFRelease(¤t_set
);
1137 /* -----------------------------------------------------------------------------
1138 ----------------------------------------------------------------------------- */
1140 nc_help(int argc
, char **argv
)
1142 SCPrint(TRUE
, stderr
, CFSTR("Valid commands for scutil --nc (VPN connections)\n"));
1143 SCPrint(TRUE
, stderr
, CFSTR("Usage: scutil --nc [command]\n"));
1144 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1145 SCPrint(TRUE
, stderr
, CFSTR("\tlist\n"));
1146 SCPrint(TRUE
, stderr
, CFSTR("\t\tList available network connection services in the current set\n"));
1147 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1148 SCPrint(TRUE
, stderr
, CFSTR("\tstatus <service>\n"));
1149 SCPrint(TRUE
, stderr
, CFSTR("\t\tIndicate whether a given service is connected, as well as extended status information for the service\n"));
1150 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1151 SCPrint(TRUE
, stderr
, CFSTR("\tshow <service>\n"));
1152 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisplay configuration information for a given service\n"));
1153 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1154 SCPrint(TRUE
, stderr
, CFSTR("\tstatistics <service>\n"));
1155 SCPrint(TRUE
, stderr
, CFSTR("\t\tProvide statistics on bytes, packets, and errors for a given service\n"));
1156 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1157 SCPrint(TRUE
, stderr
, CFSTR("\tselect <service>\n"));
1158 SCPrint(TRUE
, stderr
, CFSTR("\t\tMake the given service active in the current set. This allows it to be started\n"));
1159 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1160 SCPrint(TRUE
, stderr
, CFSTR("\tstart <service> [--user user] [--password password] [--secret secret]\n"));
1161 SCPrint(TRUE
, stderr
, CFSTR("\t\tStart a given service. Can take optional arguments for user, password, and secret\n"));
1162 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1163 SCPrint(TRUE
, stderr
, CFSTR("\tstop <service>\n"));
1164 SCPrint(TRUE
, stderr
, CFSTR("\t\tStop a given service\n"));
1165 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1166 SCPrint(TRUE
, stderr
, CFSTR("\tsuspend <service>\n"));
1167 SCPrint(TRUE
, stderr
, CFSTR("\t\tSuspend a given service (PPP, Modem on Hold)\n"));
1168 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1169 SCPrint(TRUE
, stderr
, CFSTR("\tresume <service>\n"));
1170 SCPrint(TRUE
, stderr
, CFSTR("\t\tResume a given service (PPP, Modem on Hold)\n"));
1171 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1172 SCPrint(TRUE
, stderr
, CFSTR("\tondemand [-W] [hostname]\n"));
1173 SCPrint(TRUE
, stderr
, CFSTR("\tondemand -- --refresh\n"));
1174 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisplay VPN on-demand information\n"));
1175 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1176 SCPrint(TRUE
, stderr
, CFSTR("\ttrigger <hostname> [background] [port]\n"));
1177 SCPrint(TRUE
, stderr
, CFSTR("\t\tTrigger VPN on-demand with specified hostname, and optional port and background flag\n"));
1178 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1179 #if !TARGET_OS_IPHONE
1180 SCPrint(TRUE
, stderr
, CFSTR("\tenablevpn <service or vpn type> [path]\n"));
1181 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"));
1182 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1184 SCPrint(TRUE
, stderr
, CFSTR("\tenablevpn <service or vpn type>\n"));
1185 SCPrint(TRUE
, stderr
, CFSTR("\t\tEnables the given VPN application type. Takes either a service or VPN type\n"));
1186 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1188 SCPrint(TRUE
, stderr
, CFSTR("\tdisablevpn <service or vpn type>\n"));
1189 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisables the given VPN application type. Takes either a service or VPN type\n"));
1190 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1191 SCPrint(TRUE
, stderr
, CFSTR("\thelp\n"));
1192 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisplay available commands for --nc\n"));
1193 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1197 /* -----------------------------------------------------------------------------
1198 ----------------------------------------------------------------------------- */
1199 typedef void (*nc_func
) (int argc
, char **argv
);
1201 static const struct {
1205 { "enablevpn", nc_enablevpn
},
1206 { "help", nc_help
},
1207 { "list", nc_list
},
1208 { "ondemand", nc_ondemand
},
1209 { "resume", nc_resume
},
1210 { "select", nc_select
},
1211 { "show", nc_show
},
1212 { "start", nc_start
},
1213 { "statistics", nc_statistics
},
1214 { "status", nc_status
},
1215 { "stop", nc_stop
},
1216 { "suspend", nc_suspend
},
1217 { "trigger", nc_trigger
},
1219 #define N_NC_CMNDS (sizeof(nc_cmds) / sizeof(nc_cmds[0]))
1222 /* -----------------------------------------------------------------------------
1223 ----------------------------------------------------------------------------- */
1225 find_nc_cmd(char *cmd
)
1229 for (i
= 0; i
< (int)N_NC_CMNDS
; i
++) {
1230 if (strcmp(cmd
, nc_cmds
[i
].cmd
) == 0) {
1239 /* -----------------------------------------------------------------------------
1240 ----------------------------------------------------------------------------- */
1242 do_nc_cmd(char *cmd
, int argc
, char **argv
, Boolean watch
)
1246 i
= find_nc_cmd(cmd
);
1250 func
= nc_cmds
[i
].func
;
1252 if (func
== nc_status
) {
1254 } else if (func
== nc_ondemand
) {
1255 ondemandwatch
= TRUE
;
1258 (*func
)(argc
, argv
);