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