]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkService.c
configd-801.1.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkService.c
1 /*
2 * Copyright (c) 2004-2015 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 #include "SCPreferencesInternal.h"
39
40 #include <pthread.h>
41
42 #define EXTERNAL_ID_DOMAIN_PREFIX "_"
43
44 static CFStringRef __SCNetworkServiceCopyDescription (CFTypeRef cf);
45 static void __SCNetworkServiceDeallocate (CFTypeRef cf);
46 static Boolean __SCNetworkServiceEqual (CFTypeRef cf1, CFTypeRef cf2);
47 static CFHashCode __SCNetworkServiceHash (CFTypeRef cf);
48
49
50 static CFTypeID __kSCNetworkServiceTypeID = _kCFRuntimeNotATypeID;
51
52
53 static const CFRuntimeClass __SCNetworkServiceClass = {
54 0, // version
55 "SCNetworkService", // className
56 NULL, // init
57 NULL, // copy
58 __SCNetworkServiceDeallocate, // dealloc
59 __SCNetworkServiceEqual, // equal
60 __SCNetworkServiceHash, // hash
61 NULL, // copyFormattingDesc
62 __SCNetworkServiceCopyDescription // copyDebugDesc
63 };
64
65
66 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
67
68
69 static CFStringRef
70 __SCNetworkServiceCopyDescription(CFTypeRef cf)
71 {
72 CFAllocatorRef allocator = CFGetAllocator(cf);
73 CFMutableStringRef result;
74 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
75
76 result = CFStringCreateMutable(allocator, 0);
77 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkService %p [%p]> {"), cf, allocator);
78 CFStringAppendFormat(result, NULL, CFSTR("id = %@"), servicePrivate->serviceID);
79 if (servicePrivate->prefs != NULL) {
80 CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), servicePrivate->prefs);
81 } else if (servicePrivate->store != NULL) {
82 CFStringAppendFormat(result, NULL, CFSTR(", store = %p"), servicePrivate->store);
83 }
84 if (servicePrivate->name != NULL) {
85 CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), servicePrivate->name);
86 }
87 CFStringAppendFormat(result, NULL, CFSTR("}"));
88
89 return result;
90 }
91
92
93 static void
94 __SCNetworkServiceDeallocate(CFTypeRef cf)
95 {
96 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
97
98 /* release resources */
99
100 CFRelease(servicePrivate->serviceID);
101 if (servicePrivate->interface != NULL) CFRelease(servicePrivate->interface);
102 if (servicePrivate->prefs != NULL) CFRelease(servicePrivate->prefs);
103 if (servicePrivate->store != NULL) CFRelease(servicePrivate->store);
104 if (servicePrivate->name != NULL) CFRelease(servicePrivate->name);
105 if (servicePrivate->externalIDs != NULL) CFRelease(servicePrivate->externalIDs);
106
107 return;
108 }
109
110
111 static Boolean
112 __SCNetworkServiceEqual(CFTypeRef cf1, CFTypeRef cf2)
113 {
114 SCNetworkServicePrivateRef s1 = (SCNetworkServicePrivateRef)cf1;
115 SCNetworkServicePrivateRef s2 = (SCNetworkServicePrivateRef)cf2;
116
117 if (s1 == s2)
118 return TRUE;
119
120 if (s1->prefs != s2->prefs)
121 return FALSE; // if not the same prefs
122
123 if (!CFEqual(s1->serviceID, s2->serviceID))
124 return FALSE; // if not the same service identifier
125
126 return TRUE;
127 }
128
129
130 static CFHashCode
131 __SCNetworkServiceHash(CFTypeRef cf)
132 {
133 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
134
135 return CFHash(servicePrivate->serviceID);
136 }
137
138
139 static void
140 __SCNetworkServiceInitialize(void)
141 {
142 __kSCNetworkServiceTypeID = _CFRuntimeRegisterClass(&__SCNetworkServiceClass);
143 return;
144 }
145
146
147 __private_extern__ SCNetworkServicePrivateRef
148 __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator,
149 SCPreferencesRef prefs,
150 CFStringRef serviceID,
151 SCNetworkInterfaceRef interface)
152 {
153 SCNetworkServicePrivateRef servicePrivate;
154 uint32_t size;
155
156 /* initialize runtime */
157 pthread_once(&initialized, __SCNetworkServiceInitialize);
158
159 /* allocate target */
160 size = sizeof(SCNetworkServicePrivate) - sizeof(CFRuntimeBase);
161 servicePrivate = (SCNetworkServicePrivateRef)_CFRuntimeCreateInstance(allocator,
162 __kSCNetworkServiceTypeID,
163 size,
164 NULL);
165 if (servicePrivate == NULL) {
166 return NULL;
167 }
168
169 servicePrivate->prefs = (prefs != NULL) ? CFRetain(prefs): NULL;
170 servicePrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
171 servicePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL;
172 servicePrivate->name = NULL;
173
174 return servicePrivate;
175 }
176
177
178 #pragma mark -
179 #pragma mark Service ordering
180
181
182 CFComparisonResult
183 _SCNetworkServiceCompare(const void *val1, const void *val2, void *context)
184 {
185 CFStringRef id1;
186 CFStringRef id2;
187 CFArrayRef order = (CFArrayRef)context;
188 SCNetworkServiceRef s1 = (SCNetworkServiceRef)val1;
189 SCNetworkServiceRef s2 = (SCNetworkServiceRef)val2;
190
191 id1 = SCNetworkServiceGetServiceID(s1);
192 id2 = SCNetworkServiceGetServiceID(s2);
193
194 if (order != NULL) {
195 CFIndex o1;
196 CFIndex o2;
197 CFRange range;
198
199 range = CFRangeMake(0, CFArrayGetCount(order));
200 o1 = CFArrayGetFirstIndexOfValue(order, range, id1);
201 o2 = CFArrayGetFirstIndexOfValue(order, range, id2);
202
203 if (o1 > o2) {
204 return (o2 != kCFNotFound) ? kCFCompareGreaterThan : kCFCompareLessThan;
205 } else if (o1 < o2) {
206 return (o1 != kCFNotFound) ? kCFCompareLessThan : kCFCompareGreaterThan;
207 }
208 }
209
210 return CFStringCompare(id1, id2, 0);
211 }
212
213
214 #pragma mark -
215 #pragma mark SCNetworkService APIs
216
217
218 #define N_QUICK 64
219
220
221 __private_extern__ CFArrayRef /* of SCNetworkServiceRef's */
222 __SCNetworkServiceCopyAllEnabled(SCPreferencesRef prefs)
223 {
224 CFMutableArrayRef array = NULL;
225 CFIndex i_sets;
226 CFIndex n_sets;
227 CFArrayRef sets;
228
229 sets = SCNetworkSetCopyAll(prefs);
230 if (sets == NULL) {
231 return NULL;
232 }
233
234 n_sets = CFArrayGetCount(sets);
235 for (i_sets = 0; i_sets < n_sets; i_sets++) {
236 CFIndex i_services;
237 CFIndex n_services;
238 CFArrayRef services;
239 SCNetworkSetRef set;
240
241 set = CFArrayGetValueAtIndex(sets, i_sets);
242 services = SCNetworkSetCopyServices(set);
243 if (services == NULL) {
244 continue;
245 }
246
247 n_services = CFArrayGetCount(services);
248 for (i_services = 0; i_services < n_services; i_services++) {
249 SCNetworkServiceRef service;
250
251 service = CFArrayGetValueAtIndex(services, i_services);
252 if (!SCNetworkServiceGetEnabled(service)) {
253 // if not enabled
254 continue;
255 }
256
257 if ((array == NULL) ||
258 !CFArrayContainsValue(array,
259 CFRangeMake(0, CFArrayGetCount(array)),
260 service)) {
261 if (array == NULL) {
262 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
263 }
264 CFArrayAppendValue(array, service);
265 }
266 }
267 CFRelease(services);
268 }
269 CFRelease(sets);
270
271 return array;
272 }
273
274
275 __private_extern__ Boolean
276 __SCNetworkServiceExistsForInterface(CFArrayRef services, SCNetworkInterfaceRef interface)
277 {
278 CFIndex i;
279 CFIndex n;
280
281 n = isA_CFArray(services) ? CFArrayGetCount(services) : 0;
282 for (i = 0; i < n; i++) {
283 SCNetworkServiceRef service;
284 SCNetworkInterfaceRef service_interface;
285
286 service = CFArrayGetValueAtIndex(services, i);
287
288 service_interface = SCNetworkServiceGetInterface(service);
289 while (service_interface != NULL) {
290 if (CFEqual(interface, service_interface)) {
291 return TRUE;
292 }
293
294 service_interface = SCNetworkInterfaceGetInterface(service_interface);
295 }
296 }
297
298 return FALSE;
299 }
300
301
302 static void
303 mergeDict(const void *key, const void *value, void *context)
304 {
305 CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context;
306
307 CFDictionarySetValue(newDict, key, value);
308 return;
309 }
310
311
312 static CF_RETURNS_RETAINED CFDictionaryRef
313 _protocolTemplate(SCNetworkServiceRef service, CFStringRef protocolType)
314 {
315 SCNetworkInterfaceRef interface;
316 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
317 CFDictionaryRef template = NULL;
318
319 interface = servicePrivate->interface;
320 if (interface != NULL) {
321 SCNetworkInterfaceRef childInterface;
322 CFStringRef childInterfaceType = NULL;
323 CFStringRef interfaceType;
324
325 // get the template
326 interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface);
327 childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface);
328 if (childInterface != NULL) {
329 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
330 }
331
332 template = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType);
333 if (template != NULL) {
334 CFDictionaryRef overrides;
335
336 // move to the interface at the lowest layer
337 while (childInterface != NULL) {
338 interface = childInterface;
339 childInterface = SCNetworkInterfaceGetInterface(interface);
340 }
341
342 overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, protocolType);
343 if (overrides != NULL) {
344 CFMutableDictionaryRef newTemplate;
345
346 newTemplate = CFDictionaryCreateMutableCopy(NULL, 0, template);
347 CFDictionaryApplyFunction(overrides, mergeDict, newTemplate);
348 CFRelease(template);
349 template = newTemplate;
350 }
351 }
352 }
353
354 if (template == NULL) {
355 template = CFDictionaryCreate(NULL,
356 NULL,
357 NULL,
358 0,
359 &kCFTypeDictionaryKeyCallBacks,
360 &kCFTypeDictionaryValueCallBacks);
361 }
362
363 return template;
364 }
365
366
367 Boolean
368 SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
369 {
370 CFDictionaryRef entity;
371 CFDictionaryRef newEntity = NULL;
372 Boolean ok = FALSE;
373 CFStringRef path;
374 SCNetworkProtocolRef protocol;
375 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
376
377 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
378 _SCErrorSet(kSCStatusInvalidArgument);
379 return FALSE;
380 }
381
382 if (!__SCNetworkProtocolIsValidType(protocolType)) {
383 _SCErrorSet(kSCStatusInvalidArgument);
384 return FALSE;
385 }
386
387 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
388 servicePrivate->serviceID, // service
389 protocolType); // entity
390
391 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
392 if (entity != NULL) {
393 // if "protocol" already exists
394 _SCErrorSet(kSCStatusKeyExists);
395 goto done;
396 }
397
398 newEntity = CFDictionaryCreate(NULL,
399 NULL,
400 NULL,
401 0,
402 &kCFTypeDictionaryKeyCallBacks,
403 &kCFTypeDictionaryValueCallBacks);
404 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
405 CFRelease(newEntity);
406 if (!ok) {
407 goto done;
408 }
409
410 protocol = SCNetworkServiceCopyProtocol(service, protocolType);
411 assert(protocol != NULL);
412
413 newEntity = _protocolTemplate(service, protocolType);
414 ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
415 CFRelease(newEntity);
416 CFRelease(protocol);
417
418 done :
419
420 CFRelease(path);
421 return ok;
422 }
423
424
425 CFArrayRef /* of SCNetworkServiceRef's */
426 SCNetworkServiceCopyAll(SCPreferencesRef prefs)
427 {
428 CFMutableArrayRef array;
429 CFIndex n;
430 CFStringRef path;
431 CFDictionaryRef services;
432
433 path = SCPreferencesPathKeyCreateNetworkServices(NULL);
434 services = SCPreferencesPathGetValue(prefs, path);
435 CFRelease(path);
436
437 if ((services != NULL) && !isA_CFDictionary(services)) {
438 return NULL;
439 }
440
441 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
442
443 n = (services != NULL) ? CFDictionaryGetCount(services) : 0;
444 if (n > 0) {
445 CFIndex i;
446 const void * keys_q[N_QUICK];
447 const void ** keys = keys_q;
448 const void * vals_q[N_QUICK];
449 const void ** vals = vals_q;
450
451 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
452 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
453 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
454 }
455 CFDictionaryGetKeysAndValues(services, keys, vals);
456 for (i = 0; i < n; i++) {
457 CFDictionaryRef entity;
458 SCNetworkServicePrivateRef servicePrivate;
459
460 if (!isA_CFDictionary(vals[i])) {
461 SC_log(LOG_INFO, "error w/service \"%@\"", keys[i]);
462 continue;
463 }
464
465 entity = CFDictionaryGetValue(vals[i], kSCEntNetInterface);
466 if (!isA_CFDictionary(entity)) {
467 // if no "interface"
468 SC_log(LOG_INFO, "no \"%@\" entity for service \"%@\"",
469 kSCEntNetInterface,
470 keys[i]);
471 continue;
472 }
473
474 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, keys[i], NULL);
475 assert(servicePrivate != NULL);
476 CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
477 CFRelease(servicePrivate);
478 }
479 if (keys != keys_q) {
480 CFAllocatorDeallocate(NULL, keys);
481 CFAllocatorDeallocate(NULL, vals);
482 }
483 }
484
485 return array;
486 }
487
488
489 __private_extern__
490 CFArrayRef /* of SCNetworkInterfaceRef's */
491 __SCNetworkServiceCopyAllInterfaces(SCPreferencesRef prefs)
492 {
493 CFMutableArrayRef interfaces = NULL;
494 CFArrayRef services = NULL;
495 CFIndex servicesCount = 0;
496 SCNetworkServiceRef service = NULL;
497 SCNetworkInterfaceRef interface = NULL;
498
499 services = SCNetworkServiceCopyAll(prefs);
500 if (services == NULL) {
501 goto done;
502 }
503
504 servicesCount = CFArrayGetCount(services);
505 if (servicesCount == 0) {
506 goto done;
507 }
508
509 interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
510
511 for (CFIndex idx = 0; idx < servicesCount; idx++) {
512 service = CFArrayGetValueAtIndex(services, idx);
513 interface = SCNetworkServiceGetInterface(service);
514
515 if (isA_SCNetworkInterface(interface) == NULL) {
516 continue;
517 }
518 CFArrayAppendValue(interfaces, interface);
519 }
520
521 if (CFArrayGetCount(interfaces) == 0) {
522 // Do not return an empty array
523 CFRelease(interfaces);
524 interfaces = NULL;
525 }
526
527 done:
528
529 if (services != NULL) {
530 CFRelease(services);
531 }
532 return interfaces;
533 }
534
535
536 /*
537 * build a list of all of a services entity types that are associated
538 * with the services interface. The list will include :
539 *
540 * - entity types associated with the interface type (Ethernet, FireWire, PPP, ...)
541 * - entity types associated with the interface sub-type (PPPSerial, PPPoE, L2TP, PPTP, ...)
542 * - entity types associated with the hardware device (Ethernet, AirPort, FireWire, Modem, ...)
543 */
544 static CFSetRef
545 _copyInterfaceEntityTypes(CFDictionaryRef protocols)
546 {
547 CFDictionaryRef interface;
548 CFMutableSetRef interface_entity_types;
549
550 interface_entity_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
551
552 interface = CFDictionaryGetValue(protocols, kSCEntNetInterface);
553 if (isA_CFDictionary(interface)) {
554 CFStringRef entities[] = { kSCPropNetInterfaceType,
555 kSCPropNetInterfaceSubType,
556 kSCPropNetInterfaceHardware };
557 int i;
558
559 // include the "Interface" entity itself
560 CFSetAddValue(interface_entity_types, kSCEntNetInterface);
561
562 // include the entities associated with the interface
563 for (i = 0; i < sizeof(entities)/sizeof(entities[0]); i++) {
564 CFStringRef entity;
565
566 entity = CFDictionaryGetValue(interface, entities[i]);
567 if (isA_CFString(entity)) {
568 CFSetAddValue(interface_entity_types, entity);
569 }
570 }
571
572 /*
573 * and, because we've found some misguided network preference code
574 * developers leaving [PPP] entity dictionaries around even though
575 * they are unused and/or unneeded...
576 */
577 CFSetAddValue(interface_entity_types, kSCEntNetPPP);
578 }
579
580 return interface_entity_types;
581 }
582
583
584 SCNetworkServiceRef
585 SCNetworkServiceCopy(SCPreferencesRef prefs, CFStringRef serviceID)
586 {
587 CFDictionaryRef entity;
588 CFStringRef path;
589 SCNetworkServicePrivateRef servicePrivate;
590
591 if (!isA_CFString(serviceID)) {
592 _SCErrorSet(kSCStatusInvalidArgument);
593 return NULL;
594 }
595
596 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
597 serviceID, // service
598 kSCEntNetInterface); // entity
599 entity = SCPreferencesPathGetValue(prefs, path);
600 CFRelease(path);
601
602 if (!isA_CFDictionary(entity)) {
603 // a "service" must have an "interface"
604 _SCErrorSet(kSCStatusNoKey);
605 return NULL;
606 }
607
608 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
609 return (SCNetworkServiceRef)servicePrivate;
610 }
611
612
613 SCNetworkServiceRef
614 _SCNetworkServiceCopyActive(SCDynamicStoreRef store, CFStringRef serviceID)
615 {
616 SCNetworkServicePrivateRef servicePrivate;
617
618 if (!isA_CFString(serviceID)) {
619 _SCErrorSet(kSCStatusInvalidArgument);
620 return NULL;
621 }
622
623 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, NULL, serviceID, NULL);
624 assert(servicePrivate != NULL);
625 if (store != NULL) {
626 servicePrivate->store = CFRetain(store);
627 }
628 return (SCNetworkServiceRef)servicePrivate;
629 }
630
631
632 SCNetworkProtocolRef
633 SCNetworkServiceCopyProtocol(SCNetworkServiceRef service, CFStringRef protocolType)
634 {
635 CFSetRef non_protocol_entities;
636 CFStringRef path;
637 CFDictionaryRef protocols;
638 SCNetworkProtocolPrivateRef protocolPrivate = NULL;
639 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
640
641 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
642 _SCErrorSet(kSCStatusInvalidArgument);
643 return NULL;
644 }
645
646 if (!isA_CFString(protocolType)) {
647 _SCErrorSet(kSCStatusInvalidArgument);
648 return NULL;
649 }
650
651 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
652 servicePrivate->serviceID, // service
653 NULL); // entity
654 protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
655 CFRelease(path);
656
657 if (!isA_CFDictionary(protocols)) {
658 // if corrupt prefs
659 _SCErrorSet(kSCStatusFailed);
660 return NULL;
661 }
662
663 non_protocol_entities = _copyInterfaceEntityTypes(protocols);
664 if (CFSetContainsValue(non_protocol_entities, protocolType)) {
665 // if the "protocolType" matches an interface entity type
666 _SCErrorSet(kSCStatusInvalidArgument);
667 goto done;
668 }
669
670 if (!CFDictionaryContainsKey(protocols, protocolType)) {
671 // if the "protocolType" entity does not exist
672 _SCErrorSet(kSCStatusNoKey);
673 goto done;
674 }
675
676 protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, protocolType, service);
677
678 done :
679
680 CFRelease(non_protocol_entities);
681
682 return (SCNetworkProtocolRef)protocolPrivate;
683 }
684
685
686 CFArrayRef /* of SCNetworkProtocolRef's */
687 SCNetworkServiceCopyProtocols(SCNetworkServiceRef service)
688 {
689 CFMutableArrayRef array;
690 CFIndex n;
691 CFSetRef non_protocol_entities;
692 CFStringRef path;
693 CFDictionaryRef protocols;
694 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
695
696 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
697 _SCErrorSet(kSCStatusInvalidArgument);
698 return NULL;
699 }
700
701 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
702 servicePrivate->serviceID, // service
703 NULL); // entity
704 protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
705 CFRelease(path);
706
707 if (!isA_CFDictionary(protocols)) {
708 // if corrupt prefs
709 _SCErrorSet(kSCStatusFailed);
710 return NULL;
711 }
712
713 non_protocol_entities = _copyInterfaceEntityTypes(protocols);
714
715 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
716
717 n = CFDictionaryGetCount(protocols);
718 if (n > 0) {
719 CFIndex i;
720 const void * keys_q[N_QUICK];
721 const void ** keys = keys_q;
722 const void * vals_q[N_QUICK];
723 const void ** vals = vals_q;
724
725 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
726 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
727 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
728 }
729 CFDictionaryGetKeysAndValues(protocols, keys, vals);
730 for (i = 0; i < n; i++) {
731 SCNetworkProtocolPrivateRef protocolPrivate;
732
733 if (!isA_CFDictionary(vals[i])) {
734 // if it's not a dictionary then it can't be a protocol entity
735 continue;
736 }
737
738 if (CFSetContainsValue(non_protocol_entities, keys[i])) {
739 // skip any non-protocol (interface) entities
740 continue;
741 }
742
743 protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, keys[i], service);
744 CFArrayAppendValue(array, (SCNetworkProtocolRef)protocolPrivate);
745
746 CFRelease(protocolPrivate);
747 }
748 if (keys != keys_q) {
749 CFAllocatorDeallocate(NULL, keys);
750 CFAllocatorDeallocate(NULL, vals);
751 }
752 }
753
754 CFRelease(non_protocol_entities);
755
756 return array;
757 }
758
759
760 static Boolean
761 __SCNetworkServiceSetInterfaceEntity(SCNetworkServiceRef service,
762 SCNetworkInterfaceRef interface)
763 {
764 CFDictionaryRef entity;
765 Boolean ok;
766 CFStringRef path;
767 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
768
769 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
770 servicePrivate->serviceID, // service
771 kSCEntNetInterface); // entity
772 entity = __SCNetworkInterfaceCopyInterfaceEntity(interface);
773 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, entity);
774 CFRelease(entity);
775 CFRelease(path);
776
777 return ok;
778 }
779
780
781 SCNetworkServiceRef
782 SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface)
783 {
784 CFArrayRef components;
785 CFArrayRef interface_config;
786 CFStringRef interface_name;
787 SCNetworkInterfaceRef newInterface;
788 CFStringRef path;
789 CFStringRef prefix;
790 CFStringRef serviceID;
791 SCNetworkServicePrivateRef servicePrivate;
792 CFArrayRef supported_protocols;
793
794 if (!isA_SCNetworkInterface(interface)) {
795 _SCErrorSet(kSCStatusInvalidArgument);
796 return NULL;
797 }
798
799 // only allow network interfaces which support one or more protocols
800 // to be added to a service. The one exception is that we allow
801 // third-party interface types to be configured.
802 supported_protocols = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
803 if (supported_protocols == NULL) {
804 CFStringRef interface_type;
805
806 interface_type = SCNetworkInterfaceGetInterfaceType(interface);
807 if (CFStringFind(interface_type, CFSTR("."), 0).location == kCFNotFound) {
808 _SCErrorSet(kSCStatusInvalidArgument);
809 return NULL;
810 }
811 }
812
813 // do not allow creation of a network service if the interface is a
814 // member of a bond or bridge
815 if (__SCNetworkInterfaceIsMember(prefs, interface)) {
816 _SCErrorSet(kSCStatusKeyExists);
817 return NULL;
818 }
819
820 // establish the service
821 prefix = SCPreferencesPathKeyCreateNetworkServices(NULL);
822 path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
823 if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
824 CFRelease(prefix);
825 if (path == NULL) {
826 return NULL;
827 }
828
829 components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
830 CFRelease(path);
831
832 serviceID = CFArrayGetValueAtIndex(components, 2);
833 servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
834 CFRelease(components);
835
836 // duplicate the interface and associate the copy with the new service
837 newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,
838 interface,
839 prefs,
840 serviceID);
841 servicePrivate->interface = newInterface;
842
843 // establish "default" configuration(s) for the interface
844 for (interface = newInterface;
845 interface != NULL;
846 interface = SCNetworkInterfaceGetInterface(interface)) {
847 SCNetworkInterfaceRef childInterface;
848 CFStringRef childInterfaceType = NULL;
849 CFDictionaryRef config;
850 CFStringRef interfaceType;
851
852 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
853 childInterface = SCNetworkInterfaceGetInterface(interface);
854 if (childInterface != NULL) {
855 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
856 }
857
858 config = __copyInterfaceTemplate(interfaceType, childInterfaceType);
859 if (config != NULL) {
860 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBluetooth) ||
861 CFEqual(interfaceType, kSCNetworkInterfaceTypeIrDA ) ||
862 CFEqual(interfaceType, kSCNetworkInterfaceTypeModem ) ||
863 CFEqual(interfaceType, kSCNetworkInterfaceTypeSerial ) ||
864 CFEqual(interfaceType, kSCNetworkInterfaceTypeWWAN )) {
865 CFDictionaryRef overrides;
866
867 overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypeModem);
868
869 // a ConnectionScript (and related keys) from the interface
870 // should trump the settings from the configuration template.
871 if (overrides != NULL) {
872 CFMutableDictionaryRef newConfig;
873
874 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
875 if (CFDictionaryContainsKey(overrides, kSCPropNetModemConnectionScript)) {
876 CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionPersonality);
877 CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionScript);
878 CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceVendor);
879 CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceModel);
880 }
881 CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
882 CFRelease(config);
883 config = newConfig;
884 }
885 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP) ||
886 CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
887 CFDictionaryRef overrides;
888
889 overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypePPP);
890 if (overrides != NULL) {
891 CFMutableDictionaryRef newConfig;
892
893 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
894 CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
895 CFRelease(config);
896 config = newConfig;
897 }
898 }
899
900 if (!__SCNetworkInterfaceSetConfiguration(interface, NULL, config, TRUE)) {
901 SC_log(LOG_INFO, "__SCNetworkInterfaceSetConfiguration failed(), interface=%@, type=NULL",
902 interface);
903 }
904 CFRelease(config);
905 }
906 }
907
908 // add the interface [entity] to the service
909 (void) __SCNetworkServiceSetInterfaceEntity((SCNetworkServiceRef)servicePrivate,
910 servicePrivate->interface);
911
912 // push the [deep] interface configuration into the service.
913 interface_config = __SCNetworkInterfaceCopyDeepConfiguration(NULL, servicePrivate->interface);
914 __SCNetworkInterfaceSetDeepConfiguration(NULL, servicePrivate->interface, interface_config);
915 if (interface_config != NULL) CFRelease(interface_config);
916
917 // set the service name to match that of the associated interface
918 //
919 // Note: It might seem a bit odd to call SCNetworkServiceGetName
920 // followed by an immediate call to SCNetworkServiceSetName. The
921 // trick here is that if no name has previously been set, the
922 // "get" function will return the name of the associated interface.
923 //
924 // ... and we "set" a name to ensure that applications that do
925 // not use the APIs will still find a UserDefinedName property
926 // in the SCDynamicStore.
927 //
928 interface_name = SCNetworkServiceGetName((SCNetworkServiceRef)servicePrivate);
929 if (interface_name != NULL) {
930 (void) SCNetworkServiceSetName((SCNetworkServiceRef)servicePrivate,
931 interface_name);
932 }
933
934 return (SCNetworkServiceRef)servicePrivate;
935 }
936
937
938 Boolean
939 SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service)
940 {
941 CFIndex i;
942 SCNetworkInterfaceRef interface;
943 CFIndex n;
944 CFArrayRef protocolTypes;
945 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
946
947 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
948 _SCErrorSet(kSCStatusInvalidArgument);
949 return FALSE;
950 }
951
952 interface = SCNetworkServiceGetInterface(service);
953 if (interface == NULL) {
954 return FALSE;
955 }
956
957 protocolTypes = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
958 n = (protocolTypes != NULL) ? CFArrayGetCount(protocolTypes) : 0;
959 for (i = 0; i < n; i++) {
960 Boolean enabled;
961 CFDictionaryRef newEntity = NULL;
962 Boolean ok;
963 SCNetworkProtocolRef protocol = NULL;
964 CFStringRef protocolType;
965
966 protocolType = CFArrayGetValueAtIndex(protocolTypes, i);
967 ok = SCNetworkServiceAddProtocolType(service, protocolType);
968 if (!ok && (SCError() != kSCStatusKeyExists)) {
969 // could not add protocol
970 goto nextProtocol;
971 }
972
973 protocol = SCNetworkServiceCopyProtocol(service, protocolType);
974 if (protocol == NULL) {
975 // oops, somethings wrong (should never happen)
976 goto nextProtocol;
977 }
978
979 newEntity = _protocolTemplate(service, protocolType);
980 ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
981 if (!ok) {
982 // could not set default configuration
983 goto nextProtocol;
984 }
985
986 enabled = !CFDictionaryContainsKey(newEntity, kSCResvInactive);
987 ok = SCNetworkProtocolSetEnabled(protocol, enabled);
988 if (!ok) {
989 // could not enable/disable protocol
990 goto nextProtocol;
991 }
992
993 nextProtocol :
994
995 if (newEntity != NULL) CFRelease(newEntity);
996 if (protocol != NULL) CFRelease(protocol);
997 }
998
999 return TRUE;
1000 }
1001
1002
1003 Boolean
1004 SCNetworkServiceGetEnabled(SCNetworkServiceRef service)
1005 {
1006 Boolean enabled;
1007 CFStringRef path;
1008 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1009
1010 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1011 _SCErrorSet(kSCStatusInvalidArgument);
1012 return FALSE;
1013 }
1014
1015 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1016 servicePrivate->serviceID, // service
1017 NULL); // entity
1018 enabled = __getPrefsEnabled(servicePrivate->prefs, path);
1019 CFRelease(path);
1020
1021 return enabled;
1022 }
1023
1024
1025 SCNetworkInterfaceRef
1026 SCNetworkServiceGetInterface(SCNetworkServiceRef service)
1027 {
1028 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1029
1030 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1031 _SCErrorSet(kSCStatusInvalidArgument);
1032 return NULL;
1033 }
1034
1035 if (servicePrivate->interface == NULL) {
1036 CFDictionaryRef entity;
1037 CFStringRef path;
1038
1039 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1040 servicePrivate->serviceID, // service
1041 kSCEntNetInterface); // entity
1042 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1043 CFRelease(path);
1044
1045 if (isA_CFDictionary(entity)) {
1046 servicePrivate->interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, service);
1047 }
1048 }
1049
1050 return servicePrivate->interface;
1051 }
1052
1053
1054 CFStringRef
1055 SCNetworkServiceGetName(SCNetworkServiceRef service)
1056 {
1057 CFDictionaryRef entity;
1058 SCNetworkInterfaceRef interface;
1059 CFStringRef name = NULL;
1060 CFStringRef path;
1061 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1062 Boolean useSystemInterfaces = TRUE;
1063
1064 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1065 _SCErrorSet(kSCStatusInvalidArgument);
1066 return NULL;
1067 }
1068
1069 if (servicePrivate->name != NULL) {
1070 return servicePrivate->name;
1071 }
1072
1073 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1074 servicePrivate->serviceID, // service
1075 NULL); // entity
1076 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1077 CFRelease(path);
1078
1079 useSystemInterfaces = ((__SCPreferencesUsingDefaultPrefs(servicePrivate->prefs)) &&
1080 (__SCPreferencesGetLimitSCNetworkConfiguration(servicePrivate->prefs) == FALSE));
1081
1082 if (isA_CFDictionary(entity)) {
1083 name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
1084 if (isA_CFString(name)) {
1085 servicePrivate->name = CFRetain(name);
1086 if (useSystemInterfaces == FALSE) {
1087 return servicePrivate->name;
1088 }
1089 }
1090 }
1091
1092 interface = SCNetworkServiceGetInterface(service);
1093 while (interface != NULL) {
1094 SCNetworkInterfaceRef childInterface;
1095 CFStringRef interfaceType;
1096
1097 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
1098 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
1099 break;
1100 }
1101
1102 childInterface = SCNetworkInterfaceGetInterface(interface);
1103 if ((childInterface == NULL) ||
1104 CFEqual(childInterface, kSCNetworkInterfaceIPv4)) {
1105 break;
1106 }
1107
1108 interface = childInterface;
1109 }
1110
1111 if (interface != NULL) {
1112 int i;
1113 CFStringRef interface_name = NULL;
1114 CFStringRef suffix = NULL;
1115
1116 //
1117 // check if the [stored] service name matches the non-localized interface
1118 // name. If so, return the localized name.
1119 //
1120 // Also, the older "Built-in XXX" interface names are too long for the
1121 // current UI. If we find that the [stored] service name matches the older
1122 // name, return the newer (and shorter) localized name.
1123 //
1124 // Note: the user/admin will no longer be able to set the service name
1125 // to "Built-in Ethernet".
1126 //
1127 for (i = 0; i < 3; i++) {
1128 if (servicePrivate->name == NULL) {
1129 // if no [stored] service name to compare
1130 break;
1131 }
1132
1133 switch (i) {
1134 case 0 :
1135 // compare the non-localized interface name
1136 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
1137 if (interface_name != NULL) {
1138 CFRetain(interface_name);
1139 }
1140 break;
1141 #if !TARGET_OS_IPHONE
1142 case 1 :
1143 // compare the older "Built-in XXX" localized name
1144 interface_name = __SCNetworkInterfaceCopyXLocalizedDisplayName(interface);
1145 break;
1146 case 2 :
1147 // compare the older "Built-in XXX" non-localized name
1148 interface_name = __SCNetworkInterfaceCopyXNonLocalizedDisplayName(interface);
1149 break;
1150 #endif // !TARGET_OS_IPHONE
1151 default :
1152 continue;
1153 }
1154
1155 if (interface_name != NULL) {
1156 Boolean match = FALSE;
1157
1158 if (CFEqual(name, interface_name)) {
1159 // if service name matches the OLD localized
1160 // interface name
1161 match = TRUE;
1162 } else if (CFStringHasPrefix(name, interface_name)) {
1163 CFIndex prefixLen = CFStringGetLength(interface_name);
1164 CFIndex suffixLen = CFStringGetLength(name);
1165
1166 suffix = CFStringCreateWithSubstring(NULL,
1167 name,
1168 CFRangeMake(prefixLen, suffixLen - prefixLen));
1169 match = TRUE;
1170 }
1171 CFRelease(interface_name);
1172
1173 if (match) {
1174 CFRelease(servicePrivate->name);
1175 servicePrivate->name = NULL;
1176 break;
1177 }
1178 }
1179 }
1180
1181 //
1182 // if the service name has not been set, use the localized interface name
1183 //
1184 if (servicePrivate->name == NULL) {
1185 interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
1186 if (interface_name != NULL) {
1187 if (suffix != NULL) {
1188 servicePrivate->name = CFStringCreateWithFormat(NULL,
1189 NULL,
1190 CFSTR("%@%@"),
1191 interface_name,
1192 suffix);
1193 } else {
1194 servicePrivate->name = CFRetain(interface_name);
1195 }
1196 }
1197 }
1198 if (suffix != NULL) CFRelease(suffix);
1199 }
1200
1201 return servicePrivate->name;
1202 }
1203
1204
1205 CFStringRef
1206 SCNetworkServiceGetServiceID(SCNetworkServiceRef service)
1207 {
1208 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1209
1210 if (!isA_SCNetworkService(service)) {
1211 _SCErrorSet(kSCStatusInvalidArgument);
1212 return NULL;
1213 }
1214
1215 return servicePrivate->serviceID;
1216 }
1217
1218
1219 CFTypeID
1220 SCNetworkServiceGetTypeID(void)
1221 {
1222 pthread_once(&initialized, __SCNetworkServiceInitialize); /* initialize runtime */
1223 return __kSCNetworkServiceTypeID;
1224 }
1225
1226
1227 Boolean
1228 SCNetworkServiceRemove(SCNetworkServiceRef service)
1229 {
1230 Boolean ok = FALSE;
1231 CFStringRef path;
1232 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1233 CFArrayRef sets;
1234
1235 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1236 _SCErrorSet(kSCStatusInvalidArgument);
1237 return FALSE;
1238 }
1239
1240 // remove service from all sets
1241
1242 sets = SCNetworkSetCopyAll(servicePrivate->prefs);
1243 if (sets != NULL) {
1244 CFIndex i;
1245 CFIndex n;
1246
1247 n = CFArrayGetCount(sets);
1248 for (i = 0; i < n; i++) {
1249 SCNetworkSetRef set;
1250
1251 set = CFArrayGetValueAtIndex(sets, i);
1252 ok = SCNetworkSetRemoveService(set, service);
1253 if (!ok && (SCError() != kSCStatusNoKey)) {
1254 CFRelease(sets);
1255 return ok;
1256 }
1257 }
1258 CFRelease(sets);
1259 }
1260
1261 // remove service
1262
1263 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1264 servicePrivate->serviceID, // service
1265 NULL); // entity
1266 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
1267 CFRelease(path);
1268
1269 return ok;
1270 }
1271
1272
1273 Boolean
1274 SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
1275 {
1276 CFDictionaryRef entity;
1277 Boolean ok = FALSE;
1278 CFStringRef path;
1279 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1280
1281 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1282 _SCErrorSet(kSCStatusInvalidArgument);
1283 return FALSE;
1284 }
1285
1286 if (!__SCNetworkProtocolIsValidType(protocolType)) {
1287 _SCErrorSet(kSCStatusInvalidArgument);
1288 return FALSE;
1289 }
1290
1291 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1292 servicePrivate->serviceID, // service
1293 protocolType); // entity
1294
1295 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1296 if (entity == NULL) {
1297 // if "protocol" does not exist
1298 _SCErrorSet(kSCStatusNoKey);
1299 goto done;
1300 }
1301
1302 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
1303
1304 done :
1305
1306 CFRelease(path);
1307 return ok;
1308 }
1309
1310
1311 Boolean
1312 SCNetworkServiceSetEnabled(SCNetworkServiceRef service, Boolean enabled)
1313 {
1314 Boolean ok;
1315 CFStringRef path;
1316 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1317
1318 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1319 _SCErrorSet(kSCStatusInvalidArgument);
1320 return FALSE;
1321 }
1322
1323 // make sure that we do not enable a network service if the
1324 // associated interface is a member of a bond or bridge.
1325 if (enabled) {
1326 SCNetworkInterfaceRef interface;
1327
1328 interface = SCNetworkServiceGetInterface(service);
1329 if ((interface != NULL) &&
1330 __SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) {
1331 _SCErrorSet(kSCStatusKeyExists);
1332 return FALSE;
1333 }
1334 }
1335
1336 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1337 servicePrivate->serviceID, // service
1338 NULL); // entity
1339 ok = __setPrefsEnabled(servicePrivate->prefs, path, enabled);
1340 CFRelease(path);
1341
1342 return ok;
1343 }
1344
1345
1346 Boolean
1347 SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name)
1348 {
1349 CFDictionaryRef entity;
1350 Boolean ok = FALSE;
1351 CFStringRef path;
1352 CFStringRef saveName = NULL;
1353 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1354
1355 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1356 _SCErrorSet(kSCStatusInvalidArgument);
1357 return FALSE;
1358 }
1359
1360 if (name != NULL) {
1361 if (!isA_CFString(name)) {
1362 _SCErrorSet(kSCStatusInvalidArgument);
1363 return FALSE;
1364 }
1365 saveName = CFRetain(name);
1366 }
1367
1368 if (name != NULL) {
1369 SCNetworkInterfaceRef interface;
1370
1371 interface = SCNetworkServiceGetInterface(service);
1372 while (interface != NULL) {
1373 SCNetworkInterfaceRef childInterface;
1374
1375 childInterface = SCNetworkInterfaceGetInterface(interface);
1376 if (childInterface == NULL) {
1377 break;
1378 }
1379
1380 interface = childInterface;
1381 }
1382
1383 if (interface != NULL) {
1384 CFStringRef interface_name;
1385
1386 interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
1387 if (interface_name != NULL) {
1388 if (CFEqual(name, interface_name)) {
1389 // if service name matches the localized interface name
1390 // then store the non-localized name.
1391 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
1392 if (interface_name != NULL) {
1393 CFRelease(saveName);
1394 saveName = CFRetain(interface_name);
1395 }
1396 } else if (CFStringHasPrefix(name, interface_name)) {
1397 CFIndex prefixLen = CFStringGetLength(interface_name);
1398 CFStringRef suffix;
1399 CFIndex suffixLen = CFStringGetLength(name);
1400
1401 // if service name matches the localized interface name plus
1402 // a few extra characters) then store the non-localized name with
1403 // the same suffix.
1404 suffix = CFStringCreateWithSubstring(NULL,
1405 name,
1406 CFRangeMake(prefixLen, suffixLen - prefixLen));
1407 interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
1408 if (interface_name != NULL) {
1409 CFRelease(saveName);
1410 saveName = CFStringCreateWithFormat(NULL,
1411 NULL,
1412 CFSTR("%@%@"),
1413 interface_name,
1414 suffix);
1415 }
1416 CFRelease(suffix);
1417 }
1418 }
1419 }
1420 }
1421
1422 #define PREVENT_DUPLICATE_SERVICE_NAMES
1423 #ifdef PREVENT_DUPLICATE_SERVICE_NAMES
1424 if (name != NULL) {
1425 CFArrayRef sets;
1426
1427 // ensure that each service is uniquely named within its sets
1428
1429 sets = SCNetworkSetCopyAll(servicePrivate->prefs);
1430 if (sets != NULL) {
1431 CFIndex set_index;
1432 CFIndex set_count;
1433
1434 set_count = CFArrayGetCount(sets);
1435 for (set_index = 0; set_index < set_count; set_index++) {
1436 CFIndex service_index;
1437 Boolean isDup = FALSE;
1438 Boolean isMember = FALSE;
1439 CFIndex service_count;
1440 CFArrayRef services;
1441 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, set_index);
1442
1443 services = SCNetworkSetCopyServices(set);
1444
1445 service_count = CFArrayGetCount(services);
1446 for (service_index = 0; service_index < service_count; service_index++) {
1447 CFStringRef otherID;
1448 CFStringRef otherName;
1449 SCNetworkServiceRef otherService;
1450
1451 otherService = CFArrayGetValueAtIndex(services, service_index);
1452
1453 otherID = SCNetworkServiceGetServiceID(otherService);
1454 if (CFEqual(servicePrivate->serviceID, otherID)) {
1455 // if the service is a member of this set
1456 isMember = TRUE;
1457 continue;
1458 }
1459
1460 otherName = SCNetworkServiceGetName(otherService);
1461 if ((otherName != NULL) && CFEqual(name, otherName)) {
1462 isDup = TRUE;
1463 continue;
1464 }
1465 }
1466
1467 CFRelease(services);
1468
1469 if (isMember && isDup) {
1470 /*
1471 * if this service is a member of the set and
1472 * the "name" is not unique.
1473 */
1474 CFRelease(sets);
1475 if (saveName != NULL) CFRelease(saveName);
1476 _SCErrorSet(kSCStatusKeyExists);
1477 return FALSE;
1478 }
1479 }
1480
1481 CFRelease(sets);
1482 }
1483 }
1484 #endif /* PREVENT_DUPLICATE_SERVICE_NAMES */
1485
1486 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1487 servicePrivate->serviceID, // service
1488 NULL); // entity
1489 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1490 if (isA_CFDictionary(entity) ||
1491 ((entity == NULL) && (name != NULL))) {
1492 CFMutableDictionaryRef newEntity;
1493
1494 if (entity != NULL) {
1495 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1496 } else {
1497 newEntity = CFDictionaryCreateMutable(NULL,
1498 0,
1499 &kCFTypeDictionaryKeyCallBacks,
1500 &kCFTypeDictionaryValueCallBacks);
1501 }
1502 if (saveName != NULL) {
1503 CFDictionarySetValue(newEntity, kSCPropUserDefinedName, saveName);
1504 } else {
1505 CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
1506 }
1507 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
1508 CFRelease(newEntity);
1509 }
1510 CFRelease(path);
1511 if (saveName != NULL) CFRelease(saveName);
1512
1513 if (servicePrivate->name != NULL) CFRelease(servicePrivate->name);
1514 if (name != NULL) CFRetain(name);
1515 servicePrivate->name = name;
1516
1517 return ok;
1518 }
1519
1520
1521 #pragma mark -
1522 #pragma mark SCNetworkService SPIs
1523
1524
1525 SCNetworkServicePrimaryRank
1526 SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service)
1527 {
1528 CFDictionaryRef entity;
1529 Boolean ok = TRUE;
1530 CFStringRef path;
1531 SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault;
1532 CFStringRef rankStr = NULL;
1533 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1534
1535 if (!isA_SCNetworkService(service)) {
1536 _SCErrorSet(kSCStatusInvalidArgument);
1537 return rank;
1538 }
1539
1540 if (servicePrivate->prefs != NULL) {
1541 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
1542 servicePrivate->serviceID,
1543 NULL);
1544 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1545 CFRelease(path);
1546 if (isA_CFDictionary(entity)) {
1547 rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
1548 ok = __str_to_rank(rankStr, &rank);
1549 }
1550 } else if (servicePrivate->store != NULL) {
1551 path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1552 kSCDynamicStoreDomainState,
1553 servicePrivate->serviceID,
1554 NULL);
1555 entity = SCDynamicStoreCopyValue(servicePrivate->store, path);
1556 CFRelease(path);
1557 if (entity != NULL) {
1558 if (isA_CFDictionary(entity)) {
1559 rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
1560 ok = __str_to_rank(rankStr, &rank);
1561 }
1562 CFRelease(entity);
1563 }
1564 } else {
1565 _SCErrorSet(kSCStatusInvalidArgument);
1566 return rank;
1567 }
1568
1569 if (!ok) {
1570 rank = kSCNetworkServicePrimaryRankDefault;
1571 _SCErrorSet(kSCStatusInvalidArgument);
1572 } else if (rank == kSCNetworkServicePrimaryRankDefault) {
1573 _SCErrorSet(kSCStatusOK);
1574 }
1575
1576 return rank;
1577 }
1578
1579
1580 Boolean
1581 SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service,
1582 SCNetworkServicePrimaryRank newRank)
1583 {
1584 Boolean ok;
1585 CFDictionaryRef entity;
1586 CFMutableDictionaryRef newEntity;
1587 CFStringRef path = NULL;
1588 CFStringRef rankStr = NULL;
1589 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1590
1591 if (!isA_SCNetworkService(service)) {
1592 _SCErrorSet(kSCStatusInvalidArgument);
1593 return FALSE;
1594 }
1595
1596 ok = __rank_to_str(newRank, &rankStr);
1597 if (!ok) {
1598 _SCErrorSet(kSCStatusInvalidArgument);
1599 return FALSE;
1600 }
1601
1602 if (servicePrivate->prefs != NULL) {
1603 switch (newRank) {
1604 case kSCNetworkServicePrimaryRankDefault:
1605 case kSCNetworkServicePrimaryRankNever:
1606 case kSCNetworkServicePrimaryRankScoped:
1607 path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
1608 servicePrivate->serviceID,
1609 NULL);
1610 entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
1611 if (entity != NULL) {
1612 if (!isA_CFDictionary(entity)) {
1613 // if corrupt prefs
1614 _SCErrorSet(kSCStatusFailed);
1615 goto done;
1616 }
1617 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1618 } else {
1619 newEntity = CFDictionaryCreateMutable(NULL,
1620 0,
1621 &kCFTypeDictionaryKeyCallBacks,
1622 &kCFTypeDictionaryValueCallBacks);
1623 }
1624 if (rankStr != NULL) {
1625 CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
1626 } else {
1627 CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
1628 }
1629 if (CFDictionaryGetCount(newEntity) > 0) {
1630 ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
1631 } else {
1632 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
1633 }
1634 CFRelease(newEntity);
1635 if (!ok) {
1636 goto done;
1637 }
1638 break;
1639 default:
1640 _SCErrorSet(kSCStatusInvalidArgument);
1641 return FALSE;
1642 }
1643 } else if (servicePrivate->store != NULL) {
1644 path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1645 kSCDynamicStoreDomainState,
1646 servicePrivate->serviceID,
1647 NULL);
1648 entity = SCDynamicStoreCopyValue(servicePrivate->store, path);
1649 if (entity != NULL) {
1650 if (!isA_CFDictionary(entity)) {
1651 // if corrupt prefs
1652 CFRelease(entity);
1653 _SCErrorSet(kSCStatusFailed);
1654 goto done;
1655 }
1656 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1657 CFRelease(entity);
1658 } else {
1659 newEntity = CFDictionaryCreateMutable(NULL,
1660 0,
1661 &kCFTypeDictionaryKeyCallBacks,
1662 &kCFTypeDictionaryValueCallBacks);
1663 }
1664 if (rankStr != NULL) {
1665 CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
1666 } else {
1667 CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
1668 }
1669 if (CFDictionaryGetCount(newEntity) > 0) {
1670 ok = SCDynamicStoreSetValue(servicePrivate->store, path, newEntity);
1671 } else {
1672 ok = SCDynamicStoreRemoveValue(servicePrivate->store, path);
1673 }
1674 CFRelease(newEntity);
1675 if (!ok) {
1676 goto done;
1677 }
1678 } else {
1679 _SCErrorSet(kSCStatusInvalidArgument);
1680 return FALSE;
1681 }
1682
1683 done :
1684
1685 if (path != NULL) CFRelease(path);
1686 return ok;
1687 }
1688
1689
1690 Boolean
1691 _SCNetworkServiceIsVPN(SCNetworkServiceRef service)
1692 {
1693 SCNetworkInterfaceRef interface;
1694 CFStringRef interfaceType;
1695
1696 interface = SCNetworkServiceGetInterface(service);
1697 if (interface == NULL) {
1698 return FALSE;
1699 }
1700
1701 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
1702 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
1703 interface = SCNetworkInterfaceGetInterface(interface);
1704 if (interface == NULL) {
1705 return FALSE;
1706 }
1707
1708 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
1709 if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
1710 return TRUE;
1711 }
1712 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
1713 return TRUE;
1714 }
1715 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
1716 return TRUE;
1717 } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
1718 return TRUE;
1719 }
1720
1721 return FALSE;
1722 }
1723
1724
1725 Boolean
1726 SCNetworkServiceSetExternalID(SCNetworkServiceRef service, CFStringRef identifierDomain, CFStringRef identifier)
1727 {
1728 CFStringRef prefs_path;
1729 CFDictionaryRef service_dictionary;
1730 SCNetworkServicePrivateRef service_private = (SCNetworkServicePrivateRef)service;
1731 Boolean success = FALSE;
1732 CFStringRef prefixed_domain;
1733
1734 if (!isA_SCNetworkService(service) || (service_private->prefs == NULL) || !isA_CFString(identifierDomain)) {
1735 _SCErrorSet(kSCStatusInvalidArgument);
1736 return FALSE;
1737 }
1738
1739 if (identifier != NULL && !isA_CFString(identifier)) {
1740 _SCErrorSet(kSCStatusInvalidArgument);
1741 return FALSE;
1742 }
1743
1744 prefixed_domain = CFStringCreateWithFormat(NULL, 0, CFSTR("%s%@"), EXTERNAL_ID_DOMAIN_PREFIX, identifierDomain);
1745
1746 prefs_path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
1747 service_private->serviceID,
1748 NULL);
1749
1750 service_dictionary = SCPreferencesPathGetValue(service_private->prefs, prefs_path);
1751 if (isA_CFDictionary(service_dictionary) || ((service_dictionary == NULL) && (identifier != NULL))) {
1752 CFMutableDictionaryRef new_service_dictionary;
1753
1754 if (service_dictionary != NULL) {
1755 new_service_dictionary = CFDictionaryCreateMutableCopy(NULL, 0, service_dictionary);
1756 } else {
1757 new_service_dictionary = CFDictionaryCreateMutable(NULL,
1758 0,
1759 &kCFTypeDictionaryKeyCallBacks,
1760 &kCFTypeDictionaryValueCallBacks);
1761 }
1762
1763 if (identifier != NULL) {
1764 CFDictionarySetValue(new_service_dictionary, prefixed_domain, identifier);
1765 } else {
1766 CFDictionaryRemoveValue(new_service_dictionary, prefixed_domain);
1767 }
1768 success = SCPreferencesPathSetValue(service_private->prefs, prefs_path, new_service_dictionary);
1769 CFRelease(new_service_dictionary);
1770 }
1771 CFRelease(prefs_path);
1772
1773 if (identifier != NULL) {
1774 if (service_private->externalIDs == NULL) {
1775 service_private->externalIDs = CFDictionaryCreateMutable(NULL,
1776 0,
1777 &kCFTypeDictionaryKeyCallBacks,
1778 &kCFTypeDictionaryValueCallBacks);
1779 }
1780 CFDictionarySetValue(service_private->externalIDs, prefixed_domain, identifier);
1781 } else {
1782 if (service_private->externalIDs != NULL) {
1783 CFDictionaryRemoveValue(service_private->externalIDs, prefixed_domain);
1784 }
1785 }
1786
1787 CFRelease(prefixed_domain);
1788
1789 if (!success) {
1790 _SCErrorSet(kSCStatusFailed);
1791 }
1792
1793 return success;
1794 }
1795
1796
1797 CFStringRef
1798 SCNetworkServiceCopyExternalID(SCNetworkServiceRef service, CFStringRef identifierDomain)
1799 {
1800 SCNetworkServicePrivateRef service_private = (SCNetworkServicePrivateRef)service;
1801 CFStringRef identifier = NULL;
1802 CFStringRef prefixed_domain;
1803
1804 if (!isA_SCNetworkService(service) || (service_private->prefs == NULL) || !isA_CFString(identifierDomain)) {
1805 _SCErrorSet(kSCStatusInvalidArgument);
1806 return NULL;
1807 }
1808
1809 prefixed_domain = CFStringCreateWithFormat(NULL, 0, CFSTR("%s%@"), EXTERNAL_ID_DOMAIN_PREFIX, identifierDomain);
1810
1811 if (service_private->externalIDs != NULL) {
1812 identifier = CFDictionaryGetValue(service_private->externalIDs, prefixed_domain);
1813 if (identifier != NULL) {
1814 CFRetain(identifier);
1815 }
1816 }
1817
1818 if (identifier == NULL) {
1819 CFStringRef prefs_path;
1820 CFDictionaryRef service_dictionary;
1821
1822 prefs_path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
1823 service_private->serviceID,
1824 NULL);
1825
1826 service_dictionary = SCPreferencesPathGetValue(service_private->prefs, prefs_path);
1827 if (isA_CFDictionary(service_dictionary)) {
1828 identifier = CFDictionaryGetValue(service_dictionary, prefixed_domain);
1829 if (identifier != NULL) {
1830 CFRetain(identifier);
1831 if (service_private->externalIDs == NULL) {
1832 service_private->externalIDs = CFDictionaryCreateMutable(NULL,
1833 0,
1834 &kCFTypeDictionaryKeyCallBacks,
1835 &kCFTypeDictionaryValueCallBacks);
1836 }
1837 CFDictionarySetValue(service_private->externalIDs, prefixed_domain, identifier);
1838 }
1839 }
1840 CFRelease(prefs_path);
1841 }
1842
1843 CFRelease(prefixed_domain);
1844
1845 if (identifier == NULL) {
1846 _SCErrorSet(kSCStatusNoKey);
1847 }
1848
1849 return identifier;
1850 }
1851
1852
1853 typedef struct {
1854 CFStringRef oldServiceID;
1855 CFStringRef newServiceID;
1856 } serviceContext, *serviceContextRef;
1857
1858
1859 static void
1860 replaceServiceID(const void *value, void *context)
1861 {
1862 CFStringRef link = NULL;
1863 CFStringRef oldLink;
1864 CFMutableArrayRef newServiceOrder;
1865 CFStringRef path;
1866 serviceContextRef service_context = (serviceContextRef)context;
1867 CFArrayRef serviceOrder = NULL;
1868 SCNetworkSetRef set = (SCNetworkSetRef)value;
1869 SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
1870
1871 // update service order
1872 serviceOrder = SCNetworkSetGetServiceOrder(set);
1873 if ((isA_CFArray(serviceOrder) != NULL) &&
1874 (CFArrayContainsValue(serviceOrder,
1875 CFRangeMake(0, CFArrayGetCount(serviceOrder)),
1876 service_context->oldServiceID) == TRUE)) {
1877 CFIndex count;
1878 CFIndex serviceOrderIndex;
1879
1880 // replacing all instances of old service ID with new one
1881 newServiceOrder = CFArrayCreateMutableCopy(NULL, 0, serviceOrder);
1882 count = CFArrayGetCount(newServiceOrder);
1883 for (serviceOrderIndex = 0; serviceOrderIndex < count; serviceOrderIndex++) {
1884 CFStringRef serviceID;
1885
1886 serviceID = CFArrayGetValueAtIndex(newServiceOrder, serviceOrderIndex);
1887 if (CFEqual(serviceID, service_context->oldServiceID)) {
1888 CFArraySetValueAtIndex(newServiceOrder, serviceOrderIndex, service_context->newServiceID);
1889 }
1890 }
1891 SCNetworkSetSetServiceOrder(set, newServiceOrder);
1892 CFRelease(newServiceOrder);
1893 }
1894
1895 // check if service with old serviceID is part of the set
1896 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator
1897 setPrivate->setID, // set
1898 service_context->oldServiceID, // service
1899 NULL); // entity
1900 oldLink = SCPreferencesPathGetLink(setPrivate->prefs, path);
1901 if (oldLink == NULL) {
1902 // don't make any changes if service with old serviceID is not found
1903 goto done;
1904 }
1905
1906 // remove link between "set" and old "service"
1907 SCPreferencesPathRemoveValue(setPrivate->prefs, path);
1908 CFRelease(path);
1909
1910 // create the link between "set" and the "service"
1911 path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator
1912 setPrivate->setID, // set
1913 service_context->newServiceID, // service
1914 NULL); // entity
1915 link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1916 service_context->newServiceID, // service
1917 NULL); // entity
1918 SCPreferencesPathSetLink(setPrivate->prefs, path, link);
1919
1920 done:
1921
1922 if (path != NULL) {
1923 CFRelease(path);
1924 }
1925 if (link != NULL) {
1926 CFRelease(link);
1927 }
1928
1929 return;
1930 }
1931
1932
1933 Boolean
1934 _SCNetworkServiceSetServiceID(SCNetworkServiceRef service, CFStringRef newServiceID)
1935 {
1936 CFArrayRef allSets = NULL;
1937 CFDictionaryRef entity;
1938 CFStringRef newPath;
1939 Boolean ok = FALSE;
1940 CFStringRef oldPath = NULL;
1941 serviceContext service_context;
1942 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
1943
1944 if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
1945 _SCErrorSet(kSCStatusInvalidArgument);
1946 return FALSE;
1947 }
1948
1949 if (!isA_CFString(newServiceID)) {
1950 _SCErrorSet(kSCStatusInvalidArgument);
1951 return FALSE;
1952 }
1953
1954 if (CFEqual(newServiceID, servicePrivate->serviceID)) {
1955 // no work needs to be done if new service ID is equal to current service ID
1956 return TRUE;
1957 }
1958
1959 newPath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1960 newServiceID, // service
1961 NULL); // entity
1962 entity = SCPreferencesPathGetValue(servicePrivate->prefs, newPath);
1963 if (isA_CFDictionary(entity)) {
1964 // if the new service already exists
1965 _SCErrorSet(kSCStatusKeyExists);
1966 goto done;
1967 }
1968
1969 oldPath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
1970 servicePrivate->serviceID, // service
1971 NULL); // entity
1972 entity = SCPreferencesPathGetValue(servicePrivate->prefs, oldPath);
1973 if (!isA_CFDictionary(entity)) {
1974 // if the service has already been removed
1975 _SCErrorSet(kSCStatusNoKey);
1976 goto done;
1977 }
1978
1979 ok = SCPreferencesPathSetValue(servicePrivate->prefs, newPath, entity);
1980 if (!ok) goto done;
1981
1982 ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, oldPath);
1983 if (!ok) goto done;
1984
1985 allSets = SCNetworkSetCopyAll(servicePrivate->prefs);
1986
1987 service_context.newServiceID = newServiceID;
1988 service_context.oldServiceID = servicePrivate->serviceID;
1989
1990 // find all sets w/oldServiceID and update
1991 // ... and update the serviceOrder
1992 CFArrayApplyFunction(allSets,
1993 CFRangeMake(0, CFArrayGetCount(allSets)),
1994 replaceServiceID,
1995 &service_context);
1996
1997 if (servicePrivate->interface != NULL) {
1998 SCNetworkInterfaceRef newInterface;
1999
2000 // duplicate the interface and associate the copy with the new service ID
2001 newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,
2002 servicePrivate->interface,
2003 servicePrivate->prefs,
2004 newServiceID);
2005 CFRelease(servicePrivate->interface);
2006 servicePrivate->interface = newInterface;
2007 }
2008
2009 // replace serviceID with new one
2010 CFRetain(newServiceID);
2011 CFRelease(servicePrivate->serviceID);
2012 servicePrivate->serviceID = newServiceID;
2013
2014 done:
2015
2016 if (oldPath != NULL) {
2017 CFRelease(oldPath);
2018 }
2019 if (newPath != NULL) {
2020 CFRelease(newPath);
2021 }
2022 if (allSets != NULL) {
2023 CFRelease(allSets);
2024 }
2025 return ok;
2026 }
2027
2028 #define kVPNProtocolPayloadInfo CFSTR("com.apple.payload")
2029 #define kSCEntNetLoginWindowEAPOL CFSTR("EAPOL.LoginWindow")
2030
2031 static void
2032 copyInterfaceConfiguration(SCNetworkServiceRef oldService, SCNetworkServiceRef newService)
2033 {
2034 SCNetworkInterfaceRef oldInterface;
2035 SCNetworkInterfaceRef newInterface;
2036
2037 oldInterface = SCNetworkServiceGetInterface(oldService);
2038 newInterface = SCNetworkServiceGetInterface(newService);
2039
2040 while (oldInterface != NULL) {
2041 CFDictionaryRef configuration;
2042 CFStringRef interfaceType;
2043
2044 if (newInterface == NULL) {
2045 // oops ... interface layering does not match
2046 return;
2047 }
2048
2049 // copy interface configuration
2050 configuration = SCNetworkInterfaceGetConfiguration(oldInterface);
2051
2052 if ((configuration != NULL) ||
2053 (SCError() == kSCStatusOK)) {
2054 if (SCNetworkInterfaceSetConfiguration(newInterface, configuration) == FALSE) {
2055 SC_log(LOG_INFO, "problem setting interface configuration");
2056 }
2057
2058 }
2059
2060 // special case: PPP/L2TP + IPSec
2061 interfaceType = SCNetworkInterfaceGetInterfaceType(oldInterface);
2062 if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
2063 SCNetworkInterfaceRef childInterface;
2064
2065 childInterface = SCNetworkInterfaceGetInterface(oldInterface);
2066 if (childInterface != NULL) {
2067 CFStringRef childInterfaceType;
2068
2069 childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
2070
2071 if (CFEqual(childInterfaceType, kSCNetworkInterfaceTypeL2TP)) {
2072 configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetIPSec);
2073 if ((configuration != NULL) ||
2074 (SCError() == kSCStatusOK)) {
2075 if (SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetIPSec, configuration) == FALSE) {
2076 SC_log(LOG_INFO, "problem setting child interface configuration");
2077 }
2078 }
2079 }
2080 }
2081 }
2082
2083 // special case: 802.1x
2084 configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetEAPOL);
2085 if ((configuration != NULL) ||
2086 (SCError() == kSCStatusOK)) {
2087 (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetEAPOL, configuration);
2088 }
2089
2090 // special case: Managed Client
2091 configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kVPNProtocolPayloadInfo);
2092 if ((configuration != NULL) ||
2093 (SCError() == kSCStatusOK)) {
2094 (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kVPNProtocolPayloadInfo, configuration);
2095 }
2096
2097 // special case: Network Pref
2098 configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCValNetPPPAuthProtocolEAP);
2099 if ((configuration != NULL) ||
2100 (SCError() == kSCStatusOK)) {
2101 (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCValNetPPPAuthProtocolEAP, configuration);
2102 }
2103
2104 // special case: Remote Pref
2105 configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetLoginWindowEAPOL);
2106 if ((configuration != NULL) ||
2107 (SCError() == kSCStatusOK)) {
2108 (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetLoginWindowEAPOL, configuration);
2109 }
2110
2111 // special case: Network Extension
2112 configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCNetworkInterfaceTypeIPSec);
2113 if ((configuration != NULL) ||
2114 (SCError() == kSCStatusOK)) {
2115 (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCNetworkInterfaceTypeIPSec, configuration);
2116 }
2117
2118 oldInterface = SCNetworkInterfaceGetInterface(oldInterface);
2119 newInterface = SCNetworkInterfaceGetInterface(newInterface);
2120 }
2121
2122 return;
2123 }
2124
2125 __private_extern__
2126 void
2127 __SCNetworkServiceAddProtocolToService(SCNetworkServiceRef service, CFStringRef protocolType, CFDictionaryRef configuration, Boolean enabled)
2128 {
2129 Boolean ok;
2130 SCNetworkProtocolRef protocol;
2131
2132 protocol = SCNetworkServiceCopyProtocol(service, protocolType);
2133
2134 if ((protocol == NULL) &&
2135 (SCError() == kSCStatusNoKey)) {
2136 ok = SCNetworkServiceAddProtocolType(service, protocolType);
2137 if (ok) {
2138 protocol = SCNetworkServiceCopyProtocol(service, protocolType);
2139 }
2140 }
2141 if (protocol != NULL) {
2142 SCNetworkProtocolSetConfiguration(protocol, configuration);
2143 SCNetworkProtocolSetEnabled(protocol, enabled);
2144 CFRelease(protocol);
2145 }
2146 return;
2147 }
2148
2149
2150
2151 __private_extern__
2152 Boolean
2153 __SCNetworkServiceMigrateNew(SCPreferencesRef prefs,
2154 SCNetworkServiceRef service,
2155 CFDictionaryRef bsdMapping,
2156 CFDictionaryRef setMapping,
2157 CFDictionaryRef serviceSetMapping)
2158 {
2159 CFStringRef deviceName = NULL;
2160 Boolean enabled;
2161 SCNetworkInterfaceRef interface = NULL;
2162 CFDictionaryRef interfaceEntity = NULL;
2163 CFMutableDictionaryRef interfaceEntityMutable = NULL;
2164 SCNetworkSetRef newSet = NULL;
2165 SCPreferencesRef ni_prefs = NULL;
2166 SCNetworkInterfaceRef ni_interface = NULL;
2167 SCNetworkInterfaceRef oldInterface = NULL;
2168 SCNetworkSetRef oldSet = NULL;
2169 SCNetworkServiceRef newService = NULL;
2170 CFStringRef serviceID = NULL;
2171 SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef) service;
2172 CFMutableDictionaryRef servicesMutable = NULL;
2173 CFArrayRef setList = NULL;
2174 Boolean success = FALSE;
2175 CFStringRef targetDeviceName = NULL;
2176 CFStringRef userDefinedName = NULL;
2177 CFStringRef userDefinedNameInterface = NULL;
2178 CFArrayRef protocols = NULL;
2179 CFStringRef subType;
2180
2181 if ((isA_SCNetworkService(service) == NULL) ||
2182 (isA_SCNetworkInterface(servicePrivate->interface) == NULL) ||
2183 (servicePrivate->prefs == NULL)) {
2184 goto done;
2185 }
2186 serviceID = servicePrivate->serviceID;
2187
2188 newService = SCNetworkServiceCopy(prefs, serviceID);
2189 if (newService != NULL) {
2190 // Cannot add service if it already exists
2191 SC_log(LOG_INFO, "Service already exists");
2192 goto done;
2193 }
2194
2195 oldInterface = SCNetworkServiceGetInterface(service);
2196 interfaceEntity = __SCNetworkInterfaceCopyInterfaceEntity(oldInterface);
2197 if (interfaceEntity == NULL) {
2198 SC_log(LOG_INFO, "No interface entity");
2199 goto done;
2200 }
2201 interfaceEntityMutable = CFDictionaryCreateMutableCopy(NULL, 0, interfaceEntity);
2202
2203 if (isA_CFDictionary(bsdMapping) != NULL) {
2204 deviceName = CFDictionaryGetValue(interfaceEntityMutable, kSCPropNetInterfaceDeviceName);
2205 if (isA_CFString(deviceName) != NULL) {
2206 targetDeviceName = CFDictionaryGetValue(bsdMapping, deviceName);
2207 if (targetDeviceName != NULL) {
2208 // update mapping
2209 CFDictionarySetValue(interfaceEntityMutable, kSCPropNetInterfaceDeviceName, targetDeviceName);
2210 ni_prefs = __SCPreferencesCreateNIPrefsFromPrefs(prefs);
2211 ni_interface = __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL, ni_prefs, targetDeviceName);
2212 if (ni_interface != NULL) {
2213 userDefinedNameInterface = __SCNetworkInterfaceGetUserDefinedName(ni_interface);
2214 }
2215 }
2216 }
2217 if (userDefinedNameInterface == NULL) {
2218 userDefinedNameInterface = CFDictionaryGetValue(interfaceEntityMutable, kSCPropUserDefinedName);
2219 }
2220 }
2221 subType = CFDictionaryGetValue(interfaceEntityMutable, kSCPropNetInterfaceSubType);
2222 interface = _SCNetworkInterfaceCreateWithEntity(NULL, interfaceEntityMutable, NULL);
2223 if (userDefinedNameInterface != NULL) {
2224 __SCNetworkInterfaceSetUserDefinedName(interface, userDefinedNameInterface);
2225 }
2226 // Supporting PPPoE subtype
2227 if (subType != NULL &&
2228 CFEqual(subType, kSCValNetInterfaceSubTypePPPoE)) {
2229 SCNetworkInterfaceRef childInterface = SCNetworkInterfaceGetInterface(interface);
2230 if (childInterface != NULL) {
2231 __SCNetworkInterfaceSetUserDefinedName(childInterface, userDefinedNameInterface);
2232 }
2233 }
2234 newService = SCNetworkServiceCreate(prefs, interface);
2235 if (newService == NULL) {
2236 SC_log(LOG_INFO, "SCNetworkServiceCreate() failed");
2237 goto done;
2238 }
2239
2240 enabled = SCNetworkServiceGetEnabled(service);
2241 SCNetworkServiceSetEnabled(newService, enabled);
2242
2243 if (SCNetworkServiceEstablishDefaultConfiguration(newService) == FALSE) {
2244 SCNetworkServiceRemove(newService);
2245 SC_log(LOG_INFO, "SCNetworkServiceEstablishDefaultConfiguration() failed");
2246 goto done;
2247 }
2248
2249 // Set service ID
2250 _SCNetworkServiceSetServiceID(newService, serviceID);
2251
2252 userDefinedName = SCNetworkServiceGetName(service);
2253 if (userDefinedName != NULL &&
2254 SCNetworkServiceSetName(newService, userDefinedName) == FALSE) {
2255 SC_log(LOG_INFO, "SCNetworkServiceSetName(, %@) failed", userDefinedName);
2256 }
2257
2258 // Determine which sets to add service
2259 if (setMapping != NULL &&
2260 serviceSetMapping != NULL) {
2261 setList = CFDictionaryGetValue(serviceSetMapping, service);
2262 if (setList != NULL) {
2263 for (CFIndex idx = 0; idx < CFArrayGetCount(setList); idx++) {
2264 oldSet = CFArrayGetValueAtIndex(setList, idx);
2265 newSet = CFDictionaryGetValue(setMapping, oldSet);
2266
2267 if (newSet == NULL) {
2268 continue;
2269 }
2270 if (SCNetworkSetAddService(newSet, newService) == FALSE) {
2271 SC_log(LOG_INFO, "SCNetworkSetAddService() failed");
2272 continue;
2273 }
2274 }
2275 }
2276 }
2277
2278 protocols = SCNetworkServiceCopyProtocols(service);
2279 if (protocols != NULL) {
2280
2281 for (CFIndex idx = 0; idx < CFArrayGetCount(protocols); idx++) {
2282 SCNetworkProtocolRef protocol = CFArrayGetValueAtIndex(protocols, idx);
2283 CFDictionaryRef configuration = SCNetworkProtocolGetConfiguration(protocol);
2284 CFStringRef protocolType = SCNetworkProtocolGetProtocolType(protocol);
2285 enabled = SCNetworkProtocolGetEnabled(protocol);
2286 __SCNetworkServiceAddProtocolToService(newService, protocolType, configuration, enabled);
2287 }
2288 CFRelease(protocols);
2289 }
2290
2291 copyInterfaceConfiguration(service, newService);
2292
2293 success = TRUE;
2294 done:
2295 if (interface != NULL) {
2296 CFRelease(interface);
2297 }
2298 if (interfaceEntity != NULL) {
2299 CFRelease(interfaceEntity);
2300 }
2301 if (interfaceEntityMutable != NULL) {
2302 CFRelease(interfaceEntityMutable);
2303 }
2304 if (newService != NULL) {
2305 CFRelease(newService);
2306 }
2307 if (servicesMutable != NULL) {
2308 CFRelease(servicesMutable);
2309 }
2310 if (ni_prefs != NULL) {
2311 CFRelease(ni_prefs);
2312 }
2313 if (ni_interface != NULL) {
2314 CFRelease(ni_interface);
2315 }
2316 return success;
2317 }
2318
2319
2320 __private_extern__
2321 Boolean
2322 __SCNetworkServiceCreate(SCPreferencesRef prefs,
2323 SCNetworkInterfaceRef interface,
2324 CFStringRef userDefinedName)
2325 {
2326 SCNetworkSetRef currentSet = NULL;
2327 Boolean ok = FALSE;
2328 SCNetworkServiceRef service = NULL;
2329
2330 if (interface == NULL) {
2331 goto done;
2332 }
2333
2334 if (userDefinedName == NULL) {
2335 userDefinedName = __SCNetworkInterfaceGetUserDefinedName(interface);
2336 if (userDefinedName == NULL) {
2337 SC_log(LOG_INFO, "No userDefinedName");
2338 goto done;
2339 }
2340 }
2341 service = SCNetworkServiceCreate(prefs, interface);
2342 if (service == NULL) {
2343 SC_log(LOG_INFO, "SCNetworkServiceCreate() failed: %s", SCErrorString(SCError()));
2344 } else {
2345 ok = SCNetworkServiceSetName(service, userDefinedName);
2346 if (ok == FALSE) {
2347 SC_log(LOG_INFO, "SCNetworkServiceSetName() failed: %s", SCErrorString(SCError()));
2348 SCNetworkServiceRemove(service);
2349 goto done;
2350 }
2351
2352 ok = SCNetworkServiceEstablishDefaultConfiguration(service);
2353 if (ok == FALSE) {
2354 SC_log(LOG_INFO, "SCNetworkServiceEstablishDefaultConfiguration() failed: %s", SCErrorString(SCError()));
2355 SCNetworkServiceRemove(service);
2356 goto done;
2357 }
2358 }
2359 currentSet = SCNetworkSetCopyCurrent(prefs);
2360 if (currentSet == NULL) {
2361 SC_log(LOG_INFO, "No current set");
2362 if (service != NULL) {
2363 SCNetworkServiceRemove(service);
2364 }
2365 goto done;
2366 }
2367 if (service != NULL) {
2368 ok = SCNetworkSetAddService(currentSet, service);
2369 if (ok == FALSE) {
2370 SC_log(LOG_INFO, "Could not add service to the current set");
2371 SCNetworkServiceRemove(service);
2372 goto done;
2373 }
2374 }
2375
2376 done:
2377 if (service != NULL) {
2378 CFRelease(service);
2379 }
2380 if (currentSet != NULL) {
2381 CFRelease(currentSet);
2382 }
2383 return ok;
2384 }