2 * Copyright (c) 2004-2007, 2009, 2010-2013, 2015-2018 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 "SCPreferencesInternal.h"
33 #include "SCNetworkConfigurationInternal.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");
52 __private_extern__ CFDictionaryRef
53 __getPrefsConfiguration(SCPreferencesRef prefs
, CFStringRef path
)
55 CFDictionaryRef config
;
58 config
= SCPreferencesPathGetValue(prefs
, path
);
60 n
= isA_CFDictionary(config
) ? CFDictionaryGetCount(config
) : 0;
63 // ignore empty configuration entities
67 if (CFDictionaryContainsKey(config
, kSCResvInactive
)) {
68 // ignore [effectively] empty configuration entities
80 __private_extern__ Boolean
81 __setPrefsConfiguration(SCPreferencesRef prefs
,
83 CFDictionaryRef config
,
86 CFDictionaryRef curConfig
;
87 CFMutableDictionaryRef newConfig
= NULL
;
90 if ((config
!= NULL
) && !isA_CFDictionary(config
)) {
91 _SCErrorSet(kSCStatusInvalidArgument
);
95 curConfig
= SCPreferencesPathGetValue(prefs
, path
);
98 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
102 if (config
== NULL
) {
103 newConfig
= CFDictionaryCreateMutable(NULL
,
105 &kCFTypeDictionaryKeyCallBacks
,
106 &kCFTypeDictionaryValueCallBacks
);
109 if (isA_CFDictionary(curConfig
) && CFDictionaryContainsKey(curConfig
, kSCResvInactive
)) {
110 // if currently disabled
111 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
113 // if currently enabled
114 CFDictionaryRemoveValue(newConfig
, kSCResvInactive
);
118 // set new configuration
119 if (_SC_CFEqual(curConfig
, newConfig
)) {
121 if (newConfig
!= NULL
) CFRelease(newConfig
);
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
);
128 ok
= SCPreferencesPathRemoveValue(prefs
, path
);
129 if (!ok
&& (SCError() == kSCStatusNoKey
)) {
138 __private_extern__ Boolean
139 __getPrefsEnabled(SCPreferencesRef prefs
, CFStringRef path
)
141 CFDictionaryRef config
;
143 config
= SCPreferencesPathGetValue(prefs
, path
);
144 if (isA_CFDictionary(config
) && CFDictionaryContainsKey(config
, kSCResvInactive
)) {
152 __private_extern__ Boolean
153 __setPrefsEnabled(SCPreferencesRef prefs
,
157 CFDictionaryRef curConfig
;
158 CFMutableDictionaryRef newConfig
= NULL
;
161 // preserve current configuration
162 curConfig
= SCPreferencesPathGetValue(prefs
, path
);
163 if (curConfig
!= NULL
) {
164 if (!isA_CFDictionary(curConfig
)) {
165 _SCErrorSet(kSCStatusFailed
);
168 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, curConfig
);
172 CFDictionaryRemoveValue(newConfig
, kSCResvInactive
);
175 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
180 newConfig
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
181 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
185 // set new configuration
186 if (_SC_CFEqual(curConfig
, newConfig
)) {
188 if (newConfig
!= NULL
) CFRelease(newConfig
);
190 } else if (newConfig
!= NULL
) {
191 // if updated configuration (or we are establishing as disabled)
192 ok
= SCPreferencesPathSetValue(prefs
, path
, newConfig
);
193 CFRelease(newConfig
);
195 ok
= SCPreferencesPathRemoveValue(prefs
, path
);
196 if (!ok
&& (SCError() == kSCStatusNoKey
)) {
205 #define SYSTEMCONFIGURATION_RESOURCES_PATH SYSTEMCONFIGURATION_FRAMEWORK_PATH "/Resources"
207 #define SYSTEMCONFIGURATION_RESOURCES_PATH SYSTEMCONFIGURATION_FRAMEWORK_PATH
208 #endif // TARGET_OS_OSX
210 #define NETWORKCONFIGURATION_RESOURCE_FILE "NetworkConfiguration.plist"
212 static CFDictionaryRef
216 CFDictionaryRef templates
;
219 bundle
= _SC_CFBundleGet();
220 if (bundle
== NULL
) {
224 url
= CFBundleCopyResourceURL(bundle
, CFSTR("NetworkConfiguration"), CFSTR("plist"), 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
230 NETWORKCONFIGURATION_RESOURCE_FILE
),
231 kCFURLPOSIXPathStyle
,
235 SC_log(LOG_ERR
, "failed to CREATE resource URL to \"%s\"", SYSTEMCONFIGURATION_RESOURCES_PATH
237 NETWORKCONFIGURATION_RESOURCE_FILE
);
242 templates
= _SCCreatePropertyListFromResource(url
);
245 if ((templates
!= NULL
) && !isA_CFDictionary(templates
)) {
246 CFRelease(templates
);
254 __private_extern__ CFDictionaryRef
255 __copyInterfaceTemplate(CFStringRef interfaceType
,
256 CFStringRef childInterfaceType
)
258 CFDictionaryRef interface
= NULL
;
259 CFDictionaryRef interfaces
;
260 CFDictionaryRef templates
;
262 templates
= __copyTemplates();
263 if (templates
== NULL
) {
267 interfaces
= CFDictionaryGetValue(templates
, CFSTR("Interface"));
268 if (!isA_CFDictionary(interfaces
)) {
269 CFRelease(templates
);
273 if (childInterfaceType
== NULL
) {
274 interface
= CFDictionaryGetValue(interfaces
, interfaceType
);
276 CFStringRef expandedType
;
278 if (CFStringFind(childInterfaceType
, CFSTR("."), 0).location
!= kCFNotFound
) {
280 childInterfaceType
= CFSTR("*");
283 expandedType
= CFStringCreateWithFormat(NULL
,
288 interface
= CFDictionaryGetValue(interfaces
, expandedType
);
289 CFRelease(expandedType
);
292 if (isA_CFDictionary(interface
) && (CFDictionaryGetCount(interface
) > 0)) {
298 CFRelease(templates
);
304 __private_extern__ CFDictionaryRef
305 __copyProtocolTemplate(CFStringRef interfaceType
,
306 CFStringRef childInterfaceType
,
307 CFStringRef protocolType
)
309 CFDictionaryRef interface
= NULL
;
310 CFDictionaryRef protocol
= NULL
;
311 CFDictionaryRef protocols
;
312 CFDictionaryRef templates
;
314 templates
= __copyTemplates();
315 if (templates
== NULL
) {
319 protocols
= CFDictionaryGetValue(templates
, CFSTR("Protocol"));
320 if (!isA_CFDictionary(protocols
)) {
321 CFRelease(templates
);
325 if (childInterfaceType
== NULL
) {
326 interface
= CFDictionaryGetValue(protocols
, interfaceType
);
328 CFStringRef expandedType
;
330 if (CFStringFind(childInterfaceType
, CFSTR("."), 0).location
!= kCFNotFound
) {
332 childInterfaceType
= CFSTR("*");
335 expandedType
= CFStringCreateWithFormat(NULL
,
340 interface
= CFDictionaryGetValue(protocols
, expandedType
);
341 CFRelease(expandedType
);
344 if (isA_CFDictionary(interface
)) {
345 protocol
= CFDictionaryGetValue(interface
, protocolType
);
346 if (isA_CFDictionary(protocol
)) {
353 CFRelease(templates
);
359 __private_extern__ Boolean
360 __createInterface(int s
, CFStringRef interface
)
364 memset(&ifr
, 0, sizeof(ifr
));
365 (void) _SC_cfstring_to_cstring(interface
,
367 sizeof(ifr
.ifr_name
),
368 kCFStringEncodingASCII
);
370 if (ioctl(s
, SIOCIFCREATE
, &ifr
) == -1) {
371 SC_log(LOG_NOTICE
, "could not create interface \"%@\": %s",
381 __private_extern__ Boolean
382 __destroyInterface(int s
, CFStringRef interface
)
386 memset(&ifr
, 0, sizeof(ifr
));
387 (void) _SC_cfstring_to_cstring(interface
,
389 sizeof(ifr
.ifr_name
),
390 kCFStringEncodingASCII
);
392 if (ioctl(s
, SIOCIFDESTROY
, &ifr
) == -1) {
393 SC_log(LOG_NOTICE
, "could not destroy interface \"%@\": %s",
404 * For rdar://problem/4685223
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.
410 * Note: this backwards compatibility code must be enabled using the
413 * sudo defaults write \
414 * /Library/Preferences/SystemConfiguration/preferences \
420 __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(SCPreferencesRef prefs
, CFStringRef prefix
)
422 static int hack
= -1;
423 CFStringRef path
= NULL
;
428 enable
= SCPreferencesGetValue(prefs
, CFSTR("MoreSCF"));
429 hack
= (isA_CFBoolean(enable
) && CFBooleanGetValue(enable
)) ? 1 : 0;
433 CFDictionaryRef dict
;
436 path
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@/%@"), prefix
, CFSTR("0"));
437 dict
= SCPreferencesPathGetValue(prefs
, path
);
439 // if path "0" exists
444 // unique child with path "0" does not exist, create
445 dict
= CFDictionaryCreate(NULL
,
447 &kCFTypeDictionaryKeyCallBacks
,
448 &kCFTypeDictionaryValueCallBacks
);
449 ok
= SCPreferencesPathSetValue(prefs
, path
, dict
);
463 __copy_legacy_password(CFTypeRef password
)
465 if (password
== NULL
) {
469 if (isA_CFData(password
)) {
472 n
= CFDataGetLength(password
);
473 if ((n
% sizeof(UniChar
)) == 0) {
474 CFStringEncoding encoding
;
478 encoding
= (*(CFDataGetBytePtr(password
) + 1) == 0x00) ? kCFStringEncodingUTF16LE
: kCFStringEncodingUTF16BE
;
479 #else // __LITTLE_ENDIAN__
480 encoding
= (*(CFDataGetBytePtr(password
) ) == 0x00) ? kCFStringEncodingUTF16BE
: kCFStringEncodingUTF16LE
;
482 str
= CFStringCreateWithBytes(NULL
,
483 (const UInt8
*)CFDataGetBytePtr(password
),
487 password
= CFStringCreateExternalRepresentation(NULL
,
489 kCFStringEncodingUTF8
,
495 } else if (isA_CFString(password
) && (CFStringGetLength(password
) > 0)) {
496 // convert password to CFData
497 password
= CFStringCreateExternalRepresentation(NULL
,
499 kCFStringEncodingUTF8
,
511 __extract_password(SCPreferencesRef prefs
,
512 CFDictionaryRef config
,
513 CFStringRef passwordKey
,
514 CFStringRef encryptionKey
,
515 CFStringRef encryptionKeyChainValue
,
516 CFStringRef unique_id
,
519 CFStringRef encryption
= NULL
;
520 Boolean exists
= FALSE
;
522 // check for keychain password
523 if (config
!= NULL
) {
524 encryption
= CFDictionaryGetValue(config
, encryptionKey
);
526 if ((encryption
== NULL
) ||
527 (isA_CFString(encryption
) &&
528 CFEqual(encryption
, encryptionKeyChainValue
))) {
530 if (password
!= NULL
) {
532 *password
= _SCPreferencesSystemKeychainPasswordItemCopy(prefs
, unique_id
);
534 *password
= _SCSecKeychainPasswordItemCopy(NULL
, unique_id
);
536 exists
= (*password
!= NULL
);
539 exists
= _SCPreferencesSystemKeychainPasswordItemExists(prefs
, unique_id
);
541 exists
= _SCSecKeychainPasswordItemExists(NULL
, unique_id
);
546 // as needed, check for in-line password
547 if (!exists
&& (encryption
== NULL
) && (config
!= NULL
)) {
548 CFDataRef inline_password
;
550 inline_password
= CFDictionaryGetValue(config
, passwordKey
);
551 inline_password
= __copy_legacy_password(inline_password
);
552 if (inline_password
!= NULL
) {
555 if (password
!= NULL
) {
556 *password
= inline_password
;
558 CFRelease(inline_password
);
569 __remove_password(SCPreferencesRef prefs
,
570 CFDictionaryRef config
,
571 CFStringRef passwordKey
,
572 CFStringRef encryptionKey
,
573 CFStringRef encryptionKeyChainValue
,
574 CFStringRef unique_id
,
575 CFDictionaryRef
*newConfig
)
577 CFStringRef encryption
= NULL
;
580 // check for keychain password
581 if (config
!= NULL
) {
582 encryption
= CFDictionaryGetValue(config
, encryptionKey
);
584 if ((encryption
== NULL
) ||
585 (isA_CFString(encryption
) &&
586 CFEqual(encryption
, encryptionKeyChainValue
))) {
587 // remove keychain password
589 ok
= _SCPreferencesSystemKeychainPasswordItemRemove(prefs
, unique_id
);
591 ok
= _SCSecKeychainPasswordItemRemove(NULL
, unique_id
);
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
;
599 inline_password
= CFDictionaryGetValue(config
, passwordKey
);
600 inline_password
= __copy_legacy_password(inline_password
);
601 if (inline_password
!= NULL
) {
602 CFRelease(inline_password
);
607 if (newConfig
!= NULL
) {
608 if (ok
&& (config
!= NULL
)) {
609 CFMutableDictionaryRef temp
;
611 temp
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
612 CFDictionaryRemoveValue(temp
, passwordKey
);
613 CFDictionaryRemoveValue(temp
, encryptionKey
);
614 *newConfig
= (CFDictionaryRef
)temp
;
624 __private_extern__ Boolean
625 __rank_to_str(SCNetworkServicePrimaryRank rank
, CFStringRef
*rankStr
)
628 case kSCNetworkServicePrimaryRankDefault
:
631 case kSCNetworkServicePrimaryRankFirst
:
632 *rankStr
= kSCValNetServicePrimaryRankFirst
;
634 case kSCNetworkServicePrimaryRankLast
:
635 *rankStr
= kSCValNetServicePrimaryRankLast
;
637 case kSCNetworkServicePrimaryRankNever
:
638 *rankStr
= kSCValNetServicePrimaryRankNever
;
640 case kSCNetworkServicePrimaryRankScoped
:
641 *rankStr
= kSCValNetServicePrimaryRankScoped
;
651 __private_extern__ Boolean
652 __str_to_rank(CFStringRef rankStr
, SCNetworkServicePrimaryRank
*rank
)
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
;
666 } else if (rankStr
== NULL
) {
667 *rank
= kSCNetworkServicePrimaryRankDefault
;