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