2 * Copyright (c) 2019, 2020 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * October 4, 2018 Allan Nathanson <ajn@apple.com>
32 #include "SCNetworkConfigurationInternal.h"
33 #include "SCPreferencesInternal.h"
34 #include <IOKit/IOBSD.h>
37 #define logDetails (_sc_log == kSCLogDestinationDefault) || _sc_debug
41 savePreferences(SCPreferencesRef prefs
,
42 CFStringRef save_prefsID
,
45 CFStringRef extra_key
,
46 CFPropertyListRef extra_value
)
48 const CFStringRef keys
[] = {
51 kSCPrefNetworkServices
,
55 kSCPrefVirtualNetworkInterfaces
58 SCPreferencesRef save_prefs
;
60 // open [companion] backup
61 save_prefs
= SCPreferencesCreateCompanion(prefs
, save_prefsID
);
63 for (CFIndex i
= 0; i
< (CFIndex
)(sizeof(keys
)/sizeof(keys
[0])); i
++) {
64 CFStringRef key
= keys
[i
];
68 src_key
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@%@"), prefix
, key
);
69 val
= SCPreferencesGetValue(prefs
, src_key
);
71 SCPreferencesSetValue(save_prefs
, key
, val
);
73 SCPreferencesRemoveValue(prefs
, src_key
);
79 if (extra_key
!= NULL
) {
80 SCPreferencesSetValue(save_prefs
, extra_key
, extra_value
);
83 ok
= SCPreferencesCommitChanges(save_prefs
);
84 CFRelease(save_prefs
);
86 SC_log(LOG_ERR
, "could not save preferences (%@): %s",
88 SCErrorString(SCError()));
96 __SCNetworkConfigurationBackup(SCPreferencesRef prefs
, CFStringRef suffix
, SCPreferencesRef relativeTo
)
98 SCPreferencesRef backup
;
99 CFMutableStringRef backupPrefsID
;
101 CFPropertyListRef plist
;
103 SCPreferencesPrivateRef sourcePrivate
= (SCPreferencesPrivateRef
)prefs
;
104 CFStringRef sourcePrefsID
;
106 SC_log(LOG_NOTICE
, "creating [%@] backup", suffix
);
108 sourcePrefsID
= (sourcePrivate
->prefsID
!= NULL
) ? sourcePrivate
->prefsID
: PREFS_DEFAULT_CONFIG
;
109 backupPrefsID
= CFStringCreateMutableCopy(NULL
, 0, sourcePrefsID
);
110 if (CFStringFindWithOptions(backupPrefsID
,
112 CFRangeMake(0, CFStringGetLength(backupPrefsID
)),
115 // if slash, remove path prefix
116 range
.length
= range
.location
+ 1;
118 CFStringReplace(backupPrefsID
, range
, CFSTR(""));
120 CFStringInsert(backupPrefsID
,
121 CFStringGetLength(backupPrefsID
) - sizeof(".plist") + 1,
123 CFStringInsert(backupPrefsID
,
124 CFStringGetLength(backupPrefsID
) - sizeof(".plist") + 1,
126 backup
= SCPreferencesCreateCompanion(relativeTo
, backupPrefsID
);
127 CFRelease(backupPrefsID
);
130 "__SCNetworkConfigurationBackup()"
138 if (backup
!= NULL
) {
139 plist
= SCPreferencesPathGetValue(prefs
, CFSTR("/"));
140 SCPreferencesPathSetValue(backup
, CFSTR("/"), plist
);
141 ok
= SCPreferencesCommitChanges(backup
);
150 __SCNetworkConfigurationSaveModel(SCPreferencesRef prefs
, CFStringRef model
)
153 CFStringRef save_prefsID
;
155 SC_log(LOG_NOTICE
, "creating [per-device] backup: %@", model
);
157 save_prefsID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("preferences-%@.plist"), model
);
158 ok
= savePreferences(prefs
, save_prefsID
, CFSTR(""), TRUE
, MODEL
, model
);
159 CFRelease(save_prefsID
);
165 needsUpdate(SCPreferencesRef prefs
, int new_version
)
171 // if no prefs, no updated needed
175 num
= SCPreferencesGetValue(prefs
, kSCPrefVersion
);
176 if (!isA_CFNumber(num
) ||
177 !CFNumberGetValue(num
, kCFNumberIntType
, &old_version
)) {
180 if (old_version
== new_version
) {
181 // if no update is needed
190 lockWithSync(SCPreferencesRef prefs
)
194 assert(prefs
!= NULL
);
195 ok
= SCPreferencesLock(prefs
, TRUE
);
196 if (!ok
&& (SCError() == kSCStatusStale
)) {
197 SCPreferencesSynchronize(prefs
);
198 ok
= SCPreferencesLock(prefs
, TRUE
);
206 __SCNetworkConfigurationUpgrade(SCPreferencesRef
*prefs_p
,
207 SCPreferencesRef
*ni_prefs_p
,
210 SCPreferencesRef ni_prefs
= NULL
;
211 Boolean ni_prefs_added
= FALSE
;
212 const int new_version
= NETWORK_CONFIGURATION_VERSION
;
215 SCPreferencesRef prefs
= NULL
;
216 Boolean prefs_added
= FALSE
;
219 // The following table describes how the SPI is called (input parameters), what actions
220 // are performed, and whether any changes should be committed as part of the call.
222 // +====================+===========================+===========================+========+
223 // | | preferences.plist | NetworkInterfaces.plist | |
224 // | +=============+=============+=============+=============+ COMMIT |
225 // | | ptr | plist | ptr | plist | |
226 // +====================+=============+=============+=============+=============+========+
227 // | InterfaceNamer | NULL | CREATE, REL | &ni_prefs | USE | YES |
228 // +====================+=============+=============+=============+=============+========+
229 // | PreferencesMonitor | &prefs | USE | NULL | NO UPDATE | YES |
230 // +====================+=============+=============+=============+=============+========+
231 // | scutil | &prefs | USE | &ni_prefs | USE/CREATE | NO |
232 // +====================+=============+=============+=============+=============+========+
234 // For InterfaceNamer, we are passed a reference to the SCPreferences[Ref] for the
235 // NetworkInterfaces.plist. During the upgrade process we create (and then release)
236 // the companion preferences.plist. Any needed changes will be committed to both
239 // For PreferencesMonitor, we are passed a reference to the SCPreferences[Ref] for
240 // the preferences.plist. Any needed changes to the plist will be committed. The
241 // companion NetworkInterfaces.plist is not passed nor is it referenced/modified.
243 // For scutil, we are passed references to the SCPreferences[Ref] for both the
244 // preferences.plist and NetworkInterfaces.plist. The NetworkInterfaces.plist
245 // reference will be used, if already open. Else, the companion will be created
246 // and returned. Regardless, any changes made will not be committed (we expect
247 // one to use scutil's "commit" command).
250 if (prefs_p
!= NULL
) {
254 if (ni_prefs_p
!= NULL
) {
255 ni_prefs
= *ni_prefs_p
;
258 if ((prefs_p
== NULL
) && (ni_prefs_p
!= NULL
) && (ni_prefs
!= NULL
)) {
259 // Here, we have been called by InterfaceNamer and need to get the [companion]
260 // preferences.plist (we need to update both)
261 prefs
= SCPreferencesCreateCompanion(ni_prefs
, NULL
);
264 "__SCNetworkConfigurationUpgrade(): could not open [preferences.plist]: %s",
265 SCErrorString(SCError()));
271 if ((prefs_p
!= NULL
) && (prefs
!= NULL
) && (ni_prefs_p
!= NULL
) && (ni_prefs
== NULL
)) {
272 // Here, we have been called by scutil with the [companion] NetworkInterfaces.plist
273 // not yet open. Open the companion so that we can update both.
274 ni_prefs
= SCPreferencesCreateCompanion(prefs
, INTERFACES_DEFAULT_CONFIG
);
275 if (ni_prefs
== NULL
) {
277 "__SCNetworkConfigurationUpgrade(): could not open [NetworkInterfaces.plist]: %s",
278 SCErrorString(SCError()));
281 ni_prefs_added
= TRUE
;
284 if (!needsUpdate(prefs
, NETWORK_CONFIGURATION_VERSION
) &&
285 !needsUpdate(ni_prefs
, NETWORK_CONFIGURATION_VERSION
)) {
289 // lock [preferences.plist] changes while we are updating
290 ok
= lockWithSync(prefs
);
293 "__SCNetworkConfigurationUpgrade(): could not lock [preferences.plist]: %s",
294 SCErrorString(SCError()));
298 if (ni_prefs
!= NULL
) {
299 // lock [NetworkInterfaces.plist] changes while we are updating
300 ok
= lockWithSync(ni_prefs
);
303 "__SCNetworkConfigurationUpgrade(): could not lock [NetworkInterfaces.plist]: %s",
304 SCErrorString(SCError()));
305 SCPreferencesUnlock(prefs
);
310 // first, cleanup any leftover cruft from the configuration
311 __SCNetworkConfigurationClean(prefs
, ni_prefs
);
313 // update the version(s)
314 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
315 SCPreferencesSetValue(prefs
, kSCPrefVersion
, num
);
317 if (ni_prefs
!= NULL
) {
318 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
319 SCPreferencesSetValue(ni_prefs
, kSCPrefVersion
, num
);
324 // commit the [preferences.plist] changes
325 ok
= SCPreferencesCommitChanges(prefs
);
328 "__SCNetworkConfigurationUpgrade(): update not saved [preferences.plist]: %s",
329 SCErrorString(SCError()));
332 ok
= SCPreferencesApplyChanges(prefs
);
335 "__SCNetworkConfigurationUpgrade(): update not applied [preferences.plist]: %s",
336 SCErrorString(SCError()));
340 SCPreferencesUnlock(prefs
);
342 if (ni_prefs
!= NULL
) {
344 // commit the [NetworkInterfaces.plist] changes
346 ok
= SCPreferencesCommitChanges(ni_prefs
);
349 "__SCNetworkConfigurationUpgrade(): update not saved [NetworkInterfaces.plist]: %s",
350 SCErrorString(SCError()));
354 SCPreferencesUnlock(ni_prefs
);
360 // per the expected usage, even if we on-the-fly create
361 // a [preferences.plist] companion it is not returned to
362 // the caller. So, just release.
366 if (ni_prefs_added
) {
367 if (ok
&& (ni_prefs_p
!= NULL
)) {
368 *ni_prefs_p
= CFRetain(ni_prefs
);
378 #pragma mark Remove "Hidden" Interface Configurations
382 isThin(CFArrayRef interfaces
, CFStringRef bsdName
)
386 thin
= CFArrayContainsValue(interfaces
,
387 CFRangeMake(0, CFArrayGetCount(interfaces
)),
394 thinAdd(CFMutableArrayRef interfaces
, CFStringRef bsdName
)
396 if (!CFArrayContainsValue(interfaces
,
397 CFRangeMake(0, CFArrayGetCount(interfaces
)),
399 CFArrayAppendValue(interfaces
, bsdName
);
408 thinRemove(CFMutableArrayRef interfaces
, CFStringRef bsdName
)
412 n
= CFArrayGetFirstIndexOfValue(interfaces
,
413 CFRangeMake(0, CFArrayGetCount(interfaces
)),
415 if (n
!= kCFNotFound
) {
416 CFArrayRemoveValueAtIndex(interfaces
, n
);
424 static CF_RETURNS_RETAINED CFStringRef
425 serviceMatchesTemplate(SCPreferencesRef prefs
, SCNetworkServiceRef existingService
)
427 CFStringRef conflict
= NULL
;
428 SCNetworkInterfaceRef existingInterface
;
430 CFArrayRef protocols
;
431 CFMutableArrayRef protocolTypes
;
432 SCNetworkServiceRef templateService
;
434 // create a temporary network service (so that we can get the template configuration)
435 existingInterface
= SCNetworkServiceGetInterface(existingService
);
436 if (existingInterface
== NULL
) {
437 conflict
= CFStringCreateCopy(NULL
, CFSTR("could not get interface for service"));
441 templateService
= SCNetworkServiceCreate(prefs
, existingInterface
);
442 if (templateService
== NULL
) {
443 conflict
= CFStringCreateCopy(NULL
, CFSTR("could not create service for interface"));
447 (void) SCNetworkServiceEstablishDefaultConfiguration(templateService
);
449 protocolTypes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
451 // get protocol types from the existing service
452 protocols
= SCNetworkServiceCopyProtocols(existingService
);
453 if (protocols
!= NULL
) {
454 n
= CFArrayGetCount(protocols
);
456 for (CFIndex i
= 0; i
< n
; i
++) {
457 SCNetworkProtocolRef protocol
;
458 CFStringRef protocolType
;
460 protocol
= CFArrayGetValueAtIndex(protocols
, i
);
461 protocolType
= SCNetworkProtocolGetProtocolType(protocol
);
462 if (!CFArrayContainsValue(protocolTypes
,
463 CFRangeMake(0, CFArrayGetCount(protocolTypes
)),
465 CFArrayAppendValue(protocolTypes
, protocolType
);
469 CFRelease(protocols
);
472 // get protocol types from the template service
473 protocols
= SCNetworkServiceCopyProtocols(templateService
);
474 if (protocols
!= NULL
) {
475 n
= CFArrayGetCount(protocols
);
477 for (CFIndex i
= 0; i
< n
; i
++) {
478 SCNetworkProtocolRef protocol
;
479 CFStringRef protocolType
;
481 protocol
= CFArrayGetValueAtIndex(protocols
, i
);
482 protocolType
= SCNetworkProtocolGetProtocolType(protocol
);
483 if (!CFArrayContainsValue(protocolTypes
,
484 CFRangeMake(0, CFArrayGetCount(protocolTypes
)),
486 CFArrayAppendValue(protocolTypes
, protocolType
);
490 CFRelease(protocols
);
493 // compare the existing protocols with the template
494 n
= CFArrayGetCount(protocolTypes
);
495 for (CFIndex i
= 0; i
< n
; i
++) {
496 CFDictionaryRef existingConfiguration
= NULL
;
497 SCNetworkProtocolRef existingProtocol
;
499 CFStringRef protocolType
;
500 CFDictionaryRef templateConfiguration
= NULL
;
501 SCNetworkProtocolRef templateProtocol
;
503 protocolType
= CFArrayGetValueAtIndex(protocolTypes
, i
);
504 existingProtocol
= SCNetworkServiceCopyProtocol(existingService
, protocolType
);
505 templateProtocol
= SCNetworkServiceCopyProtocol(templateService
, protocolType
);
509 match
= ((existingProtocol
!= NULL
) &&
510 (templateProtocol
!= NULL
) &&
511 (SCNetworkProtocolGetEnabled(existingProtocol
) == SCNetworkProtocolGetEnabled(templateProtocol
)));
513 conflict
= CFStringCreateWithFormat(NULL
, NULL
,
514 CFSTR("conflicting %@ enable/disable"),
516 break; // if enable/disable conflict
519 if (existingProtocol
!= NULL
) {
520 existingConfiguration
= SCNetworkProtocolGetConfiguration(existingProtocol
);
522 if (templateProtocol
!= NULL
) {
523 templateConfiguration
= SCNetworkProtocolGetConfiguration(templateProtocol
);
525 match
= _SC_CFEqual(existingConfiguration
, templateConfiguration
);
527 conflict
= CFStringCreateWithFormat(NULL
, NULL
,
528 CFSTR("conflicting %@ configuration"),
530 break; // if configuration conflict
534 if (existingProtocol
!= NULL
) CFRelease(existingProtocol
);
535 if (templateProtocol
!= NULL
) CFRelease(templateProtocol
);
541 (void) SCNetworkServiceRemove(templateService
);
542 CFRelease(templateService
);
543 CFRelease(protocolTypes
);
549 effectivelyHiddenConfiguration(SCNetworkInterfaceRef interface
)
551 const CFStringRef known
[] = {
560 name
= SCNetworkInterfaceGetLocalizedDisplayName(interface
);
561 for (int i
= 0; i
< (int)(sizeof(known
) / sizeof(known
[0])); i
++) {
562 if (CFStringHasPrefix(name
, known
[i
])) {
572 __SCNetworkConfigurationCleanHiddenInterfaces(SCPreferencesRef prefs
, SCPreferencesRef ni_prefs
)
574 #pragma unused(prefs)
575 #pragma unused(ni_prefs)
577 Boolean changed
= FALSE
;
578 CFArrayRef interfaces
;
579 CFMutableArrayRef interfaces_thin
;
582 CFDictionaryRef nat_config
;
583 SCPreferencesRef nat_prefs
;
584 #endif // TARGET_OS_OSX
588 // build a list of interfaces we "could" remove
590 interfaces_thin
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
592 services
= SCNetworkServiceCopyAll(prefs
);
593 if (services
!= NULL
) {
594 n
= CFArrayGetCount(services
);
595 for (CFIndex i
= 0; i
< n
; i
++) {
596 CFStringRef conflict
;
597 SCNetworkInterfaceRef interface
;
598 SCNetworkServiceRef service
;
599 const char *thin
= NULL
;
601 service
= CFArrayGetValueAtIndex(services
, i
);
602 interface
= SCNetworkServiceGetInterface(service
);
603 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
605 if (bsdName
== NULL
) {
606 // if no interface name
609 "skipping service : %@ : %@ (no interface)",
610 SCNetworkServiceGetServiceID(service
),
611 SCNetworkServiceGetName(service
));
616 if (_SCNetworkInterfaceIsHiddenConfiguration(interface
)) {
618 } else if (effectivelyHiddenConfiguration(interface
)) {
619 thin
= "effectively hidden";
621 // if not HiddenConfiguration
624 "skipping service : %@ : %@ : %@ (not hidden)",
625 SCNetworkServiceGetServiceID(service
),
626 SCNetworkServiceGetName(service
),
632 conflict
= serviceMatchesTemplate(prefs
, service
);
633 if (conflict
!= NULL
) {
634 // if any part of the service's configuration was changed
637 "skipping service : %@ : %@ : %@ (%s, non-default, %@)",
638 SCNetworkServiceGetServiceID(service
),
639 SCNetworkServiceGetName(service
),
649 SC_log(LOG_INFO
, "candidate interface : %@ (%s)", bsdName
, thin
);
652 thinAdd(interfaces_thin
, bsdName
);
656 // remove any virtual interfaces from the list
658 #if !TARGET_OS_IPHONE
659 interfaces
= SCBondInterfaceCopyAll(prefs
);
660 if (interfaces
!= NULL
) {
663 n
= CFArrayGetCount(interfaces
);
664 for (CFIndex i
= 0; i
< n
; i
++) {
665 SCBondInterfaceRef bondInterface
;
669 bondInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
670 members
= SCBondInterfaceGetMemberInterfaces(bondInterface
);
671 nn
= (members
!= NULL
) ? CFArrayGetCount(members
) : 0;
672 for (CFIndex ii
= 0; ii
< nn
; ii
++) {
673 SCNetworkInterfaceRef member
;
675 member
= CFArrayGetValueAtIndex(members
, ii
);
676 bsdName
= SCNetworkInterfaceGetBSDName(member
);
677 if ((bsdName
!= NULL
) &&
678 thinRemove(interfaces_thin
, bsdName
)) {
680 SC_log(LOG_INFO
, "skipping interface : %@ (bond member)", bsdName
);
686 CFRelease(interfaces
);
688 #endif // !TARGET_OS_IPHONE
690 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
691 if (interfaces
!= NULL
) {
694 n
= CFArrayGetCount(interfaces
);
695 for (CFIndex i
= 0; i
< n
; i
++) {
696 SCBridgeInterfaceRef bridgeInterface
;
700 bridgeInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
701 members
= SCBridgeInterfaceGetMemberInterfaces(bridgeInterface
);
702 nn
= (members
!= NULL
) ? CFArrayGetCount(members
) : 0;
703 for (CFIndex ii
= 0; ii
< nn
; ii
++) {
704 SCNetworkInterfaceRef member
;
706 member
= CFArrayGetValueAtIndex(members
, ii
);
707 bsdName
= SCNetworkInterfaceGetBSDName(member
);
708 if ((bsdName
!= NULL
) &&
709 thinRemove(interfaces_thin
, bsdName
)) {
711 SC_log(LOG_INFO
, "skipping interface : %@ (bridge member)", bsdName
);
717 CFRelease(interfaces
);
720 interfaces
= SCVLANInterfaceCopyAll(prefs
);
721 if (interfaces
!= NULL
) {
724 n
= CFArrayGetCount(interfaces
);
725 for (CFIndex i
= 0; i
< n
; i
++) {
726 SCBridgeInterfaceRef vlanInterface
;
727 SCNetworkInterfaceRef physicalInterface
;
729 vlanInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
730 physicalInterface
= SCVLANInterfaceGetPhysicalInterface(vlanInterface
);
731 bsdName
= SCNetworkInterfaceGetBSDName(physicalInterface
);
732 if ((bsdName
!= NULL
) &&
733 thinRemove(interfaces_thin
, bsdName
)) {
735 SC_log(LOG_INFO
, "skipping interface : %@ (vlan physical)", bsdName
);
740 CFRelease(interfaces
);
743 // remove any "shared" interfaces from the list
746 nat_prefs
= SCPreferencesCreateCompanion(prefs
, CFSTR("com.apple.nat.plist"));
747 nat_config
= SCPreferencesGetValue(nat_prefs
, CFSTR("NAT"));
748 if (isA_CFDictionary(nat_config
)) {
749 CFBooleanRef bVal
= NULL
;
750 Boolean enabled
= FALSE
;
751 CFStringRef sharedFrom
= NULL
;
752 CFArrayRef sharedTo
= NULL
;
754 if (CFDictionaryGetValueIfPresent(nat_config
,
756 (const void **)&bVal
) &&
757 isA_CFBoolean(bVal
)) {
758 enabled
= CFBooleanGetValue(bVal
);
762 CFDictionaryGetValueIfPresent(nat_config
,
763 CFSTR("PrimaryService"),
764 (const void **)&sharedFrom
) &&
765 isA_CFString(sharedFrom
)) {
766 SCNetworkInterfaceRef interface
;
767 SCNetworkServiceRef service
;
769 // if "Share your connection from" service configured
770 service
= SCNetworkServiceCopy(prefs
, sharedFrom
);
771 if (service
!= NULL
) {
772 interface
= SCNetworkServiceGetInterface(service
);
773 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
774 if ((bsdName
!= NULL
) &&
775 thinRemove(interfaces_thin
, bsdName
)) {
777 SC_log(LOG_INFO
, "skipping interface : %@ (Share your connection from)", bsdName
);
782 SC_log(LOG_INFO
, "keeping [not found] service : %@ (Share your connection from)", sharedFrom
);
787 CFDictionaryGetValueIfPresent(nat_config
,
788 CFSTR("SharingDevices"),
789 (const void **)&sharedTo
) &&
790 isA_CFArray(sharedTo
)) {
791 // if "To computers using" interfaces configured
792 n
= CFArrayGetCount(sharedTo
);
793 for (CFIndex i
= 0; i
< n
; i
++) {
794 bsdName
= CFArrayGetValueAtIndex(sharedTo
, i
);
795 if (thinRemove(interfaces_thin
, bsdName
)) {
797 SC_log(LOG_INFO
, "skipping interface : %@ (To computers using)", bsdName
);
803 CFRelease(nat_prefs
);
804 #endif // TARGET_OS_OSX
806 // thin preferences.plist
807 n
= (services
!= NULL
) ? CFArrayGetCount(services
) : 0;
811 for (CFIndex i
= 0; i
< n
; i
++) {
812 SCNetworkInterfaceRef interface
;
813 SCNetworkServiceRef service
;
815 service
= CFArrayGetValueAtIndex(services
, i
);
816 interface
= SCNetworkServiceGetInterface(service
);
817 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
818 if (bsdName
== NULL
) {
819 // if no interface name
823 if (!isThin(interfaces_thin
, bsdName
)) {
828 // remove this service associated with a "thinned" interface
829 if (logDetails
|| _sc_verbose
) {
831 "thinned network service : %@ : %@ : %@",
832 SCNetworkServiceGetServiceID(service
),
833 SCNetworkServiceGetName(service
),
836 SCNetworkServiceRemove(service
);
843 "Updating \"preferences.plist\" (thinned %d service%s)",
845 (updated
!= 1) ? "s" : "");
851 // thin NetworkInterfaces.plist
852 interfaces
= SCPreferencesGetValue(ni_prefs
, INTERFACES
);
853 interfaces
= isA_CFArray(interfaces
);
854 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
856 CFMutableArrayRef interfaces_new
;
860 interfaces_new
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
861 n
= CFArrayGetCount(interfaces
);
862 for (CFIndex i
= 0; i
< n
; i
++) {
863 CFDictionaryRef if_dict
;
865 if_dict
= CFArrayGetValueAtIndex(interfaces
, i
);
866 bsdName
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
867 if (isThin(interfaces_thin
, bsdName
)) {
868 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
870 SC_log(LOG_INFO
, "skipping interface : %@ (active)", bsdName
);
873 // remove this "thinned" interface
874 if (logDetails
|| _sc_verbose
) {
875 SC_log(LOG_INFO
, "thinned network interface : %@", bsdName
);
882 CFArrayAppendValue(interfaces_new
, if_dict
);
884 SCPreferencesSetValue(ni_prefs
, INTERFACES
, interfaces_new
);
885 CFRelease(interfaces_new
);
890 "Updating \"NetworkInterfaces.plist\" (thinned %d interface%s)",
892 (updated
!= 1) ? "s" : "");
898 if (services
!= NULL
) CFRelease(services
);
899 CFRelease(interfaces_thin
);
905 #pragma mark Remove [SCNetworkMigration] Inline Backups
909 thinInlineBackup(const void *value
, void *context
)
911 CFStringRef backup
= (CFStringRef
)value
;
913 SCPreferencesRef prefs
= (SCPreferencesRef
)context
;
914 CFStringRef save_prefix
;
915 CFStringRef save_prefsID
= NULL
;
917 SC_log(LOG_NOTICE
, "thinning [inline] backup: %@", backup
);
919 save_prefix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@ : "), backup
);
920 backup_str
= _SC_cfstring_to_cstring(backup
, NULL
, 0, kCFStringEncodingASCII
);
921 if (backup_str
!= NULL
) {
922 struct tm save_tm
= { 0 };
924 if (strptime(backup_str
, "%Y-%m-%d %H:%M:%S", &save_tm
) != NULL
) {
925 save_prefsID
= CFStringCreateWithFormat(NULL
,
927 CFSTR("preferences-%4d-%02d-%02d-%02d%02d%02d.plist"),
928 save_tm
.tm_year
+ 1900,
935 CFAllocatorDeallocate(NULL
, backup_str
);
937 if (save_prefsID
== NULL
) {
938 save_prefsID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("preferences-%@.plist"), backup
);
940 savePreferences(prefs
, save_prefsID
, save_prefix
, TRUE
, NULL
, NULL
);
941 CFRelease(save_prefsID
);
942 CFRelease(save_prefix
);
948 __SCNetworkConfigurationCleanInlineBackups(SCPreferencesRef prefs
)
950 CFMutableSetRef backups
= NULL
;
951 Boolean cleaned
= FALSE
;
956 keys
= SCPreferencesCopyKeyList(prefs
);
961 suffix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR(" : %@"), kSCPrefSets
);
962 n
= CFArrayGetCount(keys
);
963 for (CFIndex i
= 0; i
< n
; i
++) {
964 CFStringRef key
= CFArrayGetValueAtIndex(keys
, i
);
965 CFMutableStringRef str
;
967 if (CFStringHasSuffix(key
, suffix
)) {
968 // if "<backup-date> : Sets"
969 if (backups
== NULL
) {
970 backups
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
972 str
= CFStringCreateMutableCopy(NULL
, 0, key
);
973 CFStringTrim(str
, suffix
);
974 CFSetAddValue(backups
, str
);
982 if (backups
!= NULL
) {
983 CFSetApplyFunction(backups
, thinInlineBackup
, (void *)prefs
);
993 #pragma mark Remove [new device type] Inline Backups
997 thinInlineModel(const void *value
, void *context
)
999 CFStringRef model
= (CFStringRef
)value
;
1000 SCPreferencesRef prefs
= (SCPreferencesRef
)context
;
1001 CFStringRef save_prefix
;
1002 CFStringRef save_prefsID
;
1004 SC_log(LOG_NOTICE
, "thinning [per-model] backup: %@", model
);
1006 save_prefix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:"), model
);
1007 save_prefsID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("preferences-%@.plist"), model
);
1008 savePreferences(prefs
, save_prefsID
, save_prefix
, TRUE
, MODEL
, model
);
1009 CFRelease(save_prefsID
);
1010 CFRelease(save_prefix
);
1016 __SCNetworkConfigurationCleanInlineModels(SCPreferencesRef prefs
)
1018 Boolean cleaned
= FALSE
;
1020 CFMutableSetRef models
= NULL
;
1024 keys
= SCPreferencesCopyKeyList(prefs
);
1029 suffix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR(":%@"), kSCPrefSets
);
1030 n
= CFArrayGetCount(keys
);
1031 for (CFIndex i
= 0; i
< n
; i
++) {
1032 CFStringRef key
= CFArrayGetValueAtIndex(keys
, i
);
1033 CFMutableStringRef str
;
1035 if (CFStringHasSuffix(key
, suffix
)) {
1036 // if "<backup-date> : Sets"
1037 if (models
== NULL
) {
1038 models
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1040 str
= CFStringCreateMutableCopy(NULL
, 0, key
);
1041 CFStringTrim(str
, suffix
);
1042 CFSetAddValue(models
, str
);
1050 if (models
!= NULL
) {
1051 CFSetApplyFunction(models
, thinInlineModel
, (void *)prefs
);
1061 #pragma mark Remove Orphaned Services
1066 __SCNetworkConfigurationCleanOrphanedServices(SCPreferencesRef prefs)
1068 #pragma unused(prefs)
1075 #pragma mark Cleanup network service order issues
1079 __SCNetworkConfigurationCleanServiceOrderIssues(SCPreferencesRef prefs
)
1081 #pragma unused(prefs)
1082 Boolean cleaned
= FALSE
;
1086 sets
= SCNetworkSetCopyAll(prefs
);
1087 nSets
= (sets
!= NULL
) ? CFArrayGetCount(sets
) : 0;
1088 for (CFIndex iSets
= 0; iSets
< nSets
; iSets
++) {
1090 CFMutableSetRef known
= NULL
;
1092 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, iSets
);
1093 CFStringRef setID
= SCNetworkSetGetSetID(set
);
1094 CFArrayRef order
= SCNetworkSetGetServiceOrder(set
);
1095 CFMutableArrayRef newOrder
= NULL
;
1098 nServices
= (order
!= NULL
) ? CFArrayGetCount(order
) : 0;
1099 if (nServices
> 0) {
1100 known
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1101 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
1104 while (iServices
< nServices
) {
1105 SCNetworkServiceRef service
;
1106 CFStringRef serviceID
= CFArrayGetValueAtIndex(newOrder
, iServices
);
1108 // check if serviceID already known/processed
1109 if (CFSetContainsValue(known
, serviceID
)) {
1110 // if duplicate/removed service, remove from serviceOrder
1113 "set: %@, removing serviceID %@ (duplicate/removed)",
1117 CFArrayRemoveValueAtIndex(newOrder
, iServices
);
1123 // track this serviceID as known, already removed, or removed below
1124 CFSetAddValue(known
, serviceID
);
1126 // validate serviceID
1127 service
= SCNetworkServiceCopy(prefs
, serviceID
);
1128 if (service
== NULL
) {
1129 // if no service, remove from serviceOrder
1132 "set: %@, removing serviceID %@ (no service)",
1136 CFArrayRemoveValueAtIndex(newOrder
, iServices
);
1142 if (!__SCNetworkServiceExists(service
)) {
1143 // if service already removed, remove from serviceOrder
1146 "set: %@, removing serviceID %@ (service already removed)",
1150 CFArrayRemoveValueAtIndex(newOrder
, iServices
);
1161 if (known
!= NULL
) {
1165 if (newOrder
!= NULL
) {
1167 SCNetworkSetSetServiceOrder(set
, newOrder
);
1169 CFRelease(newOrder
);
1182 #pragma mark Cleanup Network Configuration(s)
1186 __SCNetworkConfigurationClean(SCPreferencesRef prefs
, SCPreferencesRef ni_prefs
)
1189 Boolean updated
= FALSE
;
1191 changed
= __SCNetworkConfigurationCleanInlineBackups(prefs
);
1193 SC_log(LOG_NOTICE
, "network configuration: unwanted inline backups removed");
1197 changed
= __SCNetworkConfigurationCleanInlineModels(prefs
);
1199 SC_log(LOG_NOTICE
, "network configuration: unwanted device backups removed");
1203 if (ni_prefs
!= NULL
) {
1204 changed
= __SCNetworkConfigurationCleanHiddenInterfaces(prefs
, ni_prefs
);
1206 SC_log(LOG_NOTICE
, "network configuration: hidden interface configurations removed");
1211 changed
= __SCNetworkConfigurationCleanServiceOrderIssues(prefs
);
1213 SC_log(LOG_NOTICE
, "network configuration: ServiceOrder cleaned");