2 * Copyright (c) 2000-2008, 2010, 2012-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 * 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>
39 #include <sys/types.h>
42 #define SC_LOG_HANDLE __log_PreferencesMonitor
43 #define SC_LOG_HANDLE_TYPE static
44 #include <SystemConfiguration/SystemConfiguration.h>
45 #include <SystemConfiguration/SCPrivate.h>
46 #include <SystemConfiguration/SCValidation.h>
47 #include "SCNetworkConfigurationInternal.h"
48 #include "plugin_shared.h"
52 static SCPreferencesRef prefs
= NULL
;
53 static SCDynamicStoreRef store
= NULL
;
55 /* InterfaceNamer[.plugin] monitoring globals */
56 static CFMutableArrayRef excluded_interfaces
= NULL
; // of SCNetworkInterfaceRef
57 static CFMutableArrayRef excluded_names
= NULL
; // of CFStringRef (BSD name)
58 static Boolean haveConfiguration
= FALSE
;
59 static CFStringRef namerKey
= NULL
;
60 static CFMutableArrayRef preconfigured_interfaces
= NULL
; // of SCNetworkInterfaceRef
61 static CFMutableArrayRef preconfigured_names
= NULL
; // of CFStringRef (BSD name)
63 /* KernelEventMonitor[.plugin] monitoring globals */
64 static CFStringRef interfacesKey
= NULL
;
66 /* SCDynamicStore (Setup:) */
67 static CFMutableDictionaryRef currentPrefs
; /* current prefs */
68 static CFMutableDictionaryRef newPrefs
; /* new prefs */
69 static CFMutableArrayRef unchangedPrefsKeys
; /* new prefs keys which match current */
70 static CFMutableArrayRef removedPrefsKeys
; /* old prefs keys to be removed */
72 static Boolean rofs
= FALSE
;
74 #define MY_PLUGIN_NAME "PreferencesMonitor"
75 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
79 updateConfiguration(SCPreferencesRef prefs
,
80 SCPreferencesNotification notificationType
,
85 __log_PreferencesMonitor(void)
87 static os_log_t log
= NULL
;
90 log
= os_log_create("com.apple.SystemConfiguration", "PreferencesMonitor");
98 savePastConfiguration(CFStringRef old_model
)
100 CFDictionaryRef system
;
102 // save "/System" (e.g. host names)
103 system
= SCPreferencesGetValue(prefs
, kSCPrefSystem
);
104 if (system
!= NULL
) {
108 // save the [previous devices] configuration
109 __SCNetworkConfigurationSaveModel(prefs
, old_model
);
111 if (system
!= NULL
) {
112 // and retain "/System" (e.g. host names)
113 SCPreferencesSetValue(prefs
, kSCPrefSystem
, system
);
122 establishNewPreferences()
124 SCNetworkSetRef current
= NULL
;
125 CFStringRef new_model
;
127 CFStringRef old_model
;
128 int sc_status
= kSCStatusFailed
;
129 SCNetworkSetRef set
= NULL
;
130 Boolean updated
= FALSE
;
133 ok
= SCPreferencesLock(prefs
, TRUE
);
138 sc_status
= SCError();
139 if (sc_status
== kSCStatusStale
) {
140 SCPreferencesSynchronize(prefs
);
142 SC_log(LOG_NOTICE
, "Could not acquire network configuration lock: %s",
143 SCErrorString(sc_status
));
148 // check if we need to regenerate the configuration for a new model
149 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
150 new_model
= _SC_hw_model(FALSE
);
151 if ((old_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
152 SC_log(LOG_NOTICE
, "Hardware model changed\n"
153 " created on \"%@\"\n"
158 // save (and clean) the configuration that was created for "other" hardware
159 savePastConfiguration(old_model
);
162 current
= SCNetworkSetCopyCurrent(prefs
);
163 if (current
!= NULL
) {
168 set
= _SCNetworkSetCreateDefault(prefs
);
171 sc_status
= SCError();
176 ok
= SCNetworkSetEstablishDefaultConfiguration(set
);
178 sc_status
= SCError();
185 ok
= SCPreferencesCommitChanges(prefs
);
187 SC_log(LOG_NOTICE
, "New network configuration saved");
190 sc_status
= SCError();
191 if (sc_status
== EROFS
) {
192 /* a read-only fileysstem is OK */
195 /* ... but we don't want to synchronize */
200 /* apply (committed or temporary/read-only) changes */
201 (void) SCPreferencesApplyChanges(prefs
);
202 } else if ((current
== NULL
) && (set
!= NULL
)) {
203 (void) SCNetworkSetRemove(set
);
207 if (sc_status
== kSCStatusOK
) {
208 SC_log(LOG_NOTICE
, "Network configuration not updated");
210 SC_log(LOG_NOTICE
, "Could not establish network configuration: %s",
211 SCErrorString(sc_status
));
215 (void)SCPreferencesUnlock(prefs
);
216 if (set
!= NULL
) CFRelease(set
);
222 watchSCDynamicStore()
224 CFMutableArrayRef keys
;
226 CFRunLoopSourceRef rls
;
229 * watch for KernelEventMonitor[.bundle] changes (the list of
230 * active network interfaces)
232 interfacesKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
233 kSCDynamicStoreDomainState
);
236 * watch for InterfaceNamer[.bundle] changes (quiet, timeout,
237 * and the list of pre-configured interfaces)
239 namerKey
= SCDynamicStoreKeyCreate(NULL
,
240 CFSTR("%@" "InterfaceNamer"),
241 kSCDynamicStoreDomainPlugin
);
243 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
245 SC_log(LOG_NOTICE
, "SCDynamicStoreCreateRunLoopSource() failed: %s", SCErrorString(SCError()));
246 haveConfiguration
= TRUE
;
249 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
252 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
253 CFArrayAppendValue(keys
, interfacesKey
);
254 CFArrayAppendValue(keys
, namerKey
);
255 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
258 SC_log(LOG_NOTICE
, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError()));
259 haveConfiguration
= TRUE
;
267 findInterfaces(CFArrayRef interfaces
, CFMutableArrayRef
*matched_interfaces
, CFMutableArrayRef
*matched_names
)
271 Boolean updated
= FALSE
;
274 if (*matched_interfaces
!= NULL
) {
275 CFRelease(*matched_interfaces
);
276 *matched_interfaces
= NULL
;
278 if (*matched_names
!= NULL
) {
279 nx
= CFArrayGetCount(*matched_names
);
280 CFRelease(*matched_names
);
281 *matched_names
= NULL
;
284 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
285 for (CFIndex i
= 0; i
< n
; i
++) {
286 CFStringRef bsdName
= CFArrayGetValueAtIndex(interfaces
, i
);
287 SCNetworkInterfaceRef interface
;
289 for (int retry
= 0; retry
< 10; retry
++) {
291 // add short delay (before retry)
292 usleep(20 * 1000); // 20ms
295 interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, bsdName
, kIncludeNoVirtualInterfaces
);
296 if (interface
== NULL
) {
297 SC_log(LOG_ERR
, "could not create network interface for %@", bsdName
);
298 } else if (_SCNetworkInterfaceGetIOPath(interface
) == NULL
) {
299 SC_log(LOG_ERR
, "could not get IOPath for %@", bsdName
);
300 CFRelease(interface
);
304 if (interface
== NULL
) {
305 // if SCNetworkInterface not [currently] available
309 // keep track of the interface name (quicker than having to iterate the list
310 // of SCNetworkInterfaces, extract the name, and compare).
311 if (*matched_names
== NULL
) {
312 *matched_names
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
314 CFArrayAppendValue(*matched_names
, bsdName
);
316 if (*matched_interfaces
== NULL
) {
317 *matched_interfaces
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
319 CFArrayAppendValue(*matched_interfaces
, interface
);
320 CFRelease(interface
);
327 // check if all interfaces were detached
328 n
= (*matched_names
!= NULL
) ? CFArrayGetCount(*matched_names
) : 0;
329 if ((nx
> 0) && (n
== 0)) {
338 storeCallback(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
)
341 CFDictionaryRef dict
;
342 Boolean quiet
= FALSE
;
343 Boolean timeout
= FALSE
;
344 Boolean updated
= FALSE
;
347 * Capture/process InterfaceNamer[.bundle] info
348 * 1. check if IORegistry "quiet", "timeout"
349 * 2. update list of excluded interfaces (e.g. those requiring that
350 * the attached host be trusted)
351 * 3. update list of named pre-configured interfaces
353 dict
= SCDynamicStoreCopyValue(store
, namerKey
);
355 if (isA_CFDictionary(dict
)) {
357 CFArrayRef preconfigured
;
359 if (CFDictionaryContainsKey(dict
, kInterfaceNamerKey_Quiet
)) {
362 if (CFDictionaryContainsKey(dict
, kInterfaceNamerKey_Timeout
)) {
366 excluded
= CFDictionaryGetValue(dict
, kInterfaceNamerKey_ExcludedInterfaces
);
367 excluded
= isA_CFArray(excluded
);
368 if (!_SC_CFEqual(excluded
, excluded_names
)) {
369 Boolean excluded_updated
;
371 excluded_updated
= findInterfaces(excluded
, &excluded_interfaces
, &excluded_names
);
372 if (excluded_updated
) {
373 CFStringRef interfaces
= CFSTR("<empty>");
375 // report [updated] pre-configured interfaces
376 if (excluded_names
!= NULL
) {
377 interfaces
= CFStringCreateByCombiningStrings(NULL
, excluded_names
, CFSTR(","));
379 CFRetain(interfaces
);
381 SC_log(LOG_INFO
, "excluded interface list changed: %@", interfaces
);
382 CFRelease(interfaces
);
388 preconfigured
= CFDictionaryGetValue(dict
, kInterfaceNamerKey_PreConfiguredInterfaces
);
389 preconfigured
= isA_CFArray(preconfigured
);
390 if (!_SC_CFEqual(preconfigured
, preconfigured_names
)) {
391 Boolean preconfigured_updated
;
393 preconfigured_updated
= findInterfaces(preconfigured
, &preconfigured_interfaces
, &preconfigured_names
);
394 if (preconfigured_updated
) {
395 CFStringRef interfaces
= CFSTR("<empty>");
397 // report [updated] pre-configured interfaces
398 if (preconfigured_names
!= NULL
) {
399 interfaces
= CFStringCreateByCombiningStrings(NULL
, preconfigured_names
, CFSTR(","));
401 CFRetain(interfaces
);
403 SC_log(LOG_INFO
, "pre-configured interface list changed: %@", interfaces
);
404 CFRelease(interfaces
);
414 if (!haveConfiguration
&& (quiet
|| timeout
)) {
415 static int logged
= 0;
418 #if !TARGET_OS_IPHONE
420 #endif /* !TARGET_OS_IPHONE */
422 haveConfiguration
= TRUE
;
425 (void) establishNewPreferences();
427 if (timeout
&& (logged
++ == 0)) {
428 SC_log(LOG_ERR
, "Network configuration creation timed out waiting for IORegistry");
432 if (updated
&& (changedKeys
!= NULL
)) {
433 // if pre-configured interface list changed
434 updateConfiguration(prefs
, kSCPreferencesNotificationApply
, (void *)store
);
442 updateCache(const void *key
, const void *value
, void *context
)
444 #pragma unused(context)
445 CFStringRef configKey
= (CFStringRef
)key
;
446 CFPropertyListRef configData
= (CFPropertyListRef
)value
;
447 CFPropertyListRef cacheData
;
450 cacheData
= CFDictionaryGetValue(currentPrefs
, configKey
);
453 if (CFEqual(cacheData
, configData
)) {
455 * if the old & new property list values have
456 * not changed then we don't need to update
459 CFArrayAppendValue(unchangedPrefsKeys
, configKey
);
463 /* in any case, this key should not be removed */
464 i
= CFArrayGetFirstIndexOfValue(removedPrefsKeys
,
465 CFRangeMake(0, CFArrayGetCount(removedPrefsKeys
)),
467 if (i
!= kCFNotFound
) {
468 CFArrayRemoveValueAtIndex(removedPrefsKeys
, i
);
476 flatten(SCPreferencesRef prefs
,
478 CFDictionaryRef base
)
480 CFDictionaryRef subset
;
482 CFMutableDictionaryRef myDict
;
489 if (!CFDictionaryGetValueIfPresent(base
, kSCResvLink
, (const void **)&link
)) {
490 /* if this dictionary is not linked */
493 /* if __LINK__ key is present */
494 subset
= SCPreferencesPathGetValue(prefs
, link
);
496 /* if error with link */
497 SC_log(LOG_NOTICE
, "SCPreferencesPathGetValue(,%@,) failed: %s",
499 SCErrorString(SCError()));
504 if (CFDictionaryContainsKey(subset
, kSCResvInactive
)) {
505 /* if __INACTIVE__ key is present */
509 myKey
= CFStringCreateWithFormat(NULL
,
512 kSCDynamicStoreDomainSetup
,
515 myDict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(newPrefs
, myKey
);
517 myDict
= CFDictionaryCreateMutableCopy(NULL
,
519 (CFDictionaryRef
)myDict
);
521 myDict
= CFDictionaryCreateMutable(NULL
,
523 &kCFTypeDictionaryKeyCallBacks
,
524 &kCFTypeDictionaryValueCallBacks
);
527 nKeys
= CFDictionaryGetCount(subset
);
529 keys
= CFAllocatorAllocate(NULL
, nKeys
* sizeof(CFStringRef
) , 0);
530 vals
= CFAllocatorAllocate(NULL
, nKeys
* sizeof(CFPropertyListRef
), 0);
531 CFDictionaryGetKeysAndValues(subset
, keys
, vals
);
532 for (i
= 0; i
< nKeys
; i
++) {
533 if (CFGetTypeID((CFTypeRef
)vals
[i
]) != CFDictionaryGetTypeID()) {
534 /* add this key/value to the current dictionary */
535 CFDictionarySetValue(myDict
, keys
[i
], vals
[i
]);
539 /* flatten [sub]dictionaries */
540 subKey
= CFStringCreateWithFormat(NULL
,
544 CFEqual(key
, CFSTR("/")) ? "" : "/",
546 flatten(prefs
, subKey
, vals
[i
]);
550 CFAllocatorDeallocate(NULL
, keys
);
551 CFAllocatorDeallocate(NULL
, vals
);
554 if (CFDictionaryGetCount(myDict
) > 0) {
555 /* add this dictionary to the new preferences */
556 CFDictionarySetValue(newPrefs
, myKey
, myDict
);
567 excludeConfigurations(SCPreferencesRef prefs
)
574 range
= CFRangeMake(0,
575 (excluded_names
!= NULL
) ? CFArrayGetCount(excluded_names
) : 0);
576 if (range
.length
== 0) {
577 // if no [excluded] interfaces
581 set
= SCNetworkSetCopyCurrent(prefs
);
588 * Check for (and remove) any network services associated with
589 * an excluded interface from the prefs.
591 services
= SCNetworkSetCopyServices(set
);
592 if (services
!= NULL
) {
595 n
= CFArrayGetCount(services
);
596 for (CFIndex i
= 0; i
< n
; i
++) {
598 SCNetworkInterfaceRef interface
;
599 SCNetworkServiceRef service
;
601 service
= CFArrayGetValueAtIndex(services
, i
);
603 interface
= SCNetworkServiceGetInterface(service
);
604 if (interface
== NULL
) {
609 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
610 if (bsdName
== NULL
) {
611 // if no interface name
615 if (!CFArrayContainsValue(excluded_names
, range
, bsdName
)) {
620 // remove [excluded] network service from the prefs
621 SC_log(LOG_NOTICE
, "excluding network service for %@", bsdName
);
622 ok
= SCNetworkSetRemoveService(set
, service
);
624 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() failed: %s",
625 SCErrorString(SCError()));
638 updatePreConfiguredConfiguration(SCPreferencesRef prefs
)
644 Boolean updated
= FALSE
;
646 range
= CFRangeMake(0,
647 (preconfigured_names
!= NULL
) ? CFArrayGetCount(preconfigured_names
) : 0);
648 if (range
.length
== 0) {
649 // if no [pre-configured] interfaces
653 set
= SCNetworkSetCopyCurrent(prefs
);
660 * Check for (and remove) any network services associated with
661 * a pre-configured interface from the prefs.
663 services
= SCNetworkServiceCopyAll(prefs
);
664 if (services
!= NULL
) {
667 n
= CFArrayGetCount(services
);
668 for (CFIndex i
= 0; i
< n
; i
++) {
670 SCNetworkInterfaceRef interface
;
671 SCNetworkServiceRef service
;
673 service
= CFArrayGetValueAtIndex(services
, i
);
675 interface
= SCNetworkServiceGetInterface(service
);
676 if (interface
== NULL
) {
681 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
682 if (bsdName
== NULL
) {
683 // if no interface name
687 if (!CFArrayContainsValue(preconfigured_names
, range
, bsdName
)) {
688 // if not preconfigured
692 // remove [preconfigured] network service from the prefs
693 SC_log(LOG_NOTICE
, "removing network service for %@", bsdName
);
694 ok
= SCNetworkServiceRemove(service
);
696 SC_log(LOG_ERR
, "SCNetworkServiceRemove() failed: %s",
697 SCErrorString(SCError()));
706 // commit the updated prefs ... but don't apply
707 ok
= SCPreferencesCommitChanges(prefs
);
709 if (SCError() != EROFS
) {
710 SC_log(LOG_ERR
, "SCPreferencesCommitChanges() failed: %s",
711 SCErrorString(SCError()));
717 * Now, add a new network service for each pre-configured interface
719 for (CFIndex i
= 0; i
< range
.length
; i
++) {
721 SCNetworkInterfaceRef interface
= CFArrayGetValueAtIndex(preconfigured_interfaces
, i
);
722 SCNetworkServiceRef service
;
724 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
726 // create network service
727 service
= _SCNetworkServiceCreatePreconfigured(prefs
, interface
);
728 if (service
== NULL
) {
732 // add network service to the current set
733 ok
= SCNetworkSetAddService(set
, service
);
735 SC_log(LOG_ERR
, "could not add service for \"%@\": %s",
737 SCErrorString(SCError()));
738 SCNetworkServiceRemove(service
);
743 SC_log(LOG_INFO
, "network service %@ added for \"%@\"",
744 SCNetworkServiceGetServiceID(service
),
756 updateSCDynamicStore(SCPreferencesRef prefs
)
758 CFStringRef current
= NULL
;
759 CFDateRef date
= NULL
;
760 CFMutableDictionaryRef dict
= NULL
;
761 CFDictionaryRef global
= NULL
;
766 CFMutableArrayRef patterns
;
767 CFDictionaryRef set
= NULL
;
770 * initialize old preferences, new preferences, an array
771 * of keys which have not changed, and an array of keys
772 * to be removed (cleaned up).
775 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
776 pattern
= CFStringCreateWithFormat(NULL
,
779 kSCDynamicStoreDomainSetup
);
780 CFArrayAppendValue(patterns
, pattern
);
781 dict
= (CFMutableDictionaryRef
)SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
785 currentPrefs
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
788 currentPrefs
= CFDictionaryCreateMutable(NULL
,
790 &kCFTypeDictionaryKeyCallBacks
,
791 &kCFTypeDictionaryValueCallBacks
);
794 unchangedPrefsKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
796 i
= CFDictionaryGetCount(currentPrefs
);
798 const void **currentKeys
;
801 currentKeys
= CFAllocatorAllocate(NULL
, i
* sizeof(CFStringRef
), 0);
802 CFDictionaryGetKeysAndValues(currentPrefs
, currentKeys
, NULL
);
803 array
= CFArrayCreate(NULL
, currentKeys
, i
, &kCFTypeArrayCallBacks
);
804 removedPrefsKeys
= CFArrayCreateMutableCopy(NULL
, 0, array
);
806 CFAllocatorDeallocate(NULL
, currentKeys
);
808 removedPrefsKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
812 * The "newPrefs" dictionary will contain the new / updated
813 * configuration which will be written to the configuration cache.
815 newPrefs
= CFDictionaryCreateMutable(NULL
,
817 &kCFTypeDictionaryKeyCallBacks
,
818 &kCFTypeDictionaryValueCallBacks
);
821 * create status dictionary associated with current configuration
822 * information including:
823 * - current set "name" to cache
824 * - time stamp indicating when the cache preferences were
827 dict
= CFDictionaryCreateMutable(NULL
,
829 &kCFTypeDictionaryKeyCallBacks
,
830 &kCFTypeDictionaryValueCallBacks
);
831 date
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
836 keys
= SCPreferencesCopyKeyList(prefs
);
837 if ((keys
== NULL
) || (CFArrayGetCount(keys
) == 0)) {
838 SC_log(LOG_NOTICE
, "updateConfiguration(): no preferences");
843 * get "global" system preferences
845 global
= SCPreferencesGetValue(prefs
, kSCPrefSystem
);
847 /* if no global preferences are defined */
851 if (!isA_CFDictionary(global
)) {
852 SC_log(LOG_NOTICE
, "updateConfiguration(): %@ is not a dictionary",
857 /* flatten property list */
858 flatten(prefs
, CFSTR("/"), global
);
863 * get current set name
865 current
= SCPreferencesGetValue(prefs
, kSCPrefCurrentSet
);
867 /* if current set not defined */
871 if (!isA_CFString(current
)) {
872 SC_log(LOG_NOTICE
, "updateConfiguration(): %@ is not a string",
880 set
= SCPreferencesPathGetValue(prefs
, current
);
882 /* if error with path */
883 SC_log(LOG_NOTICE
, "%@ value (%@) not valid",
889 if (!isA_CFDictionary(set
)) {
890 SC_log(LOG_NOTICE
, "updateConfiguration(): %@ is not a dictionary",
895 /* flatten property list */
896 flatten(prefs
, CFSTR("/"), set
);
898 CFDictionarySetValue(dict
, kSCDynamicStorePropSetupCurrentSet
, current
);
902 /* add last updated time stamp */
903 CFDictionarySetValue(dict
, kSCDynamicStorePropSetupLastUpdated
, date
);
906 CFDictionarySetValue(newPrefs
, kSCDynamicStoreDomainSetup
, dict
);
908 /* compare current and new preferences */
909 CFDictionaryApplyFunction(newPrefs
, updateCache
, NULL
);
911 /* remove those keys which have not changed from the update */
912 n
= CFArrayGetCount(unchangedPrefsKeys
);
913 for (i
= 0; i
< n
; i
++) {
916 key
= CFArrayGetValueAtIndex(unchangedPrefsKeys
, i
);
917 CFDictionaryRemoveValue(newPrefs
, key
);
920 /* Update the dynamic store */
922 if (!SCDynamicStoreSetMultiple(store
, newPrefs
, removedPrefsKeys
, NULL
)) {
923 SC_log(LOG_NOTICE
, "SCDynamicStoreSetMultiple() failed: %s", SCErrorString(SCError()));
926 SC_log(LOG_DEBUG
, "SCDynamicStore\nset: %@\nremove: %@",
931 CFRelease(currentPrefs
);
933 CFRelease(unchangedPrefsKeys
);
934 CFRelease(removedPrefsKeys
);
935 if (dict
) CFRelease(dict
);
936 if (date
) CFRelease(date
);
937 if (keys
) CFRelease(keys
);
943 updateConfiguration(SCPreferencesRef prefs
,
944 SCPreferencesNotification notificationType
,
948 #if !TARGET_OS_IPHONE
949 if ((notificationType
& kSCPreferencesNotificationCommit
) == kSCPreferencesNotificationCommit
) {
950 SCNetworkSetRef current
;
952 current
= SCNetworkSetCopyCurrent(prefs
);
953 if (current
!= NULL
) {
954 /* network configuration available, disable template creation */
955 haveConfiguration
= TRUE
;
959 #endif /* !TARGET_OS_IPHONE */
961 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
965 SC_log(LOG_INFO
, "updating configuration");
967 /* add any [Apple] pre-configured network services */
968 updatePreConfiguredConfiguration(prefs
);
970 /* remove any excluded network services */
971 excludeConfigurations(prefs
);
973 /* update SCDynamicStore (Setup:) */
974 updateSCDynamicStore(prefs
);
976 /* finished with current prefs, wait for changes */
978 SCPreferencesSynchronize(prefs
);
989 prime_PreferencesMonitor()
991 SC_log(LOG_DEBUG
, "prime() called");
993 /* load the initial configuration from the database */
994 updateConfiguration(prefs
, kSCPreferencesNotificationApply
, (void *)store
);
1001 #define PREFERENCES_MONITOR_PLIST NULL
1003 #define PREFERENCES_MONITOR_PLIST CFSTR("/tmp/preferences.plist")
1009 load_PreferencesMonitor(CFBundleRef bundle
, Boolean bundleVerbose
)
1011 #pragma unused(bundle)
1012 #pragma unused(bundleVerbose)
1013 SC_log(LOG_DEBUG
, "load() called");
1014 SC_log(LOG_DEBUG
, " bundle ID = %@", CFBundleGetIdentifier(bundle
));
1016 /* open a SCDynamicStore session to allow cache updates */
1017 store
= SCDynamicStoreCreate(NULL
,
1018 CFSTR("PreferencesMonitor.bundle"),
1021 if (store
== NULL
) {
1022 SC_log(LOG_NOTICE
, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
1026 /* open a SCPreferences session */
1027 prefs
= SCPreferencesCreateWithOptions(NULL
,
1029 PREFERENCES_MONITOR_PLIST
,
1030 NULL
, // authorization
1032 if (prefs
!= NULL
) {
1033 Boolean need_update
= FALSE
;
1034 CFStringRef new_model
;
1035 CFStringRef old_model
;
1037 // check if we need to update the configuration
1038 __SCNetworkConfigurationUpgrade(&prefs
, NULL
, TRUE
);
1040 // check if we need to regenerate the configuration for a new model
1041 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
1042 new_model
= _SC_hw_model(FALSE
);
1043 if ((old_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
1044 SC_log(LOG_NOTICE
, "Hardware model changed\n"
1045 " created on \"%@\"\n"
1050 // save (and clean) the configuration that was created for "other" hardware
1051 savePastConfiguration(old_model
);
1053 // ... and we'll update the configuration later (when the IORegistry quiesces)
1058 SCNetworkSetRef current
;
1060 current
= SCNetworkSetCopyCurrent(prefs
);
1061 if (current
!= NULL
) {
1062 /* network configuration available, disable template creation */
1063 haveConfiguration
= TRUE
;
1068 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
1073 * register for change notifications.
1075 if (!SCPreferencesSetCallback(prefs
, updateConfiguration
, NULL
)) {
1076 SC_log(LOG_NOTICE
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
1080 if (!SCPreferencesScheduleWithRunLoop(prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
1081 SC_log(LOG_NOTICE
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
1086 * watch InterfaceNamer and KernelEventMonitor changes to know when
1087 * the IORegistry has quiesced (to create the initial configuration
1088 * template), to track any pre-configured interfaces, and to ensure
1089 * that we create a network service for any active interfaces.
1091 watchSCDynamicStore();
1092 storeCallback(store
, NULL
, NULL
);
1098 if (store
!= NULL
) CFRelease(store
);
1099 if (prefs
!= NULL
) CFRelease(prefs
);
1100 haveConfiguration
= TRUE
;
1108 main(int argc
, char **argv
)
1111 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1113 load_PreferencesMonitor(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);
1114 prime_PreferencesMonitor();