]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkConfigurationPrivate.c
configd-1109.101.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkConfigurationPrivate.c
1 /*
2 * Copyright (c) 2019, 2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * October 4, 2018 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include "SCNetworkConfigurationInternal.h"
33 #include "SCPreferencesInternal.h"
34 #include <IOKit/IOBSD.h>
35
36
37 #define logDetails (_sc_log == kSCLogDestinationDefault) || _sc_debug
38
39
40 static Boolean
41 savePreferences(SCPreferencesRef prefs,
42 CFStringRef save_prefsID,
43 CFStringRef prefix,
44 Boolean remove,
45 CFStringRef extra_key,
46 CFPropertyListRef extra_value)
47 {
48 const CFStringRef keys[] = {
49 kSCPrefCurrentSet,
50 MODEL,
51 kSCPrefNetworkServices,
52 kSCPrefSets,
53 kSCPrefSystem,
54 kSCPrefVersion,
55 kSCPrefVirtualNetworkInterfaces
56 };
57 Boolean ok;
58 SCPreferencesRef save_prefs;
59
60 // open [companion] backup
61 save_prefs = SCPreferencesCreateCompanion(prefs, save_prefsID);
62
63 for (CFIndex i = 0; i < (CFIndex)(sizeof(keys)/sizeof(keys[0])); i++) {
64 CFStringRef key = keys[i];
65 CFStringRef src_key;
66 CFTypeRef val;
67
68 src_key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, key);
69 val = SCPreferencesGetValue(prefs, src_key);
70 if (val != NULL) {
71 SCPreferencesSetValue(save_prefs, key, val);
72 if (remove) {
73 SCPreferencesRemoveValue(prefs, src_key);
74 }
75 }
76 CFRelease(src_key);
77 }
78
79 if (extra_key != NULL) {
80 SCPreferencesSetValue(save_prefs, extra_key, extra_value);
81 }
82
83 ok = SCPreferencesCommitChanges(save_prefs);
84 CFRelease(save_prefs);
85 if (!ok) {
86 SC_log(LOG_ERR, "could not save preferences (%@): %s",
87 save_prefsID,
88 SCErrorString(SCError()));
89 }
90 return ok;
91 }
92
93
94 __private_extern__
95 Boolean
96 __SCNetworkConfigurationBackup(SCPreferencesRef prefs, CFStringRef suffix, SCPreferencesRef relativeTo)
97 {
98 SCPreferencesRef backup;
99 CFMutableStringRef backupPrefsID;
100 Boolean ok = FALSE;
101 CFPropertyListRef plist;
102 CFRange range;
103 SCPreferencesPrivateRef sourcePrivate = (SCPreferencesPrivateRef)prefs;
104 CFStringRef sourcePrefsID;
105
106 SC_log(LOG_NOTICE, "creating [%@] backup", suffix);
107
108 sourcePrefsID = (sourcePrivate->prefsID != NULL) ? sourcePrivate->prefsID : PREFS_DEFAULT_CONFIG;
109 backupPrefsID = CFStringCreateMutableCopy(NULL, 0, sourcePrefsID);
110 if (CFStringFindWithOptions(backupPrefsID,
111 CFSTR("/"),
112 CFRangeMake(0, CFStringGetLength(backupPrefsID)),
113 kCFCompareBackwards,
114 &range)) {
115 // if slash, remove path prefix
116 range.length = range.location + 1;
117 range.location = 0;
118 CFStringReplace(backupPrefsID, range, CFSTR(""));
119 }
120 CFStringInsert(backupPrefsID,
121 CFStringGetLength(backupPrefsID) - sizeof(".plist") + 1,
122 CFSTR("-"));
123 CFStringInsert(backupPrefsID,
124 CFStringGetLength(backupPrefsID) - sizeof(".plist") + 1,
125 suffix);
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);
132 CFRelease(backup);
133 }
134
135 return ok;
136 }
137
138
139 Boolean
140 __SCNetworkConfigurationSaveModel(SCPreferencesRef prefs, CFStringRef model)
141 {
142 Boolean ok;
143 CFStringRef save_prefsID;
144
145 SC_log(LOG_NOTICE, "creating [per-device] backup: %@", model);
146
147 save_prefsID = CFStringCreateWithFormat(NULL, NULL, CFSTR("preferences-%@.plist"), model);
148 ok = savePreferences(prefs, save_prefsID, CFSTR(""), TRUE, MODEL, model);
149 CFRelease(save_prefsID);
150 return ok;
151 }
152
153
154 static Boolean
155 needsUpdate(SCPreferencesRef prefs, int new_version)
156 {
157 CFNumberRef num;
158 int old_version = 0;
159
160 if (prefs == NULL) {
161 // if no prefs, no updated needed
162 return FALSE;
163 }
164
165 num = SCPreferencesGetValue(prefs, kSCPrefVersion);
166 if (!isA_CFNumber(num) ||
167 !CFNumberGetValue(num, kCFNumberIntType, &old_version)) {
168 old_version = 0;
169 }
170 if (old_version == new_version) {
171 // if no update is needed
172 return FALSE;
173 }
174
175 return TRUE;
176 }
177
178
179 static Boolean
180 lockWithSync(SCPreferencesRef prefs)
181 {
182 Boolean ok;
183
184 assert(prefs != NULL);
185 ok = SCPreferencesLock(prefs, TRUE);
186 if (!ok && (SCError() == kSCStatusStale)) {
187 SCPreferencesSynchronize(prefs);
188 ok = SCPreferencesLock(prefs, TRUE);
189 }
190
191 return ok;
192 }
193
194
195 Boolean
196 __SCNetworkConfigurationUpgrade(SCPreferencesRef *prefs_p,
197 SCPreferencesRef *ni_prefs_p,
198 Boolean commit)
199 {
200 SCPreferencesRef ni_prefs = NULL;
201 Boolean ni_prefs_added = FALSE;
202 const int new_version = NETWORK_CONFIGURATION_VERSION;
203 CFNumberRef num;
204 Boolean ok = FALSE;
205 SCPreferencesRef prefs = NULL;
206 Boolean prefs_added = FALSE;
207
208 //
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.
211 //
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 // +====================+=============+=============+=============+=============+========+
223 //
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
227 // plists.
228 //
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.
232 //
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).
238 //
239
240 if (prefs_p != NULL) {
241 prefs = *prefs_p;
242 }
243
244 if (ni_prefs_p != NULL) {
245 ni_prefs = *ni_prefs_p;
246 }
247
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);
252 if (prefs == NULL) {
253 SC_log(LOG_ERR,
254 "__SCNetworkConfigurationUpgrade(): could not open [preferences.plist]: %s",
255 SCErrorString(SCError()));
256 return FALSE;
257 }
258 prefs_added = TRUE;
259 }
260
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) {
266 SC_log(LOG_ERR,
267 "__SCNetworkConfigurationUpgrade(): could not open [NetworkInterfaces.plist]: %s",
268 SCErrorString(SCError()));
269 return FALSE;
270 }
271 ni_prefs_added = TRUE;
272 }
273
274 if (!needsUpdate(prefs, NETWORK_CONFIGURATION_VERSION) &&
275 !needsUpdate(ni_prefs, NETWORK_CONFIGURATION_VERSION)) {
276 goto done;
277 }
278
279 // lock [preferences.plist] changes while we are updating
280 ok = lockWithSync(prefs);
281 if (!ok) {
282 SC_log(LOG_ERR,
283 "__SCNetworkConfigurationUpgrade(): could not lock [preferences.plist]: %s",
284 SCErrorString(SCError()));
285 goto done;
286 }
287
288 if (ni_prefs != NULL) {
289 // lock [NetworkInterfaces.plist] changes while we are updating
290 ok = lockWithSync(ni_prefs);
291 if (!ok) {
292 SC_log(LOG_ERR,
293 "__SCNetworkConfigurationUpgrade(): could not lock [NetworkInterfaces.plist]: %s",
294 SCErrorString(SCError()));
295 SCPreferencesUnlock(prefs);
296 goto done;
297 }
298 }
299
300 // first, cleanup any leftover cruft from the configuration
301 __SCNetworkConfigurationClean(prefs, ni_prefs);
302
303 // update the version(s)
304 num = CFNumberCreate(NULL, kCFNumberIntType, &new_version);
305 SCPreferencesSetValue(prefs, kSCPrefVersion, num);
306 CFRelease(num);
307 if (ni_prefs != NULL) {
308 num = CFNumberCreate(NULL, kCFNumberIntType, &new_version);
309 SCPreferencesSetValue(ni_prefs, kSCPrefVersion, num);
310 CFRelease(num);
311 }
312
313 if (commit) {
314 // commit the [preferences.plist] changes
315 ok = SCPreferencesCommitChanges(prefs);
316 if (!ok) {
317 SC_log(LOG_ERR,
318 "__SCNetworkConfigurationUpgrade(): update not saved [preferences.plist]: %s",
319 SCErrorString(SCError()));
320 }
321 if (ok) {
322 ok = SCPreferencesApplyChanges(prefs);
323 if (!ok) {
324 SC_log(LOG_ERR,
325 "__SCNetworkConfigurationUpgrade(): update not applied [preferences.plist]: %s",
326 SCErrorString(SCError()));
327 }
328 }
329 }
330 SCPreferencesUnlock(prefs);
331
332 if (ni_prefs != NULL) {
333 if (commit) {
334 // commit the [NetworkInterfaces.plist] changes
335 if (ok) {
336 ok = SCPreferencesCommitChanges(ni_prefs);
337 if (!ok) {
338 SC_log(LOG_ERR,
339 "__SCNetworkConfigurationUpgrade(): update not saved [NetworkInterfaces.plist]: %s",
340 SCErrorString(SCError()));
341 }
342 }
343 }
344 SCPreferencesUnlock(ni_prefs);
345 }
346
347 done :
348
349 if (prefs_added) {
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.
353 CFRelease(prefs);
354 }
355
356 if (ni_prefs_added) {
357 if (ok && (ni_prefs_p != NULL)) {
358 *ni_prefs_p = CFRetain(ni_prefs);
359 }
360 CFRelease(ni_prefs);
361 }
362
363 return ok;
364 }
365
366
367 #pragma mark -
368 #pragma mark Remove "Hidden" Interface Configurations
369
370
371 static Boolean
372 isThin(CFArrayRef interfaces, CFStringRef bsdName)
373 {
374 Boolean thin;
375
376 thin = CFArrayContainsValue(interfaces,
377 CFRangeMake(0, CFArrayGetCount(interfaces)),
378 bsdName);
379 return thin;
380 }
381
382
383 static Boolean
384 thinAdd(CFMutableArrayRef interfaces, CFStringRef bsdName)
385 {
386 if (!CFArrayContainsValue(interfaces,
387 CFRangeMake(0, CFArrayGetCount(interfaces)),
388 bsdName)) {
389 CFArrayAppendValue(interfaces, bsdName);
390 return TRUE;
391 }
392
393 return FALSE;
394 }
395
396
397 static Boolean
398 thinRemove(CFMutableArrayRef interfaces, CFStringRef bsdName)
399 {
400 CFIndex n;
401
402 n = CFArrayGetFirstIndexOfValue(interfaces,
403 CFRangeMake(0, CFArrayGetCount(interfaces)),
404 bsdName);
405 if (n != kCFNotFound) {
406 CFArrayRemoveValueAtIndex(interfaces, n);
407 return TRUE;
408 }
409
410 return FALSE;
411 }
412
413
414 static CF_RETURNS_RETAINED CFStringRef
415 serviceMatchesTemplate(SCPreferencesRef prefs, SCNetworkServiceRef existingService)
416 {
417 CFStringRef conflict = NULL;
418 SCNetworkInterfaceRef existingInterface;
419 CFIndex n;
420 CFArrayRef protocols;
421 CFMutableArrayRef protocolTypes;
422 SCNetworkServiceRef templateService;
423
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"));
428 return conflict;
429 }
430
431 templateService = SCNetworkServiceCreate(prefs, existingInterface);
432 if (templateService == NULL) {
433 conflict = CFStringCreateCopy(NULL, CFSTR("could not create service for interface"));
434 return conflict;
435 }
436
437 (void) SCNetworkServiceEstablishDefaultConfiguration(templateService);
438
439 protocolTypes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
440
441 // get protocol types from the existing service
442 protocols = SCNetworkServiceCopyProtocols(existingService);
443 if (protocols != NULL) {
444 n = CFArrayGetCount(protocols);
445
446 for (CFIndex i = 0; i < n; i++) {
447 SCNetworkProtocolRef protocol;
448 CFStringRef protocolType;
449
450 protocol = CFArrayGetValueAtIndex(protocols, i);
451 protocolType = SCNetworkProtocolGetProtocolType(protocol);
452 if (!CFArrayContainsValue(protocolTypes,
453 CFRangeMake(0, CFArrayGetCount(protocolTypes)),
454 protocolType)) {
455 CFArrayAppendValue(protocolTypes, protocolType);
456 }
457 }
458
459 CFRelease(protocols);
460 }
461
462 // get protocol types from the template service
463 protocols = SCNetworkServiceCopyProtocols(templateService);
464 if (protocols != NULL) {
465 n = CFArrayGetCount(protocols);
466
467 for (CFIndex i = 0; i < n; i++) {
468 SCNetworkProtocolRef protocol;
469 CFStringRef protocolType;
470
471 protocol = CFArrayGetValueAtIndex(protocols, i);
472 protocolType = SCNetworkProtocolGetProtocolType(protocol);
473 if (!CFArrayContainsValue(protocolTypes,
474 CFRangeMake(0, CFArrayGetCount(protocolTypes)),
475 protocolType)) {
476 CFArrayAppendValue(protocolTypes, protocolType);
477 }
478 }
479
480 CFRelease(protocols);
481 }
482
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;
488 Boolean match;
489 CFStringRef protocolType;
490 CFDictionaryRef templateConfiguration = NULL;
491 SCNetworkProtocolRef templateProtocol;
492
493 protocolType = CFArrayGetValueAtIndex(protocolTypes, i);
494 existingProtocol = SCNetworkServiceCopyProtocol(existingService, protocolType);
495 templateProtocol = SCNetworkServiceCopyProtocol(templateService, protocolType);
496
497 do {
498 // compare "enabled"
499 match = ((existingProtocol != NULL) &&
500 (templateProtocol != NULL) &&
501 (SCNetworkProtocolGetEnabled(existingProtocol) == SCNetworkProtocolGetEnabled(templateProtocol)));
502 if (!match) {
503 conflict = CFStringCreateWithFormat(NULL, NULL,
504 CFSTR("conflicting %@ enable/disable"),
505 protocolType);
506 break; // if enable/disable conflict
507 }
508
509 if (existingProtocol != NULL) {
510 existingConfiguration = SCNetworkProtocolGetConfiguration(existingProtocol);
511 }
512 if (templateProtocol != NULL) {
513 templateConfiguration = SCNetworkProtocolGetConfiguration(templateProtocol);
514 }
515 match = _SC_CFEqual(existingConfiguration, templateConfiguration);
516 if (!match) {
517 conflict = CFStringCreateWithFormat(NULL, NULL,
518 CFSTR("conflicting %@ configuration"),
519 protocolType);
520 break; // if configuration conflict
521 }
522 } while (FALSE);
523
524 if (existingProtocol != NULL) CFRelease(existingProtocol);
525 if (templateProtocol != NULL) CFRelease(templateProtocol);
526 if (!match) {
527 break;
528 }
529 }
530
531 (void) SCNetworkServiceRemove(templateService);
532 CFRelease(templateService);
533 CFRelease(protocolTypes);
534 return conflict;
535 }
536
537
538 static Boolean
539 effectivelyHiddenConfiguration(SCNetworkInterfaceRef interface)
540 {
541 const CFStringRef known[] = {
542 CFSTR("Apple TV"),
543 CFSTR("Watch"),
544 CFSTR("iPad"),
545 CFSTR("iPhone"),
546 CFSTR("iPod"),
547 };
548 CFStringRef name;
549
550 name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
551 for (int i = 0; i < (int)(sizeof(known) / sizeof(known[0])); i++) {
552 if (CFStringHasPrefix(name, known[i])) {
553 return TRUE;
554 }
555 }
556
557 return FALSE;
558 }
559
560
561 static Boolean
562 __SCNetworkConfigurationCleanHiddenInterfaces(SCPreferencesRef prefs, SCPreferencesRef ni_prefs)
563 {
564 #pragma unused(prefs)
565 #pragma unused(ni_prefs)
566 CFStringRef bsdName;
567 Boolean changed = FALSE;
568 CFArrayRef interfaces;
569 CFMutableArrayRef interfaces_thin;
570 CFIndex n;
571 #if TARGET_OS_OSX
572 CFDictionaryRef nat_config;
573 SCPreferencesRef nat_prefs;
574 #endif // TARGET_OS_OSX
575 CFArrayRef services;
576 int updated = 0;
577
578 // build a list of interfaces we "could" remove
579
580 interfaces_thin = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
581
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;
590
591 service = CFArrayGetValueAtIndex(services, i);
592 interface = SCNetworkServiceGetInterface(service);
593 bsdName = SCNetworkInterfaceGetBSDName(interface);
594
595 if (bsdName == NULL) {
596 // if no interface name
597 if (logDetails) {
598 SC_log(LOG_INFO,
599 "skipping service : %@ : %@ (no interface)",
600 SCNetworkServiceGetServiceID(service),
601 SCNetworkServiceGetName(service));
602 }
603 continue;
604 }
605
606 if (_SCNetworkInterfaceIsHiddenConfiguration(interface)) {
607 thin = "hidden";
608 } else if (effectivelyHiddenConfiguration(interface)) {
609 thin = "effectively hidden";
610 } else {
611 // if not HiddenConfiguration
612 if (logDetails) {
613 SC_log(LOG_INFO,
614 "skipping service : %@ : %@ : %@ (not hidden)",
615 SCNetworkServiceGetServiceID(service),
616 SCNetworkServiceGetName(service),
617 bsdName);
618 }
619 continue;
620 }
621
622 conflict = serviceMatchesTemplate(prefs, service);
623 if (conflict != NULL) {
624 // if any part of the service's configuration was changed
625 if (logDetails) {
626 SC_log(LOG_INFO,
627 "skipping service : %@ : %@ : %@ (%s, non-default, %@)",
628 SCNetworkServiceGetServiceID(service),
629 SCNetworkServiceGetName(service),
630 bsdName,
631 thin,
632 conflict);
633 }
634 CFRelease(conflict);
635 continue;
636 }
637
638 if (logDetails) {
639 SC_log(LOG_INFO, "candidate interface : %@ (%s)", bsdName, thin);
640 }
641
642 thinAdd(interfaces_thin, bsdName);
643 }
644 }
645
646 // remove any virtual interfaces from the list
647
648 #if !TARGET_OS_IPHONE
649 interfaces = SCBondInterfaceCopyAll(prefs);
650 if (interfaces != NULL) {
651 CFIndex n;
652
653 n = CFArrayGetCount(interfaces);
654 for (CFIndex i = 0; i < n; i++) {
655 SCBondInterfaceRef bondInterface;
656 CFArrayRef members;
657 CFIndex nn;
658
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;
664
665 member = CFArrayGetValueAtIndex(members, ii);
666 bsdName = SCNetworkInterfaceGetBSDName(member);
667 if ((bsdName != NULL) &&
668 thinRemove(interfaces_thin, bsdName)) {
669 if (logDetails) {
670 SC_log(LOG_INFO, "skipping interface : %@ (bond member)", bsdName);
671 }
672 }
673 }
674 }
675
676 CFRelease(interfaces);
677 }
678 #endif // !TARGET_OS_IPHONE
679
680 interfaces = SCBridgeInterfaceCopyAll(prefs);
681 if (interfaces != NULL) {
682 CFIndex n;
683
684 n = CFArrayGetCount(interfaces);
685 for (CFIndex i = 0; i < n; i++) {
686 SCBridgeInterfaceRef bridgeInterface;
687 CFArrayRef members;
688 CFIndex nn;
689
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;
695
696 member = CFArrayGetValueAtIndex(members, ii);
697 bsdName = SCNetworkInterfaceGetBSDName(member);
698 if ((bsdName != NULL) &&
699 thinRemove(interfaces_thin, bsdName)) {
700 if (logDetails) {
701 SC_log(LOG_INFO, "skipping interface : %@ (bridge member)", bsdName);
702 }
703 }
704 }
705 }
706
707 CFRelease(interfaces);
708 }
709
710 interfaces = SCVLANInterfaceCopyAll(prefs);
711 if (interfaces != NULL) {
712 CFIndex n;
713
714 n = CFArrayGetCount(interfaces);
715 for (CFIndex i = 0; i < n; i++) {
716 SCBridgeInterfaceRef vlanInterface;
717 SCNetworkInterfaceRef physicalInterface;
718
719 vlanInterface = CFArrayGetValueAtIndex(interfaces, i);
720 physicalInterface = SCVLANInterfaceGetPhysicalInterface(vlanInterface);
721 bsdName = SCNetworkInterfaceGetBSDName(physicalInterface);
722 if ((bsdName != NULL) &&
723 thinRemove(interfaces_thin, bsdName)) {
724 if (logDetails) {
725 SC_log(LOG_INFO, "skipping interface : %@ (vlan physical)", bsdName);
726 }
727 }
728 }
729
730 CFRelease(interfaces);
731 }
732
733 // remove any "shared" interfaces from the list
734
735 #if TARGET_OS_OSX
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;
743
744 if (CFDictionaryGetValueIfPresent(nat_config,
745 CFSTR("Enabled"),
746 (const void **)&bVal) &&
747 isA_CFBoolean(bVal)) {
748 enabled = CFBooleanGetValue(bVal);
749 }
750
751 if (enabled &&
752 CFDictionaryGetValueIfPresent(nat_config,
753 CFSTR("PrimaryService"),
754 (const void **)&sharedFrom) &&
755 isA_CFString(sharedFrom)) {
756 SCNetworkInterfaceRef interface;
757 SCNetworkServiceRef service;
758
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)) {
766 if (logDetails) {
767 SC_log(LOG_INFO, "skipping interface : %@ (Share your connection from)", bsdName);
768 }
769 }
770 CFRelease(service);
771 } else {
772 SC_log(LOG_INFO, "keeping [not found] service : %@ (Share your connection from)", sharedFrom);
773 }
774 }
775
776 if (enabled &&
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)) {
786 if (logDetails) {
787 SC_log(LOG_INFO, "skipping interface : %@ (To computers using)", bsdName);
788 }
789 }
790 }
791 }
792 }
793 CFRelease(nat_prefs);
794 #endif // TARGET_OS_OSX
795
796 // thin preferences.plist
797 n = (services != NULL) ? CFArrayGetCount(services) : 0;
798 if (n > 0) {
799 updated = 0;
800
801 for (CFIndex i = 0; i < n; i++) {
802 SCNetworkInterfaceRef interface;
803 SCNetworkServiceRef service;
804
805 service = CFArrayGetValueAtIndex(services, i);
806 interface = SCNetworkServiceGetInterface(service);
807 bsdName = SCNetworkInterfaceGetBSDName(interface);
808 if (bsdName == NULL) {
809 // if no interface name
810 continue;
811 }
812
813 if (!isThin(interfaces_thin, bsdName)) {
814 // if not thinned
815 continue;
816 }
817
818 // remove this service associated with a "thinned" interface
819 if (logDetails || _sc_verbose) {
820 SC_log(LOG_INFO,
821 "thinned network service : %@ : %@ : %@",
822 SCNetworkServiceGetServiceID(service),
823 SCNetworkServiceGetName(service),
824 bsdName);
825 }
826 SCNetworkServiceRemove(service);
827 updated++;
828 }
829
830 if (updated > 0) {
831 if (logDetails) {
832 SC_log(LOG_NOTICE,
833 "Updating \"preferences.plist\" (thinned %d service%s)",
834 updated,
835 (updated != 1) ? "s" : "");
836 }
837 changed = TRUE;
838 }
839 }
840
841 // thin NetworkInterfaces.plist
842 interfaces = SCPreferencesGetValue(ni_prefs, INTERFACES);
843 interfaces = isA_CFArray(interfaces);
844 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
845 if (n > 0) {
846 CFMutableArrayRef interfaces_new;
847
848 updated = 0;
849
850 interfaces_new = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
851 n = CFArrayGetCount(interfaces);
852 for (CFIndex i = 0; i < n; i++) {
853 CFDictionaryRef if_dict;
854
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))) {
859 if (logDetails) {
860 SC_log(LOG_INFO, "skipping interface : %@ (active)", bsdName);
861 }
862 } else {
863 // remove this "thinned" interface
864 if (logDetails || _sc_verbose) {
865 SC_log(LOG_INFO, "thinned network interface : %@", bsdName);
866 }
867 updated++;
868 continue;
869 }
870 }
871
872 CFArrayAppendValue(interfaces_new, if_dict);
873 }
874 SCPreferencesSetValue(ni_prefs, INTERFACES, interfaces_new);
875 CFRelease(interfaces_new);
876
877 if (updated > 0) {
878 if (logDetails) {
879 SC_log(LOG_INFO,
880 "Updating \"NetworkInterfaces.plist\" (thinned %d interface%s)",
881 updated,
882 (updated != 1) ? "s" : "");
883 }
884 changed = TRUE;
885 }
886 }
887
888 if (services != NULL) CFRelease(services);
889 CFRelease(interfaces_thin);
890 return changed;
891 }
892
893
894 #pragma mark -
895 #pragma mark Remove [SCNetworkMigration] Inline Backups
896
897
898 static void
899 thinInlineBackup(const void *value, void *context)
900 {
901 CFStringRef backup = (CFStringRef)value;
902 char *backup_str;
903 SCPreferencesRef prefs = (SCPreferencesRef)context;
904 CFStringRef save_prefix;
905 CFStringRef save_prefsID = NULL;
906
907 SC_log(LOG_NOTICE, "thinning [inline] backup: %@", backup);
908
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 };
913
914 if (strptime(backup_str, "%Y-%m-%d %H:%M:%S", &save_tm) != NULL) {
915 save_prefsID = CFStringCreateWithFormat(NULL,
916 NULL,
917 CFSTR("preferences-%4d-%02d-%02d-%02d%02d%02d.plist"),
918 save_tm.tm_year + 1900,
919 save_tm.tm_mon + 1,
920 save_tm.tm_mday,
921 save_tm.tm_hour,
922 save_tm.tm_min,
923 save_tm.tm_sec);
924 }
925 CFAllocatorDeallocate(NULL, backup_str);
926 }
927 if (save_prefsID == NULL) {
928 save_prefsID = CFStringCreateWithFormat(NULL, NULL, CFSTR("preferences-%@.plist"), backup);
929 }
930 savePreferences(prefs, save_prefsID, save_prefix, TRUE, NULL, NULL);
931 CFRelease(save_prefsID);
932 CFRelease(save_prefix);
933 return;
934 }
935
936
937 static Boolean
938 __SCNetworkConfigurationCleanInlineBackups(SCPreferencesRef prefs)
939 {
940 CFMutableSetRef backups = NULL;
941 Boolean cleaned = FALSE;
942 CFArrayRef keys;
943 CFIndex n;
944 CFStringRef suffix;
945
946 keys = SCPreferencesCopyKeyList(prefs);
947 if (keys == NULL) {
948 return FALSE;
949 }
950
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;
956
957 if (CFStringHasSuffix(key, suffix)) {
958 // if "<backup-date> : Sets"
959 if (backups == NULL) {
960 backups = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
961 }
962 str = CFStringCreateMutableCopy(NULL, 0, key);
963 CFStringTrim(str, suffix);
964 CFSetAddValue(backups, str);
965 CFRelease(str);
966 continue;
967 }
968 }
969 CFRelease(suffix);
970 CFRelease(keys);
971
972 if (backups != NULL) {
973 CFSetApplyFunction(backups, thinInlineBackup, (void *)prefs);
974 CFRelease(backups);
975 cleaned = TRUE;
976 }
977
978 return cleaned;
979 }
980
981
982 #pragma mark -
983 #pragma mark Remove [new device type] Inline Backups
984
985
986 static void
987 thinInlineModel(const void *value, void *context)
988 {
989 CFStringRef model = (CFStringRef)value;
990 SCPreferencesRef prefs = (SCPreferencesRef)context;
991 CFStringRef save_prefix;
992 CFStringRef save_prefsID;
993
994 SC_log(LOG_NOTICE, "thinning [per-model] backup: %@", model);
995
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);
1001 return;
1002 }
1003
1004
1005 static Boolean
1006 __SCNetworkConfigurationCleanInlineModels(SCPreferencesRef prefs)
1007 {
1008 Boolean cleaned = FALSE;
1009 CFArrayRef keys;
1010 CFMutableSetRef models = NULL;
1011 CFIndex n;
1012 CFStringRef suffix;
1013
1014 keys = SCPreferencesCopyKeyList(prefs);
1015 if (keys == NULL) {
1016 return FALSE;
1017 }
1018
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;
1024
1025 if (CFStringHasSuffix(key, suffix)) {
1026 // if "<backup-date> : Sets"
1027 if (models == NULL) {
1028 models = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1029 }
1030 str = CFStringCreateMutableCopy(NULL, 0, key);
1031 CFStringTrim(str, suffix);
1032 CFSetAddValue(models, str);
1033 CFRelease(str);
1034 continue;
1035 }
1036 }
1037 CFRelease(suffix);
1038 CFRelease(keys);
1039
1040 if (models != NULL) {
1041 CFSetApplyFunction(models, thinInlineModel, (void *)prefs);
1042 CFRelease(models);
1043 cleaned = TRUE;
1044 }
1045
1046 return cleaned;
1047 }
1048
1049
1050 #pragma mark -
1051 #pragma mark Remove Orphaned Services
1052
1053
1054 /*
1055 static Boolean
1056 __SCNetworkConfigurationCleanOrphanedServices(SCPreferencesRef prefs)
1057 {
1058 #pragma unused(prefs)
1059 return FALSE;
1060 }
1061 */
1062
1063
1064 #pragma mark -
1065 #pragma mark Cleanup network service order issues
1066
1067
1068 static Boolean
1069 __SCNetworkConfigurationCleanServiceOrderIssues(SCPreferencesRef prefs)
1070 {
1071 #pragma unused(prefs)
1072 Boolean cleaned = FALSE;
1073 CFIndex nSets;
1074 CFArrayRef sets;
1075
1076 sets = SCNetworkSetCopyAll(prefs);
1077 nSets = (sets != NULL) ? CFArrayGetCount(sets) : 0;
1078 for (CFIndex iSets = 0; iSets < nSets; iSets++) {
1079 CFIndex iServices;
1080 CFMutableSetRef known = NULL;
1081 CFIndex nServices;
1082 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, iSets);
1083 CFStringRef setID = SCNetworkSetGetSetID(set);
1084 CFArrayRef order = SCNetworkSetGetServiceOrder(set);
1085 CFMutableArrayRef newOrder = NULL;
1086
1087 iServices = 0;
1088 nServices = (order != NULL) ? CFArrayGetCount(order) : 0;
1089 if (nServices > 0) {
1090 known = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1091 newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
1092 }
1093
1094 while (iServices < nServices) {
1095 SCNetworkServiceRef service;
1096 CFStringRef serviceID = CFArrayGetValueAtIndex(newOrder, iServices);
1097
1098 // check if serviceID already known/processed
1099 if (CFSetContainsValue(known, serviceID)) {
1100 // if duplicate/removed service, remove from serviceOrder
1101 if (logDetails) {
1102 SC_log(LOG_NOTICE,
1103 "set: %@, removing serviceID %@ (duplicate/removed)",
1104 setID,
1105 serviceID);
1106 }
1107 CFArrayRemoveValueAtIndex(newOrder, iServices);
1108 nServices--;
1109 cleaned = TRUE;
1110 continue;
1111 }
1112
1113 // track this serviceID as known, already removed, or removed below
1114 CFSetAddValue(known, serviceID);
1115
1116 // validate serviceID
1117 service = SCNetworkServiceCopy(prefs, serviceID);
1118 if (service == NULL) {
1119 // if no service, remove from serviceOrder
1120 if (logDetails) {
1121 SC_log(LOG_NOTICE,
1122 "set: %@, removing serviceID %@ (no service)",
1123 setID,
1124 serviceID);
1125 }
1126 CFArrayRemoveValueAtIndex(newOrder, iServices);
1127 nServices--;
1128 cleaned = TRUE;
1129 continue;
1130 }
1131
1132 if (!__SCNetworkServiceExists(service)) {
1133 // if service already removed, remove from serviceOrder
1134 if (logDetails) {
1135 SC_log(LOG_NOTICE,
1136 "set: %@, removing serviceID %@ (service already removed)",
1137 setID,
1138 serviceID);
1139 }
1140 CFArrayRemoveValueAtIndex(newOrder, iServices);
1141 nServices--;
1142 cleaned = TRUE;
1143 CFRelease(service);
1144 continue;
1145 }
1146
1147 CFRelease(service);
1148 iServices++;
1149 }
1150
1151 if (known != NULL) {
1152 CFRelease(known);
1153 }
1154
1155 if (newOrder != NULL) {
1156 if (cleaned) {
1157 SCNetworkSetSetServiceOrder(set, newOrder);
1158 }
1159 CFRelease(newOrder);
1160 }
1161 }
1162
1163 if (sets != NULL) {
1164 CFRelease(sets);
1165 }
1166
1167 return cleaned;
1168 }
1169
1170
1171 #pragma mark -
1172 #pragma mark Cleanup Network Configuration(s)
1173
1174
1175 Boolean
1176 __SCNetworkConfigurationClean(SCPreferencesRef prefs, SCPreferencesRef ni_prefs)
1177 {
1178 Boolean changed;
1179 Boolean updated = FALSE;
1180
1181 changed = __SCNetworkConfigurationCleanInlineBackups(prefs);
1182 if (changed) {
1183 SC_log(LOG_NOTICE, "network configuration: unwanted inline backups removed");
1184 updated = TRUE;
1185 }
1186
1187 changed = __SCNetworkConfigurationCleanInlineModels(prefs);
1188 if (changed) {
1189 SC_log(LOG_NOTICE, "network configuration: unwanted device backups removed");
1190 updated = TRUE;
1191 }
1192
1193 if (ni_prefs != NULL) {
1194 changed = __SCNetworkConfigurationCleanHiddenInterfaces(prefs, ni_prefs);
1195 if (changed) {
1196 SC_log(LOG_NOTICE, "network configuration: hidden interface configurations removed");
1197 updated = TRUE;
1198 }
1199 }
1200
1201 changed = __SCNetworkConfigurationCleanServiceOrderIssues(prefs);
1202 if (changed) {
1203 SC_log(LOG_NOTICE, "network configuration: ServiceOrder cleaned");
1204 updated = TRUE;
1205 }
1206
1207 return updated;
1208 }