]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkConfigurationInternal.c
configd-963.50.8.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkConfigurationInternal.c
1 /*
2 * Copyright (c) 2004-2007, 2009, 2010-2013, 2015, 2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * May 27, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include "SCNetworkConfigurationInternal.h"
33
34 #include <sys/ioctl.h>
35 #include <net/if.h>
36
37
38 __private_extern__ os_log_t
39 __log_SCNetworkConfiguration()
40 {
41 static os_log_t log = NULL;
42
43 if (log == NULL) {
44 log = os_log_create("com.apple.SystemConfiguration", "SCNetworkConfiguration");
45 }
46
47 return log;
48 }
49
50
51 __private_extern__ CFDictionaryRef
52 __getPrefsConfiguration(SCPreferencesRef prefs, CFStringRef path)
53 {
54 CFDictionaryRef config;
55 CFIndex n;
56
57 config = SCPreferencesPathGetValue(prefs, path);
58
59 n = isA_CFDictionary(config) ? CFDictionaryGetCount(config) : 0;
60 switch (n) {
61 case 0 :
62 // ignore empty configuration entities
63 config = NULL;
64 break;
65 case 1 :
66 if (CFDictionaryContainsKey(config, kSCResvInactive)) {
67 // ignore [effectively] empty configuration entities
68 config = NULL;
69 }
70 break;
71 default :
72 break;
73 }
74
75 return config;
76 }
77
78
79 __private_extern__ Boolean
80 __setPrefsConfiguration(SCPreferencesRef prefs,
81 CFStringRef path,
82 CFDictionaryRef config,
83 Boolean keepInactive)
84 {
85 CFDictionaryRef curConfig;
86 CFMutableDictionaryRef newConfig = NULL;
87 Boolean ok;
88
89 if ((config != NULL) && !isA_CFDictionary(config)) {
90 _SCErrorSet(kSCStatusInvalidArgument);
91 return FALSE;
92 }
93
94 curConfig = SCPreferencesPathGetValue(prefs, path);
95
96 if (config != NULL) {
97 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
98 }
99
100 if (keepInactive) {
101 if (config == NULL) {
102 newConfig = CFDictionaryCreateMutable(NULL,
103 0,
104 &kCFTypeDictionaryKeyCallBacks,
105 &kCFTypeDictionaryValueCallBacks);
106 }
107
108 if (isA_CFDictionary(curConfig) && CFDictionaryContainsKey(curConfig, kSCResvInactive)) {
109 // if currently disabled
110 CFDictionarySetValue(newConfig, kSCResvInactive, kCFBooleanTrue);
111 } else {
112 // if currently enabled
113 CFDictionaryRemoveValue(newConfig, kSCResvInactive);
114 }
115 }
116
117 // set new configuration
118 if (_SC_CFEqual(curConfig, newConfig)) {
119 // if no change
120 if (newConfig != NULL) CFRelease(newConfig);
121 ok = TRUE;
122 } else if (newConfig != NULL) {
123 // if new configuration (or we are preserving a disabled state)
124 ok = SCPreferencesPathSetValue(prefs, path, newConfig);
125 CFRelease(newConfig);
126 } else {
127 ok = SCPreferencesPathRemoveValue(prefs, path);
128 if (!ok && (SCError() == kSCStatusNoKey)) {
129 ok = TRUE;
130 }
131 }
132
133 return ok;
134 }
135
136
137 __private_extern__ Boolean
138 __getPrefsEnabled(SCPreferencesRef prefs, CFStringRef path)
139 {
140 CFDictionaryRef config;
141
142 config = SCPreferencesPathGetValue(prefs, path);
143 if (isA_CFDictionary(config) && CFDictionaryContainsKey(config, kSCResvInactive)) {
144 return FALSE;
145 }
146
147 return TRUE;
148 }
149
150
151 __private_extern__ Boolean
152 __setPrefsEnabled(SCPreferencesRef prefs,
153 CFStringRef path,
154 Boolean enabled)
155 {
156 CFDictionaryRef curConfig;
157 CFMutableDictionaryRef newConfig = NULL;
158 Boolean ok = FALSE;
159
160 // preserve current configuration
161 curConfig = SCPreferencesPathGetValue(prefs, path);
162 if (curConfig != NULL) {
163 if (!isA_CFDictionary(curConfig)) {
164 _SCErrorSet(kSCStatusFailed);
165 return FALSE;
166 }
167 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, curConfig);
168
169 if (enabled) {
170 // enable
171 CFDictionaryRemoveValue(newConfig, kSCResvInactive);
172 } else {
173 // disable
174 CFDictionarySetValue(newConfig, kSCResvInactive, kCFBooleanTrue);
175 }
176 } else {
177 if (!enabled) {
178 // disable
179 newConfig = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
180 CFDictionarySetValue(newConfig, kSCResvInactive, kCFBooleanTrue);
181 }
182 }
183
184 // set new configuration
185 if (_SC_CFEqual(curConfig, newConfig)) {
186 // if no change
187 if (newConfig != NULL) CFRelease(newConfig);
188 ok = TRUE;
189 } else if (newConfig != NULL) {
190 // if updated configuration (or we are establishing as disabled)
191 ok = SCPreferencesPathSetValue(prefs, path, newConfig);
192 CFRelease(newConfig);
193 } else {
194 ok = SCPreferencesPathRemoveValue(prefs, path);
195 if (!ok && (SCError() == kSCStatusNoKey)) {
196 ok = TRUE;
197 }
198 }
199
200 return ok;
201 }
202
203 #if !TARGET_OS_EMBEDDED
204 #define SYSTEMCONFIGURATION_RESOURCES_PATH SYSTEMCONFIGURATION_FRAMEWORK_PATH "/Resources"
205 #else
206 #define SYSTEMCONFIGURATION_RESOURCES_PATH SYSTEMCONFIGURATION_FRAMEWORK_PATH
207 #endif // !TARGET_OS_EMBEDDED
208
209 #define NETWORKCONFIGURATION_RESOURCE_FILE "NetworkConfiguration.plist"
210
211 static CFDictionaryRef
212 __copyTemplates()
213 {
214 CFBundleRef bundle;
215 CFDictionaryRef templates;
216 CFURLRef url;
217
218 bundle = _SC_CFBundleGet();
219 if (bundle == NULL) {
220 return NULL;
221 }
222
223 url = CFBundleCopyResourceURL(bundle, CFSTR("NetworkConfiguration"), CFSTR("plist"), NULL);
224 if (url == NULL) {
225 SC_log(LOG_ERR, "failed to GET resource URL to \"%s\". Trying harder...", NETWORKCONFIGURATION_RESOURCE_FILE);
226 url = CFURLCreateWithFileSystemPath(NULL,
227 CFSTR(SYSTEMCONFIGURATION_RESOURCES_PATH
228 "/"
229 NETWORKCONFIGURATION_RESOURCE_FILE),
230 kCFURLPOSIXPathStyle,
231 TRUE);
232
233 if (url == NULL) {
234 SC_log(LOG_ERR, "failed to CREATE resource URL to \"%s\"", SYSTEMCONFIGURATION_RESOURCES_PATH
235 "/"
236 NETWORKCONFIGURATION_RESOURCE_FILE);
237 return NULL;
238 }
239 }
240
241 templates = _SCCreatePropertyListFromResource(url);
242 CFRelease(url);
243
244 if ((templates != NULL) && !isA_CFDictionary(templates)) {
245 CFRelease(templates);
246 return NULL;
247 }
248
249 return templates;
250 }
251
252
253 __private_extern__ CFDictionaryRef
254 __copyInterfaceTemplate(CFStringRef interfaceType,
255 CFStringRef childInterfaceType)
256 {
257 CFDictionaryRef interface = NULL;
258 CFDictionaryRef interfaces;
259 CFDictionaryRef templates;
260
261 templates = __copyTemplates();
262 if (templates == NULL) {
263 return NULL;
264 }
265
266 interfaces = CFDictionaryGetValue(templates, CFSTR("Interface"));
267 if (!isA_CFDictionary(interfaces)) {
268 CFRelease(templates);
269 return NULL;
270 }
271
272 if (childInterfaceType == NULL) {
273 interface = CFDictionaryGetValue(interfaces, interfaceType);
274 } else {
275 CFStringRef expandedType;
276
277 if (CFStringFind(childInterfaceType, CFSTR("."), 0).location != kCFNotFound) {
278 // if "vendor" type
279 childInterfaceType = CFSTR("*");
280 }
281
282 expandedType = CFStringCreateWithFormat(NULL,
283 NULL,
284 CFSTR("%@-%@"),
285 interfaceType,
286 childInterfaceType);
287 interface = CFDictionaryGetValue(interfaces, expandedType);
288 CFRelease(expandedType);
289 }
290
291 if (isA_CFDictionary(interface) && (CFDictionaryGetCount(interface) > 0)) {
292 CFRetain(interface);
293 } else {
294 interface = NULL;
295 }
296
297 CFRelease(templates);
298
299 return interface;
300 }
301
302
303 __private_extern__ CFDictionaryRef
304 __copyProtocolTemplate(CFStringRef interfaceType,
305 CFStringRef childInterfaceType,
306 CFStringRef protocolType)
307 {
308 CFDictionaryRef interface = NULL;
309 CFDictionaryRef protocol = NULL;
310 CFDictionaryRef protocols;
311 CFDictionaryRef templates;
312
313 templates = __copyTemplates();
314 if (templates == NULL) {
315 return NULL;
316 }
317
318 protocols = CFDictionaryGetValue(templates, CFSTR("Protocol"));
319 if (!isA_CFDictionary(protocols)) {
320 CFRelease(templates);
321 return NULL;
322 }
323
324 if (childInterfaceType == NULL) {
325 interface = CFDictionaryGetValue(protocols, interfaceType);
326 } else {
327 CFStringRef expandedType;
328
329 if (CFStringFind(childInterfaceType, CFSTR("."), 0).location != kCFNotFound) {
330 // if "vendor" type
331 childInterfaceType = CFSTR("*");
332 }
333
334 expandedType = CFStringCreateWithFormat(NULL,
335 NULL,
336 CFSTR("%@-%@"),
337 interfaceType,
338 childInterfaceType);
339 interface = CFDictionaryGetValue(protocols, expandedType);
340 CFRelease(expandedType);
341 }
342
343 if (isA_CFDictionary(interface)) {
344 protocol = CFDictionaryGetValue(interface, protocolType);
345 if (isA_CFDictionary(protocol)) {
346 CFRetain(protocol);
347 } else {
348 protocol = NULL;
349 }
350 }
351
352 CFRelease(templates);
353
354 return protocol;
355 }
356
357
358 __private_extern__ Boolean
359 __createInterface(int s, CFStringRef interface)
360 {
361 struct ifreq ifr;
362
363 bzero(&ifr, sizeof(ifr));
364 (void) _SC_cfstring_to_cstring(interface,
365 ifr.ifr_name,
366 sizeof(ifr.ifr_name),
367 kCFStringEncodingASCII);
368
369 if (ioctl(s, SIOCIFCREATE, &ifr) == -1) {
370 SC_log(LOG_NOTICE, "could not create interface \"%@\": %s",
371 interface,
372 strerror(errno));
373 return FALSE;
374 }
375
376 return TRUE;
377 }
378
379
380 __private_extern__ Boolean
381 __destroyInterface(int s, CFStringRef interface)
382 {
383 struct ifreq ifr;
384
385 bzero(&ifr, sizeof(ifr));
386 (void) _SC_cfstring_to_cstring(interface,
387 ifr.ifr_name,
388 sizeof(ifr.ifr_name),
389 kCFStringEncodingASCII);
390
391 if (ioctl(s, SIOCIFDESTROY, &ifr) == -1) {
392 SC_log(LOG_NOTICE, "could not destroy interface \"%@\": %s",
393 interface,
394 strerror(errno));
395 return FALSE;
396 }
397
398 return TRUE;
399 }
400
401
402 /*
403 * For rdar://problem/4685223
404 *
405 * To keep MoreSCF happy we need to ensure that the first "Set" and
406 * "NetworkService" have a [less than] unique identifier that can
407 * be parsed as a numeric string.
408 *
409 * Note: this backwards compatibility code must be enabled using the
410 * following command:
411 *
412 * sudo defaults write \
413 * /Library/Preferences/SystemConfiguration/preferences \
414 * MoreSCF \
415 * -bool true
416 */
417 __private_extern__
418 CFStringRef
419 __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(SCPreferencesRef prefs, CFStringRef prefix)
420 {
421 static int hack = -1;
422 CFStringRef path = NULL;
423
424 if (hack < 0) {
425 CFBooleanRef enable;
426
427 enable = SCPreferencesGetValue(prefs, CFSTR("MoreSCF"));
428 hack = (isA_CFBoolean(enable) && CFBooleanGetValue(enable)) ? 1 : 0;
429 }
430
431 if (hack > 0) {
432 CFDictionaryRef dict;
433 Boolean ok;
434
435 path = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), prefix, CFSTR("0"));
436 dict = SCPreferencesPathGetValue(prefs, path);
437 if (dict != NULL) {
438 // if path "0" exists
439 CFRelease(path);
440 return NULL;
441 }
442
443 // unique child with path "0" does not exist, create
444 dict = CFDictionaryCreate(NULL,
445 NULL, NULL, 0,
446 &kCFTypeDictionaryKeyCallBacks,
447 &kCFTypeDictionaryValueCallBacks);
448 ok = SCPreferencesPathSetValue(prefs, path, dict);
449 CFRelease(dict);
450 if (!ok) {
451 // if create failed
452 CFRelease(path);
453 return NULL;
454 }
455 }
456
457 return path;
458 }
459
460
461 static CFDataRef
462 __copy_legacy_password(CFTypeRef password)
463 {
464 if (password == NULL) {
465 return NULL;
466 }
467
468 if (isA_CFData(password)) {
469 CFIndex n;
470
471 n = CFDataGetLength(password);
472 if ((n % sizeof(UniChar)) == 0) {
473 CFStringEncoding encoding;
474 CFStringRef str;
475
476 #if __BIG_ENDIAN__
477 encoding = (*(CFDataGetBytePtr(password) + 1) == 0x00) ? kCFStringEncodingUTF16LE : kCFStringEncodingUTF16BE;
478 #else // __LITTLE_ENDIAN__
479 encoding = (*(CFDataGetBytePtr(password) ) == 0x00) ? kCFStringEncodingUTF16BE : kCFStringEncodingUTF16LE;
480 #endif
481 str = CFStringCreateWithBytes(NULL,
482 (const UInt8 *)CFDataGetBytePtr(password),
483 n,
484 encoding,
485 FALSE);
486 password = CFStringCreateExternalRepresentation(NULL,
487 str,
488 kCFStringEncodingUTF8,
489 0);
490 CFRelease(str);
491 } else {
492 password = NULL;
493 }
494 } else if (isA_CFString(password) && (CFStringGetLength(password) > 0)) {
495 // convert password to CFData
496 password = CFStringCreateExternalRepresentation(NULL,
497 password,
498 kCFStringEncodingUTF8,
499 0);
500 } else {
501 password = NULL;
502 }
503
504 return password;
505 }
506
507
508 __private_extern__
509 Boolean
510 __extract_password(SCPreferencesRef prefs,
511 CFDictionaryRef config,
512 CFStringRef passwordKey,
513 CFStringRef encryptionKey,
514 CFStringRef encryptionKeyChainValue,
515 CFStringRef unique_id,
516 CFDataRef *password)
517 {
518 CFStringRef encryption = NULL;
519 Boolean exists = FALSE;
520
521 // check for keychain password
522 if (config != NULL) {
523 encryption = CFDictionaryGetValue(config, encryptionKey);
524 }
525 if ((encryption == NULL) ||
526 (isA_CFString(encryption) &&
527 CFEqual(encryption, encryptionKeyChainValue))) {
528 // check password
529 if (password != NULL) {
530 if (prefs != NULL) {
531 *password = _SCPreferencesSystemKeychainPasswordItemCopy(prefs, unique_id);
532 } else {
533 *password = _SCSecKeychainPasswordItemCopy(NULL, unique_id);
534 }
535 exists = (*password != NULL);
536 } else {
537 if (prefs != NULL) {
538 exists = _SCPreferencesSystemKeychainPasswordItemExists(prefs, unique_id);
539 } else {
540 exists = _SCSecKeychainPasswordItemExists(NULL, unique_id);
541 }
542 }
543 }
544
545 // as needed, check for in-line password
546 if (!exists && (encryption == NULL) && (config != NULL)) {
547 CFDataRef inline_password;
548
549 inline_password = CFDictionaryGetValue(config, passwordKey);
550 inline_password = __copy_legacy_password(inline_password);
551 if (inline_password != NULL) {
552 exists = TRUE;
553
554 if (password != NULL) {
555 *password = inline_password;
556 } else {
557 CFRelease(inline_password);
558 }
559 }
560 }
561
562 return exists;
563 }
564
565
566 __private_extern__
567 Boolean
568 __remove_password(SCPreferencesRef prefs,
569 CFDictionaryRef config,
570 CFStringRef passwordKey,
571 CFStringRef encryptionKey,
572 CFStringRef encryptionKeyChainValue,
573 CFStringRef unique_id,
574 CFDictionaryRef *newConfig)
575 {
576 CFStringRef encryption = NULL;
577 Boolean ok = FALSE;
578
579 // check for keychain password
580 if (config != NULL) {
581 encryption = CFDictionaryGetValue(config, encryptionKey);
582 }
583 if ((encryption == NULL) ||
584 (isA_CFString(encryption) &&
585 CFEqual(encryption, encryptionKeyChainValue))) {
586 // remove keychain password
587 if (prefs != NULL) {
588 ok = _SCPreferencesSystemKeychainPasswordItemRemove(prefs, unique_id);
589 } else {
590 ok = _SCSecKeychainPasswordItemRemove(NULL, unique_id);
591 }
592 }
593
594 // as needed, check if we have an in-line password that we can remove
595 if (!ok && (encryption == NULL) && (config != NULL)) {
596 CFDataRef inline_password;
597
598 inline_password = CFDictionaryGetValue(config, passwordKey);
599 inline_password = __copy_legacy_password(inline_password);
600 if (inline_password != NULL) {
601 CFRelease(inline_password);
602 ok = TRUE;
603 }
604 }
605
606 if (newConfig != NULL) {
607 if (ok && (config != NULL)) {
608 CFMutableDictionaryRef temp;
609
610 temp = CFDictionaryCreateMutableCopy(NULL, 0, config);
611 CFDictionaryRemoveValue(temp, passwordKey);
612 CFDictionaryRemoveValue(temp, encryptionKey);
613 *newConfig = (CFDictionaryRef)temp;
614 } else {
615 *newConfig = NULL;
616 }
617 }
618
619 return ok;
620 }
621
622
623 __private_extern__ Boolean
624 __rank_to_str(SCNetworkServicePrimaryRank rank, CFStringRef *rankStr)
625 {
626 switch (rank) {
627 case kSCNetworkServicePrimaryRankDefault :
628 *rankStr = NULL;
629 break;
630 case kSCNetworkServicePrimaryRankFirst :
631 *rankStr = kSCValNetServicePrimaryRankFirst;
632 break;
633 case kSCNetworkServicePrimaryRankLast :
634 *rankStr = kSCValNetServicePrimaryRankLast;
635 break;
636 case kSCNetworkServicePrimaryRankNever :
637 *rankStr = kSCValNetServicePrimaryRankNever;
638 break;
639 case kSCNetworkServicePrimaryRankScoped :
640 *rankStr = kSCValNetServicePrimaryRankScoped;
641 break;
642 default :
643 return FALSE;
644 }
645
646 return TRUE;
647 }
648
649
650 __private_extern__ Boolean
651 __str_to_rank(CFStringRef rankStr, SCNetworkServicePrimaryRank *rank)
652 {
653 if (isA_CFString(rankStr)) {
654 if (CFEqual(rankStr, kSCValNetServicePrimaryRankFirst)) {
655 *rank = kSCNetworkServicePrimaryRankFirst;
656 } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankLast)) {
657 *rank = kSCNetworkServicePrimaryRankLast;
658 } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankNever)) {
659 *rank = kSCNetworkServicePrimaryRankNever;
660 } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankScoped)) {
661 *rank = kSCNetworkServicePrimaryRankScoped;
662 } else {
663 return FALSE;
664 }
665 } else if (rankStr == NULL) {
666 *rank = kSCNetworkServicePrimaryRankDefault;
667 } else {
668 return FALSE;
669 }
670
671 return TRUE;
672 }