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();