2 * Copyright (c) 2004-2007, 2009, 2010-2013, 2015, 2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * May 27, 2004 Allan Nathanson <ajn@apple.com>
32 #include "SCNetworkConfigurationInternal.h"
34 #include <sys/ioctl.h>
38 __private_extern__ os_log_t
39 __log_SCNetworkConfiguration()
41 static os_log_t log
= NULL
;
44 log
= os_log_create("com.apple.SystemConfiguration", "SCNetworkConfiguration");
51 __private_extern__ CFDictionaryRef
52 __getPrefsConfiguration(SCPreferencesRef prefs
, CFStringRef path
)
54 CFDictionaryRef config
;
57 config
= SCPreferencesPathGetValue(prefs
, path
);
59 n
= isA_CFDictionary(config
) ? CFDictionaryGetCount(config
) : 0;
62 // ignore empty configuration entities
66 if (CFDictionaryContainsKey(config
, kSCResvInactive
)) {
67 // ignore [effectively] empty configuration entities
79 __private_extern__ Boolean
80 __setPrefsConfiguration(SCPreferencesRef prefs
,
82 CFDictionaryRef config
,
85 CFDictionaryRef curConfig
;
86 CFMutableDictionaryRef newConfig
= NULL
;
89 if ((config
!= NULL
) && !isA_CFDictionary(config
)) {
90 _SCErrorSet(kSCStatusInvalidArgument
);
94 curConfig
= SCPreferencesPathGetValue(prefs
, path
);
97 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
101 if (config
== NULL
) {
102 newConfig
= CFDictionaryCreateMutable(NULL
,
104 &kCFTypeDictionaryKeyCallBacks
,
105 &kCFTypeDictionaryValueCallBacks
);
108 if (isA_CFDictionary(curConfig
) && CFDictionaryContainsKey(curConfig
, kSCResvInactive
)) {
109 // if currently disabled
110 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
112 // if currently enabled
113 CFDictionaryRemoveValue(newConfig
, kSCResvInactive
);
117 // set new configuration
118 if (_SC_CFEqual(curConfig
, newConfig
)) {
120 if (newConfig
!= NULL
) CFRelease(newConfig
);
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
);
127 ok
= SCPreferencesPathRemoveValue(prefs
, path
);
128 if (!ok
&& (SCError() == kSCStatusNoKey
)) {
137 __private_extern__ Boolean
138 __getPrefsEnabled(SCPreferencesRef prefs
, CFStringRef path
)
140 CFDictionaryRef config
;
142 config
= SCPreferencesPathGetValue(prefs
, path
);
143 if (isA_CFDictionary(config
) && CFDictionaryContainsKey(config
, kSCResvInactive
)) {
151 __private_extern__ Boolean
152 __setPrefsEnabled(SCPreferencesRef prefs
,
156 CFDictionaryRef curConfig
;
157 CFMutableDictionaryRef newConfig
= NULL
;
160 // preserve current configuration
161 curConfig
= SCPreferencesPathGetValue(prefs
, path
);
162 if (curConfig
!= NULL
) {
163 if (!isA_CFDictionary(curConfig
)) {
164 _SCErrorSet(kSCStatusFailed
);
167 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, curConfig
);
171 CFDictionaryRemoveValue(newConfig
, kSCResvInactive
);
174 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
179 newConfig
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
180 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
184 // set new configuration
185 if (_SC_CFEqual(curConfig
, newConfig
)) {
187 if (newConfig
!= NULL
) CFRelease(newConfig
);
189 } else if (newConfig
!= NULL
) {
190 // if updated configuration (or we are establishing as disabled)
191 ok
= SCPreferencesPathSetValue(prefs
, path
, newConfig
);
192 CFRelease(newConfig
);
194 ok
= SCPreferencesPathRemoveValue(prefs
, path
);
195 if (!ok
&& (SCError() == kSCStatusNoKey
)) {
203 #if !TARGET_OS_EMBEDDED
204 #define SYSTEMCONFIGURATION_RESOURCES_PATH SYSTEMCONFIGURATION_FRAMEWORK_PATH "/Resources"
206 #define SYSTEMCONFIGURATION_RESOURCES_PATH SYSTEMCONFIGURATION_FRAMEWORK_PATH
207 #endif // !TARGET_OS_EMBEDDED
209 #define NETWORKCONFIGURATION_RESOURCE_FILE "NetworkConfiguration.plist"
211 static CFDictionaryRef
215 CFDictionaryRef templates
;
218 bundle
= _SC_CFBundleGet();
219 if (bundle
== NULL
) {
223 url
= CFBundleCopyResourceURL(bundle
, CFSTR("NetworkConfiguration"), CFSTR("plist"), 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
229 NETWORKCONFIGURATION_RESOURCE_FILE
),
230 kCFURLPOSIXPathStyle
,
234 SC_log(LOG_ERR
, "failed to CREATE resource URL to \"%s\"", SYSTEMCONFIGURATION_RESOURCES_PATH
236 NETWORKCONFIGURATION_RESOURCE_FILE
);
241 templates
= _SCCreatePropertyListFromResource(url
);
244 if ((templates
!= NULL
) && !isA_CFDictionary(templates
)) {
245 CFRelease(templates
);
253 __private_extern__ CFDictionaryRef
254 __copyInterfaceTemplate(CFStringRef interfaceType
,
255 CFStringRef childInterfaceType
)
257 CFDictionaryRef interface
= NULL
;
258 CFDictionaryRef interfaces
;
259 CFDictionaryRef templates
;
261 templates
= __copyTemplates();
262 if (templates
== NULL
) {
266 interfaces
= CFDictionaryGetValue(templates
, CFSTR("Interface"));
267 if (!isA_CFDictionary(interfaces
)) {
268 CFRelease(templates
);
272 if (childInterfaceType
== NULL
) {
273 interface
= CFDictionaryGetValue(interfaces
, interfaceType
);
275 CFStringRef expandedType
;
277 if (CFStringFind(childInterfaceType
, CFSTR("."), 0).location
!= kCFNotFound
) {
279 childInterfaceType
= CFSTR("*");
282 expandedType
= CFStringCreateWithFormat(NULL
,
287 interface
= CFDictionaryGetValue(interfaces
, expandedType
);
288 CFRelease(expandedType
);
291 if (isA_CFDictionary(interface
) && (CFDictionaryGetCount(interface
) > 0)) {
297 CFRelease(templates
);
303 __private_extern__ CFDictionaryRef
304 __copyProtocolTemplate(CFStringRef interfaceType
,
305 CFStringRef childInterfaceType
,
306 CFStringRef protocolType
)
308 CFDictionaryRef interface
= NULL
;
309 CFDictionaryRef protocol
= NULL
;
310 CFDictionaryRef protocols
;
311 CFDictionaryRef templates
;
313 templates
= __copyTemplates();
314 if (templates
== NULL
) {
318 protocols
= CFDictionaryGetValue(templates
, CFSTR("Protocol"));
319 if (!isA_CFDictionary(protocols
)) {
320 CFRelease(templates
);
324 if (childInterfaceType
== NULL
) {
325 interface
= CFDictionaryGetValue(protocols
, interfaceType
);
327 CFStringRef expandedType
;
329 if (CFStringFind(childInterfaceType
, CFSTR("."), 0).location
!= kCFNotFound
) {
331 childInterfaceType
= CFSTR("*");
334 expandedType
= CFStringCreateWithFormat(NULL
,
339 interface
= CFDictionaryGetValue(protocols
, expandedType
);
340 CFRelease(expandedType
);
343 if (isA_CFDictionary(interface
)) {
344 protocol
= CFDictionaryGetValue(interface
, protocolType
);
345 if (isA_CFDictionary(protocol
)) {
352 CFRelease(templates
);
358 __private_extern__ Boolean
359 __createInterface(int s
, CFStringRef interface
)
363 bzero(&ifr
, sizeof(ifr
));
364 (void) _SC_cfstring_to_cstring(interface
,
366 sizeof(ifr
.ifr_name
),
367 kCFStringEncodingASCII
);
369 if (ioctl(s
, SIOCIFCREATE
, &ifr
) == -1) {
370 SC_log(LOG_NOTICE
, "could not create interface \"%@\": %s",
380 __private_extern__ Boolean
381 __destroyInterface(int s
, CFStringRef interface
)
385 bzero(&ifr
, sizeof(ifr
));
386 (void) _SC_cfstring_to_cstring(interface
,
388 sizeof(ifr
.ifr_name
),
389 kCFStringEncodingASCII
);
391 if (ioctl(s
, SIOCIFDESTROY
, &ifr
) == -1) {
392 SC_log(LOG_NOTICE
, "could not destroy interface \"%@\": %s",
403 * For rdar://problem/4685223
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.
409 * Note: this backwards compatibility code must be enabled using the
412 * sudo defaults write \
413 * /Library/Preferences/SystemConfiguration/preferences \
419 __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(SCPreferencesRef prefs
, CFStringRef prefix
)
421 static int hack
= -1;
422 CFStringRef path
= NULL
;
427 enable
= SCPreferencesGetValue(prefs
, CFSTR("MoreSCF"));
428 hack
= (isA_CFBoolean(enable
) && CFBooleanGetValue(enable
)) ? 1 : 0;
432 CFDictionaryRef dict
;
435 path
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@/%@"), prefix
, CFSTR("0"));
436 dict
= SCPreferencesPathGetValue(prefs
, path
);
438 // if path "0" exists
443 // unique child with path "0" does not exist, create
444 dict
= CFDictionaryCreate(NULL
,
446 &kCFTypeDictionaryKeyCallBacks
,
447 &kCFTypeDictionaryValueCallBacks
);
448 ok
= SCPreferencesPathSetValue(prefs
, path
, dict
);
462 __copy_legacy_password(CFTypeRef password
)
464 if (password
== NULL
) {
468 if (isA_CFData(password
)) {
471 n
= CFDataGetLength(password
);
472 if ((n
% sizeof(UniChar
)) == 0) {
473 CFStringEncoding encoding
;
477 encoding
= (*(CFDataGetBytePtr(password
) + 1) == 0x00) ? kCFStringEncodingUTF16LE
: kCFStringEncodingUTF16BE
;
478 #else // __LITTLE_ENDIAN__
479 encoding
= (*(CFDataGetBytePtr(password
) ) == 0x00) ? kCFStringEncodingUTF16BE
: kCFStringEncodingUTF16LE
;
481 str
= CFStringCreateWithBytes(NULL
,
482 (const UInt8
*)CFDataGetBytePtr(password
),
486 password
= CFStringCreateExternalRepresentation(NULL
,
488 kCFStringEncodingUTF8
,
494 } else if (isA_CFString(password
) && (CFStringGetLength(password
) > 0)) {
495 // convert password to CFData
496 password
= CFStringCreateExternalRepresentation(NULL
,
498 kCFStringEncodingUTF8
,
510 __extract_password(SCPreferencesRef prefs
,
511 CFDictionaryRef config
,
512 CFStringRef passwordKey
,
513 CFStringRef encryptionKey
,
514 CFStringRef encryptionKeyChainValue
,
515 CFStringRef unique_id
,
518 CFStringRef encryption
= NULL
;
519 Boolean exists
= FALSE
;
521 // check for keychain password
522 if (config
!= NULL
) {
523 encryption
= CFDictionaryGetValue(config
, encryptionKey
);
525 if ((encryption
== NULL
) ||
526 (isA_CFString(encryption
) &&
527 CFEqual(encryption
, encryptionKeyChainValue
))) {
529 if (password
!= NULL
) {
531 *password
= _SCPreferencesSystemKeychainPasswordItemCopy(prefs
, unique_id
);
533 *password
= _SCSecKeychainPasswordItemCopy(NULL
, unique_id
);
535 exists
= (*password
!= NULL
);
538 exists
= _SCPreferencesSystemKeychainPasswordItemExists(prefs
, unique_id
);
540 exists
= _SCSecKeychainPasswordItemExists(NULL
, unique_id
);
545 // as needed, check for in-line password
546 if (!exists
&& (encryption
== NULL
) && (config
!= NULL
)) {
547 CFDataRef inline_password
;
549 inline_password
= CFDictionaryGetValue(config
, passwordKey
);
550 inline_password
= __copy_legacy_password(inline_password
);
551 if (inline_password
!= NULL
) {
554 if (password
!= NULL
) {
555 *password
= inline_password
;
557 CFRelease(inline_password
);
568 __remove_password(SCPreferencesRef prefs
,
569 CFDictionaryRef config
,
570 CFStringRef passwordKey
,
571 CFStringRef encryptionKey
,
572 CFStringRef encryptionKeyChainValue
,
573 CFStringRef unique_id
,
574 CFDictionaryRef
*newConfig
)
576 CFStringRef encryption
= NULL
;
579 // check for keychain password
580 if (config
!= NULL
) {
581 encryption
= CFDictionaryGetValue(config
, encryptionKey
);
583 if ((encryption
== NULL
) ||
584 (isA_CFString(encryption
) &&
585 CFEqual(encryption
, encryptionKeyChainValue
))) {
586 // remove keychain password
588 ok
= _SCPreferencesSystemKeychainPasswordItemRemove(prefs
, unique_id
);
590 ok
= _SCSecKeychainPasswordItemRemove(NULL
, unique_id
);
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
;
598 inline_password
= CFDictionaryGetValue(config
, passwordKey
);
599 inline_password
= __copy_legacy_password(inline_password
);
600 if (inline_password
!= NULL
) {
601 CFRelease(inline_password
);
606 if (newConfig
!= NULL
) {
607 if (ok
&& (config
!= NULL
)) {
608 CFMutableDictionaryRef temp
;
610 temp
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
611 CFDictionaryRemoveValue(temp
, passwordKey
);
612 CFDictionaryRemoveValue(temp
, encryptionKey
);
613 *newConfig
= (CFDictionaryRef
)temp
;
623 __private_extern__ Boolean
624 __rank_to_str(SCNetworkServicePrimaryRank rank
, CFStringRef
*rankStr
)
627 case kSCNetworkServicePrimaryRankDefault
:
630 case kSCNetworkServicePrimaryRankFirst
:
631 *rankStr
= kSCValNetServicePrimaryRankFirst
;
633 case kSCNetworkServicePrimaryRankLast
:
634 *rankStr
= kSCValNetServicePrimaryRankLast
;
636 case kSCNetworkServicePrimaryRankNever
:
637 *rankStr
= kSCValNetServicePrimaryRankNever
;
639 case kSCNetworkServicePrimaryRankScoped
:
640 *rankStr
= kSCValNetServicePrimaryRankScoped
;
650 __private_extern__ Boolean
651 __str_to_rank(CFStringRef rankStr
, SCNetworkServicePrimaryRank
*rank
)
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
;
665 } else if (rankStr
== NULL
) {
666 *rank
= kSCNetworkServicePrimaryRankDefault
;