]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkService.c
5a19657584f3eae3bfa6d9291bc3350ff52f0dce
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkService.c
1 /*
2 * Copyright (c) 2004-2013 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 #define EXTERNAL_ID_DOMAIN_PREFIX "_"
42
43 static CFStringRef __SCNetworkServiceCopyDescription (CFTypeRef cf);
44 static void __SCNetworkServiceDeallocate (CFTypeRef cf);
45 static Boolean __SCNetworkServiceEqual (CFTypeRef cf1, CFTypeRef cf2);
46 static CFHashCode __SCNetworkServiceHash (CFTypeRef cf);
47
48
49 static CFTypeID __kSCNetworkServiceTypeID = _kCFRuntimeNotATypeID;
50
51
52 static const CFRuntimeClass __SCNetworkServiceClass = {
53 0, // version
54 "SCNetworkService", // className
55 NULL, // init
56 NULL, // copy
57 __SCNetworkServiceDeallocate, // dealloc
58 __SCNetworkServiceEqual, // equal
59 __SCNetworkServiceHash, // hash
60 NULL, // copyFormattingDesc
61 __SCNetworkServiceCopyDescription // copyDebugDesc
62 };
63
64
65 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
66
67
68 static CFStringRef
69 __SCNetworkServiceCopyDescription(CFTypeRef cf)
70 {
71 CFAllocatorRef allocator = CFGetAllocator(cf);
72 CFMutableStringRef result;
73 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
74
75 result = CFStringCreateMutable(allocator, 0);
76 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkService %p [%p]> {"), cf, allocator);
77 CFStringAppendFormat(result, NULL, CFSTR("id = %@"), servicePrivate->serviceID);
78 if (servicePrivate->prefs != NULL) {
79 CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), servicePrivate->prefs);
80 } else if (servicePrivate->store != NULL) {
81 CFStringAppendFormat(result, NULL, CFSTR(", store = %p"), servicePrivate->store);
82 }
83 if (servicePrivate->name != NULL) {
84 CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), servicePrivate->name);
85 }
86 CFStringAppendFormat(result, NULL, CFSTR("}"));
87
88 return result;
89 }
90
91
92 static void
93 __SCNetworkServiceDeallocate(CFTypeRef cf)
94 {
95 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
96
97 /* release resources */
98
99 CFRelease(servicePrivate->serviceID);
100 if (servicePrivate->interface != NULL) CFRelease(servicePrivate->interface);
101 if (servicePrivate->prefs != NULL) CFRelease(servicePrivate->prefs);
102 if (servicePrivate->store != NULL) CFRelease(servicePrivate->store);
103 if (servicePrivate->name != NULL) CFRelease(servicePrivate->name);
104 if (servicePrivate->externalIDs != NULL) CFRelease(servicePrivate->externalIDs);
105
106 return;
107 }
108
109
110 static Boolean
111 __SCNetworkServiceEqual(CFTypeRef cf1, CFTypeRef cf2)
112 {
113 SCNetworkServicePrivateRef s1 = (SCNetworkServicePrivateRef)cf1;
114 SCNetworkServicePrivateRef s2 = (SCNetworkServicePrivateRef)cf2;
115
116 if (s1 == s2)
117 return TRUE;
118
119 if (s1->prefs != s2->prefs)
120 return FALSE; // if not the same prefs
121
122 if (!CFEqual(s1->serviceID, s2->serviceID))
123 return FALSE; // if not the same service identifier
124
125 return TRUE;
126 }
127
128
129 static CFHashCode
130 __SCNetworkServiceHash(CFTypeRef cf)
131 {
132 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
133
134 return CFHash(servicePrivate->serviceID);
135 }
136
137
138 static void
139 __SCNetworkServiceInitialize(void)
140 {
141 __kSCNetworkServiceTypeID = _CFRuntimeRegisterClass(&__SCNetworkServiceClass);
142 return;
143 }
144
145
146 __private_extern__ SCNetworkServicePrivateRef
147 __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator,
148 SCPreferencesRef prefs,
149 CFStringRef serviceID,
150 SCNetworkInterfaceRef interface)
151 {
152 SCNetworkServicePrivateRef servicePrivate;
153 uint32_t size;
154
155 /* initialize runtime */
156 pthread_once(&initialized, __SCNetworkServiceInitialize);
157
158 /* allocate target */
159 size = sizeof(SCNetworkServicePrivate) - sizeof(CFRuntimeBase);
160 servicePrivate = (SCNetworkServicePrivateRef)_CFRuntimeCreateInstance(allocator,
161 __kSCNetworkServiceTypeID,
162 size,
163 NULL);
164 if (servicePrivate == NULL) {
165 return NULL;
166 }
167
168 servicePrivate->prefs = (prefs != NULL) ? CFRetain(prefs): NULL;
169 servicePrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
170 servicePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL;
171 servicePrivate->name = NULL;
172
173 return servicePrivate;
174 }
175
176
177 #pragma mark -
178 #pragma mark Service ordering
179
180
181 CFComparisonResult
182 _SCNetworkServiceCompare(const void *val1, const void *val2, void *context)
183 {
184 CFStringRef id1;
185 CFStringRef id2;
186 CFArrayRef order = (CFArrayRef)context;
187 SCNetworkServiceRef s1 = (SCNetworkServiceRef)val1;
188 SCNetworkServiceRef s2 = (SCNetworkServiceRef)val2;
189
190 id1 = SCNetworkServiceGetServiceID(s1);
191 id2 = SCNetworkServiceGetServiceID(s2);
192
193 if (order != NULL) {
194 CFIndex o1;
195 CFIndex o2;
196 CFRange range;
197
198 range = CFRangeMake(0, CFArrayGetCount(order));
199 o1 = CFArrayGetFirstIndexOfValue(order, range, id1);
200 o2 = CFArrayGetFirstIndexOfValue(order, range, id2);
201
202 if (o1 > o2) {
203 return (o2 != kCFNotFound) ? kCFCompareGreaterThan : kCFCompareLessThan;
204 } else if (o1 < o2) {
205 return (o1 != kCFNotFound) ? kCFCompareLessThan : kCFCompareGreaterThan;
206 }
207 }
208
209 return CFStringCompare(id1, id2, 0);
210 }
211
212
213 #pragma mark -
214 #pragma mark SCNetworkService APIs
215
216
217 #define N_QUICK 64
218
219
220 __private_extern__ CFArrayRef /* of SCNetworkServiceRef's */
221 __SCNetworkServiceCopyAllEnabled(SCPreferencesRef prefs)
222 {
223 CFMutableArrayRef array = NULL;
224 CFIndex i_sets;
225 CFIndex n_sets;
226 CFArrayRef sets;
227
228 sets = SCNetworkSetCopyAll(prefs);
229 if (sets == NULL) {
230 return NULL;
231 }
232
233 n_sets = CFArrayGetCount(sets);
234 for (i_sets = 0; i_sets < n_sets; i_sets++) {
235 CFIndex i_services;
236 CFIndex n_services;
237 CFArrayRef services;
238 SCNetworkSetRef set;
239
240 set = CFArrayGetValueAtIndex(sets, i_sets);
241 services = SCNetworkSetCopyServices(set);
242 if (services == NULL) {
243 continue;
244 }
245
246 n_services = CFArrayGetCount(services);
247 for (i_services = 0; i_services < n_services; i_services++) {
248 SCNetworkServiceRef service;
249
250 service = CFArrayGetValueAtIndex(services, i_services);
251 if (!SCNetworkServiceGetEnabled(service)) {
252 // if not enabled
253 continue;
254 }
255
256 if ((array == NULL) ||
257 !CFArrayContainsValue(array,
258 CFRangeMake(0, CFArrayGetCount(array)),
259 service)) {
260 if (array == NULL) {
261 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
262 }
263 CFArrayAppendValue(array, service);
264 }
265 }
266 CFRelease(services);
267 }
268 CFRelease(sets);
269
270 return array;
271 }
272
273
274 __private_extern__ Boolean
275 __SCNetworkServiceExistsForInterface(CFArrayRef services, SCNetworkInterfaceRef interface)
276 {
277 CFIndex i;
278 CFIndex n;
279
280 n = isA_CFArray(services) ? CFArrayGetCount(services) : 0;
281 for (i = 0; i < n; i++) {
282 SCNetworkServiceRef service;
283 SCNetworkInterfaceRef service_interface;
284
285 service = CFArrayGetValueAtIndex(services, i);
286
287 service_interface = SCNetworkServiceGetInterface(service);
288 while (service_interface != NULL) {
289 if (CFEqual(interface, service_interface)) {
290 return TRUE;
291 }
292
293 service_interface = SCNetworkInterfaceGetInterface(service_interface);
294 }
295 }
296
297 return FALSE;
298 }
299
300
301 __private_extern__ CF_RETURNS_RETAINED CFStringRef
302 __SCNetworkServiceNextName(SCNetworkServiceRef service)
303 {
304 CFArrayRef components;
305 CFIndex n;
306 CFStringRef name;
307 CFMutableArrayRef newComponents;
308 SInt32 suffix = 2;
309
310 name = SCNetworkServiceGetName(service);
311 if (name == NULL) {
312 return NULL;
313 }
314
315 components = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR(" "));
316 if (components != NULL) {
317 newComponents = CFArrayCreateMutableCopy(NULL, 0, components);
318 CFRelease(components);
319 } else {
320 newComponents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
321 CFArrayAppendValue(newComponents, name);
322 }
323
324 n = CFArrayGetCount(newComponents);
325 if (n > 1) {
326 CFStringRef str;
327
328 str = CFArrayGetValueAtIndex(newComponents, n - 1);
329 suffix = CFStringGetIntValue(str);
330 if (suffix++ > 0) {
331 CFArrayRemoveValueAtIndex(newComponents, n - 1);
332 } else {
333 suffix = 2;
334 }
335 }
336
337 name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), (int)suffix);
338 CFArrayAppendValue(newComponents, name);
339 CFRelease(name);
340
341 name = CFStringCreateByCombiningStrings(NULL, newComponents, CFSTR(" "));
342 CFRelease(newComponents);
343
344 return name;
345 }
346
347
348 static void
349 mergeDict(const void *key, const void *value, void *context)
350 {
351 CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context;
352
353 CFDictionarySetValue(newDict, key, value);
354 return;
355 }
356
357
358 static CF_RETURNS_RETAINED CFDictionaryRef
359 _protocolTemplate(SCNetworkServiceRef service, CFStringRef protocolType)
360 {
361 SCNetworkInterfaceRef interface;
362 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
363 CFDictionaryRef template = NULL;
364
365 interface = servicePrivate->interface;
366 if (interface != NULL) {
367 SCNetworkInterfaceRef childInterface;
368 CFStringRef childInterfaceType = NULL;
369 CFStringRef interfaceType;
370
371 // get the template
372 interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface);
373 childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface);
374 if (childInterface != NULL) {
375 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
376 }
377
378 template = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType);
379 if (template != NULL) {
380 CFDictionaryRef overrides;
381
382 // move to the interface at the lowest layer
383 while (childInterface != NULL) {
384 interface = childInterface;
385 childInterface = SCNetworkInterfaceGetInterface(interface);
386 }
387
388 overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, protocolType);
389 if (overrides != NULL) {
390 CFMutableDictionaryRef newTemplate;
391
392 newTemplate = CFDictionaryCreateMutableCopy(NULL, 0, template);
393 CFDictionaryApplyFunction(overrides, mergeDict, newTemplate);
394 CFRelease(template);
395 template = newTemplate;
396 }
397 }
398 }
399
400 if (template == NULL) {
401 template = CFDictionaryCreate(NULL,
402 NULL,
403 NULL,
404 0,
405 &kCFTypeDictionaryKeyCallBacks,
406 &kCFTypeDictionaryValueCallBacks);
407 }
408
409 return template;
410 }
411
412
413 Boolean
414 SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
415 {
416 CFDictionaryRef entity;
417 CFDictionaryRef newEntity = NULL;
418 Boolean ok = FALSE;
419 CFStringRef path;
420 SCNetworkProtocolRef protocol;
421 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
422
423 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
424 _SCErrorSet(kSCStatusInvalidArgument);
425 return FALSE;
426 }
427
428 if (!__SCNetworkProtocolIsValidType(protocolType)) {
429 _SCErrorSet(kSCStatusInvalidArgument);
430 return FALSE;
431 }
432
433 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
434 servicePrivate->serviceID, // service
435 protocolType); // entity
436
437 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
438 if (entity != NULL) {
439 // if "protocol" already exists
440 _SCErrorSet(kSCStatusKeyExists);
441 goto done;
442 }
443
444 newEntity = CFDictionaryCreate(NULL,
445 NULL,
446 NULL,
447 0,
448 &kCFTypeDictionaryKeyCallBacks,
449 &kCFTypeDictionaryValueCallBacks);
450 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
451 CFRelease(newEntity);
452 if (!ok) {
453 goto done;
454 }
455
456 protocol = SCNetworkServiceCopyProtocol(service, protocolType);
457 assert(protocol != NULL);
458
459 newEntity = _protocolTemplate(service, protocolType);
460 ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
461 CFRelease(newEntity);
462 CFRelease(protocol);
463
464 done :
465
466 CFRelease(path);
467 return ok;
468 }
469
470
471 CFArrayRef /* of SCNetworkServiceRef's */
472 SCNetworkServiceCopyAll(SCPreferencesRef prefs)
473 {
474 CFMutableArrayRef array;
475 CFIndex n;
476 CFStringRef path;
477 CFDictionaryRef services;
478
479 path = SCPreferencesPathKeyCreateNetworkServices(NULL);
480 services = SCPreferencesPathGetValue(prefs, path);
481 CFRelease(path);
482
483 if ((services != NULL) && !isA_CFDictionary(services)) {
484 return NULL;
485 }
486
487 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
488
489 n = (services != NULL) ? CFDictionaryGetCount(services) : 0;
490 if (n > 0) {
491 CFIndex i;
492 const void * keys_q[N_QUICK];
493 const void ** keys = keys_q;
494 const void * vals_q[N_QUICK];
495 const void ** vals = vals_q;
496
497 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
498 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
499 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
500 }
501 CFDictionaryGetKeysAndValues(services, keys, vals);
502 for (i = 0; i < n; i++) {
503 CFDictionaryRef entity;
504 SCNetworkServicePrivateRef servicePrivate;
505
506 if (!isA_CFDictionary(vals[i])) {
507 SCLog(TRUE,
508 LOG_INFO,
509 CFSTR("SCNetworkServiceCopyAll(): error w/service \"%@\"\n"),
510 keys[i]);
511 continue;
512 }
513
514 entity = CFDictionaryGetValue(vals[i], kSCEntNetInterface);
515 if (!isA_CFDictionary(entity)) {
516 // if no "interface"
517 SCLog(TRUE,
518 LOG_INFO,
519 CFSTR("SCNetworkServiceCopyAll(): no \"%@\" entity for service \"%@\"\n"),
520 kSCEntNetInterface,
521 keys[i]);
522 continue;
523 }
524
525 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, keys[i], NULL);
526 assert(servicePrivate != NULL);
527 CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
528 CFRelease(servicePrivate);
529 }
530 if (keys != keys_q) {
531 CFAllocatorDeallocate(NULL, keys);
532 CFAllocatorDeallocate(NULL, vals);
533 }
534 }
535
536 return array;
537 }
538
539
540 /*
541 * build a list of all of a servives entity types that are associated
542 * with the services interface. The list will include :
543 *
544 * - entity types associated with the interface type (Ethernet, FireWire, PPP, ...)
545 * - entity types associated with the interface sub-type (PPPSerial, PPPoE, L2TP, PPTP, ...)
546 * - entity types associated with the hardware device (Ethernet, AirPort, FireWire, Modem, ...)
547 */
548 static CFSetRef
549 _copyInterfaceEntityTypes(CFDictionaryRef protocols)
550 {
551 CFDictionaryRef interface;
552 CFMutableSetRef interface_entity_types;
553
554 interface_entity_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
555
556 interface = CFDictionaryGetValue(protocols, kSCEntNetInterface);
557 if (isA_CFDictionary(interface)) {
558 CFStringRef entities[] = { kSCPropNetInterfaceType,
559 kSCPropNetInterfaceSubType,
560 kSCPropNetInterfaceHardware };
561 int i;
562
563 // include the "Interface" entity itself
564 CFSetAddValue(interface_entity_types, kSCEntNetInterface);
565
566 // include the entities associated with the interface
567 for (i = 0; i < sizeof(entities)/sizeof(entities[0]); i++) {
568 CFStringRef entity;
569
570 entity = CFDictionaryGetValue(interface, entities[i]);
571 if (isA_CFString(entity)) {
572 CFSetAddValue(interface_entity_types, entity);
573 }
574 }
575
576 /*
577 * and, because we've found some misguided network preference code
578 * developers leaving [PPP] entity dictionaries around even though
579 * they are unused and/or unneeded...
580 */
581 CFSetAddValue(interface_entity_types, kSCEntNetPPP);
582 }
583
584 return interface_entity_types;
585 }
586
587
588 SCNetworkServiceRef
589 SCNetworkServiceCopy(SCPreferencesRef prefs, CFStringRef serviceID)
590 {
591 CFDictionaryRef entity;
592 CFStringRef path;
593 SCNetworkServicePrivateRef servicePrivate;
594
595 if (!isA_CFString(serviceID)) {
596 _SCErrorSet(kSCStatusInvalidArgument);
597 return NULL;
598 }
599
600 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
601 serviceID, // service
602 kSCEntNetInterface); // entity
603 entity = SCPreferencesPathGetValue(prefs, path);
604 CFRelease(path);
605
606 if (!isA_CFDictionary(entity)) {
607 // a "service" must have an "interface"
608 _SCErrorSet(kSCStatusNoKey);
609 return NULL;
610 }
611
612 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
613 return (SCNetworkServiceRef)servicePrivate;
614 }
615
616
617 SCNetworkServiceRef
618 _SCNetworkServiceCopyActive(SCDynamicStoreRef store, CFStringRef serviceID)
619 {
620 SCNetworkServicePrivateRef servicePrivate;
621
622 if (!isA_CFString(serviceID)) {
623 _SCErrorSet(kSCStatusInvalidArgument);
624 return NULL;
625 }
626
627 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, NULL, serviceID, NULL);
628 assert(servicePrivate != NULL);
629 if (store != NULL) {
630 servicePrivate->store = CFRetain(store);
631 }
632 return (SCNetworkServiceRef)servicePrivate;
633 }
634
635
636 SCNetworkProtocolRef
637 SCNetworkServiceCopyProtocol(SCNetworkServiceRef service, CFStringRef protocolType)
638 {
639 CFSetRef non_protocol_entities;
640 CFStringRef path;
641 CFDictionaryRef protocols;
642 SCNetworkProtocolPrivateRef protocolPrivate = NULL;
643 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
644
645 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
646 _SCErrorSet(kSCStatusInvalidArgument);
647 return NULL;
648 }
649
650 if (!isA_CFString(protocolType)) {
651 _SCErrorSet(kSCStatusInvalidArgument);
652 return NULL;
653 }
654
655 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
656 servicePrivate->serviceID, // service
657 NULL); // entity
658 protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
659 CFRelease(path);
660
661 if (!isA_CFDictionary(protocols)) {
662 // if corrupt prefs
663 _SCErrorSet(kSCStatusFailed);
664 return NULL;
665 }
666
667 non_protocol_entities = _copyInterfaceEntityTypes(protocols);
668 if (CFSetContainsValue(non_protocol_entities, protocolType)) {
669 // if the "protocolType" matches an interface entity type
670 _SCErrorSet(kSCStatusInvalidArgument);
671 goto done;
672 }
673
674 if (!CFDictionaryContainsKey(protocols, protocolType)) {
675 // if the "protocolType" entity does not exist
676 _SCErrorSet(kSCStatusNoKey);
677 goto done;
678 }
679
680 protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, protocolType, service);
681
682 done :
683
684 CFRelease(non_protocol_entities);
685
686 return (SCNetworkProtocolRef)protocolPrivate;
687 }
688
689
690 CFArrayRef /* of SCNetworkProtocolRef's */
691 SCNetworkServiceCopyProtocols(SCNetworkServiceRef service)
692 {
693 CFMutableArrayRef array;
694 CFIndex n;
695 CFSetRef non_protocol_entities;
696 CFStringRef path;
697 CFDictionaryRef protocols;
698 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
699
700 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
701 _SCErrorSet(kSCStatusInvalidArgument);
702 return NULL;
703 }
704
705 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
706 servicePrivate->serviceID, // service
707 NULL); // entity
708 protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
709 CFRelease(path);
710
711 if (!isA_CFDictionary(protocols)) {
712 // if corrupt prefs
713 _SCErrorSet(kSCStatusFailed);
714 return NULL;
715 }
716
717 non_protocol_entities = _copyInterfaceEntityTypes(protocols);
718
719 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
720
721 n = CFDictionaryGetCount(protocols);
722 if (n > 0) {
723 CFIndex i;
724 const void * keys_q[N_QUICK];
725 const void ** keys = keys_q;
726 const void * vals_q[N_QUICK];
727 const void ** vals = vals_q;
728
729 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
730 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
731 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
732 }
733 CFDictionaryGetKeysAndValues(protocols, keys, vals);
734 for (i = 0; i < n; i++) {
735 SCNetworkProtocolPrivateRef protocolPrivate;
736
737 if (!isA_CFDictionary(vals[i])) {
738 // if it's not a dictionary then it can't be a protocol entity
739 continue;
740 }
741
742 if (CFSetContainsValue(non_protocol_entities, keys[i])) {
743 // skip any non-protocol (interface) entities
744 continue;
745 }
746
747 protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, keys[i], service);
748 CFArrayAppendValue(array, (SCNetworkProtocolRef)protocolPrivate);
749
750 CFRelease(protocolPrivate);
751 }
752 if (keys != keys_q) {
753 CFAllocatorDeallocate(NULL, keys);
754 CFAllocatorDeallocate(NULL, vals);
755 }
756 }
757
758 CFRelease(non_protocol_entities);
759
760 return array;
761 }
762
763
764 static Boolean
765 __SCNetworkServiceSetInterfaceEntity(SCNetworkServiceRef service,
766 SCNetworkInterfaceRef interface)
767 {
768 CFDictionaryRef entity;
769 Boolean ok;
770 CFStringRef path;
771 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
772
773 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
774 servicePrivate->serviceID, // service
775 kSCEntNetInterface); // entity
776 entity = __SCNetworkInterfaceCopyInterfaceEntity(interface);
777 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, entity);
778 CFRelease(entity);
779 CFRelease(path);
780
781 return ok;
782 }
783
784
785 SCNetworkServiceRef
786 SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface)
787 {
788 CFArrayRef components;
789 CFArrayRef interface_config;
790 CFStringRef interface_name;
791 SCNetworkInterfaceRef newInterface;
792 CFStringRef path;
793 CFStringRef prefix;
794 CFStringRef serviceID;
795 SCNetworkServicePrivateRef servicePrivate;
796 CFArrayRef supported_protocols;
797
798 if (!isA_SCNetworkInterface(interface)) {
799 _SCErrorSet(kSCStatusInvalidArgument);
800 return NULL;
801 }
802
803 // only allow network interfaces which support one or more protocols
804 // to be added to a service. The one exception is that we allow
805 // third-party interface types to be configured.
806 supported_protocols = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
807 if (supported_protocols == NULL) {
808 CFStringRef interface_type;
809
810 interface_type = SCNetworkInterfaceGetInterfaceType(interface);
811 if (CFStringFind(interface_type, CFSTR("."), 0).location == kCFNotFound) {
812 _SCErrorSet(kSCStatusInvalidArgument);
813 return NULL;
814 }
815 }
816
817 // do not allow creation of a network service if the interface is a
818 // member of a bond or bridge
819 if (__SCNetworkInterfaceIsMember(prefs, interface)) {
820 _SCErrorSet(kSCStatusKeyExists);
821 return NULL;
822 }
823
824 // establish the service
825 prefix = SCPreferencesPathKeyCreateNetworkServices(NULL);
826 path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
827 if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
828 CFRelease(prefix);
829 if (path == NULL) {
830 return NULL;
831 }
832
833 components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
834 CFRelease(path);
835
836 serviceID = CFArrayGetValueAtIndex(components, 2);
837 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
838 CFRelease(components);
839
840 // duplicate the interface and associate the copy with the new service
841 newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,
842 interface,
843 prefs,
844 serviceID);
845 servicePrivate->interface = newInterface;
846
847 // establish "default" configuration(s) for the interface
848 for (interface = newInterface;
849 interface != NULL;
850 interface = SCNetworkInterfaceGetInterface(interface)) {
851 SCNetworkInterfaceRef childInterface;
852 CFStringRef childInterfaceType = NULL;
853 CFDictionaryRef config;
854 CFStringRef interfaceType;
855
856 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
857 childInterface = SCNetworkInterfaceGetInterface(interface);
858 if (childInterface != NULL) {
859 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
860 }
861
862 config = __copyInterfaceTemplate(interfaceType, childInterfaceType);
863 if (config != NULL) {
864 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBluetooth) ||
865 CFEqual(interfaceType, kSCNetworkInterfaceTypeIrDA ) ||
866 CFEqual(interfaceType, kSCNetworkInterfaceTypeModem ) ||
867 CFEqual(interfaceType, kSCNetworkInterfaceTypeSerial ) ||
868 CFEqual(interfaceType, kSCNetworkInterfaceTypeWWAN )) {
869 CFDictionaryRef overrides;
870
871 overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypeModem);
872
873 // a ConnectionScript (and related keys) from the interface
874 // should trump the settings from the configuration template.
875 if (overrides != NULL) {
876 CFMutableDictionaryRef newConfig;
877
878 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
879 if (CFDictionaryContainsKey(overrides, kSCPropNetModemConnectionScript)) {
880 CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionPersonality);
881 CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionScript);
882 CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceVendor);
883 CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceModel);
884 }
885 CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
886 CFRelease(config);
887 config = newConfig;
888 }
889 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP) ||
890 CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
891 CFDictionaryRef overrides;
892
893 overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypePPP);
894 if (overrides != NULL) {
895 CFMutableDictionaryRef newConfig;
896
897 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
898 CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
899 CFRelease(config);
900 config = newConfig;
901 }
902 }
903
904 if (!__SCNetworkInterfaceSetConfiguration(interface, NULL, config, TRUE)) {
905 SCLog(TRUE, LOG_DEBUG,
906 CFSTR("SCNetworkService __SCNetworkInterfaceSetConfiguration failed(), interface=%@, type=NULL"),
907 interface);
908 }
909 CFRelease(config);
910 }
911 }
912
913 // add the interface [entity] to the service
914 (void) __SCNetworkServiceSetInterfaceEntity((SCNetworkServiceRef)servicePrivate,
915 servicePrivate->interface);
916
917 // push the [deep] interface configuration into the service.
918 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(NULL, servicePrivate->interface);
919 __SCNetworkInterfaceSetDeepConfiguration(NULL, servicePrivate->interface, interface_config);
920 if (interface_config != NULL) CFRelease(interface_config);
921
922 // set the service name to match that of the associated interface
923 //
924 // Note: It might seem a bit odd to call SCNetworkServiceGetName
925 // followed by an immediate call to SCNetworkServiceSetName. The
926 // trick here is that if no name has previously been set, the
927 // "get" function will return the name of the associated interface.
928 //
929 // ... and we "set" a name to ensure that applications that do
930 // not use the APIs will still find a UserDefinedName property
931 // in the SCDynamicStore.
932 //
933 interface_name = SCNetworkServiceGetName((SCNetworkServiceRef)servicePrivate);
934 if (interface_name != NULL) {
935 (void) SCNetworkServiceSetName((SCNetworkServiceRef)servicePrivate,
936 interface_name);
937 }
938
939 return (SCNetworkServiceRef)servicePrivate;
940 }
941
942
943 Boolean
944 SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service)
945 {
946 CFIndex i;
947 SCNetworkInterfaceRef interface;
948 CFIndex n;
949 CFArrayRef protocolTypes;
950 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
951
952 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
953 _SCErrorSet(kSCStatusInvalidArgument);
954 return FALSE;
955 }
956
957 interface = SCNetworkServiceGetInterface(service);
958 if (interface == NULL) {
959 return FALSE;
960 }
961
962 protocolTypes = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
963 n = (protocolTypes != NULL) ? CFArrayGetCount(protocolTypes) : 0;
964 for (i = 0; i < n; i++) {
965 Boolean enabled;
966 CFDictionaryRef newEntity = NULL;
967 Boolean ok;
968 SCNetworkProtocolRef protocol = NULL;
969 CFStringRef protocolType;
970
971 protocolType = CFArrayGetValueAtIndex(protocolTypes, i);
972 ok = SCNetworkServiceAddProtocolType(service, protocolType);
973 if (!ok && (SCError() != kSCStatusKeyExists)) {
974 // could not add protocol
975 goto nextProtocol;
976 }
977
978 protocol = SCNetworkServiceCopyProtocol(service, protocolType);
979 if (protocol == NULL) {
980 // oops, somethings wrong (should never happen)
981 goto nextProtocol;
982 }
983
984 newEntity = _protocolTemplate(service, protocolType);
985 ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
986 if (!ok) {
987 // could not set default configuration
988 goto nextProtocol;
989 }
990
991 enabled = !CFDictionaryContainsKey(newEntity, kSCResvInactive);
992 ok = SCNetworkProtocolSetEnabled(protocol, enabled);
993 if (!ok) {
994 // could not enable/disable protocol
995 goto nextProtocol;
996 }
997
998 nextProtocol :
999
1000 if (newEntity != NULL) CFRelease(newEntity);
1001 if (protocol != NULL) CFRelease(protocol);
1002 }
1003
1004 return TRUE;
1005 }
1006
1007
1008 Boolean
1009 SCNetworkServiceGetEnabled(SCNetworkServiceRef service)
1010 {
1011 Boolean enabled;
1012 CFStringRef path;
1013 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1014
1015 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1016 _SCErrorSet(kSCStatusInvalidArgument);
1017 return FALSE;
1018 }
1019
1020 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1021 servicePrivate->serviceID, // service
1022 NULL); // entity
1023 enabled = __getPrefsEnabled(servicePrivate->prefs, path);
1024 CFRelease(path);
1025
1026 return enabled;
1027 }
1028
1029
1030 SCNetworkInterfaceRef
1031 SCNetworkServiceGetInterface(SCNetworkServiceRef service)
1032 {
1033 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1034
1035 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1036 _SCErrorSet(kSCStatusInvalidArgument);
1037 return NULL;
1038 }
1039
1040 if (servicePrivate->interface == NULL) {
1041 CFDictionaryRef entity;
1042 CFStringRef path;
1043
1044 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1045 servicePrivate->serviceID, // service
1046 kSCEntNetInterface); // entity
1047 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1048 CFRelease(path);
1049
1050 if (isA_CFDictionary(entity)) {
1051 servicePrivate->interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, service);
1052 }
1053 }
1054
1055 return servicePrivate->interface;
1056 }
1057
1058
1059 CFStringRef
1060 SCNetworkServiceGetName(SCNetworkServiceRef service)
1061 {
1062 CFDictionaryRef entity;
1063 SCNetworkInterfaceRef interface;
1064 CFStringRef name = NULL;
1065 CFStringRef path;
1066 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1067
1068 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1069 _SCErrorSet(kSCStatusInvalidArgument);
1070 return NULL;
1071 }
1072
1073 if (servicePrivate->name != NULL) {
1074 return servicePrivate->name;
1075 }
1076
1077 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1078 servicePrivate->serviceID, // service
1079 NULL); // entity
1080 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1081 CFRelease(path);
1082
1083 if (isA_CFDictionary(entity)) {
1084 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
1085 if (isA_CFString(name)) {
1086 servicePrivate->name = CFRetain(name);
1087 }
1088 }
1089
1090 interface = SCNetworkServiceGetInterface(service);
1091 while (interface != NULL) {
1092 SCNetworkInterfaceRef childInterface;
1093 CFStringRef interfaceType;
1094
1095 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
1096 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
1097 break;
1098 }
1099
1100 childInterface = SCNetworkInterfaceGetInterface(interface);
1101 if ((childInterface == NULL) ||
1102 CFEqual(childInterface, kSCNetworkInterfaceIPv4)) {
1103 break;
1104 }
1105
1106 interface = childInterface;
1107 }
1108
1109 if (interface != NULL) {
1110 int i;
1111 CFStringRef interface_name = NULL;
1112 CFStringRef suffix = NULL;
1113
1114 //
1115 // check if the [stored] service name matches the non-localized interface
1116 // name. If so, return the localized name.
1117 //
1118 // Also, the older "Built-in XXX" interface names are too long for the
1119 // current UI. If we find that the [stored] service name matches the older
1120 // name, return the newer (and shorter) localized name.
1121 //
1122 // Note: the user/admin will no longer be able to set the service name
1123 // to "Built-in Ethernet".
1124 //
1125 for (i = 0; i < 3; i++) {
1126 if (servicePrivate->name == NULL) {
1127 // if no [stored] service name to compare
1128 break;
1129 }
1130
1131 switch (i) {
1132 case 0 :
1133 // compare the non-localized interface name
1134 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
1135 if (interface_name != NULL) {
1136 CFRetain(interface_name);
1137 }
1138 break;
1139 #if !TARGET_OS_IPHONE
1140 case 1 :
1141 // compare the older "Built-in XXX" localized name
1142 interface_name = __SCNetworkInterfaceCopyXLocalizedDisplayName(interface);
1143 break;
1144 case 2 :
1145 // compare the older "Built-in XXX" non-localized name
1146 interface_name = __SCNetworkInterfaceCopyXNonLocalizedDisplayName(interface);
1147 break;
1148 #endif // !TARGET_OS_IPHONE
1149 default :
1150 continue;
1151 }
1152
1153 if (interface_name != NULL) {
1154 Boolean match = FALSE;
1155
1156 if (CFEqual(name, interface_name)) {
1157 // if service name matches the OLD localized
1158 // interface name
1159 match = TRUE;
1160 } else if (CFStringHasPrefix(name, interface_name)) {
1161 CFIndex prefixLen = CFStringGetLength(interface_name);
1162 CFIndex suffixLen = CFStringGetLength(name);
1163
1164 suffix = CFStringCreateWithSubstring(NULL,
1165 name,
1166 CFRangeMake(prefixLen, suffixLen - prefixLen));
1167 match = TRUE;
1168 }
1169 CFRelease(interface_name);
1170
1171 if (match) {
1172 CFRelease(servicePrivate->name);
1173 servicePrivate->name = NULL;
1174 break;
1175 }
1176 }
1177 }
1178
1179 //
1180 // if the service name has not been set, use the localized interface name
1181 //
1182 if (servicePrivate->name == NULL) {
1183 interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
1184 if (interface_name != NULL) {
1185 if (suffix != NULL) {
1186 servicePrivate->name = CFStringCreateWithFormat(NULL,
1187 NULL,
1188 CFSTR("%@%@"),
1189 interface_name,
1190 suffix);
1191 } else {
1192 servicePrivate->name = CFRetain(interface_name);
1193 }
1194 }
1195 }
1196 if (suffix != NULL) CFRelease(suffix);
1197 }
1198
1199 return servicePrivate->name;
1200 }
1201
1202
1203 CFStringRef
1204 SCNetworkServiceGetServiceID(SCNetworkServiceRef service)
1205 {
1206 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1207
1208 if (!isA_SCNetworkService(service)) {
1209 _SCErrorSet(kSCStatusInvalidArgument);
1210 return NULL;
1211 }
1212
1213 return servicePrivate->serviceID;
1214 }
1215
1216
1217 CFTypeID
1218 SCNetworkServiceGetTypeID(void)
1219 {
1220 pthread_once(&initialized, __SCNetworkServiceInitialize); /* initialize runtime */
1221 return __kSCNetworkServiceTypeID;
1222 }
1223
1224
1225 Boolean
1226 SCNetworkServiceRemove(SCNetworkServiceRef service)
1227 {
1228 Boolean ok = FALSE;
1229 CFStringRef path;
1230 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1231 CFArrayRef sets;
1232
1233 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1234 _SCErrorSet(kSCStatusInvalidArgument);
1235 return FALSE;
1236 }
1237
1238 // remove service from all sets
1239
1240 sets = SCNetworkSetCopyAll(servicePrivate->prefs);
1241 if (sets != NULL) {
1242 CFIndex i;
1243 CFIndex n;
1244
1245 n = CFArrayGetCount(sets);
1246 for (i = 0; i < n; i++) {
1247 SCNetworkSetRef set;
1248
1249 set = CFArrayGetValueAtIndex(sets, i);
1250 ok = SCNetworkSetRemoveService(set, service);
1251 if (!ok && (SCError() != kSCStatusNoKey)) {
1252 CFRelease(sets);
1253 return ok;
1254 }
1255 }
1256 CFRelease(sets);
1257 }
1258
1259 // remove service
1260
1261 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1262 servicePrivate->serviceID, // service
1263 NULL); // entity
1264 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
1265 CFRelease(path);
1266
1267 return ok;
1268 }
1269
1270
1271 Boolean
1272 SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
1273 {
1274 CFDictionaryRef entity;
1275 Boolean ok = FALSE;
1276 CFStringRef path;
1277 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1278
1279 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1280 _SCErrorSet(kSCStatusInvalidArgument);
1281 return FALSE;
1282 }
1283
1284 if (!__SCNetworkProtocolIsValidType(protocolType)) {
1285 _SCErrorSet(kSCStatusInvalidArgument);
1286 return FALSE;
1287 }
1288
1289 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1290 servicePrivate->serviceID, // service
1291 protocolType); // entity
1292
1293 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1294 if (entity == NULL) {
1295 // if "protocol" does not exist
1296 _SCErrorSet(kSCStatusNoKey);
1297 goto done;
1298 }
1299
1300 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
1301
1302 done :
1303
1304 CFRelease(path);
1305 return ok;
1306 }
1307
1308
1309 Boolean
1310 SCNetworkServiceSetEnabled(SCNetworkServiceRef service, Boolean enabled)
1311 {
1312 Boolean ok;
1313 CFStringRef path;
1314 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1315
1316 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1317 _SCErrorSet(kSCStatusInvalidArgument);
1318 return FALSE;
1319 }
1320
1321 // make sure that we do not enable a network service if the
1322 // associated interface is a member of a bond or bridge.
1323 if (enabled) {
1324 SCNetworkInterfaceRef interface;
1325
1326 interface = SCNetworkServiceGetInterface(service);
1327 if ((interface != NULL) &&
1328 __SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) {
1329 _SCErrorSet(kSCStatusKeyExists);
1330 return FALSE;
1331 }
1332 }
1333
1334 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1335 servicePrivate->serviceID, // service
1336 NULL); // entity
1337 ok = __setPrefsEnabled(servicePrivate->prefs, path, enabled);
1338 CFRelease(path);
1339
1340 return ok;
1341 }
1342
1343
1344 Boolean
1345 SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name)
1346 {
1347 CFDictionaryRef entity;
1348 Boolean ok = FALSE;
1349 CFStringRef path;
1350 CFStringRef saveName = NULL;
1351 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1352
1353 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1354 _SCErrorSet(kSCStatusInvalidArgument);
1355 return FALSE;
1356 }
1357
1358 if (name != NULL) {
1359 if (!isA_CFString(name)) {
1360 _SCErrorSet(kSCStatusInvalidArgument);
1361 return FALSE;
1362 }
1363 saveName = CFRetain(name);
1364 }
1365
1366 if (name != NULL) {
1367 SCNetworkInterfaceRef interface;
1368
1369 interface = SCNetworkServiceGetInterface(service);
1370 while (interface != NULL) {
1371 SCNetworkInterfaceRef childInterface;
1372
1373 childInterface = SCNetworkInterfaceGetInterface(interface);
1374 if (childInterface == NULL) {
1375 break;
1376 }
1377
1378 interface = childInterface;
1379 }
1380
1381 if (interface != NULL) {
1382 CFStringRef interface_name;
1383
1384 interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
1385 if (interface_name != NULL) {
1386 if (CFEqual(name, interface_name)) {
1387 // if service name matches the localized interface name
1388 // then store the non-localized name.
1389 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
1390 if (interface_name != NULL) {
1391 CFRelease(saveName);
1392 saveName = CFRetain(interface_name);
1393 }
1394 } else if (CFStringHasPrefix(name, interface_name)) {
1395 CFIndex prefixLen = CFStringGetLength(interface_name);
1396 CFStringRef suffix;
1397 CFIndex suffixLen = CFStringGetLength(name);
1398
1399 // if service name matches the localized interface name plus
1400 // a few extra characters) then store the non-localized name with
1401 // the same suffix.
1402 suffix = CFStringCreateWithSubstring(NULL,
1403 name,
1404 CFRangeMake(prefixLen, suffixLen - prefixLen));
1405 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
1406 if (interface_name != NULL) {
1407 CFRelease(saveName);
1408 saveName = CFStringCreateWithFormat(NULL,
1409 NULL,
1410 CFSTR("%@%@"),
1411 interface_name,
1412 suffix);
1413 }
1414 CFRelease(suffix);
1415 }
1416 }
1417 }
1418 }
1419
1420 #define PREVENT_DUPLICATE_SERVICE_NAMES
1421 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
1422 if (name != NULL) {
1423 CFArrayRef sets;
1424
1425 // ensure that each service is uniquely named within its sets
1426
1427 sets = SCNetworkSetCopyAll(servicePrivate->prefs);
1428 if (sets != NULL) {
1429 CFIndex set_index;
1430 CFIndex set_count;
1431
1432 set_count = CFArrayGetCount(sets);
1433 for (set_index = 0; set_index < set_count; set_index++) {
1434 CFIndex service_index;
1435 Boolean isDup = FALSE;
1436 Boolean isMember = FALSE;
1437 CFIndex service_count;
1438 CFArrayRef services;
1439 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, set_index);
1440
1441 services = SCNetworkSetCopyServices(set);
1442
1443 service_count = CFArrayGetCount(services);
1444 for (service_index = 0; service_index < service_count; service_index++) {
1445 CFStringRef otherID;
1446 CFStringRef otherName;
1447 SCNetworkServiceRef otherService;
1448
1449 otherService = CFArrayGetValueAtIndex(services, service_index);
1450
1451 otherID = SCNetworkServiceGetServiceID(otherService);
1452 if (CFEqual(servicePrivate->serviceID, otherID)) {
1453 // if the service is a member of this set
1454 isMember = TRUE;
1455 continue;
1456 }
1457
1458 otherName = SCNetworkServiceGetName(otherService);
1459 if ((otherName != NULL) && CFEqual(name, otherName)) {
1460 isDup = TRUE;
1461 continue;
1462 }
1463 }
1464
1465 CFRelease(services);
1466
1467 if (isMember && isDup) {
1468 /*
1469 * if this service is a member of the set and
1470 * the "name" is not unique.
1471 */
1472 CFRelease(sets);
1473 if (saveName != NULL) CFRelease(saveName);
1474 _SCErrorSet(kSCStatusKeyExists);
1475 return FALSE;
1476 }
1477 }
1478
1479 CFRelease(sets);
1480 }
1481 }
1482 #endif /* PREVENT_DUPLICATE_SERVICE_NAMES */
1483
1484 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1485 servicePrivate->serviceID, // service
1486 NULL); // entity
1487 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1488 if (isA_CFDictionary(entity) ||
1489 ((entity == NULL) && (name != NULL))) {
1490 CFMutableDictionaryRef newEntity;
1491
1492 if (entity != NULL) {
1493 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1494 } else {
1495 newEntity = CFDictionaryCreateMutable(NULL,
1496 0,
1497 &kCFTypeDictionaryKeyCallBacks,
1498 &kCFTypeDictionaryValueCallBacks);
1499 }
1500 if (saveName != NULL) {
1501 CFDictionarySetValue(newEntity, kSCPropUserDefinedName, saveName);
1502 } else {
1503 CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
1504 }
1505 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
1506 CFRelease(newEntity);
1507 }
1508 CFRelease(path);
1509 if (saveName != NULL) CFRelease(saveName);
1510
1511 if (servicePrivate->name != NULL) CFRelease(servicePrivate->name);
1512 if (name != NULL) CFRetain(name);
1513 servicePrivate->name = name;
1514
1515 return ok;
1516 }
1517
1518
1519 #pragma mark -
1520 #pragma mark SCNetworkService SPIs
1521
1522
1523 SCNetworkServicePrimaryRank
1524 SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service)
1525 {
1526 CFDictionaryRef entity;
1527 Boolean ok = TRUE;
1528 CFStringRef path;
1529 SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault;
1530 CFStringRef rankStr = NULL;
1531 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1532
1533 if (!isA_SCNetworkService(service)) {
1534 _SCErrorSet(kSCStatusInvalidArgument);
1535 return rank;
1536 }
1537
1538 if (servicePrivate->prefs != NULL) {
1539 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
1540 servicePrivate->serviceID,
1541 NULL);
1542 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1543 CFRelease(path);
1544 if (isA_CFDictionary(entity)) {
1545 rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
1546 ok = __str_to_rank(rankStr, &rank);
1547 }
1548 } else if (servicePrivate->store != NULL) {
1549 path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1550 kSCDynamicStoreDomainState,
1551 servicePrivate->serviceID,
1552 NULL);
1553 entity = SCDynamicStoreCopyValue(servicePrivate->store, path);
1554 CFRelease(path);
1555 if (entity != NULL) {
1556 if (isA_CFDictionary(entity)) {
1557 rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
1558 ok = __str_to_rank(rankStr, &rank);
1559 }
1560 CFRelease(entity);
1561 }
1562 } else {
1563 _SCErrorSet(kSCStatusInvalidArgument);
1564 return rank;
1565 }
1566
1567 if (!ok) {
1568 rank = kSCNetworkServicePrimaryRankDefault;
1569 _SCErrorSet(kSCStatusInvalidArgument);
1570 } else if (rank == kSCNetworkServicePrimaryRankDefault) {
1571 _SCErrorSet(kSCStatusOK);
1572 }
1573
1574 return rank;
1575 }
1576
1577
1578 Boolean
1579 SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service,
1580 SCNetworkServicePrimaryRank newRank)
1581 {
1582 Boolean ok;
1583 CFDictionaryRef entity;
1584 CFMutableDictionaryRef newEntity;
1585 CFStringRef path = NULL;
1586 CFStringRef rankStr = NULL;
1587 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1588
1589 if (!isA_SCNetworkService(service)) {
1590 _SCErrorSet(kSCStatusInvalidArgument);
1591 return FALSE;
1592 }
1593
1594 ok = __rank_to_str(newRank, &rankStr);
1595 if (!ok) {
1596 _SCErrorSet(kSCStatusInvalidArgument);
1597 return FALSE;
1598 }
1599
1600 if (servicePrivate->prefs != NULL) {
1601 if ((newRank == kSCNetworkServicePrimaryRankDefault) || (newRank == kSCNetworkServicePrimaryRankNever)) {
1602 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
1603 servicePrivate->serviceID,
1604 NULL);
1605 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1606 if (entity != NULL) {
1607 if (!isA_CFDictionary(entity)) {
1608 // if corrupt prefs
1609 _SCErrorSet(kSCStatusFailed);
1610 goto done;
1611 }
1612 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1613 } else {
1614 newEntity = CFDictionaryCreateMutable(NULL,
1615 0,
1616 &kCFTypeDictionaryKeyCallBacks,
1617 &kCFTypeDictionaryValueCallBacks);
1618 }
1619 if (rankStr != NULL) {
1620 CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
1621 } else {
1622 CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
1623 }
1624 if (CFDictionaryGetCount(newEntity) > 0) {
1625 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
1626 } else {
1627 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
1628 }
1629 CFRelease(newEntity);
1630 if (!ok) {
1631 goto done;
1632 }
1633 } else {
1634 _SCErrorSet(kSCStatusInvalidArgument);
1635 return FALSE;
1636 }
1637 } else if (servicePrivate->store != NULL) {
1638 path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1639 kSCDynamicStoreDomainState,
1640 servicePrivate->serviceID,
1641 NULL);
1642 entity = SCDynamicStoreCopyValue(servicePrivate->store, path);
1643 if (entity != NULL) {
1644 if (!isA_CFDictionary(entity)) {
1645 // if corrupt prefs
1646 CFRelease(entity);
1647 _SCErrorSet(kSCStatusFailed);
1648 goto done;
1649 }
1650 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1651 CFRelease(entity);
1652 } else {
1653 newEntity = CFDictionaryCreateMutable(NULL,
1654 0,
1655 &kCFTypeDictionaryKeyCallBacks,
1656 &kCFTypeDictionaryValueCallBacks);
1657 }
1658 if (rankStr != NULL) {
1659 CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
1660 } else {
1661 CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
1662 }
1663 if (CFDictionaryGetCount(newEntity) > 0) {
1664 ok = SCDynamicStoreSetValue(servicePrivate->store, path, newEntity);
1665 } else {
1666 ok = SCDynamicStoreRemoveValue(servicePrivate->store, path);
1667 }
1668 CFRelease(newEntity);
1669 if (!ok) {
1670 goto done;
1671 }
1672 } else {
1673 _SCErrorSet(kSCStatusInvalidArgument);
1674 return FALSE;
1675 }
1676
1677 done :
1678
1679 if (path != NULL) CFRelease(path);
1680 return ok;
1681 }
1682
1683
1684 Boolean
1685 _SCNetworkServiceIsVPN(SCNetworkServiceRef service)
1686 {
1687 SCNetworkInterfaceRef interface;
1688 CFStringRef interfaceType;
1689
1690 interface = SCNetworkServiceGetInterface(service);
1691 if (interface == NULL) {
1692 return FALSE;
1693 }
1694
1695 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
1696 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
1697 interface = SCNetworkInterfaceGetInterface(interface);
1698 if (interface == NULL) {
1699 return FALSE;
1700 }
1701
1702 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
1703 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
1704 return TRUE;
1705 }
1706 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
1707 return TRUE;
1708 }
1709 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
1710 return TRUE;
1711 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
1712 return TRUE;
1713 }
1714
1715 return FALSE;
1716 }
1717
1718
1719 Boolean
1720 SCNetworkServiceSetExternalID(SCNetworkServiceRef service, CFStringRef identifierDomain, CFStringRef identifier)
1721 {
1722 CFStringRef prefs_path;
1723 CFDictionaryRef service_dictionary;
1724 SCNetworkServicePrivateRef service_private = (SCNetworkServicePrivateRef)service;
1725 Boolean success = FALSE;
1726 CFStringRef prefixed_domain;
1727
1728 if (!isA_SCNetworkService(service) || (service_private->prefs == NULL) || !isA_CFString(identifierDomain)) {
1729 _SCErrorSet(kSCStatusInvalidArgument);
1730 return FALSE;
1731 }
1732
1733 if (identifier != NULL && !isA_CFString(identifier)) {
1734 _SCErrorSet(kSCStatusInvalidArgument);
1735 return FALSE;
1736 }
1737
1738 prefixed_domain = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%s%@"), EXTERNAL_ID_DOMAIN_PREFIX, identifierDomain);
1739
1740 prefs_path = SCPreferencesPathKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
1741 service_private->serviceID,
1742 NULL);
1743
1744 service_dictionary = SCPreferencesPathGetValue(service_private->prefs, prefs_path);
1745 if (isA_CFDictionary(service_dictionary) || ((service_dictionary == NULL) && (identifier != NULL))) {
1746 CFMutableDictionaryRef new_service_dictionary;
1747
1748 if (service_dictionary != NULL) {
1749 new_service_dictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, service_dictionary);
1750 } else {
1751 new_service_dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault,
1752 0,
1753 &kCFTypeDictionaryKeyCallBacks,
1754 &kCFTypeDictionaryValueCallBacks);
1755 }
1756
1757 if (identifier != NULL) {
1758 CFDictionarySetValue(new_service_dictionary, prefixed_domain, identifier);
1759 } else {
1760 CFDictionaryRemoveValue(new_service_dictionary, prefixed_domain);
1761 }
1762 success = SCPreferencesPathSetValue(service_private->prefs, prefs_path, new_service_dictionary);
1763 CFRelease(new_service_dictionary);
1764 }
1765 CFRelease(prefs_path);
1766
1767 if (identifier != NULL) {
1768 if (service_private->externalIDs == NULL) {
1769 service_private->externalIDs = CFDictionaryCreateMutable(kCFAllocatorDefault,
1770 0,
1771 &kCFTypeDictionaryKeyCallBacks,
1772 &kCFTypeDictionaryValueCallBacks);
1773 }
1774 CFDictionarySetValue(service_private->externalIDs, prefixed_domain, identifier);
1775 } else {
1776 if (service_private->externalIDs != NULL) {
1777 CFDictionaryRemoveValue(service_private->externalIDs, prefixed_domain);
1778 }
1779 }
1780
1781 CFRelease(prefixed_domain);
1782
1783 if (!success) {
1784 _SCErrorSet(kSCStatusFailed);
1785 }
1786
1787 return success;
1788 }
1789
1790
1791 CFStringRef
1792 SCNetworkServiceCopyExternalID(SCNetworkServiceRef service, CFStringRef identifierDomain)
1793 {
1794 SCNetworkServicePrivateRef service_private = (SCNetworkServicePrivateRef)service;
1795 CFStringRef identifier = NULL;
1796 CFStringRef prefixed_domain;
1797
1798 if (!isA_SCNetworkService(service) || (service_private->prefs == NULL) || !isA_CFString(identifierDomain)) {
1799 _SCErrorSet(kSCStatusInvalidArgument);
1800 return NULL;
1801 }
1802
1803 prefixed_domain = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%s%@"), EXTERNAL_ID_DOMAIN_PREFIX, identifierDomain);
1804
1805 if (service_private->externalIDs != NULL) {
1806 identifier = CFDictionaryGetValue(service_private->externalIDs, prefixed_domain);
1807 if (identifier != NULL) {
1808 CFRetain(identifier);
1809 }
1810 }
1811
1812 if (identifier == NULL) {
1813 CFStringRef prefs_path;
1814 CFDictionaryRef service_dictionary;
1815
1816 prefs_path = SCPreferencesPathKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
1817 service_private->serviceID,
1818 NULL);
1819
1820 service_dictionary = SCPreferencesPathGetValue(service_private->prefs, prefs_path);
1821 if (isA_CFDictionary(service_dictionary)) {
1822 identifier = CFDictionaryGetValue(service_dictionary, prefixed_domain);
1823 if (identifier != NULL) {
1824 CFRetain(identifier);
1825 if (service_private->externalIDs == NULL) {
1826 service_private->externalIDs = CFDictionaryCreateMutable(kCFAllocatorDefault,
1827 0,
1828 &kCFTypeDictionaryKeyCallBacks,
1829 &kCFTypeDictionaryValueCallBacks);
1830 }
1831 CFDictionarySetValue(service_private->externalIDs, prefixed_domain, identifier);
1832 }
1833 }
1834 CFRelease(prefs_path);
1835 }
1836
1837 CFRelease(prefixed_domain);
1838
1839 if (identifier == NULL) {
1840 _SCErrorSet(kSCStatusNoKey);
1841 }
1842
1843 return identifier;
1844 }