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