2 * Copyright (c) 2000-2008, 2010, 2012-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 * 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 #define SC_LOG_HANDLE_TYPE static
48 #include <SystemConfiguration/SystemConfiguration.h>
49 #include <SystemConfiguration/SCPrivate.h>
50 #include <SystemConfiguration/SCValidation.h>
51 #include "plugin_shared.h"
54 #include <CommonCrypto/CommonDigest.h>
58 static SCPreferencesRef prefs
= NULL
;
59 static SCDynamicStoreRef store
= NULL
;
61 /* InterfaceNamer[.plugin] monitoring globals */
62 static CFMutableArrayRef excluded_interfaces
= NULL
; // of SCNetworkInterfaceRef
63 static CFMutableArrayRef excluded_names
= NULL
; // of CFStringRef (BSD name)
64 Boolean haveConfiguration
= FALSE
;
65 static CFStringRef namerKey
= NULL
;
66 static CFMutableArrayRef preconfigured_interfaces
= NULL
; // of SCNetworkInterfaceRef
67 static CFMutableArrayRef preconfigured_names
= NULL
; // of CFStringRef (BSD name)
69 /* KernelEventMonitor[.plugin] monitoring globals */
70 static CFStringRef interfacesKey
= NULL
;
72 /* SCDynamicStore (Setup:) */
73 static CFMutableDictionaryRef currentPrefs
; /* current prefs */
74 static CFMutableDictionaryRef newPrefs
; /* new prefs */
75 static CFMutableArrayRef unchangedPrefsKeys
; /* new prefs keys which match current */
76 static CFMutableArrayRef removedPrefsKeys
; /* old prefs keys to be removed */
78 static Boolean rofs
= FALSE
;
79 static Boolean restorePrefs
= FALSE
;
81 #define MY_PLUGIN_NAME "PreferencesMonitor"
82 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
86 updateConfiguration(SCPreferencesRef prefs
,
87 SCPreferencesNotification notificationType
,
92 __log_PreferencesMonitor(void)
94 static os_log_t log
= NULL
;
97 log
= os_log_create("com.apple.SystemConfiguration", "PreferencesMonitor");
108 CFStringRef currentModel
= NULL
;
109 CFMutableStringRef modelPrefixStr
= NULL
;
110 CFArrayRef keyList
= NULL
;
111 CFIndex keyListCount
;
113 Boolean modified
= FALSE
;
114 int sc_status
= kSCStatusFailed
;
117 ok
= SCPreferencesLock(prefs
, TRUE
);
122 sc_status
= SCError();
123 if (sc_status
== kSCStatusStale
) {
124 SCPreferencesSynchronize(prefs
);
126 SC_log(LOG_NOTICE
, "Could not acquire network configuration lock: %s",
127 SCErrorString(sc_status
));
132 keyList
= SCPreferencesCopyKeyList(prefs
);
133 if (keyList
== NULL
) {
137 currentModel
= _SC_hw_model(FALSE
);
138 if (currentModel
== NULL
) {
142 /* Create "model:" string for prefix-check */
143 modelPrefixStr
= CFStringCreateMutableCopy(NULL
, 0, currentModel
);
144 CFStringAppend(modelPrefixStr
, CFSTR(":"));
146 keyListCount
= CFArrayGetCount(keyList
);
147 for (idx
= 0; idx
< keyListCount
; idx
++) {
148 CFStringRef existingKey
= CFArrayGetValueAtIndex(keyList
, idx
);
150 CFArrayRef splitKey
= NULL
;
151 CFPropertyListRef value
;
153 if (isA_CFString(existingKey
) == NULL
) {
157 if (!CFStringHasPrefix(existingKey
, modelPrefixStr
)) {
161 splitKey
= CFStringCreateArrayBySeparatingStrings(NULL
, existingKey
, CFSTR(":"));
162 key
= CFArrayGetValueAtIndex(splitKey
, 1);
163 value
= SCPreferencesGetValue(prefs
, existingKey
);
164 SCPreferencesSetValue(prefs
, key
, value
);
165 SCPreferencesRemoveValue(prefs
, existingKey
);
171 SCPreferencesRef ni_prefs
= NULL
;
172 ni_prefs
= SCPreferencesCreate(NULL
, MY_PLUGIN_ID
, CFSTR("NetworkInterfaces.plist"));
173 if (ni_prefs
== NULL
) {
177 ok
= _SCNetworkConfigurationCheckValidityWithPreferences(prefs
, ni_prefs
, NULL
);
180 //Commit the changes only if prefs files valid
182 if (!SCPreferencesCommitChanges(prefs
)) {
183 if (SCError() != EROFS
) {
184 SC_log(LOG_NOTICE
, "SCPreferencesCommitChanges() failed: %s",
185 SCErrorString(SCError()));
191 (void) SCPreferencesApplyChanges(prefs
);
196 (void) SCPreferencesUnlock(prefs
);
198 if (keyList
!= NULL
) {
201 if (modelPrefixStr
!= NULL
) {
202 CFRelease(modelPrefixStr
);
209 establishNewPreferences()
211 SCNetworkSetRef current
= NULL
;
212 CFStringRef new_model
;
214 int sc_status
= kSCStatusFailed
;
215 SCNetworkSetRef set
= NULL
;
216 Boolean updated
= FALSE
;
219 ok
= SCPreferencesLock(prefs
, TRUE
);
224 sc_status
= SCError();
225 if (sc_status
== kSCStatusStale
) {
226 SCPreferencesSynchronize(prefs
);
228 SC_log(LOG_NOTICE
, "Could not acquire network configuration lock: %s",
229 SCErrorString(sc_status
));
234 /* Ensure that the preferences has the new model */
235 new_model
= _SC_hw_model(FALSE
);
237 /* Need to regenerate the new configuration for new model */
238 if (new_model
!= NULL
) {
239 CFStringRef old_model
;
241 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
242 if ((old_model
!= NULL
) && !_SC_CFEqual(old_model
, new_model
)) {
247 keys
= SCPreferencesCopyKeyList(prefs
);
248 count
= (keys
!= NULL
) ? CFArrayGetCount(keys
) : 0;
250 for (index
= 0; index
< count
; index
++) {
251 CFStringRef existing_key
;
253 existing_key
= CFArrayGetValueAtIndex(keys
, index
);
254 if (isA_CFString(existing_key
) != NULL
) {
256 CFPropertyListRef value
;
258 /* If it already contains a Model
259 or if it already contains a MODEL:KEY key skip it*/
260 if (CFEqual(existing_key
, MODEL
)
261 || CFStringFind(existing_key
, CFSTR(":"), 0).location
266 value
= SCPreferencesGetValue(prefs
, existing_key
);
268 /* Create a new key as OLD_MODEL:OLD_KEY */
269 new_key
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:%@"),
270 old_model
, existing_key
);
271 SCPreferencesSetValue(prefs
, new_key
, value
);
272 if (!CFEqual(existing_key
, kSCPrefSystem
)) {
273 /* preserve existing host names */
274 SCPreferencesRemoveValue(prefs
, existing_key
);
284 /* Set the new model */
285 SCPreferencesSetValue(prefs
, MODEL
, new_model
);
288 current
= SCNetworkSetCopyCurrent(prefs
);
289 if (current
!= NULL
) {
294 set
= _SCNetworkSetCreateDefault(prefs
);
297 sc_status
= SCError();
302 ok
= SCNetworkSetEstablishDefaultConfiguration(set
);
304 sc_status
= SCError();
311 ok
= SCPreferencesCommitChanges(prefs
);
313 SC_log(LOG_NOTICE
, "New network configuration saved");
316 sc_status
= SCError();
317 if (sc_status
== EROFS
) {
318 /* a read-only fileysstem is OK */
321 /* ... but we don't want to synchronize */
326 /* apply (committed or temporary/read-only) changes */
327 (void) SCPreferencesApplyChanges(prefs
);
328 } else if ((current
== NULL
) && (set
!= NULL
)) {
329 (void) SCNetworkSetRemove(set
);
333 if (sc_status
== kSCStatusOK
) {
334 SC_log(LOG_NOTICE
, "Network configuration not updated");
336 SC_log(LOG_NOTICE
, "Could not establish network configuration: %s",
337 SCErrorString(sc_status
));
341 (void)SCPreferencesUnlock(prefs
);
342 if (set
!= NULL
) CFRelease(set
);
348 watchSCDynamicStore()
350 CFMutableArrayRef keys
;
352 CFRunLoopSourceRef rls
;
355 * watch for KernelEventMonitor[.bundle] changes (the list of
356 * active network interfaces)
358 interfacesKey
= SCDynamicStoreKeyCreateNetworkInterface(NULL
,
359 kSCDynamicStoreDomainState
);
362 * watch for InterfaceNamer[.bundle] changes (quiet, timeout,
363 * and the list of pre-configured interfaces)
365 namerKey
= SCDynamicStoreKeyCreate(NULL
,
366 CFSTR("%@" "InterfaceNamer"),
367 kSCDynamicStoreDomainPlugin
);
369 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
371 SC_log(LOG_NOTICE
, "SCDynamicStoreCreateRunLoopSource() failed: %s", SCErrorString(SCError()));
372 haveConfiguration
= TRUE
;
375 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
378 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
379 CFArrayAppendValue(keys
, interfacesKey
);
380 CFArrayAppendValue(keys
, namerKey
);
381 ok
= SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
384 SC_log(LOG_NOTICE
, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError()));
385 haveConfiguration
= TRUE
;
393 previousConfigurationAvailable()
395 CFStringRef backupKey
= NULL
;
396 CFStringRef currentModel
= NULL
;
397 CFPropertyListRef properties
= NULL
;
399 currentModel
= _SC_hw_model(FALSE
);
400 if (currentModel
== NULL
) {
404 /* Currently relying only if a backup of "Sets" is present */
405 backupKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:Sets"), currentModel
);
406 properties
= SCPreferencesGetValue(prefs
, backupKey
);
407 CFRelease(backupKey
);
409 return (properties
!= NULL
);
414 findInterfaces(CFArrayRef interfaces
, CFMutableArrayRef
*matched_interfaces
, CFMutableArrayRef
*matched_names
)
418 Boolean updated
= FALSE
;
421 if (*matched_interfaces
!= NULL
) {
422 CFRelease(*matched_interfaces
);
423 *matched_interfaces
= NULL
;
425 if (*matched_names
!= NULL
) {
426 nx
= CFArrayGetCount(*matched_names
);
427 CFRelease(*matched_names
);
428 *matched_names
= NULL
;
431 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
432 for (CFIndex i
= 0; i
< n
; i
++) {
433 CFStringRef bsdName
= CFArrayGetValueAtIndex(interfaces
, i
);
434 SCNetworkInterfaceRef interface
;
436 for (int retry
= 0; retry
< 10; retry
++) {
438 // add short delay (before retry)
439 usleep(20 * 1000); // 20ms
442 interface
= _SCNetworkInterfaceCreateWithBSDName(NULL
, bsdName
, kIncludeNoVirtualInterfaces
);
443 if (interface
== NULL
) {
444 SC_log(LOG_ERR
, "could not create network interface for %@", bsdName
);
445 } else if (_SCNetworkInterfaceGetIOPath(interface
) == NULL
) {
446 SC_log(LOG_ERR
, "could not get IOPath for %@", bsdName
);
447 CFRelease(interface
);
451 if (interface
== NULL
) {
452 // if SCNetworkInterface not [currently] available
456 // keep track of the interface name (quicker than having to iterate the list
457 // of SCNetworkInterfaces, extract the name, and compare).
458 if (*matched_names
== NULL
) {
459 *matched_names
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
461 CFArrayAppendValue(*matched_names
, bsdName
);
463 if (*matched_interfaces
== NULL
) {
464 *matched_interfaces
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
466 CFArrayAppendValue(*matched_interfaces
, interface
);
467 CFRelease(interface
);
473 // check if all interfaces were detached
474 n
= (*matched_names
!= NULL
) ? CFArrayGetCount(*matched_names
) : 0;
475 if ((nx
> 0) && (n
== 0)) {
484 storeCallback(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
)
487 CFDictionaryRef dict
;
488 Boolean quiet
= FALSE
;
489 Boolean timeout
= FALSE
;
490 Boolean updated
= FALSE
;
493 * Capture/process InterfaceNamer[.bundle] info
494 * 1. check if IORegistry "quiet", "timeout"
495 * 2. update list of excluded interfaces (e.g. those requiring that
496 * the attached host be trusted)
497 * 3. update list of named pre-configured interfaces
499 dict
= SCDynamicStoreCopyValue(store
, namerKey
);
501 if (isA_CFDictionary(dict
)) {
503 CFArrayRef preconfigured
;
505 if (CFDictionaryContainsKey(dict
, kInterfaceNamerKey_Quiet
)) {
508 if (CFDictionaryContainsKey(dict
, kInterfaceNamerKey_Timeout
)) {
512 excluded
= CFDictionaryGetValue(dict
, kInterfaceNamerKey_ExcludedInterfaces
);
513 excluded
= isA_CFArray(excluded
);
514 if (!_SC_CFEqual(excluded
, excluded_names
)) {
515 Boolean excluded_updated
;
517 excluded_updated
= findInterfaces(excluded
, &excluded_interfaces
, &excluded_names
);
518 if (excluded_updated
) {
519 CFStringRef interfaces
= CFSTR("<empty>");
521 // report [updated] pre-configured interfaces
522 if (excluded_names
!= NULL
) {
523 interfaces
= CFStringCreateByCombiningStrings(NULL
, excluded_names
, CFSTR(","));
525 CFRetain(interfaces
);
527 SC_log(LOG_INFO
, "excluded interface list changed: %@", interfaces
);
528 CFRelease(interfaces
);
534 preconfigured
= CFDictionaryGetValue(dict
, kInterfaceNamerKey_PreConfiguredInterfaces
);
535 preconfigured
= isA_CFArray(preconfigured
);
536 if (!_SC_CFEqual(preconfigured
, preconfigured_names
)) {
537 Boolean preconfigured_updated
;
539 preconfigured_updated
= findInterfaces(preconfigured
, &preconfigured_interfaces
, &preconfigured_names
);
540 if (preconfigured_updated
) {
541 CFStringRef interfaces
= CFSTR("<empty>");
543 // report [updated] pre-configured interfaces
544 if (preconfigured_names
!= NULL
) {
545 interfaces
= CFStringCreateByCombiningStrings(NULL
, preconfigured_names
, CFSTR(","));
547 CFRetain(interfaces
);
549 SC_log(LOG_INFO
, "pre-configured interface list changed: %@", interfaces
);
550 CFRelease(interfaces
);
560 if (!haveConfiguration
&& (quiet
|| timeout
)) {
561 static int logged
= 0;
564 #if !TARGET_OS_IPHONE
566 #endif /* !TARGET_OS_IPHONE */
568 haveConfiguration
= TRUE
;
571 (void) establishNewPreferences();
574 (void) restorePreferences();
575 restorePrefs
= FALSE
;
578 if (timeout
&& (logged
++ == 0)) {
579 SC_log(LOG_ERR
, "Network configuration creation timed out waiting for IORegistry");
583 if (updated
&& (changedKeys
!= NULL
)) {
584 // if pre-configured interface list changed
585 updateConfiguration(prefs
, kSCPreferencesNotificationApply
, (void *)store
);
593 updateCache(const void *key
, const void *value
, void *context
)
595 #pragma unused(context)
596 CFStringRef configKey
= (CFStringRef
)key
;
597 CFPropertyListRef configData
= (CFPropertyListRef
)value
;
598 CFPropertyListRef cacheData
;
601 cacheData
= CFDictionaryGetValue(currentPrefs
, configKey
);
604 if (CFEqual(cacheData
, configData
)) {
606 * if the old & new property list values have
607 * not changed then we don't need to update
610 CFArrayAppendValue(unchangedPrefsKeys
, configKey
);
614 /* in any case, this key should not be removed */
615 i
= CFArrayGetFirstIndexOfValue(removedPrefsKeys
,
616 CFRangeMake(0, CFArrayGetCount(removedPrefsKeys
)),
618 if (i
!= kCFNotFound
) {
619 CFArrayRemoveValueAtIndex(removedPrefsKeys
, i
);
627 flatten(SCPreferencesRef prefs
,
629 CFDictionaryRef base
)
631 CFDictionaryRef subset
;
633 CFMutableDictionaryRef myDict
;
640 if (!CFDictionaryGetValueIfPresent(base
, kSCResvLink
, (const void **)&link
)) {
641 /* if this dictionary is not linked */
644 /* if __LINK__ key is present */
645 subset
= SCPreferencesPathGetValue(prefs
, link
);
647 /* if error with link */
648 SC_log(LOG_NOTICE
, "SCPreferencesPathGetValue(,%@,) failed: %s",
650 SCErrorString(SCError()));
655 if (CFDictionaryContainsKey(subset
, kSCResvInactive
)) {
656 /* if __INACTIVE__ key is present */
660 myKey
= CFStringCreateWithFormat(NULL
,
663 kSCDynamicStoreDomainSetup
,
666 myDict
= (CFMutableDictionaryRef
)CFDictionaryGetValue(newPrefs
, myKey
);
668 myDict
= CFDictionaryCreateMutableCopy(NULL
,
670 (CFDictionaryRef
)myDict
);
672 myDict
= CFDictionaryCreateMutable(NULL
,
674 &kCFTypeDictionaryKeyCallBacks
,
675 &kCFTypeDictionaryValueCallBacks
);
678 nKeys
= CFDictionaryGetCount(subset
);
680 keys
= CFAllocatorAllocate(NULL
, nKeys
* sizeof(CFStringRef
) , 0);
681 vals
= CFAllocatorAllocate(NULL
, nKeys
* sizeof(CFPropertyListRef
), 0);
682 CFDictionaryGetKeysAndValues(subset
, keys
, vals
);
683 for (i
= 0; i
< nKeys
; i
++) {
684 if (CFGetTypeID((CFTypeRef
)vals
[i
]) != CFDictionaryGetTypeID()) {
685 /* add this key/value to the current dictionary */
686 CFDictionarySetValue(myDict
, keys
[i
], vals
[i
]);
690 /* flatten [sub]dictionaries */
691 subKey
= CFStringCreateWithFormat(NULL
,
695 CFEqual(key
, CFSTR("/")) ? "" : "/",
697 flatten(prefs
, subKey
, vals
[i
]);
701 CFAllocatorDeallocate(NULL
, keys
);
702 CFAllocatorDeallocate(NULL
, vals
);
705 if (CFDictionaryGetCount(myDict
) > 0) {
706 /* add this dictionary to the new preferences */
707 CFDictionarySetValue(newPrefs
, myKey
, myDict
);
717 static CF_RETURNS_RETAINED CFStringRef
718 copyInterfaceUUID(CFStringRef bsdName
)
721 unsigned char sha1_bytes
[CC_SHA1_DIGEST_LENGTH
];
722 CFUUIDBytes uuid_bytes
;
725 char if_name
[IF_NAMESIZE
];
727 CFStringRef uuid_str
;
729 // start with interface name
730 bzero(&if_name
, sizeof(if_name
));
731 (void) _SC_cfstring_to_cstring(bsdName
,
734 kCFStringEncodingASCII
);
737 bzero(&bytes
, sizeof(bytes
));
742 CC_SHA1_Final(bytes
.sha1_bytes
, &ctx
);
744 // create UUID string
745 uuid
= CFUUIDCreateFromUUIDBytes(NULL
, bytes
.uuid_bytes
);
746 uuid_str
= CFUUIDCreateString(NULL
, uuid
);
754 excludeConfigurations(SCPreferencesRef prefs
)
761 range
= CFRangeMake(0,
762 (excluded_names
!= NULL
) ? CFArrayGetCount(excluded_names
) : 0);
763 if (range
.length
== 0) {
764 // if no [excluded] interfaces
768 set
= SCNetworkSetCopyCurrent(prefs
);
775 * Check for (and remove) any network services associated with
776 * an excluded interface from the prefs.
778 services
= SCNetworkSetCopyServices(set
);
779 if (services
!= NULL
) {
782 n
= CFArrayGetCount(services
);
783 for (CFIndex i
= 0; i
< n
; i
++) {
785 SCNetworkInterfaceRef interface
;
786 SCNetworkServiceRef service
;
788 service
= CFArrayGetValueAtIndex(services
, i
);
790 interface
= SCNetworkServiceGetInterface(service
);
791 if (interface
== NULL
) {
796 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
797 if (bsdName
== NULL
) {
798 // if no interface name
802 if (!CFArrayContainsValue(excluded_names
, range
, bsdName
)) {
807 // remove [excluded] network service from the prefs
808 SC_log(LOG_NOTICE
, "removing network service for %@", bsdName
);
809 ok
= SCNetworkSetRemoveService(set
, service
);
811 SC_log(LOG_ERR
, "SCNetworkSetRemoveService() failed: %s",
812 SCErrorString(SCError()));
825 updatePreConfiguredConfiguration(SCPreferencesRef prefs
)
831 Boolean updated
= FALSE
;
833 range
= CFRangeMake(0,
834 (preconfigured_names
!= NULL
) ? CFArrayGetCount(preconfigured_names
) : 0);
835 if (range
.length
== 0) {
836 // if no [pre-configured] interfaces
840 set
= SCNetworkSetCopyCurrent(prefs
);
847 * Check for (and remove) any network services associated with
848 * a pre-configured interface from the prefs.
850 services
= SCNetworkServiceCopyAll(prefs
);
851 if (services
!= NULL
) {
854 n
= CFArrayGetCount(services
);
855 for (CFIndex i
= 0; i
< n
; i
++) {
857 SCNetworkInterfaceRef interface
;
858 SCNetworkServiceRef service
;
860 service
= CFArrayGetValueAtIndex(services
, i
);
862 interface
= SCNetworkServiceGetInterface(service
);
863 if (interface
== NULL
) {
868 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
869 if (bsdName
== NULL
) {
870 // if no interface name
874 if (!CFArrayContainsValue(preconfigured_names
, range
, bsdName
)) {
875 // if not preconfigured
879 // remove [preconfigured] network service from the prefs
880 SC_log(LOG_NOTICE
, "removing network service for %@", bsdName
);
881 ok
= SCNetworkServiceRemove(service
);
883 SC_log(LOG_ERR
, "SCNetworkServiceRemove() failed: %s",
884 SCErrorString(SCError()));
893 // commit the updated prefs ... but don't apply
894 ok
= SCPreferencesCommitChanges(prefs
);
896 if (SCError() != EROFS
) {
897 SC_log(LOG_ERR
, "SCPreferencesCommitChanges() failed: %s",
898 SCErrorString(SCError()));
904 * Now, add a new network service for each pre-configured interface
906 for (CFIndex i
= 0; i
< range
.length
; i
++) {
908 SCNetworkInterfaceRef interface
= CFArrayGetValueAtIndex(preconfigured_interfaces
, i
);
909 SCNetworkServiceRef service
;
910 CFStringRef serviceID
;
912 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
914 // create network service
915 service
= SCNetworkServiceCreate(prefs
, interface
);
916 if (service
== NULL
) {
917 SC_log(LOG_ERR
, "could not create network service for \"%@\": %s",
919 SCErrorString(SCError()));
923 // update network service to use a consistent serviceID
924 serviceID
= copyInterfaceUUID(bsdName
);
925 if (serviceID
!= NULL
) {
926 ok
= _SCNetworkServiceSetServiceID(service
, serviceID
);
927 CFRelease(serviceID
);
929 SC_log(LOG_ERR
, "_SCNetworkServiceSetServiceID() failed: %s",
930 SCErrorString(SCError()));
931 // ... and keep whatever random UUID was created for the service
934 SC_log(LOG_ERR
, "could not create serviceID for \"%@\"", bsdName
);
935 // ... and we'll use whatever random UUID was created for the service
938 // establish [template] configuration
939 ok
= SCNetworkServiceEstablishDefaultConfiguration(service
);
941 SC_log(LOG_ERR
, "could not establish network service for \"%@\": %s",
943 SCErrorString(SCError()));
944 SCNetworkServiceRemove(service
);
949 // add network service to the current set
950 ok
= SCNetworkSetAddService(set
, service
);
952 SC_log(LOG_ERR
, "could not add service for \"%@\": %s",
954 SCErrorString(SCError()));
955 SCNetworkServiceRemove(service
);
960 SC_log(LOG_INFO
, "network service %@ added for \"%@\"",
961 SCNetworkServiceGetServiceID(service
),
973 updateSCDynamicStore(SCPreferencesRef prefs
)
975 CFStringRef current
= NULL
;
976 CFDateRef date
= NULL
;
977 CFMutableDictionaryRef dict
= NULL
;
978 CFDictionaryRef global
= NULL
;
983 CFMutableArrayRef patterns
;
984 CFDictionaryRef set
= NULL
;
987 * initialize old preferences, new preferences, an array
988 * of keys which have not changed, and an array of keys
989 * to be removed (cleaned up).
992 patterns
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
993 pattern
= CFStringCreateWithFormat(NULL
,
996 kSCDynamicStoreDomainSetup
);
997 CFArrayAppendValue(patterns
, pattern
);
998 dict
= (CFMutableDictionaryRef
)SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
1002 currentPrefs
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
1005 currentPrefs
= CFDictionaryCreateMutable(NULL
,
1007 &kCFTypeDictionaryKeyCallBacks
,
1008 &kCFTypeDictionaryValueCallBacks
);
1011 unchangedPrefsKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1013 i
= CFDictionaryGetCount(currentPrefs
);
1015 const void **currentKeys
;
1018 currentKeys
= CFAllocatorAllocate(NULL
, i
* sizeof(CFStringRef
), 0);
1019 CFDictionaryGetKeysAndValues(currentPrefs
, currentKeys
, NULL
);
1020 array
= CFArrayCreate(NULL
, currentKeys
, i
, &kCFTypeArrayCallBacks
);
1021 removedPrefsKeys
= CFArrayCreateMutableCopy(NULL
, 0, array
);
1023 CFAllocatorDeallocate(NULL
, currentKeys
);
1025 removedPrefsKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1029 * The "newPrefs" dictionary will contain the new / updated
1030 * configuration which will be written to the configuration cache.
1032 newPrefs
= CFDictionaryCreateMutable(NULL
,
1034 &kCFTypeDictionaryKeyCallBacks
,
1035 &kCFTypeDictionaryValueCallBacks
);
1038 * create status dictionary associated with current configuration
1039 * information including:
1040 * - current set "name" to cache
1041 * - time stamp indicating when the cache preferences were
1044 dict
= CFDictionaryCreateMutable(NULL
,
1046 &kCFTypeDictionaryKeyCallBacks
,
1047 &kCFTypeDictionaryValueCallBacks
);
1048 date
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent());
1053 keys
= SCPreferencesCopyKeyList(prefs
);
1054 if ((keys
== NULL
) || (CFArrayGetCount(keys
) == 0)) {
1055 SC_log(LOG_NOTICE
, "updateConfiguration(): no preferences");
1060 * get "global" system preferences
1062 global
= SCPreferencesGetValue(prefs
, kSCPrefSystem
);
1064 /* if no global preferences are defined */
1068 if (!isA_CFDictionary(global
)) {
1069 SC_log(LOG_NOTICE
, "updateConfiguration(): %@ is not a dictionary",
1074 /* flatten property list */
1075 flatten(prefs
, CFSTR("/"), global
);
1080 * get current set name
1082 current
= SCPreferencesGetValue(prefs
, kSCPrefCurrentSet
);
1084 /* if current set not defined */
1088 if (!isA_CFString(current
)) {
1089 SC_log(LOG_NOTICE
, "updateConfiguration(): %@ is not a string",
1097 set
= SCPreferencesPathGetValue(prefs
, current
);
1099 /* if error with path */
1100 SC_log(LOG_NOTICE
, "%@ value (%@) not valid",
1106 if (!isA_CFDictionary(set
)) {
1107 SC_log(LOG_NOTICE
, "updateConfiguration(): %@ is not a dictionary",
1112 /* flatten property list */
1113 flatten(prefs
, CFSTR("/"), set
);
1115 CFDictionarySetValue(dict
, kSCDynamicStorePropSetupCurrentSet
, current
);
1119 /* add last updated time stamp */
1120 CFDictionarySetValue(dict
, kSCDynamicStorePropSetupLastUpdated
, date
);
1122 /* add Setup: key */
1123 CFDictionarySetValue(newPrefs
, kSCDynamicStoreDomainSetup
, dict
);
1125 /* compare current and new preferences */
1126 CFDictionaryApplyFunction(newPrefs
, updateCache
, NULL
);
1128 /* remove those keys which have not changed from the update */
1129 n
= CFArrayGetCount(unchangedPrefsKeys
);
1130 for (i
= 0; i
< n
; i
++) {
1133 key
= CFArrayGetValueAtIndex(unchangedPrefsKeys
, i
);
1134 CFDictionaryRemoveValue(newPrefs
, key
);
1137 /* Update the dynamic store */
1139 if (!SCDynamicStoreSetMultiple(store
, newPrefs
, removedPrefsKeys
, NULL
)) {
1140 SC_log(LOG_NOTICE
, "SCDynamicStoreSetMultiple() failed: %s", SCErrorString(SCError()));
1143 SC_log(LOG_DEBUG
, "SCDynamicStore\nset: %@\nremove: %@",
1148 CFRelease(currentPrefs
);
1149 CFRelease(newPrefs
);
1150 CFRelease(unchangedPrefsKeys
);
1151 CFRelease(removedPrefsKeys
);
1152 if (dict
) CFRelease(dict
);
1153 if (date
) CFRelease(date
);
1154 if (keys
) CFRelease(keys
);
1160 updateConfiguration(SCPreferencesRef prefs
,
1161 SCPreferencesNotification notificationType
,
1164 #pragma unused(info)
1165 os_activity_t activity
;
1167 activity
= os_activity_create("processing [SC] preferences.plist changes",
1168 OS_ACTIVITY_CURRENT
,
1169 OS_ACTIVITY_FLAG_DEFAULT
);
1170 os_activity_scope(activity
);
1172 #if !TARGET_OS_IPHONE
1173 if ((notificationType
& kSCPreferencesNotificationCommit
) == kSCPreferencesNotificationCommit
) {
1174 SCNetworkSetRef current
;
1176 current
= SCNetworkSetCopyCurrent(prefs
);
1177 if (current
!= NULL
) {
1178 /* network configuration available, disable template creation */
1179 haveConfiguration
= TRUE
;
1183 #endif /* !TARGET_OS_IPHONE */
1185 if ((notificationType
& kSCPreferencesNotificationApply
) != kSCPreferencesNotificationApply
) {
1189 SC_log(LOG_INFO
, "updating configuration");
1191 /* add any [Apple] pre-configured network services */
1192 updatePreConfiguredConfiguration(prefs
);
1194 /* remove any excluded network services */
1195 excludeConfigurations(prefs
);
1197 /* update SCDynamicStore (Setup:) */
1198 updateSCDynamicStore(prefs
);
1200 /* finished with current prefs, wait for changes */
1202 SCPreferencesSynchronize(prefs
);
1207 os_release(activity
);
1215 prime_PreferencesMonitor()
1217 SC_log(LOG_DEBUG
, "prime() called");
1219 /* load the initial configuration from the database */
1220 updateConfiguration(prefs
, kSCPreferencesNotificationApply
, (void *)store
);
1228 load_PreferencesMonitor(CFBundleRef bundle
, Boolean bundleVerbose
)
1230 #pragma unused(bundle)
1231 #pragma unused(bundleVerbose)
1232 SC_log(LOG_DEBUG
, "load() called");
1233 SC_log(LOG_DEBUG
, " bundle ID = %@", CFBundleGetIdentifier(bundle
));
1235 /* open a SCDynamicStore session to allow cache updates */
1236 store
= SCDynamicStoreCreate(NULL
,
1237 CFSTR("PreferencesMonitor.bundle"),
1240 if (store
== NULL
) {
1241 SC_log(LOG_NOTICE
, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
1245 /* open a SCPreferences session */
1247 prefs
= SCPreferencesCreate(NULL
, CFSTR("PreferencesMonitor.bundle"), NULL
);
1249 prefs
= SCPreferencesCreate(NULL
, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist"));
1251 if (prefs
!= NULL
) {
1252 Boolean need_update
= FALSE
;
1253 CFStringRef new_model
;
1255 new_model
= _SC_hw_model(FALSE
);
1257 /* Need to regenerate the new configuration for new model */
1258 if (new_model
!= NULL
) {
1259 CFStringRef old_model
;
1261 old_model
= SCPreferencesGetValue(prefs
, MODEL
);
1262 if (old_model
!= NULL
&& !_SC_CFEqual(old_model
, new_model
)) {
1265 restorePrefs
= previousConfigurationAvailable();
1270 SCNetworkSetRef current
;
1272 current
= SCNetworkSetCopyCurrent(prefs
);
1273 if (current
!= NULL
) {
1274 /* network configuration available, disable template creation */
1275 haveConfiguration
= TRUE
;
1280 SC_log(LOG_NOTICE
, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
1285 * register for change notifications.
1287 if (!SCPreferencesSetCallback(prefs
, updateConfiguration
, NULL
)) {
1288 SC_log(LOG_NOTICE
, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
1292 if (!SCPreferencesScheduleWithRunLoop(prefs
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
)) {
1293 SC_log(LOG_NOTICE
, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
1298 * watch InterfaceNamer and KernelEventMonitor changes to know when
1299 * the IORegistry has quiesced (to create the initial configuration
1300 * template), to track any pre-configured interfaces, and to ensure
1301 * that we create a network service for any active interfaces.
1303 watchSCDynamicStore();
1304 storeCallback(store
, NULL
, NULL
);
1310 if (store
!= NULL
) CFRelease(store
);
1311 if (prefs
!= NULL
) CFRelease(prefs
);
1312 haveConfiguration
= TRUE
;
1320 main(int argc
, char **argv
)
1323 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
1325 load_PreferencesMonitor(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);
1326 prime_PreferencesMonitor();