]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkSet.c
configd-1061.120.2.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkSet.c
1 /*
2 * Copyright (c) 2004-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * May 13, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFRuntime.h>
34 #include "SCNetworkConfigurationInternal.h"
35
36 #include <pthread.h>
37
38
39 static CFStringRef __SCNetworkSetCopyDescription (CFTypeRef cf);
40 static void __SCNetworkSetDeallocate (CFTypeRef cf);
41 static Boolean __SCNetworkSetEqual (CFTypeRef cf1, CFTypeRef cf2);
42 static CFHashCode __SCNetworkSetHash (CFTypeRef cf);
43
44
45 static CFTypeID __kSCNetworkSetTypeID = _kCFRuntimeNotATypeID;
46
47
48 static const CFRuntimeClass __SCNetworkSetClass = {
49 0, // version
50 "SCNetworkSet", // className
51 NULL, // init
52 NULL, // copy
53 __SCNetworkSetDeallocate, // dealloc
54 __SCNetworkSetEqual, // equal
55 __SCNetworkSetHash, // hash
56 NULL, // copyFormattingDesc
57 __SCNetworkSetCopyDescription // copyDebugDesc
58 };
59
60
61 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
62
63
64 static CFStringRef
65 __SCNetworkSetCopyDescription(CFTypeRef cf)
66 {
67 CFAllocatorRef allocator = CFGetAllocator(cf);
68 CFMutableStringRef result;
69 SCNetworkSetRef set = (SCNetworkSetRef)cf;
70 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
71
72 result = CFStringCreateMutable(allocator, 0);
73 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkSet %p [%p]> {"), set, allocator);
74 CFStringAppendFormat(result, NULL, CFSTR("id = %@"), setPrivate->setID);
75 CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), setPrivate->prefs);
76 if (setPrivate->name != NULL) {
77 CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), setPrivate->name);
78 }
79 if (!__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 path = SCPreferencesPathKeyCreateSetNetworkService(NULL, setPrivate->setID, NULL);
832 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
833 CFRelease(path);
834 if ((dict != NULL) && !isA_CFDictionary(dict)) {
835 return NULL;
836 }
837
838 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
839
840 n = (dict != NULL) ? CFDictionaryGetCount(dict) : 0;
841 if (n > 0) {
842 CFIndex i;
843 const void * keys_q[N_QUICK];
844 const void ** keys = keys_q;
845
846 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
847 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
848 }
849 CFDictionaryGetKeysAndValues(dict, keys, NULL);
850 for (i = 0; i < n; i++) {
851 CFArrayRef components;
852 CFStringRef link;
853
854 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
855 setPrivate->setID,
856 (CFStringRef)keys[i],
857 NULL);
858 link = SCPreferencesPathGetLink(setPrivate->prefs, path);
859 CFRelease(path);
860 if (link == NULL) {
861 SC_log(LOG_INFO, "service \"%@\" for set \"%@\" is not a link",
862 keys[i],
863 setPrivate->setID);
864 continue; // if the service is not a link
865 }
866
867 components = CFStringCreateArrayBySeparatingStrings(NULL, link, CFSTR("/"));
868 if (CFArrayGetCount(components) == 3) {
869 CFStringRef serviceID;
870
871 serviceID = CFArrayGetValueAtIndex(components, 2);
872 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
873 serviceID, // service
874 NULL); // entity
875 if (CFEqual(path, link)) {
876 CFDictionaryRef entity;
877 CFStringRef interfacePath;
878 Boolean skip = FALSE;
879
880 interfacePath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
881 serviceID, // service
882 kSCEntNetInterface); // entity
883 entity = SCPreferencesPathGetValue(setPrivate->prefs, interfacePath);
884 CFRelease(interfacePath);
885
886 if (__SCNetworkInterfaceEntityIsPPTP(entity)) {
887 SC_log(LOG_INFO, "PPTP services are no longer supported");
888 skip = TRUE;
889 }
890
891 if (!skip) {
892 SCNetworkServicePrivateRef servicePrivate;
893
894 servicePrivate = __SCNetworkServiceCreatePrivate(NULL,
895 setPrivate->prefs,
896 serviceID,
897 NULL);
898 CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
899 CFRelease(servicePrivate);
900 }
901 }
902 CFRelease(path);
903 }
904 CFRelease(components);
905 }
906 if (keys != keys_q) {
907 CFAllocatorDeallocate(NULL, keys);
908 }
909 }
910
911 return array;
912 }
913
914
915 SCNetworkSetRef
916 SCNetworkSetCreate(SCPreferencesRef prefs)
917 {
918 CFArrayRef components;
919 CFDictionaryRef entity;
920 Boolean ok;
921 CFStringRef path;
922 CFStringRef prefix;
923 CFStringRef setID;
924 SCNetworkSetPrivateRef setPrivate;
925
926 prefix = SCPreferencesPathKeyCreateSets(NULL);
927 path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
928 if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
929 CFRelease(prefix);
930 if (path == NULL) {
931 return NULL;
932 }
933
934 components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
935 setID = CFArrayGetValueAtIndex(components, 2);
936 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
937 assert(setPrivate != NULL);
938 CFRelease(components);
939
940 // mark set as "new" (not yet established)
941 setPrivate->established = FALSE;
942
943 // establish the set in the preferences
944 entity = CFDictionaryCreate(NULL,
945 NULL, NULL, 0,
946 &kCFTypeDictionaryKeyCallBacks,
947 &kCFTypeDictionaryValueCallBacks);
948 ok = SCPreferencesPathSetValue(prefs, path, entity);
949 CFRelease(path);
950 CFRelease(entity);
951 if (!ok) {
952 CFRelease(setPrivate);
953 setPrivate = NULL;
954 }
955
956 if (setPrivate != NULL) {
957 SC_log(LOG_DEBUG, "SCNetworkSetCreate(): %@", setPrivate);
958 }
959
960 return (SCNetworkSetRef)setPrivate;
961 }
962
963
964 SCNetworkSetRef
965 _SCNetworkSetCreateDefault(SCPreferencesRef prefs)
966 {
967 CFStringRef model;
968 Boolean ok = TRUE;
969 SCNetworkSetRef set;
970 CFStringRef setName = NULL;
971 CFNumberRef version;
972
973 set = SCNetworkSetCopyCurrent(prefs);
974 if (set != NULL) {
975 SC_log(LOG_NOTICE, "creating default set w/already existing set");
976 CFRelease(set);
977 _SCErrorSet(kSCStatusKeyExists);
978 return NULL;
979 }
980
981 // create a new ("Automatic") set
982 set = SCNetworkSetCreate(prefs);
983 if (set == NULL) {
984 SC_log(LOG_NOTICE, "could not create \"new\" set: %s",
985 SCErrorString(SCError()));
986 goto done;
987 }
988
989 setName = copy_default_set_name(TRUE);
990 ok = SCNetworkSetSetName(set, setName);
991 CFRelease(setName);
992 if (!ok) {
993 // if we could not save the new set's "name"
994 SC_log(LOG_NOTICE, "could not save the new set's name: %s",
995 SCErrorString(SCError()));
996 goto done;
997 }
998
999 ok = SCNetworkSetSetCurrent(set);
1000 if (!ok) {
1001 // if we could not make this the "current" set
1002 SC_log(LOG_NOTICE, "could not establish new set as current: %s",
1003 SCErrorString(SCError()));
1004 // goto done;
1005 }
1006
1007 model = SCPreferencesGetValue(prefs, MODEL);
1008 if (model == NULL) {
1009 model = _SC_hw_model(FALSE);
1010 SCPreferencesSetValue(prefs, MODEL, model);
1011 }
1012
1013 version = SCPreferencesGetValue(prefs, kSCPrefVersion);
1014 if (version == NULL) {
1015 const int new_version = NETWORK_CONFIGURATION_VERSION;
1016
1017 version = CFNumberCreate(NULL, kCFNumberIntType, &new_version);
1018 SCPreferencesSetValue(prefs, kSCPrefVersion, version);
1019 CFRelease(version);
1020 }
1021
1022 done :
1023
1024 if (!ok && (set != NULL)) {
1025 SCNetworkSetRemove(set);
1026 CFRelease(set);
1027 set = NULL;
1028 }
1029 return set;
1030 }
1031
1032
1033 CFStringRef
1034 SCNetworkSetGetSetID(SCNetworkSetRef set)
1035 {
1036 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1037
1038 if (!isA_SCNetworkSet(set)) {
1039 _SCErrorSet(kSCStatusInvalidArgument);
1040 return NULL;
1041 }
1042
1043 return setPrivate->setID;
1044 }
1045
1046
1047 CFStringRef
1048 SCNetworkSetGetName(SCNetworkSetRef set)
1049 {
1050 CFDictionaryRef entity;
1051 CFStringRef path;
1052 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1053
1054 if (!isA_SCNetworkSet(set)) {
1055 _SCErrorSet(kSCStatusInvalidArgument);
1056 return NULL;
1057 }
1058
1059 if (setPrivate->name != NULL) {
1060 return setPrivate->name;
1061 }
1062
1063 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1064 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
1065 CFRelease(path);
1066
1067 if (isA_CFDictionary(entity)) {
1068 CFStringRef name;
1069
1070 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
1071 if (isA_CFString(name)) {
1072 setPrivate->name = CFRetain(name);
1073 }
1074 }
1075
1076 if (setPrivate->name != NULL) {
1077 CFStringRef non_localized;
1078
1079 non_localized = copy_default_set_name(FALSE);
1080 if (CFEqual(setPrivate->name, non_localized)) {
1081 CFStringRef localized;
1082
1083 // if "Automatic", return localized name
1084 localized = copy_default_set_name(TRUE);
1085 CFRelease(setPrivate->name);
1086 setPrivate->name = localized;
1087 }
1088
1089 CFRelease(non_localized);
1090 }
1091
1092 return setPrivate->name;
1093 }
1094
1095
1096 CFArrayRef /* of serviceID CFStringRef's */
1097 SCNetworkSetGetServiceOrder(SCNetworkSetRef set)
1098 {
1099 CFDictionaryRef dict;
1100 CFStringRef path;
1101 CFArrayRef serviceOrder;
1102 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1103
1104 if (!isA_SCNetworkSet(set)) {
1105 _SCErrorSet(kSCStatusInvalidArgument);
1106 return NULL;
1107 }
1108
1109 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
1110 if (path == NULL) {
1111 return NULL;
1112 }
1113
1114 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
1115 CFRelease(path);
1116 if (!isA_CFDictionary(dict)) {
1117 return NULL;
1118 }
1119
1120 serviceOrder = CFDictionaryGetValue(dict, kSCPropNetServiceOrder);
1121 serviceOrder = isA_CFArray(serviceOrder);
1122
1123 return serviceOrder;
1124 }
1125
1126
1127 CFTypeID
1128 SCNetworkSetGetTypeID(void)
1129 {
1130 pthread_once(&initialized, __SCNetworkSetInitialize); /* initialize runtime */
1131 return __kSCNetworkSetTypeID;
1132 }
1133
1134
1135 #if TARGET_OS_IPHONE
1136 static Boolean
1137 isDefaultSet(SCNetworkSetRef set)
1138 {
1139 CFStringRef defaultName;
1140 Boolean isDefault = FALSE;
1141 CFStringRef setName;
1142
1143 defaultName = copy_default_set_name(TRUE);
1144 setName = SCNetworkSetGetName(set);
1145 isDefault = _SC_CFEqual(setName, defaultName);
1146 CFRelease(defaultName);
1147
1148 return isDefault;
1149 }
1150 #endif // TARGET_OS_IPHONE
1151
1152
1153 Boolean
1154 SCNetworkSetRemove(SCNetworkSetRef set)
1155 {
1156 CFStringRef currentPath;
1157 Boolean ok = FALSE;
1158 CFStringRef path;
1159 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1160
1161 if (!isA_SCNetworkSet(set)) {
1162 _SCErrorSet(kSCStatusInvalidArgument);
1163 return FALSE;
1164 }
1165
1166 if (!__SCNetworkSetExists(set)) {
1167 SC_log(LOG_ERR, "SCNetworkSetRemove() w/removed set\n set = %@", set);
1168 _SC_crash_once("SCNetworkSetRemove() w/removed set", NULL, NULL);
1169 _SCErrorSet(kSCStatusInvalidArgument);
1170 }
1171
1172 #if TARGET_OS_IPHONE
1173 if (isDefaultSet(set) && (geteuid() != 0)) {
1174 SC_log(LOG_ERR, "SCNetworkSetRemove() failed, cannot remove set : %@", set);
1175 _SC_crash("The \"Automatic\" network set cannot be removed", NULL, NULL);
1176 _SCErrorSet(kSCStatusInvalidArgument);
1177 return FALSE;
1178 }
1179 #endif // TARGET_OS_IPHONE
1180
1181 currentPath = SCPreferencesGetValue(setPrivate->prefs, kSCPrefCurrentSet);
1182 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1183 if (!isA_CFString(currentPath) || !CFEqual(currentPath, path)) {
1184 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
1185 } else {
1186 SC_log(LOG_DEBUG, "SCNetworkSetRemove() failed, currently active: %@", setPrivate->setID);
1187 _SCErrorSet(kSCStatusInvalidArgument);
1188 }
1189 CFRelease(path);
1190
1191 if (ok) {
1192 SC_log(LOG_DEBUG, "SCNetworkSetRemove(): %@", set);
1193 }
1194
1195 return ok;
1196 }
1197
1198
1199 Boolean
1200 SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service)
1201 {
1202 SCNetworkInterfaceRef interface;
1203 CFArrayRef interface_config = NULL;
1204 Boolean ok;
1205 CFStringRef path;
1206 int sc_status = kSCStatusOK;
1207 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1208 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1209
1210 if (!isA_SCNetworkSet(set)) {
1211 _SCErrorSet(kSCStatusInvalidArgument);
1212 return FALSE;
1213 }
1214
1215 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1216 _SCErrorSet(kSCStatusInvalidArgument);
1217 return FALSE;
1218 }
1219
1220 if (!__SCNetworkSetExists(set)) {
1221 SC_log(LOG_ERR, "SCNetworkSetRemoveService() w/removed set\n set = %@\n service = %@",
1222 set,
1223 service);
1224 _SC_crash_once("SCNetworkSetRemoveService() w/removed set", NULL, NULL);
1225 _SCErrorSet(kSCStatusInvalidArgument);
1226 }
1227
1228 if (!__SCNetworkServiceExists(service)) {
1229 SC_log(LOG_ERR, "SCNetworkSetRemoveService() w/removed service\n set = %@\n service = %@",
1230 set,
1231 service);
1232 _SC_crash_once("SCNetworkSetRemoveService() w/removed service", NULL, NULL);
1233 _SCErrorSet(kSCStatusInvalidArgument);
1234 return FALSE;
1235 }
1236
1237 // remove service from ServiceOrder
1238 _serviceOrder_remove(set, service);
1239
1240 // get the [deep] interface configuration settings
1241 interface = SCNetworkServiceGetInterface(service);
1242 if (interface != NULL) {
1243 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface);
1244 if (interface_config != NULL) {
1245 // remove the interface configuration from all sets which contain this service.
1246 __SCNetworkInterfaceSetDeepConfiguration(set, interface, NULL);
1247 }
1248 }
1249
1250 // remove the link between "set" and the "service"
1251 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
1252 setPrivate->setID,
1253 servicePrivate->serviceID,
1254 NULL);
1255 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
1256 if (!ok) {
1257 sc_status = SCError(); // preserve the error
1258 }
1259 CFRelease(path);
1260
1261 // push the [deep] interface configuration [back] into all sets which contain the service.
1262 if (interface_config != NULL) {
1263 __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config);
1264 CFRelease(interface_config);
1265 }
1266
1267 if (ok) {
1268 SC_log(LOG_DEBUG, "SCNetworkSetRemoveService(): %@, %@", set, service);
1269 } else {
1270 _SCErrorSet(sc_status);
1271 }
1272
1273 return ok;
1274 }
1275
1276
1277 Boolean
1278 SCNetworkSetSetCurrent(SCNetworkSetRef set)
1279 {
1280 Boolean ok;
1281 CFStringRef path;
1282 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1283
1284 if (!isA_SCNetworkSet(set)) {
1285 _SCErrorSet(kSCStatusInvalidArgument);
1286 return FALSE;
1287 }
1288
1289 if (!__SCNetworkSetExists(set)) {
1290 SC_log(LOG_ERR, "SCNetworkSetSetCurrent() w/removed set\n set = %@", set);
1291 _SC_crash_once("SCNetworkSetSetCurrent() w/removed set", NULL, NULL);
1292 _SCErrorSet(kSCStatusInvalidArgument);
1293 return FALSE;
1294 }
1295
1296 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1297 ok = SCPreferencesSetValue(setPrivate->prefs, kSCPrefCurrentSet, path);
1298 CFRelease(path);
1299
1300 if (ok) {
1301 SC_log(LOG_DEBUG, "SCNetworkSetSetCurrent(): %@", set);
1302 }
1303
1304 return ok;
1305 }
1306
1307
1308 Boolean
1309 SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
1310 {
1311 CFDictionaryRef entity;
1312 #if TARGET_OS_IPHONE
1313 Boolean isDefaultName = FALSE;
1314 #endif // TARGET_OS_IPHONE
1315 CFStringRef localized = NULL;
1316 CFStringRef non_localized = NULL;
1317 Boolean ok = FALSE;
1318 CFStringRef path;
1319 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1320
1321 if (!isA_SCNetworkSet(set)) {
1322 _SCErrorSet(kSCStatusInvalidArgument);
1323 return FALSE;
1324 }
1325
1326 if (!__SCNetworkSetExists(set)) {
1327 SC_log(LOG_ERR, "SCNetworkSetSetName() w/removed set\n set = %@\n name = %@",
1328 set,
1329 name != NULL ? name : CFSTR("<NULL>"));
1330 _SC_crash_once("SCNetworkSetSetName() w/removed set", NULL, NULL);
1331 _SCErrorSet(kSCStatusInvalidArgument);
1332 return FALSE;
1333 }
1334
1335 if ((name != NULL) && !isA_CFString(name)) {
1336 _SCErrorSet(kSCStatusInvalidArgument);
1337 return FALSE;
1338 }
1339
1340 // if known, compare against localized name
1341
1342 if (name != NULL) {
1343 non_localized = copy_default_set_name(FALSE);
1344 if (CFEqual(name, non_localized)) {
1345 localized = copy_default_set_name(TRUE);
1346 name = localized;
1347 #if TARGET_OS_IPHONE
1348 isDefaultName = TRUE;
1349 #endif // TARGET_OS_IPHONE
1350 }
1351 #if TARGET_OS_IPHONE
1352 else {
1353 localized = copy_default_set_name(TRUE);
1354 isDefaultName = CFEqual(name, non_localized);
1355 }
1356 #endif // TARGET_OS_IPHONE
1357 }
1358
1359 #if TARGET_OS_IPHONE
1360 if (!isDefaultName && isDefaultSet(set) && (geteuid() != 0)) {
1361 // if we are trying to change the name of the "Automatic" set
1362 SC_log(LOG_ERR, "SCNetworkSetSetName() failed, cannot rename : %@", set);
1363 _SC_crash("The \"Automatic\" network set cannot be renamed", NULL, NULL);
1364 _SCErrorSet(kSCStatusInvalidArgument);
1365 goto done;
1366 }
1367 #endif // TARGET_OS_IPHONE
1368
1369 #define PREVENT_DUPLICATE_SET_NAMES
1370 #ifdef PREVENT_DUPLICATE_SET_NAMES
1371
1372 #if TARGET_OS_IPHONE
1373 if (!isDefaultName) {
1374 // On iOS, only block naming multiple sets with the name
1375 // "Automatic". Others names are OK.
1376 } else
1377 #endif // TARGET_OS_IPHONE
1378
1379 if (name != NULL) {
1380 CFArrayRef sets;
1381
1382 // ensure that each set is uniquely named
1383
1384 sets = SCNetworkSetCopyAll(setPrivate->prefs);
1385 if (sets != NULL) {
1386 CFIndex i;
1387 CFIndex n;
1388
1389 n = CFArrayGetCount(sets);
1390 for (i = 0; i < n; i++) {
1391 CFStringRef otherID;
1392 CFStringRef otherName;
1393 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, i);
1394
1395 otherID = SCNetworkSetGetSetID(set);
1396 if (CFEqual(setPrivate->setID, otherID)) {
1397 continue; // skip current set
1398 }
1399
1400 otherName = SCNetworkSetGetName(set);
1401 if ((otherName != NULL) && CFEqual(name, otherName)) {
1402 // if "name" not unique
1403 CFRelease(sets);
1404 _SCErrorSet(kSCStatusKeyExists);
1405 goto done;
1406 }
1407 }
1408 CFRelease(sets);
1409 }
1410 }
1411 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1412
1413 // if known, store non-localized name
1414
1415 if ((name != NULL) && (non_localized != NULL)) {
1416 if (localized == NULL) {
1417 localized = copy_default_set_name(TRUE);
1418 }
1419 if (CFEqual(name, localized)) {
1420 name = non_localized;
1421 }
1422 }
1423
1424 // update the "name"
1425
1426 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1427 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
1428 if (isA_CFDictionary(entity) ||
1429 ((entity == NULL) && (name != NULL))) {
1430 CFMutableDictionaryRef newEntity;
1431
1432 if (entity != NULL) {
1433 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1434 } else {
1435 newEntity = CFDictionaryCreateMutable(NULL,
1436 0,
1437 &kCFTypeDictionaryKeyCallBacks,
1438 &kCFTypeDictionaryValueCallBacks);
1439 }
1440 if (name != NULL) {
1441 CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
1442 } else {
1443 CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
1444 }
1445 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newEntity);
1446 CFRelease(newEntity);
1447 }
1448 CFRelease(path);
1449
1450 done :
1451
1452 if (ok) {
1453 SC_log(LOG_DEBUG, "SCNetworkSetSetName(): %@", set);
1454 }
1455
1456 if (localized != NULL) CFRelease(localized);
1457 if (non_localized != NULL) CFRelease(non_localized);
1458 return ok;
1459 }
1460
1461
1462 Boolean
1463 SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
1464 {
1465 CFMutableArrayRef cleanOrder;
1466 CFDictionaryRef dict;
1467 CFIndex i;
1468 CFIndex n;
1469 CFMutableDictionaryRef newDict;
1470 Boolean ok;
1471 CFStringRef path;
1472 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1473
1474 if (!isA_SCNetworkSet(set)) {
1475 _SCErrorSet(kSCStatusInvalidArgument);
1476 return FALSE;
1477 }
1478
1479 if (!__SCNetworkSetExists(set)) {
1480 SC_log(LOG_ERR, "SCNetworkSetSetServiceOrder() w/removed set\n set = %@", set);
1481 _SC_crash_once("SCNetworkSetSetServiceOrder() w/removed set", NULL, NULL);
1482 _SCErrorSet(kSCStatusInvalidArgument);
1483 return FALSE;
1484 }
1485
1486 if (isA_CFArray(newOrder)) {
1487 n = CFArrayGetCount(newOrder);
1488 for (i = 0; i < n; i++) {
1489 CFStringRef serviceID;
1490
1491 serviceID = CFArrayGetValueAtIndex(newOrder, i);
1492 if (!isA_CFString(serviceID)) {
1493 _SCErrorSet(kSCStatusInvalidArgument);
1494 return FALSE;
1495 }
1496 }
1497 } else {
1498 _SCErrorSet(kSCStatusInvalidArgument);
1499 return FALSE;
1500 }
1501
1502 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
1503 if (path == NULL) {
1504 return FALSE;
1505 }
1506
1507 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
1508 if (dict != NULL) {
1509 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
1510 } else {
1511 newDict = CFDictionaryCreateMutable(NULL,
1512 0,
1513 &kCFTypeDictionaryKeyCallBacks,
1514 &kCFTypeDictionaryValueCallBacks);
1515 }
1516
1517 cleanOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1518 n = CFArrayGetCount(newOrder);
1519 for (i = 0; i < n; i++) {
1520 CFIndex nClean = CFArrayGetCount(cleanOrder);
1521 CFStringRef serviceID = CFArrayGetValueAtIndex(newOrder, i);
1522
1523 if ((nClean == 0) ||
1524 !CFArrayContainsValue(cleanOrder, CFRangeMake(0, nClean), serviceID)) {
1525 // if first reference to this serviceID
1526 CFArrayAppendValue(cleanOrder, serviceID);
1527 } else {
1528 // skip duplicate serviceID
1529 SC_log(LOG_ERR, "SCNetworkSetSetServiceOrder() found duplicate serviceID: removed %@\n", serviceID);
1530 }
1531 }
1532 CFDictionarySetValue(newDict, kSCPropNetServiceOrder, cleanOrder);
1533 CFRelease(cleanOrder);
1534
1535 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newDict);
1536 CFRelease(newDict);
1537 CFRelease(path);
1538
1539 return ok;
1540 }
1541
1542
1543 #pragma mark -
1544 #pragma mark SCNetworkSet SPIs
1545
1546
1547 __private_extern__
1548 Boolean
1549 __SCNetworkSetExists(SCNetworkSetRef set)
1550 {
1551 CFDictionaryRef entity;
1552 CFStringRef path;
1553 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1554
1555 if (setPrivate->prefs == NULL) {
1556 return FALSE;
1557 }
1558
1559 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1560 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
1561 CFRelease(path);
1562
1563 if (!isA_CFDictionary(entity)) {
1564 // if no "set"
1565 return FALSE;
1566 }
1567
1568 return TRUE;
1569 }
1570
1571
1572 static void
1573 add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface)
1574 {
1575 CFIndex i;
1576 CFArrayRef interface_types;
1577 CFIndex n;
1578
1579 interface_types = SCNetworkInterfaceGetSupportedInterfaceTypes(interface);
1580 n = (interface_types != NULL) ? CFArrayGetCount(interface_types) : 0;
1581 for (i = 0; i < n; i++) {
1582 SCNetworkInterfaceRef parent;
1583 CFStringRef interface_type;
1584
1585 interface_type = CFArrayGetValueAtIndex(interface_types, i);
1586 parent = SCNetworkInterfaceCreateWithInterface(interface, interface_type);
1587 if (parent != NULL) {
1588 CFArrayAppendValue(interface_list, parent);
1589 CFRelease(parent);
1590 }
1591 }
1592
1593 return;
1594 }
1595
1596
1597 static CFSetRef /* of SCNetworkInterfaceRef's */
1598 copyExcludedInterfaces(SCPreferencesRef prefs)
1599 {
1600 CFMutableSetRef excluded;
1601 CFArrayRef interfaces;
1602
1603 excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1604
1605 #if !TARGET_OS_IPHONE
1606 // exclude Bond [member] interfaces
1607 interfaces = SCBondInterfaceCopyAll(prefs);
1608 if (interfaces != NULL) {
1609 __SCBondInterfaceListCollectMembers(interfaces, excluded);
1610 CFRelease(interfaces);
1611 }
1612 #endif // !TARGET_OS_IPHONE
1613
1614 // exclude Bridge [member] interfaces
1615 interfaces = SCBridgeInterfaceCopyAll(prefs);
1616 if (interfaces != NULL) {
1617 __SCBridgeInterfaceListCollectMembers(interfaces, excluded);
1618 CFRelease(interfaces);
1619 }
1620
1621 return excluded;
1622 }
1623
1624
1625 #if !TARGET_OS_IPHONE
1626 static SCBridgeInterfaceRef
1627 copyAutoBridgeInterface(SCPreferencesRef prefs, CFStringRef bridgeName)
1628 {
1629 SCBridgeInterfaceRef bridge = NULL;
1630 CFArrayRef interfaces;
1631
1632 // exclude Bridge [member] interfaces
1633 interfaces = SCBridgeInterfaceCopyAll(prefs);
1634 if (interfaces != NULL) {
1635 CFIndex i;
1636 CFIndex n;
1637
1638 n = CFArrayGetCount(interfaces);
1639 for (i = 0; i < n; i++) {
1640 SCBridgeInterfaceRef interface;
1641 CFStringRef name = NULL;
1642 CFDictionaryRef options;
1643
1644 interface = CFArrayGetValueAtIndex(interfaces, i);
1645 options = SCBridgeInterfaceGetOptions(interface);
1646 if ((options != NULL) &&
1647 CFDictionaryGetValueIfPresent(options,
1648 CFSTR("__AUTO__"),
1649 (const void **)&name) &&
1650 _SC_CFEqual(name, bridgeName)) {
1651 bridge = interface;
1652 CFRetain(bridge);
1653 break;
1654 }
1655 }
1656
1657 CFRelease(interfaces);
1658 }
1659
1660 if (bridge == NULL) {
1661 bridge = SCBridgeInterfaceCreate(prefs);
1662 if (bridge != NULL) {
1663 CFMutableDictionaryRef newOptions;
1664 Boolean ok;
1665
1666 newOptions = CFDictionaryCreateMutable(NULL, 0,
1667 &kCFTypeDictionaryKeyCallBacks,
1668 &kCFTypeDictionaryValueCallBacks);
1669 CFDictionarySetValue(newOptions, CFSTR("__AUTO__"), bridgeName);
1670 ok = SCBridgeInterfaceSetOptions(bridge, newOptions);
1671 CFRelease(newOptions);
1672 if (!ok) {
1673 CFRelease(bridge);
1674 bridge = NULL;
1675 }
1676 }
1677 }
1678
1679 return bridge;
1680 }
1681 #endif // !TARGET_OS_IPHONE
1682
1683
1684 static CFArrayRef
1685 copyServices(SCNetworkSetRef set)
1686 {
1687 CFArrayRef services;
1688 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1689
1690 // first, assume that we only want to add new services
1691 // for those interfaces that are not represented in the
1692 // current set.
1693 services = SCNetworkSetCopyServices(set);
1694 if ((services != NULL) && setPrivate->established) {
1695 // but, if we are given an existing (or "established") set
1696 // than we only want to add new services for those interfaces
1697 // that are not represented in *any* set.
1698 CFRelease(services);
1699 services = SCNetworkServiceCopyAll(setPrivate->prefs);
1700 }
1701
1702 return services;
1703 }
1704
1705
1706 #if !TARGET_OS_IPHONE
1707 static CF_RETURNS_RETAINED CFArrayRef
1708 updateServices(CFArrayRef services, SCNetworkInterfaceRef interface)
1709 {
1710 CFStringRef bsdName;
1711 CFIndex i;
1712 CFIndex n;
1713 CFMutableArrayRef newServices;
1714
1715 if (services == NULL) {
1716 return NULL;
1717 }
1718
1719 bsdName = SCNetworkInterfaceGetBSDName(interface);
1720
1721 newServices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1722
1723 n = CFArrayGetCount(services);
1724 for (i = 0; i < n; i++) {
1725 SCNetworkInterfaceRef interface;
1726 CFStringRef interfaceName;
1727 SCNetworkServiceRef newService;
1728 SCNetworkServiceRef service;
1729 CFStringRef serviceID;
1730 SCNetworkServicePrivateRef servicePrivate;
1731
1732 service = CFArrayGetValueAtIndex(services, i);
1733 interface = SCNetworkServiceGetInterface(service);
1734 interfaceName = SCNetworkInterfaceGetBSDName(interface);
1735 if (!_SC_CFEqual(interfaceName, bsdName)) {
1736 // if not a match, retain
1737 CFArrayAppendValue(newServices, service);
1738 continue;
1739 }
1740
1741 // if a match, update
1742 serviceID = SCNetworkServiceGetServiceID(service);
1743 servicePrivate = (SCNetworkServicePrivateRef)service;
1744 newService = SCNetworkServiceCopy(servicePrivate->prefs, serviceID);
1745 if (newService != NULL) {
1746 CFArrayAppendValue(newServices, newService);
1747 CFRelease(newService);
1748 }
1749 }
1750
1751 return newServices;
1752 }
1753 #endif // !TARGET_OS_IPHONE
1754
1755
1756 static __inline__ Boolean
1757 skipInterface(SCNetworkInterfaceRef interface)
1758 {
1759 CFStringRef action;
1760
1761 action = _SCNetworkInterfaceGetConfigurationAction(interface);
1762 if (isA_CFString(action) &&
1763 CFEqual(action, kSCNetworkInterfaceConfigurationActionValueNone)) {
1764 return TRUE;
1765 }
1766
1767 return FALSE;
1768 }
1769
1770
1771 CFComparisonResult
1772 _SCNetworkSetCompare(const void *val1, const void *val2, void *context)
1773 {
1774 #pragma unused(context)
1775 CFStringRef id1;
1776 CFStringRef id2;
1777 CFStringRef name1;
1778 CFStringRef name2;
1779 SCNetworkSetRef s1 = (SCNetworkSetRef)val1;
1780 SCNetworkSetRef s2 = (SCNetworkSetRef)val2;
1781
1782 name1 = SCNetworkSetGetName(s1);
1783 name2 = SCNetworkSetGetName(s2);
1784
1785 if (name1 != NULL) {
1786 if (name2 != NULL) {
1787 return CFStringCompare(name1, name2, 0);
1788 } else {
1789 return kCFCompareLessThan;
1790 }
1791 }
1792
1793 if (name2 != NULL) {
1794 return kCFCompareGreaterThan;
1795 }
1796
1797 id1 = SCNetworkSetGetSetID(s1);
1798 id2 = SCNetworkSetGetSetID(s2);
1799 return CFStringCompare(id1, id2, 0);
1800 }
1801
1802
1803 static Boolean
1804 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces, Boolean excludeHidden)
1805 {
1806 CFSetRef excluded;
1807 CFIndex i;
1808 CFIndex n = 0;
1809 Boolean ok = TRUE;
1810 CFArrayRef services;
1811 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1812 Boolean updated = FALSE;
1813 #if !TARGET_OS_IPHONE
1814 Boolean updatedIFs = FALSE;
1815 #endif // !TARGET_OS_IPHONE
1816
1817 #if TARGET_OS_IPHONE
1818 CFArrayRef orphans = NULL;
1819 CFArrayRef sets;
1820
1821 sets = SCNetworkSetCopyAll(setPrivate->prefs);
1822 if (sets != NULL) {
1823 if (CFArrayGetCount(sets) == 1) {
1824 services = SCNetworkSetCopyServices(set);
1825 if (services != NULL) {
1826 n = CFArrayGetCount(services);
1827 CFRelease(services);
1828 }
1829
1830 if ((n == 0) && CFEqual(set, CFArrayGetValueAtIndex(sets, 0))) {
1831 // after a "Reset Network Settings" we need to find (and
1832 // add back) any VPN services that were orphaned.
1833 orphans = SCNetworkServiceCopyAll(setPrivate->prefs);
1834 }
1835 }
1836
1837 CFRelease(sets);
1838 }
1839 #endif // TARGET_OS_IPHONE
1840
1841 // copy network services
1842 services = copyServices(set);
1843
1844 // copy network interfaces to be excluded
1845 excluded = copyExcludedInterfaces(setPrivate->prefs);
1846
1847 #if !TARGET_OS_IPHONE
1848 // look for interfaces that should auto-magically be added
1849 // to an Ethernet bridge
1850 n = ((services != NULL) && (interfaces != NULL)) ? CFArrayGetCount(interfaces) : 0;
1851 for (i = 0; i < n; i++) {
1852 SCBridgeInterfaceRef bridge = NULL;
1853 SCNetworkInterfaceRef interface;
1854
1855 interface = CFArrayGetValueAtIndex(interfaces, i);
1856
1857 if (excludeHidden && skipInterface(interface)) {
1858 // if not auto-configure
1859 continue;
1860 }
1861
1862 if (CFSetContainsValue(excluded, interface)) {
1863 // if this interface is a member of a Bond or Bridge
1864 continue;
1865 }
1866
1867 if (__SCNetworkServiceExistsForInterface(services, interface)) {
1868 // if this is not a new interface
1869 continue;
1870 }
1871
1872 if (_SCNetworkInterfaceIsBuiltin(interface) &&
1873 _SCNetworkInterfaceIsThunderbolt(interface) &&
1874 !isA_SCBridgeInterface(interface)) {
1875 // add built-in Thunderbolt interfaces to bridge
1876 bridge = copyAutoBridgeInterface(setPrivate->prefs, CFSTR("thunderbolt-bridge"));
1877 }
1878
1879 if (bridge != NULL) {
1880 CFIndex bridgeIndex;
1881 CFArrayRef members;
1882 CFMutableArrayRef newMembers;
1883 CFMutableSetRef newExcluded;
1884 CFMutableArrayRef newInterfaces;
1885 CFArrayRef newServices;
1886
1887 // track the bridge interface (if it's in our list)
1888 bridgeIndex = CFArrayGetFirstIndexOfValue(interfaces,
1889 CFRangeMake(0, CFArrayGetCount(interfaces)),
1890 bridge);
1891
1892 // add new member interface
1893 members = SCBridgeInterfaceGetMemberInterfaces(bridge);
1894 if ((members != NULL) && (CFArrayGetCount(members) > 0)) {
1895 newMembers = CFArrayCreateMutableCopy(NULL, 0, members);
1896 updated = TRUE; // if we're updating an existing bridge
1897 } else {
1898 newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1899 }
1900 CFArrayAppendValue(newMembers, interface);
1901 ok = SCBridgeInterfaceSetMemberInterfaces(bridge, newMembers);
1902 CFRelease(newMembers);
1903 if (!ok) {
1904 SC_log(LOG_INFO, "could not update bridge with \"%@\": %s",
1905 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1906 SCErrorString(SCError()));
1907 CFRelease(bridge);
1908 continue;
1909 }
1910
1911 // exclude the new member interface
1912 newExcluded = CFSetCreateMutableCopy(NULL, 0, excluded);
1913 CFRelease(excluded);
1914 CFSetAddValue(newExcluded, interface);
1915 excluded = newExcluded;
1916
1917 // update the list of interfaces to include the [new or updated] bridge
1918 newInterfaces = CFArrayCreateMutableCopy(NULL, 0, interfaces);
1919 if (bridgeIndex != kCFNotFound) {
1920 CFArraySetValueAtIndex(newInterfaces, bridgeIndex, bridge);
1921 } else {
1922 CFArrayAppendValue(newInterfaces, bridge);
1923 }
1924 if (updatedIFs) {
1925 CFRelease(interfaces);
1926 }
1927 interfaces = newInterfaces;
1928 updatedIFs = TRUE;
1929
1930 // refresh [existing] services
1931 newServices = updateServices(services, bridge);
1932 if (newServices != NULL) {
1933 CFRelease(services);
1934 services = newServices;
1935 }
1936
1937 CFRelease(bridge);
1938 }
1939 }
1940 #endif // !TARGET_OS_IPHONE
1941
1942 n = ((services != NULL) && (interfaces != NULL)) ? CFArrayGetCount(interfaces) : 0;
1943 for (i = 0; i < n; i++) {
1944 SCNetworkInterfaceRef interface;
1945 CFMutableArrayRef interface_list;
1946
1947 interface = CFArrayGetValueAtIndex(interfaces, i);
1948
1949 if (excludeHidden && skipInterface(interface)) {
1950 // if not auto-configure
1951 continue;
1952 }
1953
1954 if (CFSetContainsValue(excluded, interface)) {
1955 // if this interface is a member of a Bond or Bridge
1956 continue;
1957 }
1958
1959 if (__SCNetworkServiceExistsForInterface(services, interface)) {
1960 // if this is not a new interface
1961 continue;
1962 }
1963
1964 interface_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1965 CFArrayAppendValue(interface_list, interface);
1966
1967 while (ok && (CFArrayGetCount(interface_list) > 0)) {
1968 CFArrayRef protocol_types;
1969
1970 interface = CFArrayGetValueAtIndex(interface_list, 0);
1971
1972 protocol_types = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
1973 if ((protocol_types != NULL) && (CFArrayGetCount(protocol_types) > 0)) {
1974 SCNetworkServiceRef service;
1975
1976 service = SCNetworkServiceCreate(setPrivate->prefs, interface);
1977 if (service == NULL) {
1978 SC_log(LOG_ERR, "could not create service for \"%@\": %s",
1979 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1980 SCErrorString(SCError()));
1981 ok = FALSE;
1982 goto nextInterface;
1983 }
1984
1985 ok = SCNetworkServiceEstablishDefaultConfiguration(service);
1986 if (!ok) {
1987 SC_log(LOG_ERR, "could not estabish default configuration for \"%@\": %s",
1988 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1989 SCErrorString(SCError()));
1990 SCNetworkServiceRemove(service);
1991 CFRelease(service);
1992 goto nextInterface;
1993 }
1994
1995 ok = SCNetworkSetAddService(set, service);
1996 if (!ok) {
1997 SC_log(LOG_ERR, "could not add service for \"%@\": %s",
1998 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1999 SCErrorString(SCError()));
2000 SCNetworkServiceRemove(service);
2001 CFRelease(service);
2002 goto nextInterface;
2003 }
2004
2005 CFRelease(service);
2006 updated = TRUE;
2007 } else {
2008 add_supported_interfaces(interface_list, interface);
2009 }
2010
2011 nextInterface :
2012
2013 CFArrayRemoveValueAtIndex(interface_list, 0);
2014 }
2015 CFRelease(interface_list);
2016 }
2017 #if !TARGET_OS_IPHONE
2018 if (updatedIFs && (interfaces != NULL)) {
2019 CFRelease(interfaces);
2020 }
2021 #endif // !TARGET_OS_IPHONE
2022 if (services != NULL) CFRelease(services);
2023 CFRelease(excluded);
2024
2025 #if TARGET_OS_IPHONE
2026 if (orphans != NULL) {
2027 if (ok && updated) {
2028 CFIndex i;
2029 CFIndex n = CFArrayGetCount(orphans);
2030
2031 for (i = 0; i < n; i++) {
2032 SCNetworkServiceRef service;
2033
2034 service = CFArrayGetValueAtIndex(orphans, i);
2035 if (_SCNetworkServiceIsVPN(service)) {
2036 ok = SCNetworkSetAddService(set, service);
2037 if (!ok) {
2038 break;
2039 }
2040 }
2041 }
2042 }
2043
2044 CFRelease(orphans);
2045 }
2046 #endif // TARGET_OS_IPHONE
2047
2048 if (ok) {
2049 if (updated) {
2050 CFStringRef model;
2051
2052 model = SCPreferencesGetValue(setPrivate->prefs, MODEL);
2053 if (model == NULL) {
2054 model = _SC_hw_model(FALSE);
2055 SCPreferencesSetValue(setPrivate->prefs, MODEL, model);
2056 }
2057 } else {
2058 // if no changes were made
2059 _SCErrorSet(kSCStatusOK);
2060 }
2061 }
2062
2063 return updated;
2064 }
2065
2066
2067 Boolean
2068 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set)
2069 {
2070 CFArrayRef interfaces;
2071 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
2072 Boolean updated = FALSE;
2073
2074 if (!isA_SCNetworkSet(set)) {
2075 _SCErrorSet(kSCStatusInvalidArgument);
2076 return FALSE;
2077 }
2078
2079 interfaces = _SCNetworkInterfaceCopyAllWithPreferences(setPrivate->prefs);
2080 if (interfaces != NULL) {
2081 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, TRUE);
2082 CFRelease(interfaces);
2083 }
2084
2085 return updated;
2086 }
2087
2088
2089 Boolean
2090 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
2091 {
2092 CFArrayRef interfaces;
2093 Boolean updated;
2094
2095 if (!isA_SCNetworkSet(set)) {
2096 _SCErrorSet(kSCStatusInvalidArgument);
2097 return FALSE;
2098 }
2099
2100 if (!isA_SCNetworkInterface(interface)) {
2101 _SCErrorSet(kSCStatusInvalidArgument);
2102 return FALSE;
2103 }
2104
2105 interfaces = CFArrayCreate(NULL, (const void **)&interface, 1, &kCFTypeArrayCallBacks);
2106 assert(interfaces != NULL);
2107 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, FALSE);
2108 CFRelease(interfaces);
2109
2110 return updated;
2111 }
2112
2113
2114 SCNetworkServiceRef
2115 SCNetworkSetCopySelectedVPNService(SCNetworkSetRef set)
2116 {
2117 CFIndex i;
2118 CFIndex n;
2119 SCNetworkServiceRef selected = NULL;
2120 CFArrayRef services;
2121 CFMutableArrayRef services_vpn = NULL;
2122
2123 if (!isA_SCNetworkSet(set)) {
2124 _SCErrorSet(kSCStatusInvalidArgument);
2125 return NULL;
2126 }
2127
2128 services = SCNetworkSetCopyServices(set);
2129 if (services != NULL) {
2130 n = CFArrayGetCount(services);
2131 for (i = 0; i < n; i++) {
2132 SCNetworkServiceRef service;
2133
2134 service = CFArrayGetValueAtIndex(services, i);
2135 if (!SCNetworkServiceGetEnabled(service)) {
2136 // if not enabled
2137 continue;
2138 }
2139
2140 if (!_SCNetworkServiceIsVPN(service)) {
2141 // if not VPN service
2142 continue;
2143 }
2144
2145 if (services_vpn == NULL) {
2146 services_vpn = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2147 }
2148 CFArrayAppendValue(services_vpn, service);
2149 }
2150
2151 CFRelease(services);
2152 }
2153
2154 if (services_vpn == NULL) {
2155 // if no VPN services
2156 return NULL;
2157 }
2158
2159 n = CFArrayGetCount(services_vpn);
2160 if (n > 1) {
2161 CFArrayRef order;
2162 CFMutableArrayRef sorted;
2163
2164 order = SCNetworkSetGetServiceOrder(set);
2165 sorted = CFArrayCreateMutableCopy(NULL, 0, services_vpn);
2166 CFArraySortValues(sorted,
2167 CFRangeMake(0, CFArrayGetCount(sorted)),
2168 _SCNetworkServiceCompare,
2169 (void *)order);
2170 CFRelease(services_vpn);
2171 services_vpn = sorted;
2172 }
2173
2174 #if TARGET_OS_IPHONE
2175 if (n > 1) {
2176 CFStringRef serviceID_prefs;
2177
2178 #define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")
2179 #define VPN_SERVICE_ID CFSTR("activeVPNID")
2180
2181 CFPreferencesAppSynchronize(VPN_PREFERENCES);
2182 serviceID_prefs = CFPreferencesCopyAppValue(VPN_SERVICE_ID, VPN_PREFERENCES);
2183 if (serviceID_prefs != NULL) {
2184 for (i = 0; i < n; i++) {
2185 SCNetworkServiceRef service;
2186 CFStringRef serviceID;
2187
2188 service = CFArrayGetValueAtIndex(services_vpn, i);
2189 serviceID = SCNetworkServiceGetServiceID(service);
2190 if (CFEqual(serviceID, serviceID_prefs)) {
2191 selected = service;
2192 CFRetain(selected);
2193 break;
2194 }
2195
2196 }
2197
2198 CFRelease(serviceID_prefs);
2199 }
2200 }
2201 #endif // TARGET_OS_IPHONE
2202
2203 if (selected == NULL) {
2204 selected = CFArrayGetValueAtIndex(services_vpn, 0);
2205 CFRetain(selected);
2206 }
2207
2208 CFRelease(services_vpn);
2209 return selected;
2210 }
2211
2212
2213 Boolean
2214 SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set, SCNetworkServiceRef service)
2215 {
2216 Boolean ok = TRUE;
2217 CFArrayRef services;
2218
2219 if (!isA_SCNetworkSet(set)) {
2220 _SCErrorSet(kSCStatusInvalidArgument);
2221 return FALSE;
2222 }
2223
2224 if (!isA_SCNetworkService(service) || !_SCNetworkServiceIsVPN(service)) {
2225 _SCErrorSet(kSCStatusInvalidArgument);
2226 return FALSE;
2227 }
2228
2229 services = SCNetworkSetCopyServices(set);
2230 if (services != NULL) {
2231 CFIndex i;
2232 CFIndex n = CFArrayGetCount(services);
2233
2234 if (!CFArrayContainsValue(services, CFRangeMake(0, n), service)) {
2235 // if selected service not a member of the current set
2236 _SCErrorSet(kSCStatusInvalidArgument);
2237 ok = FALSE;
2238 goto done;
2239 }
2240
2241 for (i = 0; ok && (i < n); i++) {
2242 SCNetworkServiceRef vpn;
2243
2244 vpn = CFArrayGetValueAtIndex(services, i);
2245 if (!_SCNetworkServiceIsVPN(vpn)) {
2246 // if not VPN service
2247 continue;
2248 }
2249
2250 ok = SCNetworkServiceSetEnabled(vpn, CFEqual(service, vpn));
2251 }
2252 }
2253
2254 done :
2255
2256 if (services != NULL) CFRelease(services);
2257 return ok;
2258 }
2259
2260
2261 Boolean
2262 _SCNetworkSetSetSetID(SCNetworkSetRef set, CFStringRef newSetID)
2263 {
2264 SCNetworkSetRef currentSet = NULL;
2265 SCNetworkSetPrivateRef currentSetPrivate = NULL;
2266 CFDictionaryRef entity;
2267 CFStringRef newPath;
2268 Boolean ok = FALSE;
2269 CFStringRef oldPath = NULL;
2270 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
2271 Boolean updateCurrentSet = FALSE;
2272
2273 if (!isA_SCNetworkSet(set)) {
2274 _SCErrorSet(kSCStatusInvalidArgument);
2275 return FALSE;
2276 }
2277
2278 if (!isA_CFString(newSetID)) {
2279 _SCErrorSet(kSCStatusInvalidArgument);
2280 return FALSE;
2281 }
2282
2283 if (!__SCNetworkSetExists(set)) {
2284 SC_log(LOG_ERR, "_SCNetworkSetSetSetID() w/removed set\n set = %@\n setID = %@",
2285 set,
2286 newSetID);
2287 _SC_crash_once("_SCNetworkSetSetSetID() w/removed set", NULL, NULL);
2288 _SCErrorSet(kSCStatusInvalidArgument);
2289 return FALSE;
2290 }
2291
2292 // If newSetID is equal to current setID, our work is done
2293 if (CFEqual(newSetID, setPrivate->setID)) {
2294 return TRUE;
2295 }
2296
2297 newPath = SCPreferencesPathKeyCreateSet(NULL, newSetID);
2298 entity = SCPreferencesPathGetValue(setPrivate->prefs, newPath);
2299 if (isA_CFDictionary(entity)) {
2300 // if the new set already exists
2301 _SCErrorSet(kSCStatusKeyExists);
2302 goto done;
2303 }
2304
2305 oldPath = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
2306 entity = SCPreferencesPathGetValue(setPrivate->prefs, oldPath);
2307 if (!isA_CFDictionary(entity)) {
2308 // if the set has already been removed
2309 _SCErrorSet(kSCStatusNoKey);
2310 goto done;
2311 }
2312
2313 ok = SCPreferencesPathSetValue(setPrivate->prefs, newPath, entity);
2314 if (!ok) {
2315 goto done;
2316 }
2317
2318 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, oldPath);
2319 if (!ok) {
2320 goto done;
2321 }
2322
2323 // update current set (if needed)
2324 currentSet = SCNetworkSetCopyCurrent(setPrivate->prefs);
2325 if (currentSet != NULL) {
2326 currentSetPrivate = (SCNetworkSetPrivateRef)currentSet;
2327 if (CFEqual(currentSetPrivate->setID, setPrivate->setID)) {
2328 updateCurrentSet = TRUE;
2329 }
2330 CFRelease(currentSet);
2331 }
2332
2333 SC_log(LOG_DEBUG, "_SCNetworkSetSetID(): %@ --> %@", set, newSetID);
2334
2335 // replace setID with new one
2336 CFRetain(newSetID);
2337 CFRelease(setPrivate->setID);
2338 setPrivate->setID = newSetID;
2339
2340 if (updateCurrentSet) {
2341 SCNetworkSetSetCurrent(set);
2342 }
2343
2344 done:
2345
2346 if (oldPath != NULL) {
2347 CFRelease(oldPath);
2348 }
2349 if (newPath != NULL) {
2350 CFRelease(newPath);
2351 }
2352
2353 return ok;
2354 }