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
);
128 if (backup
!= NULL
) {
129 plist
= SCPreferencesPathGetValue(prefs
, CFSTR("/"));
130 SCPreferencesPathSetValue(backup
, CFSTR("/"), plist
);
131 ok
= SCPreferencesCommitChanges(backup
);
140 __SCNetworkConfigurationSaveModel(SCPreferencesRef prefs
, CFStringRef model
)
143 CFStringRef save_prefsID
;
145 SC_log(LOG_NOTICE
, "creating [per-device] backup: %@", model
);
147 save_prefsID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("preferences-%@.plist"), model
);
148 ok
= savePreferences(prefs
, save_prefsID
, CFSTR(""), TRUE
, MODEL
, model
);
149 CFRelease(save_prefsID
);
155 needsUpdate(SCPreferencesRef prefs
, int new_version
)
161 // if no prefs, no updated needed
165 num
= SCPreferencesGetValue(prefs
, kSCPrefVersion
);
166 if (!isA_CFNumber(num
) ||
167 !CFNumberGetValue(num
, kCFNumberIntType
, &old_version
)) {
170 if (old_version
== new_version
) {
171 // if no update is needed
180 lockWithSync(SCPreferencesRef prefs
)
184 assert(prefs
!= NULL
);
185 ok
= SCPreferencesLock(prefs
, TRUE
);
186 if (!ok
&& (SCError() == kSCStatusStale
)) {
187 SCPreferencesSynchronize(prefs
);
188 ok
= SCPreferencesLock(prefs
, TRUE
);
196 __SCNetworkConfigurationUpgrade(SCPreferencesRef
*prefs_p
,
197 SCPreferencesRef
*ni_prefs_p
,
200 SCPreferencesRef ni_prefs
= NULL
;
201 Boolean ni_prefs_added
= FALSE
;
202 const int new_version
= NETWORK_CONFIGURATION_VERSION
;
205 SCPreferencesRef prefs
= NULL
;
206 Boolean prefs_added
= FALSE
;
209 // The following table describes how the SPI is called (input parameters), what actions
210 // are performed, and whether any changes should be committed as part of the call.
212 // +====================+===========================+===========================+========+
213 // | | preferences.plist | NetworkInterfaces.plist | |
214 // | +=============+=============+=============+=============+ COMMIT |
215 // | | ptr | plist | ptr | plist | |
216 // +====================+=============+=============+=============+=============+========+
217 // | InterfaceNamer | NULL | CREATE, REL | &ni_prefs | USE | YES |
218 // +====================+=============+=============+=============+=============+========+
219 // | PreferencesMonitor | &prefs | USE | NULL | NO UPDATE | YES |
220 // +====================+=============+=============+=============+=============+========+
221 // | scutil | &prefs | USE | &ni_prefs | USE/CREATE | NO |
222 // +====================+=============+=============+=============+=============+========+
224 // For InterfaceNamer, we are passed a reference to the SCPreferences[Ref] for the
225 // NetworkInterfaces.plist. During the upgrade process we create (and then release)
226 // the companion preferences.plist. Any needed changes will be committed to both
229 // For PreferencesMonitor, we are passed a reference to the SCPreferences[Ref] for
230 // the preferences.plist. Any needed changes to the plist will be committed. The
231 // companion NetworkInterfaces.plist is not passed nor is it referenced/modified.
233 // For scutil, we are passed references to the SCPreferences[Ref] for both the
234 // preferences.plist and NetworkInterfaces.plist. The NetworkInterfaces.plist
235 // reference will be used, if already open. Else, the companion will be created
236 // and returned. Regardless, any changes made will not be committed (we expect
237 // one to use scutil's "commit" command).
240 if (prefs_p
!= NULL
) {
244 if (ni_prefs_p
!= NULL
) {
245 ni_prefs
= *ni_prefs_p
;
248 if ((prefs_p
== NULL
) && (ni_prefs_p
!= NULL
) && (ni_prefs
!= NULL
)) {
249 // Here, we have been called by InterfaceNamer and need to get the [companion]
250 // preferences.plist (we need to update both)
251 prefs
= SCPreferencesCreateCompanion(ni_prefs
, NULL
);
254 "__SCNetworkConfigurationUpgrade(): could not open [preferences.plist]: %s",
255 SCErrorString(SCError()));
261 if ((prefs_p
!= NULL
) && (prefs
!= NULL
) && (ni_prefs_p
!= NULL
) && (ni_prefs
== NULL
)) {
262 // Here, we have been called by scutil with the [companion] NetworkInterfaces.plist
263 // not yet open. Open the companion so that we can update both.
264 ni_prefs
= SCPreferencesCreateCompanion(prefs
, INTERFACES_DEFAULT_CONFIG
);
265 if (ni_prefs
== NULL
) {
267 "__SCNetworkConfigurationUpgrade(): could not open [NetworkInterfaces.plist]: %s",
268 SCErrorString(SCError()));
271 ni_prefs_added
= TRUE
;
274 if (!needsUpdate(prefs
, NETWORK_CONFIGURATION_VERSION
) &&
275 !needsUpdate(ni_prefs
, NETWORK_CONFIGURATION_VERSION
)) {
279 // lock [preferences.plist] changes while we are updating
280 ok
= lockWithSync(prefs
);
283 "__SCNetworkConfigurationUpgrade(): could not lock [preferences.plist]: %s",
284 SCErrorString(SCError()));
288 if (ni_prefs
!= NULL
) {
289 // lock [NetworkInterfaces.plist] changes while we are updating
290 ok
= lockWithSync(ni_prefs
);
293 "__SCNetworkConfigurationUpgrade(): could not lock [NetworkInterfaces.plist]: %s",
294 SCErrorString(SCError()));
295 SCPreferencesUnlock(prefs
);
300 // first, cleanup any leftover cruft from the configuration
301 __SCNetworkConfigurationClean(prefs
, ni_prefs
);
303 // update the version(s)
304 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
305 SCPreferencesSetValue(prefs
, kSCPrefVersion
, num
);
307 if (ni_prefs
!= NULL
) {
308 num
= CFNumberCreate(NULL
, kCFNumberIntType
, &new_version
);
309 SCPreferencesSetValue(ni_prefs
, kSCPrefVersion
, num
);
314 // commit the [preferences.plist] changes
315 ok
= SCPreferencesCommitChanges(prefs
);
318 "__SCNetworkConfigurationUpgrade(): update not saved [preferences.plist]: %s",
319 SCErrorString(SCError()));
322 ok
= SCPreferencesApplyChanges(prefs
);
325 "__SCNetworkConfigurationUpgrade(): update not applied [preferences.plist]: %s",
326 SCErrorString(SCError()));
330 SCPreferencesUnlock(prefs
);
332 if (ni_prefs
!= NULL
) {
334 // commit the [NetworkInterfaces.plist] changes
336 ok
= SCPreferencesCommitChanges(ni_prefs
);
339 "__SCNetworkConfigurationUpgrade(): update not saved [NetworkInterfaces.plist]: %s",
340 SCErrorString(SCError()));
344 SCPreferencesUnlock(ni_prefs
);
350 // per the expected usage, even if we on-the-fly create
351 // a [preferences.plist] companion it is not returned to
352 // the caller. So, just release.
356 if (ni_prefs_added
) {
357 if (ok
&& (ni_prefs_p
!= NULL
)) {
358 *ni_prefs_p
= CFRetain(ni_prefs
);
368 #pragma mark Remove "Hidden" Interface Configurations
372 isThin(CFArrayRef interfaces
, CFStringRef bsdName
)
376 thin
= CFArrayContainsValue(interfaces
,
377 CFRangeMake(0, CFArrayGetCount(interfaces
)),
384 thinAdd(CFMutableArrayRef interfaces
, CFStringRef bsdName
)
386 if (!CFArrayContainsValue(interfaces
,
387 CFRangeMake(0, CFArrayGetCount(interfaces
)),
389 CFArrayAppendValue(interfaces
, bsdName
);
398 thinRemove(CFMutableArrayRef interfaces
, CFStringRef bsdName
)
402 n
= CFArrayGetFirstIndexOfValue(interfaces
,
403 CFRangeMake(0, CFArrayGetCount(interfaces
)),
405 if (n
!= kCFNotFound
) {
406 CFArrayRemoveValueAtIndex(interfaces
, n
);
414 static CF_RETURNS_RETAINED CFStringRef
415 serviceMatchesTemplate(SCPreferencesRef prefs
, SCNetworkServiceRef existingService
)
417 CFStringRef conflict
= NULL
;
418 SCNetworkInterfaceRef existingInterface
;
420 CFArrayRef protocols
;
421 CFMutableArrayRef protocolTypes
;
422 SCNetworkServiceRef templateService
;
424 // create a temporary network service (so that we can get the template configuration)
425 existingInterface
= SCNetworkServiceGetInterface(existingService
);
426 if (existingInterface
== NULL
) {
427 conflict
= CFStringCreateCopy(NULL
, CFSTR("could not get interface for service"));
431 templateService
= SCNetworkServiceCreate(prefs
, existingInterface
);
432 if (templateService
== NULL
) {
433 conflict
= CFStringCreateCopy(NULL
, CFSTR("could not create service for interface"));
437 (void) SCNetworkServiceEstablishDefaultConfiguration(templateService
);
439 protocolTypes
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
441 // get protocol types from the existing service
442 protocols
= SCNetworkServiceCopyProtocols(existingService
);
443 if (protocols
!= NULL
) {
444 n
= CFArrayGetCount(protocols
);
446 for (CFIndex i
= 0; i
< n
; i
++) {
447 SCNetworkProtocolRef protocol
;
448 CFStringRef protocolType
;
450 protocol
= CFArrayGetValueAtIndex(protocols
, i
);
451 protocolType
= SCNetworkProtocolGetProtocolType(protocol
);
452 if (!CFArrayContainsValue(protocolTypes
,
453 CFRangeMake(0, CFArrayGetCount(protocolTypes
)),
455 CFArrayAppendValue(protocolTypes
, protocolType
);
459 CFRelease(protocols
);
462 // get protocol types from the template service
463 protocols
= SCNetworkServiceCopyProtocols(templateService
);
464 if (protocols
!= NULL
) {
465 n
= CFArrayGetCount(protocols
);
467 for (CFIndex i
= 0; i
< n
; i
++) {
468 SCNetworkProtocolRef protocol
;
469 CFStringRef protocolType
;
471 protocol
= CFArrayGetValueAtIndex(protocols
, i
);
472 protocolType
= SCNetworkProtocolGetProtocolType(protocol
);
473 if (!CFArrayContainsValue(protocolTypes
,
474 CFRangeMake(0, CFArrayGetCount(protocolTypes
)),
476 CFArrayAppendValue(protocolTypes
, protocolType
);
480 CFRelease(protocols
);
483 // compare the existing protocols with the template
484 n
= CFArrayGetCount(protocolTypes
);
485 for (CFIndex i
= 0; i
< n
; i
++) {
486 CFDictionaryRef existingConfiguration
= NULL
;
487 SCNetworkProtocolRef existingProtocol
;
489 CFStringRef protocolType
;
490 CFDictionaryRef templateConfiguration
= NULL
;
491 SCNetworkProtocolRef templateProtocol
;
493 protocolType
= CFArrayGetValueAtIndex(protocolTypes
, i
);
494 existingProtocol
= SCNetworkServiceCopyProtocol(existingService
, protocolType
);
495 templateProtocol
= SCNetworkServiceCopyProtocol(templateService
, protocolType
);
499 match
= ((existingProtocol
!= NULL
) &&
500 (templateProtocol
!= NULL
) &&
501 (SCNetworkProtocolGetEnabled(existingProtocol
) == SCNetworkProtocolGetEnabled(templateProtocol
)));
503 conflict
= CFStringCreateWithFormat(NULL
, NULL
,
504 CFSTR("conflicting %@ enable/disable"),
506 break; // if enable/disable conflict
509 if (existingProtocol
!= NULL
) {
510 existingConfiguration
= SCNetworkProtocolGetConfiguration(existingProtocol
);
512 if (templateProtocol
!= NULL
) {
513 templateConfiguration
= SCNetworkProtocolGetConfiguration(templateProtocol
);
515 match
= _SC_CFEqual(existingConfiguration
, templateConfiguration
);
517 conflict
= CFStringCreateWithFormat(NULL
, NULL
,
518 CFSTR("conflicting %@ configuration"),
520 break; // if configuration conflict
524 if (existingProtocol
!= NULL
) CFRelease(existingProtocol
);
525 if (templateProtocol
!= NULL
) CFRelease(templateProtocol
);
531 (void) SCNetworkServiceRemove(templateService
);
532 CFRelease(templateService
);
533 CFRelease(protocolTypes
);
539 effectivelyHiddenConfiguration(SCNetworkInterfaceRef interface
)
541 const CFStringRef known
[] = {
550 name
= SCNetworkInterfaceGetLocalizedDisplayName(interface
);
551 for (int i
= 0; i
< (int)(sizeof(known
) / sizeof(known
[0])); i
++) {
552 if (CFStringHasPrefix(name
, known
[i
])) {
562 __SCNetworkConfigurationCleanHiddenInterfaces(SCPreferencesRef prefs
, SCPreferencesRef ni_prefs
)
564 #pragma unused(prefs)
565 #pragma unused(ni_prefs)
567 Boolean changed
= FALSE
;
568 CFArrayRef interfaces
;
569 CFMutableArrayRef interfaces_thin
;
572 CFDictionaryRef nat_config
;
573 SCPreferencesRef nat_prefs
;
574 #endif // TARGET_OS_OSX
578 // build a list of interfaces we "could" remove
580 interfaces_thin
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
582 services
= SCNetworkServiceCopyAll(prefs
);
583 if (services
!= NULL
) {
584 n
= CFArrayGetCount(services
);
585 for (CFIndex i
= 0; i
< n
; i
++) {
586 CFStringRef conflict
;
587 SCNetworkInterfaceRef interface
;
588 SCNetworkServiceRef service
;
589 const char *thin
= NULL
;
591 service
= CFArrayGetValueAtIndex(services
, i
);
592 interface
= SCNetworkServiceGetInterface(service
);
593 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
595 if (bsdName
== NULL
) {
596 // if no interface name
599 "skipping service : %@ : %@ (no interface)",
600 SCNetworkServiceGetServiceID(service
),
601 SCNetworkServiceGetName(service
));
606 if (_SCNetworkInterfaceIsHiddenConfiguration(interface
)) {
608 } else if (effectivelyHiddenConfiguration(interface
)) {
609 thin
= "effectively hidden";
611 // if not HiddenConfiguration
614 "skipping service : %@ : %@ : %@ (not hidden)",
615 SCNetworkServiceGetServiceID(service
),
616 SCNetworkServiceGetName(service
),
622 conflict
= serviceMatchesTemplate(prefs
, service
);
623 if (conflict
!= NULL
) {
624 // if any part of the service's configuration was changed
627 "skipping service : %@ : %@ : %@ (%s, non-default, %@)",
628 SCNetworkServiceGetServiceID(service
),
629 SCNetworkServiceGetName(service
),
639 SC_log(LOG_INFO
, "candidate interface : %@ (%s)", bsdName
, thin
);
642 thinAdd(interfaces_thin
, bsdName
);
646 // remove any virtual interfaces from the list
648 #if !TARGET_OS_IPHONE
649 interfaces
= SCBondInterfaceCopyAll(prefs
);
650 if (interfaces
!= NULL
) {
653 n
= CFArrayGetCount(interfaces
);
654 for (CFIndex i
= 0; i
< n
; i
++) {
655 SCBondInterfaceRef bondInterface
;
659 bondInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
660 members
= SCBondInterfaceGetMemberInterfaces(bondInterface
);
661 nn
= (members
!= NULL
) ? CFArrayGetCount(members
) : 0;
662 for (CFIndex ii
= 0; ii
< nn
; ii
++) {
663 SCNetworkInterfaceRef member
;
665 member
= CFArrayGetValueAtIndex(members
, ii
);
666 bsdName
= SCNetworkInterfaceGetBSDName(member
);
667 if ((bsdName
!= NULL
) &&
668 thinRemove(interfaces_thin
, bsdName
)) {
670 SC_log(LOG_INFO
, "skipping interface : %@ (bond member)", bsdName
);
676 CFRelease(interfaces
);
678 #endif // !TARGET_OS_IPHONE
680 interfaces
= SCBridgeInterfaceCopyAll(prefs
);
681 if (interfaces
!= NULL
) {
684 n
= CFArrayGetCount(interfaces
);
685 for (CFIndex i
= 0; i
< n
; i
++) {
686 SCBridgeInterfaceRef bridgeInterface
;
690 bridgeInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
691 members
= SCBridgeInterfaceGetMemberInterfaces(bridgeInterface
);
692 nn
= (members
!= NULL
) ? CFArrayGetCount(members
) : 0;
693 for (CFIndex ii
= 0; ii
< nn
; ii
++) {
694 SCNetworkInterfaceRef member
;
696 member
= CFArrayGetValueAtIndex(members
, ii
);
697 bsdName
= SCNetworkInterfaceGetBSDName(member
);
698 if ((bsdName
!= NULL
) &&
699 thinRemove(interfaces_thin
, bsdName
)) {
701 SC_log(LOG_INFO
, "skipping interface : %@ (bridge member)", bsdName
);
707 CFRelease(interfaces
);
710 interfaces
= SCVLANInterfaceCopyAll(prefs
);
711 if (interfaces
!= NULL
) {
714 n
= CFArrayGetCount(interfaces
);
715 for (CFIndex i
= 0; i
< n
; i
++) {
716 SCBridgeInterfaceRef vlanInterface
;
717 SCNetworkInterfaceRef physicalInterface
;
719 vlanInterface
= CFArrayGetValueAtIndex(interfaces
, i
);
720 physicalInterface
= SCVLANInterfaceGetPhysicalInterface(vlanInterface
);
721 bsdName
= SCNetworkInterfaceGetBSDName(physicalInterface
);
722 if ((bsdName
!= NULL
) &&
723 thinRemove(interfaces_thin
, bsdName
)) {
725 SC_log(LOG_INFO
, "skipping interface : %@ (vlan physical)", bsdName
);
730 CFRelease(interfaces
);
733 // remove any "shared" interfaces from the list
736 nat_prefs
= SCPreferencesCreateCompanion(prefs
, CFSTR("com.apple.nat.plist"));
737 nat_config
= SCPreferencesGetValue(nat_prefs
, CFSTR("NAT"));
738 if (isA_CFDictionary(nat_config
)) {
739 CFBooleanRef bVal
= NULL
;
740 Boolean enabled
= FALSE
;
741 CFStringRef sharedFrom
= NULL
;
742 CFArrayRef sharedTo
= NULL
;
744 if (CFDictionaryGetValueIfPresent(nat_config
,
746 (const void **)&bVal
) &&
747 isA_CFBoolean(bVal
)) {
748 enabled
= CFBooleanGetValue(bVal
);
752 CFDictionaryGetValueIfPresent(nat_config
,
753 CFSTR("PrimaryService"),
754 (const void **)&sharedFrom
) &&
755 isA_CFString(sharedFrom
)) {
756 SCNetworkInterfaceRef interface
;
757 SCNetworkServiceRef service
;
759 // if "Share your connection from" service configured
760 service
= SCNetworkServiceCopy(prefs
, sharedFrom
);
761 if (service
!= NULL
) {
762 interface
= SCNetworkServiceGetInterface(service
);
763 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
764 if ((bsdName
!= NULL
) &&
765 thinRemove(interfaces_thin
, bsdName
)) {
767 SC_log(LOG_INFO
, "skipping interface : %@ (Share your connection from)", bsdName
);
772 SC_log(LOG_INFO
, "keeping [not found] service : %@ (Share your connection from)", sharedFrom
);
777 CFDictionaryGetValueIfPresent(nat_config
,
778 CFSTR("SharingDevices"),
779 (const void **)&sharedTo
) &&
780 isA_CFArray(sharedTo
)) {
781 // if "To computers using" interfaces configured
782 n
= CFArrayGetCount(sharedTo
);
783 for (CFIndex i
= 0; i
< n
; i
++) {
784 bsdName
= CFArrayGetValueAtIndex(sharedTo
, i
);
785 if (thinRemove(interfaces_thin
, bsdName
)) {
787 SC_log(LOG_INFO
, "skipping interface : %@ (To computers using)", bsdName
);
793 CFRelease(nat_prefs
);
794 #endif // TARGET_OS_OSX
796 // thin preferences.plist
797 n
= (services
!= NULL
) ? CFArrayGetCount(services
) : 0;
801 for (CFIndex i
= 0; i
< n
; i
++) {
802 SCNetworkInterfaceRef interface
;
803 SCNetworkServiceRef service
;
805 service
= CFArrayGetValueAtIndex(services
, i
);
806 interface
= SCNetworkServiceGetInterface(service
);
807 bsdName
= SCNetworkInterfaceGetBSDName(interface
);
808 if (bsdName
== NULL
) {
809 // if no interface name
813 if (!isThin(interfaces_thin
, bsdName
)) {
818 // remove this service associated with a "thinned" interface
819 if (logDetails
|| _sc_verbose
) {
821 "thinned network service : %@ : %@ : %@",
822 SCNetworkServiceGetServiceID(service
),
823 SCNetworkServiceGetName(service
),
826 SCNetworkServiceRemove(service
);
833 "Updating \"preferences.plist\" (thinned %d service%s)",
835 (updated
!= 1) ? "s" : "");
841 // thin NetworkInterfaces.plist
842 interfaces
= SCPreferencesGetValue(ni_prefs
, INTERFACES
);
843 interfaces
= isA_CFArray(interfaces
);
844 n
= (interfaces
!= NULL
) ? CFArrayGetCount(interfaces
) : 0;
846 CFMutableArrayRef interfaces_new
;
850 interfaces_new
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
851 n
= CFArrayGetCount(interfaces
);
852 for (CFIndex i
= 0; i
< n
; i
++) {
853 CFDictionaryRef if_dict
;
855 if_dict
= CFArrayGetValueAtIndex(interfaces
, i
);
856 bsdName
= CFDictionaryGetValue(if_dict
, CFSTR(kIOBSDNameKey
));
857 if (isThin(interfaces_thin
, bsdName
)) {
858 if (CFDictionaryContainsKey(if_dict
, CFSTR(kSCNetworkInterfaceActive
))) {
860 SC_log(LOG_INFO
, "skipping interface : %@ (active)", bsdName
);
863 // remove this "thinned" interface
864 if (logDetails
|| _sc_verbose
) {
865 SC_log(LOG_INFO
, "thinned network interface : %@", bsdName
);
872 CFArrayAppendValue(interfaces_new
, if_dict
);
874 SCPreferencesSetValue(ni_prefs
, INTERFACES
, interfaces_new
);
875 CFRelease(interfaces_new
);
880 "Updating \"NetworkInterfaces.plist\" (thinned %d interface%s)",
882 (updated
!= 1) ? "s" : "");
888 if (services
!= NULL
) CFRelease(services
);
889 CFRelease(interfaces_thin
);
895 #pragma mark Remove [SCNetworkMigration] Inline Backups
899 thinInlineBackup(const void *value
, void *context
)
901 CFStringRef backup
= (CFStringRef
)value
;
903 SCPreferencesRef prefs
= (SCPreferencesRef
)context
;
904 CFStringRef save_prefix
;
905 CFStringRef save_prefsID
= NULL
;
907 SC_log(LOG_NOTICE
, "thinning [inline] backup: %@", backup
);
909 save_prefix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@ : "), backup
);
910 backup_str
= _SC_cfstring_to_cstring(backup
, NULL
, 0, kCFStringEncodingASCII
);
911 if (backup_str
!= NULL
) {
912 struct tm save_tm
= { 0 };
914 if (strptime(backup_str
, "%Y-%m-%d %H:%M:%S", &save_tm
) != NULL
) {
915 save_prefsID
= CFStringCreateWithFormat(NULL
,
917 CFSTR("preferences-%4d-%02d-%02d-%02d%02d%02d.plist"),
918 save_tm
.tm_year
+ 1900,
925 CFAllocatorDeallocate(NULL
, backup_str
);
927 if (save_prefsID
== NULL
) {
928 save_prefsID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("preferences-%@.plist"), backup
);
930 savePreferences(prefs
, save_prefsID
, save_prefix
, TRUE
, NULL
, NULL
);
931 CFRelease(save_prefsID
);
932 CFRelease(save_prefix
);
938 __SCNetworkConfigurationCleanInlineBackups(SCPreferencesRef prefs
)
940 CFMutableSetRef backups
= NULL
;
941 Boolean cleaned
= FALSE
;
946 keys
= SCPreferencesCopyKeyList(prefs
);
951 suffix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR(" : %@"), kSCPrefSets
);
952 n
= CFArrayGetCount(keys
);
953 for (CFIndex i
= 0; i
< n
; i
++) {
954 CFStringRef key
= CFArrayGetValueAtIndex(keys
, i
);
955 CFMutableStringRef str
;
957 if (CFStringHasSuffix(key
, suffix
)) {
958 // if "<backup-date> : Sets"
959 if (backups
== NULL
) {
960 backups
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
962 str
= CFStringCreateMutableCopy(NULL
, 0, key
);
963 CFStringTrim(str
, suffix
);
964 CFSetAddValue(backups
, str
);
972 if (backups
!= NULL
) {
973 CFSetApplyFunction(backups
, thinInlineBackup
, (void *)prefs
);
983 #pragma mark Remove [new device type] Inline Backups
987 thinInlineModel(const void *value
, void *context
)
989 CFStringRef model
= (CFStringRef
)value
;
990 SCPreferencesRef prefs
= (SCPreferencesRef
)context
;
991 CFStringRef save_prefix
;
992 CFStringRef save_prefsID
;
994 SC_log(LOG_NOTICE
, "thinning [per-model] backup: %@", model
);
996 save_prefix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:"), model
);
997 save_prefsID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("preferences-%@.plist"), model
);
998 savePreferences(prefs
, save_prefsID
, save_prefix
, TRUE
, MODEL
, model
);
999 CFRelease(save_prefsID
);
1000 CFRelease(save_prefix
);
1006 __SCNetworkConfigurationCleanInlineModels(SCPreferencesRef prefs
)
1008 Boolean cleaned
= FALSE
;
1010 CFMutableSetRef models
= NULL
;
1014 keys
= SCPreferencesCopyKeyList(prefs
);
1019 suffix
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR(":%@"), kSCPrefSets
);
1020 n
= CFArrayGetCount(keys
);
1021 for (CFIndex i
= 0; i
< n
; i
++) {
1022 CFStringRef key
= CFArrayGetValueAtIndex(keys
, i
);
1023 CFMutableStringRef str
;
1025 if (CFStringHasSuffix(key
, suffix
)) {
1026 // if "<backup-date> : Sets"
1027 if (models
== NULL
) {
1028 models
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1030 str
= CFStringCreateMutableCopy(NULL
, 0, key
);
1031 CFStringTrim(str
, suffix
);
1032 CFSetAddValue(models
, str
);
1040 if (models
!= NULL
) {
1041 CFSetApplyFunction(models
, thinInlineModel
, (void *)prefs
);
1051 #pragma mark Remove Orphaned Services
1056 __SCNetworkConfigurationCleanOrphanedServices(SCPreferencesRef prefs)
1058 #pragma unused(prefs)
1065 #pragma mark Cleanup network service order issues
1069 __SCNetworkConfigurationCleanServiceOrderIssues(SCPreferencesRef prefs
)
1071 #pragma unused(prefs)
1072 Boolean cleaned
= FALSE
;
1076 sets
= SCNetworkSetCopyAll(prefs
);
1077 nSets
= (sets
!= NULL
) ? CFArrayGetCount(sets
) : 0;
1078 for (CFIndex iSets
= 0; iSets
< nSets
; iSets
++) {
1080 CFMutableSetRef known
= NULL
;
1082 SCNetworkSetRef set
= CFArrayGetValueAtIndex(sets
, iSets
);
1083 CFStringRef setID
= SCNetworkSetGetSetID(set
);
1084 CFArrayRef order
= SCNetworkSetGetServiceOrder(set
);
1085 CFMutableArrayRef newOrder
= NULL
;
1088 nServices
= (order
!= NULL
) ? CFArrayGetCount(order
) : 0;
1089 if (nServices
> 0) {
1090 known
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
1091 newOrder
= CFArrayCreateMutableCopy(NULL
, 0, order
);
1094 while (iServices
< nServices
) {
1095 SCNetworkServiceRef service
;
1096 CFStringRef serviceID
= CFArrayGetValueAtIndex(newOrder
, iServices
);
1098 // check if serviceID already known/processed
1099 if (CFSetContainsValue(known
, serviceID
)) {
1100 // if duplicate/removed service, remove from serviceOrder
1103 "set: %@, removing serviceID %@ (duplicate/removed)",
1107 CFArrayRemoveValueAtIndex(newOrder
, iServices
);
1113 // track this serviceID as known, already removed, or removed below
1114 CFSetAddValue(known
, serviceID
);
1116 // validate serviceID
1117 service
= SCNetworkServiceCopy(prefs
, serviceID
);
1118 if (service
== NULL
) {
1119 // if no service, remove from serviceOrder
1122 "set: %@, removing serviceID %@ (no service)",
1126 CFArrayRemoveValueAtIndex(newOrder
, iServices
);
1132 if (!__SCNetworkServiceExists(service
)) {
1133 // if service already removed, remove from serviceOrder
1136 "set: %@, removing serviceID %@ (service already removed)",
1140 CFArrayRemoveValueAtIndex(newOrder
, iServices
);
1151 if (known
!= NULL
) {
1155 if (newOrder
!= NULL
) {
1157 SCNetworkSetSetServiceOrder(set
, newOrder
);
1159 CFRelease(newOrder
);
1172 #pragma mark Cleanup Network Configuration(s)
1176 __SCNetworkConfigurationClean(SCPreferencesRef prefs
, SCPreferencesRef ni_prefs
)
1179 Boolean updated
= FALSE
;
1181 changed
= __SCNetworkConfigurationCleanInlineBackups(prefs
);
1183 SC_log(LOG_NOTICE
, "network configuration: unwanted inline backups removed");
1187 changed
= __SCNetworkConfigurationCleanInlineModels(prefs
);
1189 SC_log(LOG_NOTICE
, "network configuration: unwanted device backups removed");
1193 if (ni_prefs
!= NULL
) {
1194 changed
= __SCNetworkConfigurationCleanHiddenInterfaces(prefs
, ni_prefs
);
1196 SC_log(LOG_NOTICE
, "network configuration: hidden interface configurations removed");
1201 changed
= __SCNetworkConfigurationCleanServiceOrderIssues(prefs
);
1203 SC_log(LOG_NOTICE
, "network configuration: ServiceOrder cleaned");