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