]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkSet.c
configd-289.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkSet.c
1 /*
2 * Copyright (c) 2004-2007, 2009 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 <SystemConfiguration/SystemConfiguration.h>
35 #include "SCNetworkConfigurationInternal.h"
36 #include <SystemConfiguration/SCValidation.h>
37 #include <SystemConfiguration/SCPrivate.h>
38
39 #include <pthread.h>
40
41
42 static CFStringRef __SCNetworkSetCopyDescription (CFTypeRef cf);
43 static void __SCNetworkSetDeallocate (CFTypeRef cf);
44 static Boolean __SCNetworkSetEqual (CFTypeRef cf1, CFTypeRef cf2);
45 static CFHashCode __SCNetworkSetHash (CFTypeRef cf);
46
47
48 static CFTypeID __kSCNetworkSetTypeID = _kCFRuntimeNotATypeID;
49
50
51 static const CFRuntimeClass __SCNetworkSetClass = {
52 0, // version
53 "SCNetworkSet", // className
54 NULL, // init
55 NULL, // copy
56 __SCNetworkSetDeallocate, // dealloc
57 __SCNetworkSetEqual, // equal
58 __SCNetworkSetHash, // hash
59 NULL, // copyFormattingDesc
60 __SCNetworkSetCopyDescription // copyDebugDesc
61 };
62
63
64 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
65
66
67 static CFStringRef
68 __SCNetworkSetCopyDescription(CFTypeRef cf)
69 {
70 CFAllocatorRef allocator = CFGetAllocator(cf);
71 CFMutableStringRef result;
72 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
73
74 result = CFStringCreateMutable(allocator, 0);
75 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkSet %p [%p]> {"), cf, allocator);
76 CFStringAppendFormat(result, NULL, CFSTR("id = %@"), setPrivate->setID);
77 CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), setPrivate->prefs);
78 if (setPrivate->name != NULL) {
79 CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), setPrivate->name);
80 }
81 CFStringAppendFormat(result, NULL, CFSTR("}"));
82
83 return result;
84 }
85
86
87 static void
88 __SCNetworkSetDeallocate(CFTypeRef cf)
89 {
90 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
91
92 /* release resources */
93
94 CFRelease(setPrivate->setID);
95 CFRelease(setPrivate->prefs);
96 if (setPrivate->name != NULL)
97 CFRelease(setPrivate->name);
98
99 return;
100 }
101
102
103 static Boolean
104 __SCNetworkSetEqual(CFTypeRef cf1, CFTypeRef cf2)
105 {
106 SCNetworkSetPrivateRef s1 = (SCNetworkSetPrivateRef)cf1;
107 SCNetworkSetPrivateRef s2 = (SCNetworkSetPrivateRef)cf2;
108
109 if (s1 == s2)
110 return TRUE;
111
112 if (s1->prefs != s2->prefs)
113 return FALSE; // if not the same prefs
114
115 if (!CFEqual(s1->setID, s2->setID))
116 return FALSE; // if not the same set identifier
117
118 return TRUE;
119 }
120
121
122 static CFHashCode
123 __SCNetworkSetHash(CFTypeRef cf)
124 {
125 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
126
127 return CFHash(setPrivate->setID);
128 }
129
130
131 static void
132 __SCNetworkSetInitialize(void)
133 {
134 __kSCNetworkSetTypeID = _CFRuntimeRegisterClass(&__SCNetworkSetClass);
135 return;
136 }
137
138
139 static SCNetworkSetPrivateRef
140 __SCNetworkSetCreatePrivate(CFAllocatorRef allocator,
141 SCPreferencesRef prefs,
142 CFStringRef setID)
143 {
144 SCNetworkSetPrivateRef setPrivate;
145 uint32_t size;
146
147 /* initialize runtime */
148 pthread_once(&initialized, __SCNetworkSetInitialize);
149
150 /* allocate target */
151 size = sizeof(SCNetworkSetPrivate) - sizeof(CFRuntimeBase);
152 setPrivate = (SCNetworkSetPrivateRef)_CFRuntimeCreateInstance(allocator,
153 __kSCNetworkSetTypeID,
154 size,
155 NULL);
156 if (setPrivate == NULL) {
157 return NULL;
158 }
159
160 setPrivate->setID = CFStringCreateCopy(NULL, setID);
161 setPrivate->prefs = CFRetain(prefs);
162 setPrivate->name = NULL;
163 setPrivate->established = FALSE; // "new" (not yet established) set
164
165 return setPrivate;
166 }
167
168
169 #pragma mark -
170
171
172 static Boolean
173 _serviceIsVPN(SCNetworkServiceRef service)
174 {
175 SCNetworkInterfaceRef interface;
176 CFStringRef interfaceType;
177
178 interface = SCNetworkServiceGetInterface(service);
179 if (interface == NULL) {
180 return FALSE;
181 }
182
183 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
184 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
185 interface = SCNetworkInterfaceGetInterface(interface);
186 if (interface == NULL) {
187 return FALSE;
188 }
189
190 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
191 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
192 return TRUE;
193 }
194 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
195 return TRUE;
196 }
197 return FALSE;
198 }
199 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
200 return TRUE;
201 }
202
203 return FALSE;
204 }
205
206
207 static int
208 _serviceOrder(SCNetworkServiceRef service)
209 {
210 SCNetworkInterfaceRef interface;
211
212 interface = SCNetworkServiceGetInterface(service);
213 if ((interface == NULL) || _serviceIsVPN(service)) {
214 return 100000; // if unknown or VPN interface, sort last
215 }
216
217 return __SCNetworkInterfaceOrder(interface);
218 }
219
220
221 static void
222 _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service)
223 {
224 CFIndex i;
225 CFIndex n;
226 CFMutableArrayRef newOrder;
227 CFArrayRef order;
228 CFStringRef serviceID;
229 CFIndex serviceOrder;
230 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
231 CFIndex slot;
232
233 order = SCNetworkSetGetServiceOrder(set);
234 if (order != NULL) {
235 newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
236 } else {
237 newOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
238 }
239 n = CFArrayGetCount(newOrder);
240
241 serviceID = SCNetworkServiceGetServiceID(service);
242 if (CFArrayContainsValue(newOrder, CFRangeMake(0, n), serviceID)) {
243 // if serviceID already present
244 goto done;
245 }
246
247 serviceOrder = _serviceOrder(service);
248
249 slot = 0;
250 for (i = 0; i < n; i++) {
251 int slotOrder;
252 SCNetworkServiceRef slotService;
253 CFStringRef slotServiceID;
254
255 slotServiceID = CFArrayGetValueAtIndex(newOrder, i);
256 if (!isA_CFString(slotServiceID)) {
257 // if bad prefs
258 continue;
259 }
260
261 slotService = SCNetworkServiceCopy(setPrivate->prefs, slotServiceID);
262 if (slotService == NULL) {
263 // if serviceID not valid
264 continue;
265 }
266
267 slotOrder = _serviceOrder(slotService);
268 if (serviceOrder >= slotOrder) {
269 // add the service *after* this one
270 slot = i + 1;
271 }
272
273 CFRelease(slotService);
274 }
275
276 CFArrayInsertValueAtIndex(newOrder, slot, serviceID);
277 (void) SCNetworkSetSetServiceOrder(set, newOrder);
278
279 done :
280
281 CFRelease(newOrder);
282
283 return;
284 }
285
286
287 static void
288 _serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service)
289 {
290 CFMutableArrayRef newOrder;
291 CFArrayRef order;
292 CFStringRef serviceID;
293
294 order = SCNetworkSetGetServiceOrder(set);
295 if (order == NULL) {
296 return;
297 }
298
299 serviceID = SCNetworkServiceGetServiceID(service);
300
301 newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
302 while (TRUE) {
303 CFIndex i;
304
305 i = CFArrayGetFirstIndexOfValue(newOrder,
306 CFRangeMake(0, CFArrayGetCount(newOrder)),
307 serviceID);
308 if (i == kCFNotFound) {
309 break;
310 }
311
312 CFArrayRemoveValueAtIndex(newOrder, i);
313 }
314 (void) SCNetworkSetSetServiceOrder(set, newOrder);
315 CFRelease(newOrder);
316
317 return;
318 }
319
320
321 #pragma mark -
322 #pragma mark SCNetworkSet APIs
323
324
325 #define N_QUICK 16
326
327
328 Boolean
329 SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
330 {
331 SCNetworkInterfaceRef interface;
332 CFArrayRef interface_config = NULL;
333 CFStringRef link;
334 Boolean ok;
335 CFStringRef path;
336 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
337 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
338
339 if (!isA_SCNetworkSet(set)) {
340 _SCErrorSet(kSCStatusInvalidArgument);
341 return FALSE;
342 }
343
344 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
345 _SCErrorSet(kSCStatusInvalidArgument);
346 return FALSE;
347 }
348
349 #define PREVENT_DUPLICATE_SERVICE_NAMES
350 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
351 CFStringRef name;
352
353 name = SCNetworkServiceGetName(service);
354 if (name != NULL) {
355 CFArrayRef services;
356
357 services = SCNetworkSetCopyServices(set);
358 if (services != NULL) {
359 CFIndex i;
360 CFIndex n;
361
362 n = CFArrayGetCount(services);
363 for (i = 0; i < n; i++) {
364 CFStringRef otherName;
365 SCNetworkServiceRef otherService;
366
367 otherService = CFArrayGetValueAtIndex(services, i);
368 otherName = SCNetworkServiceGetName(otherService);
369 if ((otherName != NULL) && CFEqual(name, otherName)) {
370 /*
371 * if a service with the same "name" is
372 * already a member of the set.
373 */
374 CFRelease(services);
375 _SCErrorSet(kSCStatusKeyExists);
376 return FALSE;
377 }
378 }
379 }
380
381 CFRelease(services);
382 }
383 #endif // PREVENT_DUPLICATE_SERVICE_NAMES
384
385 //#define PREVENT_DUPLICATE_SETS
386 #ifdef PREVENT_DUPLICATE_SETS
387 CFArrayRef sets;
388
389 // ensure that each service is only a member of ONE set
390 sets = SCNetworkSetCopyAll(setPrivate->prefs);
391 if (sets != NULL) {
392 CFIndex i;
393 CFIndex n;
394
395 n = CFArrayGetCount(sets);
396 for (i = 0; i < n; i++) {
397 Boolean found;
398 CFArrayRef services;
399 SCNetworkSetRef set;
400
401 set = CFArrayGetValueAtIndex(sets, i);
402 services = SCNetworkSetCopyServices(set);
403 found = CFArrayContainsValue(services,
404 CFRangeMake(0, CFArrayGetCount(services)),
405 service);
406 CFRelease(services);
407
408 if (found) {
409 CFRelease(sets);
410 _SCErrorSet(kSCStatusKeyExists);
411 return FALSE;
412 }
413 }
414 CFRelease(sets);
415 }
416 #endif /* PREVENT_DUPLICATE_SETS */
417
418 // get the [deep] interface configuration settings
419 interface = SCNetworkServiceGetInterface(service);
420 if (interface != NULL) {
421 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface);
422 }
423
424 // create the link between "set" and the "service"
425 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator
426 setPrivate->setID, // set
427 servicePrivate->serviceID, // service
428 NULL); // entity
429 link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
430 servicePrivate->serviceID, // service
431 NULL); // entity
432 ok = SCPreferencesPathSetLink(setPrivate->prefs, path, link);
433 CFRelease(path);
434 CFRelease(link);
435 if (!ok) {
436 goto done;
437 }
438
439 // push the [deep] interface configuration into all sets which contain this service.
440 if (interface != NULL) {
441 __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config);
442 }
443
444 // add service to ServiceOrder
445 _serviceOrder_add(set, service);
446
447 // mark set as no longer "new"
448 setPrivate->established = TRUE;
449
450 done :
451
452 if (interface_config != NULL) CFRelease(interface_config);
453 return ok;
454 }
455
456
457 SCNetworkSetRef
458 SCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID)
459 {
460 CFDictionaryRef entity;
461 CFStringRef path;
462 SCNetworkSetPrivateRef setPrivate;
463
464 if (!isA_CFString(setID)) {
465 _SCErrorSet(kSCStatusInvalidArgument);
466 return NULL;
467 }
468
469 path = SCPreferencesPathKeyCreateSet(NULL, setID);
470 entity = SCPreferencesPathGetValue(prefs, path);
471 CFRelease(path);
472
473 if (!isA_CFDictionary(entity)) {
474 _SCErrorSet(kSCStatusNoKey);
475 return NULL;
476 }
477
478 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
479
480 // mark set as "old" (already established)
481 setPrivate->established = TRUE;
482
483 return (SCNetworkSetRef)setPrivate;
484 }
485
486
487 static Boolean
488 _SCNetworkServiceExistsForInterface(CFArrayRef services, SCNetworkInterfaceRef interface)
489 {
490 CFIndex i;
491 CFIndex n;
492
493 n = isA_CFArray(services) ? CFArrayGetCount(services) : 0;
494 for (i = 0; i < n; i++) {
495 SCNetworkServiceRef service;
496 SCNetworkInterfaceRef service_interface;
497
498 service = CFArrayGetValueAtIndex(services, i);
499
500 service_interface = SCNetworkServiceGetInterface(service);
501 while (service_interface != NULL) {
502 if (CFEqual(interface, service_interface)) {
503 return TRUE;
504 }
505
506 service_interface = SCNetworkInterfaceGetInterface(service_interface);
507 }
508 }
509
510 return FALSE;
511 }
512
513
514 Boolean
515 SCNetworkSetContainsInterface(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
516 {
517 Boolean found = FALSE;
518 CFArrayRef services;
519
520 services = SCNetworkSetCopyServices(set);
521 if (services != NULL) {
522 found = _SCNetworkServiceExistsForInterface(services, interface);
523 CFRelease(services);
524 }
525
526 return found;
527 }
528
529
530 CFArrayRef /* of SCNetworkSetRef's */
531 SCNetworkSetCopyAll(SCPreferencesRef prefs)
532 {
533 CFMutableArrayRef array;
534 CFIndex n;
535 CFStringRef path;
536 CFDictionaryRef sets;
537
538 path = SCPreferencesPathKeyCreateSets(NULL);
539 sets = SCPreferencesPathGetValue(prefs, path);
540 CFRelease(path);
541
542 if ((sets != NULL) && !isA_CFDictionary(sets)) {
543 return NULL;
544 }
545
546 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
547
548 n = (sets != NULL) ? CFDictionaryGetCount(sets) : 0;
549 if (n > 0) {
550 CFIndex i;
551 const void * keys_q[N_QUICK];
552 const void ** keys = keys_q;
553 const void * vals_q[N_QUICK];
554 const void ** vals = vals_q;
555
556 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
557 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
558 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
559 }
560 CFDictionaryGetKeysAndValues(sets, keys, vals);
561 for (i = 0; i < n; i++) {
562 SCNetworkSetPrivateRef setPrivate;
563
564 if (!isA_CFDictionary(vals[i])) {
565 SCLog(TRUE,
566 LOG_INFO,
567 CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"),
568 keys[i]);
569 continue;
570 }
571
572 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, keys[i]);
573
574 // mark set as "old" (already established)
575 setPrivate->established = TRUE;
576
577 CFArrayAppendValue(array, (SCNetworkSetRef)setPrivate);
578 CFRelease(setPrivate);
579 }
580 if (keys != keys_q) {
581 CFAllocatorDeallocate(NULL, keys);
582 CFAllocatorDeallocate(NULL, vals);
583 }
584 }
585
586 return array;
587 }
588
589
590 SCNetworkSetRef
591 SCNetworkSetCopyCurrent(SCPreferencesRef prefs)
592 {
593 CFArrayRef components;
594 CFStringRef currentID;
595 SCNetworkSetPrivateRef setPrivate = NULL;
596
597 currentID = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
598 if (!isA_CFString(currentID)) {
599 return NULL;
600 }
601
602 components = CFStringCreateArrayBySeparatingStrings(NULL, currentID, CFSTR("/"));
603 if (CFArrayGetCount(components) == 3) {
604 CFStringRef setID;
605 CFStringRef path;
606
607 setID = CFArrayGetValueAtIndex(components, 2);
608 path = SCPreferencesPathKeyCreateSet(NULL, setID);
609 if (CFEqual(path, currentID)) {
610 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
611
612 // mark set as "old" (already established)
613 setPrivate->established = TRUE;
614 } else {
615 SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant"));
616 }
617 CFRelease(path);
618 }
619 CFRelease(components);
620
621 return (SCNetworkSetRef)setPrivate;
622 }
623
624
625 CFArrayRef /* of SCNetworkServiceRef's */
626 SCNetworkSetCopyServices(SCNetworkSetRef set)
627 {
628 CFMutableArrayRef array;
629 CFDictionaryRef dict;
630 CFIndex n;
631 CFStringRef path;
632 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
633
634 if (!isA_SCNetworkSet(set)) {
635 _SCErrorSet(kSCStatusInvalidArgument);
636 return NULL;
637 }
638
639 path = SCPreferencesPathKeyCreateSetNetworkService(NULL, setPrivate->setID, NULL);
640 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
641 CFRelease(path);
642 if ((dict != NULL) && !isA_CFDictionary(dict)) {
643 return NULL;
644 }
645
646 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
647
648 n = (dict != NULL) ? CFDictionaryGetCount(dict) : 0;
649 if (n > 0) {
650 CFIndex i;
651 const void * keys_q[N_QUICK];
652 const void ** keys = keys_q;
653
654 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
655 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
656 }
657 CFDictionaryGetKeysAndValues(dict, keys, NULL);
658 for (i = 0; i < n; i++) {
659 CFArrayRef components;
660 CFStringRef link;
661
662 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
663 setPrivate->setID,
664 (CFStringRef)keys[i],
665 NULL);
666 link = SCPreferencesPathGetLink(setPrivate->prefs, path);
667 CFRelease(path);
668 if (link == NULL) {
669 SCLog(TRUE,
670 LOG_INFO,
671 CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"),
672 keys[i],
673 setPrivate->setID);
674 continue; // if the service is not a link
675 }
676
677 components = CFStringCreateArrayBySeparatingStrings(NULL, link, CFSTR("/"));
678 if (CFArrayGetCount(components) == 3) {
679 CFStringRef serviceID;
680
681 serviceID = CFArrayGetValueAtIndex(components, 2);
682 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
683 serviceID, // service
684 NULL); // entity
685 if (CFEqual(path, link)) {
686 SCNetworkServicePrivateRef servicePrivate;
687
688 servicePrivate = __SCNetworkServiceCreatePrivate(NULL,
689 setPrivate->prefs,
690 serviceID,
691 NULL);
692 CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
693 CFRelease(servicePrivate);
694 }
695 CFRelease(path);
696 }
697 CFRelease(components);
698 }
699 if (keys != keys_q) {
700 CFAllocatorDeallocate(NULL, keys);
701 }
702 }
703
704 return array;
705 }
706
707
708 SCNetworkSetRef
709 SCNetworkSetCreate(SCPreferencesRef prefs)
710 {
711 CFArrayRef components;
712 CFStringRef path;
713 CFStringRef prefix;
714 CFStringRef setID;
715 SCNetworkSetPrivateRef setPrivate;
716
717 prefix = SCPreferencesPathKeyCreateSets(NULL);
718 path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
719 if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
720 CFRelease(prefix);
721 if (path == NULL) {
722 return NULL;
723 }
724
725 components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
726 CFRelease(path);
727
728 setID = CFArrayGetValueAtIndex(components, 2);
729 setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
730 CFRelease(components);
731
732 // mark set as "new" (not yet established)
733 setPrivate->established = FALSE;
734
735 return (SCNetworkSetRef)setPrivate;
736 }
737
738
739 CFStringRef
740 SCNetworkSetGetSetID(SCNetworkSetRef set)
741 {
742 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
743
744 if (!isA_SCNetworkSet(set)) {
745 _SCErrorSet(kSCStatusInvalidArgument);
746 return NULL;
747 }
748
749 return setPrivate->setID;
750 }
751
752
753 CFStringRef
754 SCNetworkSetGetName(SCNetworkSetRef set)
755 {
756 CFBundleRef bundle;
757 CFDictionaryRef entity;
758 CFStringRef path;
759 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
760
761 if (!isA_SCNetworkSet(set)) {
762 _SCErrorSet(kSCStatusInvalidArgument);
763 return NULL;
764 }
765
766 if (setPrivate->name != NULL) {
767 return setPrivate->name;
768 }
769
770 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
771 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
772 CFRelease(path);
773
774 if (isA_CFDictionary(entity)) {
775 CFStringRef name;
776
777 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
778 if (isA_CFString(name)) {
779 setPrivate->name = CFRetain(name);
780 }
781 }
782
783 bundle = _SC_CFBundleGet();
784 if (bundle != NULL) {
785 if (setPrivate->name != NULL) {
786 CFStringRef non_localized;
787
788 non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
789 CFSTR("DEFAULT_SET_NAME"),
790 CFSTR("Automatic"),
791 NULL);
792 if (non_localized != NULL) {
793 if (CFEqual(setPrivate->name, non_localized)) {
794 CFStringRef localized;
795
796 // if "Automatic", return localized name
797 localized = CFBundleCopyLocalizedString(bundle,
798 CFSTR("DEFAULT_SET_NAME"),
799 CFSTR("Automatic"),
800 NULL);
801 if (localized != NULL) {
802 CFRelease(setPrivate->name);
803 setPrivate->name = localized;
804 }
805 }
806
807 CFRelease(non_localized);
808 }
809 }
810 }
811
812 return setPrivate->name;
813 }
814
815
816 CFArrayRef /* of serviceID CFStringRef's */
817 SCNetworkSetGetServiceOrder(SCNetworkSetRef set)
818 {
819 CFDictionaryRef dict;
820 CFStringRef path;
821 CFArrayRef serviceOrder;
822 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
823
824 if (!isA_SCNetworkSet(set)) {
825 _SCErrorSet(kSCStatusInvalidArgument);
826 return NULL;
827 }
828
829 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
830 if (path == NULL) {
831 return NULL;
832 }
833
834 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
835 CFRelease(path);
836 if (!isA_CFDictionary(dict)) {
837 return NULL;
838 }
839
840 serviceOrder = CFDictionaryGetValue(dict, kSCPropNetServiceOrder);
841 serviceOrder = isA_CFArray(serviceOrder);
842
843 return serviceOrder;
844 }
845
846
847 CFTypeID
848 SCNetworkSetGetTypeID(void)
849 {
850 pthread_once(&initialized, __SCNetworkSetInitialize); /* initialize runtime */
851 return __kSCNetworkSetTypeID;
852 }
853
854
855 Boolean
856 SCNetworkSetRemove(SCNetworkSetRef set)
857 {
858 CFStringRef currentPath;
859 Boolean ok = FALSE;
860 CFStringRef path;
861 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
862
863 if (!isA_SCNetworkSet(set)) {
864 _SCErrorSet(kSCStatusInvalidArgument);
865 return FALSE;
866 }
867
868 currentPath = SCPreferencesGetValue(setPrivate->prefs, kSCPrefCurrentSet);
869 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
870 if (!isA_CFString(currentPath) || !CFEqual(currentPath, path)) {
871 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
872 }
873 CFRelease(path);
874
875 return ok;
876 }
877
878
879 Boolean
880 SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service)
881 {
882 SCNetworkInterfaceRef interface;
883 CFArrayRef interface_config = NULL;
884 Boolean ok;
885 CFStringRef path;
886 int sc_status = kSCStatusOK;
887 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
888 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
889
890 if (!isA_SCNetworkSet(set)) {
891 _SCErrorSet(kSCStatusInvalidArgument);
892 return FALSE;
893 }
894
895 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
896 _SCErrorSet(kSCStatusInvalidArgument);
897 return FALSE;
898 }
899
900 // remove service from ServiceOrder
901 _serviceOrder_remove(set, service);
902
903 // get the [deep] interface configuration settings
904 interface = SCNetworkServiceGetInterface(service);
905 if (interface != NULL) {
906 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface);
907 if (interface_config != NULL) {
908 // remove the interface configuration from all sets which contain this service.
909 __SCNetworkInterfaceSetDeepConfiguration(set, interface, NULL);
910 }
911 }
912
913 // remove the link between "set" and the "service"
914 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
915 setPrivate->setID,
916 servicePrivate->serviceID,
917 NULL);
918 ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
919 if (!ok) {
920 sc_status = SCError(); // preserve the error
921 }
922 CFRelease(path);
923
924 // push the [deep] interface configuration [back] into all sets which contain the service.
925 if (interface_config != NULL) {
926 __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config);
927 }
928
929 if (interface_config != NULL) CFRelease(interface_config);
930 if (!ok) {
931 _SCErrorSet(sc_status);
932 }
933 return ok;
934 }
935
936
937 Boolean
938 SCNetworkSetSetCurrent(SCNetworkSetRef set)
939 {
940 Boolean ok;
941 CFStringRef path;
942 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
943
944 if (!isA_SCNetworkSet(set)) {
945 _SCErrorSet(kSCStatusInvalidArgument);
946 return FALSE;
947 }
948
949 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
950 ok = SCPreferencesSetValue(setPrivate->prefs, kSCPrefCurrentSet, path);
951 CFRelease(path);
952 return ok;
953 }
954
955
956 Boolean
957 SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
958 {
959 CFBundleRef bundle = NULL;
960 CFDictionaryRef entity;
961 CFStringRef localized = NULL;
962 CFStringRef non_localized = NULL;
963 Boolean ok = FALSE;
964 CFStringRef path;
965 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
966
967 if (!isA_SCNetworkSet(set)) {
968 _SCErrorSet(kSCStatusInvalidArgument);
969 return FALSE;
970 }
971
972 if ((name != NULL) && !isA_CFString(name)) {
973 _SCErrorSet(kSCStatusInvalidArgument);
974 return FALSE;
975 }
976
977 // if known, compare against localized name
978
979 if (name != NULL) {
980 bundle = _SC_CFBundleGet();
981 if (bundle != NULL) {
982 non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
983 CFSTR("DEFAULT_SET_NAME"),
984 CFSTR("Automatic"),
985 NULL);
986 if (non_localized != NULL) {
987 if (CFEqual(name, non_localized)) {
988 localized = CFBundleCopyLocalizedString(bundle,
989 CFSTR("DEFAULT_SET_NAME"),
990 CFSTR("Automatic"),
991 NULL);
992 if (localized != NULL) {
993 name = localized;
994 }
995 }
996 }
997 }
998 }
999
1000 #define PREVENT_DUPLICATE_SET_NAMES
1001 #ifdef PREVENT_DUPLICATE_SET_NAMES
1002 if (name != NULL) {
1003 CFArrayRef sets;
1004
1005 // ensure that each set is uniquely named
1006
1007 sets = SCNetworkSetCopyAll(setPrivate->prefs);
1008 if (sets != NULL) {
1009 CFIndex i;
1010 CFIndex n;
1011
1012 n = CFArrayGetCount(sets);
1013 for (i = 0; i < n; i++) {
1014 CFStringRef otherID;
1015 CFStringRef otherName;
1016 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, i);
1017
1018 otherID = SCNetworkSetGetSetID(set);
1019 if (CFEqual(setPrivate->setID, otherID)) {
1020 continue; // skip current set
1021 }
1022
1023 otherName = SCNetworkSetGetName(set);
1024 if ((otherName != NULL) && CFEqual(name, otherName)) {
1025 // if "name" not unique
1026 CFRelease(sets);
1027 _SCErrorSet(kSCStatusKeyExists);
1028 goto done;
1029 }
1030 }
1031 CFRelease(sets);
1032 }
1033 }
1034 #endif /* PREVENT_DUPLICATE_SET_NAMES */
1035
1036 // if known, store non-localized name
1037
1038 if ((name != NULL) && (bundle != NULL) && (non_localized != NULL)) {
1039 if (localized == NULL) {
1040 localized = CFBundleCopyLocalizedString(bundle,
1041 CFSTR("DEFAULT_SET_NAME"),
1042 CFSTR("Automatic"),
1043 NULL);
1044 }
1045
1046 if (localized != NULL) {
1047 if (CFEqual(name, localized)) {
1048 name = non_localized;
1049 }
1050 }
1051 }
1052
1053 // update the "name"
1054
1055 path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
1056 entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
1057 if (isA_CFDictionary(entity) ||
1058 ((entity == NULL) && (name != NULL))) {
1059 CFMutableDictionaryRef newEntity;
1060
1061 if (entity != NULL) {
1062 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1063 } else {
1064 newEntity = CFDictionaryCreateMutable(NULL,
1065 0,
1066 &kCFTypeDictionaryKeyCallBacks,
1067 &kCFTypeDictionaryValueCallBacks);
1068 }
1069 if (name != NULL) {
1070 CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
1071 } else {
1072 CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
1073 }
1074 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newEntity);
1075 CFRelease(newEntity);
1076 }
1077 CFRelease(path);
1078
1079 done :
1080
1081 if (localized != NULL) CFRelease(localized);
1082 if (non_localized != NULL) CFRelease(non_localized);
1083 return ok;
1084 }
1085
1086
1087 Boolean
1088 SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
1089 {
1090 CFDictionaryRef dict;
1091 CFMutableDictionaryRef newDict;
1092 Boolean ok;
1093 CFStringRef path;
1094 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1095
1096 if (!isA_SCNetworkSet(set)) {
1097 _SCErrorSet(kSCStatusInvalidArgument);
1098 return FALSE;
1099 }
1100
1101 if (isA_CFArray(newOrder)) {
1102 CFIndex i;
1103 CFIndex n = CFArrayGetCount(newOrder);
1104
1105 for (i = 0; i < n; i++) {
1106 CFStringRef serviceID;
1107
1108 serviceID = CFArrayGetValueAtIndex(newOrder, i);
1109 if (!isA_CFString(serviceID)) {
1110 _SCErrorSet(kSCStatusInvalidArgument);
1111 return FALSE;
1112 }
1113 }
1114 } else {
1115 _SCErrorSet(kSCStatusInvalidArgument);
1116 return FALSE;
1117 }
1118
1119 path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
1120 if (path == NULL) {
1121 return FALSE;
1122 }
1123
1124 dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
1125 if (dict != NULL) {
1126 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
1127 } else {
1128 newDict = CFDictionaryCreateMutable(NULL,
1129 0,
1130 &kCFTypeDictionaryKeyCallBacks,
1131 &kCFTypeDictionaryValueCallBacks);
1132 }
1133
1134 CFDictionarySetValue(newDict, kSCPropNetServiceOrder, newOrder);
1135 ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newDict);
1136 CFRelease(newDict);
1137 CFRelease(path);
1138
1139 return ok;
1140 }
1141
1142
1143 #pragma mark -
1144 #pragma mark SCNetworkSet SPIs
1145
1146
1147 static void
1148 add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface)
1149 {
1150 CFIndex i;
1151 CFArrayRef interface_types;
1152 CFIndex n;
1153
1154 interface_types = SCNetworkInterfaceGetSupportedInterfaceTypes(interface);
1155 n = (interface_types != NULL) ? CFArrayGetCount(interface_types) : 0;
1156 for (i = 0; i < n; i++) {
1157 SCNetworkInterfaceRef parent;
1158 CFStringRef interface_type;
1159
1160 interface_type = CFArrayGetValueAtIndex(interface_types, i);
1161 parent = SCNetworkInterfaceCreateWithInterface(interface, interface_type);
1162 if (parent != NULL) {
1163 CFArrayAppendValue(interface_list, parent);
1164 CFRelease(parent);
1165 }
1166 }
1167
1168 return;
1169 }
1170
1171
1172 static CFStringRef
1173 next_service_name(SCNetworkServiceRef service)
1174 {
1175 CFArrayRef components;
1176 CFIndex n;
1177 CFStringRef name;
1178 CFMutableArrayRef newComponents;
1179 SInt32 suffix = 2;
1180
1181 name = SCNetworkServiceGetName(service);
1182 if (name == NULL) {
1183 return NULL;
1184 }
1185
1186 components = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR(" "));
1187 if (components != NULL) {
1188 newComponents = CFArrayCreateMutableCopy(NULL, 0, components);
1189 CFRelease(components);
1190 } else {
1191 newComponents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1192 CFArrayAppendValue(newComponents, name);
1193 }
1194
1195 n = CFArrayGetCount(newComponents);
1196 if (n > 1) {
1197 CFStringRef str;
1198
1199 str = CFArrayGetValueAtIndex(newComponents, n - 1);
1200 suffix = CFStringGetIntValue(str);
1201 if (suffix++ > 0) {
1202 CFArrayRemoveValueAtIndex(newComponents, n - 1);
1203 } else {
1204 suffix = 2;
1205 }
1206 }
1207
1208 name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), suffix);
1209 CFArrayAppendValue(newComponents, name);
1210 CFRelease(name);
1211
1212 name = CFStringCreateByCombiningStrings(NULL, newComponents, CFSTR(" "));
1213 CFRelease(newComponents);
1214
1215 return name;
1216 }
1217
1218
1219 static Boolean
1220 __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces)
1221 {
1222 CFIndex i;
1223 CFIndex n;
1224 Boolean ok = TRUE;
1225 CFArrayRef services;
1226 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1227 Boolean updated = FALSE;
1228
1229 // first, assume that we only want to add new services
1230 // for those interfaces that are not represented in the
1231 // current set.
1232 services = SCNetworkSetCopyServices(set);
1233 if ((services != NULL) && setPrivate->established) {
1234 // but, if we are given an existing (or "established") set
1235 // than we only want to add new services for those interfaces
1236 // that are not represented in *any* set.
1237 CFRelease(services);
1238 services = SCNetworkServiceCopyAll(setPrivate->prefs);
1239 }
1240
1241 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
1242 for (i = 0; i < n; i++) {
1243 SCNetworkInterfaceRef interface;
1244 CFMutableArrayRef interface_list;
1245
1246 interface = CFArrayGetValueAtIndex(interfaces, i);
1247 if (_SCNetworkServiceExistsForInterface(services, interface)) {
1248 // if this is not a new interface
1249 continue;
1250 }
1251
1252 interface_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1253 CFArrayAppendValue(interface_list, interface);
1254
1255 while (ok && (CFArrayGetCount(interface_list) > 0)) {
1256 CFArrayRef protocol_types;
1257
1258 interface = CFArrayGetValueAtIndex(interface_list, 0);
1259
1260 protocol_types = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
1261 if ((protocol_types != NULL) && (CFArrayGetCount(protocol_types) > 0)) {
1262 SCNetworkServiceRef service;
1263
1264 service = SCNetworkServiceCreate(setPrivate->prefs, interface);
1265 if (service == NULL) {
1266 SCLog(TRUE, LOG_DEBUG,
1267 CFSTR("could not create service for \"%@\": %s\n"),
1268 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1269 SCErrorString(SCError()));
1270 ok = FALSE;
1271 goto nextInterface;
1272 }
1273
1274 ok = SCNetworkServiceEstablishDefaultConfiguration(service);
1275 if (!ok) {
1276 SCLog(TRUE, LOG_DEBUG,
1277 CFSTR("could not estabish default configuration for \"%@\": %s\n"),
1278 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1279 SCErrorString(SCError()));
1280 SCNetworkServiceRemove(service);
1281 CFRelease(service);
1282 goto nextInterface;
1283 }
1284
1285 while (TRUE) {
1286 CFStringRef newName;
1287
1288 ok = SCNetworkSetAddService(set, service);
1289 if (ok) {
1290 break;
1291 }
1292
1293 if (SCError() != kSCStatusKeyExists) {
1294 SCLog(TRUE, LOG_DEBUG,
1295 CFSTR("could not add service for \"%@\": %s\n"),
1296 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1297 SCErrorString(SCError()));
1298 SCNetworkServiceRemove(service);
1299 CFRelease(service);
1300 goto nextInterface;
1301 }
1302
1303 // we have two interfaces with the same service
1304 // name, acquire a new, hopefully unique, name
1305
1306 newName = next_service_name(service);
1307 if (newName == NULL) {
1308 SCLog(TRUE, LOG_DEBUG,
1309 CFSTR("could not set unique name for \"%@\": %s\n"),
1310 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1311 SCErrorString(SCError()));
1312 SCNetworkServiceRemove(service);
1313 CFRelease(service);
1314 goto nextInterface;
1315 }
1316
1317 ok = SCNetworkServiceSetName(service, newName);
1318 CFRelease(newName);
1319 if (ok) {
1320 continue;
1321 }
1322
1323 if (SCError() != kSCStatusKeyExists) {
1324 SCLog(TRUE, LOG_DEBUG,
1325 CFSTR("could not set unique name for \"%@\": %s\n"),
1326 SCNetworkInterfaceGetLocalizedDisplayName(interface),
1327 SCErrorString(SCError()));
1328 SCNetworkServiceRemove(service);
1329 CFRelease(service);
1330 goto nextInterface;
1331 }
1332 }
1333
1334 CFRelease(service);
1335 updated = TRUE;
1336 } else {
1337 add_supported_interfaces(interface_list, interface);
1338 }
1339
1340 nextInterface :
1341
1342 CFArrayRemoveValueAtIndex(interface_list, 0);
1343 }
1344 CFRelease(interface_list);
1345 }
1346 if (services != NULL) CFRelease(services);
1347
1348 if (ok && !updated) {
1349 // if no changes were made
1350 _SCErrorSet(kSCStatusOK);
1351 }
1352
1353 return updated;
1354 }
1355
1356
1357 Boolean
1358 SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set)
1359 {
1360 CFArrayRef interfaces;
1361 Boolean updated;
1362
1363 if (!isA_SCNetworkSet(set)) {
1364 _SCErrorSet(kSCStatusInvalidArgument);
1365 return FALSE;
1366 }
1367
1368 interfaces = SCNetworkInterfaceCopyAll();
1369 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
1370 if (interfaces != NULL) CFRelease(interfaces);
1371
1372 return updated;
1373 }
1374
1375
1376 Boolean
1377 SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
1378 {
1379 CFMutableArrayRef interfaces;
1380 Boolean updated;
1381
1382 if (!isA_SCNetworkSet(set)) {
1383 _SCErrorSet(kSCStatusInvalidArgument);
1384 return FALSE;
1385 }
1386
1387 if (!isA_SCNetworkInterface(interface)) {
1388 _SCErrorSet(kSCStatusInvalidArgument);
1389 return FALSE;
1390 }
1391
1392 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1393 CFArrayAppendValue(interfaces, interface);
1394 updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
1395 CFRelease(interfaces);
1396
1397 return updated;
1398 }