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