]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkConfigurationPrivate.c
52ce138f7ec8977fc1b2b5da26e7dde3daa10887
[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
129 SC_log(LOG_INFO,
130 "__SCNetworkConfigurationBackup()"
131 "\n relativeTo = %@"
132 "\n prefs = %@"
133 "\n backup = %@",
134 relativeTo,
135 prefs,
136 backup);
137
138 if (backup != NULL) {
139 plist = SCPreferencesPathGetValue(prefs, CFSTR("/"));
140 SCPreferencesPathSetValue(backup, CFSTR("/"), plist);
141 ok = SCPreferencesCommitChanges(backup);
142 CFRelease(backup);
143 }
144
145 return ok;
146 }
147
148
149 Boolean
150 __SCNetworkConfigurationSaveModel(SCPreferencesRef prefs, CFStringRef model)
151 {
152 Boolean ok;
153 CFStringRef save_prefsID;
154
155 SC_log(LOG_NOTICE, "creating [per-device] backup: %@", model);
156
157 save_prefsID = CFStringCreateWithFormat(NULL, NULL, CFSTR("preferences-%@.plist"), model);
158 ok = savePreferences(prefs, save_prefsID, CFSTR(""), TRUE, MODEL, model);
159 CFRelease(save_prefsID);
160 return ok;
161 }
162
163
164 static Boolean
165 needsUpdate(SCPreferencesRef prefs, int new_version)
166 {
167 CFNumberRef num;
168 int old_version = 0;
169
170 if (prefs == NULL) {
171 // if no prefs, no updated needed
172 return FALSE;
173 }
174
175 num = SCPreferencesGetValue(prefs, kSCPrefVersion);
176 if (!isA_CFNumber(num) ||
177 !CFNumberGetValue(num, kCFNumberIntType, &old_version)) {
178 old_version = 0;
179 }
180 if (old_version == new_version) {
181 // if no update is needed
182 return FALSE;
183 }
184
185 return TRUE;
186 }
187
188
189 static Boolean
190 lockWithSync(SCPreferencesRef prefs)
191 {
192 Boolean ok;
193
194 assert(prefs != NULL);
195 ok = SCPreferencesLock(prefs, TRUE);
196 if (!ok && (SCError() == kSCStatusStale)) {
197 SCPreferencesSynchronize(prefs);
198 ok = SCPreferencesLock(prefs, TRUE);
199 }
200
201 return ok;
202 }
203
204
205 Boolean
206 __SCNetworkConfigurationUpgrade(SCPreferencesRef *prefs_p,
207 SCPreferencesRef *ni_prefs_p,
208 Boolean commit)
209 {
210 SCPreferencesRef ni_prefs = NULL;
211 Boolean ni_prefs_added = FALSE;
212 const int new_version = NETWORK_CONFIGURATION_VERSION;
213 CFNumberRef num;
214 Boolean ok = FALSE;
215 SCPreferencesRef prefs = NULL;
216 Boolean prefs_added = FALSE;
217
218 //
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.
221 //
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 // +====================+=============+=============+=============+=============+========+
233 //
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
237 // plists.
238 //
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.
242 //
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).
248 //
249
250 if (prefs_p != NULL) {
251 prefs = *prefs_p;
252 }
253
254 if (ni_prefs_p != NULL) {
255 ni_prefs = *ni_prefs_p;
256 }
257
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);
262 if (prefs == NULL) {
263 SC_log(LOG_ERR,
264 "__SCNetworkConfigurationUpgrade(): could not open [preferences.plist]: %s",
265 SCErrorString(SCError()));
266 return FALSE;
267 }
268 prefs_added = TRUE;
269 }
270
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) {
276 SC_log(LOG_ERR,
277 "__SCNetworkConfigurationUpgrade(): could not open [NetworkInterfaces.plist]: %s",
278 SCErrorString(SCError()));
279 return FALSE;
280 }
281 ni_prefs_added = TRUE;
282 }
283
284 if (!needsUpdate(prefs, NETWORK_CONFIGURATION_VERSION) &&
285 !needsUpdate(ni_prefs, NETWORK_CONFIGURATION_VERSION)) {
286 goto done;
287 }
288
289 // lock [preferences.plist] changes while we are updating
290 ok = lockWithSync(prefs);
291 if (!ok) {
292 SC_log(LOG_ERR,
293 "__SCNetworkConfigurationUpgrade(): could not lock [preferences.plist]: %s",
294 SCErrorString(SCError()));
295 goto done;
296 }
297
298 if (ni_prefs != NULL) {
299 // lock [NetworkInterfaces.plist] changes while we are updating
300 ok = lockWithSync(ni_prefs);
301 if (!ok) {
302 SC_log(LOG_ERR,
303 "__SCNetworkConfigurationUpgrade(): could not lock [NetworkInterfaces.plist]: %s",
304 SCErrorString(SCError()));
305 SCPreferencesUnlock(prefs);
306 goto done;
307 }
308 }
309
310 // first, cleanup any leftover cruft from the configuration
311 __SCNetworkConfigurationClean(prefs, ni_prefs);
312
313 // update the version(s)
314 num = CFNumberCreate(NULL, kCFNumberIntType, &new_version);
315 SCPreferencesSetValue(prefs, kSCPrefVersion, num);
316 CFRelease(num);
317 if (ni_prefs != NULL) {
318 num = CFNumberCreate(NULL, kCFNumberIntType, &new_version);
319 SCPreferencesSetValue(ni_prefs, kSCPrefVersion, num);
320 CFRelease(num);
321 }
322
323 if (commit) {
324 // commit the [preferences.plist] changes
325 ok = SCPreferencesCommitChanges(prefs);
326 if (!ok) {
327 SC_log(LOG_ERR,
328 "__SCNetworkConfigurationUpgrade(): update not saved [preferences.plist]: %s",
329 SCErrorString(SCError()));
330 }
331 if (ok) {
332 ok = SCPreferencesApplyChanges(prefs);
333 if (!ok) {
334 SC_log(LOG_ERR,
335 "__SCNetworkConfigurationUpgrade(): update not applied [preferences.plist]: %s",
336 SCErrorString(SCError()));
337 }
338 }
339 }
340 SCPreferencesUnlock(prefs);
341
342 if (ni_prefs != NULL) {
343 if (commit) {
344 // commit the [NetworkInterfaces.plist] changes
345 if (ok) {
346 ok = SCPreferencesCommitChanges(ni_prefs);
347 if (!ok) {
348 SC_log(LOG_ERR,
349 "__SCNetworkConfigurationUpgrade(): update not saved [NetworkInterfaces.plist]: %s",
350 SCErrorString(SCError()));
351 }
352 }
353 }
354 SCPreferencesUnlock(ni_prefs);
355 }
356
357 done :
358
359 if (prefs_added) {
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.
363 CFRelease(prefs);
364 }
365
366 if (ni_prefs_added) {
367 if (ok && (ni_prefs_p != NULL)) {
368 *ni_prefs_p = CFRetain(ni_prefs);
369 }
370 CFRelease(ni_prefs);
371 }
372
373 return ok;
374 }
375
376
377 #pragma mark -
378 #pragma mark Remove "Hidden" Interface Configurations
379
380
381 static Boolean
382 isThin(CFArrayRef interfaces, CFStringRef bsdName)
383 {
384 Boolean thin;
385
386 thin = CFArrayContainsValue(interfaces,
387 CFRangeMake(0, CFArrayGetCount(interfaces)),
388 bsdName);
389 return thin;
390 }
391
392
393 static Boolean
394 thinAdd(CFMutableArrayRef interfaces, CFStringRef bsdName)
395 {
396 if (!CFArrayContainsValue(interfaces,
397 CFRangeMake(0, CFArrayGetCount(interfaces)),
398 bsdName)) {
399 CFArrayAppendValue(interfaces, bsdName);
400 return TRUE;
401 }
402
403 return FALSE;
404 }
405
406
407 static Boolean
408 thinRemove(CFMutableArrayRef interfaces, CFStringRef bsdName)
409 {
410 CFIndex n;
411
412 n = CFArrayGetFirstIndexOfValue(interfaces,
413 CFRangeMake(0, CFArrayGetCount(interfaces)),
414 bsdName);
415 if (n != kCFNotFound) {
416 CFArrayRemoveValueAtIndex(interfaces, n);
417 return TRUE;
418 }
419
420 return FALSE;
421 }
422
423
424 static CF_RETURNS_RETAINED CFStringRef
425 serviceMatchesTemplate(SCPreferencesRef prefs, SCNetworkServiceRef existingService)
426 {
427 CFStringRef conflict = NULL;
428 SCNetworkInterfaceRef existingInterface;
429 CFIndex n;
430 CFArrayRef protocols;
431 CFMutableArrayRef protocolTypes;
432 SCNetworkServiceRef templateService;
433
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"));
438 return conflict;
439 }
440
441 templateService = SCNetworkServiceCreate(prefs, existingInterface);
442 if (templateService == NULL) {
443 conflict = CFStringCreateCopy(NULL, CFSTR("could not create service for interface"));
444 return conflict;
445 }
446
447 (void) SCNetworkServiceEstablishDefaultConfiguration(templateService);
448
449 protocolTypes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
450
451 // get protocol types from the existing service
452 protocols = SCNetworkServiceCopyProtocols(existingService);
453 if (protocols != NULL) {
454 n = CFArrayGetCount(protocols);
455
456 for (CFIndex i = 0; i < n; i++) {
457 SCNetworkProtocolRef protocol;
458 CFStringRef protocolType;
459
460 protocol = CFArrayGetValueAtIndex(protocols, i);
461 protocolType = SCNetworkProtocolGetProtocolType(protocol);
462 if (!CFArrayContainsValue(protocolTypes,
463 CFRangeMake(0, CFArrayGetCount(protocolTypes)),
464 protocolType)) {
465 CFArrayAppendValue(protocolTypes, protocolType);
466 }
467 }
468
469 CFRelease(protocols);
470 }
471
472 // get protocol types from the template service
473 protocols = SCNetworkServiceCopyProtocols(templateService);
474 if (protocols != NULL) {
475 n = CFArrayGetCount(protocols);
476
477 for (CFIndex i = 0; i < n; i++) {
478 SCNetworkProtocolRef protocol;
479 CFStringRef protocolType;
480
481 protocol = CFArrayGetValueAtIndex(protocols, i);
482 protocolType = SCNetworkProtocolGetProtocolType(protocol);
483 if (!CFArrayContainsValue(protocolTypes,
484 CFRangeMake(0, CFArrayGetCount(protocolTypes)),
485 protocolType)) {
486 CFArrayAppendValue(protocolTypes, protocolType);
487 }
488 }
489
490 CFRelease(protocols);
491 }
492
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;
498 Boolean match;
499 CFStringRef protocolType;
500 CFDictionaryRef templateConfiguration = NULL;
501 SCNetworkProtocolRef templateProtocol;
502
503 protocolType = CFArrayGetValueAtIndex(protocolTypes, i);
504 existingProtocol = SCNetworkServiceCopyProtocol(existingService, protocolType);
505 templateProtocol = SCNetworkServiceCopyProtocol(templateService, protocolType);
506
507 do {
508 // compare "enabled"
509 match = ((existingProtocol != NULL) &&
510 (templateProtocol != NULL) &&
511 (SCNetworkProtocolGetEnabled(existingProtocol) == SCNetworkProtocolGetEnabled(templateProtocol)));
512 if (!match) {
513 conflict = CFStringCreateWithFormat(NULL, NULL,
514 CFSTR("conflicting %@ enable/disable"),
515 protocolType);
516 break; // if enable/disable conflict
517 }
518
519 if (existingProtocol != NULL) {
520 existingConfiguration = SCNetworkProtocolGetConfiguration(existingProtocol);
521 }
522 if (templateProtocol != NULL) {
523 templateConfiguration = SCNetworkProtocolGetConfiguration(templateProtocol);
524 }
525 match = _SC_CFEqual(existingConfiguration, templateConfiguration);
526 if (!match) {
527 conflict = CFStringCreateWithFormat(NULL, NULL,
528 CFSTR("conflicting %@ configuration"),
529 protocolType);
530 break; // if configuration conflict
531 }
532 } while (FALSE);
533
534 if (existingProtocol != NULL) CFRelease(existingProtocol);
535 if (templateProtocol != NULL) CFRelease(templateProtocol);
536 if (!match) {
537 break;
538 }
539 }
540
541 (void) SCNetworkServiceRemove(templateService);
542 CFRelease(templateService);
543 CFRelease(protocolTypes);
544 return conflict;
545 }
546
547
548 static Boolean
549 effectivelyHiddenConfiguration(SCNetworkInterfaceRef interface)
550 {
551 const CFStringRef known[] = {
552 CFSTR("Apple TV"),
553 CFSTR("Watch"),
554 CFSTR("iPad"),
555 CFSTR("iPhone"),
556 CFSTR("iPod"),
557 };
558 CFStringRef name;
559
560 name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
561 for (int i = 0; i < (int)(sizeof(known) / sizeof(known[0])); i++) {
562 if (CFStringHasPrefix(name, known[i])) {
563 return TRUE;
564 }
565 }
566
567 return FALSE;
568 }
569
570
571 static Boolean
572 __SCNetworkConfigurationCleanHiddenInterfaces(SCPreferencesRef prefs, SCPreferencesRef ni_prefs)
573 {
574 #pragma unused(prefs)
575 #pragma unused(ni_prefs)
576 CFStringRef bsdName;
577 Boolean changed = FALSE;
578 CFArrayRef interfaces;
579 CFMutableArrayRef interfaces_thin;
580 CFIndex n;
581 #if TARGET_OS_OSX
582 CFDictionaryRef nat_config;
583 SCPreferencesRef nat_prefs;
584 #endif // TARGET_OS_OSX
585 CFArrayRef services;
586 int updated = 0;
587
588 // build a list of interfaces we "could" remove
589
590 interfaces_thin = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
591
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;
600
601 service = CFArrayGetValueAtIndex(services, i);
602 interface = SCNetworkServiceGetInterface(service);
603 bsdName = SCNetworkInterfaceGetBSDName(interface);
604
605 if (bsdName == NULL) {
606 // if no interface name
607 if (logDetails) {
608 SC_log(LOG_INFO,
609 "skipping service : %@ : %@ (no interface)",
610 SCNetworkServiceGetServiceID(service),
611 SCNetworkServiceGetName(service));
612 }
613 continue;
614 }
615
616 if (_SCNetworkInterfaceIsHiddenConfiguration(interface)) {
617 thin = "hidden";
618 } else if (effectivelyHiddenConfiguration(interface)) {
619 thin = "effectively hidden";
620 } else {
621 // if not HiddenConfiguration
622 if (logDetails) {
623 SC_log(LOG_INFO,
624 "skipping service : %@ : %@ : %@ (not hidden)",
625 SCNetworkServiceGetServiceID(service),
626 SCNetworkServiceGetName(service),
627 bsdName);
628 }
629 continue;
630 }
631
632 conflict = serviceMatchesTemplate(prefs, service);
633 if (conflict != NULL) {
634 // if any part of the service's configuration was changed
635 if (logDetails) {
636 SC_log(LOG_INFO,
637 "skipping service : %@ : %@ : %@ (%s, non-default, %@)",
638 SCNetworkServiceGetServiceID(service),
639 SCNetworkServiceGetName(service),
640 bsdName,
641 thin,
642 conflict);
643 }
644 CFRelease(conflict);
645 continue;
646 }
647
648 if (logDetails) {
649 SC_log(LOG_INFO, "candidate interface : %@ (%s)", bsdName, thin);
650 }
651
652 thinAdd(interfaces_thin, bsdName);
653 }
654 }
655
656 // remove any virtual interfaces from the list
657
658 #if !TARGET_OS_IPHONE
659 interfaces = SCBondInterfaceCopyAll(prefs);
660 if (interfaces != NULL) {
661 CFIndex n;
662
663 n = CFArrayGetCount(interfaces);
664 for (CFIndex i = 0; i < n; i++) {
665 SCBondInterfaceRef bondInterface;
666 CFArrayRef members;
667 CFIndex nn;
668
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;
674
675 member = CFArrayGetValueAtIndex(members, ii);
676 bsdName = SCNetworkInterfaceGetBSDName(member);
677 if ((bsdName != NULL) &&
678 thinRemove(interfaces_thin, bsdName)) {
679 if (logDetails) {
680 SC_log(LOG_INFO, "skipping interface : %@ (bond member)", bsdName);
681 }
682 }
683 }
684 }
685
686 CFRelease(interfaces);
687 }
688 #endif // !TARGET_OS_IPHONE
689
690 interfaces = SCBridgeInterfaceCopyAll(prefs);
691 if (interfaces != NULL) {
692 CFIndex n;
693
694 n = CFArrayGetCount(interfaces);
695 for (CFIndex i = 0; i < n; i++) {
696 SCBridgeInterfaceRef bridgeInterface;
697 CFArrayRef members;
698 CFIndex nn;
699
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;
705
706 member = CFArrayGetValueAtIndex(members, ii);
707 bsdName = SCNetworkInterfaceGetBSDName(member);
708 if ((bsdName != NULL) &&
709 thinRemove(interfaces_thin, bsdName)) {
710 if (logDetails) {
711 SC_log(LOG_INFO, "skipping interface : %@ (bridge member)", bsdName);
712 }
713 }
714 }
715 }
716
717 CFRelease(interfaces);
718 }
719
720 interfaces = SCVLANInterfaceCopyAll(prefs);
721 if (interfaces != NULL) {
722 CFIndex n;
723
724 n = CFArrayGetCount(interfaces);
725 for (CFIndex i = 0; i < n; i++) {
726 SCBridgeInterfaceRef vlanInterface;
727 SCNetworkInterfaceRef physicalInterface;
728
729 vlanInterface = CFArrayGetValueAtIndex(interfaces, i);
730 physicalInterface = SCVLANInterfaceGetPhysicalInterface(vlanInterface);
731 bsdName = SCNetworkInterfaceGetBSDName(physicalInterface);
732 if ((bsdName != NULL) &&
733 thinRemove(interfaces_thin, bsdName)) {
734 if (logDetails) {
735 SC_log(LOG_INFO, "skipping interface : %@ (vlan physical)", bsdName);
736 }
737 }
738 }
739
740 CFRelease(interfaces);
741 }
742
743 // remove any "shared" interfaces from the list
744
745 #if TARGET_OS_OSX
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;
753
754 if (CFDictionaryGetValueIfPresent(nat_config,
755 CFSTR("Enabled"),
756 (const void **)&bVal) &&
757 isA_CFBoolean(bVal)) {
758 enabled = CFBooleanGetValue(bVal);
759 }
760
761 if (enabled &&
762 CFDictionaryGetValueIfPresent(nat_config,
763 CFSTR("PrimaryService"),
764 (const void **)&sharedFrom) &&
765 isA_CFString(sharedFrom)) {
766 SCNetworkInterfaceRef interface;
767 SCNetworkServiceRef service;
768
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)) {
776 if (logDetails) {
777 SC_log(LOG_INFO, "skipping interface : %@ (Share your connection from)", bsdName);
778 }
779 }
780 CFRelease(service);
781 } else {
782 SC_log(LOG_INFO, "keeping [not found] service : %@ (Share your connection from)", sharedFrom);
783 }
784 }
785
786 if (enabled &&
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)) {
796 if (logDetails) {
797 SC_log(LOG_INFO, "skipping interface : %@ (To computers using)", bsdName);
798 }
799 }
800 }
801 }
802 }
803 CFRelease(nat_prefs);
804 #endif // TARGET_OS_OSX
805
806 // thin preferences.plist
807 n = (services != NULL) ? CFArrayGetCount(services) : 0;
808 if (n > 0) {
809 updated = 0;
810
811 for (CFIndex i = 0; i < n; i++) {
812 SCNetworkInterfaceRef interface;
813 SCNetworkServiceRef service;
814
815 service = CFArrayGetValueAtIndex(services, i);
816 interface = SCNetworkServiceGetInterface(service);
817 bsdName = SCNetworkInterfaceGetBSDName(interface);
818 if (bsdName == NULL) {
819 // if no interface name
820 continue;
821 }
822
823 if (!isThin(interfaces_thin, bsdName)) {
824 // if not thinned
825 continue;
826 }
827
828 // remove this service associated with a "thinned" interface
829 if (logDetails || _sc_verbose) {
830 SC_log(LOG_INFO,
831 "thinned network service : %@ : %@ : %@",
832 SCNetworkServiceGetServiceID(service),
833 SCNetworkServiceGetName(service),
834 bsdName);
835 }
836 SCNetworkServiceRemove(service);
837 updated++;
838 }
839
840 if (updated > 0) {
841 if (logDetails) {
842 SC_log(LOG_NOTICE,
843 "Updating \"preferences.plist\" (thinned %d service%s)",
844 updated,
845 (updated != 1) ? "s" : "");
846 }
847 changed = TRUE;
848 }
849 }
850
851 // thin NetworkInterfaces.plist
852 interfaces = SCPreferencesGetValue(ni_prefs, INTERFACES);
853 interfaces = isA_CFArray(interfaces);
854 n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
855 if (n > 0) {
856 CFMutableArrayRef interfaces_new;
857
858 updated = 0;
859
860 interfaces_new = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
861 n = CFArrayGetCount(interfaces);
862 for (CFIndex i = 0; i < n; i++) {
863 CFDictionaryRef if_dict;
864
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))) {
869 if (logDetails) {
870 SC_log(LOG_INFO, "skipping interface : %@ (active)", bsdName);
871 }
872 } else {
873 // remove this "thinned" interface
874 if (logDetails || _sc_verbose) {
875 SC_log(LOG_INFO, "thinned network interface : %@", bsdName);
876 }
877 updated++;
878 continue;
879 }
880 }
881
882 CFArrayAppendValue(interfaces_new, if_dict);
883 }
884 SCPreferencesSetValue(ni_prefs, INTERFACES, interfaces_new);
885 CFRelease(interfaces_new);
886
887 if (updated > 0) {
888 if (logDetails) {
889 SC_log(LOG_INFO,
890 "Updating \"NetworkInterfaces.plist\" (thinned %d interface%s)",
891 updated,
892 (updated != 1) ? "s" : "");
893 }
894 changed = TRUE;
895 }
896 }
897
898 if (services != NULL) CFRelease(services);
899 CFRelease(interfaces_thin);
900 return changed;
901 }
902
903
904 #pragma mark -
905 #pragma mark Remove [SCNetworkMigration] Inline Backups
906
907
908 static void
909 thinInlineBackup(const void *value, void *context)
910 {
911 CFStringRef backup = (CFStringRef)value;
912 char *backup_str;
913 SCPreferencesRef prefs = (SCPreferencesRef)context;
914 CFStringRef save_prefix;
915 CFStringRef save_prefsID = NULL;
916
917 SC_log(LOG_NOTICE, "thinning [inline] backup: %@", backup);
918
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 };
923
924 if (strptime(backup_str, "%Y-%m-%d %H:%M:%S", &save_tm) != NULL) {
925 save_prefsID = CFStringCreateWithFormat(NULL,
926 NULL,
927 CFSTR("preferences-%4d-%02d-%02d-%02d%02d%02d.plist"),
928 save_tm.tm_year + 1900,
929 save_tm.tm_mon + 1,
930 save_tm.tm_mday,
931 save_tm.tm_hour,
932 save_tm.tm_min,
933 save_tm.tm_sec);
934 }
935 CFAllocatorDeallocate(NULL, backup_str);
936 }
937 if (save_prefsID == NULL) {
938 save_prefsID = CFStringCreateWithFormat(NULL, NULL, CFSTR("preferences-%@.plist"), backup);
939 }
940 savePreferences(prefs, save_prefsID, save_prefix, TRUE, NULL, NULL);
941 CFRelease(save_prefsID);
942 CFRelease(save_prefix);
943 return;
944 }
945
946
947 static Boolean
948 __SCNetworkConfigurationCleanInlineBackups(SCPreferencesRef prefs)
949 {
950 CFMutableSetRef backups = NULL;
951 Boolean cleaned = FALSE;
952 CFArrayRef keys;
953 CFIndex n;
954 CFStringRef suffix;
955
956 keys = SCPreferencesCopyKeyList(prefs);
957 if (keys == NULL) {
958 return FALSE;
959 }
960
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;
966
967 if (CFStringHasSuffix(key, suffix)) {
968 // if "<backup-date> : Sets"
969 if (backups == NULL) {
970 backups = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
971 }
972 str = CFStringCreateMutableCopy(NULL, 0, key);
973 CFStringTrim(str, suffix);
974 CFSetAddValue(backups, str);
975 CFRelease(str);
976 continue;
977 }
978 }
979 CFRelease(suffix);
980 CFRelease(keys);
981
982 if (backups != NULL) {
983 CFSetApplyFunction(backups, thinInlineBackup, (void *)prefs);
984 CFRelease(backups);
985 cleaned = TRUE;
986 }
987
988 return cleaned;
989 }
990
991
992 #pragma mark -
993 #pragma mark Remove [new device type] Inline Backups
994
995
996 static void
997 thinInlineModel(const void *value, void *context)
998 {
999 CFStringRef model = (CFStringRef)value;
1000 SCPreferencesRef prefs = (SCPreferencesRef)context;
1001 CFStringRef save_prefix;
1002 CFStringRef save_prefsID;
1003
1004 SC_log(LOG_NOTICE, "thinning [per-model] backup: %@", model);
1005
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);
1011 return;
1012 }
1013
1014
1015 static Boolean
1016 __SCNetworkConfigurationCleanInlineModels(SCPreferencesRef prefs)
1017 {
1018 Boolean cleaned = FALSE;
1019 CFArrayRef keys;
1020 CFMutableSetRef models = NULL;
1021 CFIndex n;
1022 CFStringRef suffix;
1023
1024 keys = SCPreferencesCopyKeyList(prefs);
1025 if (keys == NULL) {
1026 return FALSE;
1027 }
1028
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;
1034
1035 if (CFStringHasSuffix(key, suffix)) {
1036 // if "<backup-date> : Sets"
1037 if (models == NULL) {
1038 models = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1039 }
1040 str = CFStringCreateMutableCopy(NULL, 0, key);
1041 CFStringTrim(str, suffix);
1042 CFSetAddValue(models, str);
1043 CFRelease(str);
1044 continue;
1045 }
1046 }
1047 CFRelease(suffix);
1048 CFRelease(keys);
1049
1050 if (models != NULL) {
1051 CFSetApplyFunction(models, thinInlineModel, (void *)prefs);
1052 CFRelease(models);
1053 cleaned = TRUE;
1054 }
1055
1056 return cleaned;
1057 }
1058
1059
1060 #pragma mark -
1061 #pragma mark Remove Orphaned Services
1062
1063
1064 /*
1065 static Boolean
1066 __SCNetworkConfigurationCleanOrphanedServices(SCPreferencesRef prefs)
1067 {
1068 #pragma unused(prefs)
1069 return FALSE;
1070 }
1071 */
1072
1073
1074 #pragma mark -
1075 #pragma mark Cleanup network service order issues
1076
1077
1078 static Boolean
1079 __SCNetworkConfigurationCleanServiceOrderIssues(SCPreferencesRef prefs)
1080 {
1081 #pragma unused(prefs)
1082 Boolean cleaned = FALSE;
1083 CFIndex nSets;
1084 CFArrayRef sets;
1085
1086 sets = SCNetworkSetCopyAll(prefs);
1087 nSets = (sets != NULL) ? CFArrayGetCount(sets) : 0;
1088 for (CFIndex iSets = 0; iSets < nSets; iSets++) {
1089 CFIndex iServices;
1090 CFMutableSetRef known = NULL;
1091 CFIndex nServices;
1092 SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, iSets);
1093 CFStringRef setID = SCNetworkSetGetSetID(set);
1094 CFArrayRef order = SCNetworkSetGetServiceOrder(set);
1095 CFMutableArrayRef newOrder = NULL;
1096
1097 iServices = 0;
1098 nServices = (order != NULL) ? CFArrayGetCount(order) : 0;
1099 if (nServices > 0) {
1100 known = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
1101 newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
1102 }
1103
1104 while (iServices < nServices) {
1105 SCNetworkServiceRef service;
1106 CFStringRef serviceID = CFArrayGetValueAtIndex(newOrder, iServices);
1107
1108 // check if serviceID already known/processed
1109 if (CFSetContainsValue(known, serviceID)) {
1110 // if duplicate/removed service, remove from serviceOrder
1111 if (logDetails) {
1112 SC_log(LOG_NOTICE,
1113 "set: %@, removing serviceID %@ (duplicate/removed)",
1114 setID,
1115 serviceID);
1116 }
1117 CFArrayRemoveValueAtIndex(newOrder, iServices);
1118 nServices--;
1119 cleaned = TRUE;
1120 continue;
1121 }
1122
1123 // track this serviceID as known, already removed, or removed below
1124 CFSetAddValue(known, serviceID);
1125
1126 // validate serviceID
1127 service = SCNetworkServiceCopy(prefs, serviceID);
1128 if (service == NULL) {
1129 // if no service, remove from serviceOrder
1130 if (logDetails) {
1131 SC_log(LOG_NOTICE,
1132 "set: %@, removing serviceID %@ (no service)",
1133 setID,
1134 serviceID);
1135 }
1136 CFArrayRemoveValueAtIndex(newOrder, iServices);
1137 nServices--;
1138 cleaned = TRUE;
1139 continue;
1140 }
1141
1142 if (!__SCNetworkServiceExists(service)) {
1143 // if service already removed, remove from serviceOrder
1144 if (logDetails) {
1145 SC_log(LOG_NOTICE,
1146 "set: %@, removing serviceID %@ (service already removed)",
1147 setID,
1148 serviceID);
1149 }
1150 CFArrayRemoveValueAtIndex(newOrder, iServices);
1151 nServices--;
1152 cleaned = TRUE;
1153 CFRelease(service);
1154 continue;
1155 }
1156
1157 CFRelease(service);
1158 iServices++;
1159 }
1160
1161 if (known != NULL) {
1162 CFRelease(known);
1163 }
1164
1165 if (newOrder != NULL) {
1166 if (cleaned) {
1167 SCNetworkSetSetServiceOrder(set, newOrder);
1168 }
1169 CFRelease(newOrder);
1170 }
1171 }
1172
1173 if (sets != NULL) {
1174 CFRelease(sets);
1175 }
1176
1177 return cleaned;
1178 }
1179
1180
1181 #pragma mark -
1182 #pragma mark Cleanup Network Configuration(s)
1183
1184
1185 Boolean
1186 __SCNetworkConfigurationClean(SCPreferencesRef prefs, SCPreferencesRef ni_prefs)
1187 {
1188 Boolean changed;
1189 Boolean updated = FALSE;
1190
1191 changed = __SCNetworkConfigurationCleanInlineBackups(prefs);
1192 if (changed) {
1193 SC_log(LOG_NOTICE, "network configuration: unwanted inline backups removed");
1194 updated = TRUE;
1195 }
1196
1197 changed = __SCNetworkConfigurationCleanInlineModels(prefs);
1198 if (changed) {
1199 SC_log(LOG_NOTICE, "network configuration: unwanted device backups removed");
1200 updated = TRUE;
1201 }
1202
1203 if (ni_prefs != NULL) {
1204 changed = __SCNetworkConfigurationCleanHiddenInterfaces(prefs, ni_prefs);
1205 if (changed) {
1206 SC_log(LOG_NOTICE, "network configuration: hidden interface configurations removed");
1207 updated = TRUE;
1208 }
1209 }
1210
1211 changed = __SCNetworkConfigurationCleanServiceOrderIssues(prefs);
1212 if (changed) {
1213 SC_log(LOG_NOTICE, "network configuration: ServiceOrder cleaned");
1214 updated = TRUE;
1215 }
1216
1217 return updated;
1218 }