2 * Copyright (c) 2000-2008, 2010, 2012-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 * April 2, 2004 Allan Nathanson <ajn@apple.com>
28 * - use SCPreference notification APIs
30 * June 24, 2001 Allan Nathanson <ajn@apple.com>
31 * - update to public SystemConfiguration.framework APIs
33 * November 10, 2000 Allan Nathanson <ajn@apple.com>
38 #include <TargetConditionals.h>
41 #include <sys/types.h>
46 #define SC_LOG_HANDLE __log_PreferencesMonitor()
47 #include <SystemConfiguration/SystemConfiguration.h>
48 #include <SystemConfiguration/SCPrivate.h>
49 #include <SystemConfiguration/SCValidation.h>
50 #include "plugin_shared.h"
53 #include <CommonCrypto/CommonDigest.h>
57 static SCPreferencesRef prefs
= NULL
;
58 static SCDynamicStoreRef store
= NULL
;
60 /* InterfaceNamer[.plugin] monitoring globals */
61 Boolean haveConfiguration
= FALSE
;
62 static CFStringRef namerKey
= NULL
;
63 static CFArrayRef preconfigured
= NULL
;
65 /* KernelEventMonitor[.plugin] monitoring globals */
66 static CFStringRef interfacesKey
= NULL
;
68 /* SCDynamicStore (Setup:) */
69 static CFMutableDictionaryRef currentPrefs
; /* current prefs */
70 static CFMutableDictionaryRef newPrefs
; /* new prefs */
71 static CFMutableArrayRef unchangedPrefsKeys
; /* new prefs keys which match current */
72 static CFMutableArrayRef removedPrefsKeys
; /* old prefs keys to be removed */
74 static Boolean rofs
= FALSE
;
75 static Boolean restorePrefs
= FALSE
;
77 #define MY_PLUGIN_NAME "PreferencesMonitor"
78 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
82 updateConfiguration(SCPreferencesRef prefs
,
83 SCPreferencesNotification notificationType
,
88 __log_PreferencesMonitor()
90 static os_log_t log
= NULL
;
93 log
= os_log_create("com.apple.SystemConfiguration", "PreferencesMonitor");
104 CFStringRef currentModel
= NULL
;
105 CFMutableStringRef modelPrefixStr
= NULL
;
106 CFArrayRef keyList
= NULL
;
107 CFIndex keyListCount
;
109 Boolean modified
= FALSE
;
110 int sc_status
= kSCStatusFailed
;
113 ok
= SCPreferencesLock(prefs
, TRUE
);
118 sc_status
= SCError();
119 if (sc_status
== kSCStatusStale
) {
120 SCPreferencesSynchronize(prefs
);
122 SC_log(LOG_NOTICE
, "Could not acquire network configuration lock: %s",
123 SCErrorString(sc_status
));
128 keyList
= SCPreferencesCopyKeyList(prefs
);
129 if (keyList
== NULL
) {
133 currentModel
= _SC_hw_model(FALSE
);
134 if (currentModel
== NULL
) {
138 /* Create "model:" string for prefix-check */
139 modelPrefixStr
= CFStringCreateMutableCopy(NULL
, 0, currentModel
);
140 CFStringAppend(modelPrefixStr
, CFSTR(":"));
142 keyListCount
= CFArrayGetCount(keyList
);
143 for (idx
= 0; idx
< keyListCount
; idx
++) {
144 CFStringRef existingKey
= CFArrayGetValueAtIndex(keyList
, idx
);
146 CFArrayRef splitKey
= NULL
;
147 CFPropertyListRef value
;
149 if (isA_CFString(existingKey
) == NULL
) {
153 if (!CFStringHasPrefix(existingKey
, modelPrefixStr
)) {
157 splitKey
= CFStringCreateArrayBySeparatingStrings(NULL
, existingKey
, CFSTR(":"));
158 key
= CFArrayGetValueAtIndex(splitKey
, 1);
159 value
= SCPreferencesGetValue(prefs
, existingKey
);
160 SCPreferencesSetValue(prefs
, key
, value
);
161 SCPreferencesRemoveValue(prefs
, existingKey
);
167 SCPreferencesRef ni_prefs
= NULL
;
168 ni_prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, CFSTR("NetworkInterfaces.plist"));
169 if (ni_prefs
== NULL
) {
173 ok
= _SCNetworkConfigurationCheckValidityWithPreferences(prefs
, ni_prefs
, NULL
);
176 //Commit the changes only if prefs files valid
178 if (!SCPreferencesCommitChanges(prefs
)) {
179 if (SCError() != EROFS
) {
180 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s",
181 SCErrorString(SCError()));
187 (void) SCPreferencesApplyChanges(prefs
);
192 (void) SCPreferencesUnlock(prefs
);
194 if (keyList
!= NULL
) {
197 if (modelPrefixStr
!= NULL
) {
198 CFRelease(modelPrefixStr
);
205 establishNewPreferences()
207 SCNetworkSetRef current
= NULL
;
208 CFStringRef new_model
;
210 int sc_status
= kSCStatusFailed
;
211 SCNetworkSetRef set
= NULL
;
212 Boolean updated
= FALSE
;
215 ok
= SCPreferencesLock(prefs
, TRUE
);
220 sc_status
= SCError();
221 if (sc_status
== kSCStatusStale
) {
222 SCPreferencesSynchronize(prefs
);
224 SC_log(LOG_NOTICE
, "Could not acquire network configuration lock: %s",
225 SCErrorString(sc_status
));
230 /* Ensure that the preferences has the new model */
231 new_model
= _SC_hw_model(FALSE
);
233 /* Need to regenerate the new configuration for new model */
234 if (new_model
!= NULL
) {
235 CFStringRef old_model
;
237 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
238 if ((old_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
243 keys
= SCPreferencesCopyKeyList(prefs
);
244 count
= (keys
!= NULL
) ? CFArrayGetCount(keys
) : 0;
246 for (index
= 0; index
< count
; index
++) {
247 CFStringRef existing_key
;
249 existing_key
= CFArrayGetValueAtIndex(keys
, index
);
250 if (isA_CFString(existing_key
) != NULL
) {
252 CFPropertyListRef value
;
254 /* If it already contains a Model
255 or if it already contains a MODEL:KEY key skip it*/
256 if (CFEqual(existing_key
, MODEL
)
257 || CFStringFind(existing_key
, CFSTR(":"), 0).location
262 value
= SCPreferencesGetValue(prefs
, existing_key
);
264 /* Create a new key as OLD_MODEL:OLD_KEY */
265 new_key
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:%@"),
266 old_model
, existing_key
);
267 SCPreferencesSetValue(prefs
, new_key
, value
);
268 if (!CFEqual(existing_key
, kSCPrefSystem
)) {
269 /* preserve existing host names */
270 SCPreferencesRemoveValue(prefs
, existing_key
);
280 /* Set the new model */
281 SCPreferencesSetValue(prefs
, MODEL
, new_model
);
284 current
= SCNetworkSetCopyCurrent(prefs
);
285 if (current
!= NULL
) {
290 set
= _SCNetworkSetCreateDefault(prefs
);
293 sc_status
= SCError();
298 ok
= SCNetworkSetEstablishDefaultConfiguration(set
);
300 sc_status
= SCError();
307 ok
= SCPreferencesCommitChanges(prefs
);
309 SC_log(LOG_NOTICE
, "New network configuration saved");
312 sc_status
= SCError();
313 if (sc_status
== EROFS
) {
314 /* a read-only fileysstem is OK */
317 /* ... but we don't want to synchronize */
322 /* apply (committed or temporary/read-only) changes */
323 (void) SCPreferencesApplyChanges(prefs
);
324 } else if ((current
== NULL
) && (set
!= NULL
)) {
325 (void) SCNetworkSetRemove(set
);
329 SC_log(LOG_NOTICE
, "Could not establish network configuration: %s",
330 SCErrorString(sc_status
));
333 (void)SCPreferencesUnlock(prefs
);
334 if (set
!= NULL
) CFRelease(set
);
340 watchSCDynamicStore()
342 CFMutableArrayRef keys
;
344 CFRunLoopSourceRef rls
;
347 * watch for KernelEventMonitor[.bundle] changes (the list of
348 * active network interfaces)
350 interfacesKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
351 kSCDynamicStoreDomainState
);
354 * watch for InterfaceNamer[.bundle] changes (quiet, timeout,
355 * and the list of pre-configured interfaces)
357 namerKey
= SCDynamicStoreKeyCreate(NULL
,
358 CFSTR("%@" "InterfaceNamer"),
359 kSCDynamicStoreDomainPlugin
);
361 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
363 SC_log(LOG_NOTICE
, "SCDynamicStoreCreateRunLoopSource() failed: %s", SCErrorString(SCError()));
364 haveConfiguration
= TRUE
;
367 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
370 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
371 CFArrayAppendValue(keys
, interfacesKey
);
372 CFArrayAppendValue(keys
, namerKey
);
373 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
376 SC_log(LOG_NOTICE
, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError()));
377 haveConfiguration
= TRUE
;
387 previousConfigurationAvailable()
389 CFStringRef backupKey
= NULL
;
390 CFStringRef currentModel
= NULL
;
391 CFPropertyListRef properties
= NULL
;
393 currentModel
= _SC_hw_model(FALSE
);
394 if (currentModel
== NULL
) {
398 /* Currently relying only if a backup of "Sets" is present */
399 backupKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:Sets"), currentModel
);
400 properties
= SCPreferencesGetValue(prefs
, backupKey
);
401 CFRelease(backupKey
);
403 return (properties
!= NULL
);
408 storeCallback(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
)
410 CFDictionaryRef dict
;
411 CFArrayRef interfaces
= NULL
;
412 Boolean quiet
= FALSE
;
413 Boolean timeout
= FALSE
;
414 Boolean updated
= FALSE
;
417 * Capture/process KernelEventMonitor[.bundle] info
418 * 1. get list of active network interfaces
420 dict
= SCDynamicStoreCopyValue(store
, interfacesKey
);
422 if (isA_CFDictionary(dict
)) {
423 interfaces
= CFDictionaryGetValue(dict
, kSCPropNetInterfaces
);
424 interfaces
= isA_CFArray(interfaces
);
425 if (interfaces
!= NULL
) {
426 CFRetain(interfaces
);
434 * Capture/process InterfaceNamer[.bundle] info
435 * 1. check if IORegistry "quiet", "timeout"
436 * 2. get list of named pre-configured interfaces
437 * 3. merge list of active interfaces (from KEV) with the
438 * list of preconfigured interfaces.
440 dict
= SCDynamicStoreCopyValue(store
, namerKey
);
442 if (isA_CFDictionary(dict
)) {
443 CFArrayRef cur_preconfigured
;
444 CFMutableArrayRef new_preconfigured
= NULL
;
446 if (CFDictionaryContainsKey(dict
, kInterfaceNamerKey_Quiet
)) {
449 if (CFDictionaryContainsKey(dict
, kInterfaceNamerKey_Timeout
)) {
453 cur_preconfigured
= CFDictionaryGetValue(dict
, kInterfaceNamerKey_PreConfiguredInterfaces
);
454 cur_preconfigured
= isA_CFArray(cur_preconfigured
);
455 if ((cur_preconfigured
!= NULL
) && (interfaces
!= NULL
)) {
458 CFRange r
= CFRangeMake(0, CFArrayGetCount(interfaces
));
460 n
= CFArrayGetCount(cur_preconfigured
);
461 for (i
= 0; i
< n
; i
++) {
464 bsdName
= CFArrayGetValueAtIndex(cur_preconfigured
, i
);
465 if (!CFArrayContainsValue(interfaces
, r
, bsdName
)) {
466 // if interface not currently active
470 if (new_preconfigured
== NULL
) {
471 new_preconfigured
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
473 CFArrayAppendValue(new_preconfigured
, bsdName
);
477 if (!_SC_CFEqual(preconfigured
, new_preconfigured
)) {
478 SC_log(LOG_INFO
, "pre-configured interface list changed");
480 if (preconfigured
!= NULL
) {
481 CFRelease(preconfigured
);
483 if (new_preconfigured
!= NULL
) {
484 CFRetain(new_preconfigured
);
486 preconfigured
= new_preconfigured
;
491 if (new_preconfigured
!= NULL
) {
492 CFRelease(new_preconfigured
);
499 if (interfaces
!= NULL
) {
500 CFRelease(interfaces
);
503 if (!haveConfiguration
&& (quiet
|| timeout
)) {
504 static int logged
= 0;
507 #if !TARGET_OS_IPHONE
509 #endif /* !TARGET_OS_IPHONE */
511 haveConfiguration
= TRUE
;
514 (void) establishNewPreferences();
517 (void) restorePreferences();
518 restorePrefs
= FALSE
;
521 if (timeout
&& (logged
++ == 0)) {
522 SC_log(LOG_ERR
, "Network configuration creation timed out waiting for IORegistry");
526 if (updated
&& (changedKeys
!= NULL
)) {
527 // if pre-configured interface list changed
528 updateConfiguration(prefs
, kSCPreferencesNotificationApply
, (void *)store
);
536 updateCache(const void *key
, const void *value
, void *context
)
538 CFStringRef configKey
= (CFStringRef
)key
;
539 CFPropertyListRef configData
= (CFPropertyListRef
)value
;
540 CFPropertyListRef cacheData
;
543 cacheData
= CFDictionaryGetValue(currentPrefs
, configKey
);
546 if (CFEqual(cacheData
, configData
)) {
548 * if the old & new property list values have
549 * not changed then we don't need to update
552 CFArrayAppendValue(unchangedPrefsKeys
, configKey
);
556 /* in any case, this key should not be removed */
557 i
= CFArrayGetFirstIndexOfValue(removedPrefsKeys
,
558 CFRangeMake(0, CFArrayGetCount(removedPrefsKeys
)),
560 if (i
!= kCFNotFound
) {
561 CFArrayRemoveValueAtIndex(removedPrefsKeys
, i
);
569 flatten(SCPreferencesRef prefs
,
571 CFDictionaryRef base
)
573 CFDictionaryRef subset
;
575 CFMutableDictionaryRef myDict
;
582 if (!CFDictionaryGetValueIfPresent(base
, kSCResvLink
, (const void **)&link
)) {
583 /* if this dictionary is not linked */
586 /* if __LINK__ key is present */
587 subset
= SCPreferencesPathGetValue(prefs
, link
);
589 /* if error with link */
590 SC_log(LOG_NOTICE
, "SCPreferencesPathGetValue(,%@,) failed: %s",
592 SCErrorString(SCError()));
597 if (CFDictionaryContainsKey(subset
, kSCResvInactive
)) {
598 /* if __INACTIVE__ key is present */
602 myKey
= CFStringCreateWithFormat(NULL
,
605 kSCDynamicStoreDomainSetup
,
608 myDict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(newPrefs
, myKey
);
610 myDict
= CFDictionaryCreateMutableCopy(NULL
,
612 (CFDictionaryRef
)myDict
);
614 myDict
= CFDictionaryCreateMutable(NULL
,
616 &kCFTypeDictionaryKeyCallBacks
,
617 &kCFTypeDictionaryValueCallBacks
);
620 nKeys
= CFDictionaryGetCount(subset
);
622 keys
= CFAllocatorAllocate(NULL
, nKeys
* sizeof(CFStringRef
) , 0);
623 vals
= CFAllocatorAllocate(NULL
, nKeys
* sizeof(CFPropertyListRef
), 0);
624 CFDictionaryGetKeysAndValues(subset
, keys
, vals
);
625 for (i
= 0; i
< nKeys
; i
++) {
626 if (CFGetTypeID((CFTypeRef
)vals
[i
]) != CFDictionaryGetTypeID()) {
627 /* add this key/value to the current dictionary */
628 CFDictionarySetValue(myDict
, keys
[i
], vals
[i
]);
632 /* flatten [sub]dictionaries */
633 subKey
= CFStringCreateWithFormat(NULL
,
637 CFEqual(key
, CFSTR("/")) ? "" : "/",
639 flatten(prefs
, subKey
, vals
[i
]);
643 CFAllocatorDeallocate(NULL
, keys
);
644 CFAllocatorDeallocate(NULL
, vals
);
647 if (CFDictionaryGetCount(myDict
) > 0) {
648 /* add this dictionary to the new preferences */
649 CFDictionarySetValue(newPrefs
, myKey
, myDict
);
659 static CF_RETURNS_RETAINED SCNetworkServiceRef
660 copyInterfaceService(SCNetworkSetRef set
, CFStringRef matchName
)
664 SCNetworkServiceRef service
= NULL
;
667 services
= SCNetworkSetCopyServices(set
);
668 assert(services
!= NULL
);
670 n
= CFArrayGetCount(services
);
671 for (i
= 0; i
< n
; i
++) {
672 SCNetworkInterfaceRef interface
;
674 service
= CFArrayGetValueAtIndex(services
, i
);
675 interface
= SCNetworkServiceGetInterface(service
);
676 if (interface
!= NULL
) {
679 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
680 if (_SC_CFEqual(bsdName
, matchName
)) {
695 static CF_RETURNS_RETAINED CFStringRef
696 copyInterfaceUUID(CFStringRef bsdName
)
699 unsigned char sha1_bytes
[CC_SHA1_DIGEST_LENGTH
];
700 CFUUIDBytes uuid_bytes
;
703 char if_name
[IF_NAMESIZE
];
705 CFStringRef uuid_str
;
707 // start with interface name
708 bzero(&if_name
, sizeof(if_name
));
709 (void) _SC_cfstring_to_cstring(bsdName
,
712 kCFStringEncodingASCII
);
715 bzero(&bytes
, sizeof(bytes
));
720 CC_SHA1_Final(bytes
.sha1_bytes
, &ctx
);
722 // create UUID string
723 uuid
= CFUUIDCreateFromUUIDBytes(NULL
, bytes
.uuid_bytes
);
724 uuid_str
= CFUUIDCreateString(NULL
, uuid
);
732 updatePreConfiguredConfiguration(SCPreferencesRef prefs
)
737 Boolean updated
= FALSE
;
739 range
.length
= (preconfigured
!= NULL
) ? CFArrayGetCount(preconfigured
) : 0;
740 if (range
.length
== 0) {
741 // if no [preconfigured] interfaces
746 set
= SCNetworkSetCopyCurrent(prefs
);
751 * Check for (and remove) and network services associated with
752 * a pre-configured interface from the prefs.
754 services
= SCNetworkSetCopyServices(set
);
755 if (services
!= NULL
) {
758 n
= CFArrayGetCount(services
);
759 for (CFIndex i
= 0; i
< n
; i
++) {
761 SCNetworkInterfaceRef interface
;
762 SCNetworkServiceRef service
;
764 service
= CFArrayGetValueAtIndex(services
, i
);
766 interface
= SCNetworkServiceGetInterface(service
);
767 if (interface
== NULL
) {
772 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
773 if (bsdName
== NULL
) {
774 // if no interface name
778 if (!CFArrayContainsValue(preconfigured
, range
, bsdName
)) {
779 // if not preconfigured
783 // remove [preconfigured] network service from the prefs
784 SC_log(LOG_NOTICE
, "removing network service for %@", bsdName
);
785 SCNetworkServiceRemove(service
);
793 // commit the updated prefs ... but don't apply
794 ok
= SCPreferencesCommitChanges(prefs
);
796 if (SCError() != EROFS
) {
797 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s",
798 SCErrorString(SCError()));
804 * Now, add a new network service for each pre-configured interface
806 for (CFIndex i
= 0; i
< range
.length
; i
++) {
808 SCNetworkInterfaceRef interface
;
809 SCNetworkServiceRef service
;
811 bsdName
= CFArrayGetValueAtIndex(preconfigured
, i
);
812 interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, bsdName
, kIncludeNoVirtualInterfaces
);
813 if (interface
== NULL
) {
814 SC_log(LOG_ERR
, "could not create network interface for %@", bsdName
);
818 if (_SCNetworkInterfaceGetIOPath(interface
) == NULL
) {
819 // if no [real] interface exists
820 CFRelease(interface
);
824 ok
= SCNetworkSetEstablishDefaultInterfaceConfiguration(set
, interface
);
825 CFRelease(interface
);
827 SC_log(LOG_ERR
, "could not create network service for %@", bsdName
);
831 service
= copyInterfaceService(set
, bsdName
);
832 if (service
!= NULL
) {
833 CFStringRef serviceID
;
835 serviceID
= copyInterfaceUUID(bsdName
);
836 if (serviceID
!= NULL
) {
837 ok
= _SCNetworkServiceSetServiceID(service
, serviceID
);
838 CFRelease(serviceID
);
840 SC_log(LOG_ERR
, "_SCNetworkServiceSetServiceID() failed: %s",
841 SCErrorString(SCError()));
842 // ... and keep whatever random UUID was created for the service
845 SC_log(LOG_ERR
, "could not create serviceID for %@", bsdName
);
846 // ... and we'll use whatever random UUID was created for the service
849 SC_log(LOG_INFO
, "network service %@ added for %@",
850 SCNetworkServiceGetServiceID(service
),
855 SC_log(LOG_ERR
, "could not find network service for %@", bsdName
);
867 updateSCDynamicStore(SCPreferencesRef prefs
)
869 CFStringRef current
= NULL
;
870 CFDateRef date
= NULL
;
871 CFMutableDictionaryRef dict
= NULL
;
872 CFDictionaryRef global
= NULL
;
877 CFMutableArrayRef patterns
;
878 CFDictionaryRef set
= NULL
;
881 * initialize old preferences, new preferences, an array
882 * of keys which have not changed, and an array of keys
883 * to be removed (cleaned up).
886 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
887 pattern
= CFStringCreateWithFormat(NULL
,
890 kSCDynamicStoreDomainSetup
);
891 CFArrayAppendValue(patterns
, pattern
);
892 dict
= (CFMutableDictionaryRef
)SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
896 currentPrefs
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
899 currentPrefs
= CFDictionaryCreateMutable(NULL
,
901 &kCFTypeDictionaryKeyCallBacks
,
902 &kCFTypeDictionaryValueCallBacks
);
905 unchangedPrefsKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
907 i
= CFDictionaryGetCount(currentPrefs
);
909 const void **currentKeys
;
912 currentKeys
= CFAllocatorAllocate(NULL
, i
* sizeof(CFStringRef
), 0);
913 CFDictionaryGetKeysAndValues(currentPrefs
, currentKeys
, NULL
);
914 array
= CFArrayCreate(NULL
, currentKeys
, i
, &kCFTypeArrayCallBacks
);
915 removedPrefsKeys
= CFArrayCreateMutableCopy(NULL
, 0, array
);
917 CFAllocatorDeallocate(NULL
, currentKeys
);
919 removedPrefsKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
923 * The "newPrefs" dictionary will contain the new / updated
924 * configuration which will be written to the configuration cache.
926 newPrefs
= CFDictionaryCreateMutable(NULL
,
928 &kCFTypeDictionaryKeyCallBacks
,
929 &kCFTypeDictionaryValueCallBacks
);
932 * create status dictionary associated with current configuration
933 * information including:
934 * - current set "name" to cache
935 * - time stamp indicating when the cache preferences were
938 dict
= CFDictionaryCreateMutable(NULL
,
940 &kCFTypeDictionaryKeyCallBacks
,
941 &kCFTypeDictionaryValueCallBacks
);
942 date
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
947 keys
= SCPreferencesCopyKeyList(prefs
);
948 if ((keys
== NULL
) || (CFArrayGetCount(keys
) == 0)) {
949 SC_log(LOG_NOTICE
, "updateConfiguration(): no preferences");
954 * get "global" system preferences
956 global
= SCPreferencesGetValue(prefs
, kSCPrefSystem
);
958 /* if no global preferences are defined */
962 if (!isA_CFDictionary(global
)) {
963 SC_log(LOG_NOTICE
, "updateConfiguration(): %@ is not a dictionary",
968 /* flatten property list */
969 flatten(prefs
, CFSTR("/"), global
);
974 * get current set name
976 current
= SCPreferencesGetValue(prefs
, kSCPrefCurrentSet
);
978 /* if current set not defined */
982 if (!isA_CFString(current
)) {
983 SC_log(LOG_NOTICE
, "updateConfiguration(): %@ is not a string",
991 set
= SCPreferencesPathGetValue(prefs
, current
);
993 /* if error with path */
994 SC_log(LOG_NOTICE
, "%@ value (%@) not valid",
1000 if (!isA_CFDictionary(set
)) {
1001 SC_log(LOG_NOTICE
, "updateConfiguration(): %@ is not a dictionary",
1006 /* flatten property list */
1007 flatten(prefs
, CFSTR("/"), set
);
1009 CFDictionarySetValue(dict
, kSCDynamicStorePropSetupCurrentSet
, current
);
1013 /* add last updated time stamp */
1014 CFDictionarySetValue(dict
, kSCDynamicStorePropSetupLastUpdated
, date
);
1016 /* add Setup: key */
1017 CFDictionarySetValue(newPrefs
, kSCDynamicStoreDomainSetup
, dict
);
1019 /* compare current and new preferences */
1020 CFDictionaryApplyFunction(newPrefs
, updateCache
, NULL
);
1022 /* remove those keys which have not changed from the update */
1023 n
= CFArrayGetCount(unchangedPrefsKeys
);
1024 for (i
= 0; i
< n
; i
++) {
1027 key
= CFArrayGetValueAtIndex(unchangedPrefsKeys
, i
);
1028 CFDictionaryRemoveValue(newPrefs
, key
);
1031 /* Update the dynamic store */
1033 if (!SCDynamicStoreSetMultiple(store
, newPrefs
, removedPrefsKeys
, NULL
)) {
1034 SC_log(LOG_NOTICE
, "SCDynamicStoreSetMultiple() failed: %s", SCErrorString(SCError()));
1037 SC_log(LOG_DEBUG
, "SCDynamicStore\nset: %@\nremove: %@",
1042 CFRelease(currentPrefs
);
1043 CFRelease(newPrefs
);
1044 CFRelease(unchangedPrefsKeys
);
1045 CFRelease(removedPrefsKeys
);
1046 if (dict
) CFRelease(dict
);
1047 if (date
) CFRelease(date
);
1048 if (keys
) CFRelease(keys
);
1054 updateConfiguration(SCPreferencesRef prefs
,
1055 SCPreferencesNotification notificationType
,
1058 os_activity_t activity
;
1060 activity
= os_activity_create("processing [SC] preferences.plist changes",
1061 OS_ACTIVITY_CURRENT
,
1062 OS_ACTIVITY_FLAG_DEFAULT
);
1063 os_activity_scope(activity
);
1065 #if !TARGET_OS_IPHONE
1066 if ((notificationType
& kSCPreferencesNotificationCommit
) == kSCPreferencesNotificationCommit
) {
1067 SCNetworkSetRef current
;
1069 current
= SCNetworkSetCopyCurrent(prefs
);
1070 if (current
!= NULL
) {
1071 /* network configuration available, disable template creation */
1072 haveConfiguration
= TRUE
;
1076 #endif /* !TARGET_OS_IPHONE */
1078 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
1082 SC_log(LOG_INFO
, "updating configuration");
1084 /* add any [Apple] pre-configured network services */
1085 updatePreConfiguredConfiguration(prefs
);
1087 /* update SCDynamicStore (Setup:) */
1088 updateSCDynamicStore(prefs
);
1090 /* finished with current prefs, wait for changes */
1092 SCPreferencesSynchronize(prefs
);
1097 os_release(activity
);
1105 prime_PreferencesMonitor()
1107 SC_log(LOG_DEBUG
, "prime() called");
1109 /* load the initial configuration from the database */
1110 updateConfiguration(prefs
, kSCPreferencesNotificationApply
, (void *)store
);
1118 load_PreferencesMonitor(CFBundleRef bundle
, Boolean bundleVerbose
)
1120 SC_log(LOG_DEBUG
, "load() called");
1121 SC_log(LOG_DEBUG
, " bundle ID = %@", CFBundleGetIdentifier(bundle
));
1123 /* open a SCDynamicStore session to allow cache updates */
1124 store
= SCDynamicStoreCreate(NULL
,
1125 CFSTR("PreferencesMonitor.bundle"),
1128 if (store
== NULL
) {
1129 SC_log(LOG_NOTICE
, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
1133 /* open a SCPreferences session */
1135 prefs
= SCPreferencesCreate(NULL
, CFSTR("PreferencesMonitor.bundle"), NULL
);
1137 prefs
= SCPreferencesCreate(NULL
, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist"));
1139 if (prefs
!= NULL
) {
1140 Boolean need_update
= FALSE
;
1141 CFStringRef new_model
;
1143 new_model
= _SC_hw_model(FALSE
);
1145 /* Need to regenerate the new configuration for new model */
1146 if (new_model
!= NULL
) {
1147 CFStringRef old_model
;
1149 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
1150 if (old_model
!= NULL
&& !_SC_CFEqual(old_model
, new_model
)) {
1153 restorePrefs
= previousConfigurationAvailable();
1158 SCNetworkSetRef current
;
1160 current
= SCNetworkSetCopyCurrent(prefs
);
1161 if (current
!= NULL
) {
1162 /* network configuration available, disable template creation */
1163 haveConfiguration
= TRUE
;
1168 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
1173 * register for change notifications.
1175 if (!SCPreferencesSetCallback(prefs
, updateConfiguration
, NULL
)) {
1176 SC_log(LOG_NOTICE
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
1180 if (!SCPreferencesScheduleWithRunLoop(prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
1181 SC_log(LOG_NOTICE
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
1186 * watch InterfaceNamer and KernelEventMonitor changes to know when
1187 * the IORegistry has quiesced (to create the initial configuration
1188 * template), to track any pre-configured interfaces, and to ensure
1189 * that we create a network service for any active interfaces.
1191 watchSCDynamicStore();
1192 storeCallback(store
, NULL
, NULL
);
1198 if (store
!= NULL
) CFRelease(store
);
1199 if (prefs
!= NULL
) CFRelease(prefs
);
1200 haveConfiguration
= TRUE
;
1208 main(int argc
, char **argv
)
1211 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1213 load_PreferencesMonitor(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);
1214 prime_PreferencesMonitor();