]> git.saurik.com Git - apple/configd.git/blobdiff - Plugins/PreferencesMonitor/prefsmon.c
configd-1109.101.1.tar.gz
[apple/configd.git] / Plugins / PreferencesMonitor / prefsmon.c
index bd496eb6c8dbde33dd44a86ca35df2d53155f7ee..31ce760baddc4ac204f9ce167a82c48ef83e9b6f 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2000-2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008, 2010, 2012-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -17,7 +17,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
 
 
 #include <TargetConditionals.h>
-#include <fcntl.h>
 #include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
 
-
+#define        SC_LOG_HANDLE           __log_PreferencesMonitor
+#define SC_LOG_HANDLE_TYPE     static
 #include <SystemConfiguration/SystemConfiguration.h>
 #include <SystemConfiguration/SCPrivate.h>
 #include <SystemConfiguration/SCValidation.h>
-
-
+#include "SCNetworkConfigurationInternal.h"
+#include "plugin_shared.h"
 
 
 /* globals */
-static SCPreferencesRef                prefs           = NULL;
-static SCDynamicStoreRef       store           = NULL;
+static SCPreferencesRef                prefs                   = NULL;
+static SCDynamicStoreRef       store                   = NULL;
+
+/* InterfaceNamer[.plugin] monitoring globals */
+static CFMutableArrayRef       excluded_interfaces     = NULL;         // of SCNetworkInterfaceRef
+static CFMutableArrayRef       excluded_names          = NULL;         // of CFStringRef (BSD name)
+static Boolean                 haveConfiguration       = FALSE;
+static CFStringRef             namerKey                = NULL;
+static CFMutableArrayRef       preconfigured_interfaces= NULL;         // of SCNetworkInterfaceRef
+static CFMutableArrayRef       preconfigured_names     = NULL;         // of CFStringRef (BSD name)
 
-/* preferences "initialization" globals */
-static CFStringRef             initKey         = NULL;
-static CFRunLoopSourceRef      initRls         = NULL;
+/* KernelEventMonitor[.plugin] monitoring globals */
+static CFStringRef             interfacesKey           = NULL;
 
 /* SCDynamicStore (Setup:) */
 static CFMutableDictionaryRef  currentPrefs;           /* current prefs */
@@ -63,19 +69,64 @@ static CFMutableDictionaryRef       newPrefs;               /* new prefs */
 static CFMutableArrayRef       unchangedPrefsKeys;     /* new prefs keys which match current */
 static CFMutableArrayRef       removedPrefsKeys;       /* old prefs keys to be removed */
 
-static Boolean                 rofs            = FALSE;
-static Boolean                 _verbose        = FALSE;
+static Boolean                 rofs                    = FALSE;
+
+#define MY_PLUGIN_NAME         "PreferencesMonitor"
+#define        MY_PLUGIN_ID            CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
+
+
+static void
+updateConfiguration(SCPreferencesRef           prefs,
+                   SCPreferencesNotification   notificationType,
+                   void                        *info);
+
+
+static os_log_t
+__log_PreferencesMonitor(void)
+{
+       static os_log_t log     = NULL;
+
+       if (log == NULL) {
+               log = os_log_create("com.apple.SystemConfiguration", "PreferencesMonitor");
+       }
+
+       return log;
+}
+
+
+static void
+savePastConfiguration(CFStringRef old_model)
+{
+       CFDictionaryRef system;
+
+       // save "/System" (e.g. host names)
+       system = SCPreferencesGetValue(prefs, kSCPrefSystem);
+       if (system != NULL) {
+               CFRetain(system);
+       }
+
+       // save the [previous devices] configuration
+       __SCNetworkConfigurationSaveModel(prefs, old_model);
+
+       if (system != NULL) {
+               // and retain "/System" (e.g. host names)
+               SCPreferencesSetValue(prefs, kSCPrefSystem, system);
+               CFRelease(system);
+       }
+
+       return;
+}
 
 
 static Boolean
 establishNewPreferences()
 {
-       CFBundleRef     bundle;
        SCNetworkSetRef current         = NULL;
+       CFStringRef     new_model;
        Boolean         ok              = FALSE;
+       CFStringRef     old_model;
        int             sc_status       = kSCStatusFailed;
        SCNetworkSetRef set             = NULL;
-       CFStringRef     setName         = NULL;
        Boolean         updated         = FALSE;
 
        while (TRUE) {
@@ -88,45 +139,38 @@ establishNewPreferences()
                if (sc_status == kSCStatusStale) {
                        SCPreferencesSynchronize(prefs);
                } else {
-                       SCLog(TRUE, LOG_ERR,
-                             CFSTR("Could not acquire network configuration lock: %s"),
-                             SCErrorString(sc_status));
+                       SC_log(LOG_NOTICE, "Could not acquire network configuration lock: %s",
+                              SCErrorString(sc_status));
                        return FALSE;
                }
        }
 
+       // check if we need to regenerate the configuration for a new model
+       old_model = SCPreferencesGetValue(prefs, MODEL);
+       new_model = _SC_hw_model(FALSE);
+       if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
+               SC_log(LOG_NOTICE, "Hardware model changed\n"
+                                  "  created on \"%@\"\n"
+                                  "  now on     \"%@\"",
+                      old_model,
+                      new_model);
+
+               // save (and clean) the configuration that was created for "other" hardware
+               savePastConfiguration(old_model);
+       }
+
        current = SCNetworkSetCopyCurrent(prefs);
        if (current != NULL) {
                set = current;
        }
 
        if (set == NULL) {
-               set = SCNetworkSetCreate(prefs);
+               set = _SCNetworkSetCreateDefault(prefs);
                if (set == NULL) {
                        ok = FALSE;
                        sc_status = SCError();
                        goto done;
                }
-
-               bundle = _SC_CFBundleGet();
-               if (bundle != NULL) {
-                       setName = CFBundleCopyLocalizedString(bundle,
-                                                             CFSTR("DEFAULT_SET_NAME"),
-                                                             CFSTR("Automatic"),
-                                                             NULL);
-               }
-
-               ok = SCNetworkSetSetName(set, (setName != NULL) ? setName : CFSTR("Automatic"));
-               if (!ok) {
-                       sc_status = SCError();
-                       goto done;
-               }
-
-               ok = SCNetworkSetSetCurrent(set);
-               if (!ok) {
-                       sc_status = SCError();
-                       goto done;
-               }
        }
 
        ok = SCNetworkSetEstablishDefaultConfiguration(set);
@@ -140,7 +184,7 @@ establishNewPreferences()
        if (ok) {
                ok = SCPreferencesCommitChanges(prefs);
                if (ok) {
-                       SCLog(TRUE, LOG_NOTICE, CFSTR("New network configuration saved"));
+                       SC_log(LOG_NOTICE, "New network configuration saved");
                        updated = TRUE;
                } else {
                        sc_status = SCError();
@@ -160,116 +204,236 @@ establishNewPreferences()
        }
 
        if (!ok) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("Could not establish network configuration: %s"),
-                     SCErrorString(sc_status));
+               if (sc_status == kSCStatusOK) {
+                       SC_log(LOG_NOTICE, "Network configuration not updated");
+               } else {
+                       SC_log(LOG_NOTICE, "Could not establish network configuration: %s",
+                              SCErrorString(sc_status));
+               }
        }
 
        (void)SCPreferencesUnlock(prefs);
-       if (setName != NULL) CFRelease(setName);
        if (set != NULL) CFRelease(set);
        return updated;
 }
 
 
-static Boolean
-quiet(Boolean *timeout)
+static void
+watchSCDynamicStore()
 {
-       CFDictionaryRef dict;
-       Boolean         _quiet          = FALSE;
-       Boolean         _timeout        = FALSE;
+       CFMutableArrayRef       keys;
+       Boolean                 ok;
+       CFRunLoopSourceRef      rls;
 
-       // check if quiet
-       dict = SCDynamicStoreCopyValue(store, initKey);
-       if (dict != NULL) {
-               if (isA_CFDictionary(dict)) {
-                       if (CFDictionaryContainsKey(dict, CFSTR("*QUIET*"))) {
-                               _quiet = TRUE;
-                       }
-                       if (CFDictionaryContainsKey(dict, CFSTR("*TIMEOUT*"))) {
-                               _timeout = TRUE;
-                       }
-               }
-               CFRelease(dict);
+       /*
+        * watch for KernelEventMonitor[.bundle] changes (the list of
+        * active network interfaces)
+        */
+       interfacesKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
+                                                               kSCDynamicStoreDomainState);
+
+       /*
+        * watch for InterfaceNamer[.bundle] changes (quiet, timeout,
+        * and the list of pre-configured interfaces)
+        */
+       namerKey = SCDynamicStoreKeyCreate(NULL,
+                                          CFSTR("%@" "InterfaceNamer"),
+                                          kSCDynamicStoreDomainPlugin);
+
+       rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
+       if (rls == NULL) {
+               SC_log(LOG_NOTICE, "SCDynamicStoreCreateRunLoopSource() failed: %s", SCErrorString(SCError()));
+               haveConfiguration = TRUE;
+               return;
        }
+       CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+       CFRelease(rls);
 
-       if (timeout != NULL) {
-               *timeout = _timeout;
+       keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       CFArrayAppendValue(keys, interfacesKey);
+       CFArrayAppendValue(keys, namerKey);
+       ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
+       CFRelease(keys);
+       if (!ok) {
+               SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError()));
+               haveConfiguration = TRUE;
        }
-       return _quiet;
+
+       return;
 }
 
 
-static void
-watchQuietDisable()
+static Boolean
+findInterfaces(CFArrayRef interfaces, CFMutableArrayRef *matched_interfaces, CFMutableArrayRef *matched_names)
 {
-       if ((initKey == NULL) || (initRls == NULL)) {
-               return;
+       CFIndex         n;
+       CFIndex         nx      = 0;
+       Boolean         updated = FALSE;
+
+       // start clean
+       if (*matched_interfaces != NULL) {
+               CFRelease(*matched_interfaces);
+               *matched_interfaces = NULL;
+       }
+       if (*matched_names != NULL) {
+               nx = CFArrayGetCount(*matched_names);
+               CFRelease(*matched_names);
+               *matched_names = NULL;
        }
 
-       (void) SCDynamicStoreSetNotificationKeys(store, NULL, NULL);
-
-       CFRunLoopSourceInvalidate(initRls);
-       CFRelease(initRls);
-       initRls = NULL;
+       n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
+       for (CFIndex i = 0; i < n; i++) {
+               CFStringRef             bsdName  = CFArrayGetValueAtIndex(interfaces, i);
+               SCNetworkInterfaceRef   interface;
 
-       CFRelease(initKey);
-       initKey = NULL;
+               for (int retry = 0; retry < 10; retry++) {
+                       if (retry != 0) {
+                               // add short delay (before retry)
+                               usleep(20 * 1000);      // 20ms
+                       }
 
-       return;
-}
+                       interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeNoVirtualInterfaces);
+                       if (interface == NULL) {
+                               SC_log(LOG_ERR, "could not create network interface for %@", bsdName);
+                       } else if (_SCNetworkInterfaceGetIOPath(interface) == NULL) {
+                               SC_log(LOG_ERR, "could not get IOPath for %@", bsdName);
+                               CFRelease(interface);
+                               interface = NULL;
+                       }
 
+                       if (interface == NULL) {
+                               // if SCNetworkInterface not [currently] available
+                               continue;
+                       }
 
-static void
-watchQuietEnable()
-{
-       CFArrayRef      keys;
-       Boolean         ok;
+                       // keep track of the interface name (quicker than having to iterate the list
+                       // of SCNetworkInterfaces, extract the name, and compare).
+                       if (*matched_names == NULL) {
+                               *matched_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+                       }
+                       CFArrayAppendValue(*matched_names, bsdName);
 
-       initKey = SCDynamicStoreKeyCreate(NULL,
-                                         CFSTR("%@" "InterfaceNamer"),
-                                         kSCDynamicStoreDomainPlugin);
+                       if (*matched_interfaces == NULL) {
+                               *matched_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+                       }
+                       CFArrayAppendValue(*matched_interfaces, interface);
+                       CFRelease(interface);
 
-       initRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
-       CFRunLoopAddSource(CFRunLoopGetCurrent(), initRls, kCFRunLoopDefaultMode);
+                       updated = TRUE;
+                       break;
+               }
+       }
 
-       keys = CFArrayCreate(NULL, (const void **)&initKey, 1, &kCFTypeArrayCallBacks);
-       ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
-       CFRelease(keys);
-       if (!ok) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
-               watchQuietDisable();
+       // check if all interfaces were detached
+       n = (*matched_names != NULL) ? CFArrayGetCount(*matched_names) : 0;
+       if ((nx > 0) && (n == 0)) {
+               updated = TRUE;
        }
 
-       return;
+       return updated;
 }
 
+
 static void
-watchQuietCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
+storeCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
 {
-       Boolean _quiet;
-       Boolean _timeout        = FALSE;
+#pragma unused(info)
+       CFDictionaryRef dict;
+       Boolean         quiet           = FALSE;
+       Boolean         timeout         = FALSE;
+       Boolean         updated         = FALSE;
 
-       _quiet = quiet(&_timeout);
-       if (_quiet
-#if    !TARGET_OS_IPHONE
-           || _timeout
-#endif /* !TARGET_OS_IPHONE */
-          ) {
-               watchQuietDisable();
+       /*
+        * Capture/process InterfaceNamer[.bundle] info
+        * 1. check if IORegistry "quiet", "timeout"
+        * 2. update list of excluded interfaces (e.g. those requiring that
+        *    the attached host be trusted)
+        * 3. update list of named pre-configured interfaces
+        */
+       dict = SCDynamicStoreCopyValue(store, namerKey);
+       if (dict != NULL) {
+               if (isA_CFDictionary(dict)) {
+                       CFArrayRef      excluded;
+                       CFArrayRef      preconfigured;
+
+                       if (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Quiet)) {
+                               quiet = TRUE;
+                       }
+                       if (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Timeout)) {
+                               timeout = TRUE;
+                       }
+
+                       excluded = CFDictionaryGetValue(dict, kInterfaceNamerKey_ExcludedInterfaces);
+                       excluded = isA_CFArray(excluded);
+                       if (!_SC_CFEqual(excluded, excluded_names)) {
+                               Boolean         excluded_updated;
+
+                               excluded_updated = findInterfaces(excluded, &excluded_interfaces, &excluded_names);
+                               if (excluded_updated) {
+                                       CFStringRef     interfaces      = CFSTR("<empty>");
+
+                                       // report [updated] pre-configured interfaces
+                                       if (excluded_names != NULL) {
+                                               interfaces = CFStringCreateByCombiningStrings(NULL, excluded_names, CFSTR(","));
+                                       } else {
+                                               CFRetain(interfaces);
+                                       }
+                                       SC_log(LOG_INFO, "excluded interface list changed: %@", interfaces);
+                                       CFRelease(interfaces);
+
+                                       updated = TRUE;
+                               }
+                       }
+
+                       preconfigured = CFDictionaryGetValue(dict, kInterfaceNamerKey_PreConfiguredInterfaces);
+                       preconfigured = isA_CFArray(preconfigured);
+                       if (!_SC_CFEqual(preconfigured, preconfigured_names)) {
+                               Boolean         preconfigured_updated;
+
+                               preconfigured_updated = findInterfaces(preconfigured, &preconfigured_interfaces, &preconfigured_names);
+                               if (preconfigured_updated) {
+                                       CFStringRef     interfaces      = CFSTR("<empty>");
+
+                                       // report [updated] pre-configured interfaces
+                                       if (preconfigured_names != NULL) {
+                                               interfaces = CFStringCreateByCombiningStrings(NULL, preconfigured_names, CFSTR(","));
+                                       } else {
+                                               CFRetain(interfaces);
+                                       }
+                                       SC_log(LOG_INFO, "pre-configured interface list changed: %@", interfaces);
+                                       CFRelease(interfaces);
+
+                                       updated = TRUE;
+                               }
+                       }
+               }
+
+               CFRelease(dict);
        }
 
-       if (_quiet || _timeout) {
+       if (!haveConfiguration && (quiet || timeout)) {
                static int      logged  = 0;
 
+               if (quiet
+#if    !TARGET_OS_IPHONE
+                   || timeout
+#endif /* !TARGET_OS_IPHONE */
+                   ) {
+                       haveConfiguration = TRUE;
+               }
+
                (void) establishNewPreferences();
-               if (_timeout && (logged++ == 0)) {
-                       SCLog(TRUE, LOG_NOTICE,
-                             CFSTR("Network configuration creation timed out waiting for IORegistry"));
+
+               if (timeout && (logged++ == 0)) {
+                       SC_log(LOG_ERR, "Network configuration creation timed out waiting for IORegistry");
                }
        }
 
+       if (updated && (changedKeys != NULL)) {
+               // if pre-configured interface list changed
+               updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
+       }
+
        return;
 }
 
@@ -277,6 +441,7 @@ watchQuietCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
 static void
 updateCache(const void *key, const void *value, void *context)
 {
+#pragma unused(context)
        CFStringRef             configKey       = (CFStringRef)key;
        CFPropertyListRef       configData      = (CFPropertyListRef)value;
        CFPropertyListRef       cacheData;
@@ -329,10 +494,9 @@ flatten(SCPreferencesRef   prefs,
                subset = SCPreferencesPathGetValue(prefs, link);
                if (!subset) {
                        /* if error with link */
-                       SCLog(TRUE, LOG_ERR,
-                             CFSTR("SCPreferencesPathGetValue(,%@,) failed: %s"),
-                             link,
-                             SCErrorString(SCError()));
+                       SC_log(LOG_NOTICE, "SCPreferencesPathGetValue(,%@,) failed: %s",
+                              link,
+                              SCErrorString(SCError()));
                        return;
                }
        }
@@ -399,6 +563,195 @@ flatten(SCPreferencesRef  prefs,
 }
 
 
+static void
+excludeConfigurations(SCPreferencesRef prefs)
+{
+       Boolean         ok;
+       CFRange         range;
+       CFArrayRef      services;
+       SCNetworkSetRef set;
+
+       range = CFRangeMake(0,
+                           (excluded_names != NULL) ? CFArrayGetCount(excluded_names) : 0);
+       if (range.length == 0) {
+               // if no [excluded] interfaces
+               return;
+       }
+
+       set = SCNetworkSetCopyCurrent(prefs);
+       if (set == NULL) {
+               // if no current set
+               return;
+       }
+
+       /*
+        * Check for (and remove) any network services associated with
+        * an excluded interface from the prefs.
+        */
+       services = SCNetworkSetCopyServices(set);
+       if (services != NULL) {
+               CFIndex         n;
+
+               n = CFArrayGetCount(services);
+               for (CFIndex i = 0; i < n; i++) {
+                       CFStringRef             bsdName;
+                       SCNetworkInterfaceRef   interface;
+                       SCNetworkServiceRef     service;
+
+                       service = CFArrayGetValueAtIndex(services, i);
+
+                       interface = SCNetworkServiceGetInterface(service);
+                       if (interface == NULL) {
+                               // if no interface
+                               continue;
+                       }
+
+                       bsdName = SCNetworkInterfaceGetBSDName(interface);
+                       if (bsdName == NULL) {
+                               // if no interface name
+                               continue;
+                       }
+
+                       if (!CFArrayContainsValue(excluded_names, range, bsdName)) {
+                               // if not excluded
+                               continue;
+                       }
+
+                       // remove [excluded] network service from the prefs
+                       SC_log(LOG_NOTICE, "excluding network service for %@", bsdName);
+                       ok = SCNetworkSetRemoveService(set, service);
+                       if (!ok) {
+                               SC_log(LOG_ERR, "SCNetworkSetRemoveService() failed: %s",
+                                      SCErrorString(SCError()));
+                       }
+               }
+
+               CFRelease(services);
+       }
+
+       CFRelease(set);
+       return;
+}
+
+
+static void
+updatePreConfiguredConfiguration(SCPreferencesRef prefs)
+{
+       Boolean         ok;
+       CFRange         range;
+       CFArrayRef      services;
+       SCNetworkSetRef set;
+       Boolean         updated = FALSE;
+
+       range = CFRangeMake(0,
+                           (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0);
+       if (range.length == 0) {
+               // if no [pre-configured] interfaces
+               return;
+       }
+
+       set = SCNetworkSetCopyCurrent(prefs);
+       if (set == NULL) {
+               // if no current set
+               return;
+       }
+
+       /*
+        * Check for (and remove) any network services associated with
+        * a pre-configured interface from the prefs.
+        */
+       services = SCNetworkServiceCopyAll(prefs);
+       if (services != NULL) {
+               CFIndex         n;
+
+               n = CFArrayGetCount(services);
+               for (CFIndex i = 0; i < n; i++) {
+                       CFStringRef             bsdName;
+                       SCNetworkInterfaceRef   interface;
+                       SCNetworkServiceRef     service;
+
+                       service = CFArrayGetValueAtIndex(services, i);
+
+                       interface = SCNetworkServiceGetInterface(service);
+                       if (interface == NULL) {
+                               // if no interface
+                               continue;
+                       }
+
+                       bsdName = SCNetworkInterfaceGetBSDName(interface);
+                       if (bsdName == NULL) {
+                               // if no interface name
+                               continue;
+                       }
+
+                       if (!CFArrayContainsValue(preconfigured_names, range, bsdName)) {
+                               // if not preconfigured
+                               continue;
+                       }
+
+                       // remove [preconfigured] network service from the prefs
+                       SC_log(LOG_NOTICE, "removing network service for %@", bsdName);
+                       ok = SCNetworkServiceRemove(service);
+                       if (!ok) {
+                               SC_log(LOG_ERR, "SCNetworkServiceRemove() failed: %s",
+                                      SCErrorString(SCError()));
+                       }
+                       updated = TRUE;
+               }
+
+               CFRelease(services);
+       }
+
+       if (updated) {
+               // commit the updated prefs ... but don't apply
+               ok = SCPreferencesCommitChanges(prefs);
+               if (!ok) {
+                       if (SCError() != EROFS) {
+                               SC_log(LOG_ERR, "SCPreferencesCommitChanges() failed: %s",
+                                      SCErrorString(SCError()));
+                       }
+               }
+       }
+
+       /*
+        * Now, add a new network service for each pre-configured interface
+        */
+       for (CFIndex i = 0; i < range.length; i++) {
+               CFStringRef             bsdName;
+               SCNetworkInterfaceRef   interface       = CFArrayGetValueAtIndex(preconfigured_interfaces, i);
+               SCNetworkServiceRef     service;
+
+               bsdName = SCNetworkInterfaceGetBSDName(interface);
+
+               // create network service
+               service = _SCNetworkServiceCreatePreconfigured(prefs, interface);
+               if (service == NULL) {
+                       continue;
+               }
+
+               // add network service to the current set
+               ok = SCNetworkSetAddService(set, service);
+               if (!ok) {
+                       SC_log(LOG_ERR, "could not add service for \"%@\": %s",
+                              bsdName,
+                              SCErrorString(SCError()));
+                       SCNetworkServiceRemove(service);
+                       CFRelease(service);
+                       continue;
+               }
+
+               SC_log(LOG_INFO, "network service %@ added for \"%@\"",
+                      SCNetworkServiceGetServiceID(service),
+                      bsdName);
+
+               CFRelease(service);
+       }
+
+       CFRelease(set);
+       return;
+}
+
+
 static void
 updateSCDynamicStore(SCPreferencesRef prefs)
 {
@@ -482,7 +835,7 @@ updateSCDynamicStore(SCPreferencesRef prefs)
         */
        keys = SCPreferencesCopyKeyList(prefs);
        if ((keys == NULL) || (CFArrayGetCount(keys) == 0)) {
-               SCLog(TRUE, LOG_NOTICE, CFSTR("updateConfiguration(): no preferences."));
+               SC_log(LOG_NOTICE, "updateConfiguration(): no preferences");
                goto done;
        }
 
@@ -496,9 +849,8 @@ updateSCDynamicStore(SCPreferencesRef prefs)
        }
 
        if (!isA_CFDictionary(global)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("updateConfiguration(): %@ is not a dictionary."),
-                     kSCPrefSystem);
+               SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a dictionary",
+                      kSCPrefSystem);
                goto done;
        }
 
@@ -517,9 +869,8 @@ updateSCDynamicStore(SCPreferencesRef prefs)
        }
 
        if (!isA_CFString(current)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("updateConfiguration(): %@ is not a string."),
-                     kSCPrefCurrentSet);
+               SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a string",
+                      kSCPrefCurrentSet);
                goto done;
        }
 
@@ -529,17 +880,15 @@ updateSCDynamicStore(SCPreferencesRef prefs)
        set = SCPreferencesPathGetValue(prefs, current);
        if (!set) {
                /* if error with path */
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("%@ value (%@) not valid"),
-                     kSCPrefCurrentSet,
-                     current);
+               SC_log(LOG_NOTICE, "%@ value (%@) not valid",
+                      kSCPrefCurrentSet,
+                      current);
                goto done;
        }
 
        if (!isA_CFDictionary(set)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("updateConfiguration(): %@ is not a dictionary."),
-                     current);
+               SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a dictionary",
+                      current);
                goto done;
        }
 
@@ -569,11 +918,15 @@ updateSCDynamicStore(SCPreferencesRef prefs)
        }
 
        /* Update the dynamic store */
+#ifndef MAIN
        if (!SCDynamicStoreSetMultiple(store, newPrefs, removedPrefsKeys, NULL)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCDynamicStoreSetMultiple() failed: %s"),
-                     SCErrorString(SCError()));
+               SC_log(LOG_NOTICE, "SCDynamicStoreSetMultiple() failed: %s", SCErrorString(SCError()));
        }
+#else  // !MAIN
+       SC_log(LOG_DEBUG, "SCDynamicStore\nset: %@\nremove: %@",
+              newPrefs,
+              removedPrefsKeys);
+#endif // !MAIN
 
        CFRelease(currentPrefs);
        CFRelease(newPrefs);
@@ -591,8 +944,7 @@ updateConfiguration(SCPreferencesRef                prefs,
                    SCPreferencesNotification   notificationType,
                    void                        *info)
 {
-
-
+#pragma unused(info)
 #if    !TARGET_OS_IPHONE
        if ((notificationType & kSCPreferencesNotificationCommit) == kSCPreferencesNotificationCommit) {
                SCNetworkSetRef current;
@@ -600,17 +952,23 @@ updateConfiguration(SCPreferencesRef              prefs,
                current = SCNetworkSetCopyCurrent(prefs);
                if (current != NULL) {
                        /* network configuration available, disable template creation */
-                       watchQuietDisable();
+                       haveConfiguration = TRUE;
                        CFRelease(current);
                }
        }
 #endif /* !TARGET_OS_IPHONE */
 
        if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
-               return;
+               goto done;
        }
 
-       SCLog(_verbose, LOG_DEBUG, CFSTR("updating configuration"));
+       SC_log(LOG_INFO, "updating configuration");
+
+       /* add any [Apple] pre-configured network services */
+       updatePreConfiguredConfiguration(prefs);
+
+       /* remove any excluded network services */
+       excludeConfigurations(prefs);
 
        /* update SCDynamicStore (Setup:) */
        updateSCDynamicStore(prefs);
@@ -620,6 +978,8 @@ updateConfiguration(SCPreferencesRef                prefs,
                SCPreferencesSynchronize(prefs);
        }
 
+    done :
+
        return;
 }
 
@@ -628,7 +988,7 @@ __private_extern__
 void
 prime_PreferencesMonitor()
 {
-       SCLog(_verbose, LOG_DEBUG, CFSTR("prime() called"));
+       SC_log(LOG_DEBUG, "prime() called");
 
        /* load the initial configuration from the database */
        updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
@@ -637,46 +997,75 @@ prime_PreferencesMonitor()
 }
 
 
+#ifndef        MAIN
+#define        PREFERENCES_MONITOR_PLIST       NULL
+#else  // !MAIN
+#define        PREFERENCES_MONITOR_PLIST       CFSTR("/tmp/preferences.plist")
+#endif // !MAIN
+
+
 __private_extern__
 void
 load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose)
 {
-       Boolean initPrefs       = TRUE;
-
-       if (bundleVerbose) {
-               _verbose = TRUE;
-       }
-
-       SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
-       SCLog(_verbose, LOG_DEBUG, CFSTR("  bundle ID = %@"), CFBundleGetIdentifier(bundle));
+#pragma unused(bundle)
+#pragma unused(bundleVerbose)
+       SC_log(LOG_DEBUG, "load() called");
+       SC_log(LOG_DEBUG, "  bundle ID = %@", CFBundleGetIdentifier(bundle));
 
        /* open a SCDynamicStore session to allow cache updates */
        store = SCDynamicStoreCreate(NULL,
                                     CFSTR("PreferencesMonitor.bundle"),
-                                    watchQuietCallback,
+                                    storeCallback,
                                     NULL);
        if (store == NULL) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCDynamicStoreCreate() failed: %s"),
-                     SCErrorString(SCError()));
+               SC_log(LOG_NOTICE, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
                goto error;
        }
 
        /* open a SCPreferences session */
-       prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL);
+       prefs = SCPreferencesCreateWithOptions(NULL,
+                                              MY_PLUGIN_ID,
+                                              PREFERENCES_MONITOR_PLIST,
+                                              NULL,    // authorization
+                                              NULL);
        if (prefs != NULL) {
-               SCNetworkSetRef current;
+               Boolean         need_update = FALSE;
+               CFStringRef     new_model;
+               CFStringRef     old_model;
+
+               // check if we need to update the configuration
+               __SCNetworkConfigurationUpgrade(&prefs, NULL, TRUE);
+
+               // check if we need to regenerate the configuration for a new model
+               old_model = SCPreferencesGetValue(prefs, MODEL);
+               new_model = _SC_hw_model(FALSE);
+               if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
+                       SC_log(LOG_NOTICE, "Hardware model changed\n"
+                                          "  created on \"%@\"\n"
+                                          "  now on     \"%@\"",
+                              old_model,
+                              new_model);
+
+                       // save (and clean) the configuration that was created for "other" hardware
+                       savePastConfiguration(old_model);
+
+                       // ... and we'll update the configuration later (when the IORegistry quiesces)
+                       need_update = TRUE;
+               }
 
-               current = SCNetworkSetCopyCurrent(prefs);
-               if (current != NULL) {
-                       /* network configuration available, disable template creation */
-                       initPrefs = FALSE;
-                       CFRelease(current);
+               if (!need_update) {
+                       SCNetworkSetRef current;
+
+                       current = SCNetworkSetCopyCurrent(prefs);
+                       if (current != NULL) {
+                               /* network configuration available, disable template creation */
+                               haveConfiguration = TRUE;
+                               CFRelease(current);
+                       }
                }
        } else {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCPreferencesCreate() failed: %s"),
-                     SCErrorString(SCError()));
+               SC_log(LOG_NOTICE, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
                goto error;
        }
 
@@ -684,35 +1073,31 @@ load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose)
         * register for change notifications.
         */
        if (!SCPreferencesSetCallback(prefs, updateConfiguration, NULL)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCPreferencesSetCallBack() failed: %s"),
-                     SCErrorString(SCError()));
+               SC_log(LOG_NOTICE, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
                goto error;
        }
 
        if (!SCPreferencesScheduleWithRunLoop(prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCPreferencesScheduleWithRunLoop() failed: %s"),
-                     SCErrorString(SCError()));
+               SC_log(LOG_NOTICE, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
                goto error;
        }
 
        /*
-        * if no preferences, initialize with a template (now or
-        * when IOKit has quiesced).
+        * watch InterfaceNamer and KernelEventMonitor changes to know when
+        * the IORegistry has quiesced (to create the initial configuration
+        * template), to track any pre-configured interfaces, and to ensure
+        * that we create a network service for any active interfaces.
         */
-       if (initPrefs) {
-               watchQuietEnable();
-               watchQuietCallback(store, NULL, NULL);
-       }
+       watchSCDynamicStore();
+       storeCallback(store, NULL, NULL);
 
        return;
 
     error :
 
-       watchQuietDisable();
        if (store != NULL)      CFRelease(store);
        if (prefs != NULL)      CFRelease(prefs);
+       haveConfiguration = TRUE;
 
        return;
 }
@@ -722,7 +1107,7 @@ load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose)
 int
 main(int argc, char **argv)
 {
-       _sc_log     = FALSE;
+       _sc_log     = kSCLogDestinationFile;
        _sc_verbose = (argc > 1) ? TRUE : FALSE;
 
        load_PreferencesMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);