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