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