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