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