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