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