2 * Copyright (c) 2004-2007, 2009, 2010-2013, 2015-2020 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"
33 #include "SCPreferencesInternal.h"
35 #include <sys/ioctl.h>
39 __private_extern__ os_log_t
40 __log_SCNetworkConfiguration(void)
42 static os_log_t log
= NULL
;
45 log
= os_log_create("com.apple.SystemConfiguration", "SCNetworkConfiguration");
53 isEffectivelyEmptyConfiguration(CFDictionaryRef config
)
55 Boolean empty
= FALSE
;
58 n
= isA_CFDictionary(config
) ? CFDictionaryGetCount(config
) : 0;
65 if (CFDictionaryContainsKey(config
, kSCResvInactive
)) {
66 // ignore [effectively] empty configuration entities
78 __private_extern__ CFDictionaryRef
79 __SCNetworkConfigurationGetValue(SCPreferencesRef prefs
, CFStringRef path
)
81 CFDictionaryRef config
;
83 config
= SCPreferencesPathGetValue(prefs
, path
);
84 if (isEffectivelyEmptyConfiguration(config
)) {
85 // ignore [effectively] empty configuration entities
93 __private_extern__ Boolean
94 __SCNetworkConfigurationSetValue(SCPreferencesRef prefs
,
96 CFDictionaryRef config
,
100 CFDictionaryRef curConfig
;
101 CFMutableDictionaryRef newConfig
= NULL
;
104 if ((config
!= NULL
) && !isA_CFDictionary(config
)) {
105 _SCErrorSet(kSCStatusInvalidArgument
);
109 curConfig
= SCPreferencesPathGetValue(prefs
, path
);
110 curConfig
= isA_CFDictionary(curConfig
);
112 if (config
!= NULL
) {
113 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
117 if (config
== NULL
) {
118 newConfig
= CFDictionaryCreateMutable(NULL
,
120 &kCFTypeDictionaryKeyCallBacks
,
121 &kCFTypeDictionaryValueCallBacks
);
124 if (isA_CFDictionary(curConfig
) && CFDictionaryContainsKey(curConfig
, kSCResvInactive
)) {
125 // if currently disabled
126 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
128 // if currently enabled
129 CFDictionaryRemoveValue(newConfig
, kSCResvInactive
);
133 // check if the configuration changed
134 changed
= !_SC_CFEqual(curConfig
, newConfig
);
136 // set new configuration
139 if (newConfig
!= NULL
) CFRelease(newConfig
);
141 } else if (newConfig
!= NULL
) {
142 // if new configuration (or we are preserving a disabled state), update the prefs
143 ok
= SCPreferencesPathSetValue(prefs
, path
, newConfig
);
144 CFRelease(newConfig
);
147 ok
= SCPreferencesPathRemoveValue(prefs
, path
);
148 if (!ok
&& (SCError() == kSCStatusNoKey
)) {
157 __private_extern__ Boolean
158 __getPrefsEnabled(SCPreferencesRef prefs
, CFStringRef path
)
160 CFDictionaryRef config
;
162 config
= SCPreferencesPathGetValue(prefs
, path
);
163 if (isA_CFDictionary(config
) && CFDictionaryContainsKey(config
, kSCResvInactive
)) {
171 __private_extern__ Boolean
172 __setPrefsEnabled(SCPreferencesRef prefs
,
177 CFDictionaryRef curConfig
;
178 CFMutableDictionaryRef newConfig
= NULL
;
181 // preserve current configuration
182 curConfig
= SCPreferencesPathGetValue(prefs
, path
);
183 if (curConfig
!= NULL
) {
184 if (!isA_CFDictionary(curConfig
)) {
185 _SCErrorSet(kSCStatusFailed
);
188 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, curConfig
);
192 CFDictionaryRemoveValue(newConfig
, kSCResvInactive
);
195 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
200 newConfig
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
201 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
205 // check if the configuration changed
206 changed
= !_SC_CFEqual(curConfig
, newConfig
);
208 // set new configuration
211 if (newConfig
!= NULL
) CFRelease(newConfig
);
213 } else if (newConfig
!= NULL
) {
214 // if updated configuration (or we are establishing as disabled)
216 ok
= SCPreferencesPathSetValue(prefs
, path
, newConfig
);
217 CFRelease(newConfig
);
219 ok
= SCPreferencesPathRemoveValue(prefs
, path
);
220 if (!ok
&& (SCError() == kSCStatusNoKey
)) {
229 #define SYSTEMCONFIGURATION_RESOURCES_PATH SYSTEMCONFIGURATION_FRAMEWORK_PATH "/Resources"
231 #define SYSTEMCONFIGURATION_RESOURCES_PATH SYSTEMCONFIGURATION_FRAMEWORK_PATH
232 #endif // TARGET_OS_OSX
234 #define NETWORKCONFIGURATION_RESOURCE_FILE "NetworkConfiguration.plist"
236 static CFDictionaryRef
240 CFDictionaryRef templates
;
243 bundle
= _SC_CFBundleGet();
244 if (bundle
== NULL
) {
248 url
= CFBundleCopyResourceURL(bundle
, CFSTR("NetworkConfiguration"), CFSTR("plist"), NULL
);
250 SC_log(LOG_ERR
, "failed to GET resource URL to \"%s\". Trying harder...", NETWORKCONFIGURATION_RESOURCE_FILE
);
251 url
= CFURLCreateWithFileSystemPath(NULL
,
252 CFSTR(SYSTEMCONFIGURATION_RESOURCES_PATH
254 NETWORKCONFIGURATION_RESOURCE_FILE
),
255 kCFURLPOSIXPathStyle
,
259 SC_log(LOG_ERR
, "failed to CREATE resource URL to \"%s\"", SYSTEMCONFIGURATION_RESOURCES_PATH
261 NETWORKCONFIGURATION_RESOURCE_FILE
);
266 templates
= _SCCreatePropertyListFromResource(url
);
269 if ((templates
!= NULL
) && !isA_CFDictionary(templates
)) {
270 CFRelease(templates
);
278 __private_extern__ CFDictionaryRef
279 __copyInterfaceTemplate(CFStringRef interfaceType
,
280 CFStringRef childInterfaceType
)
282 CFDictionaryRef interface
= NULL
;
283 CFDictionaryRef interfaces
;
284 CFDictionaryRef templates
;
286 templates
= __copyTemplates();
287 if (templates
== NULL
) {
291 interfaces
= CFDictionaryGetValue(templates
, CFSTR("Interface"));
292 if (!isA_CFDictionary(interfaces
)) {
293 CFRelease(templates
);
297 if (childInterfaceType
== NULL
) {
298 interface
= CFDictionaryGetValue(interfaces
, interfaceType
);
300 CFStringRef expandedType
;
302 if (CFStringFind(childInterfaceType
, CFSTR("."), 0).location
!= kCFNotFound
) {
304 childInterfaceType
= CFSTR("*");
307 expandedType
= CFStringCreateWithFormat(NULL
,
312 interface
= CFDictionaryGetValue(interfaces
, expandedType
);
313 CFRelease(expandedType
);
316 if (isA_CFDictionary(interface
) && (CFDictionaryGetCount(interface
) > 0)) {
322 CFRelease(templates
);
328 __private_extern__ CFDictionaryRef
329 __copyProtocolTemplate(CFStringRef interfaceType
,
330 CFStringRef childInterfaceType
,
331 CFStringRef protocolType
)
333 CFDictionaryRef interface
= NULL
;
334 CFDictionaryRef protocol
= NULL
;
335 CFDictionaryRef protocols
;
336 CFDictionaryRef templates
;
338 templates
= __copyTemplates();
339 if (templates
== NULL
) {
343 protocols
= CFDictionaryGetValue(templates
, CFSTR("Protocol"));
344 if (!isA_CFDictionary(protocols
)) {
345 CFRelease(templates
);
349 if (childInterfaceType
== NULL
) {
350 interface
= CFDictionaryGetValue(protocols
, interfaceType
);
352 CFStringRef expandedType
;
354 if (CFStringFind(childInterfaceType
, CFSTR("."), 0).location
!= kCFNotFound
) {
356 childInterfaceType
= CFSTR("*");
359 expandedType
= CFStringCreateWithFormat(NULL
,
364 interface
= CFDictionaryGetValue(protocols
, expandedType
);
365 CFRelease(expandedType
);
368 if (isA_CFDictionary(interface
)) {
369 protocol
= CFDictionaryGetValue(interface
, protocolType
);
370 if (isA_CFDictionary(protocol
)) {
377 CFRelease(templates
);
383 __private_extern__ Boolean
384 __createInterface(int s
, CFStringRef interface
)
388 memset(&ifr
, 0, sizeof(ifr
));
389 (void) _SC_cfstring_to_cstring(interface
,
391 sizeof(ifr
.ifr_name
),
392 kCFStringEncodingASCII
);
394 if (ioctl(s
, SIOCIFCREATE
, &ifr
) == -1) {
395 SC_log(LOG_NOTICE
, "could not create interface \"%@\": %s",
405 __private_extern__ Boolean
406 __destroyInterface(int s
, CFStringRef interface
)
410 memset(&ifr
, 0, sizeof(ifr
));
411 (void) _SC_cfstring_to_cstring(interface
,
413 sizeof(ifr
.ifr_name
),
414 kCFStringEncodingASCII
);
416 if (ioctl(s
, SIOCIFDESTROY
, &ifr
) == -1) {
417 SC_log(LOG_NOTICE
, "could not destroy interface \"%@\": %s",
428 * For rdar://problem/4685223
430 * To keep MoreSCF happy we need to ensure that the first "Set" and
431 * "NetworkService" have a [less than] unique identifier that can
432 * be parsed as a numeric string.
434 * Note: this backwards compatibility code must be enabled using the
437 * sudo defaults write \
438 * /Library/Preferences/SystemConfiguration/preferences \
444 __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(SCPreferencesRef prefs
, CFStringRef prefix
)
446 static int hack
= -1;
447 CFStringRef path
= NULL
;
452 enable
= SCPreferencesGetValue(prefs
, CFSTR("MoreSCF"));
453 hack
= (isA_CFBoolean(enable
) && CFBooleanGetValue(enable
)) ? 1 : 0;
457 CFDictionaryRef dict
;
460 path
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@/%@"), prefix
, CFSTR("0"));
461 dict
= SCPreferencesPathGetValue(prefs
, path
);
463 // if path "0" exists
468 // unique child with path "0" does not exist, create
469 dict
= CFDictionaryCreate(NULL
,
471 &kCFTypeDictionaryKeyCallBacks
,
472 &kCFTypeDictionaryValueCallBacks
);
473 ok
= SCPreferencesPathSetValue(prefs
, path
, dict
);
487 __copy_legacy_password(CFTypeRef password
)
489 if (password
== NULL
) {
493 if (isA_CFData(password
)) {
496 n
= CFDataGetLength(password
);
497 if ((n
% sizeof(UniChar
)) == 0) {
498 CFStringEncoding encoding
;
502 encoding
= (*(CFDataGetBytePtr(password
) + 1) == 0x00) ? kCFStringEncodingUTF16LE
: kCFStringEncodingUTF16BE
;
503 #else // __LITTLE_ENDIAN__
504 encoding
= (*(CFDataGetBytePtr(password
) ) == 0x00) ? kCFStringEncodingUTF16BE
: kCFStringEncodingUTF16LE
;
506 str
= CFStringCreateWithBytes(NULL
,
507 (const UInt8
*)CFDataGetBytePtr(password
),
511 password
= CFStringCreateExternalRepresentation(NULL
,
513 kCFStringEncodingUTF8
,
519 } else if (isA_CFString(password
) && (CFStringGetLength(password
) > 0)) {
520 // convert password to CFData
521 password
= CFStringCreateExternalRepresentation(NULL
,
523 kCFStringEncodingUTF8
,
535 __extract_password(SCPreferencesRef prefs
,
536 CFDictionaryRef config
,
537 CFStringRef passwordKey
,
538 CFStringRef encryptionKey
,
539 CFStringRef encryptionKeyChainValue
,
540 CFStringRef unique_id
,
543 CFStringRef encryption
= NULL
;
544 Boolean exists
= FALSE
;
546 // check for keychain password
547 if (config
!= NULL
) {
548 encryption
= CFDictionaryGetValue(config
, encryptionKey
);
550 if ((encryption
== NULL
) ||
551 (isA_CFString(encryption
) &&
552 CFEqual(encryption
, encryptionKeyChainValue
))) {
554 if (password
!= NULL
) {
556 *password
= _SCPreferencesSystemKeychainPasswordItemCopy(prefs
, unique_id
);
558 *password
= _SCSecKeychainPasswordItemCopy(NULL
, unique_id
);
560 exists
= (*password
!= NULL
);
563 exists
= _SCPreferencesSystemKeychainPasswordItemExists(prefs
, unique_id
);
565 exists
= _SCSecKeychainPasswordItemExists(NULL
, unique_id
);
570 // as needed, check for in-line password
571 if (!exists
&& (encryption
== NULL
) && (config
!= NULL
)) {
572 CFDataRef inline_password
;
574 inline_password
= CFDictionaryGetValue(config
, passwordKey
);
575 inline_password
= __copy_legacy_password(inline_password
);
576 if (inline_password
!= NULL
) {
579 if (password
!= NULL
) {
580 *password
= inline_password
;
582 CFRelease(inline_password
);
593 __remove_password(SCPreferencesRef prefs
,
594 CFDictionaryRef config
,
595 CFStringRef passwordKey
,
596 CFStringRef encryptionKey
,
597 CFStringRef encryptionKeyChainValue
,
598 CFStringRef unique_id
,
599 CFDictionaryRef
*newConfig
)
601 CFStringRef encryption
= NULL
;
604 // check for keychain password
605 if (config
!= NULL
) {
606 encryption
= CFDictionaryGetValue(config
, encryptionKey
);
608 if ((encryption
== NULL
) ||
609 (isA_CFString(encryption
) &&
610 CFEqual(encryption
, encryptionKeyChainValue
))) {
611 // remove keychain password
613 ok
= _SCPreferencesSystemKeychainPasswordItemRemove(prefs
, unique_id
);
615 ok
= _SCSecKeychainPasswordItemRemove(NULL
, unique_id
);
619 // as needed, check if we have an in-line password that we can remove
620 if (!ok
&& (encryption
== NULL
) && (config
!= NULL
)) {
621 CFDataRef inline_password
;
623 inline_password
= CFDictionaryGetValue(config
, passwordKey
);
624 inline_password
= __copy_legacy_password(inline_password
);
625 if (inline_password
!= NULL
) {
626 CFRelease(inline_password
);
631 if (newConfig
!= NULL
) {
632 if (ok
&& (config
!= NULL
)) {
633 CFMutableDictionaryRef temp
;
635 temp
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
636 CFDictionaryRemoveValue(temp
, passwordKey
);
637 CFDictionaryRemoveValue(temp
, encryptionKey
);
638 *newConfig
= (CFDictionaryRef
)temp
;
648 __private_extern__ Boolean
649 __rank_to_str(SCNetworkServicePrimaryRank rank
, CFStringRef
*rankStr
)
652 case kSCNetworkServicePrimaryRankDefault
:
655 case kSCNetworkServicePrimaryRankFirst
:
656 *rankStr
= kSCValNetServicePrimaryRankFirst
;
658 case kSCNetworkServicePrimaryRankLast
:
659 *rankStr
= kSCValNetServicePrimaryRankLast
;
661 case kSCNetworkServicePrimaryRankNever
:
662 *rankStr
= kSCValNetServicePrimaryRankNever
;
664 case kSCNetworkServicePrimaryRankScoped
:
665 *rankStr
= kSCValNetServicePrimaryRankScoped
;
675 __private_extern__ Boolean
676 __str_to_rank(CFStringRef rankStr
, SCNetworkServicePrimaryRank
*rank
)
678 if (isA_CFString(rankStr
)) {
679 if (CFEqual(rankStr
, kSCValNetServicePrimaryRankFirst
)) {
680 *rank
= kSCNetworkServicePrimaryRankFirst
;
681 } else if (CFEqual(rankStr
, kSCValNetServicePrimaryRankLast
)) {
682 *rank
= kSCNetworkServicePrimaryRankLast
;
683 } else if (CFEqual(rankStr
, kSCValNetServicePrimaryRankNever
)) {
684 *rank
= kSCNetworkServicePrimaryRankNever
;
685 } else if (CFEqual(rankStr
, kSCValNetServicePrimaryRankScoped
)) {
686 *rank
= kSCNetworkServicePrimaryRankScoped
;
690 } else if (rankStr
== NULL
) {
691 *rank
= kSCNetworkServicePrimaryRankDefault
;
700 #define kSCNetworkConfigurationFlagsBypassSystemInterfaces (1<<0)
701 #define kSCNetworkConfigurationFlagsBypassSystemInterfacesForced (1<<1)
705 _SCNetworkConfigurationBypassSystemInterfaces(SCPreferencesRef prefs
)
710 nc_flags
= __SCPreferencesGetNetworkConfigurationFlags(prefs
);
711 bypass
= ((nc_flags
& kSCNetworkConfigurationFlagsBypassSystemInterfaces
) != 0);
713 (nc_flags
& kSCNetworkConfigurationFlagsBypassSystemInterfacesForced
) != 0) {
714 // if bypass flag explicitly requested
718 if (!__SCPreferencesUsingDefaultPrefs(prefs
)) {
719 // if not using the default prefs (i.e. /L/P/SC/preferences.plist)
728 _SCNetworkConfigurationSetBypassSystemInterfaces(SCPreferencesRef prefs
, Boolean shouldBypass
)
732 nc_flags
= __SCPreferencesGetNetworkConfigurationFlags(prefs
);
734 nc_flags
|= kSCNetworkConfigurationFlagsBypassSystemInterfaces
;
736 nc_flags
&= ~kSCNetworkConfigurationFlagsBypassSystemInterfaces
;
738 nc_flags
|= kSCNetworkConfigurationFlagsBypassSystemInterfacesForced
;
739 __SCPreferencesSetNetworkConfigurationFlags(prefs
, nc_flags
);