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