/* * Copyright (c) 2004-2011, 2013-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, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * 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@ */ /* * Modification History * * August 5, 2004 Allan Nathanson * - initial revision */ #include #include "scutil.h" #include "net.h" #include "prefs.h" #if TARGET_OS_IPHONE #define INLINE_PASSWORDS_USE_CFSTRING #endif // TARGET_OS_IPHONE #pragma mark - #pragma mark Interface management static CFArrayRef _copy_interfaces() { CFMutableArrayRef interfaces; CFArrayRef real_interfaces; real_interfaces = _SCNetworkInterfaceCopyAllWithPreferences(prefs); if (real_interfaces == NULL) { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); return NULL; } interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); // include real interfaces CFArrayAppendArray(interfaces, real_interfaces, CFRangeMake(0, CFArrayGetCount(real_interfaces))); CFRelease(real_interfaces); // include pseudo interfaces CFArrayAppendValue(interfaces, kSCNetworkInterfaceLoopback); CFArrayAppendValue(interfaces, kSCNetworkInterfaceIPv4); // include interfaces that we have created if (new_interfaces != NULL) { CFArrayAppendArray(interfaces, new_interfaces, CFRangeMake(0, CFArrayGetCount(new_interfaces))); } return (CFArrayRef)interfaces; } __private_extern__ SCNetworkInterfaceRef _find_interface(int argc, char **argv, int *nArgs) { Boolean allowIndex = TRUE; CFIndex i; CFArrayRef myInterfaces = interfaces; CFIndex n; CFStringRef select_name = NULL; SCNetworkInterfaceRef selected = NULL; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("no interface specified\n")); return NULL; } if (nArgs != NULL) *nArgs = 1; if (strcasecmp(argv[0], "$child") == 0) { if (net_interface == NULL) { SCPrint(TRUE, stdout, CFSTR("interface not selected\n")); goto done; } selected = SCNetworkInterfaceGetInterface(net_interface); if(selected == NULL) { SCPrint(TRUE, stdout, CFSTR("no child interface\n")); } goto done; } else if (strcasecmp(argv[0], "$service") == 0) { if (net_service == NULL) { SCPrint(TRUE, stdout, CFSTR("service not selected\n")); goto done; } selected = SCNetworkServiceGetInterface(net_service); if(selected == NULL) { SCPrint(TRUE, stdout, CFSTR("no interface for service\n")); } goto done; } #if !TARGET_OS_IPHONE else if (strcasecmp(argv[0], "$bond") == 0) { CFStringRef interfaceType; if (net_interface == NULL) { SCPrint(TRUE, stdout, CFSTR("interface not selected\n")); goto done; } interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface); if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) { SCPrint(TRUE, stdout, CFSTR("interface not Bond\n")); goto done; } if (argc < 2) { SCPrint(TRUE, stdout, CFSTR("no member interface specified\n")); return NULL; } argv++; argc--; if (nArgs != NULL) *nArgs += 1; myInterfaces = SCBondInterfaceGetMemberInterfaces(net_interface); if (myInterfaces == NULL) { SCPrint(TRUE, stdout, CFSTR("no member interfaces\n")); goto done; } allowIndex = FALSE; } #endif // !TARGET_OS_IPHONE else if (strcasecmp(argv[0], "$bridge") == 0) { CFStringRef interfaceType; if (net_interface == NULL) { SCPrint(TRUE, stdout, CFSTR("interface not selected\n")); goto done; } interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface); if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) { SCPrint(TRUE, stdout, CFSTR("interface not Bridge\n")); goto done; } if (argc < 2) { SCPrint(TRUE, stdout, CFSTR("no member interface specified\n")); return NULL; } argv++; argc--; if (nArgs != NULL) *nArgs += 1; myInterfaces = SCBridgeInterfaceGetMemberInterfaces(net_interface); if (myInterfaces == NULL) { SCPrint(TRUE, stdout, CFSTR("no member interfaces\n")); goto done; } allowIndex = FALSE; } else if (strcasecmp(argv[0], "$vlan") == 0) { CFStringRef interfaceType; if (net_interface == NULL) { SCPrint(TRUE, stdout, CFSTR("interface not selected\n")); goto done; } interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface); if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) { SCPrint(TRUE, stdout, CFSTR("interface not VLAN\n")); goto done; } selected = SCVLANInterfaceGetPhysicalInterface(net_interface); if(selected == NULL) { SCPrint(TRUE, stdout, CFSTR("no physical interface\n")); } goto done; } if ((myInterfaces == NULL) && (interfaces == NULL)) { interfaces = _copy_interfaces(); if (interfaces == NULL) { return NULL; } myInterfaces = interfaces; allowIndex = FALSE; } // try to select the interface by its display name select_name = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); n = (myInterfaces != NULL) ? CFArrayGetCount(myInterfaces) : 0; for (i = 0; i < n; i++) { SCNetworkInterfaceRef interface; CFStringRef interfaceName; interface = CFArrayGetValueAtIndex(myInterfaces, i); interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface); if ((interfaceName != NULL) && CFEqual(select_name, interfaceName)) { if (selected == NULL) { selected = interface; } else { // if multiple interfaces match selected = NULL; SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n")); goto done; } } } if (selected != NULL) { goto done; } // try to select the interface by its BSD name for (i = 0; i < n; i++) { SCNetworkInterfaceRef interface; CFStringRef bsd_name = NULL; interface = CFArrayGetValueAtIndex(myInterfaces, i); while ((interface != NULL) && (bsd_name == NULL)) { bsd_name = SCNetworkInterfaceGetBSDName(interface); if (bsd_name == NULL) { interface = SCNetworkInterfaceGetInterface(interface); } } if ((bsd_name != NULL) && CFEqual(select_name, bsd_name)) { if (selected == NULL) { selected = interface; } else { // if multiple interfaces match selected = NULL; SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n")); goto done; } } } if (selected != NULL) { goto done; } // try to select an [Apple] pre-configured / hidden interface by its BSD name selected = _SCNetworkInterfaceCreateWithBSDName(NULL, select_name, kIncludeNoVirtualInterfaces); if (selected != NULL) { if (_SCNetworkInterfaceGetIOPath(selected) != NULL) { // if [real] interface exists goto done; } CFRelease(selected); selected = NULL; } // try to select the interface by its interface type for (i = 0; i < n; i++) { SCNetworkInterfaceRef interface; CFStringRef interfaceType; interface = CFArrayGetValueAtIndex(myInterfaces, i); interfaceType = SCNetworkInterfaceGetInterfaceType(interface); if (CFEqual(select_name, interfaceType)) { if (selected == NULL) { selected = interface; } else { // if multiple interfaces match selected = NULL; SCPrint(TRUE, stdout, CFSTR("multiple interfaces match\n")); goto done; } } } if (selected != NULL) { goto done; } if (allowIndex) { char *end; char *str = argv[0]; long val; // try to select the interface by its index errno = 0; val = strtol(str, &end, 10); if ((*str != '\0') && ((*end == '\0') || (*end == '.')) && (errno == 0)) { if ((val > 0) && (val <= n)) { selected = CFArrayGetValueAtIndex(myInterfaces, val - 1); if (*end == '.') { str = end + 1; val = strtol(str, &end, 10); if ((*str != '\0') && (*end == '\0') && (errno == 0)) { while (val-- > 0) { selected = SCNetworkInterfaceGetInterface(selected); if (selected == NULL) { break; } } } } } } } if (selected != NULL) { goto done; } SCPrint(TRUE, stdout, CFSTR("no match\n")); done : if (select_name != NULL) CFRelease(select_name); return selected; } /* -------------------- */ __private_extern__ void create_interface(int argc, char **argv) { SCNetworkInterfaceRef interface; CFStringRef interfaceName; CFStringRef interfaceType; SCNetworkInterfaceRef new_interface; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("what interface type?\n")); return; } interfaceType = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); argv++; argc--; if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) { SCPrint(TRUE, stdout, CFSTR("bond creation not yet supported\n")); goto done; } if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) { SCPrint(TRUE, stdout, CFSTR("bridge creation not yet supported\n")); goto done; } if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) { SCPrint(TRUE, stdout, CFSTR("vlan creation not yet supported\n")); goto done; } if (argc < 1) { if (net_interface == NULL) { SCPrint(TRUE, stdout, CFSTR("no network interface selected\n")); goto done; } interface = net_interface; } else { interface = _find_interface(argc, argv, NULL); } if (interface == NULL) { goto done; } new_interface = SCNetworkInterfaceCreateWithInterface(interface, interfaceType); if (new_interface == NULL) { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); goto done; } if (new_interfaces == NULL) { new_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } CFArrayAppendValue(new_interfaces, new_interface); if (net_interface != NULL) CFRelease(net_interface); net_interface = new_interface; interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(net_interface); if (interfaceName == NULL) { interfaceName = SCNetworkInterfaceGetBSDName(net_interface); } if (interfaceName == NULL) { interfaceName = SCNetworkInterfaceGetInterfaceType(net_interface); } SCPrint(TRUE, stdout, CFSTR("interface \"%@\" created and selected\n"), interfaceName); done : CFRelease(interfaceType); return; } /* -------------------- */ __private_extern__ void select_interface(int argc, char **argv) { SCNetworkInterfaceRef interface; interface = _find_interface(argc, argv, NULL); if (interface != NULL) { CFStringRef interfaceName; if (net_interface != NULL) CFRelease(net_interface); net_interface = CFRetain(interface); interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface); if (interfaceName == NULL) { interfaceName = SCNetworkInterfaceGetBSDName(interface); } if (interfaceName == NULL) { interfaceName = SCNetworkInterfaceGetInterfaceType(interface); } SCPrint(TRUE, stdout, CFSTR("interface \"%@\" selected\n"), interfaceName); } return; } /* -------------------- */ __private_extern__ void _show_interface(SCNetworkInterfaceRef interface, CFStringRef prefix, Boolean showChild) { CFDictionaryRef configuration; CFStringRef if_bsd_name; CFStringRef if_localized_name; CFStringRef if_mac_address; CFStringRef if_type; Boolean isPhysicalEthernet; CFArrayRef supported; if_localized_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); if (if_localized_name != NULL) { SCPrint(TRUE, stdout, CFSTR("%@ name = %@\n"), prefix, if_localized_name); } if_bsd_name = SCNetworkInterfaceGetBSDName(interface); if (if_bsd_name != NULL) { SCPrint(TRUE, stdout, CFSTR("%@ interface name = %@\n"), prefix, if_bsd_name); } if_type = SCNetworkInterfaceGetInterfaceType(interface); SCPrint(TRUE, stdout, CFSTR("%@ type = %@\n"), prefix, if_type); if_mac_address = SCNetworkInterfaceGetHardwareAddressString(interface); if (if_mac_address != NULL) { SCPrint(TRUE, stdout, CFSTR("%@ address = %@\n"), prefix, if_mac_address); } configuration = SCNetworkInterfaceGetConfiguration(interface); if ((configuration != NULL) && CFDictionaryContainsKey(configuration, kSCResvInactive)) { configuration = NULL; } if (if_bsd_name != NULL) { CFArrayRef available; CFDictionaryRef active; CFDictionaryRef cap_current; int mtu_cur; int mtu_min; int mtu_max; CFDictionaryRef qosPolicy; cap_current = SCNetworkInterfaceCopyCapability(interface, NULL); if (cap_current != NULL) { CFIndex i; CFArrayRef cap_names; CFMutableArrayRef cap_sorted; const void **keys; CFIndex n; n = CFDictionaryGetCount(cap_current); keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0); CFDictionaryGetKeysAndValues(cap_current, keys, NULL); cap_names = CFArrayCreate(NULL, keys, n, &kCFTypeArrayCallBacks); CFAllocatorDeallocate(NULL, keys); cap_sorted = CFArrayCreateMutableCopy(NULL, 0, cap_names); CFRelease(cap_names); CFArraySortValues(cap_sorted, CFRangeMake(0, n), (CFComparatorFunction)CFStringCompare, NULL); SCPrint(TRUE, stdout, CFSTR("%@ capabilities = "), prefix); for (i = 0; i < n; i++) { CFStringRef cap_name; int cap_val; CFNumberRef val = NULL; cap_name = CFArrayGetValueAtIndex(cap_sorted, i); if (configuration != NULL) { val = CFDictionaryGetValue(configuration, cap_name); } if (!isA_CFNumber(val)) { val = CFDictionaryGetValue(cap_current, cap_name); } SCPrint(TRUE, stdout, CFSTR("%s%@%c"), (i == 0) ? "" : ",", cap_name, (CFNumberGetValue(val, kCFNumberIntType, &cap_val) && (cap_val != 0)) ? '+' : '-'); } SCPrint(TRUE, stdout, CFSTR("\n")); CFRelease(cap_sorted); CFRelease(cap_current); } if (SCNetworkInterfaceCopyMTU(interface, &mtu_cur, &mtu_min, &mtu_max)) { char isCurrent = '*'; if (configuration != NULL) { int mtu_req; CFNumberRef num; num = CFDictionaryGetValue(configuration, kSCPropNetEthernetMTU); if (isA_CFNumber(num) && CFNumberGetValue(num, kCFNumberIntType, &mtu_req)) { if (mtu_cur != mtu_req) { mtu_cur = mtu_req; isCurrent = ' '; } } } SCPrint(TRUE, stdout, CFSTR("%@ mtu %c = %d (%d < n < %d)\n"), prefix, isCurrent, mtu_cur, mtu_min, mtu_max); } if (SCNetworkInterfaceCopyMediaOptions(interface, NULL, &active, &available, TRUE)) { char isCurrent = ' '; CFArrayRef options = NULL; CFArrayRef options_req = NULL; CFStringRef subtype = NULL; CFStringRef subtype_req = NULL; if (configuration != NULL) { subtype_req = CFDictionaryGetValue(configuration, kSCPropNetEthernetMediaSubType); options_req = CFDictionaryGetValue(configuration, kSCPropNetEthernetMediaOptions); } if (subtype_req == NULL) { subtype_req = CFSTR("autoselect"); } if (active != NULL) { subtype = CFDictionaryGetValue(active, kSCPropNetEthernetMediaSubType); options = CFDictionaryGetValue(active, kSCPropNetEthernetMediaOptions); } if (subtype != NULL) { if (((subtype_req != NULL) && CFEqual(subtype, subtype_req)) && ((options == options_req) || ((options != NULL) && (options_req != NULL) && CFEqual(options, options_req))) ) { isCurrent = '*'; } else if ((subtype_req == NULL) || ((subtype_req != NULL) && CFEqual(subtype_req, CFSTR("autoselect")))) { // if requested subtype not specified or "autoselect" isCurrent = '*'; } } if (subtype_req != NULL) { SCPrint(TRUE, stdout, CFSTR("%@ media %c = %@"), prefix, isCurrent, subtype_req); if ((options_req != NULL) && (CFArrayGetCount(options_req) > 0)) { CFStringRef options_str; options_str = CFStringCreateByCombiningStrings(NULL, options_req, CFSTR(",")); SCPrint(TRUE, stdout, CFSTR(" <%@>"), options_str); CFRelease(options_str); } SCPrint(TRUE, stdout, CFSTR("\n")); } SCPrint(TRUE, stdout, CFSTR("\n")); if (available != NULL) { CFIndex i; CFIndex n_subtypes; CFArrayRef subtypes; subtypes = SCNetworkInterfaceCopyMediaSubTypes(available); n_subtypes = (subtypes != NULL) ? CFArrayGetCount(subtypes) : 0; for (i = 0; i < n_subtypes; i++) { CFIndex j; CFIndex n_subtype_options; CFStringRef subtype; CFArrayRef subtype_options; subtype = CFArrayGetValueAtIndex(subtypes, i); subtype_options = SCNetworkInterfaceCopyMediaSubTypeOptions(available, subtype); n_subtype_options = (subtype_options != NULL) ? CFArrayGetCount(subtype_options) : 0; for (j = 0; j < n_subtype_options; j++) { char isCurrent = ' '; CFArrayRef options; options = CFArrayGetValueAtIndex(subtype_options, j); if (((subtype_req != NULL) && CFEqual(subtype, subtype_req)) && ((options == options_req) || ((options != NULL) && (options_req != NULL) && CFEqual(options, options_req))) ) { isCurrent = '*'; } SCPrint(TRUE, stdout, CFSTR("%@ %s %c = %@"), prefix, ((i == 0) && (j == 0)) ? "supported media" : " ", isCurrent, subtype); if ((options != NULL) && (CFArrayGetCount(options) > 0)) { CFStringRef options_str; options_str = CFStringCreateByCombiningStrings(NULL, options, CFSTR(",")); SCPrint(TRUE, stdout, CFSTR(" <%@>"), options_str); CFRelease(options_str); } SCPrint(TRUE, stdout, CFSTR("\n")); } if (subtype_options != NULL) CFRelease(subtype_options); } if (subtypes != NULL) CFRelease(subtypes); } } else { SCPrint(TRUE, stdout, CFSTR("\n")); } qosPolicy = SCNetworkInterfaceGetQoSMarkingPolicy(interface); if (qosPolicy != NULL) { CFBooleanRef bVal; CFArrayRef bundleIDs; Boolean needComma = FALSE; SCPrint(TRUE, stdout, CFSTR("%@ qos marking ="), prefix); bVal = CFDictionaryGetValue(qosPolicy, kSCPropNetQoSMarkingEnabled); if ((bVal != NULL) && isA_CFBoolean(bVal)) { SCPrint(TRUE, stdout, CFSTR(" %senabled"), CFBooleanGetValue(bVal) ? "" : "!"); needComma = TRUE; } bVal = CFDictionaryGetValue(qosPolicy, kSCPropNetQoSMarkingAppleAudioVideoCalls); if ((bVal != NULL) && isA_CFBoolean(bVal)) { SCPrint(TRUE, stdout, CFSTR("%s %sapple-av"), needComma ? "," : "", CFBooleanGetValue(bVal) ? "" : "!"); needComma = TRUE; } bundleIDs = CFDictionaryGetValue(qosPolicy, kSCPropNetQoSMarkingWhitelistedAppIdentifiers); if ((bundleIDs != NULL) && CFArrayGetCount(bundleIDs)) { CFIndex n = CFArrayGetCount(bundleIDs); SCPrint(TRUE, stdout, CFSTR("%s applications = ("), needComma ? "," : ""); for (CFIndex i = 0; i < n; i++) { CFStringRef bundleID; bundleID = CFArrayGetValueAtIndex(bundleIDs, i); if (!isA_CFString(bundleID)) { bundleID = CFSTR("--invalid-bundle-id--"); } SCPrint(TRUE, stdout, CFSTR("%s%@"), (i > 0) ? ", " : "", bundleID); } SCPrint(TRUE, stdout, CFSTR(")")); } SCPrint(TRUE, stdout, CFSTR("\n")); } } supported = SCNetworkInterfaceGetSupportedInterfaceTypes(interface); SCPrint(TRUE, stdout, CFSTR("%@ supported interfaces = "), prefix); if (supported != NULL) { CFIndex i; CFIndex n = CFArrayGetCount(supported); for (i = 0; i < n; i++) { SCPrint(TRUE, stdout, CFSTR("%s%@"), (i == 0) ? "" : ", ", CFArrayGetValueAtIndex(supported, i)); } } SCPrint(TRUE, stdout, CFSTR("\n")); supported = SCNetworkInterfaceGetSupportedProtocolTypes(interface); SCPrint(TRUE, stdout, CFSTR("%@ supported protocols = "), prefix); if (supported != NULL) { CFIndex i; CFIndex n = CFArrayGetCount(supported); for (i = 0; i < n; i++) { SCPrint(TRUE, stdout, CFSTR("%s%@"), (i == 0) ? "" : ", ", CFArrayGetValueAtIndex(supported, i)); } } SCPrint(TRUE, stdout, CFSTR("\n")); isPhysicalEthernet = _SCNetworkInterfaceIsPhysicalEthernet(interface); SCPrint(TRUE, stdout, CFSTR("%@ is%s physical ethernet\n"), prefix, isPhysicalEthernet ? "" : " not"); if (_SCNetworkInterfaceIsApplePreconfigured(interface)) { SCPrint(TRUE, stdout, CFSTR("%@ is pre-configured\n"), prefix); } if (configuration != NULL) { CFMutableDictionaryRef effective; effective = CFDictionaryCreateMutableCopy(NULL, 0, configuration); // remove known (and already reported) interface configuration keys if (CFDictionaryContainsKey(effective, kSCResvInactive)) { CFDictionaryRemoveAllValues(effective); } CFDictionaryRemoveValue(effective, kSCPropNetEthernetMTU); CFDictionaryRemoveValue(effective, kSCPropNetEthernetMediaSubType); CFDictionaryRemoveValue(effective, kSCPropNetEthernetMediaOptions); if (CFDictionaryGetCount(effective) > 0) { SCPrint(TRUE, stdout, CFSTR("\n%@ per-interface configuration\n"), prefix); _show_entity(effective, prefix); } CFRelease(effective); } if (CFEqual(if_type, kSCNetworkInterfaceTypePPP)) { SCNetworkInterfaceRef childInterface; childInterface = SCNetworkInterfaceGetInterface(interface); if (childInterface != NULL) { CFStringRef childInterfaceType; childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface); if (CFEqual(childInterfaceType, kSCNetworkInterfaceTypeL2TP)) { CFDictionaryRef ipsec_configuration; ipsec_configuration = SCNetworkInterfaceGetExtendedConfiguration(interface, kSCEntNetIPSec); if (isA_CFDictionary(ipsec_configuration) && (CFDictionaryGetCount(ipsec_configuration) > 0)) { SCPrint(TRUE, stdout, CFSTR("\n%@ per-interface IPSec configuration\n"), prefix); _show_entity(ipsec_configuration, prefix); } } } } if (_sc_debug) { SCPrint(TRUE, stdout, CFSTR("\n%@\n"), interface); } interface = SCNetworkInterfaceGetInterface(interface); if (interface != NULL) { CFStringRef newPrefix; newPrefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ "), prefix); SCPrint(TRUE, stdout, CFSTR("\n%@child interface\n"), newPrefix); _show_interface(interface, newPrefix, showChild); CFRelease(newPrefix); } return; } /* -------------------- */ static Boolean validateMediaOptions(SCNetworkInterfaceRef interface, CFMutableDictionaryRef newConfiguration) { Boolean ok = TRUE; CFNumberRef mtu; CFArrayRef options; CFStringRef subtype; mtu = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMTU); if (isA_CFNumber(mtu)) { int mtu_max; int mtu_min; int mtu_val; if (!SCNetworkInterfaceCopyMTU(interface, NULL, &mtu_min, &mtu_max)) { SCPrint(TRUE, stdout, CFSTR("cannot set MTU\n")); return FALSE; } if (!CFNumberGetValue(mtu, kCFNumberIntType, &mtu_val) || (mtu_val < mtu_min) || (mtu_val > mtu_max)) { SCPrint(TRUE, stdout, CFSTR("mtu out of range\n")); return FALSE; } } subtype = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMediaSubType); options = CFDictionaryGetValue(newConfiguration, kSCPropNetEthernetMediaOptions); if (subtype != NULL) { CFArrayRef available = NULL; CFArrayRef config_options = options; CFArrayRef subtypes = NULL; CFArrayRef subtype_options = NULL; ok = FALSE; if (options == NULL) { config_options = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); } if (!SCNetworkInterfaceCopyMediaOptions(interface, NULL, NULL, &available, FALSE)) { SCPrint(TRUE, stdout, CFSTR("media type / options not available\n")); goto checked; } if (available == NULL) { goto checked; } subtypes = SCNetworkInterfaceCopyMediaSubTypes(available); if ((subtypes == NULL) || !CFArrayContainsValue(subtypes, CFRangeMake(0, CFArrayGetCount(subtypes)), subtype)) { SCPrint(TRUE, stdout, CFSTR("media type not valid\n")); goto checked; } subtype_options = SCNetworkInterfaceCopyMediaSubTypeOptions(available, subtype); if ((subtype_options == NULL) || !CFArrayContainsValue(subtype_options, CFRangeMake(0, CFArrayGetCount(subtype_options)), config_options)) { SCPrint(TRUE, stdout, CFSTR("media options not valid for \"%@\"\n"), subtype); goto checked; } if (options == NULL) { CFDictionarySetValue(newConfiguration, kSCPropNetEthernetMediaOptions, config_options); } ok = TRUE; checked : if (available != NULL) CFRelease(available); if (subtypes != NULL) CFRelease(subtypes); if (subtype_options != NULL) CFRelease(subtype_options); if (options == NULL) CFRelease(config_options); } else { if (options != NULL) { SCPrint(TRUE, stdout, CFSTR("media type and options must both be specified\n")); return FALSE; } } return ok; } /* -------------------- */ __private_extern__ void show_interfaces(int argc, char **argv) { #pragma unused(argc) #pragma unused(argv) CFIndex i; CFIndex n; if (interfaces != NULL) CFRelease(interfaces); interfaces = _copy_interfaces(); if (interfaces == NULL) { return; } n = CFArrayGetCount(interfaces); for (i = 0; i < n; i++) { CFIndex childIndex = 0; SCNetworkInterfaceRef interface; interface = CFArrayGetValueAtIndex(interfaces, i); do { CFStringRef interfaceName; char isSelected; interfaceName = SCNetworkInterfaceGetLocalizedDisplayName(interface); if (interfaceName == NULL) { interfaceName = SCNetworkInterfaceGetBSDName(interface); } if (interfaceName == NULL) { interfaceName = SCNetworkInterfaceGetInterfaceType(interface); } isSelected = ' '; if ((net_interface != NULL) && CFEqual(interface, net_interface)) { isSelected = '>'; } if (childIndex == 0) { SCPrint(TRUE, stdout, CFSTR("%c%2ld: %@\n"), isSelected, i + 1, interfaceName); } else { SCPrint(TRUE, stdout, CFSTR("%c%2ld.%ld: %@\n"), isSelected, i + 1, childIndex, interfaceName); } if (_sc_debug) { CFMutableStringRef desc; CFMutableDictionaryRef formatOptions; desc = CFStringCreateMutable(NULL, 0); formatOptions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(formatOptions, CFSTR("PREFIX1"), CFSTR("")); CFDictionarySetValue(formatOptions, CFSTR("PREFIX2"), CFSTR("$$")); CFStringAppendFormat(desc, formatOptions, CFSTR("%@"), interface); CFRelease(formatOptions); // cleanup SCNetworkInterface details CFStringFindAndReplace(desc, CFSTR("]> {"), CFSTR("]>\n {\n "), CFRangeMake(0, CFStringGetLength(desc)), 0); CFStringFindAndReplace(desc, CFSTR(", "), CFSTR("\n "), CFRangeMake(0, CFStringGetLength(desc)), 0); CFStringFindAndReplace(desc, CFSTR("}"), CFSTR("\n }"), CFRangeMake(CFStringGetLength(desc) - 1, 1), kCFCompareBackwards|kCFCompareAnchored); // additional cleanup for Bond, Bridge, VLAN options CFStringFindAndReplace(desc, CFSTR("> {\n"), CFSTR(">\n {\n"), CFRangeMake(0, CFStringGetLength(desc)), 0); CFStringFindAndReplace(desc, CFSTR("\n$$"), CFSTR("\n "), CFRangeMake(0, CFStringGetLength(desc)), 0); CFStringFindAndReplace(desc, CFSTR("$$"), CFSTR(""), CFRangeMake(0, CFStringGetLength(desc)), 0); SCPrint(TRUE, stdout, CFSTR("\n %@\n\n"), desc); CFRelease(desc); } interface = SCNetworkInterfaceGetInterface(interface); childIndex++; } while (interface != NULL); } return; } /* -------------------- */ static int __doRank(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(key) #pragma unused(info) #pragma unused(newConfiguration) SCNetworkInterfaceRef interface; CFStringRef interfaceName; Boolean ok = FALSE; SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault; SCDynamicStoreRef store; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("%s not specified\n"), description != NULL ? description : "rank"); return -1; } if (strlen(argv[0]) == 0) { rank = kSCNetworkServicePrimaryRankDefault; } else if ((strcasecmp(argv[0], "First") == 0)) { rank = kSCNetworkServicePrimaryRankFirst; } else if ((strcasecmp(argv[0], "Last") == 0)) { rank = kSCNetworkServicePrimaryRankLast; } else if ((strcasecmp(argv[0], "Never") == 0)) { rank = kSCNetworkServicePrimaryRankNever; } else if ((strcasecmp(argv[0], "Scoped") == 0)) { rank = kSCNetworkServicePrimaryRankScoped; } else { SCPrint(TRUE, stdout, CFSTR("invalid rank\n")); return -1; } interfaceName = SCNetworkInterfaceGetBSDName(net_interface); if (interfaceName == NULL) { SCPrint(TRUE, stdout, CFSTR("no BSD interface\n")); return FALSE; } store = SCDynamicStoreCreate(NULL, CFSTR("scutil --net"), NULL, NULL); interface = _SCNetworkInterfaceCopyActive(store, interfaceName); CFRelease(store); if (interface == NULL) { SCPrint(TRUE, stdout, CFSTR("No active interface\n")); return -1; } ok = SCNetworkInterfaceSetPrimaryRank(interface, rank); CFRelease(interface); if (!ok) { SCPrint(TRUE, stdout, CFSTR("could not update per-interface rank\n")); return -1; } return 1; } /* -------------------- */ static void _replaceOne(const void *key, const void *value, void *context) { CFMutableDictionaryRef newConfiguration = (CFMutableDictionaryRef)context; CFDictionarySetValue(newConfiguration, key, value); return; } static void updateInterfaceConfiguration(CFMutableDictionaryRef newConfiguration) { CFDictionaryRef configuration; CFDictionaryRemoveAllValues(newConfiguration); configuration = SCNetworkInterfaceGetConfiguration(net_interface); if (configuration != NULL) { CFDictionaryApplyFunction(configuration, _replaceOne, (void *)newConfiguration); } return; } #pragma mark - #pragma mark QoS Marking Policy options static options qosOptions[] = { { "enabled" , NULL, isBool , &kSCPropNetQoSMarkingEnabled , NULL, NULL }, { "apple-av" , NULL, isBool , &kSCPropNetQoSMarkingAppleAudioVideoCalls , NULL, NULL }, { "bundle-ids", NULL, isStringArray, &kSCPropNetQoSMarkingWhitelistedAppIdentifiers, NULL, NULL }, { "?" , NULL, isHelp , NULL , NULL, "\nQoS marking policy commands\n\n" " set interface qos [enabled {yes|no}]\n" " set interface qos [apple-av {yes|no}]\n" " set interface qos [bundle-ids bundle-id[,bundle-id]]\n" } }; #define N_QOS_OPTIONS (sizeof(qosOptions) / sizeof(qosOptions[0])) static int __doQoSMarking(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(key) #pragma unused(description) #pragma unused(info) #pragma unused(newConfiguration) CFStringRef interfaceName; CFMutableDictionaryRef newPolicy; Boolean ok; CFDictionaryRef policy; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("set what?\n")); return -1; } interfaceName = SCNetworkInterfaceGetBSDName(net_interface); if (interfaceName == NULL) { SCPrint(TRUE, stdout, CFSTR("no BSD interface\n")); return -1; } policy = SCNetworkInterfaceGetQoSMarkingPolicy(net_interface); if (policy != NULL) { newPolicy = CFDictionaryCreateMutableCopy(NULL, 0, policy); CFDictionaryRemoveValue(newPolicy, kSCResvInactive); } else { newPolicy = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } ok = _process_options(qosOptions, N_QOS_OPTIONS, argc, argv, newPolicy); if (!ok) { goto done; } if (((policy == NULL) && (CFDictionaryGetCount(newPolicy) > 0)) || ((policy != NULL) && !CFEqual(policy, newPolicy))) { if (!SCNetworkInterfaceSetQoSMarkingPolicy(net_interface, newPolicy)) { if (SCError() == kSCStatusNoKey) { SCPrint(TRUE, stdout, CFSTR("could not update per-interface QoS marking policy\n")); } else { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); } goto done; } _prefs_changed = TRUE; } done : if (newPolicy != NULL) CFRelease(newPolicy); return argc; } #pragma mark - #pragma mark Bond options static options bondOptions[] = { { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL }, // xxx { "+device" , ... }, // xxx { "-device" , ... }, { "?" , NULL , isHelp , NULL , NULL, "\nBond configuration commands\n\n" " set interface [mtu n] [media type] [mediaopts opts]\n" } }; #define N_BOND_OPTIONS (sizeof(bondOptions) / sizeof(bondOptions[0])) static Boolean set_interface_bond(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { CFStringRef interfaceName; Boolean ok; interfaceName = SCNetworkInterfaceGetBSDName(net_interface); if (interfaceName == NULL) { SCPrint(TRUE, stdout, CFSTR("no BSD interface\n")); return FALSE; } ok = _process_options(bondOptions, N_BOND_OPTIONS, argc, argv, newConfiguration); if (ok) { // validate configuration if (!validateMediaOptions(net_interface, newConfiguration)) { return FALSE; } } return ok; } #pragma mark - #pragma mark Bridge options static options bridgeOptions[] = { { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL }, // xxx { "+device" , ... }, // xxx { "-device" , ... }, { "?" , NULL , isHelp , NULL , NULL, "\nBridge configuration commands\n\n" " set interface [mtu n] [media type] [mediaopts opts]\n" } }; #define N_BRIDGE_OPTIONS (sizeof(bridgeOptions) / sizeof(bridgeOptions[0])) static Boolean set_interface_bridge(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { CFStringRef interfaceName; Boolean ok; interfaceName = SCNetworkInterfaceGetBSDName(net_interface); if (interfaceName == NULL) { SCPrint(TRUE, stdout, CFSTR("no BSD interface\n")); return FALSE; } ok = _process_options(bridgeOptions, N_BRIDGE_OPTIONS, argc, argv, newConfiguration); if (ok) { // validate configuration if (!validateMediaOptions(net_interface, newConfiguration)) { return FALSE; } } return ok; } #pragma mark - #pragma mark AirPort options static options airportOptions[] = { { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL }, { "media" , NULL, isString , &kSCPropNetEthernetMediaSubType, NULL, NULL }, { "mediaopt" , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL }, { "rank" , NULL, isOther , NULL , __doRank, NULL }, { "qos" , NULL, isOther , NULL , __doQoSMarking, NULL }, { "?" , NULL, isHelp , NULL , NULL, "\nAirPort configuration commands\n\n" " set interface [mtu n] [media type] [mediaopts opts]\n" " set interface [rank [{First|Last|Never|Scoped}]]\n" " set interface [qos ]]\n" } }; #define N_AIRPORT_OPTIONS (sizeof(airportOptions) / sizeof(airportOptions[0])) static Boolean set_interface_airport(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { CFStringRef interfaceName; Boolean ok; interfaceName = SCNetworkInterfaceGetBSDName(net_interface); if (interfaceName == NULL) { SCPrint(TRUE, stdout, CFSTR("no BSD interface\n")); return FALSE; } ok = _process_options(airportOptions, N_AIRPORT_OPTIONS, argc, argv, newConfiguration); if (ok) { // validate configuration if (!validateMediaOptions(net_interface, newConfiguration)) { return FALSE; } } return ok; } #pragma mark - #pragma mark Ethernet options static int __doCapability(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(info) Boolean ok = FALSE; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("%s not specified\n"), description != NULL ? description : "enable/disable"); return -1; } if (strlen(argv[0]) == 0) { ok = SCNetworkInterfaceSetCapability(net_interface, key, NULL); } else if ((strcasecmp(argv[0], "disable") == 0) || (strcasecmp(argv[0], "no" ) == 0) || (strcasecmp(argv[0], "off" ) == 0) || (strcasecmp(argv[0], "0" ) == 0)) { ok = SCNetworkInterfaceSetCapability(net_interface, key, CFNumberRef_0); } else if ((strcasecmp(argv[0], "enable") == 0) || (strcasecmp(argv[0], "yes" ) == 0) || (strcasecmp(argv[0], "on" ) == 0) || (strcasecmp(argv[0], "1" ) == 0)) { ok = SCNetworkInterfaceSetCapability(net_interface, key, CFNumberRef_1); } else { SCPrint(TRUE, stdout, CFSTR("invalid value\n")); return -1; } if (ok) { updateInterfaceConfiguration(newConfiguration); } else { SCPrint(TRUE, stdout, CFSTR("%@ not updated: %s\n"), key, SCErrorString(SCError())); return -1; } return 1; } static options ethernetOptions[] = { { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL }, { "media" , NULL, isString , &kSCPropNetEthernetMediaSubType , NULL, NULL }, { "mediaopt" , NULL, isStringArray, &kSCPropNetEthernetMediaOptions , NULL, NULL }, { "av" , NULL, isOther , &kSCPropNetEthernetCapabilityAV , __doCapability, NULL }, { "lro" , NULL, isOther , &kSCPropNetEthernetCapabilityLRO , __doCapability, NULL }, { "rxcsum" , NULL, isOther , &kSCPropNetEthernetCapabilityRXCSUM, __doCapability, NULL }, { "tso" , NULL, isOther , &kSCPropNetEthernetCapabilityTSO , __doCapability, NULL }, { "txcsum" , NULL, isOther , &kSCPropNetEthernetCapabilityTXCSUM, __doCapability, NULL }, { "rank" , NULL, isOther , NULL , __doRank, NULL }, { "qos" , NULL, isOther , NULL , __doQoSMarking, NULL }, { "?" , NULL, isHelp , NULL , NULL, "\nEthernet configuration commands\n\n" " set interface [mtu n] [media type] [mediaopts opts]\n" " set interface [rank [{First|Last|Never|Scoped}]]\n" " set interface [qos []]\n" } }; #define N_ETHERNET_OPTIONS (sizeof(ethernetOptions) / sizeof(ethernetOptions[0])) static Boolean set_interface_ethernet(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { CFStringRef interfaceName; Boolean ok; interfaceName = SCNetworkInterfaceGetBSDName(net_interface); if (interfaceName == NULL) { SCPrint(TRUE, stdout, CFSTR("no BSD interface\n")); return FALSE; } ok = _process_options(ethernetOptions, N_ETHERNET_OPTIONS, argc, argv, newConfiguration); if (ok) { // validate configuration if (!validateMediaOptions(net_interface, newConfiguration)) { return FALSE; } } return ok; } #pragma mark - #pragma mark IPSec options static int __doIPSecSharedSecret(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) CFStringRef encryptionType; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("IPSec shared secret not specified\n")); return -1; } encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecSharedSecretEncryption); if (strlen(argv[0]) > 0) { if (encryptionType == NULL) { #ifdef INLINE_PASSWORDS_USE_CFSTRING CFStringRef pw; pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); #else // INLINE_PASSWORDS_USE_CFSTRING CFIndex n; CFMutableDataRef pw; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); n = CFStringGetLength(str); pw = CFDataCreateMutable(NULL, n * sizeof(UniChar)); CFDataSetLength(pw, n * sizeof(UniChar)); /* ALIGN: CF aligns to at least >8 bytes */ CFStringGetCharacters(str, CFRangeMake(0, n), (UniChar *)(void *)CFDataGetMutableBytePtr(pw)); CFRelease(str); #endif // INLINE_PASSWORDS_USE_CFSTRING CFDictionarySetValue(newConfiguration, key, pw); CFRelease(pw); } else if (CFEqual(encryptionType, kSCValNetIPSecSharedSecretEncryptionKeychain)) { Boolean ok; CFDataRef pw; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0); ok = SCNetworkInterfaceSetPassword(net_interface, kSCNetworkInterfacePasswordTypeIPSecSharedSecret, pw, NULL); CFRelease(pw); CFRelease(str); if (ok) { updateInterfaceConfiguration(newConfiguration); } else { return -1; } } else { SCPrint(TRUE, stdout, CFSTR("IPSec shared secret type \"%@\" not supported\n"), encryptionType); return -1; } } else { if (encryptionType == NULL) { CFDictionaryRemoveValue(newConfiguration, key); } else if (CFEqual(encryptionType, kSCValNetIPSecSharedSecretEncryptionKeychain)) { Boolean ok; ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeIPSecSharedSecret); if (ok) { updateInterfaceConfiguration(newConfiguration); } else { return -1; } } else { SCPrint(TRUE, stdout, CFSTR("IPSec shared secret type \"%@\" not supported\n"), encryptionType); return -1; } } return 1; } static int __doIPSecSharedSecretType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("IPSec shared secret type mode not specified\n")); return -1; } if (strlen(argv[0]) > 0) { if (strcasecmp(argv[0], "keychain") == 0) { CFDictionarySetValue(newConfiguration, key, kSCValNetIPSecSharedSecretEncryptionKeychain); } else { SCPrint(TRUE, stdout, CFSTR("invalid shared secret type\n")); return -1; } } else { CFDictionaryRemoveValue(newConfiguration, key); } // encryption type changed, reset shared secret CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPSecSharedSecret); return 1; } static int __doIPSecXAuthPassword(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) CFStringRef encryptionType; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("IPSec XAuth password not specified\n")); return -1; } encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecXAuthPasswordEncryption); if (strlen(argv[0]) > 0) { if (encryptionType == NULL) { #ifdef INLINE_PASSWORDS_USE_CFSTRING CFStringRef pw; pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); #else // INLINE_PASSWORDS_USE_CFSTRING CFIndex n; CFMutableDataRef pw; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); n = CFStringGetLength(str); pw = CFDataCreateMutable(NULL, n * sizeof(UniChar)); CFDataSetLength(pw, n * sizeof(UniChar)); /* ALIGN: CF aligns to at least >8 byte boundries */ CFStringGetCharacters(str, CFRangeMake(0, n), (UniChar *)(void *)CFDataGetMutableBytePtr(pw)); CFRelease(str); #endif // INLINE_PASSWORDS_USE_CFSTRING CFDictionarySetValue(newConfiguration, key, pw); CFRelease(pw); } else if (CFEqual(encryptionType, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) { Boolean ok; CFDataRef pw; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0); ok = SCNetworkInterfaceSetPassword(net_interface, kSCNetworkInterfacePasswordTypeIPSecXAuth, pw, NULL); CFRelease(pw); CFRelease(str); if (ok) { updateInterfaceConfiguration(newConfiguration); } else { return -1; } } else { SCPrint(TRUE, stdout, CFSTR("IPSec XAuthPassword type \"%@\" not supported\n"), encryptionType); return -1; } } else { if (encryptionType == NULL) { CFDictionaryRemoveValue(newConfiguration, key); } else if (CFEqual(encryptionType, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) { Boolean ok; ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeIPSecXAuth); if (ok) { updateInterfaceConfiguration(newConfiguration); } else { return -1; } } else { SCPrint(TRUE, stdout, CFSTR("IPSec XAuthPassword type \"%@\" not supported\n"), encryptionType); return -1; } } return 1; } static int __doIPSecXAuthPasswordType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("IPSec XAuth password type mode not specified\n")); return -1; } if (strlen(argv[0]) > 0) { if (strcasecmp(argv[0], "keychain") == 0) { CFDictionarySetValue(newConfiguration, key, kSCValNetIPSecXAuthPasswordEncryptionKeychain); } else { SCPrint(TRUE, stdout, CFSTR("invalid XAuth password type\n")); return -1; } } else { CFDictionaryRemoveValue(newConfiguration, key); } // encryption type changed, reset XAuthPassword CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPSecXAuthPassword); return 1; } static CF_RETURNS_RETAINED CFStringRef __cleanupDomainName(CFStringRef domain) { CFMutableStringRef newDomain; newDomain = CFStringCreateMutableCopy(NULL, 0, domain); CFStringTrimWhitespace(newDomain); CFStringTrim(newDomain, CFSTR(".")); if (CFStringGetLength(newDomain) == 0) { CFRelease(newDomain); newDomain = NULL; } return newDomain; } static int __doOnDemandDomains(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) CFMutableArrayRef domains; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("OnDemand domain name(s) not specified\n")); return -1; } domains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (strlen(argv[0]) > 0) { CFArrayRef array; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(",")); CFRelease(str); if (array != NULL) { CFIndex i; CFIndex n = CFArrayGetCount(array); for (i = 0; i < n; i++) { CFStringRef domain; domain = __cleanupDomainName(CFArrayGetValueAtIndex(array, i)); if (domain != NULL) { CFArrayAppendValue(domains, domain); CFRelease(domain); } else { CFRelease(array); CFRelease(domains); SCPrint(TRUE, stdout, CFSTR("invalid OnDemand domain name\n")); return -1; } } CFRelease(array); } } if (CFArrayGetCount(domains) > 0) { CFDictionarySetValue(newConfiguration, key, domains); } else { CFDictionaryRemoveValue(newConfiguration, key); } CFRelease(domains); return 1; } static options ipsecOnDemandOptions[] = { { "OnDemandMatchDomainsAlways" , "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL }, { "always" , "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL }, { "OnDemandMatchDomainsOnRetry", "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL }, { "retry" , "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL }, { "OnDemandMatchDomainsNever" , "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsNever , __doOnDemandDomains, NULL }, { "never" , "domain", isOther , &kSCPropNetIPSecOnDemandMatchDomainsNever , __doOnDemandDomains, NULL }, { "?" , NULL , isHelp , NULL , NULL , "\nOnDemandMatch configuration commands\n\n" " set interface OnDemandMatch [always domain-name[,domain-name]]\n" " set interface OnDemandMatch [retry domain-name[,domain-name]]\n" " set interface OnDemandMatch [never domain-name[,domain-name]]\n" } }; #define N_IPSEC_ONDEMAND_OPTIONS (sizeof(ipsecOnDemandOptions) / sizeof(ipsecOnDemandOptions[0])) static int __doIPSecOnDemandMatch(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(key) #pragma unused(description) #pragma unused(info) Boolean ok; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("set what?\n")); return -1; } ok = _process_options(ipsecOnDemandOptions, N_IPSEC_ONDEMAND_OPTIONS, argc, argv, newConfiguration); if (!ok) { goto done; } done : return argc; } static selections ipsecAuthenticationMethodSelections[] = { { CFSTR("SharedSecret"), &kSCValNetIPSecAuthenticationMethodSharedSecret, 0 }, { CFSTR("Certificate") , &kSCValNetIPSecAuthenticationMethodCertificate , 0 }, { CFSTR("Hybrid") , &kSCValNetIPSecAuthenticationMethodHybrid , 0 }, { NULL , NULL , 0 } }; static selections ipsecLocalIdentifierTypeSelections[] = { { CFSTR("KeyID") , &kSCValNetIPSecLocalIdentifierTypeKeyID , 0 }, { NULL , NULL , 0 } }; static options ipsecOptions[] = { { "AuthenticationMethod" , NULL, isChooseOne , &kSCPropNetIPSecAuthenticationMethod , NULL , (void *)ipsecAuthenticationMethodSelections }, { "LocalIdentifier" , NULL, isString , &kSCPropNetIPSecLocalIdentifier , NULL , NULL }, { "group" , NULL, isString , &kSCPropNetIPSecLocalIdentifier , NULL , NULL }, { "LocalIdentifierType" , NULL, isChooseOne , &kSCPropNetIPSecLocalIdentifierType , NULL , (void *)ipsecLocalIdentifierTypeSelections }, { "RemoteAddress" , NULL, isString , &kSCPropNetIPSecRemoteAddress , NULL , NULL }, { "SharedSecret" , NULL, isOther , &kSCPropNetIPSecSharedSecret , __doIPSecSharedSecret , NULL }, { "SharedSecretEncryption" , NULL, isOther , &kSCPropNetIPSecSharedSecretEncryption , __doIPSecSharedSecretType , NULL }, // --- XAuth: --- { "XAuthEnabled" , NULL, isBoolean , &kSCPropNetIPSecXAuthEnabled , NULL , NULL }, { "XAuthName" , NULL, isString , &kSCPropNetIPSecXAuthName , NULL , NULL }, { "XAuthPassword" , NULL, isOther , &kSCPropNetIPSecXAuthPassword , __doIPSecXAuthPassword , NULL }, { "XAuthPasswordEncryption", NULL, isOther , &kSCPropNetIPSecXAuthPasswordEncryption, __doIPSecXAuthPasswordType, NULL }, // --- OnDemand: --- { "OnDemandEnabled" , NULL, isBoolean , &kSCPropNetIPSecOnDemandEnabled , NULL , NULL }, { "OnDemandMatch" , NULL, isOther , NULL , __doIPSecOnDemandMatch , NULL }, { "?" , NULL , isHelp , NULL , NULL, "\nIPSec configuration commands\n\n" " set interface [AuthenticationMethod {SharedSecret|Certificate|Hybrid}]\n" " set interface [LocalIdentifier group]\n" " set interface [LocalIdentifierType {KeyID}]\n" " set interface [RemoteAddress name-or-address]\n" " set interface [SharedSecret secret]\n" " set interface [SharedSecretEncryption {Keychain}]\n" " set interface [XAuthEnabled {enable|disable}]\n" " set interface [XAuthPassword password]\n" " set interface [XAuthPasswordEncryption {Keychain}]\n" " set interface [OnDemandEnabled {enable|disable}]\n" " set interface [OnDemandMatch ]\n" } }; #define N_IPSEC_OPTIONS (sizeof(ipsecOptions) / sizeof(ipsecOptions[0])) static Boolean set_interface_ipsec(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { Boolean ok; ok = _process_options(ipsecOptions, N_IPSEC_OPTIONS, argc, argv, newConfiguration); return ok; } #pragma mark - #pragma mark FireWire options static options firewireOptions[] = { { "mtu" , NULL, isNumber , &kSCPropNetEthernetMTU , NULL, NULL }, { "media" , NULL, isString , &kSCPropNetEthernetMediaSubType, NULL, NULL }, { "mediaopt" , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL }, { "?" , NULL , isHelp , NULL , NULL, "\nFireWire configuration commands\n\n" " set interface [mtu n] [media type] [mediaopts opts]\n" } }; #define N_FIREWIRE_OPTIONS (sizeof(firewireOptions) / sizeof(firewireOptions[0])) static Boolean set_interface_firewire(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { CFStringRef interfaceName; Boolean ok; interfaceName = SCNetworkInterfaceGetBSDName(net_interface); if (interfaceName == NULL) { SCPrint(TRUE, stdout, CFSTR("no BSD interface\n")); return FALSE; } ok = _process_options(firewireOptions, N_FIREWIRE_OPTIONS, argc, argv, newConfiguration); if (ok) { // validate configuration if (!validateMediaOptions(net_interface, newConfiguration)) { return FALSE; } } return ok; } #pragma mark - #pragma mark Modem options static selections modemDialSelections[] = { { CFSTR("ignore"), &kSCValNetModemDialModeIgnoreDialTone , 0 }, { CFSTR("manual"), &kSCValNetModemDialModeManual , 0 }, { CFSTR("wait") , &kSCValNetModemDialModeWaitForDialTone, 0 }, { NULL , NULL , 0 } }; static options modemOptions[] = { { "ConnectionPersonality" , "NULL" , isString , &kSCPropNetModemConnectionPersonality , NULL, NULL }, { "DeviceModel" , "model" , isString , &kSCPropNetModemDeviceModel , NULL, NULL }, { "DeviceVendor" , "vendor", isString , &kSCPropNetModemDeviceVendor , NULL, NULL }, { "ConnectionScript" , "script", isString , &kSCPropNetModemConnectionScript , NULL, NULL }, { "DialMode" , "mode" , isChooseOne, &kSCPropNetModemDialMode , NULL, (void *)modemDialSelections }, { "CallWaiting" , NULL , isBoolean , &kSCPropNetModemHoldEnabled , NULL, NULL }, { "CallWaitingAlert" , NULL , isBoolean , &kSCPropNetModemHoldCallWaitingAudibleAlert, NULL, NULL }, { "CallWaitingDisconnectOnAnswer", NULL , isBoolean , &kSCPropNetModemHoldDisconnectOnAnswer , NULL, NULL }, { "DataCompression" , NULL , isBoolean , &kSCPropNetModemDataCompression , NULL, NULL }, { "ErrorCorrection" , NULL , isBoolean , &kSCPropNetModemErrorCorrection , NULL, NULL }, { "HoldReminder" , NULL , isBoolean , &kSCPropNetModemHoldReminder , NULL, NULL }, { "HoldReminderTime" , "time" , isNumber , &kSCPropNetModemHoldReminderTime , NULL, NULL }, { "PulseDial" , NULL , isBoolean , &kSCPropNetModemPulseDial , NULL, NULL }, { "Speaker" , NULL , isBoolean , &kSCPropNetModemSpeaker , NULL, NULL }, { "?" , NULL , isHelp , NULL , NULL, "\nModem configuration commands\n\n" " set interface [DeviceVendor vendor]\n" " set interface [DeviceModel model]\n" " set interface [ConnectionPersonality personality]\n" "\n" " set interface [ConnectionScript connection-script]\n" "\n" " set interface [CallWaiting {enable|disable}]\n" " set interface [CallWaitingAlert {enable|disable}]\n" " set interface [CallWaitingDisconnectOnAnswer {enable|disable}]\n" " set interface [DialMode {ignore|wait}]\n" " set interface [DataCompression {enable|disable}]\n" " set interface [ErrorCorrection {enable|disable}]\n" " set interface [HoldReminder {enable|disable}]\n" " set interface [HoldReminderTime n]\n" " set interface [PulseDial {enable|disable}]\n" " set interface [Speaker {enable|disable}]\n" } }; #define N_MODEM_OPTIONS (sizeof(modemOptions) / sizeof(modemOptions[0])) static Boolean set_interface_modem(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { Boolean ok; ok = _process_options(modemOptions, N_MODEM_OPTIONS, argc, argv, newConfiguration); return ok; } #pragma mark - #pragma mark PPP options static int __doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) CFStringRef encryptionType; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("PPP password not specified\n")); return -1; } encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetPPPAuthPasswordEncryption); if (strlen(argv[0]) > 0) { if (encryptionType == NULL) { #ifdef INLINE_PASSWORDS_USE_CFSTRING CFStringRef pw; pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); #else // INLINE_PASSWORDS_USE_CFSTRING CFIndex n; CFMutableDataRef pw; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); n = CFStringGetLength(str); pw = CFDataCreateMutable(NULL, n * sizeof(UniChar)); CFDataSetLength(pw, n * sizeof(UniChar)); /* ALIGN: CF aligns to at least >8 byte boundries */ CFStringGetCharacters(str, CFRangeMake(0, n), (UniChar *)(void *)CFDataGetMutableBytePtr(pw)); CFRelease(str); #endif // INLINE_PASSWORDS_USE_CFSTRING CFDictionarySetValue(newConfiguration, key, pw); CFRelease(pw); } else if (CFEqual(encryptionType, kSCValNetPPPAuthPasswordEncryptionKeychain)) { Boolean ok; CFDataRef pw; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0); ok = SCNetworkInterfaceSetPassword(net_interface, kSCNetworkInterfacePasswordTypePPP, pw, NULL); CFRelease(pw); CFRelease(str); if (ok) { updateInterfaceConfiguration(newConfiguration); } else { return -1; } } else { SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType); return -1; } } else { if (encryptionType == NULL) { CFDictionaryRemoveValue(newConfiguration, key); } else if (CFEqual(encryptionType, kSCValNetPPPAuthPasswordEncryptionKeychain)) { Boolean ok; ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypePPP); if (ok) { updateInterfaceConfiguration(newConfiguration); } else { return -1; } } else { SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType); return -1; } } return 1; } static int __doPPPAuthPWType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("PPP password type mode not specified\n")); return -1; } if (strlen(argv[0]) > 0) { if (strcasecmp(argv[0], "keychain") == 0) { CFDictionarySetValue(newConfiguration, key, kSCValNetPPPAuthPasswordEncryptionKeychain); } else { SCPrint(TRUE, stdout, CFSTR("invalid password type\n")); return -1; } } else { CFDictionaryRemoveValue(newConfiguration, key); } // encryption type changed, reset password CFDictionaryRemoveValue(newConfiguration, kSCPropNetPPPAuthPassword); return 1; } static options l2tp_ipsecOptions[] = { { "SharedSecret" , NULL, isOther , &kSCPropNetIPSecSharedSecret , __doIPSecSharedSecret , NULL }, { "SharedSecretEncryption", NULL, isOther , &kSCPropNetIPSecSharedSecretEncryption, __doIPSecSharedSecretType, NULL }, { "?" , NULL , isHelp , NULL , NULL, "\nIPSec configuration commands\n\n" " set interface ipsec [SharedSecret secret]\n" " set interface ipsec [SharedSecretEncryption {Keychain}]\n" } }; #define N_L2TP_IPSEC_OPTIONS (sizeof(l2tp_ipsecOptions) / sizeof(l2tp_ipsecOptions[0])) static int __doPPPIPSec(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newPPPConfiguration) { #pragma unused(key) #pragma unused(description) #pragma unused(info) #pragma unused(newPPPConfiguration) SCNetworkInterfaceRef childInterface; CFStringRef childInterfaceType; CFDictionaryRef configuration; CFMutableDictionaryRef newConfiguration; Boolean ok; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("set what?\n")); return -1; } childInterface = SCNetworkInterfaceGetInterface(net_interface); if (childInterface == NULL) { SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n")); return -1; } childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface); if (!CFEqual(childInterfaceType, kSCNetworkInterfaceTypeL2TP)) { SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n")); return -1; } configuration = SCNetworkInterfaceGetExtendedConfiguration(net_interface, kSCEntNetIPSec); if (configuration == NULL) { newConfiguration = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } else { newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration); CFDictionaryRemoveValue(newConfiguration, kSCResvInactive); } ok = _process_options(l2tp_ipsecOptions, N_L2TP_IPSEC_OPTIONS, argc, argv, newConfiguration); if (!ok) { goto done; } if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) || ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) { if (!SCNetworkInterfaceSetExtendedConfiguration(net_interface, kSCEntNetIPSec, newConfiguration)) { if (SCError() == kSCStatusNoKey) { SCPrint(TRUE, stdout, CFSTR("could not update per-service interface configuration\n")); } else { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); } goto done; } _prefs_changed = TRUE; } done : if (newConfiguration != NULL) CFRelease(newConfiguration); return argc; } #ifdef NOTYET static options pppOnDemandOptions[] = { { "OnDemandMatchDomainsAlways" , "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL }, { "always" , "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsAlways , __doOnDemandDomains, NULL }, { "OnDemandMatchDomainsOnRetry", "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL }, { "retry" , "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsOnRetry, __doOnDemandDomains, NULL }, { "OnDemandMatchDomainsNever" , "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsNever , __doOnDemandDomains, NULL }, { "never" , "domain", isOther , &kSCPropNetPPPOnDemandMatchDomainsNever , __doOnDemandDomains, NULL }, { "?" , NULL , isHelp , NULL , NULL , "\nOnDemandMatch configuration commands\n\n" " set interface OnDemand always domain-name[,domain-name]\n" " set interface OnDemand retry domain-name[,domain-name]\n" " set interface OnDemand never domain-name[,domain-name]\n" } }; #define N_PPP_ONDEMAND_OPTIONS (sizeof(pppOnDemandOptions) / sizeof(pppOnDemandOptions[0])) static int __doPPPOnDemandMatch(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { Boolean ok; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("set what?\n")); return -1; } ok = _process_options(pppOnDemandOptions, N_PPP_ONDEMAND_OPTIONS, argc, argv, newConfiguration); if (!ok) { goto done; } done : return argc; } #endif // NOTYET static selections authPromptSelections[] = { { CFSTR("before"), &kSCValNetPPPAuthPromptBefore, 0 }, { CFSTR("after") , &kSCValNetPPPAuthPromptAfter , 0 }, { NULL , NULL , 0 } }; static selections authProtocolSelections[] = { { CFSTR("CHAP") , &kSCValNetPPPAuthProtocolCHAP , 0 }, { CFSTR("EAP") , &kSCValNetPPPAuthProtocolEAP , 0 }, { CFSTR("MSCHAP1"), &kSCValNetPPPAuthProtocolMSCHAP1, 0 }, { CFSTR("MSCHAP2"), &kSCValNetPPPAuthProtocolMSCHAP2, 0 }, { CFSTR("PAP") , &kSCValNetPPPAuthProtocolPAP , 0 }, { NULL , NULL , 0 } }; static options pppOptions[] = { { "ACSP" , NULL , isBoolean , &kSCPropNetPPPACSPEnabled , NULL , NULL }, { "ConnectTime" , "?time" , isNumber , &kSCPropNetPPPConnectTime , NULL , NULL }, { "DialOnDemand" , NULL , isBoolean , &kSCPropNetPPPDialOnDemand , NULL , NULL }, { "DisconnectOnFastUserSwitch", NULL , isBoolean , &kSCPropNetPPPDisconnectOnFastUserSwitch, NULL , NULL }, { "DisconnectOnIdle" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnIdle , NULL , NULL }, { "DisconnectOnIdleTimer" , "timeout" , isNumber , &kSCPropNetPPPDisconnectOnIdleTimer , NULL , NULL }, { "DisconnectOnLogout" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnLogout , NULL , NULL }, { "DisconnectOnSleep" , NULL , isBoolean , &kSCPropNetPPPDisconnectOnSleep , NULL , NULL }, { "DisconnectTime" , "?time" , isNumber , &kSCPropNetPPPDisconnectTime , NULL , NULL }, { "IdleReminder" , NULL , isBoolean , &kSCPropNetPPPIdleReminder , NULL , NULL }, { "IdleReminderTimer" , "time" , isNumber , &kSCPropNetPPPIdleReminderTimer , NULL , NULL }, { "Logfile" , "path" , isString , &kSCPropNetPPPLogfile , NULL , NULL }, #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated" { "Plugins" , "plugin" , isStringArray , &kSCPropNetPPPPlugins , NULL , NULL }, #pragma GCC diagnostic pop { "RetryConnectTime" , "time" , isNumber , &kSCPropNetPPPRetryConnectTime , NULL , NULL }, { "SessionTimer" , "time" , isNumber , &kSCPropNetPPPSessionTimer , NULL , NULL }, { "UseSessionTimer" , NULL , isBoolean , &kSCPropNetPPPUseSessionTimer , NULL , NULL }, { "VerboseLogging" , NULL , isBoolean , &kSCPropNetPPPVerboseLogging , NULL , NULL }, // --- Auth: --- #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated" { "AuthEAPPlugins" , "plugin" , isStringArray , &kSCPropNetPPPAuthEAPPlugins , NULL , NULL }, #pragma GCC diagnostic pop { "AuthName" , "account" , isString , &kSCPropNetPPPAuthName , NULL , NULL }, { "Account" , "account" , isString , &kSCPropNetPPPAuthName , NULL , NULL }, { "AuthPassword" , "password" , isOther , &kSCPropNetPPPAuthPassword , __doPPPAuthPW , NULL }, { "Password" , "password" , isOther , &kSCPropNetPPPAuthPassword , __doPPPAuthPW , NULL }, { "AuthPasswordEncryption" , "type" , isOther , &kSCPropNetPPPAuthPasswordEncryption , __doPPPAuthPWType , NULL }, { "AuthPrompt" , "before/after", isChooseOne , &kSCPropNetPPPAuthPrompt , NULL , (void *)authPromptSelections }, { "AuthProtocol" , "protocol" , isChooseMultiple , &kSCPropNetPPPAuthProtocol , NULL , (void *)authProtocolSelections }, // --- Comm: --- { "CommRemoteAddress" , "phone#" , isString , &kSCPropNetPPPCommRemoteAddress , NULL , NULL }, { "Number" , "phone#" , isString , &kSCPropNetPPPCommRemoteAddress , NULL , NULL }, { "CommAlternateRemoteAddress", "phone#" , isString , &kSCPropNetPPPCommAlternateRemoteAddress, NULL , NULL }, { "CommConnectDelay" , "time" , isNumber , &kSCPropNetPPPCommConnectDelay , NULL , NULL }, { "CommDisplayTerminalWindow" , NULL , isBoolean , &kSCPropNetPPPCommDisplayTerminalWindow , NULL , NULL }, { "CommRedialCount" , "retry count" , isNumber , &kSCPropNetPPPCommRedialCount , NULL , NULL }, { "CommRedialEnabled" , NULL , isBoolean , &kSCPropNetPPPCommRedialEnabled , NULL , NULL }, { "CommRedialInterval" , "retry delay" , isNumber , &kSCPropNetPPPCommRedialInterval , NULL , NULL }, { "CommTerminalScript" , "script" , isString , &kSCPropNetPPPCommTerminalScript , NULL , NULL }, { "CommUseTerminalScript" , NULL , isBoolean , &kSCPropNetPPPCommUseTerminalScript , NULL , NULL }, // --- CCP: --- { "CCPEnabled" , NULL , isBoolean , &kSCPropNetPPPCCPEnabled , NULL , NULL }, { "CCPMPPE40Enabled" , NULL , isBoolean , &kSCPropNetPPPCCPMPPE40Enabled , NULL , NULL }, { "CCPMPPE128Enabled" , NULL , isBoolean , &kSCPropNetPPPCCPMPPE128Enabled , NULL , NULL }, // --- IPCP: --- { "IPCPCompressionVJ" , NULL , isBoolean , &kSCPropNetPPPIPCPCompressionVJ , NULL , NULL }, { "IPCPUsePeerDNS" , NULL , isBoolean , &kSCPropNetPPPIPCPUsePeerDNS , NULL , NULL }, // --- LCP: --- { "LCPEchoEnabled" , NULL , isBoolean , &kSCPropNetPPPLCPEchoEnabled , NULL , NULL }, { "LCPEchoFailure" , NULL , isNumber , &kSCPropNetPPPLCPEchoFailure , NULL , NULL }, { "LCPEchoInterval" , NULL , isNumber , &kSCPropNetPPPLCPEchoInterval , NULL , NULL }, { "LCPCompressionACField" , NULL , isBoolean , &kSCPropNetPPPLCPCompressionACField , NULL , NULL }, { "LCPCompressionPField" , NULL , isBoolean , &kSCPropNetPPPLCPCompressionPField , NULL , NULL }, { "LCPMRU" , NULL , isNumber , &kSCPropNetPPPLCPMRU , NULL , NULL }, { "LCPMTU" , NULL , isNumber , &kSCPropNetPPPLCPMTU , NULL , NULL }, { "LCPReceiveACCM" , NULL , isNumber , &kSCPropNetPPPLCPReceiveACCM , NULL , NULL }, { "LCPTransmitACCM" , NULL , isNumber , &kSCPropNetPPPLCPTransmitACCM , NULL , NULL }, // --- IPSec: --- { "IPSec" , NULL , isOther , NULL , __doPPPIPSec , NULL }, #ifdef NOTYET // --- OnDemand: --- { "OnDemandEnabled" , NULL , isBoolean , &kSCPropNetPPPOnDemandEnabled , NULL , NULL }, { "OnDemandMatch" , NULL , isOther , NULL , __doPPPOnDemandMatch, NULL }, #endif // NOTYET // --- Help --- { "?" , NULL , isHelp , NULL , NULL , "\nPPP configuration commands\n\n" " set interface [Account account]\n" " set interface [Password password]\n" " set interface [Number telephone-number]\n" " set interface [AlternateNumber telephone-number]\n" " set interface [IdleReminder {enable|disable}]\n" " set interface [IdleReminderTimer time-in-seconds]\n" " set interface [DisconnectOnIdle {enable|disable}]\n" " set interface [DisconnectOnIdleTimer time-in-seconds]\n" " set interface [DisconnectOnLogout {enable|disable}]\n" " set interface [IPSec ]\n" #ifdef NOTYET " set interface [OnDemandEnabled {enable|disable}]\n" " set interface [OnDemandMatch ]\n" #endif // NOTYET } }; #define N_PPP_OPTIONS (sizeof(pppOptions) / sizeof(pppOptions[0])) static Boolean set_interface_ppp(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { Boolean ok; ok = _process_options(pppOptions, N_PPP_OPTIONS, argc, argv, newConfiguration); return ok; } #pragma mark - #pragma mark VLAN options static Boolean set_interface_vlan(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(argc) #pragma unused(argv) #pragma unused(newConfiguration) // xxxxx ("device", "tag") SCPrint(TRUE, stdout, CFSTR("vlan interface management not yet supported\n")); return FALSE; } #pragma mark - #pragma mark VPN options static int __doVPNAuthPW(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) CFStringRef encryptionType; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("VPN password not specified\n")); return -1; } encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetVPNAuthPasswordEncryption); if (strlen(argv[0]) > 0) { if (encryptionType == NULL) { #ifdef INLINE_PASSWORDS_USE_CFSTRING CFStringRef pw; pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); #else // INLINE_PASSWORDS_USE_CFSTRING CFIndex n; CFMutableDataRef pw; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); n = CFStringGetLength(str); pw = CFDataCreateMutable(NULL, n * sizeof(UniChar)); CFDataSetLength(pw, n * sizeof(UniChar)); CFStringGetCharacters(str, CFRangeMake(0, n), (UniChar *)(void *)CFDataGetMutableBytePtr(pw)); CFRelease(str); #endif // INLINE_PASSWORDS_USE_CFSTRING CFDictionarySetValue(newConfiguration, key, pw); CFRelease(pw); } else if (CFEqual(encryptionType, kSCValNetVPNAuthPasswordEncryptionKeychain)) { Boolean ok; CFDataRef pw; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); pw = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0); ok = SCNetworkInterfaceSetPassword(net_interface, kSCNetworkInterfacePasswordTypeVPN, pw, NULL); CFRelease(pw); CFRelease(str); if (ok) { updateInterfaceConfiguration(newConfiguration); } else { return -1; } } else { SCPrint(TRUE, stdout, CFSTR("VPN password type \"%@\" not supported\n"), encryptionType); return -1; } } else { if (encryptionType == NULL) { CFDictionaryRemoveValue(newConfiguration, key); } else if (CFEqual(encryptionType, kSCValNetVPNAuthPasswordEncryptionKeychain)) { Boolean ok; ok = SCNetworkInterfaceRemovePassword(net_interface, kSCNetworkInterfacePasswordTypeVPN); if (ok) { updateInterfaceConfiguration(newConfiguration); } else { return -1; } } else { SCPrint(TRUE, stdout, CFSTR("PPP password type \"%@\" not supported\n"), encryptionType); return -1; } } return 1; } static int __doVPNAuthPWType(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("VPN password type mode not specified\n")); return -1; } if (strlen(argv[0]) > 0) { if (strcasecmp(argv[0], "keychain") == 0) { CFDictionarySetValue(newConfiguration, key, kSCValNetVPNAuthPasswordEncryptionKeychain); } else if (strcasecmp(argv[0], "prompt") == 0) { CFDictionarySetValue(newConfiguration, key, kSCValNetVPNAuthPasswordEncryptionPrompt); } else { SCPrint(TRUE, stdout, CFSTR("invalid password type\n")); return -1; } } else { CFDictionaryRemoveValue(newConfiguration, key); } // encryption type changed, reset password CFDictionaryRemoveValue(newConfiguration, kSCPropNetVPNAuthPassword); return 1; } static selections vpnAuthenticationMethodSelections[] = { { CFSTR("Password") , &kSCValNetVPNAuthenticationMethodPassword , 0 }, { CFSTR("Certificate") , &kSCValNetVPNAuthenticationMethodCertificate , 0 }, { NULL , NULL , 0 } }; static options vpnOptions[] = { { "AuthName" , "account" , isString , &kSCPropNetVPNAuthName , NULL , NULL }, { "Account" , "account" , isString , &kSCPropNetVPNAuthName , NULL , NULL }, { "AuthPassword" , "password" , isOther , &kSCPropNetVPNAuthPassword , __doVPNAuthPW , NULL }, { "Password" , "password" , isOther , &kSCPropNetVPNAuthPassword , __doVPNAuthPW , NULL }, { "AuthPasswordEncryption" , "type" , isOther , &kSCPropNetVPNAuthPasswordEncryption , __doVPNAuthPWType , NULL }, { "AuthenticationMethod" , NULL , isChooseOne , &kSCPropNetVPNAuthenticationMethod , NULL , (void *)vpnAuthenticationMethodSelections }, { "ConnectTime" , "?time" , isNumber , &kSCPropNetVPNConnectTime , NULL , NULL }, { "DisconnectOnFastUserSwitch", NULL , isBoolean , &kSCPropNetVPNDisconnectOnFastUserSwitch, NULL , NULL }, { "DisconnectOnIdle" , NULL , isBoolean , &kSCPropNetVPNDisconnectOnIdle , NULL , NULL }, { "DisconnectOnIdleTimer" , "timeout" , isNumber , &kSCPropNetVPNDisconnectOnIdleTimer , NULL , NULL }, { "DisconnectOnLogout" , NULL , isBoolean , &kSCPropNetVPNDisconnectOnLogout , NULL , NULL }, { "DisconnectOnSleep" , NULL , isBoolean , &kSCPropNetVPNDisconnectOnSleep , NULL , NULL }, { "Logfile" , "path" , isString , &kSCPropNetVPNLogfile , NULL , NULL }, { "MTU" , NULL , isNumber , &kSCPropNetVPNMTU , NULL , NULL }, { "RemoteAddress" , "server" , isString , &kSCPropNetVPNRemoteAddress , NULL , NULL }, { "Server" , "server" , isString , &kSCPropNetVPNRemoteAddress , NULL , NULL }, { "VerboseLogging" , NULL , isBoolean , &kSCPropNetVPNVerboseLogging , NULL , NULL }, // --- Help --- { "?" , NULL , isHelp , NULL , NULL , "\nVPN configuration commands\n\n" " set interface [Server server]\n" " set interface [Account account]\n" " set interface [Password password]\n" } }; #define N_VPN_OPTIONS (sizeof(vpnOptions) / sizeof(vpnOptions[0])) static Boolean set_interface_vpn(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { Boolean ok; ok = _process_options(vpnOptions, N_VPN_OPTIONS, argc, argv, newConfiguration); return ok; } #pragma mark - #pragma mark [more] Interface management __private_extern__ void set_interface(int argc, char **argv) { CFDictionaryRef configuration; CFStringRef interfaceType; CFMutableDictionaryRef newConfiguration = NULL; Boolean ok = FALSE; if (net_interface == NULL) { SCPrint(TRUE, stdout, CFSTR("interface not selected\n")); return; } if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("set what?\n")); return; } configuration = SCNetworkInterfaceGetConfiguration(net_interface); if (configuration != NULL) { configuration = CFDictionaryCreateCopy(NULL, configuration); newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration); CFDictionaryRemoveValue(newConfiguration, kSCResvInactive); } else { newConfiguration = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } interfaceType = SCNetworkInterfaceGetInterfaceType(net_interface); if (CFEqual(interfaceType, kSCNetworkInterfaceTypeEthernet)) { ok = set_interface_ethernet(argc, argv, newConfiguration); } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeFireWire)) { ok = set_interface_firewire(argc, argv, newConfiguration); } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) { ok = set_interface_ipsec(argc, argv, newConfiguration); } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeModem)) { ok = set_interface_modem(argc, argv, newConfiguration); } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIEEE80211)) { ok = set_interface_airport(argc, argv, newConfiguration); } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) { ok = set_interface_ppp(argc, argv, newConfiguration); } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBond)) { ok = set_interface_bond(argc, argv, newConfiguration); } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBridge)) { ok = set_interface_bridge(argc, argv, newConfiguration); } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVLAN)) { ok = set_interface_vlan(argc, argv, newConfiguration); } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) { ok = set_interface_vpn(argc, argv, newConfiguration); } else { SCPrint(TRUE, stdout, CFSTR("this interfaces configuration cannot be changed\n")); } if (!ok) { goto done; } if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) || ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) { if (!SCNetworkInterfaceSetConfiguration(net_interface, newConfiguration)) { if (SCError() == kSCStatusNoKey) { SCPrint(TRUE, stdout, CFSTR("could not update per-service interface configuration\n")); } else { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); } goto done; } _prefs_changed = TRUE; } done : if (configuration != NULL) CFRelease(configuration); if (newConfiguration != NULL) CFRelease(newConfiguration); return; } /* -------------------- */ __private_extern__ void show_interface(int argc, char **argv) { SCNetworkInterfaceRef interface; if (argc >= 1) { interface = _find_interface(argc, argv, NULL); } else { if (net_interface != NULL) { interface = net_interface; } else { SCPrint(TRUE, stdout, CFSTR("interface not selected\n")); return; } } if (interface != NULL) { _show_interface(interface, CFSTR(""), TRUE); } return; } /* -------------------- */ __private_extern__ CF_RETURNS_RETAINED CFStringRef _interface_description(SCNetworkInterfaceRef interface) { CFMutableStringRef description; CFStringRef if_bsd_name; CFStringRef if_type; description = CFStringCreateMutable(NULL, 0); if_type = SCNetworkInterfaceGetInterfaceType(interface); CFStringAppend(description, if_type); if_bsd_name = SCNetworkInterfaceGetBSDName(interface); if (if_bsd_name != NULL) { CFStringAppendFormat(description, NULL, CFSTR(" (%@)"), if_bsd_name); } interface = SCNetworkInterfaceGetInterface(interface); while ((interface != NULL) && !CFEqual(interface, kSCNetworkInterfaceIPv4)) { CFStringRef childDescription; childDescription = _interface_description(interface); CFStringAppendFormat(description, NULL, CFSTR(" / %@"), childDescription); CFRelease(childDescription); interface = SCNetworkInterfaceGetInterface(interface); } return description; }