2 * Copyright (c) 2004-2007, 2009, 2010-2013, 2015 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 <CoreFoundation/CoreFoundation.h>
33 #include <SystemConfiguration/SystemConfiguration.h>
34 #include <SystemConfiguration/SCValidation.h>
35 #include <SystemConfiguration/SCPrivate.h>
37 #include <sys/ioctl.h>
41 __private_extern__ CFDictionaryRef
42 __getPrefsConfiguration(SCPreferencesRef prefs
, CFStringRef path
)
44 CFDictionaryRef config
;
47 config
= SCPreferencesPathGetValue(prefs
, path
);
49 n
= isA_CFDictionary(config
) ? CFDictionaryGetCount(config
) : 0;
52 // ignore empty configuration entities
56 if (CFDictionaryContainsKey(config
, kSCResvInactive
)) {
57 // ignore [effectively] empty configuration entities
69 __private_extern__ Boolean
70 __setPrefsConfiguration(SCPreferencesRef prefs
,
72 CFDictionaryRef config
,
75 CFDictionaryRef curConfig
;
76 CFMutableDictionaryRef newConfig
= NULL
;
79 if ((config
!= NULL
) && !isA_CFDictionary(config
)) {
80 _SCErrorSet(kSCStatusInvalidArgument
);
84 curConfig
= SCPreferencesPathGetValue(prefs
, path
);
87 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
92 newConfig
= CFDictionaryCreateMutable(NULL
,
94 &kCFTypeDictionaryKeyCallBacks
,
95 &kCFTypeDictionaryValueCallBacks
);
98 if (isA_CFDictionary(curConfig
) && CFDictionaryContainsKey(curConfig
, kSCResvInactive
)) {
99 // if currently disabled
100 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
102 // if currently enabled
103 CFDictionaryRemoveValue(newConfig
, kSCResvInactive
);
107 // set new configuration
108 if (_SC_CFEqual(curConfig
, newConfig
)) {
110 if (newConfig
!= NULL
) CFRelease(newConfig
);
112 } else if (newConfig
!= NULL
) {
113 // if new configuration (or we are preserving a disabled state)
114 ok
= SCPreferencesPathSetValue(prefs
, path
, newConfig
);
115 CFRelease(newConfig
);
117 ok
= SCPreferencesPathRemoveValue(prefs
, path
);
118 if (!ok
&& (SCError() == kSCStatusNoKey
)) {
127 __private_extern__ Boolean
128 __getPrefsEnabled(SCPreferencesRef prefs
, CFStringRef path
)
130 CFDictionaryRef config
;
132 config
= SCPreferencesPathGetValue(prefs
, path
);
133 if (isA_CFDictionary(config
) && CFDictionaryContainsKey(config
, kSCResvInactive
)) {
141 __private_extern__ Boolean
142 __setPrefsEnabled(SCPreferencesRef prefs
,
146 CFDictionaryRef curConfig
;
147 CFMutableDictionaryRef newConfig
= NULL
;
150 // preserve current configuration
151 curConfig
= SCPreferencesPathGetValue(prefs
, path
);
152 if (curConfig
!= NULL
) {
153 if (!isA_CFDictionary(curConfig
)) {
154 _SCErrorSet(kSCStatusFailed
);
157 newConfig
= CFDictionaryCreateMutableCopy(NULL
, 0, curConfig
);
161 CFDictionaryRemoveValue(newConfig
, kSCResvInactive
);
164 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
169 newConfig
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
170 CFDictionarySetValue(newConfig
, kSCResvInactive
, kCFBooleanTrue
);
174 // set new configuration
175 if (_SC_CFEqual(curConfig
, newConfig
)) {
177 if (newConfig
!= NULL
) CFRelease(newConfig
);
179 } else if (newConfig
!= NULL
) {
180 // if updated configuration (or we are establishing as disabled)
181 ok
= SCPreferencesPathSetValue(prefs
, path
, newConfig
);
182 CFRelease(newConfig
);
184 ok
= SCPreferencesPathRemoveValue(prefs
, path
);
185 if (!ok
&& (SCError() == kSCStatusNoKey
)) {
193 #if !TARGET_OS_EMBEDDED
194 #define SYSTEMCONFIGURATION_RESOURCES_PATH SYSTEMCONFIGURATION_FRAMEWORK_PATH "/Resources"
196 #define SYSTEMCONFIGURATION_RESOURCES_PATH SYSTEMCONFIGURATION_FRAMEWORK_PATH
197 #endif // !TARGET_OS_EMBEDDED
199 #define NETWORKCONFIGURATION_RESOURCE_FILE "NetworkConfiguration.plist"
201 static CFDictionaryRef
205 CFErrorRef error
= NULL
;
208 CFDictionaryRef templates
;
210 CFDataRef xmlTemplates
= NULL
;
212 bundle
= _SC_CFBundleGet();
213 if (bundle
== NULL
) {
217 url
= CFBundleCopyResourceURL(bundle
, CFSTR("NetworkConfiguration"), CFSTR("plist"), NULL
);
219 SC_log(LOG_ERR
, "failed to GET resource URL to \"%s\". Trying harder...", NETWORKCONFIGURATION_RESOURCE_FILE
);
220 url
= CFURLCreateWithFileSystemPath(NULL
,
221 CFSTR(SYSTEMCONFIGURATION_RESOURCES_PATH
223 NETWORKCONFIGURATION_RESOURCE_FILE
),
224 kCFURLPOSIXPathStyle
,
228 SC_log(LOG_ERR
, "failed to CREATE resource URL to \"%s\"", SYSTEMCONFIGURATION_RESOURCES_PATH
230 NETWORKCONFIGURATION_RESOURCE_FILE
);
235 #pragma GCC diagnostic push
236 #pragma GCC diagnostic ignored "-Wdeprecated"
237 ok
= CFURLCreateDataAndPropertiesFromResource(NULL
, url
, &xmlTemplates
, NULL
, NULL
, &errorCode
);
238 #pragma GCC diagnostic pop
240 if (!ok
|| (xmlTemplates
== NULL
)) {
241 SC_log(LOG_NOTICE
, "%s: failed to create data properties from resource (error=%ld)", __FUNCTION__
, (long)errorCode
);
245 // convert the XML data into a property list
246 templates
= CFPropertyListCreateWithData(NULL
, xmlTemplates
, kCFPropertyListImmutable
, NULL
, &error
);
247 CFRelease(xmlTemplates
);
248 if (templates
== NULL
) {
250 SC_log(LOG_NOTICE
, "could not load SCNetworkConfiguration templates: %@", error
);
256 if (!isA_CFDictionary(templates
)) {
257 CFRelease(templates
);
265 __private_extern__ CFDictionaryRef
266 __copyInterfaceTemplate(CFStringRef interfaceType
,
267 CFStringRef childInterfaceType
)
269 CFDictionaryRef interface
= NULL
;
270 CFDictionaryRef interfaces
;
271 CFDictionaryRef templates
;
273 templates
= __copyTemplates();
274 if (templates
== NULL
) {
278 interfaces
= CFDictionaryGetValue(templates
, CFSTR("Interface"));
279 if (!isA_CFDictionary(interfaces
)) {
280 CFRelease(templates
);
284 if (childInterfaceType
== NULL
) {
285 interface
= CFDictionaryGetValue(interfaces
, interfaceType
);
287 CFStringRef expandedType
;
289 if (CFStringFind(childInterfaceType
, CFSTR("."), 0).location
!= kCFNotFound
) {
291 childInterfaceType
= CFSTR("*");
294 expandedType
= CFStringCreateWithFormat(NULL
,
299 interface
= CFDictionaryGetValue(interfaces
, expandedType
);
300 CFRelease(expandedType
);
303 if (isA_CFDictionary(interface
) && (CFDictionaryGetCount(interface
) > 0)) {
309 CFRelease(templates
);
315 __private_extern__ CFDictionaryRef
316 __copyProtocolTemplate(CFStringRef interfaceType
,
317 CFStringRef childInterfaceType
,
318 CFStringRef protocolType
)
320 CFDictionaryRef interface
= NULL
;
321 CFDictionaryRef protocol
= NULL
;
322 CFDictionaryRef protocols
;
323 CFDictionaryRef templates
;
325 templates
= __copyTemplates();
326 if (templates
== NULL
) {
330 protocols
= CFDictionaryGetValue(templates
, CFSTR("Protocol"));
331 if (!isA_CFDictionary(protocols
)) {
332 CFRelease(templates
);
336 if (childInterfaceType
== NULL
) {
337 interface
= CFDictionaryGetValue(protocols
, interfaceType
);
339 CFStringRef expandedType
;
341 if (CFStringFind(childInterfaceType
, CFSTR("."), 0).location
!= kCFNotFound
) {
343 childInterfaceType
= CFSTR("*");
346 expandedType
= CFStringCreateWithFormat(NULL
,
351 interface
= CFDictionaryGetValue(protocols
, expandedType
);
352 CFRelease(expandedType
);
355 if (isA_CFDictionary(interface
)) {
356 protocol
= CFDictionaryGetValue(interface
, protocolType
);
357 if (isA_CFDictionary(protocol
)) {
364 CFRelease(templates
);
370 __private_extern__ Boolean
371 __createInterface(int s
, CFStringRef interface
)
375 bzero(&ifr
, sizeof(ifr
));
376 (void) _SC_cfstring_to_cstring(interface
,
378 sizeof(ifr
.ifr_name
),
379 kCFStringEncodingASCII
);
381 if (ioctl(s
, SIOCIFCREATE
, &ifr
) == -1) {
382 SC_log(LOG_NOTICE
, "could not create interface \"%@\": %s",
392 __private_extern__ Boolean
393 __destroyInterface(int s
, CFStringRef interface
)
397 bzero(&ifr
, sizeof(ifr
));
398 (void) _SC_cfstring_to_cstring(interface
,
400 sizeof(ifr
.ifr_name
),
401 kCFStringEncodingASCII
);
403 if (ioctl(s
, SIOCIFDESTROY
, &ifr
) == -1) {
404 SC_log(LOG_NOTICE
, "could not destroy interface \"%@\": %s",
415 * For rdar://problem/4685223
417 * To keep MoreSCF happy we need to ensure that the first "Set" and
418 * "NetworkService" have a [less than] unique identifier that can
419 * be parsed as a numeric string.
421 * Note: this backwards compatibility code must be enabled using the
424 * sudo defaults write \
425 * /Library/Preferences/SystemConfiguration/preferences \
431 __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(SCPreferencesRef prefs
, CFStringRef prefix
)
433 static int hack
= -1;
434 CFStringRef path
= NULL
;
439 enable
= SCPreferencesGetValue(prefs
, CFSTR("MoreSCF"));
440 hack
= (isA_CFBoolean(enable
) && CFBooleanGetValue(enable
)) ? 1 : 0;
444 CFDictionaryRef dict
;
447 path
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@/%@"), prefix
, CFSTR("0"));
448 dict
= SCPreferencesPathGetValue(prefs
, path
);
450 // if path "0" exists
455 // unique child with path "0" does not exist, create
456 dict
= CFDictionaryCreate(NULL
,
458 &kCFTypeDictionaryKeyCallBacks
,
459 &kCFTypeDictionaryValueCallBacks
);
460 ok
= SCPreferencesPathSetValue(prefs
, path
, dict
);
474 __copy_legacy_password(CFTypeRef password
)
476 if (password
== NULL
) {
480 if (isA_CFData(password
)) {
483 n
= CFDataGetLength(password
);
484 if ((n
% sizeof(UniChar
)) == 0) {
485 CFStringEncoding encoding
;
489 encoding
= (*(CFDataGetBytePtr(password
) + 1) == 0x00) ? kCFStringEncodingUTF16LE
: kCFStringEncodingUTF16BE
;
490 #else // __LITTLE_ENDIAN__
491 encoding
= (*(CFDataGetBytePtr(password
) ) == 0x00) ? kCFStringEncodingUTF16BE
: kCFStringEncodingUTF16LE
;
493 str
= CFStringCreateWithBytes(NULL
,
494 (const UInt8
*)CFDataGetBytePtr(password
),
498 password
= CFStringCreateExternalRepresentation(NULL
,
500 kCFStringEncodingUTF8
,
506 } else if (isA_CFString(password
) && (CFStringGetLength(password
) > 0)) {
507 // convert password to CFData
508 password
= CFStringCreateExternalRepresentation(NULL
,
510 kCFStringEncodingUTF8
,
522 __extract_password(SCPreferencesRef prefs
,
523 CFDictionaryRef config
,
524 CFStringRef passwordKey
,
525 CFStringRef encryptionKey
,
526 CFStringRef encryptionKeyChainValue
,
527 CFStringRef unique_id
,
530 CFStringRef encryption
= NULL
;
531 Boolean exists
= FALSE
;
533 // check for keychain password
534 if (config
!= NULL
) {
535 encryption
= CFDictionaryGetValue(config
, encryptionKey
);
537 if ((encryption
== NULL
) ||
538 (isA_CFString(encryption
) &&
539 CFEqual(encryption
, encryptionKeyChainValue
))) {
541 if (password
!= NULL
) {
543 *password
= _SCPreferencesSystemKeychainPasswordItemCopy(prefs
, unique_id
);
545 *password
= _SCSecKeychainPasswordItemCopy(NULL
, unique_id
);
547 exists
= (*password
!= NULL
);
550 exists
= _SCPreferencesSystemKeychainPasswordItemExists(prefs
, unique_id
);
552 exists
= _SCSecKeychainPasswordItemExists(NULL
, unique_id
);
557 // as needed, check for in-line password
558 if (!exists
&& (encryption
== NULL
) && (config
!= NULL
)) {
559 CFDataRef inline_password
;
561 inline_password
= CFDictionaryGetValue(config
, passwordKey
);
562 inline_password
= __copy_legacy_password(inline_password
);
563 if (inline_password
!= NULL
) {
566 if (password
!= NULL
) {
567 *password
= inline_password
;
569 CFRelease(inline_password
);
580 __remove_password(SCPreferencesRef prefs
,
581 CFDictionaryRef config
,
582 CFStringRef passwordKey
,
583 CFStringRef encryptionKey
,
584 CFStringRef encryptionKeyChainValue
,
585 CFStringRef unique_id
,
586 CFDictionaryRef
*newConfig
)
588 CFStringRef encryption
= NULL
;
591 // check for keychain password
592 if (config
!= NULL
) {
593 encryption
= CFDictionaryGetValue(config
, encryptionKey
);
595 if ((encryption
== NULL
) ||
596 (isA_CFString(encryption
) &&
597 CFEqual(encryption
, encryptionKeyChainValue
))) {
598 // remove keychain password
600 ok
= _SCPreferencesSystemKeychainPasswordItemRemove(prefs
, unique_id
);
602 ok
= _SCSecKeychainPasswordItemRemove(NULL
, unique_id
);
606 // as needed, check if we have an in-line password that we can remove
607 if (!ok
&& (encryption
== NULL
) && (config
!= NULL
)) {
608 CFDataRef inline_password
;
610 inline_password
= CFDictionaryGetValue(config
, passwordKey
);
611 inline_password
= __copy_legacy_password(inline_password
);
612 if (inline_password
!= NULL
) {
613 CFRelease(inline_password
);
618 if (newConfig
!= NULL
) {
619 if (ok
&& (config
!= NULL
)) {
620 CFMutableDictionaryRef temp
;
622 temp
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
623 CFDictionaryRemoveValue(temp
, passwordKey
);
624 CFDictionaryRemoveValue(temp
, encryptionKey
);
625 *newConfig
= (CFDictionaryRef
)temp
;
635 __private_extern__ Boolean
636 __rank_to_str(SCNetworkServicePrimaryRank rank
, CFStringRef
*rankStr
)
639 case kSCNetworkServicePrimaryRankDefault
:
642 case kSCNetworkServicePrimaryRankFirst
:
643 *rankStr
= kSCValNetServicePrimaryRankFirst
;
645 case kSCNetworkServicePrimaryRankLast
:
646 *rankStr
= kSCValNetServicePrimaryRankLast
;
648 case kSCNetworkServicePrimaryRankNever
:
649 *rankStr
= kSCValNetServicePrimaryRankNever
;
651 case kSCNetworkServicePrimaryRankScoped
:
652 *rankStr
= kSCValNetServicePrimaryRankScoped
;
662 __private_extern__ Boolean
663 __str_to_rank(CFStringRef rankStr
, SCNetworkServicePrimaryRank
*rank
)
665 if (isA_CFString(rankStr
)) {
666 if (CFEqual(rankStr
, kSCValNetServicePrimaryRankFirst
)) {
667 *rank
= kSCNetworkServicePrimaryRankFirst
;
668 } else if (CFEqual(rankStr
, kSCValNetServicePrimaryRankLast
)) {
669 *rank
= kSCNetworkServicePrimaryRankLast
;
670 } else if (CFEqual(rankStr
, kSCValNetServicePrimaryRankNever
)) {
671 *rank
= kSCNetworkServicePrimaryRankNever
;
672 } else if (CFEqual(rankStr
, kSCValNetServicePrimaryRankScoped
)) {
673 *rank
= kSCNetworkServicePrimaryRankScoped
;
677 } else if (rankStr
== NULL
) {
678 *rank
= kSCNetworkServicePrimaryRankDefault
;