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