2 * Copyright (c) 2010-2015, 2017, 2018 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
)
562 CFStringRef key
= NULL
;
563 CFDictionaryRef ondemand_dict
= NULL
;
565 struct timeval tv_now
;
567 if (CFArrayGetCount(changedKeys
) < 1) {
571 (void)gettimeofday(&tv_now
, NULL
);
572 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
574 SCPrint(TRUE
, stdout
, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"),
578 tv_now
.tv_usec
/ 1000);
580 if (ondemand_nodename
) {
581 checkOnDemandHost(store
, ondemand_nodename
, FALSE
);
582 checkOnDemandHost(store
, ondemand_nodename
, TRUE
);
584 key
= CFArrayGetValueAtIndex(changedKeys
, 0);
586 ondemand_dict
= SCDynamicStoreCopyValue(store
, key
);
588 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), kSCEntNetOnDemand
, ondemand_dict
);
590 SCPrint(TRUE
, stdout
, CFSTR("%@ not configured\n"), kSCEntNetOnDemand
);
593 my_CFRelease(&ondemand_dict
);
598 nc_ondemand(int argc
, char **argv
)
601 CFStringRef key
= NULL
;
602 CFDictionaryRef ondemand_dict
= NULL
;
603 SCDynamicStoreRef store
;
605 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil --nc"), nc_ondemand_callback
, NULL
);
607 SCPrint(TRUE
, stderr
, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError()));
612 #if !TARGET_OS_SIMULATOR
613 if (strcmp("--refresh", argv
[0]) == 0) {
614 SCNetworkConnectionRef connection
= NULL
;
616 connection
= SCNetworkConnectionCreate(kCFAllocatorDefault
, NULL
, NULL
);
617 if (connection
&& SCNetworkConnectionRefreshOnDemandState(connection
)) {
622 SCPrint(TRUE
, stderr
, CFSTR("Unable to refresh OnDemand state: %s\n"), SCErrorString(SCError()));
625 my_CFRelease(&connection
);
628 #endif // !TARGET_OS_SIMULATOR
630 ondemand_nodename
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
631 } else if (argc
!= 0) {
632 SCPrint(TRUE
, stderr
, CFSTR("Usage: scutil --nc ondemand [-W] [hostname]\n"
633 " scutil --nc ondemand -- --refresh\n"));
637 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetOnDemand
);
639 if (ondemand_nodename
) {
640 checkOnDemandHost(store
, ondemand_nodename
, FALSE
);
641 checkOnDemandHost(store
, ondemand_nodename
, TRUE
);
643 ondemand_dict
= SCDynamicStoreCopyValue(store
, key
);
645 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), kSCEntNetOnDemand
, ondemand_dict
);
647 SCPrint(TRUE
, stdout
, CFSTR("%@ not configured\n"), kSCEntNetOnDemand
);
652 CFMutableArrayRef keys
= NULL
;
654 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
655 CFArrayAppendValue(keys
, key
);
656 SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
660 SCDynamicStoreSetDispatchQueue(store
, dispatch_get_main_queue());
667 my_CFRelease(&ondemand_dict
);
669 my_CFRelease(&store
);
670 my_CFRelease(&ondemand_nodename
);
675 /* -----------------------------------------------------------------------------
676 ----------------------------------------------------------------------------- */
678 copy_padded_string(CFStringRef original
, int width
, CFStringRef prefix
, CFStringRef suffix
)
680 CFMutableStringRef padded
;
682 padded
= CFStringCreateMutable(NULL
, 0);
683 if (prefix
!= NULL
) {
684 CFStringAppend(padded
, prefix
);
686 if (original
!= NULL
) {
687 CFStringAppend(padded
, original
);
689 if (suffix
!= NULL
) {
690 CFStringAppend(padded
, suffix
);
692 CFStringPad(padded
, CFSTR(" "), MAX(CFStringGetLength(original
), width
), 0);
697 copy_VPN_status(SCNetworkServiceRef service
)
699 CFStringRef output
= NULL
;
700 SCNetworkConnectionStatus status
= kSCNetworkConnectionInvalid
;
701 SCNetworkConnectionRef service_connection
= NULL
;
703 /* Only calculate status is the service is enabled. Default is invalid. */
704 if (SCNetworkServiceGetEnabled(service
)) {
705 service_connection
= SCNetworkConnectionCreateWithService(NULL
, service
, NULL
, NULL
);
706 if (service_connection
== NULL
) goto done
;
707 status
= SCNetworkConnectionGetStatus(service_connection
);
710 output
= CFStringCreateWithCString(NULL
, nc_status_string(status
), kCFStringEncodingUTF8
);
713 my_CFRelease(&service_connection
);
718 nc_print_VPN_service(SCNetworkServiceRef service
)
720 SCNetworkInterfaceRef interface
= NULL
;
721 CFStringRef display_name
= NULL
;
722 CFStringRef display_name_padded
= NULL
;
723 CFStringRef service_id
= NULL
;
724 CFStringRef service_name
= NULL
;
725 CFStringRef service_name_padded
= NULL
;
726 CFStringRef service_status
= NULL
;
727 CFStringRef service_status_padded
= NULL
;
728 CFStringRef sub_type
= NULL
;
729 CFStringRef type
= NULL
;
731 nc_get_service_type_and_subtype(service
, &type
, &sub_type
);
733 service_name
= SCNetworkServiceGetName(service
);
734 service_name_padded
= copy_padded_string(service_name
, 32, CFSTR("\""), CFSTR("\""));
736 service_id
= SCNetworkServiceGetServiceID(service
);
738 interface
= SCNetworkServiceGetInterface(service
);
739 display_name
= SCNetworkInterfaceGetLocalizedDisplayName(interface
);
740 display_name_padded
= copy_padded_string(display_name
, 18, NULL
, NULL
);
742 service_status
= copy_VPN_status(service
);
743 service_status_padded
= copy_padded_string(service_status
, 16, CFSTR("("), CFSTR(")"));
747 CFSTR("%@ %@ %@ %@ %@ [%@%@%@]\n"),
748 SCNetworkServiceGetEnabled(service
) ? CFSTR("*") : CFSTR(" "),
749 service_status_padded
,
754 (sub_type
== NULL
) ? CFSTR("") : CFSTR(":"),
755 (sub_type
== NULL
) ? CFSTR("") : sub_type
);
757 CFRelease(display_name_padded
);
758 CFRelease(service_name_padded
);
759 CFRelease(service_status_padded
);
760 my_CFRelease(&service_status
);
764 /* -----------------------------------------------------------------------------
765 ----------------------------------------------------------------------------- */
767 nc_list(int argc
, char **argv
)
773 CFArrayRef services
= NULL
;
775 SCPrint(TRUE
, stdout
, CFSTR("Available network connection services in the current set (*=enabled):\n"));
776 services
= SCNetworkConnectionCopyAvailableServices(NULL
);
777 if (services
!= NULL
) {
778 count
= CFArrayGetCount(services
);
779 for (i
= 0; i
< count
; i
++) {
780 SCNetworkServiceRef service
;
782 service
= CFArrayGetValueAtIndex(services
, i
);
783 nc_print_VPN_service(service
);
787 my_CFRelease(&services
);
791 /* -----------------------------------------------------------------------------
792 ----------------------------------------------------------------------------- */
794 nc_enable_vpntype(CFStringRef vpnType
)
796 Boolean is_enabled
= FALSE
;
797 Boolean success
= FALSE
;
799 if (vpnType
== NULL
) {
800 SCPrint(TRUE
, stderr
, CFSTR("No VPN type provided\n"));
804 is_enabled
= VPNConfigurationIsVPNTypeEnabled(vpnType
);
807 SCPrint(TRUE
, stdout
, CFSTR("VPN is already enabled\n"));
809 #if !TARGET_OS_IPHONE
810 AuthorizationRef authorization
;
812 authorization
= _prefs_AuthorizationCreate();
813 if ((authorization
== NULL
) ||
814 !VPNConfigurationSetAuthorization(authorization
)) {
815 SCPrint(TRUE
, stderr
, CFSTR("VPNConfigurationSetAuthorization failed: %s\n"), SCErrorString(SCError()));
818 #endif // !TARGET_OS_IPHONE
820 if (!VPNConfigurationEnableVPNType(vpnType
)) {
821 SCPrint(TRUE
, stderr
, CFSTR("VPN could not be enabled: %s\n"), SCErrorString(SCError()));
825 #if !TARGET_OS_IPHONE
826 _prefs_AuthorizationFree(authorization
);
827 #endif // !TARGET_OS_IPHONE
829 SCPrint(TRUE
, stdout
, CFSTR("VPN enabled\n"));
837 /* Turns a service ID or name into a vendor type, or preserves type */
839 nc_copy_vendor_type (CFStringRef input
)
841 SCNetworkInterfaceRef child
;
842 SCNetworkInterfaceRef interface
;
843 CFStringRef output_name
= input
;
844 SCNetworkServiceRef service
= NULL
;
851 service
= nc_copy_service(NULL
, input
);
852 if (service
!= NULL
) {
853 interface
= SCNetworkServiceGetInterface(service
);
854 child
= SCNetworkInterfaceGetInterface(interface
);
855 type
= SCNetworkInterfaceGetInterfaceType(interface
);
857 /* Must be of type VPN */
858 if (!CFEqual(type
, kSCNetworkInterfaceTypeVPN
)) {
862 output_name
= SCNetworkInterfaceGetInterfaceType(child
);
867 if (output_name
!= NULL
) CFRetain(output_name
);
868 my_CFRelease(&service
);
872 /* -----------------------------------------------------------------------------
873 ----------------------------------------------------------------------------- */
874 #if !TARGET_OS_IPHONE
875 static const CFStringRef PREF_PREFIX
= CFSTR("VPN-");
876 static const CFStringRef PREF_SUFFIX
= CFSTR(".plist");
878 nc_set_application_url(CFStringRef subtype
, CFStringRef directory
)
880 CFURLRef directory_url
= NULL
;
881 CFDataRef directory_url_data
= NULL
;
882 CFStringRef vpnprefpath
= NULL
;
884 CFIndex path_len
= 0;
886 if (subtype
== NULL
|| directory
== NULL
) {
890 directory_url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
,
892 kCFURLPOSIXPathStyle
,
894 if (directory_url
== NULL
) {
895 SCPrint(TRUE
, stderr
, CFSTR("CFURLCreateWithFileSystemPath failed\n"));
899 directory_url_data
= CFURLCreateBookmarkData(NULL
, directory_url
, 0, 0, 0, 0);
900 if (directory_url_data
== NULL
) {
901 SCPrint(TRUE
, stderr
, CFSTR("CFURLCreateBookmarkData failed\n"));
905 vpnprefpath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@"), PREF_PREFIX
, subtype
, PREF_SUFFIX
);
906 if (vpnprefpath
== NULL
) {
907 SCPrint(TRUE
, stderr
, CFSTR("CFStringCreateWithFormat failed\n"));
911 path_len
= CFStringGetLength(vpnprefpath
) + 1;
912 path
= malloc(path_len
);
917 if (!CFStringGetCString(vpnprefpath
, path
, path_len
, kCFStringEncodingASCII
)) {
918 SCPrint(TRUE
, stderr
, CFSTR("CFStringGetCString failed\n"));
922 do_prefs_init(); /* initialization */
923 do_prefs_open(1, &path
); /* open prefs */
925 SCPreferencesSetValue(prefs
, CFSTR("ApplicationURL"), directory_url_data
);
930 my_CFRelease(&directory_url
);
931 my_CFRelease(&directory_url_data
);
932 my_CFRelease(&vpnprefpath
);
940 #endif // !TARGET_OS_IPHONE
942 /* -----------------------------------------------------------------------------
943 ----------------------------------------------------------------------------- */
945 nc_enablevpn(int argc
, char **argv
)
947 CFStringRef argument
= NULL
;
948 CFStringRef vendorType
= NULL
;
952 SCPrint(TRUE
, stderr
, CFSTR("No service type or ID\n"));
954 argument
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
955 vendorType
= nc_copy_vendor_type(argument
);
956 my_CFRelease(&argument
);
958 if (!nc_enable_vpntype(vendorType
)) {
961 #if !TARGET_OS_IPHONE
963 argument
= CFStringCreateWithCString(NULL
, argv
[1], kCFStringEncodingUTF8
);
964 nc_set_application_url(vendorType
, argument
);
965 my_CFRelease(&argument
);
967 #endif // !TARGET_OS_IPHONE
973 my_CFRelease(&vendorType
);
977 /* -----------------------------------------------------------------------------
978 ----------------------------------------------------------------------------- */
980 nc_show(int argc
, char **argv
)
982 SCNetworkServiceRef service
= NULL
;
983 SCDynamicStoreRef store
= NULL
;
985 CFStringRef serviceID
= NULL
;
986 CFStringRef iftype
= NULL
;
987 CFStringRef ifsubtype
= NULL
;
988 CFStringRef type_entity_key
= NULL
;
989 CFStringRef subtype_entity_key
= NULL
;
990 CFDictionaryRef type_entity_dict
= NULL
;
991 CFDictionaryRef subtype_entity_dict
= NULL
;
992 CFStringRef vpnprefpath
= NULL
;
993 #if !TARGET_OS_IPHONE
994 CFDataRef bookmarkData
= NULL
;
995 CFURLRef directory
= NULL
;
996 Boolean isStale
= FALSE
;
998 CFIndex path_len
= 0;
999 #endif // !TARGET_OS_IPHONE
1001 service
= nc_copy_service_from_arguments(argc
, argv
, NULL
);
1002 if (service
== NULL
) {
1003 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
1007 if (!_SCNetworkServiceIsVPN(service
)) {
1008 SCPrint(TRUE
, stderr
, CFSTR("Not a connection oriented service: %@\n"), serviceID
);
1012 serviceID
= SCNetworkServiceGetServiceID(service
);
1014 nc_get_service_type_and_subtype(service
, &iftype
, &ifsubtype
);
1016 type_entity_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceID
, iftype
);
1018 nc_print_VPN_service(service
);
1020 #if !TARGET_OS_IPHONE
1021 vpnprefpath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@%@"), PREF_PREFIX
, ifsubtype
, PREF_SUFFIX
);
1022 if (vpnprefpath
== NULL
) {
1026 path_len
= CFStringGetLength(vpnprefpath
) + 1;
1027 path
= malloc(path_len
);
1032 if (!CFStringGetCString(vpnprefpath
, path
, path_len
, kCFStringEncodingASCII
)) {
1033 SCPrint(TRUE
, stderr
, CFSTR("CFStringGetCString failed\n"));
1037 do_prefs_init(); /* initialization */
1038 do_prefs_open(1, &path
); /* open prefs */
1040 bookmarkData
= SCPreferencesGetValue(prefs
, CFSTR("ApplicationURL"));
1041 if (bookmarkData
== NULL
) {
1045 directory
= CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault
, bookmarkData
, 0, NULL
, NULL
, &isStale
, NULL
);
1046 if (directory
== NULL
) {
1050 SCPrint(TRUE
, stdout
, CFSTR("ApplicationURL: %@\n"), directory
);
1052 #endif // !TARGET_OS_IPHONE
1054 store
= SCDynamicStoreCreate(NULL
, CFSTR("scutil --nc"), NULL
, NULL
);
1055 if (store
== NULL
) {
1056 SCPrint(TRUE
, stderr
, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError()));
1059 type_entity_dict
= SCDynamicStoreCopyValue(store
, type_entity_key
);
1061 if (!type_entity_dict
) {
1062 SCPrint(TRUE
, stderr
, CFSTR("No \"%@\" configuration available\n"), iftype
);
1064 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), iftype
, type_entity_dict
);
1068 subtype_entity_key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
, kSCDynamicStoreDomainSetup
, serviceID
, ifsubtype
);
1069 subtype_entity_dict
= SCDynamicStoreCopyValue(store
, subtype_entity_key
);
1070 if (!subtype_entity_dict
) {
1074 SCPrint(TRUE
, stdout
, CFSTR("%@ %@\n"), ifsubtype
, subtype_entity_dict
);
1081 my_CFRelease(&type_entity_key
);
1082 my_CFRelease(&type_entity_dict
);
1083 my_CFRelease(&subtype_entity_key
);
1084 my_CFRelease(&subtype_entity_dict
);
1085 my_CFRelease(&store
);
1086 my_CFRelease(&service
);
1087 my_CFRelease(&vpnprefpath
);
1092 /* -----------------------------------------------------------------------------
1093 ----------------------------------------------------------------------------- */
1095 nc_select(int argc
, char **argv
)
1097 SCNetworkSetRef current_set
;
1099 SCNetworkServiceRef service
= NULL
;
1102 do_prefs_init(); /* initialization */
1103 do_prefs_open(0, NULL
); /* open default prefs */
1105 current_set
= SCNetworkSetCopyCurrent(prefs
);
1106 if (current_set
== NULL
) {
1107 SCPrint(TRUE
, stderr
, CFSTR("No current location\n"));
1111 service
= nc_copy_service_from_arguments(argc
, argv
, current_set
);
1112 if (service
== NULL
) {
1113 SCPrint(TRUE
, stderr
, CFSTR("No service\n"));
1117 #if !TARGET_OS_IPHONE
1118 status
= SCNetworkServiceSetEnabled(service
, TRUE
);
1120 SCPrint(TRUE
, stderr
, CFSTR("Unable to enable service: %s\n"), SCErrorString(SCError()));
1123 #else // !TARGET_OS_IPHONE
1124 status
= SCNetworkSetSetSelectedVPNService(current_set
, service
);
1126 SCPrint(TRUE
, stderr
, CFSTR("Unable to select service: %s\n"), SCErrorString(SCError()));
1129 #endif // !TARGET_OS_IPHONE
1134 my_CFRelease(&service
);
1135 my_CFRelease(¤t_set
);
1140 /* -----------------------------------------------------------------------------
1141 ----------------------------------------------------------------------------- */
1143 nc_help(int argc
, char **argv
)
1145 #pragma unused(argc)
1146 #pragma unused(argv)
1147 SCPrint(TRUE
, stderr
, CFSTR("Valid commands for scutil --nc (VPN connections)\n"));
1148 SCPrint(TRUE
, stderr
, CFSTR("Usage: scutil --nc [command]\n"));
1149 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1150 SCPrint(TRUE
, stderr
, CFSTR("\tlist\n"));
1151 SCPrint(TRUE
, stderr
, CFSTR("\t\tList available network connection services in the current set\n"));
1152 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1153 SCPrint(TRUE
, stderr
, CFSTR("\tstatus <service>\n"));
1154 SCPrint(TRUE
, stderr
, CFSTR("\t\tIndicate whether a given service is connected, as well as extended status information for the service\n"));
1155 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1156 SCPrint(TRUE
, stderr
, CFSTR("\tshow <service>\n"));
1157 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisplay configuration information for a given service\n"));
1158 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1159 SCPrint(TRUE
, stderr
, CFSTR("\tstatistics <service>\n"));
1160 SCPrint(TRUE
, stderr
, CFSTR("\t\tProvide statistics on bytes, packets, and errors for a given service\n"));
1161 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1162 SCPrint(TRUE
, stderr
, CFSTR("\tselect <service>\n"));
1163 SCPrint(TRUE
, stderr
, CFSTR("\t\tMake the given service active in the current set. This allows it to be started\n"));
1164 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1165 SCPrint(TRUE
, stderr
, CFSTR("\tstart <service> [--user user] [--password password] [--secret secret]\n"));
1166 SCPrint(TRUE
, stderr
, CFSTR("\t\tStart a given service. Can take optional arguments for user, password, and secret\n"));
1167 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1168 SCPrint(TRUE
, stderr
, CFSTR("\tstop <service>\n"));
1169 SCPrint(TRUE
, stderr
, CFSTR("\t\tStop a given service\n"));
1170 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1171 SCPrint(TRUE
, stderr
, CFSTR("\tsuspend <service>\n"));
1172 SCPrint(TRUE
, stderr
, CFSTR("\t\tSuspend a given service (PPP, Modem on Hold)\n"));
1173 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1174 SCPrint(TRUE
, stderr
, CFSTR("\tresume <service>\n"));
1175 SCPrint(TRUE
, stderr
, CFSTR("\t\tResume a given service (PPP, Modem on Hold)\n"));
1176 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1177 SCPrint(TRUE
, stderr
, CFSTR("\tondemand [-W] [hostname]\n"));
1178 SCPrint(TRUE
, stderr
, CFSTR("\tondemand -- --refresh\n"));
1179 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisplay VPN on-demand information\n"));
1180 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1181 SCPrint(TRUE
, stderr
, CFSTR("\ttrigger <hostname> [background] [port]\n"));
1182 SCPrint(TRUE
, stderr
, CFSTR("\t\tTrigger VPN on-demand with specified hostname, and optional port and background flag\n"));
1183 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1184 #if !TARGET_OS_IPHONE
1185 SCPrint(TRUE
, stderr
, CFSTR("\tenablevpn <service or vpn type> [path]\n"));
1186 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"));
1187 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1188 #else // !TARGET_OS_IPHONE
1189 SCPrint(TRUE
, stderr
, CFSTR("\tenablevpn <service or vpn type>\n"));
1190 SCPrint(TRUE
, stderr
, CFSTR("\t\tEnables the given VPN application type. Takes either a service or VPN type\n"));
1191 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1192 #endif // !TARGET_OS_IPHONE
1193 SCPrint(TRUE
, stderr
, CFSTR("\tdisablevpn <service or vpn type>\n"));
1194 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisables the given VPN application type. Takes either a service or VPN type\n"));
1195 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1196 SCPrint(TRUE
, stderr
, CFSTR("\thelp\n"));
1197 SCPrint(TRUE
, stderr
, CFSTR("\t\tDisplay available commands for --nc\n"));
1198 SCPrint(TRUE
, stderr
, CFSTR("\n"));
1202 /* -----------------------------------------------------------------------------
1203 ----------------------------------------------------------------------------- */
1204 typedef void (*nc_func
) (int argc
, char **argv
);
1206 static const struct {
1210 { "enablevpn", nc_enablevpn
},
1211 { "help", nc_help
},
1212 { "list", nc_list
},
1213 { "ondemand", nc_ondemand
},
1214 { "resume", nc_resume
},
1215 { "select", nc_select
},
1216 { "show", nc_show
},
1217 { "start", nc_start
},
1218 { "statistics", nc_statistics
},
1219 { "status", nc_status
},
1220 { "stop", nc_stop
},
1221 { "suspend", nc_suspend
},
1222 { "trigger", nc_trigger
},
1224 #define N_NC_CMNDS (sizeof(nc_cmds) / sizeof(nc_cmds[0]))
1227 /* -----------------------------------------------------------------------------
1228 ----------------------------------------------------------------------------- */
1230 find_nc_cmd(char *cmd
)
1234 for (i
= 0; i
< (int)N_NC_CMNDS
; i
++) {
1235 if (strcmp(cmd
, nc_cmds
[i
].cmd
) == 0) {
1244 /* -----------------------------------------------------------------------------
1245 ----------------------------------------------------------------------------- */
1247 do_nc_cmd(char *cmd
, int argc
, char **argv
, Boolean watch
)
1251 i
= find_nc_cmd(cmd
);
1255 func
= nc_cmds
[i
].func
;
1257 if (func
== nc_status
) {
1259 } else if (func
== nc_ondemand
) {
1260 ondemandwatch
= TRUE
;
1263 (*func
)(argc
, argv
);