/*
- * Copyright (c) 2000-2008, 2010, 2012-2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008, 2010, 2012-2020 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <TargetConditionals.h>
-#include <fcntl.h>
-#include <net/if.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <unistd.h>
-
-#define SC_LOG_HANDLE __log_PreferencesMonitor()
+#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"
-#include <CommonCrypto/CommonDigest.h>
-
-
/* globals */
static SCPreferencesRef prefs = NULL;
static SCDynamicStoreRef store = NULL;
/* InterfaceNamer[.plugin] monitoring globals */
-Boolean haveConfiguration = FALSE;
+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_names = NULL; // of CFStringRef (BSD name)
static CFMutableArrayRef preconfigured_interfaces= NULL; // of SCNetworkInterfaceRef
+static CFMutableArrayRef preconfigured_names = NULL; // of CFStringRef (BSD name)
/* KernelEventMonitor[.plugin] monitoring globals */
static CFStringRef interfacesKey = NULL;
static CFMutableArrayRef removedPrefsKeys; /* old prefs keys to be removed */
static Boolean rofs = FALSE;
-static Boolean restorePrefs = FALSE;
#define MY_PLUGIN_NAME "PreferencesMonitor"
#define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
static os_log_t
-__log_PreferencesMonitor()
+__log_PreferencesMonitor(void)
{
static os_log_t log = NULL;
}
-static Boolean
-restorePreferences()
+static void
+savePastConfiguration(CFStringRef old_model)
{
- Boolean ok = FALSE;
- CFStringRef currentModel = NULL;
- CFMutableStringRef modelPrefixStr = NULL;
- CFArrayRef keyList = NULL;
- CFIndex keyListCount;
- CFIndex idx;
- Boolean modified = FALSE;
- int sc_status = kSCStatusFailed;
-
- while (TRUE) {
- ok = SCPreferencesLock(prefs, TRUE);
- if (ok) {
- break;
- }
+ CFDictionaryRef system;
- sc_status = SCError();
- if (sc_status == kSCStatusStale) {
- SCPreferencesSynchronize(prefs);
- } else {
- SC_log(LOG_NOTICE, "Could not acquire network configuration lock: %s",
- SCErrorString(sc_status));
- return FALSE;
- }
+ // save "/System" (e.g. host names)
+ system = SCPreferencesGetValue(prefs, kSCPrefSystem);
+ if (system != NULL) {
+ CFRetain(system);
}
- keyList = SCPreferencesCopyKeyList(prefs);
- if (keyList == NULL) {
- goto error;
- }
+ // save the [previous devices] configuration
+ __SCNetworkConfigurationSaveModel(prefs, old_model);
- currentModel = _SC_hw_model(FALSE);
- if (currentModel == NULL) {
- goto error;
+ if (system != NULL) {
+ // and retain "/System" (e.g. host names)
+ SCPreferencesSetValue(prefs, kSCPrefSystem, system);
+ CFRelease(system);
}
- /* Create "model:" string for prefix-check */
- modelPrefixStr = CFStringCreateMutableCopy(NULL, 0, currentModel);
- CFStringAppend(modelPrefixStr, CFSTR(":"));
-
- keyListCount = CFArrayGetCount(keyList);
- for (idx = 0; idx < keyListCount; idx++) {
- CFStringRef existingKey = CFArrayGetValueAtIndex(keyList, idx);
- CFStringRef key;
- CFArrayRef splitKey = NULL;
- CFPropertyListRef value;
-
- if (isA_CFString(existingKey) == NULL) {
- continue;
- }
-
- if (!CFStringHasPrefix(existingKey, modelPrefixStr)) {
- continue;
- }
-
- splitKey = CFStringCreateArrayBySeparatingStrings(NULL, existingKey, CFSTR(":"));
- key = CFArrayGetValueAtIndex(splitKey, 1);
- value = SCPreferencesGetValue(prefs, existingKey);
- SCPreferencesSetValue(prefs, key, value);
- SCPreferencesRemoveValue(prefs, existingKey);
- modified = TRUE;
- CFRelease(splitKey);
- }
-
- if (modified) {
- SCPreferencesRef ni_prefs = NULL;
- ni_prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, CFSTR("NetworkInterfaces.plist"));
- if (ni_prefs == NULL) {
- goto error;
- }
-
- ok = _SCNetworkConfigurationCheckValidityWithPreferences(prefs, ni_prefs, NULL);
- CFRelease(ni_prefs);
-
- //Commit the changes only if prefs files valid
- if (ok) {
- if (!SCPreferencesCommitChanges(prefs)) {
- if (SCError() != EROFS) {
- SC_log(LOG_NOTICE, "SCPreferencesCommitChanges() failed: %s",
- SCErrorString(SCError()));
- }
- goto error;
-
- }
-
- (void) SCPreferencesApplyChanges(prefs);
- }
- }
-
-error:
- (void) SCPreferencesUnlock(prefs);
-
- if (keyList != NULL) {
- CFRelease(keyList);
- }
- if (modelPrefixStr != NULL) {
- CFRelease(modelPrefixStr);
- }
-
- return modified;
+ return;
}
+
static Boolean
establishNewPreferences()
{
SCNetworkSetRef current = NULL;
CFStringRef new_model;
Boolean ok = FALSE;
+ CFStringRef old_model;
int sc_status = kSCStatusFailed;
SCNetworkSetRef set = NULL;
Boolean updated = FALSE;
}
}
- /* Ensure that the preferences has the new model */
+ // check if we need to regenerate the configuration for a new model
+ old_model = SCPreferencesGetValue(prefs, MODEL);
new_model = _SC_hw_model(FALSE);
-
- /* Need to regenerate the new configuration for new model */
- if (new_model != NULL) {
- CFStringRef old_model;
-
- old_model = SCPreferencesGetValue(prefs, MODEL);
- if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
- CFIndex count;
- CFIndex index;
- CFArrayRef keys;
-
- keys = SCPreferencesCopyKeyList(prefs);
- count = (keys != NULL) ? CFArrayGetCount(keys) : 0;
- // if new hardware
- for (index = 0; index < count; index++) {
- CFStringRef existing_key;
-
- existing_key = CFArrayGetValueAtIndex(keys, index);
- if (isA_CFString(existing_key) != NULL) {
- CFStringRef new_key;
- CFPropertyListRef value;
-
- /* If it already contains a Model
- or if it already contains a MODEL:KEY key skip it*/
- if (CFEqual(existing_key, MODEL)
- || CFStringFind(existing_key, CFSTR(":"), 0).location
- != kCFNotFound) {
- continue;
- }
-
- value = SCPreferencesGetValue(prefs, existing_key);
-
- /* Create a new key as OLD_MODEL:OLD_KEY */
- new_key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"),
- old_model, existing_key);
- SCPreferencesSetValue(prefs, new_key, value);
- if (!CFEqual(existing_key, kSCPrefSystem)) {
- /* preserve existing host names */
- SCPreferencesRemoveValue(prefs, existing_key);
- }
- CFRelease(new_key);
- }
- }
-
- if (keys != NULL) {
- CFRelease(keys);
- }
- }
- /* Set the new model */
- SCPreferencesSetValue(prefs, MODEL, new_model);
+ 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);
static Boolean
-previousConfigurationAvailable()
+findInterfaces(CFArrayRef interfaces, CFMutableArrayRef *matched_interfaces, CFMutableArrayRef *matched_names)
{
- CFStringRef backupKey = NULL;
- CFStringRef currentModel = NULL;
- CFPropertyListRef properties = NULL;
+ CFIndex n;
+ CFIndex nx = 0;
+ Boolean updated = FALSE;
- currentModel = _SC_hw_model(FALSE);
- if (currentModel == NULL) {
- goto done;
+ // 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;
+ }
+
+ n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
+ for (CFIndex i = 0; i < n; i++) {
+ CFStringRef bsdName = CFArrayGetValueAtIndex(interfaces, i);
+ SCNetworkInterfaceRef interface;
+
+ for (int retry = 0; retry < 10; retry++) {
+ if (retry != 0) {
+ // add short delay (before retry)
+ usleep(20 * 1000); // 20ms
+ }
+
+ 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;
+ }
- /* Currently relying only if a backup of "Sets" is present */
- backupKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:Sets"), currentModel);
- properties = SCPreferencesGetValue(prefs, backupKey);
- CFRelease(backupKey);
-done:
- return (properties != NULL);
+ // 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);
+
+ if (*matched_interfaces == NULL) {
+ *matched_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+ CFArrayAppendValue(*matched_interfaces, interface);
+ CFRelease(interface);
+
+ updated = TRUE;
+ break;
+ }
+ }
+
+ // check if all interfaces were detached
+ n = (*matched_names != NULL) ? CFArrayGetCount(*matched_names) : 0;
+ if ((nx > 0) && (n == 0)) {
+ updated = TRUE;
+ }
+
+ return updated;
}
/*
* Capture/process InterfaceNamer[.bundle] info
* 1. check if IORegistry "quiet", "timeout"
- * 2. update list of named pre-configured interfaces
+ * 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)) {
timeout = TRUE;
}
- preconfigured = CFDictionaryGetValue(dict, kInterfaceNamerKey_PreConfiguredInterfaces);
- preconfigured = isA_CFArray(preconfigured);
- if (!_SC_CFEqual(preconfigured, preconfigured_names)) {
- CFIndex n;
- CFIndex nx = 0;
-
- // start clean
- if (preconfigured_names != NULL) {
- nx = CFArrayGetCount(preconfigured_names);
- CFRelease(preconfigured_names);
- preconfigured_names = NULL;
- }
- if (preconfigured_interfaces != NULL) {
- CFRelease(preconfigured_interfaces);
- preconfigured_interfaces = NULL;
- }
-
- // add pre-configured interfaces
- n = (preconfigured != NULL) ? CFArrayGetCount(preconfigured) : 0;
- for (CFIndex i = 0; i < n; i++) {
- CFStringRef bsdName = CFArrayGetValueAtIndex(preconfigured, i);
- SCNetworkInterfaceRef interface;
-
- for (int retry = 0; retry < 10; retry++) {
- if (retry != 0) {
- // add short delay (before retry)
- usleep(20 * 1000); // 20ms
- }
-
- 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 we have an interface
- break;
- }
- }
+ excluded = CFDictionaryGetValue(dict, kInterfaceNamerKey_ExcludedInterfaces);
+ excluded = isA_CFArray(excluded);
+ if (!_SC_CFEqual(excluded, excluded_names)) {
+ Boolean excluded_updated;
- if (interface == NULL) {
- // if SCNetworkInterface not [currently] available
- continue;
- }
-
- // keep track of the interface name (quicker than having to iterate the list
- // of SCNetworkInterfaces, extract the name, and compare).
- if (preconfigured_names == NULL) {
- preconfigured_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- }
- CFArrayAppendValue(preconfigured_names, bsdName);
+ excluded_updated = findInterfaces(excluded, &excluded_interfaces, &excluded_names);
+ if (excluded_updated) {
+ CFStringRef interfaces = CFSTR("<empty>");
- if (preconfigured_interfaces == NULL) {
- preconfigured_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ // report [updated] pre-configured interfaces
+ if (excluded_names != NULL) {
+ interfaces = CFStringCreateByCombiningStrings(NULL, excluded_names, CFSTR(","));
+ } else {
+ CFRetain(interfaces);
}
- CFArrayAppendValue(preconfigured_interfaces, interface);
- CFRelease(interface);
+ SC_log(LOG_INFO, "excluded interface list changed: %@", interfaces);
+ CFRelease(interfaces);
updated = TRUE;
}
+ }
- // check if all pre-configured interfaces were detached
- n = (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0;
- if ((nx > 0) && (n == 0)) {
- updated = TRUE;
- }
+ preconfigured = CFDictionaryGetValue(dict, kInterfaceNamerKey_PreConfiguredInterfaces);
+ preconfigured = isA_CFArray(preconfigured);
+ if (!_SC_CFEqual(preconfigured, preconfigured_names)) {
+ Boolean preconfigured_updated;
- if (updated) {
+ preconfigured_updated = findInterfaces(preconfigured, &preconfigured_interfaces, &preconfigured_names);
+ if (preconfigured_updated) {
CFStringRef interfaces = CFSTR("<empty>");
// report [updated] pre-configured interfaces
}
SC_log(LOG_INFO, "pre-configured interface list changed: %@", interfaces);
CFRelease(interfaces);
+
+ updated = TRUE;
}
}
}
(void) establishNewPreferences();
- if (restorePrefs) {
- (void) restorePreferences();
- restorePrefs = FALSE;
- }
-
if (timeout && (logged++ == 0)) {
SC_log(LOG_ERR, "Network configuration creation timed out waiting for IORegistry");
}
}
-static CF_RETURNS_RETAINED CFStringRef
-copyInterfaceUUID(CFStringRef bsdName)
+static void
+excludeConfigurations(SCPreferencesRef prefs)
{
- union {
- unsigned char sha1_bytes[CC_SHA1_DIGEST_LENGTH];
- CFUUIDBytes uuid_bytes;
- } bytes;
- CC_SHA1_CTX ctx;
- char if_name[IF_NAMESIZE];
- CFUUIDRef uuid;
- CFStringRef uuid_str;
-
- // start with interface name
- bzero(&if_name, sizeof(if_name));
- (void) _SC_cfstring_to_cstring(bsdName,
- if_name,
- sizeof(if_name),
- kCFStringEncodingASCII);
-
- // create SHA1 hash
- bzero(&bytes, sizeof(bytes));
- CC_SHA1_Init(&ctx);
- CC_SHA1_Update(&ctx,
- if_name,
- sizeof(if_name));
- CC_SHA1_Final(bytes.sha1_bytes, &ctx);
-
- // create UUID string
- uuid = CFUUIDCreateFromUUIDBytes(NULL, bytes.uuid_bytes);
- uuid_str = CFUUIDCreateString(NULL, uuid);
- CFRelease(uuid);
-
- return uuid_str;
+ 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;
}
CFStringRef bsdName;
SCNetworkInterfaceRef interface = CFArrayGetValueAtIndex(preconfigured_interfaces, i);
SCNetworkServiceRef service;
- CFStringRef serviceID;
bsdName = SCNetworkInterfaceGetBSDName(interface);
// create network service
- service = SCNetworkServiceCreate(prefs, interface);
+ service = _SCNetworkServiceCreatePreconfigured(prefs, interface);
if (service == NULL) {
- SC_log(LOG_ERR, "could not create network service for \"%@\": %s",
- bsdName,
- SCErrorString(SCError()));
- continue;
- }
-
- // update network service to use a consistent serviceID
- serviceID = copyInterfaceUUID(bsdName);
- if (serviceID != NULL) {
- ok = _SCNetworkServiceSetServiceID(service, serviceID);
- CFRelease(serviceID);
- if (!ok) {
- SC_log(LOG_ERR, "_SCNetworkServiceSetServiceID() failed: %s",
- SCErrorString(SCError()));
- // ... and keep whatever random UUID was created for the service
- }
- } else {
- SC_log(LOG_ERR, "could not create serviceID for \"%@\"", bsdName);
- // ... and we'll use whatever random UUID was created for the service
- }
-
- // establish [template] configuration
- ok = SCNetworkServiceEstablishDefaultConfiguration(service);
- if (!ok) {
- SC_log(LOG_ERR, "could not establish network service for \"%@\": %s",
- bsdName,
- SCErrorString(SCError()));
- SCNetworkServiceRemove(service);
- CFRelease(service);
continue;
}
void *info)
{
#pragma unused(info)
- os_activity_t activity;
-
- activity = os_activity_create("processing [SC] preferences.plist changes",
- OS_ACTIVITY_CURRENT,
- OS_ACTIVITY_FLAG_DEFAULT);
- os_activity_scope(activity);
-
#if !TARGET_OS_IPHONE
if ((notificationType & kSCPreferencesNotificationCommit) == kSCPreferencesNotificationCommit) {
SCNetworkSetRef current;
/* add any [Apple] pre-configured network services */
updatePreConfiguredConfiguration(prefs);
+ /* remove any excluded network services */
+ excludeConfigurations(prefs);
+
/* update SCDynamicStore (Setup:) */
updateSCDynamicStore(prefs);
done :
- os_release(activity);
-
return;
}
}
+#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)
}
/* open a SCPreferences session */
-#ifndef MAIN
- prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL);
-#else // !MAIN
- prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist"));
-#endif // !MAIN
+ prefs = SCPreferencesCreateWithOptions(NULL,
+ MY_PLUGIN_ID,
+ PREFERENCES_MONITOR_PLIST,
+ NULL, // authorization
+ NULL);
if (prefs != NULL) {
Boolean need_update = FALSE;
- CFStringRef new_model;
+ 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);
- /* Need to regenerate the new configuration for new model */
- if (new_model != NULL) {
- CFStringRef old_model;
+ // save (and clean) the configuration that was created for "other" hardware
+ savePastConfiguration(old_model);
- old_model = SCPreferencesGetValue(prefs, MODEL);
- if (old_model != NULL && !_SC_CFEqual(old_model, new_model)) {
- // if new hardware
- need_update = TRUE;
- restorePrefs = previousConfigurationAvailable();
- }
+ // ... and we'll update the configuration later (when the IORegistry quiesces)
+ need_update = TRUE;
}
if (!need_update) {
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);