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