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