X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/17d3ee29fb04fcc79d3be0b9d5c7bcb377cfc610..HEAD:/scutil.tproj/nc.c?ds=inline diff --git a/scutil.tproj/nc.c b/scutil.tproj/nc.c index 551289c..b4b6766 100644 --- a/scutil.tproj/nc.c +++ b/scutil.tproj/nc.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2010-2012 Apple Inc. All rights reserved. + * Copyright (c) 2010-2015, 2017-2019 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,7 +17,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ @@ -41,11 +41,19 @@ #include "nc.h" #include "prefs.h" +#include + #include +#if !TARGET_OS_SIMULATOR +#include +#endif // !TARGET_OS_SIMULATOR -CFStringRef username = NULL; -CFStringRef password = NULL; -CFStringRef sharedsecret = NULL; +CFStringRef username = NULL; +CFStringRef password = NULL; +CFStringRef sharedsecret = NULL; + +static Boolean ondemandwatch = FALSE; +static CFStringRef ondemand_nodename = NULL; static SCNetworkConnectionRef connection = NULL; static int n_callback = 0; @@ -143,7 +151,7 @@ nc_copy_service_from_arguments(int argc, char **argv, SCNetworkSetRef set) { SCNetworkServiceRef service = NULL; if (argc == 0) { - serviceID = _copyStringFromSTDIN(); + serviceID = _copyStringFromSTDIN(CFSTR("Service"), NULL); } else { serviceID = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); } @@ -242,6 +250,70 @@ nc_create_connection(int argc, char **argv, Boolean exit_on_failure) } } +/* ----------------------------------------------------------------------------- + ----------------------------------------------------------------------------- */ + +static void +nc_trigger(int argc, char **argv) +{ + Boolean background = FALSE; + int i; + CFStringRef hostName = NULL; + int port = 80; + + for (i = 0; i < 3 && i < argc; i++) { + /* Parse host name. Must be first arg. */ + if (i == 0) { + hostName = CFStringCreateWithCString(NULL, argv[i], kCFStringEncodingUTF8); + continue; + } + + /* Check for optional background flag */ + if (strcmp(argv[i], "background") == 0) { + background = TRUE; + continue; + } + + /* Parse optional port number */ + CFStringRef str = CFStringCreateWithCString(NULL, argv[i], kCFStringEncodingUTF8); + if (str) { + int num = CFStringGetIntValue(str); + if (num) { + port = num; + } + my_CFRelease(&str); + } + } + + if (hostName) { + CFReadStreamRef readStream = NULL; + CFWriteStreamRef writeStream = NULL; + + CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, hostName, port, &readStream, &writeStream); + + if (background) { + CFReadStreamSetProperty(readStream, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground")); + CFWriteStreamSetProperty(writeStream, CFSTR("kCFStreamNetworkServiceType"), CFSTR("kCFStreamNetworkServiceTypeBackground")); + } + + if (readStream && writeStream) { + CFReadStreamOpen(readStream); + CFWriteStreamOpen(writeStream); + SCPrint(TRUE, stdout, CFSTR("Opened stream to %@, port %d%s\n"), hostName, port, background ? ", background traffic class" : ""); + sleep(1); + } + + my_CFRelease(&readStream); + my_CFRelease(&writeStream); + } else { + SCPrint(TRUE, stderr, CFSTR("Invalid or missing host name\n")); + } + + my_CFRelease(&hostName); + + exit(0); +} + /* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ static void @@ -402,7 +474,7 @@ nc_watch(int argc, char **argv) // setup watcher if (doDispatch) { - if (!SCNetworkConnectionSetDispatchQueue(connection, dispatch_get_current_queue())) { + if (!SCNetworkConnectionSetDispatchQueue(connection, dispatch_get_main_queue())) { SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError())); exit(1); } @@ -486,6 +558,45 @@ checkOnDemandHost(SCDynamicStoreRef store, CFStringRef nodeName, Boolean retry) return; } +static void +nc_ondemand_callback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) +{ +#pragma unused(info) + CFStringRef key = NULL; + CFDictionaryRef ondemand_dict = NULL; + struct tm tm_now; + struct timeval tv_now; + + if (CFArrayGetCount(changedKeys) < 1) { + return; + } + + (void)gettimeofday(&tv_now, NULL); + (void)localtime_r(&tv_now.tv_sec, &tm_now); + + SCPrint(TRUE, stdout, CFSTR("\n*** %2d:%02d:%02d.%03d\n\n"), + tm_now.tm_hour, + tm_now.tm_min, + tm_now.tm_sec, + tv_now.tv_usec / 1000); + + if (ondemand_nodename) { + checkOnDemandHost(store, ondemand_nodename, FALSE); + checkOnDemandHost(store, ondemand_nodename, TRUE); + } else { + key = CFArrayGetValueAtIndex(changedKeys, 0); + + ondemand_dict = SCDynamicStoreCopyValue(store, key); + if (ondemand_dict) { + SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), kSCEntNetOnDemand, ondemand_dict); + } else { + SCPrint(TRUE, stdout, CFSTR("%@ not configured\n"), kSCEntNetOnDemand); + } + + my_CFRelease(&ondemand_dict); + } +} + static void nc_ondemand(int argc, char **argv) { @@ -494,28 +605,64 @@ nc_ondemand(int argc, char **argv) CFDictionaryRef ondemand_dict = NULL; SCDynamicStoreRef store; - store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL); + store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), nc_ondemand_callback, NULL); if (store == NULL) { SCPrint(TRUE, stderr, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError())); goto done; } - if (argc > 0) { - CFStringRef nodeName; + if (argc == 1) { +#if !TARGET_OS_SIMULATOR + if (strcmp("--refresh", argv[0]) == 0) { + SCNetworkConnectionRef connection = NULL; + + connection = SCNetworkConnectionCreate(kCFAllocatorDefault, NULL, NULL); + if (connection && SCNetworkConnectionRefreshOnDemandState(connection)) { + exit_code = 0; + } + + if (exit_code) { + SCPrint(TRUE, stderr, CFSTR("Unable to refresh OnDemand state: %s\n"), SCErrorString(SCError())); + } + + my_CFRelease(&connection); + goto done; + } +#endif // !TARGET_OS_SIMULATOR - nodeName = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); - checkOnDemandHost(store, nodeName, FALSE); - checkOnDemandHost(store, nodeName, TRUE); + ondemand_nodename = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); + } else if (argc != 0) { + SCPrint(TRUE, stderr, CFSTR("Usage: scutil --nc ondemand [-W] [hostname]\n" + " scutil --nc ondemand -- --refresh\n")); goto done; } key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetOnDemand); - ondemand_dict = SCDynamicStoreCopyValue(store, key); - if (ondemand_dict) { - SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), kSCEntNetOnDemand, ondemand_dict); + if (ondemand_nodename) { + checkOnDemandHost(store, ondemand_nodename, FALSE); + checkOnDemandHost(store, ondemand_nodename, TRUE); } else { - SCPrint(TRUE, stdout, CFSTR("%@ not configured\n"), kSCEntNetOnDemand); + ondemand_dict = SCDynamicStoreCopyValue(store, key); + if (ondemand_dict) { + SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), kSCEntNetOnDemand, ondemand_dict); + } else { + SCPrint(TRUE, stdout, CFSTR("%@ not configured\n"), kSCEntNetOnDemand); + } + } + + if (ondemandwatch) { + CFMutableArrayRef keys = NULL; + + keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(keys, key); + SCDynamicStoreSetNotificationKeys(store, keys, NULL); + + my_CFRelease(&keys); + + SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()); + + CFRunLoopRun(); } exit_code = 0; @@ -523,63 +670,97 @@ done: my_CFRelease(&ondemand_dict); my_CFRelease(&key); my_CFRelease(&store); + my_CFRelease(&ondemand_nodename); exit(exit_code); } /* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - CFStringRef -copy_padded_string(CFStringRef original, int width) +copy_padded_string(CFStringRef original, int width, CFStringRef prefix, CFStringRef suffix) { CFMutableStringRef padded; - padded = CFStringCreateMutableCopy(NULL, 0, original); + padded = CFStringCreateMutable(NULL, 0); + if (prefix != NULL) { + CFStringAppend(padded, prefix); + } + if (original != NULL) { + CFStringAppend(padded, original); + } + if (suffix != NULL) { + CFStringAppend(padded, suffix); + } CFStringPad(padded, CFSTR(" "), MAX(CFStringGetLength(original), width), 0); return padded; } +CFStringRef +copy_VPN_status(SCNetworkServiceRef service) +{ + CFStringRef output = NULL; + SCNetworkConnectionStatus status = kSCNetworkConnectionInvalid; + SCNetworkConnectionRef service_connection = NULL; + + /* Only calculate status is the service is enabled. Default is invalid. */ + if (SCNetworkServiceGetEnabled(service)) { + service_connection = SCNetworkConnectionCreateWithService(NULL, service, NULL, NULL); + if (service_connection == NULL) goto done; + status = SCNetworkConnectionGetStatus(service_connection); + } + + output = CFStringCreateWithCString(NULL, nc_status_string(status), kCFStringEncodingUTF8); + +done: + my_CFRelease(&service_connection); + return output; +} static void nc_print_VPN_service(SCNetworkServiceRef service) { - CFStringRef type = NULL; + SCNetworkInterfaceRef interface = NULL; + CFStringRef display_name = NULL; + CFStringRef display_name_padded = NULL; + CFStringRef service_id = NULL; + CFStringRef service_name = NULL; + CFStringRef service_name_padded = NULL; + CFStringRef service_status = NULL; + CFStringRef service_status_padded = NULL; CFStringRef sub_type = NULL; + CFStringRef type = NULL; nc_get_service_type_and_subtype(service, &type, &sub_type); - CFStringRef service_name = SCNetworkServiceGetName(service); - if (service_name == NULL) - service_name = CFSTR(""); - CFStringRef service_name_quoted = CFStringCreateWithFormat(NULL, NULL, CFSTR("\"%@\""), service_name); - if (service_name_quoted == NULL) { - service_name_quoted = CFRetain(CFSTR("")); - } - CFStringRef service_name_padded = copy_padded_string(service_name, 30); + service_name = SCNetworkServiceGetName(service); + service_name_padded = copy_padded_string(service_name, 32, CFSTR("\""), CFSTR("\"")); - CFStringRef service_id = SCNetworkServiceGetServiceID(service); - SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface(service); - CFStringRef display_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); - if (display_name == NULL) - display_name = CFSTR(""); - CFStringRef display_name_padded = copy_padded_string(display_name, 18); + service_id = SCNetworkServiceGetServiceID(service); + interface = SCNetworkServiceGetInterface(service); + display_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); + display_name_padded = copy_padded_string(display_name, 18, NULL, NULL); + + service_status = copy_VPN_status(service); + service_status_padded = copy_padded_string(service_status, 16, CFSTR("("), CFSTR(")")); SCPrint(TRUE, stdout, - CFSTR("%@ %@ %@ %@ [%@%@%@]\n"), + CFSTR("%@ %@ %@ %@ %@ [%@%@%@]\n"), SCNetworkServiceGetEnabled(service) ? CFSTR("*") : CFSTR(" "), + service_status_padded, service_id, display_name_padded, service_name_padded, type, (sub_type == NULL) ? CFSTR("") : CFSTR(":"), (sub_type == NULL) ? CFSTR("") : sub_type); - CFRelease(service_name_quoted); + CFRelease(display_name_padded); CFRelease(service_name_padded); + CFRelease(service_status_padded); + my_CFRelease(&service_status); } @@ -588,15 +769,16 @@ nc_print_VPN_service(SCNetworkServiceRef service) static void nc_list(int argc, char **argv) { - int count; - int i; +#pragma unused(argc) +#pragma unused(argv) + CFIndex count; + CFIndex i; CFArrayRef services = NULL; SCPrint(TRUE, stdout, CFSTR("Available network connection services in the current set (*=enabled):\n")); services = SCNetworkConnectionCopyAvailableServices(NULL); if (services != NULL) { count = CFArrayGetCount(services); - for (i = 0; i < count; i++) { SCNetworkServiceRef service; @@ -609,22 +791,215 @@ nc_list(int argc, char **argv) exit(0); } +/* ----------------------------------------------------------------------------- + ----------------------------------------------------------------------------- */ +static Boolean +nc_enable_vpntype(CFStringRef vpnType) +{ + Boolean is_enabled = FALSE; + Boolean success = FALSE; + + if (vpnType == NULL) { + SCPrint(TRUE, stderr, CFSTR("No VPN type provided\n")); + goto done; + } + + is_enabled = VPNConfigurationIsVPNTypeEnabled(vpnType); + + if (is_enabled) { + SCPrint(TRUE, stdout, CFSTR("VPN is already enabled\n")); + } else { +#if !TARGET_OS_IPHONE + AuthorizationRef authorization; + + authorization = _prefs_AuthorizationCreate(); + if ((authorization == NULL) || + !VPNConfigurationSetAuthorization(authorization)) { + SCPrint(TRUE, stderr, CFSTR("VPNConfigurationSetAuthorization failed: %s\n"), SCErrorString(SCError())); + goto done; + } +#endif // !TARGET_OS_IPHONE + + if (!VPNConfigurationEnableVPNType(vpnType)) { + SCPrint(TRUE, stderr, CFSTR("VPN could not be enabled: %s\n"), SCErrorString(SCError())); + goto done; + } + +#if !TARGET_OS_IPHONE + _prefs_AuthorizationFree(authorization); +#endif // !TARGET_OS_IPHONE + + SCPrint(TRUE, stdout, CFSTR("VPN enabled\n")); + } + success = TRUE; + +done: + return success; +} + +/* Turns a service ID or name into a vendor type, or preserves type */ +static CFStringRef +nc_copy_vendor_type (CFStringRef input) +{ + SCNetworkInterfaceRef child; + SCNetworkInterfaceRef interface; + CFStringRef output_name = input; + SCNetworkServiceRef service = NULL; + CFStringRef type; + + if (input == NULL) { + goto done; + } + + service = nc_copy_service(NULL, input); + if (service != NULL) { + interface = SCNetworkServiceGetInterface(service); + child = SCNetworkInterfaceGetInterface(interface); + type = SCNetworkInterfaceGetInterfaceType(interface); + + /* Must be of type VPN */ + if (!CFEqual(type, kSCNetworkInterfaceTypeVPN)) { + output_name = NULL; + goto done; + } + output_name = SCNetworkInterfaceGetInterfaceType(child); + goto done; + } + +done : + if (output_name != NULL) CFRetain(output_name); + my_CFRelease(&service); + return output_name; +} + +/* ----------------------------------------------------------------------------- + ----------------------------------------------------------------------------- */ +#if !TARGET_OS_IPHONE +static const CFStringRef PREF_PREFIX = CFSTR("VPN-"); +static const CFStringRef PREF_SUFFIX = CFSTR(".plist"); +static void +nc_set_application_url(CFStringRef subtype, CFStringRef directory) +{ + CFURLRef directory_url = NULL; + CFDataRef directory_url_data = NULL; + CFStringRef vpnprefpath = NULL; + char *path = NULL; + CFIndex path_len = 0; + + if (subtype == NULL || directory == NULL) { + goto done; + } + + directory_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, + directory, + kCFURLPOSIXPathStyle, + FALSE); + if (directory_url == NULL) { + SCPrint(TRUE, stderr, CFSTR("CFURLCreateWithFileSystemPath failed\n")); + goto done; + } + + directory_url_data = CFURLCreateBookmarkData(NULL, directory_url, 0, 0, 0, 0); + if (directory_url_data == NULL) { + SCPrint(TRUE, stderr, CFSTR("CFURLCreateBookmarkData failed\n")); + goto done; + } + + vpnprefpath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@"), PREF_PREFIX, subtype, PREF_SUFFIX ); + if (vpnprefpath == NULL) { + SCPrint(TRUE, stderr, CFSTR("CFStringCreateWithFormat failed\n")); + goto done; + } + + path_len = CFStringGetLength(vpnprefpath) + 1; + path = malloc(path_len); + if (path == NULL) { + goto done; + } + + if (!CFStringGetCString(vpnprefpath, path, path_len, kCFStringEncodingASCII)) { + SCPrint(TRUE, stderr, CFSTR("CFStringGetCString failed\n")); + goto done; + } + + do_prefs_init(); /* initialization */ + do_prefs_open(1, &path); /* open prefs */ + + SCPreferencesSetValue(prefs, CFSTR("ApplicationURL"), directory_url_data); + + _prefs_save(); + +done: + my_CFRelease(&directory_url); + my_CFRelease(&directory_url_data); + my_CFRelease(&vpnprefpath); + if (path) { + free(path); + } + _prefs_close(); + + exit(0); +} +#endif // !TARGET_OS_IPHONE + +/* ----------------------------------------------------------------------------- + ----------------------------------------------------------------------------- */ +static void +nc_enablevpn(int argc, char **argv) +{ + CFStringRef argument = NULL; + CFStringRef vendorType = NULL; + int exit_code = 1; + + if (argc == 0) { + SCPrint(TRUE, stderr, CFSTR("No service type or ID\n")); + } else { + argument = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); + vendorType = nc_copy_vendor_type(argument); + my_CFRelease(&argument); + + if (!nc_enable_vpntype(vendorType)) { + goto done; + } +#if !TARGET_OS_IPHONE + if (argc >= 2) { + argument = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8); + nc_set_application_url(vendorType, argument); + my_CFRelease(&argument); + } +#endif // !TARGET_OS_IPHONE + } + + exit_code = 0; + +done: + my_CFRelease(&vendorType); + exit(exit_code); +} /* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ static void nc_show(int argc, char **argv) { - SCNetworkServiceRef service = NULL; - SCDynamicStoreRef store = NULL; - int exit_code = 1; - CFStringRef serviceID = NULL; - CFStringRef iftype = NULL; - CFStringRef ifsubtype = NULL; - CFStringRef type_entity_key = NULL; - CFStringRef subtype_entity_key = NULL; - CFDictionaryRef type_entity_dict = NULL; - CFDictionaryRef subtype_entity_dict = NULL; + SCNetworkServiceRef service = NULL; + SCDynamicStoreRef store = NULL; + int exit_code = 1; + CFStringRef serviceID = NULL; + CFStringRef iftype = NULL; + CFStringRef ifsubtype = NULL; + CFStringRef type_entity_key = NULL; + CFStringRef subtype_entity_key = NULL; + CFDictionaryRef type_entity_dict = NULL; + CFDictionaryRef subtype_entity_dict = NULL; + CFStringRef vpnprefpath = NULL; +#if !TARGET_OS_IPHONE + CFDataRef bookmarkData = NULL; + CFURLRef directory = NULL; + Boolean isStale = FALSE; + char *path = NULL; + CFIndex path_len = 0; +#endif // !TARGET_OS_IPHONE service = nc_copy_service_from_arguments(argc, argv, NULL); if (service == NULL) { @@ -632,20 +1007,52 @@ nc_show(int argc, char **argv) exit(exit_code); } + if (!_SCNetworkServiceIsVPN(service)) { + SCPrint(TRUE, stderr, CFSTR("Not a connection oriented service: %@\n"), serviceID); + goto done; + } + serviceID = SCNetworkServiceGetServiceID(service); nc_get_service_type_and_subtype(service, &iftype, &ifsubtype); - if (!CFEqual(iftype, kSCEntNetPPP) && - !CFEqual(iftype, kSCEntNetIPSec) && - !CFEqual(iftype, kSCEntNetVPN)) { - SCPrint(TRUE, stderr, CFSTR("Not a connection oriented service: %@\n"), serviceID); + type_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, iftype); + + nc_print_VPN_service(service); + +#if !TARGET_OS_IPHONE + vpnprefpath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@"), PREF_PREFIX, ifsubtype, PREF_SUFFIX); + if (vpnprefpath == NULL) { + goto skipURL; + } + + path_len = CFStringGetLength(vpnprefpath) + 1; + path = malloc(path_len); + if (path == NULL) { + goto skipURL; + } + + if (!CFStringGetCString(vpnprefpath, path, path_len, kCFStringEncodingASCII)) { + SCPrint(TRUE, stderr, CFSTR("CFStringGetCString failed\n")); goto done; } - type_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, iftype); + do_prefs_init(); /* initialization */ + do_prefs_open(1, &path); /* open prefs */ - nc_print_VPN_service(service); + bookmarkData = SCPreferencesGetValue(prefs, CFSTR("ApplicationURL")); + if (bookmarkData == NULL) { + goto skipURL; + } + + directory = CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault, bookmarkData, 0, NULL, NULL, &isStale, NULL); + if (directory == NULL) { + goto skipURL; + } + + SCPrint(TRUE, stdout, CFSTR("ApplicationURL: %@\n"), directory); +skipURL: +#endif // !TARGET_OS_IPHONE store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL); if (store == NULL) { @@ -680,6 +1087,8 @@ done: my_CFRelease(&subtype_entity_dict); my_CFRelease(&store); my_CFRelease(&service); + my_CFRelease(&vpnprefpath); + _prefs_close(); exit(exit_code); } @@ -691,14 +1100,19 @@ nc_select(int argc, char **argv) SCNetworkSetRef current_set; int exit_code = 1; SCNetworkServiceRef service = NULL; +#if NE_HAS_ENABLE_VPN + uuid_string_t config_id_string; + uuid_t config_id; +#else // NE_HAS_ENABLE_VPN Boolean status; +#endif // NE_HAS_ENABLE_VPN do_prefs_init(); /* initialization */ do_prefs_open(0, NULL); /* open default prefs */ current_set = SCNetworkSetCopyCurrent(prefs); if (current_set == NULL) { - SCPrint(TRUE, stderr, CFSTR("No current location\n"), SCErrorString(SCError())); + SCPrint(TRUE, stderr, CFSTR("No current location\n")); goto done; } @@ -708,21 +1122,34 @@ nc_select(int argc, char **argv) goto done; } +#if NE_HAS_ENABLE_VPN + memset(config_id_string, 0, sizeof(config_id_string)); + if (_SC_cfstring_to_cstring(SCNetworkServiceGetServiceID(service), config_id_string, sizeof(config_id_string), kCFStringEncodingUTF8) != NULL && + uuid_parse(config_id_string, config_id) == 0) + { + if (!NEHelperVPNSetEnabled(config_id, true)) { + SCPrint(TRUE, stderr, CFSTR("Unable to enable service\n")); + } + } else { + SCPrint(TRUE, stderr, CFSTR("Invalid service ID: %@\n"), SCNetworkServiceGetServiceID(service)); + } +#else // NE_HAS_ENABLE_VPN #if !TARGET_OS_IPHONE status = SCNetworkServiceSetEnabled(service, TRUE); if (!status) { SCPrint(TRUE, stderr, CFSTR("Unable to enable service: %s\n"), SCErrorString(SCError())); goto done; } -#else +#else // !TARGET_OS_IPHONE status = SCNetworkSetSetSelectedVPNService(current_set, service); if (!status) { SCPrint(TRUE, stderr, CFSTR("Unable to select service: %s\n"), SCErrorString(SCError())); goto done; } -#endif +#endif // !TARGET_OS_IPHONE _prefs_save(); +#endif // NE_HAS_ENABLE_VPN exit_code = 0; done: my_CFRelease(&service); @@ -731,6 +1158,68 @@ done: exit(exit_code); } +/* ----------------------------------------------------------------------------- + ----------------------------------------------------------------------------- */ +static void +nc_help(int argc, char **argv) +{ +#pragma unused(argc) +#pragma unused(argv) + SCPrint(TRUE, stderr, CFSTR("Valid commands for scutil --nc (VPN connections)\n")); + SCPrint(TRUE, stderr, CFSTR("Usage: scutil --nc [command]\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\tlist\n")); + SCPrint(TRUE, stderr, CFSTR("\t\tList available network connection services in the current set\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\tstatus \n")); + SCPrint(TRUE, stderr, CFSTR("\t\tIndicate whether a given service is connected, as well as extended status information for the service\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\tshow \n")); + SCPrint(TRUE, stderr, CFSTR("\t\tDisplay configuration information for a given service\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\tstatistics \n")); + SCPrint(TRUE, stderr, CFSTR("\t\tProvide statistics on bytes, packets, and errors for a given service\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\tselect \n")); + SCPrint(TRUE, stderr, CFSTR("\t\tMake the given service active in the current set. This allows it to be started\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\tstart [--user user] [--password password] [--secret secret]\n")); + SCPrint(TRUE, stderr, CFSTR("\t\tStart a given service. Can take optional arguments for user, password, and secret\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\tstop \n")); + SCPrint(TRUE, stderr, CFSTR("\t\tStop a given service\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\tsuspend \n")); + SCPrint(TRUE, stderr, CFSTR("\t\tSuspend a given service (PPP, Modem on Hold)\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\tresume \n")); + SCPrint(TRUE, stderr, CFSTR("\t\tResume a given service (PPP, Modem on Hold)\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\tondemand [-W] [hostname]\n")); + SCPrint(TRUE, stderr, CFSTR("\tondemand -- --refresh\n")); + SCPrint(TRUE, stderr, CFSTR("\t\tDisplay VPN on-demand information\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\ttrigger [background] [port]\n")); + SCPrint(TRUE, stderr, CFSTR("\t\tTrigger VPN on-demand with specified hostname, and optional port and background flag\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); +#if !TARGET_OS_IPHONE + SCPrint(TRUE, stderr, CFSTR("\tenablevpn [path]\n")); + 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")); + SCPrint(TRUE, stderr, CFSTR("\n")); +#else // !TARGET_OS_IPHONE + SCPrint(TRUE, stderr, CFSTR("\tenablevpn \n")); + SCPrint(TRUE, stderr, CFSTR("\t\tEnables the given VPN application type. Takes either a service or VPN type\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); +#endif // !TARGET_OS_IPHONE + SCPrint(TRUE, stderr, CFSTR("\tdisablevpn \n")); + SCPrint(TRUE, stderr, CFSTR("\t\tDisables the given VPN application type. Takes either a service or VPN type\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR("\thelp\n")); + SCPrint(TRUE, stderr, CFSTR("\t\tDisplay available commands for --nc\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + exit(0); +} + /* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ typedef void (*nc_func) (int argc, char **argv); @@ -739,6 +1228,8 @@ static const struct { char *cmd; nc_func func; } nc_cmds[] = { + { "enablevpn", nc_enablevpn }, + { "help", nc_help }, { "list", nc_list }, { "ondemand", nc_ondemand }, { "resume", nc_resume }, @@ -749,6 +1240,7 @@ static const struct { { "status", nc_status }, { "stop", nc_stop }, { "suspend", nc_suspend }, + { "trigger", nc_trigger }, }; #define N_NC_CMNDS (sizeof(nc_cmds) / sizeof(nc_cmds[0])) @@ -782,8 +1274,12 @@ do_nc_cmd(char *cmd, int argc, char **argv, Boolean watch) nc_func func; func = nc_cmds[i].func; - if (watch && (func == nc_status)) { - func = nc_watch; + if (watch) { + if (func == nc_status) { + func = nc_watch; + } else if (func == nc_ondemand) { + ondemandwatch = TRUE; + } } (*func)(argc, argv); }