1/* 2 * Copyright (c) 2004-2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Modification History 26 * 27 * May 13, 2004 Allan Nathanson <ajn@apple.com> 28 * - initial revision 29 */ 30 31 32#include <CoreFoundation/CoreFoundation.h> 33#include <CoreFoundation/CFRuntime.h> 34#include <SystemConfiguration/SystemConfiguration.h> 35#include "SCNetworkConfigurationInternal.h" 36#include <SystemConfiguration/SCValidation.h> 37#include <SystemConfiguration/SCPrivate.h> 38 39#include <pthread.h> 40 41 42static CFStringRef __SCNetworkSetCopyDescription (CFTypeRef cf); 43static void __SCNetworkSetDeallocate (CFTypeRef cf); 44static Boolean __SCNetworkSetEqual (CFTypeRef cf1, CFTypeRef cf2); 45static CFHashCode __SCNetworkSetHash (CFTypeRef cf); 46 47 48static CFTypeID __kSCNetworkSetTypeID = _kCFRuntimeNotATypeID; 49 50 51static const CFRuntimeClass __SCNetworkSetClass = { 52 0, // version 53 "SCNetworkSet", // className 54 NULL, // init 55 NULL, // copy 56 __SCNetworkSetDeallocate, // dealloc 57 __SCNetworkSetEqual, // equal 58 __SCNetworkSetHash, // hash 59 NULL, // copyFormattingDesc 60 __SCNetworkSetCopyDescription // copyDebugDesc 61}; 62 63 64static pthread_once_t initialized = PTHREAD_ONCE_INIT; 65 66 67static CFStringRef 68__SCNetworkSetCopyDescription(CFTypeRef cf) 69{ 70 CFAllocatorRef allocator = CFGetAllocator(cf); 71 CFMutableStringRef result; 72 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf; 73 74 result = CFStringCreateMutable(allocator, 0); 75 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkSet %p [%p]> {"), cf, allocator); 76 CFStringAppendFormat(result, NULL, CFSTR("id = %@"), setPrivate->setID); 77 CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), setPrivate->prefs); 78 if (setPrivate->name != NULL) { 79 CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), setPrivate->name); 80 } 81 CFStringAppendFormat(result, NULL, CFSTR("}")); 82 83 return result; 84} 85 86 87static void 88__SCNetworkSetDeallocate(CFTypeRef cf) 89{ 90 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf; 91 92 /* release resources */ 93 94 CFRelease(setPrivate->setID); 95 CFRelease(setPrivate->prefs); 96 if (setPrivate->name != NULL) 97 CFRelease(setPrivate->name); 98 99 return; 100} 101 102 103static Boolean 104__SCNetworkSetEqual(CFTypeRef cf1, CFTypeRef cf2) 105{ 106 SCNetworkSetPrivateRef s1 = (SCNetworkSetPrivateRef)cf1; 107 SCNetworkSetPrivateRef s2 = (SCNetworkSetPrivateRef)cf2; 108 109 if (s1 == s2) 110 return TRUE; 111 112 if (s1->prefs != s2->prefs) 113 return FALSE; // if not the same prefs 114 115 if (!CFEqual(s1->setID, s2->setID)) 116 return FALSE; // if not the same set identifier 117 118 return TRUE; 119} 120 121 122static CFHashCode 123__SCNetworkSetHash(CFTypeRef cf) 124{ 125 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf; 126 127 return CFHash(setPrivate->setID); 128} 129 130 131static void 132__SCNetworkSetInitialize(void) 133{ 134 __kSCNetworkSetTypeID = _CFRuntimeRegisterClass(&__SCNetworkSetClass); 135 return; 136} 137 138 139static SCNetworkSetPrivateRef 140__SCNetworkSetCreatePrivate(CFAllocatorRef allocator, 141 SCPreferencesRef prefs, 142 CFStringRef setID) 143{ 144 SCNetworkSetPrivateRef setPrivate; 145 uint32_t size; 146 147 /* initialize runtime */ 148 pthread_once(&initialized, __SCNetworkSetInitialize); 149 150 /* allocate target */ 151 size = sizeof(SCNetworkSetPrivate) - sizeof(CFRuntimeBase); 152 setPrivate = (SCNetworkSetPrivateRef)_CFRuntimeCreateInstance(allocator, 153 __kSCNetworkSetTypeID, 154 size, 155 NULL); 156 if (setPrivate == NULL) { 157 return NULL; 158 } 159 160 setPrivate->setID = CFStringCreateCopy(NULL, setID); 161 setPrivate->prefs = CFRetain(prefs); 162 setPrivate->name = NULL; 163 setPrivate->established = FALSE; // "new" (not yet established) set 164 165 return setPrivate; 166} 167 168 169#pragma mark - 170 171 172static int 173_serviceOrder(SCNetworkServiceRef service) 174{ 175 SCNetworkInterfaceRef interface; 176 177 interface = SCNetworkServiceGetInterface(service); 178 if ((interface == NULL) || _SCNetworkServiceIsVPN(service)) { 179 return 100000; // if unknown or VPN interface, sort last 180 } 181 182 return __SCNetworkInterfaceOrder(interface); 183} 184 185 186static void 187_serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service) 188{ 189 CFIndex i; 190 CFIndex n; 191 CFMutableArrayRef newOrder; 192 CFArrayRef order; 193 CFStringRef serviceID; 194 CFIndex serviceOrder; 195 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 196 CFIndex slot; 197 198 order = SCNetworkSetGetServiceOrder(set); 199 if (order != NULL) { 200 newOrder = CFArrayCreateMutableCopy(NULL, 0, order); 201 } else { 202 newOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 203 } 204 assert(newOrder != NULL); 205 n = CFArrayGetCount(newOrder); 206 207 serviceID = SCNetworkServiceGetServiceID(service); 208 if (CFArrayContainsValue(newOrder, CFRangeMake(0, n), serviceID)) { 209 // if serviceID already present 210 goto done; 211 } 212 213 serviceOrder = _serviceOrder(service); 214 215 slot = 0; 216 for (i = 0; i < n; i++) { 217 int slotOrder; 218 SCNetworkServiceRef slotService; 219 CFStringRef slotServiceID; 220 221 slotServiceID = CFArrayGetValueAtIndex(newOrder, i); 222 if (!isA_CFString(slotServiceID)) { 223 // if bad prefs 224 continue; 225 } 226 227 slotService = SCNetworkServiceCopy(setPrivate->prefs, slotServiceID); 228 if (slotService == NULL) { 229 // if serviceID not valid 230 continue; 231 } 232 233 slotOrder = _serviceOrder(slotService); 234 if (serviceOrder >= slotOrder) { 235 // add the service *after* this one 236 slot = i + 1; 237 } 238 239 CFRelease(slotService); 240 } 241 242 CFArrayInsertValueAtIndex(newOrder, slot, serviceID); 243 (void) SCNetworkSetSetServiceOrder(set, newOrder); 244 245 done : 246 247 CFRelease(newOrder); 248 249 return; 250} 251 252 253static void 254_serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service) 255{ 256 CFMutableArrayRef newOrder; 257 CFArrayRef order; 258 CFStringRef serviceID; 259 260 order = SCNetworkSetGetServiceOrder(set); 261 if (order == NULL) { 262 return; 263 } 264 265 serviceID = SCNetworkServiceGetServiceID(service); 266 267 newOrder = CFArrayCreateMutableCopy(NULL, 0, order); 268 while (TRUE) { 269 CFIndex i; 270 271 i = CFArrayGetFirstIndexOfValue(newOrder, 272 CFRangeMake(0, CFArrayGetCount(newOrder)), 273 serviceID); 274 if (i == kCFNotFound) { 275 break; 276 } 277 278 CFArrayRemoveValueAtIndex(newOrder, i); 279 } 280 (void) SCNetworkSetSetServiceOrder(set, newOrder); 281 CFRelease(newOrder); 282 283 return; 284} 285 286 287#pragma mark - 288#pragma mark SCNetworkSet APIs 289 290 291#define N_QUICK 16 292 293 294#define PREVENT_DUPLICATE_SERVICE_NAMES 295#ifdef PREVENT_DUPLICATE_SERVICE_NAMES 296static CFStringRef 297copy_next_name(CFStringRef name) 298{ 299 CFArrayRef components; 300 CFIndex n; 301 CFMutableArrayRef newComponents; 302 SInt32 suffix = 2; 303 304 if (name == NULL) { 305 return NULL; 306 } 307 308 components = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR(" ")); 309 if (components != NULL) { 310 newComponents = CFArrayCreateMutableCopy(NULL, 0, components); 311 CFRelease(components); 312 } else { 313 newComponents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 314 CFArrayAppendValue(newComponents, name); 315 } 316 317 n = CFArrayGetCount(newComponents); 318 if (n > 1) { 319 CFStringRef str; 320 321 str = CFArrayGetValueAtIndex(newComponents, n - 1); 322 suffix = CFStringGetIntValue(str); 323 if (suffix++ > 0) { 324 CFArrayRemoveValueAtIndex(newComponents, n - 1); 325 } else { 326 suffix = 2; 327 } 328 } 329 330 name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), (int)suffix); 331 CFArrayAppendValue(newComponents, name); 332 CFRelease(name); 333 334 name = CFStringCreateByCombiningStrings(NULL, newComponents, CFSTR(" ")); 335 CFRelease(newComponents); 336 337 return name; 338} 339 340 341static Boolean 342ensure_unique_service_name(SCNetworkServiceRef service) 343{ 344 SCNetworkInterfaceRef interface; 345 CFStringRef name; 346 Boolean ok = TRUE; 347 348 interface = SCNetworkServiceGetInterface(service); 349 350 name = SCNetworkServiceGetName(service); 351 if (name != NULL) { 352 CFRetain(name); 353 } 354 355 while (TRUE) { 356 CFStringRef newName; 357 358 ok = SCNetworkServiceSetName(service, name); 359 if (ok) { 360 break; 361 } 362 363 if (SCError() != kSCStatusKeyExists) { 364 SCLog(TRUE, LOG_DEBUG, 365 CFSTR("could not update service name for \"%@\": %s"), 366 SCNetworkInterfaceGetLocalizedDisplayName(interface), 367 SCErrorString(SCError())); 368 break; 369 } 370 371 newName = copy_next_name(name); 372 if (newName == NULL) { 373 SCLog(TRUE, LOG_DEBUG, 374 CFSTR("could not create unique name for \"%@\": %s"), 375 SCNetworkInterfaceGetLocalizedDisplayName(interface), 376 SCErrorString(SCError())); 377 break; 378 } 379 380 // try again with the "new" name 381 if (name != NULL) { 382 CFRelease(name); 383 } 384 name = newName; 385 } 386 387 if (name != NULL) { 388 CFRelease(name); 389 } 390 391 return ok; 392} 393#endif // PREVENT_DUPLICATE_SERVICE_NAMES 394 395 396Boolean 397SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service) 398{ 399 SCNetworkInterfaceRef interface; 400 CFArrayRef interface_config = NULL; 401 CFStringRef link; 402 Boolean ok; 403 CFStringRef path; 404 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; 405 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 406 407 if (!isA_SCNetworkSet(set)) { 408 _SCErrorSet(kSCStatusInvalidArgument); 409 return FALSE; 410 } 411 412 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { 413 _SCErrorSet(kSCStatusInvalidArgument); 414 return FALSE; 415 } 416 417 // make sure that we do not add an orphaned network service if its 418 // associated interface is a member of a bond or bridge. 419 interface = SCNetworkServiceGetInterface(service); 420 if ((interface != NULL) && 421 __SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) { 422 _SCErrorSet(kSCStatusKeyExists); 423 return FALSE; 424 } 425 426//#define PREVENT_DUPLICATE_SETS 427#ifdef PREVENT_DUPLICATE_SETS 428 CFArrayRef sets; 429 430 // ensure that each service is only a member of ONE set 431 sets = SCNetworkSetCopyAll(setPrivate->prefs); 432 if (sets != NULL) { 433 CFIndex i; 434 CFIndex n; 435 436 n = CFArrayGetCount(sets); 437 for (i = 0; i < n; i++) { 438 Boolean found; 439 CFArrayRef services; 440 SCNetworkSetRef set; 441 442 set = CFArrayGetValueAtIndex(sets, i); 443 services = SCNetworkSetCopyServices(set); 444 found = CFArrayContainsValue(services, 445 CFRangeMake(0, CFArrayGetCount(services)), 446 service); 447 CFRelease(services); 448 449 if (found) { 450 CFRelease(sets); 451 _SCErrorSet(kSCStatusKeyExists); 452 return FALSE; 453 } 454 } 455 CFRelease(sets); 456 } 457#endif /* PREVENT_DUPLICATE_SETS */ 458 459 // get the [deep] interface configuration settings 460 interface = SCNetworkServiceGetInterface(service); 461 if (interface != NULL) { 462 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface); 463 } 464 465 // create the link between "set" and the "service" 466 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator 467 setPrivate->setID, // set 468 servicePrivate->serviceID, // service 469 NULL); // entity 470 link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator 471 servicePrivate->serviceID, // service 472 NULL); // entity 473 ok = SCPreferencesPathSetLink(setPrivate->prefs, path, link); 474#ifdef PREVENT_DUPLICATE_SERVICE_NAMES 475 if (ok) { 476 ok = ensure_unique_service_name(service); 477 if (!ok) { 478 // if we could not ensure a unique name, remove the (just added) 479 // link between the "set" and the "service" 480 (void) SCPreferencesPathRemoveValue(setPrivate->prefs, path); 481 } 482 } 483#endif // PREVENT_DUPLICATE_SERVICE_NAMES 484 CFRelease(path); 485 CFRelease(link); 486 if (!ok) { 487 goto done; 488 } 489 490 // push the [deep] interface configuration into all sets which contain this service. 491 if (interface != NULL) { 492 __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config); 493 } 494 495 // add service to ServiceOrder 496 _serviceOrder_add(set, service); 497 498 // mark set as no longer "new" 499 setPrivate->established = TRUE; 500 501 done : 502 503 if (interface_config != NULL) CFRelease(interface_config); 504 return ok; 505} 506 507 508SCNetworkSetRef 509SCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID) 510{ 511 CFDictionaryRef entity; 512 CFStringRef path; 513 SCNetworkSetPrivateRef setPrivate; 514 515 if (!isA_CFString(setID)) { 516 _SCErrorSet(kSCStatusInvalidArgument); 517 return NULL; 518 } 519 520 path = SCPreferencesPathKeyCreateSet(NULL, setID); 521 entity = SCPreferencesPathGetValue(prefs, path); 522 CFRelease(path); 523 524 if (!isA_CFDictionary(entity)) { 525 _SCErrorSet(kSCStatusNoKey); 526 return NULL; 527 } 528 529 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID); 530 assert(setPrivate != NULL); 531 532 // mark set as "old" (already established) 533 setPrivate->established = TRUE; 534 535 return (SCNetworkSetRef)setPrivate; 536} 537 538 539Boolean 540SCNetworkSetContainsInterface(SCNetworkSetRef set, SCNetworkInterfaceRef interface) 541{ 542 Boolean found = FALSE; 543 CFArrayRef services; 544 545 services = SCNetworkSetCopyServices(set); 546 if (services != NULL) { 547 found = __SCNetworkServiceExistsForInterface(services, interface); 548 CFRelease(services); 549 } 550 551 return found; 552} 553 554 555CFArrayRef /* of SCNetworkSetRef's */ 556SCNetworkSetCopyAll(SCPreferencesRef prefs) 557{ 558 CFMutableArrayRef array; 559 CFIndex n; 560 CFStringRef path; 561 CFDictionaryRef sets; 562 563 path = SCPreferencesPathKeyCreateSets(NULL); 564 sets = SCPreferencesPathGetValue(prefs, path); 565 CFRelease(path); 566 567 if ((sets != NULL) && !isA_CFDictionary(sets)) { 568 return NULL; 569 } 570 571 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 572 573 n = (sets != NULL) ? CFDictionaryGetCount(sets) : 0; 574 if (n > 0) { 575 CFIndex i; 576 const void * keys_q[N_QUICK]; 577 const void ** keys = keys_q; 578 const void * vals_q[N_QUICK]; 579 const void ** vals = vals_q; 580 581 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { 582 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); 583 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0); 584 } 585 CFDictionaryGetKeysAndValues(sets, keys, vals); 586 for (i = 0; i < n; i++) { 587 SCNetworkSetPrivateRef setPrivate; 588 589 if (!isA_CFDictionary(vals[i])) { 590 SCLog(TRUE, 591 LOG_INFO, 592 CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"), 593 keys[i]); 594 continue; 595 } 596 597 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, keys[i]); 598 assert(setPrivate != NULL); 599 600 // mark set as "old" (already established) 601 setPrivate->established = TRUE; 602 603 CFArrayAppendValue(array, (SCNetworkSetRef)setPrivate); 604 CFRelease(setPrivate); 605 } 606 if (keys != keys_q) { 607 CFAllocatorDeallocate(NULL, keys); 608 CFAllocatorDeallocate(NULL, vals); 609 } 610 } 611 612 return array; 613} 614 615 616CFArrayRef /* of SCNetworkInterfaceRef's */ 617SCNetworkSetCopyAvailableInterfaces(SCNetworkSetRef set) 618{ 619 CFMutableArrayRef available; 620 CFMutableSetRef excluded = NULL; 621 int i; 622 CFArrayRef interfaces; 623 CFIndex n_interfaces; 624 CFIndex n_exclusions = 0; 625 SCPreferencesRef prefs; 626 SCNetworkSetPrivateRef setPrivate; 627 628 setPrivate = (SCNetworkSetPrivateRef)set; 629 prefs = setPrivate->prefs; 630 631 interfaces = _SCNetworkInterfaceCopyAllWithPreferences(prefs); 632 n_interfaces = CFArrayGetCount(interfaces); 633 if (n_interfaces == 0) { 634 return interfaces; 635 } 636 637 if (prefs != NULL) { 638 CFArrayRef bridges = NULL; 639 640 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); 641 642#if !TARGET_OS_IPHONE 643 CFArrayRef bonds = NULL; 644 645 bonds = SCBondInterfaceCopyAll(prefs); 646 if (bonds != NULL) { 647 __SCBondInterfaceListCollectMembers(bonds, excluded); 648 CFRelease(bonds); 649 } 650#endif /* !TARGET_OS_IPHONE */ 651 652 bridges = SCBridgeInterfaceCopyAll(prefs); 653 if (bridges != NULL) { 654 __SCBridgeInterfaceListCollectMembers(bridges, excluded); 655 CFRelease(bridges); 656 } 657 658 n_exclusions = CFSetGetCount(excluded); 659 } 660 661 if (n_exclusions == 0) { 662 if (excluded != NULL) { 663 CFRelease(excluded); 664 } 665 666 return interfaces; 667 } 668 669 available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 670 671 for (i = 0; i < n_interfaces; i++) { 672 SCNetworkInterfaceRef interface; 673 674 interface = CFArrayGetValueAtIndex(interfaces, i); 675 if (CFSetContainsValue(excluded, interface)) { 676 // if excluded 677 continue; 678 } 679 680 CFArrayAppendValue(available, interface); 681 } 682 683 CFRelease(interfaces); 684 CFRelease(excluded); 685 686 return available; 687} 688 689 690SCNetworkSetRef 691SCNetworkSetCopyCurrent(SCPreferencesRef prefs) 692{ 693 CFArrayRef components; 694 CFStringRef currentID; 695 SCNetworkSetPrivateRef setPrivate = NULL; 696 697 currentID = SCPreferencesGetValue(prefs, kSCPrefCurrentSet); 698 if (!isA_CFString(currentID)) { 699 return NULL; 700 } 701 702 components = CFStringCreateArrayBySeparatingStrings(NULL, currentID, CFSTR("/")); 703 if (CFArrayGetCount(components) == 3) { 704 CFStringRef setID; 705 CFStringRef path; 706 707 setID = CFArrayGetValueAtIndex(components, 2); 708 path = SCPreferencesPathKeyCreateSet(NULL, setID); 709 if (CFEqual(path, currentID)) { 710 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID); 711 assert(setPrivate != NULL); 712 713 // mark set as "old" (already established) 714 setPrivate->established = TRUE; 715 } else { 716 SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant")); 717 } 718 CFRelease(path); 719 } 720 CFRelease(components); 721 722 return (SCNetworkSetRef)setPrivate; 723} 724 725 726CFArrayRef /* of SCNetworkServiceRef's */ 727SCNetworkSetCopyServices(SCNetworkSetRef set) 728{ 729 CFMutableArrayRef array; 730 CFDictionaryRef dict; 731 CFIndex n; 732 CFStringRef path; 733 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 734 735 if (!isA_SCNetworkSet(set)) { 736 _SCErrorSet(kSCStatusInvalidArgument); 737 return NULL; 738 } 739 740 path = SCPreferencesPathKeyCreateSetNetworkService(NULL, setPrivate->setID, NULL); 741 dict = SCPreferencesPathGetValue(setPrivate->prefs, path); 742 CFRelease(path); 743 if ((dict != NULL) && !isA_CFDictionary(dict)) { 744 return NULL; 745 } 746 747 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 748 749 n = (dict != NULL) ? CFDictionaryGetCount(dict) : 0; 750 if (n > 0) { 751 CFIndex i; 752 const void * keys_q[N_QUICK]; 753 const void ** keys = keys_q; 754 755 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { 756 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); 757 } 758 CFDictionaryGetKeysAndValues(dict, keys, NULL); 759 for (i = 0; i < n; i++) { 760 CFArrayRef components; 761 CFStringRef link; 762 763 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, 764 setPrivate->setID, 765 (CFStringRef)keys[i], 766 NULL); 767 link = SCPreferencesPathGetLink(setPrivate->prefs, path); 768 CFRelease(path); 769 if (link == NULL) { 770 SCLog(TRUE, 771 LOG_INFO, 772 CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"), 773 keys[i], 774 setPrivate->setID); 775 continue; // if the service is not a link 776 } 777 778 components = CFStringCreateArrayBySeparatingStrings(NULL, link, CFSTR("/")); 779 if (CFArrayGetCount(components) == 3) { 780 CFStringRef serviceID; 781 782 serviceID = CFArrayGetValueAtIndex(components, 2); 783 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator 784 serviceID, // service 785 NULL); // entity 786 if (CFEqual(path, link)) { 787 SCNetworkServicePrivateRef servicePrivate; 788 789 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, 790 setPrivate->prefs, 791 serviceID, 792 NULL); 793 CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate); 794 CFRelease(servicePrivate); 795 } 796 CFRelease(path); 797 } 798 CFRelease(components); 799 } 800 if (keys != keys_q) { 801 CFAllocatorDeallocate(NULL, keys); 802 } 803 } 804 805 return array; 806} 807 808 809SCNetworkSetRef 810SCNetworkSetCreate(SCPreferencesRef prefs) 811{ 812 CFArrayRef components; 813 CFDictionaryRef entity; 814 Boolean ok; 815 CFStringRef path; 816 CFStringRef prefix; 817 CFStringRef setID; 818 SCNetworkSetPrivateRef setPrivate; 819 820 prefix = SCPreferencesPathKeyCreateSets(NULL); 821 path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix); 822 if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix); 823 CFRelease(prefix); 824 if (path == NULL) { 825 return NULL; 826 } 827 828 components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/")); 829 setID = CFArrayGetValueAtIndex(components, 2); 830 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID); 831 assert(setPrivate != NULL); 832 CFRelease(components); 833 834 // mark set as "new" (not yet established) 835 setPrivate->established = FALSE; 836 837 // establish the set in the preferences 838 entity = CFDictionaryCreate(NULL, 839 NULL, NULL, 0, 840 &kCFTypeDictionaryKeyCallBacks, 841 &kCFTypeDictionaryValueCallBacks); 842 ok = SCPreferencesPathSetValue(prefs, path, entity); 843 CFRelease(path); 844 CFRelease(entity); 845 if (!ok) { 846 CFRelease(setPrivate); 847 setPrivate = NULL; 848 } 849 850 return (SCNetworkSetRef)setPrivate; 851} 852 853 854CFStringRef 855SCNetworkSetGetSetID(SCNetworkSetRef set) 856{ 857 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 858 859 if (!isA_SCNetworkSet(set)) { 860 _SCErrorSet(kSCStatusInvalidArgument); 861 return NULL; 862 } 863 864 return setPrivate->setID; 865} 866 867 868CFStringRef 869SCNetworkSetGetName(SCNetworkSetRef set) 870{ 871 CFBundleRef bundle; 872 CFDictionaryRef entity; 873 CFStringRef path; 874 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 875 876 if (!isA_SCNetworkSet(set)) { 877 _SCErrorSet(kSCStatusInvalidArgument); 878 return NULL; 879 } 880 881 if (setPrivate->name != NULL) { 882 return setPrivate->name; 883 } 884 885 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); 886 entity = SCPreferencesPathGetValue(setPrivate->prefs, path); 887 CFRelease(path); 888 889 if (isA_CFDictionary(entity)) { 890 CFStringRef name; 891 892 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName); 893 if (isA_CFString(name)) { 894 setPrivate->name = CFRetain(name); 895 } 896 } 897 898 bundle = _SC_CFBundleGet(); 899 if (bundle != NULL) { 900 if (setPrivate->name != NULL) { 901 CFStringRef non_localized; 902 903 non_localized = _SC_CFBundleCopyNonLocalizedString(bundle, 904 CFSTR("DEFAULT_SET_NAME"), 905 CFSTR("Automatic"), 906 NULL); 907 if (non_localized != NULL) { 908 if (CFEqual(setPrivate->name, non_localized)) { 909 CFStringRef localized; 910 911 // if "Automatic", return localized name 912 localized = CFBundleCopyLocalizedString(bundle, 913 CFSTR("DEFAULT_SET_NAME"), 914 CFSTR("Automatic"), 915 NULL); 916 if (localized != NULL) { 917 CFRelease(setPrivate->name); 918 setPrivate->name = localized; 919 } 920 } 921 922 CFRelease(non_localized); 923 } 924 } 925 } 926 927 return setPrivate->name; 928} 929 930 931CFArrayRef /* of serviceID CFStringRef's */ 932SCNetworkSetGetServiceOrder(SCNetworkSetRef set) 933{ 934 CFDictionaryRef dict; 935 CFStringRef path; 936 CFArrayRef serviceOrder; 937 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 938 939 if (!isA_SCNetworkSet(set)) { 940 _SCErrorSet(kSCStatusInvalidArgument); 941 return NULL; 942 } 943 944 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4); 945 if (path == NULL) { 946 return NULL; 947 } 948 949 dict = SCPreferencesPathGetValue(setPrivate->prefs, path); 950 CFRelease(path); 951 if (!isA_CFDictionary(dict)) { 952 return NULL; 953 } 954 955 serviceOrder = CFDictionaryGetValue(dict, kSCPropNetServiceOrder); 956 serviceOrder = isA_CFArray(serviceOrder); 957 958 return serviceOrder; 959} 960 961 962CFTypeID 963SCNetworkSetGetTypeID(void) 964{ 965 pthread_once(&initialized, __SCNetworkSetInitialize); /* initialize runtime */ 966 return __kSCNetworkSetTypeID; 967} 968 969 970Boolean 971SCNetworkSetRemove(SCNetworkSetRef set) 972{ 973 CFStringRef currentPath; 974 Boolean ok = FALSE; 975 CFStringRef path; 976 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 977 978 if (!isA_SCNetworkSet(set)) { 979 _SCErrorSet(kSCStatusInvalidArgument); 980 return FALSE; 981 } 982 983 currentPath = SCPreferencesGetValue(setPrivate->prefs, kSCPrefCurrentSet); 984 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); 985 if (!isA_CFString(currentPath) || !CFEqual(currentPath, path)) { 986 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path); 987 } else { 988 _SCErrorSet(kSCStatusInvalidArgument); 989 } 990 CFRelease(path); 991 992 return ok; 993} 994 995 996Boolean 997SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service) 998{ 999 SCNetworkInterfaceRef interface; 1000 CFArrayRef interface_config = NULL; 1001 Boolean ok; 1002 CFStringRef path; 1003 int sc_status = kSCStatusOK; 1004 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; 1005 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 1006 1007 if (!isA_SCNetworkSet(set)) { 1008 _SCErrorSet(kSCStatusInvalidArgument); 1009 return FALSE; 1010 } 1011 1012 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { 1013 _SCErrorSet(kSCStatusInvalidArgument); 1014 return FALSE; 1015 } 1016 1017 // remove service from ServiceOrder 1018 _serviceOrder_remove(set, service); 1019 1020 // get the [deep] interface configuration settings 1021 interface = SCNetworkServiceGetInterface(service); 1022 if (interface != NULL) { 1023 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface); 1024 if (interface_config != NULL) { 1025 // remove the interface configuration from all sets which contain this service. 1026 __SCNetworkInterfaceSetDeepConfiguration(set, interface, NULL); 1027 } 1028 } 1029 1030 // remove the link between "set" and the "service" 1031 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, 1032 setPrivate->setID, 1033 servicePrivate->serviceID, 1034 NULL); 1035 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path); 1036 if (!ok) { 1037 sc_status = SCError(); // preserve the error 1038 } 1039 CFRelease(path); 1040 1041 // push the [deep] interface configuration [back] into all sets which contain the service. 1042 if (interface_config != NULL) { 1043 __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config); 1044 } 1045 1046 if (interface_config != NULL) CFRelease(interface_config); 1047 if (!ok) { 1048 _SCErrorSet(sc_status); 1049 } 1050 return ok; 1051} 1052 1053 1054Boolean 1055SCNetworkSetSetCurrent(SCNetworkSetRef set) 1056{ 1057 Boolean ok; 1058 CFStringRef path; 1059 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 1060 1061 if (!isA_SCNetworkSet(set)) { 1062 _SCErrorSet(kSCStatusInvalidArgument); 1063 return FALSE; 1064 } 1065 1066 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); 1067 ok = SCPreferencesSetValue(setPrivate->prefs, kSCPrefCurrentSet, path); 1068 CFRelease(path); 1069 return ok; 1070} 1071 1072 1073Boolean 1074SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name) 1075{ 1076 CFBundleRef bundle = NULL; 1077 CFDictionaryRef entity; 1078 CFStringRef localized = NULL; 1079 CFStringRef non_localized = NULL; 1080 Boolean ok = FALSE; 1081 CFStringRef path; 1082 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 1083 1084 if (!isA_SCNetworkSet(set)) { 1085 _SCErrorSet(kSCStatusInvalidArgument); 1086 return FALSE; 1087 } 1088 1089 if ((name != NULL) && !isA_CFString(name)) { 1090 _SCErrorSet(kSCStatusInvalidArgument); 1091 return FALSE; 1092 } 1093 1094 // if known, compare against localized name 1095 1096 if (name != NULL) { 1097 bundle = _SC_CFBundleGet(); 1098 if (bundle != NULL) { 1099 non_localized = _SC_CFBundleCopyNonLocalizedString(bundle, 1100 CFSTR("DEFAULT_SET_NAME"), 1101 CFSTR("Automatic"), 1102 NULL); 1103 if (non_localized != NULL) { 1104 if (CFEqual(name, non_localized)) { 1105 localized = CFBundleCopyLocalizedString(bundle, 1106 CFSTR("DEFAULT_SET_NAME"), 1107 CFSTR("Automatic"), 1108 NULL); 1109 if (localized != NULL) { 1110 name = localized; 1111 } 1112 } 1113 } 1114 } 1115 } 1116 1117#define PREVENT_DUPLICATE_SET_NAMES 1118#ifdef PREVENT_DUPLICATE_SET_NAMES 1119 if (name != NULL) { 1120 CFArrayRef sets; 1121 1122 // ensure that each set is uniquely named 1123 1124 sets = SCNetworkSetCopyAll(setPrivate->prefs); 1125 if (sets != NULL) { 1126 CFIndex i; 1127 CFIndex n; 1128 1129 n = CFArrayGetCount(sets); 1130 for (i = 0; i < n; i++) { 1131 CFStringRef otherID; 1132 CFStringRef otherName; 1133 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, i); 1134 1135 otherID = SCNetworkSetGetSetID(set); 1136 if (CFEqual(setPrivate->setID, otherID)) { 1137 continue; // skip current set 1138 } 1139 1140 otherName = SCNetworkSetGetName(set); 1141 if ((otherName != NULL) && CFEqual(name, otherName)) { 1142 // if "name" not unique 1143 CFRelease(sets); 1144 _SCErrorSet(kSCStatusKeyExists); 1145 goto done; 1146 } 1147 } 1148 CFRelease(sets); 1149 } 1150 } 1151#endif /* PREVENT_DUPLICATE_SET_NAMES */ 1152 1153 // if known, store non-localized name 1154 1155 if ((name != NULL) && (bundle != NULL) && (non_localized != NULL)) { 1156 if (localized == NULL) { 1157 localized = CFBundleCopyLocalizedString(bundle, 1158 CFSTR("DEFAULT_SET_NAME"), 1159 CFSTR("Automatic"), 1160 NULL); 1161 } 1162 1163 if (localized != NULL) { 1164 if (CFEqual(name, localized)) { 1165 name = non_localized; 1166 } 1167 } 1168 } 1169 1170 // update the "name" 1171 1172 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); 1173 entity = SCPreferencesPathGetValue(setPrivate->prefs, path); 1174 if (isA_CFDictionary(entity) || 1175 ((entity == NULL) && (name != NULL))) { 1176 CFMutableDictionaryRef newEntity; 1177 1178 if (entity != NULL) { 1179 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity); 1180 } else { 1181 newEntity = CFDictionaryCreateMutable(NULL, 1182 0, 1183 &kCFTypeDictionaryKeyCallBacks, 1184 &kCFTypeDictionaryValueCallBacks); 1185 } 1186 if (name != NULL) { 1187 CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name); 1188 } else { 1189 CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName); 1190 } 1191 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newEntity); 1192 CFRelease(newEntity); 1193 } 1194 CFRelease(path); 1195 1196 done : 1197 1198 if (localized != NULL) CFRelease(localized); 1199 if (non_localized != NULL) CFRelease(non_localized); 1200 return ok; 1201} 1202 1203 1204Boolean 1205SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder) 1206{ 1207 CFDictionaryRef dict; 1208 CFMutableDictionaryRef newDict; 1209 Boolean ok; 1210 CFStringRef path; 1211 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 1212 1213 if (!isA_SCNetworkSet(set)) { 1214 _SCErrorSet(kSCStatusInvalidArgument); 1215 return FALSE; 1216 } 1217 1218 if (isA_CFArray(newOrder)) { 1219 CFIndex i; 1220 CFIndex n = CFArrayGetCount(newOrder); 1221 1222 for (i = 0; i < n; i++) { 1223 CFStringRef serviceID; 1224 1225 serviceID = CFArrayGetValueAtIndex(newOrder, i); 1226 if (!isA_CFString(serviceID)) { 1227 _SCErrorSet(kSCStatusInvalidArgument); 1228 return FALSE; 1229 } 1230 } 1231 } else { 1232 _SCErrorSet(kSCStatusInvalidArgument); 1233 return FALSE; 1234 } 1235 1236 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4); 1237 if (path == NULL) { 1238 return FALSE; 1239 } 1240 1241 dict = SCPreferencesPathGetValue(setPrivate->prefs, path); 1242 if (dict != NULL) { 1243 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); 1244 } else { 1245 newDict = CFDictionaryCreateMutable(NULL, 1246 0, 1247 &kCFTypeDictionaryKeyCallBacks, 1248 &kCFTypeDictionaryValueCallBacks); 1249 } 1250 1251 CFDictionarySetValue(newDict, kSCPropNetServiceOrder, newOrder); 1252 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newDict); 1253 CFRelease(newDict); 1254 CFRelease(path); 1255 1256 return ok; 1257} 1258 1259 1260#pragma mark - 1261#pragma mark SCNetworkSet SPIs 1262 1263 1264static void 1265add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface) 1266{ 1267 CFIndex i; 1268 CFArrayRef interface_types; 1269 CFIndex n; 1270 1271 interface_types = SCNetworkInterfaceGetSupportedInterfaceTypes(interface); 1272 n = (interface_types != NULL) ? CFArrayGetCount(interface_types) : 0; 1273 for (i = 0; i < n; i++) { 1274 SCNetworkInterfaceRef parent; 1275 CFStringRef interface_type; 1276 1277 interface_type = CFArrayGetValueAtIndex(interface_types, i); 1278 parent = SCNetworkInterfaceCreateWithInterface(interface, interface_type); 1279 if (parent != NULL) { 1280 CFArrayAppendValue(interface_list, parent); 1281 CFRelease(parent); 1282 } 1283 } 1284 1285 return; 1286} 1287 1288 1289static CFSetRef /* of SCNetworkInterfaceRef's */ 1290copyExcludedInterfaces(SCPreferencesRef prefs) 1291{ 1292 CFMutableSetRef excluded; 1293 CFArrayRef interfaces; 1294 1295 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); 1296 1297#if !TARGET_OS_IPHONE 1298 // exclude Bond [member] interfaces 1299 interfaces = SCBondInterfaceCopyAll(prefs); 1300 if (interfaces != NULL) { 1301 __SCBondInterfaceListCollectMembers(interfaces, excluded); 1302 CFRelease(interfaces); 1303 } 1304#endif // !TARGET_OS_IPHONE 1305 1306 // exclude Bridge [member] interfaces 1307 interfaces = SCBridgeInterfaceCopyAll(prefs); 1308 if (interfaces != NULL) { 1309 __SCBridgeInterfaceListCollectMembers(interfaces, excluded); 1310 CFRelease(interfaces); 1311 } 1312 1313 return excluded; 1314} 1315 1316 1317#if !TARGET_OS_IPHONE 1318static SCBridgeInterfaceRef 1319copyAutoBridgeInterface(SCPreferencesRef prefs, CFStringRef bridgeName) 1320{ 1321 SCBridgeInterfaceRef bridge = NULL; 1322 CFArrayRef interfaces; 1323 1324 // exclude Bridge [member] interfaces 1325 interfaces = SCBridgeInterfaceCopyAll(prefs); 1326 if (interfaces != NULL) { 1327 CFIndex i; 1328 CFIndex n; 1329 1330 n = CFArrayGetCount(interfaces); 1331 for (i = 0; i < n; i++) { 1332 SCBridgeInterfaceRef interface; 1333 CFStringRef name = NULL; 1334 CFDictionaryRef options; 1335 1336 interface = CFArrayGetValueAtIndex(interfaces, i); 1337 options = SCBridgeInterfaceGetOptions(interface); 1338 if ((options != NULL) && 1339 CFDictionaryGetValueIfPresent(options, 1340 CFSTR("__AUTO__"), 1341 (const void **)&name) && 1342 _SC_CFEqual(name, bridgeName)) { 1343 bridge = interface; 1344 CFRetain(bridge); 1345 break; 1346 } 1347 } 1348 1349 CFRelease(interfaces); 1350 } 1351 1352 if (bridge == NULL) { 1353 bridge = SCBridgeInterfaceCreate(prefs); 1354 if (bridge != NULL) { 1355 CFMutableDictionaryRef newOptions; 1356 Boolean ok; 1357 1358 newOptions = CFDictionaryCreateMutable(NULL, 0, 1359 &kCFTypeDictionaryKeyCallBacks, 1360 &kCFTypeDictionaryValueCallBacks); 1361 CFDictionarySetValue(newOptions, CFSTR("__AUTO__"), bridgeName); 1362 ok = SCBridgeInterfaceSetOptions(bridge, newOptions); 1363 CFRelease(newOptions); 1364 if (!ok) { 1365 CFRelease(bridge); 1366 bridge = NULL; 1367 } 1368 } 1369 } 1370 1371 return bridge; 1372} 1373#endif // !TARGET_OS_IPHONE 1374 1375 1376static CFArrayRef 1377copyServices(SCNetworkSetRef set) 1378{ 1379 CFArrayRef services; 1380 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 1381 1382 // first, assume that we only want to add new services 1383 // for those interfaces that are not represented in the 1384 // current set. 1385 services = SCNetworkSetCopyServices(set); 1386 if ((services != NULL) && setPrivate->established) { 1387 // but, if we are given an existing (or "established") set 1388 // than we only want to add new services for those interfaces 1389 // that are not represented in *any* set. 1390 CFRelease(services); 1391 services = SCNetworkServiceCopyAll(setPrivate->prefs); 1392 } 1393 1394 return services; 1395} 1396 1397 1398#if !TARGET_OS_IPHONE 1399static CFArrayRef 1400updateServices(CFArrayRef services, SCNetworkInterfaceRef interface) 1401{ 1402 CFStringRef bsdName; 1403 CFIndex i; 1404 CFIndex n; 1405 CFMutableArrayRef newServices; 1406 1407 if (services == NULL) { 1408 return NULL; 1409 } 1410 1411 bsdName = SCNetworkInterfaceGetBSDName(interface); 1412 1413 newServices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1414 1415 n = CFArrayGetCount(services); 1416 for (i = 0; i < n; i++) { 1417 SCNetworkInterfaceRef interface; 1418 CFStringRef interfaceName; 1419 SCNetworkServiceRef newService; 1420 SCNetworkServiceRef service; 1421 CFStringRef serviceID; 1422 SCNetworkServicePrivateRef servicePrivate; 1423 1424 service = CFArrayGetValueAtIndex(services, i); 1425 interface = SCNetworkServiceGetInterface(service); 1426 interfaceName = SCNetworkInterfaceGetBSDName(interface); 1427 if (!_SC_CFEqual(interfaceName, bsdName)) { 1428 // if not a match, retain 1429 CFArrayAppendValue(newServices, service); 1430 continue; 1431 } 1432 1433 // if a match, update 1434 serviceID = SCNetworkServiceGetServiceID(service); 1435 servicePrivate = (SCNetworkServicePrivateRef)service; 1436 newService = SCNetworkServiceCopy(servicePrivate->prefs, serviceID); 1437 if (newService != NULL) { 1438 CFArrayAppendValue(newServices, newService); 1439 CFRelease(newService); 1440 } 1441 } 1442 1443 return newServices; 1444} 1445#endif // !TARGET_OS_IPHONE 1446 1447 1448static __inline__ Boolean 1449skipInterface(SCNetworkInterfaceRef interface) 1450{ 1451 CFStringRef action; 1452 1453 action = _SCNetworkInterfaceGetConfigurationAction(interface); 1454 if (isA_CFString(action) && 1455 CFEqual(action, kSCNetworkInterfaceConfigurationActionValueNone)) { 1456 return TRUE; 1457 } 1458 1459 return FALSE; 1460} 1461 1462 1463static Boolean 1464__SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces, Boolean excludeHidden) 1465{ 1466 CFSetRef excluded = NULL; 1467 CFIndex i; 1468 CFIndex n = 0; 1469 Boolean ok = TRUE; 1470 CFArrayRef services; 1471 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 1472 Boolean updated = FALSE; 1473 Boolean updatedIFs = FALSE; 1474 1475#if TARGET_OS_IPHONE 1476 CFArrayRef orphans = NULL; 1477 CFArrayRef sets; 1478 1479 sets = SCNetworkSetCopyAll(setPrivate->prefs); 1480 if (sets != NULL) { 1481 if (CFArrayGetCount(sets) == 1) { 1482 services = SCNetworkSetCopyServices(set); 1483 if (services != NULL) { 1484 n = CFArrayGetCount(services); 1485 CFRelease(services); 1486 } 1487 1488 if ((n == 0) && CFEqual(set, CFArrayGetValueAtIndex(sets, 0))) { 1489 // after a "Reset Network Settings" we need to find (and 1490 // add back) any VPN services that were orphaned. 1491 orphans = SCNetworkServiceCopyAll(setPrivate->prefs); 1492 } 1493 } 1494 1495 CFRelease(sets); 1496 } 1497#endif // TARGET_OS_IPHONE 1498 1499 // copy network services 1500 services = copyServices(set); 1501 1502 // copy network interfaces to be excluded 1503 excluded = copyExcludedInterfaces(setPrivate->prefs); 1504 1505#if !TARGET_OS_IPHONE 1506 // look for interfaces that should auto-magically be added 1507 // to an Ethernet bridge 1508 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0; 1509 for (i = 0; i < n; i++) { 1510 SCBridgeInterfaceRef bridge = NULL; 1511 SCNetworkInterfaceRef interface; 1512 1513 interface = CFArrayGetValueAtIndex(interfaces, i); 1514 1515 if (excludeHidden && skipInterface(interface)) { 1516 // if not auto-configure 1517 continue; 1518 } 1519 1520 if ((excluded != NULL) 1521 && CFSetContainsValue(excluded, interface)) { 1522 // if this interface is a member of a Bond or Bridge 1523 continue; 1524 } 1525 1526 if (__SCNetworkServiceExistsForInterface(services, interface)) { 1527 // if this is not a new interface 1528 continue; 1529 } 1530 1531 if (_SCNetworkInterfaceIsBuiltin(interface) && 1532 _SCNetworkInterfaceIsThunderbolt(interface) && 1533 !isA_SCBridgeInterface(interface)) { 1534 // add built-in Thunderbolt interfaces to bridge 1535 bridge = copyAutoBridgeInterface(setPrivate->prefs, CFSTR("thunderbolt-bridge")); 1536 } 1537 1538 if (bridge != NULL) { 1539 CFIndex bridgeIndex; 1540 CFArrayRef members; 1541 CFMutableArrayRef newMembers; 1542 CFMutableSetRef newExcluded; 1543 CFMutableArrayRef newInterfaces; 1544 CFArrayRef newServices; 1545 1546 // track the bridge interface (if it's in our list) 1547 bridgeIndex = CFArrayGetFirstIndexOfValue(interfaces, 1548 CFRangeMake(0, CFArrayGetCount(interfaces)), 1549 bridge); 1550 1551 // add new member interface 1552 members = SCBridgeInterfaceGetMemberInterfaces(bridge); 1553 if ((members != NULL) && (CFArrayGetCount(members) > 0)) { 1554 newMembers = CFArrayCreateMutableCopy(NULL, 0, members); 1555 updated = TRUE; // if we're updating an existing bridge 1556 } else { 1557 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1558 } 1559 CFArrayAppendValue(newMembers, interface); 1560 ok = SCBridgeInterfaceSetMemberInterfaces(bridge, newMembers); 1561 CFRelease(newMembers); 1562 if (!ok) { 1563 SCLog(TRUE, LOG_DEBUG, 1564 CFSTR("could not update bridge with \"%@\": %s\n"), 1565 SCNetworkInterfaceGetLocalizedDisplayName(interface), 1566 SCErrorString(SCError())); 1567 CFRelease(bridge); 1568 continue; 1569 } 1570 1571 // exclude the new member interface 1572 newExcluded = CFSetCreateMutableCopy(NULL, 0, excluded); 1573 CFRelease(excluded); 1574 CFSetAddValue(newExcluded, interface); 1575 excluded = newExcluded; 1576 1577 // update the list of interfaces to include the [new or updated] bridge 1578 newInterfaces = CFArrayCreateMutableCopy(NULL, 0, interfaces); 1579 if (bridgeIndex != kCFNotFound) { 1580 CFArraySetValueAtIndex(newInterfaces, bridgeIndex, bridge); 1581 } else { 1582 CFArrayAppendValue(newInterfaces, bridge); 1583 } 1584 if (updatedIFs) { 1585 CFRelease(interfaces); 1586 } 1587 interfaces = newInterfaces; 1588 updatedIFs = TRUE; 1589 1590 // refresh [existing] services 1591 newServices = updateServices(services, bridge); 1592 if (newServices != NULL) { 1593 CFRelease(services); 1594 services = newServices; 1595 } 1596 1597 CFRelease(bridge); 1598 } 1599 } 1600#endif // !TARGET_OS_IPHONE 1601 1602 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0; 1603 for (i = 0; i < n; i++) { 1604 SCNetworkInterfaceRef interface; 1605 CFMutableArrayRef interface_list; 1606 1607 interface = CFArrayGetValueAtIndex(interfaces, i); 1608 1609 if (excludeHidden && skipInterface(interface)) { 1610 // if not auto-configure 1611 continue; 1612 } 1613 1614 if ((excluded != NULL) 1615 && CFSetContainsValue(excluded, interface)) { 1616 // if this interface is a member of a Bond or Bridge 1617 continue; 1618 } 1619 1620 if (__SCNetworkServiceExistsForInterface(services, interface)) { 1621 // if this is not a new interface 1622 continue; 1623 } 1624 1625 interface_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1626 CFArrayAppendValue(interface_list, interface); 1627 1628 while (ok && (CFArrayGetCount(interface_list) > 0)) { 1629 CFArrayRef protocol_types; 1630 1631 interface = CFArrayGetValueAtIndex(interface_list, 0); 1632 1633 protocol_types = SCNetworkInterfaceGetSupportedProtocolTypes(interface); 1634 if ((protocol_types != NULL) && (CFArrayGetCount(protocol_types) > 0)) { 1635 SCNetworkServiceRef service; 1636 1637 service = SCNetworkServiceCreate(setPrivate->prefs, interface); 1638 if (service == NULL) { 1639 SCLog(TRUE, LOG_DEBUG, 1640 CFSTR("could not create service for \"%@\": %s\n"), 1641 SCNetworkInterfaceGetLocalizedDisplayName(interface), 1642 SCErrorString(SCError())); 1643 ok = FALSE; 1644 goto nextInterface; 1645 } 1646 1647 ok = SCNetworkServiceEstablishDefaultConfiguration(service); 1648 if (!ok) { 1649 SCLog(TRUE, LOG_DEBUG, 1650 CFSTR("could not estabish default configuration for \"%@\": %s\n"), 1651 SCNetworkInterfaceGetLocalizedDisplayName(interface), 1652 SCErrorString(SCError())); 1653 SCNetworkServiceRemove(service); 1654 CFRelease(service); 1655 goto nextInterface; 1656 } 1657 1658 ok = SCNetworkSetAddService(set, service); 1659 if (!ok) { 1660 SCLog(TRUE, LOG_DEBUG, 1661 CFSTR("could not add service for \"%@\": %s\n"), 1662 SCNetworkInterfaceGetLocalizedDisplayName(interface), 1663 SCErrorString(SCError())); 1664 SCNetworkServiceRemove(service); 1665 CFRelease(service); 1666 goto nextInterface; 1667 } 1668 1669 CFRelease(service); 1670 updated = TRUE; 1671 } else { 1672 add_supported_interfaces(interface_list, interface); 1673 } 1674 1675 nextInterface : 1676 1677 CFArrayRemoveValueAtIndex(interface_list, 0); 1678 } 1679 CFRelease(interface_list); 1680 } 1681 if (updatedIFs) CFRelease(interfaces); 1682 if (services != NULL) CFRelease(services); 1683 if (excluded != NULL) CFRelease(excluded); 1684 1685#if TARGET_OS_IPHONE 1686 if (orphans != NULL) { 1687 if (ok && updated) { 1688 CFIndex i; 1689 CFIndex n = CFArrayGetCount(orphans); 1690 1691 for (i = 0; i < n; i++) { 1692 SCNetworkServiceRef service; 1693 1694 service = CFArrayGetValueAtIndex(orphans, i); 1695 if (_SCNetworkServiceIsVPN(service)) { 1696 ok = SCNetworkSetAddService(set, service); 1697 if (!ok) { 1698 break; 1699 } 1700 } 1701 } 1702 } 1703 1704 CFRelease(orphans); 1705 } 1706#endif // TARGET_OS_IPHONE 1707 1708 if (ok && !updated) { 1709 // if no changes were made 1710 _SCErrorSet(kSCStatusOK); 1711 } 1712 1713 return updated; 1714} 1715 1716 1717Boolean 1718SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set) 1719{ 1720 CFArrayRef interfaces; 1721 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 1722 Boolean updated = FALSE; 1723 1724 if (!isA_SCNetworkSet(set)) { 1725 _SCErrorSet(kSCStatusInvalidArgument); 1726 return FALSE; 1727 } 1728 1729 interfaces = _SCNetworkInterfaceCopyAllWithPreferences(setPrivate->prefs); 1730 if (interfaces != NULL) { 1731 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, TRUE); 1732 CFRelease(interfaces); 1733 } 1734 1735 return updated; 1736} 1737 1738 1739Boolean 1740SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface) 1741{ 1742 CFArrayRef interfaces; 1743 Boolean updated; 1744 1745 if (!isA_SCNetworkSet(set)) { 1746 _SCErrorSet(kSCStatusInvalidArgument); 1747 return FALSE; 1748 } 1749 1750 if (!isA_SCNetworkInterface(interface)) { 1751 _SCErrorSet(kSCStatusInvalidArgument); 1752 return FALSE; 1753 } 1754 1755 interfaces = CFArrayCreate(NULL, (const void **)&interface, 1, &kCFTypeArrayCallBacks); 1756 assert(interfaces != NULL); 1757 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, FALSE); 1758 CFRelease(interfaces); 1759 1760 return updated; 1761} 1762 1763 1764SCNetworkServiceRef 1765SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set) 1766{ 1767 CFIndex i; 1768 CFIndex n; 1769 SCNetworkServiceRef selected = NULL; 1770 CFArrayRef services; 1771 CFMutableArrayRef services_vpn = NULL; 1772 1773 if (!isA_SCNetworkSet(set)) { 1774 _SCErrorSet(kSCStatusInvalidArgument); 1775 return NULL; 1776 } 1777 1778 services = SCNetworkSetCopyServices(set); 1779 if (services != NULL) { 1780 n = CFArrayGetCount(services); 1781 for (i = 0; i < n; i++) { 1782 SCNetworkServiceRef service; 1783 1784 service = CFArrayGetValueAtIndex(services, i); 1785 if (!SCNetworkServiceGetEnabled(service)) { 1786 // if not enabled 1787 continue; 1788 } 1789 1790 if (!_SCNetworkServiceIsVPN(service)) { 1791 // if not VPN service 1792 continue; 1793 } 1794 1795 if (services_vpn == NULL) { 1796 services_vpn = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1797 } 1798 CFArrayAppendValue(services_vpn, service); 1799 } 1800 1801 CFRelease(services); 1802 } 1803 1804 if (services_vpn == NULL) { 1805 // if no VPN services 1806 return NULL; 1807 } 1808 1809 n = CFArrayGetCount(services_vpn); 1810 if (n > 1) { 1811 CFArrayRef order; 1812 CFMutableArrayRef sorted; 1813 1814 order = SCNetworkSetGetServiceOrder(set); 1815 sorted = CFArrayCreateMutableCopy(NULL, 0, services_vpn); 1816 CFArraySortValues(sorted, 1817 CFRangeMake(0, CFArrayGetCount(sorted)), 1818 _SCNetworkServiceCompare, 1819 (void *)order); 1820 CFRelease(services_vpn); 1821 services_vpn = sorted; 1822 } 1823 1824#if TARGET_OS_IPHONE 1825 if (n > 1) { 1826 CFStringRef serviceID_prefs; 1827 1828#define VPN_PREFERENCES CFSTR("com.apple.mobilevpn") 1829#define VPN_SERVICE_ID CFSTR("activeVPNID") 1830 1831 CFPreferencesAppSynchronize(VPN_PREFERENCES); 1832 serviceID_prefs = CFPreferencesCopyAppValue(VPN_SERVICE_ID, VPN_PREFERENCES); 1833 if (serviceID_prefs != NULL) { 1834 for (i = 0; i < n; i++) { 1835 SCNetworkServiceRef service; 1836 CFStringRef serviceID; 1837 1838 service = CFArrayGetValueAtIndex(services_vpn, i); 1839 serviceID = SCNetworkServiceGetServiceID(service); 1840 if (CFEqual(serviceID, serviceID_prefs)) { 1841 selected = service; 1842 CFRetain(selected); 1843 break; 1844 } 1845 1846 } 1847 1848 CFRelease(serviceID_prefs); 1849 } 1850 } 1851#endif // TARGET_OS_IPHONE 1852 1853 if (selected == NULL) { 1854 selected = CFArrayGetValueAtIndex(services_vpn, 0); 1855 CFRetain(selected); 1856 } 1857 1858 CFRelease(services_vpn); 1859 return selected; 1860} 1861 1862 1863Boolean 1864SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set, SCNetworkServiceRef service) 1865{ 1866 Boolean ok = TRUE; 1867 CFArrayRef services; 1868 1869 if (!isA_SCNetworkSet(set)) { 1870 _SCErrorSet(kSCStatusInvalidArgument); 1871 return FALSE; 1872 } 1873 1874 if (!isA_SCNetworkService(service) || !_SCNetworkServiceIsVPN(service)) { 1875 _SCErrorSet(kSCStatusInvalidArgument); 1876 return FALSE; 1877 } 1878 1879 services = SCNetworkSetCopyServices(set); 1880 if (services != NULL) { 1881 CFIndex i; 1882 CFIndex n = CFArrayGetCount(services); 1883 1884 if (!CFArrayContainsValue(services, CFRangeMake(0, n), service)) { 1885 // if selected service not a member of the current set 1886 _SCErrorSet(kSCStatusInvalidArgument); 1887 ok = FALSE; 1888 goto done; 1889 } 1890 1891 for (i = 0; ok && (i < n); i++) { 1892 SCNetworkServiceRef vpn; 1893 1894 vpn = CFArrayGetValueAtIndex(services, i); 1895 if (!_SCNetworkServiceIsVPN(vpn)) { 1896 // if not VPN service 1897 continue; 1898 } 1899 1900 ok = SCNetworkServiceSetEnabled(vpn, CFEqual(service, vpn)); 1901 } 1902 } 1903 1904 done : 1905 1906 if (services != NULL) CFRelease(services); 1907 return ok; 1908} 1909 1910 1911Boolean 1912_SCNetworkSetSetSetID(SCNetworkSetRef set, CFStringRef newSetID) 1913{ 1914 SCNetworkSetRef currentSet = NULL; 1915 SCNetworkSetPrivateRef currentSetPrivate = NULL; 1916 CFDictionaryRef entity; 1917 CFStringRef newPath; 1918 Boolean ok = FALSE; 1919 CFStringRef oldPath = NULL; 1920 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; 1921 Boolean updateCurrentSet = FALSE; 1922 1923 if (!isA_SCNetworkSet(set)) { 1924 _SCErrorSet(kSCStatusInvalidArgument); 1925 return FALSE; 1926 } 1927 1928 if (!isA_CFString(newSetID)) { 1929 _SCErrorSet(kSCStatusInvalidArgument); 1930 return FALSE; 1931 } 1932 1933 // If newSetID is equal to current setID, our work is done 1934 if (CFEqual(newSetID, setPrivate->setID)) { 1935 return TRUE; 1936 } 1937 1938 newPath = SCPreferencesPathKeyCreateSet(NULL, newSetID); 1939 entity = SCPreferencesPathGetValue(setPrivate->prefs, newPath); 1940 if (isA_CFDictionary(entity)) { 1941 // if the new set already exists 1942 _SCErrorSet(kSCStatusKeyExists); 1943 goto done; 1944 } 1945 1946 oldPath = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); 1947 entity = SCPreferencesPathGetValue(setPrivate->prefs, oldPath); 1948 if (!isA_CFDictionary(entity)) { 1949 // if the set has already been removed 1950 _SCErrorSet(kSCStatusNoKey); 1951 goto done; 1952 } 1953 1954 ok = SCPreferencesPathSetValue(setPrivate->prefs, newPath, entity); 1955 if (!ok) { 1956 goto done; 1957 } 1958 1959 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, oldPath); 1960 if (!ok) { 1961 goto done; 1962 } 1963 1964 // update current set (if needed) 1965 currentSet = SCNetworkSetCopyCurrent(setPrivate->prefs); 1966 if (currentSet != NULL) { 1967 currentSetPrivate = (SCNetworkSetPrivateRef)currentSet; 1968 if (CFEqual(currentSetPrivate->setID, setPrivate->setID)) { 1969 updateCurrentSet = TRUE; 1970 } 1971 CFRelease(currentSet); 1972 } 1973 1974 CFRetain(newSetID); 1975 CFRelease(setPrivate->setID); 1976 1977 setPrivate->setID = newSetID; 1978 1979 if (updateCurrentSet) { 1980 SCNetworkSetSetCurrent(set); 1981 } 1982 1983 done: 1984 1985 if (oldPath != NULL) { 1986 CFRelease(oldPath); 1987 } 1988 if (newPath != NULL) { 1989 CFRelease(newPath); 1990 } 1991 1992 return ok; 1993} 1994