this repo has no description
at fixPythonPipStalling 513 lines 14 kB view raw
1/* 2 * Copyright (c) 2012, 2013, 2016, 2017 Apple Inc. All rights reserved. 3 */ 4 5#include "SCNetworkConfigurationInternal.h" 6#include "dy_framework.h" 7 8static CFStringRef g_apple_app_prefix = CFSTR("com.apple."); 9 10static struct { 11 CFStringRef signing_id; 12 Boolean domains_required; 13} g_apple_app_exceptions[] = { 14#if TARGET_OS_IPHONE 15 { CFSTR("com.apple.mobilesafari"), TRUE }, 16 { CFSTR("com.apple.webapp"), TRUE }, 17#else 18 { CFSTR("com.apple.WebKit.NetworkProcess"), TRUE }, 19#endif 20}; 21 22 23static Boolean 24isA_VPNService(CFTypeRef cf) 25{ 26 if (isA_SCNetworkService(cf)) { 27 SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface((SCNetworkServiceRef)cf); 28 29 return (interface != NULL && 30 CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypeVPN)); 31 } 32 33 return FALSE; 34} 35 36 37static CFArrayRef 38copy_matching_services(SCPreferencesRef prefs, CFStringRef identifierDomain, CFStringRef identifier) 39{ 40 CFMutableArrayRef results = NULL; 41 CFArrayRef services; 42 43 services = SCNetworkServiceCopyAll(prefs); 44 if (services != NULL) { 45 CFIndex idx; 46 CFIndex service_count = CFArrayGetCount(services); 47 48 for (idx = 0; idx < service_count; idx++) { 49 SCNetworkServiceRef service = CFArrayGetValueAtIndex(services, idx); 50 Boolean matches = FALSE; 51 52 if (isA_VPNService(service)) { 53 if (isA_CFString(identifierDomain) && isA_CFString(identifier)) { 54 CFStringRef ex_identifier = SCNetworkServiceCopyExternalID(service, identifierDomain); 55 if (ex_identifier != NULL) { 56 matches = CFEqual(ex_identifier, identifier); 57 CFRelease(ex_identifier); 58 } 59 } else { 60 matches = TRUE; 61 } 62 } 63 64 if (matches) { 65 if (results == NULL) { 66 results = CFArrayCreateMutable(kCFAllocatorDefault, CFArrayGetCount(services) - idx, &kCFTypeArrayCallBacks); 67 } 68 CFArrayAppendValue(results, service); 69 } 70 } 71 72 CFRelease(services); 73 } 74 75 return results; 76} 77 78 79static CFIndex 80find_app_rule(CFDictionaryRef vpn_config, CFStringRef ruleIdentifier) 81{ 82 CFArrayRef app_rules = CFDictionaryGetValue(vpn_config, kSCPropNetVPNAppRules); 83 CFIndex idx; 84 85 if (isA_CFArray(app_rules)) { 86 CFIndex rule_count = CFArrayGetCount(app_rules); 87 88 for (idx = 0; idx < rule_count; idx++) { 89 CFDictionaryRef rule = CFArrayGetValueAtIndex(app_rules, idx); 90 91 if (isA_CFDictionary(rule)) { 92 CFStringRef rule_id = CFDictionaryGetValue(rule, kSCValNetVPNAppRuleIdentifier); 93 94 if (CFEqual(ruleIdentifier, rule_id)) { 95 return idx; 96 } 97 } 98 } 99 } 100 101 return -1; 102} 103 104static Boolean 105validate_app_rule(CFDictionaryRef ruleSettings, Boolean check_for_apple_apps) 106{ 107 CFIndex account_count = 0; 108 CFArrayRef accounts; 109 CFIndex exception_idx = -1; 110 CFArrayRef executables; 111 CFIndex executable_count = 0; 112 Boolean found_exception = FALSE; 113 CFIndex idx; 114 CFArrayRef match_domains; 115 CFIndex match_domain_count = 0; 116 117 if (!isA_CFDictionary(ruleSettings)) { 118 return FALSE; 119 } 120 121 /* Validate the executable array. It needs to have at least one value. */ 122 executables = CFDictionaryGetValue(ruleSettings, kSCValNetVPNAppRuleExecutableMatch); 123 if (isA_CFArray(executables) && (executable_count = CFArrayGetCount(executables)) > 0) { 124 for (idx = 0; idx < executable_count; idx++) { 125 CFDictionaryRef executable = CFArrayGetValueAtIndex(executables, idx); 126 127 if (isA_CFDictionary(executable)) { 128 CFStringRef signingID = CFDictionaryGetValue(executable, kSCValNetVPNAppRuleExecutableSigningIdentifier); 129 CFStringRef requirement = CFDictionaryGetValue(executable, kSCValNetVPNAppRuleExecutableDesignatedRequirement); 130 131 if (!isA_CFString(signingID) || CFStringGetLength(signingID) == 0) { 132 return FALSE; 133 } 134 135 if (check_for_apple_apps && CFStringHasPrefix(signingID, g_apple_app_prefix)) { 136 for (exception_idx = 0; 137 exception_idx < (CFIndex)(sizeof(g_apple_app_exceptions) / sizeof(g_apple_app_exceptions[0])); 138 exception_idx++) 139 { 140 if (CFStringCompare(signingID, g_apple_app_exceptions[exception_idx].signing_id, 0) == 0) { 141 found_exception = TRUE; 142 break; 143 } 144 } 145 146 if (!found_exception) { 147 Boolean can_set_apple_app_rules = FALSE; 148 SecTaskRef current_task = SecTaskCreateFromSelf(kCFAllocatorDefault); 149 if (current_task != NULL) { 150 CFBooleanRef entitlement = 151 SecTaskCopyValueForEntitlement(current_task, 152 CFSTR("com.apple.private.app-vpn-config"), 153 NULL); 154 can_set_apple_app_rules = (isA_CFBoolean(entitlement) && CFBooleanGetValue(entitlement)); 155 if (entitlement != NULL) { 156 CFRelease(entitlement); 157 } 158 CFRelease(current_task); 159 } 160 if (!can_set_apple_app_rules) { 161 return FALSE; 162 } 163 } 164 } 165 166 if (requirement != NULL) { 167 if (!isA_CFString(requirement) || CFStringGetLength(requirement) == 0) { 168 return FALSE; 169 } 170#if !TARGET_OS_IPHONE 171 } else { 172 return FALSE; 173#endif /* !TARGET_OS_IPHONE */ 174 } 175 } 176 } 177 } 178 179 /* Validate the accounts array. It needs to have at least one value. */ 180 accounts = CFDictionaryGetValue(ruleSettings, kSCValNetVPNAppRuleAccountIdentifierMatch); 181 if (isA_CFArray(accounts) && (account_count = CFArrayGetCount(accounts)) > 0) { 182 for (idx = 0; idx < account_count; idx++) { 183 CFStringRef account = CFArrayGetValueAtIndex(accounts, idx); 184 if (!isA_CFString(account)) { 185 return FALSE; 186 } 187 } 188 } 189 190 /* Either executables or accounts must be present */ 191 if (executable_count == 0 && account_count == 0) { 192 return FALSE; 193 } 194 195 /* Validate the domains array. It's optional, so just make sure that it contains only strings if it's present. */ 196 match_domains = CFDictionaryGetValue(ruleSettings, kSCValNetVPNAppRuleDNSDomainMatch); 197 if (match_domains != NULL) { 198 if (!isA_CFArray(match_domains)) { 199 return FALSE; 200 } 201 202 match_domain_count = CFArrayGetCount(match_domains); 203 for (idx = 0; idx < match_domain_count; idx++) { 204 CFStringRef domain = CFArrayGetValueAtIndex(match_domains, idx); 205 if (!isA_CFString(domain)) { 206 return FALSE; 207 } 208 } 209 } 210 211 /* Require at least one match domain for some Apple apps (like Safari) */ 212 if (match_domain_count == 0 && 213 found_exception && 214 exception_idx >= 0 && 215 g_apple_app_exceptions[exception_idx].domains_required) 216 { 217 return FALSE; 218 } 219 220 return TRUE; 221} 222 223 224CFArrayRef 225VPNServiceCopyAllMatchingExternalID(SCPreferencesRef prefs, CFStringRef identifierDomain, CFStringRef identifier) 226{ 227 CFArrayRef services; 228 229 if (prefs == NULL || !isA_CFString(identifierDomain) || !isA_CFString(identifier)) { 230 _SCErrorSet(kSCStatusInvalidArgument); 231 return NULL; 232 } 233 234 services = copy_matching_services(prefs, identifierDomain, identifier); 235 if (services == NULL) { 236 _SCErrorSet(kSCStatusOK); 237 } 238 239 return services; 240} 241 242 243CFArrayRef 244VPNServiceCopyAll(SCPreferencesRef prefs) 245{ 246 CFArrayRef services; 247 248 if (prefs == NULL) { 249 _SCErrorSet(kSCStatusInvalidArgument); 250 return NULL; 251 } 252 253 services = copy_matching_services(prefs, NULL, NULL); 254 if (services == NULL) { 255 _SCErrorSet(kSCStatusOK); 256 } 257 258 return services; 259} 260 261 262CFArrayRef 263VPNServiceCopyAppRuleIDs(VPNServiceRef service) 264{ 265 SCNetworkInterfaceRef interface; 266 CFMutableArrayRef results = NULL; 267 CFDictionaryRef vpn_config; 268 269 if (!isA_VPNService(service)) { 270 _SCErrorSet(kSCStatusInvalidArgument); 271 return NULL; 272 } 273 274 interface = SCNetworkServiceGetInterface(service); 275 if (interface == NULL) { 276 _SCErrorSet(kSCStatusInvalidArgument); 277 return NULL; 278 } 279 280 vpn_config = SCNetworkInterfaceGetConfiguration(interface); 281 if (isA_CFDictionary(vpn_config)) { 282 CFArrayRef app_rules = CFDictionaryGetValue(vpn_config, kSCPropNetVPNAppRules); 283 if (isA_CFArray(app_rules)) { 284 CFIndex app_rule_count = CFArrayGetCount(app_rules); 285 CFIndex idx; 286 results = CFArrayCreateMutable(kCFAllocatorDefault, app_rule_count, &kCFTypeArrayCallBacks); 287 for (idx = 0; idx < app_rule_count; idx++) { 288 CFDictionaryRef rule = CFArrayGetValueAtIndex(app_rules, idx); 289 if (isA_CFDictionary(rule)) { 290 CFStringRef rule_ID = CFDictionaryGetValue(rule, kSCValNetVPNAppRuleIdentifier); 291 if (isA_CFString(rule_ID)) { 292 CFArrayAppendValue(results, CFDictionaryGetValue(rule, kSCValNetVPNAppRuleIdentifier)); 293 } 294 } 295 } 296 if (CFArrayGetCount(results) == 0) { 297 CFRelease(results); 298 results = NULL; 299 } 300 } 301 } 302 303 if (results == NULL) { 304 _SCErrorSet(kSCStatusOK); 305 } 306 307 return results; 308} 309 310 311Boolean 312VPNServiceSetAppRule(VPNServiceRef service, CFStringRef ruleIdentifier, CFDictionaryRef ruleSettings) 313{ 314 CFArrayRef accounts; 315 CFArrayRef app_rules; 316 CFArrayRef executables; 317 CFIndex existing_idx = -1; 318 SCNetworkInterfaceRef interface; 319 CFArrayRef match_domains; 320 CFMutableArrayRef new_app_rules; 321 CFMutableDictionaryRef new_settings; 322 CFMutableDictionaryRef new_vpn_config; 323 CFDictionaryRef vpn_config; 324 325 /* Basic parameter validation */ 326 327 if (!isA_VPNService(service) || !isA_CFString(ruleIdentifier)) { 328 _SCErrorSet(kSCStatusInvalidArgument); 329 return FALSE; 330 } 331 332 if (!validate_app_rule(ruleSettings, TRUE)) { 333 _SCErrorSet(kSCStatusInvalidArgument); 334 return FALSE; 335 } 336 337 interface = SCNetworkServiceGetInterface(service); 338 if (interface == NULL) { 339 _SCErrorSet(kSCStatusInvalidArgument); 340 return FALSE; 341 } 342 343 executables = CFDictionaryGetValue(ruleSettings, kSCValNetVPNAppRuleExecutableMatch); 344 match_domains = CFDictionaryGetValue(ruleSettings, kSCValNetVPNAppRuleDNSDomainMatch); 345 accounts = CFDictionaryGetValue(ruleSettings, kSCValNetVPNAppRuleAccountIdentifierMatch); 346 347 /* Set the new rule config, replacing any existing rule */ 348 349 vpn_config = SCNetworkInterfaceGetConfiguration(interface); 350 if (isA_CFDictionary(vpn_config)) { 351 existing_idx = find_app_rule(vpn_config, ruleIdentifier); 352 new_vpn_config = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, vpn_config); 353 } else { 354 new_vpn_config = CFDictionaryCreateMutable(kCFAllocatorDefault, 355 0, 356 &kCFTypeDictionaryKeyCallBacks, 357 &kCFTypeDictionaryValueCallBacks); 358 } 359 360 app_rules = CFDictionaryGetValue(new_vpn_config, kSCPropNetVPNAppRules); 361 if (isA_CFArray(app_rules)) { 362 new_app_rules = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, app_rules); 363 } else { 364 new_app_rules = CFArrayCreateMutable(kCFAllocatorDefault, 365 0, 366 &kCFTypeArrayCallBacks); 367 } 368 369 new_settings = CFDictionaryCreateMutable(kCFAllocatorDefault, 370 0, 371 &kCFTypeDictionaryKeyCallBacks, 372 &kCFTypeDictionaryValueCallBacks); 373 374 CFDictionarySetValue(new_settings, kSCValNetVPNAppRuleIdentifier, ruleIdentifier); 375 if (executables != NULL && CFArrayGetCount(executables) > 0) { 376 CFDictionarySetValue(new_settings, kSCValNetVPNAppRuleExecutableMatch, executables); 377 } 378 if (match_domains != NULL && CFArrayGetCount(match_domains) > 0) { 379 CFDictionarySetValue(new_settings, kSCValNetVPNAppRuleDNSDomainMatch, match_domains); 380 } 381 if (accounts != NULL && CFArrayGetCount(accounts) > 0) { 382 CFDictionarySetValue(new_settings, kSCValNetVPNAppRuleAccountIdentifierMatch, accounts); 383 } 384 385 if (existing_idx >= 0) { 386 CFArraySetValueAtIndex(new_app_rules, existing_idx, new_settings); 387 } else { 388 CFArrayAppendValue(new_app_rules, new_settings); 389 } 390 391 CFDictionarySetValue(new_vpn_config, kSCPropNetVPNAppRules, new_app_rules); 392 393 SCNetworkInterfaceSetConfiguration(interface, new_vpn_config); 394 395 CFRelease(new_vpn_config); 396 CFRelease(new_app_rules); 397 CFRelease(new_settings); 398 399 return TRUE; 400} 401 402 403CFDictionaryRef 404VPNServiceCopyAppRule(VPNServiceRef service, CFStringRef ruleIdentifier) 405{ 406 SCNetworkInterfaceRef interface; 407 CFDictionaryRef vpn_config; 408 409 if (!isA_VPNService(service) || !isA_CFString(ruleIdentifier)) { 410 _SCErrorSet(kSCStatusInvalidArgument); 411 return NULL; 412 } 413 414 interface = SCNetworkServiceGetInterface(service); 415 if (interface == NULL) { 416 _SCErrorSet(kSCStatusInvalidArgument); 417 return FALSE; 418 } 419 420 vpn_config = SCNetworkInterfaceGetConfiguration(interface); 421 if (isA_CFDictionary(vpn_config)) { 422 CFIndex idx = find_app_rule(vpn_config, ruleIdentifier); 423 if (idx >= 0) { 424 CFArrayRef app_rules = CFDictionaryGetValue(vpn_config, kSCPropNetVPNAppRules); 425 CFDictionaryRef ruleSettings = CFArrayGetValueAtIndex(app_rules, idx); 426 427 if (validate_app_rule(ruleSettings, FALSE)) { 428 return (CFDictionaryRef)CFRetain(ruleSettings); 429 } else { 430 _SCErrorSet(kSCStatusFailed); 431 } 432 } else { 433 _SCErrorSet(kSCStatusNoKey); 434 } 435 } else { 436 _SCErrorSet(kSCStatusFailed); 437 } 438 439 return NULL; 440} 441 442 443Boolean 444VPNServiceRemoveAppRule(VPNServiceRef service, CFStringRef ruleIdentifier) 445{ 446 SCNetworkInterfaceRef interface; 447 CFDictionaryRef vpn_config; 448 449 if (!isA_VPNService(service) || !isA_CFString(ruleIdentifier)) { 450 _SCErrorSet(kSCStatusInvalidArgument); 451 return FALSE; 452 } 453 454 interface = SCNetworkServiceGetInterface(service); 455 if (interface == NULL) { 456 _SCErrorSet(kSCStatusInvalidArgument); 457 return FALSE; 458 } 459 460 vpn_config = SCNetworkInterfaceGetConfiguration(interface); 461 if (isA_CFDictionary(vpn_config)) { 462 CFIndex idx = find_app_rule(vpn_config, ruleIdentifier); 463 if (idx >= 0) { 464 CFArrayRef current_app_rules; 465 current_app_rules = CFDictionaryGetValue(vpn_config, kSCPropNetVPNAppRules); 466 if (isA_CFArray(current_app_rules)) { 467 CFMutableDictionaryRef new_vpn_config; 468 CFMutableArrayRef new_app_rules; 469 470 new_vpn_config = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, vpn_config); 471 new_app_rules = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, current_app_rules); 472 473 CFArrayRemoveValueAtIndex(new_app_rules, idx); 474 if (CFArrayGetCount(new_app_rules) > 0) { 475 CFDictionarySetValue(new_vpn_config, kSCPropNetVPNAppRules, new_app_rules); 476 } else { 477 CFDictionaryRemoveValue(new_vpn_config, kSCPropNetVPNAppRules); 478 } 479 480 SCNetworkInterfaceSetConfiguration(interface, new_vpn_config); 481 482 CFRelease(new_vpn_config); 483 CFRelease(new_app_rules); 484 485 return TRUE; 486 } else { 487 _SCErrorSet(kSCStatusFailed); 488 } 489 } else { 490 _SCErrorSet(kSCStatusNoKey); 491 } 492 } else { 493 _SCErrorSet(kSCStatusFailed); 494 } 495 496 return FALSE; 497} 498 499 500Boolean 501VPNServiceIsManagedAppVPN(VPNServiceRef service) 502{ 503 Boolean result = FALSE; 504 CFStringRef mc_external_id = SCNetworkServiceCopyExternalID(service, CFSTR("MCVPNUUID")); 505 if (isA_CFString(mc_external_id)) { 506 result = TRUE; 507 } 508 if (mc_external_id != NULL) { 509 CFRelease(mc_external_id); 510 } 511 return result; 512} 513