]> git.saurik.com Git - apple/configd.git/blob - Plugins/PreferencesMonitor/prefsmon.c
8a091e2dffedd76f63af03cdb80666509a20cd98
[apple/configd.git] / Plugins / PreferencesMonitor / prefsmon.c
1 /*
2 * Copyright (c) 2000-2008, 2010, 2012-2016 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 * April 2, 2004 Allan Nathanson <ajn@apple.com>
28 * - use SCPreference notification APIs
29 *
30 * June 24, 2001 Allan Nathanson <ajn@apple.com>
31 * - update to public SystemConfiguration.framework APIs
32 *
33 * November 10, 2000 Allan Nathanson <ajn@apple.com>
34 * - initial revision
35 */
36
37
38 #include <TargetConditionals.h>
39 #include <fcntl.h>
40 #include <net/if.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44
45
46 #define SC_LOG_HANDLE __log_PreferencesMonitor()
47 #include <SystemConfiguration/SystemConfiguration.h>
48 #include <SystemConfiguration/SCPrivate.h>
49 #include <SystemConfiguration/SCValidation.h>
50 #include "plugin_shared.h"
51
52
53 #include <CommonCrypto/CommonDigest.h>
54
55
56 /* globals */
57 static SCPreferencesRef prefs = NULL;
58 static SCDynamicStoreRef store = NULL;
59
60 /* InterfaceNamer[.plugin] monitoring globals */
61 Boolean haveConfiguration = FALSE;
62 static CFStringRef namerKey = NULL;
63 static CFArrayRef preconfigured = NULL;
64
65 /* KernelEventMonitor[.plugin] monitoring globals */
66 static CFStringRef interfacesKey = NULL;
67
68 /* SCDynamicStore (Setup:) */
69 static CFMutableDictionaryRef currentPrefs; /* current prefs */
70 static CFMutableDictionaryRef newPrefs; /* new prefs */
71 static CFMutableArrayRef unchangedPrefsKeys; /* new prefs keys which match current */
72 static CFMutableArrayRef removedPrefsKeys; /* old prefs keys to be removed */
73
74 static Boolean rofs = FALSE;
75 static Boolean restorePrefs = FALSE;
76
77 #define MY_PLUGIN_NAME "PreferencesMonitor"
78 #define MY_PLUGIN_ID CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
79
80
81 static void
82 updateConfiguration(SCPreferencesRef prefs,
83 SCPreferencesNotification notificationType,
84 void *info);
85
86
87 static os_log_t
88 __log_PreferencesMonitor()
89 {
90 static os_log_t log = NULL;
91
92 if (log == NULL) {
93 log = os_log_create("com.apple.SystemConfiguration", "PreferencesMonitor");
94 }
95
96 return log;
97 }
98
99
100 static Boolean
101 restorePreferences()
102 {
103 Boolean ok = FALSE;
104 CFStringRef currentModel = NULL;
105 CFMutableStringRef modelPrefixStr = NULL;
106 CFArrayRef keyList = NULL;
107 CFIndex keyListCount;
108 CFIndex idx;
109 Boolean modified = FALSE;
110 int sc_status = kSCStatusFailed;
111
112 while (TRUE) {
113 ok = SCPreferencesLock(prefs, TRUE);
114 if (ok) {
115 break;
116 }
117
118 sc_status = SCError();
119 if (sc_status == kSCStatusStale) {
120 SCPreferencesSynchronize(prefs);
121 } else {
122 SC_log(LOG_NOTICE, "Could not acquire network configuration lock: %s",
123 SCErrorString(sc_status));
124 return FALSE;
125 }
126 }
127
128 keyList = SCPreferencesCopyKeyList(prefs);
129 if (keyList == NULL) {
130 goto error;
131 }
132
133 currentModel = _SC_hw_model(FALSE);
134 if (currentModel == NULL) {
135 goto error;
136 }
137
138 /* Create "model:" string for prefix-check */
139 modelPrefixStr = CFStringCreateMutableCopy(NULL, 0, currentModel);
140 CFStringAppend(modelPrefixStr, CFSTR(":"));
141
142 keyListCount = CFArrayGetCount(keyList);
143 for (idx = 0; idx < keyListCount; idx++) {
144 CFStringRef existingKey = CFArrayGetValueAtIndex(keyList, idx);
145 CFStringRef key;
146 CFArrayRef splitKey = NULL;
147 CFPropertyListRef value;
148
149 if (isA_CFString(existingKey) == NULL) {
150 continue;
151 }
152
153 if (!CFStringHasPrefix(existingKey, modelPrefixStr)) {
154 continue;
155 }
156
157 splitKey = CFStringCreateArrayBySeparatingStrings(NULL, existingKey, CFSTR(":"));
158 key = CFArrayGetValueAtIndex(splitKey, 1);
159 value = SCPreferencesGetValue(prefs, existingKey);
160 SCPreferencesSetValue(prefs, key, value);
161 SCPreferencesRemoveValue(prefs, existingKey);
162 modified = TRUE;
163 CFRelease(splitKey);
164 }
165
166 if (modified) {
167 SCPreferencesRef ni_prefs = NULL;
168 ni_prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, CFSTR("NetworkInterfaces.plist"));
169 if (ni_prefs == NULL) {
170 goto error;
171 }
172
173 ok = _SCNetworkConfigurationCheckValidityWithPreferences(prefs, ni_prefs, NULL);
174 CFRelease(ni_prefs);
175
176 //Commit the changes only if prefs files valid
177 if (ok) {
178 if (!SCPreferencesCommitChanges(prefs)) {
179 if (SCError() != EROFS) {
180 SC_log(LOG_NOTICE, "SCPreferencesCommitChanges() failed: %s",
181 SCErrorString(SCError()));
182 }
183 goto error;
184
185 }
186
187 (void) SCPreferencesApplyChanges(prefs);
188 }
189 }
190
191 error:
192 (void) SCPreferencesUnlock(prefs);
193
194 if (keyList != NULL) {
195 CFRelease(keyList);
196 }
197 if (modelPrefixStr != NULL) {
198 CFRelease(modelPrefixStr);
199 }
200
201 return modified;
202 }
203
204 static Boolean
205 establishNewPreferences()
206 {
207 SCNetworkSetRef current = NULL;
208 CFStringRef new_model;
209 Boolean ok = FALSE;
210 int sc_status = kSCStatusFailed;
211 SCNetworkSetRef set = NULL;
212 Boolean updated = FALSE;
213
214 while (TRUE) {
215 ok = SCPreferencesLock(prefs, TRUE);
216 if (ok) {
217 break;
218 }
219
220 sc_status = SCError();
221 if (sc_status == kSCStatusStale) {
222 SCPreferencesSynchronize(prefs);
223 } else {
224 SC_log(LOG_NOTICE, "Could not acquire network configuration lock: %s",
225 SCErrorString(sc_status));
226 return FALSE;
227 }
228 }
229
230 /* Ensure that the preferences has the new model */
231 new_model = _SC_hw_model(FALSE);
232
233 /* Need to regenerate the new configuration for new model */
234 if (new_model != NULL) {
235 CFStringRef old_model;
236
237 old_model = SCPreferencesGetValue(prefs, MODEL);
238 if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
239 CFIndex count;
240 CFIndex index;
241 CFArrayRef keys;
242
243 keys = SCPreferencesCopyKeyList(prefs);
244 count = (keys != NULL) ? CFArrayGetCount(keys) : 0;
245 // if new hardware
246 for (index = 0; index < count; index++) {
247 CFStringRef existing_key;
248
249 existing_key = CFArrayGetValueAtIndex(keys, index);
250 if (isA_CFString(existing_key) != NULL) {
251 CFStringRef new_key;
252 CFPropertyListRef value;
253
254 /* If it already contains a Model
255 or if it already contains a MODEL:KEY key skip it*/
256 if (CFEqual(existing_key, MODEL)
257 || CFStringFind(existing_key, CFSTR(":"), 0).location
258 != kCFNotFound) {
259 continue;
260 }
261
262 value = SCPreferencesGetValue(prefs, existing_key);
263
264 /* Create a new key as OLD_MODEL:OLD_KEY */
265 new_key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"),
266 old_model, existing_key);
267 SCPreferencesSetValue(prefs, new_key, value);
268 if (!CFEqual(existing_key, kSCPrefSystem)) {
269 /* preserve existing host names */
270 SCPreferencesRemoveValue(prefs, existing_key);
271 }
272 CFRelease(new_key);
273 }
274 }
275
276 if (keys != NULL) {
277 CFRelease(keys);
278 }
279 }
280 /* Set the new model */
281 SCPreferencesSetValue(prefs, MODEL, new_model);
282 }
283
284 current = SCNetworkSetCopyCurrent(prefs);
285 if (current != NULL) {
286 set = current;
287 }
288
289 if (set == NULL) {
290 set = _SCNetworkSetCreateDefault(prefs);
291 if (set == NULL) {
292 ok = FALSE;
293 sc_status = SCError();
294 goto done;
295 }
296 }
297
298 ok = SCNetworkSetEstablishDefaultConfiguration(set);
299 if (!ok) {
300 sc_status = SCError();
301 goto done;
302 }
303
304 done :
305
306 if (ok) {
307 ok = SCPreferencesCommitChanges(prefs);
308 if (ok) {
309 SC_log(LOG_NOTICE, "New network configuration saved");
310 updated = TRUE;
311 } else {
312 sc_status = SCError();
313 if (sc_status == EROFS) {
314 /* a read-only fileysstem is OK */
315 ok = TRUE;
316
317 /* ... but we don't want to synchronize */
318 rofs = TRUE;
319 }
320 }
321
322 /* apply (committed or temporary/read-only) changes */
323 (void) SCPreferencesApplyChanges(prefs);
324 } else if ((current == NULL) && (set != NULL)) {
325 (void) SCNetworkSetRemove(set);
326 }
327
328 if (!ok) {
329 SC_log(LOG_NOTICE, "Could not establish network configuration: %s",
330 SCErrorString(sc_status));
331 }
332
333 (void)SCPreferencesUnlock(prefs);
334 if (set != NULL) CFRelease(set);
335 return updated;
336 }
337
338
339 static void
340 watchSCDynamicStore()
341 {
342 CFMutableArrayRef keys;
343 Boolean ok;
344 CFRunLoopSourceRef rls;
345
346 /*
347 * watch for KernelEventMonitor[.bundle] changes (the list of
348 * active network interfaces)
349 */
350 interfacesKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
351 kSCDynamicStoreDomainState);
352
353 /*
354 * watch for InterfaceNamer[.bundle] changes (quiet, timeout,
355 * and the list of pre-configured interfaces)
356 */
357 namerKey = SCDynamicStoreKeyCreate(NULL,
358 CFSTR("%@" "InterfaceNamer"),
359 kSCDynamicStoreDomainPlugin);
360
361 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
362 if (rls == NULL) {
363 SC_log(LOG_NOTICE, "SCDynamicStoreCreateRunLoopSource() failed: %s", SCErrorString(SCError()));
364 haveConfiguration = TRUE;
365 return;
366 }
367 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
368 CFRelease(rls);
369
370 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
371 CFArrayAppendValue(keys, interfacesKey);
372 CFArrayAppendValue(keys, namerKey);
373 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
374 CFRelease(keys);
375 if (!ok) {
376 SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError()));
377 haveConfiguration = TRUE;
378 }
379
380 return;
381 }
382
383
384
385
386 static Boolean
387 previousConfigurationAvailable()
388 {
389 CFStringRef backupKey = NULL;
390 CFStringRef currentModel = NULL;
391 CFPropertyListRef properties = NULL;
392
393 currentModel = _SC_hw_model(FALSE);
394 if (currentModel == NULL) {
395 goto done;
396 }
397
398 /* Currently relying only if a backup of "Sets" is present */
399 backupKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:Sets"), currentModel);
400 properties = SCPreferencesGetValue(prefs, backupKey);
401 CFRelease(backupKey);
402 done:
403 return (properties != NULL);
404 }
405
406
407 static void
408 storeCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
409 {
410 CFDictionaryRef dict;
411 CFArrayRef interfaces = NULL;
412 Boolean quiet = FALSE;
413 Boolean timeout = FALSE;
414 Boolean updated = FALSE;
415
416 /*
417 * Capture/process KernelEventMonitor[.bundle] info
418 * 1. get list of active network interfaces
419 */
420 dict = SCDynamicStoreCopyValue(store, interfacesKey);
421 if (dict != NULL) {
422 if (isA_CFDictionary(dict)) {
423 interfaces = CFDictionaryGetValue(dict, kSCPropNetInterfaces);
424 interfaces = isA_CFArray(interfaces);
425 if (interfaces != NULL) {
426 CFRetain(interfaces);
427 }
428 }
429
430 CFRelease(dict);
431 }
432
433 /*
434 * Capture/process InterfaceNamer[.bundle] info
435 * 1. check if IORegistry "quiet", "timeout"
436 * 2. get list of named pre-configured interfaces
437 * 3. merge list of active interfaces (from KEV) with the
438 * list of preconfigured interfaces.
439 */
440 dict = SCDynamicStoreCopyValue(store, namerKey);
441 if (dict != NULL) {
442 if (isA_CFDictionary(dict)) {
443 CFArrayRef cur_preconfigured;
444 CFMutableArrayRef new_preconfigured = NULL;
445
446 if (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Quiet)) {
447 quiet = TRUE;
448 }
449 if (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Timeout)) {
450 timeout = TRUE;
451 }
452
453 cur_preconfigured = CFDictionaryGetValue(dict, kInterfaceNamerKey_PreConfiguredInterfaces);
454 cur_preconfigured = isA_CFArray(cur_preconfigured);
455 if ((cur_preconfigured != NULL) && (interfaces != NULL)) {
456 CFIndex i;
457 CFIndex n;
458 CFRange r = CFRangeMake(0, CFArrayGetCount(interfaces));
459
460 n = CFArrayGetCount(cur_preconfigured);
461 for (i = 0; i < n; i++) {
462 CFStringRef bsdName;
463
464 bsdName = CFArrayGetValueAtIndex(cur_preconfigured, i);
465 if (!CFArrayContainsValue(interfaces, r, bsdName)) {
466 // if interface not currently active
467 continue;
468 }
469
470 if (new_preconfigured == NULL) {
471 new_preconfigured = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
472 }
473 CFArrayAppendValue(new_preconfigured, bsdName);
474 }
475 }
476
477 if (!_SC_CFEqual(preconfigured, new_preconfigured)) {
478 SC_log(LOG_INFO, "pre-configured interface list changed");
479
480 if (preconfigured != NULL) {
481 CFRelease(preconfigured);
482 }
483 if (new_preconfigured != NULL) {
484 CFRetain(new_preconfigured);
485 }
486 preconfigured = new_preconfigured;
487
488 updated = TRUE;
489 }
490
491 if (new_preconfigured != NULL) {
492 CFRelease(new_preconfigured);
493 }
494 }
495
496 CFRelease(dict);
497 }
498
499 if (interfaces != NULL) {
500 CFRelease(interfaces);
501 }
502
503 if (!haveConfiguration && (quiet || timeout)) {
504 static int logged = 0;
505
506 if (quiet
507 #if !TARGET_OS_IPHONE
508 || timeout
509 #endif /* !TARGET_OS_IPHONE */
510 ) {
511 haveConfiguration = TRUE;
512 }
513
514 (void) establishNewPreferences();
515
516 if (restorePrefs) {
517 (void) restorePreferences();
518 restorePrefs = FALSE;
519 }
520
521 if (timeout && (logged++ == 0)) {
522 SC_log(LOG_ERR, "Network configuration creation timed out waiting for IORegistry");
523 }
524 }
525
526 if (updated && (changedKeys != NULL)) {
527 // if pre-configured interface list changed
528 updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
529 }
530
531 return;
532 }
533
534
535 static void
536 updateCache(const void *key, const void *value, void *context)
537 {
538 CFStringRef configKey = (CFStringRef)key;
539 CFPropertyListRef configData = (CFPropertyListRef)value;
540 CFPropertyListRef cacheData;
541 CFIndex i;
542
543 cacheData = CFDictionaryGetValue(currentPrefs, configKey);
544 if (cacheData) {
545 /* key exists */
546 if (CFEqual(cacheData, configData)) {
547 /*
548 * if the old & new property list values have
549 * not changed then we don't need to update
550 * the preference.
551 */
552 CFArrayAppendValue(unchangedPrefsKeys, configKey);
553 }
554 }
555
556 /* in any case, this key should not be removed */
557 i = CFArrayGetFirstIndexOfValue(removedPrefsKeys,
558 CFRangeMake(0, CFArrayGetCount(removedPrefsKeys)),
559 configKey);
560 if (i != kCFNotFound) {
561 CFArrayRemoveValueAtIndex(removedPrefsKeys, i);
562 }
563
564 return;
565 }
566
567
568 static void
569 flatten(SCPreferencesRef prefs,
570 CFStringRef key,
571 CFDictionaryRef base)
572 {
573 CFDictionaryRef subset;
574 CFStringRef link;
575 CFMutableDictionaryRef myDict;
576 CFStringRef myKey;
577 CFIndex i;
578 CFIndex nKeys;
579 const void **keys;
580 const void **vals;
581
582 if (!CFDictionaryGetValueIfPresent(base, kSCResvLink, (const void **)&link)) {
583 /* if this dictionary is not linked */
584 subset = base;
585 } else {
586 /* if __LINK__ key is present */
587 subset = SCPreferencesPathGetValue(prefs, link);
588 if (!subset) {
589 /* if error with link */
590 SC_log(LOG_NOTICE, "SCPreferencesPathGetValue(,%@,) failed: %s",
591 link,
592 SCErrorString(SCError()));
593 return;
594 }
595 }
596
597 if (CFDictionaryContainsKey(subset, kSCResvInactive)) {
598 /* if __INACTIVE__ key is present */
599 return;
600 }
601
602 myKey = CFStringCreateWithFormat(NULL,
603 NULL,
604 CFSTR("%@%@"),
605 kSCDynamicStoreDomainSetup,
606 key);
607
608 myDict = (CFMutableDictionaryRef)CFDictionaryGetValue(newPrefs, myKey);
609 if (myDict) {
610 myDict = CFDictionaryCreateMutableCopy(NULL,
611 0,
612 (CFDictionaryRef)myDict);
613 } else {
614 myDict = CFDictionaryCreateMutable(NULL,
615 0,
616 &kCFTypeDictionaryKeyCallBacks,
617 &kCFTypeDictionaryValueCallBacks);
618 }
619
620 nKeys = CFDictionaryGetCount(subset);
621 if (nKeys > 0) {
622 keys = CFAllocatorAllocate(NULL, nKeys * sizeof(CFStringRef) , 0);
623 vals = CFAllocatorAllocate(NULL, nKeys * sizeof(CFPropertyListRef), 0);
624 CFDictionaryGetKeysAndValues(subset, keys, vals);
625 for (i = 0; i < nKeys; i++) {
626 if (CFGetTypeID((CFTypeRef)vals[i]) != CFDictionaryGetTypeID()) {
627 /* add this key/value to the current dictionary */
628 CFDictionarySetValue(myDict, keys[i], vals[i]);
629 } else {
630 CFStringRef subKey;
631
632 /* flatten [sub]dictionaries */
633 subKey = CFStringCreateWithFormat(NULL,
634 NULL,
635 CFSTR("%@%s%@"),
636 key,
637 CFEqual(key, CFSTR("/")) ? "" : "/",
638 keys[i]);
639 flatten(prefs, subKey, vals[i]);
640 CFRelease(subKey);
641 }
642 }
643 CFAllocatorDeallocate(NULL, keys);
644 CFAllocatorDeallocate(NULL, vals);
645 }
646
647 if (CFDictionaryGetCount(myDict) > 0) {
648 /* add this dictionary to the new preferences */
649 CFDictionarySetValue(newPrefs, myKey, myDict);
650 }
651
652 CFRelease(myDict);
653 CFRelease(myKey);
654
655 return;
656 }
657
658
659 static CF_RETURNS_RETAINED SCNetworkServiceRef
660 copyInterfaceService(SCNetworkSetRef set, CFStringRef matchName)
661 {
662 CFIndex i;
663 CFIndex n;
664 SCNetworkServiceRef service = NULL;
665 CFArrayRef services;
666
667 services = SCNetworkSetCopyServices(set);
668 assert(services != NULL);
669
670 n = CFArrayGetCount(services);
671 for (i = 0; i < n; i++) {
672 SCNetworkInterfaceRef interface;
673
674 service = CFArrayGetValueAtIndex(services, i);
675 interface = SCNetworkServiceGetInterface(service);
676 if (interface != NULL) {
677 CFStringRef bsdName;
678
679 bsdName = SCNetworkInterfaceGetBSDName(interface);
680 if (_SC_CFEqual(bsdName, matchName)) {
681 // if match
682 CFRetain(service);
683 break;
684 }
685 }
686
687 service = NULL;
688 }
689
690 CFRelease(services);
691 return service;
692 }
693
694
695 static CF_RETURNS_RETAINED CFStringRef
696 copyInterfaceUUID(CFStringRef bsdName)
697 {
698 union {
699 unsigned char sha1_bytes[CC_SHA1_DIGEST_LENGTH];
700 CFUUIDBytes uuid_bytes;
701 } bytes;
702 CC_SHA1_CTX ctx;
703 char if_name[IF_NAMESIZE];
704 CFUUIDRef uuid;
705 CFStringRef uuid_str;
706
707 // start with interface name
708 bzero(&if_name, sizeof(if_name));
709 (void) _SC_cfstring_to_cstring(bsdName,
710 if_name,
711 sizeof(if_name),
712 kCFStringEncodingASCII);
713
714 // create SHA1 hash
715 bzero(&bytes, sizeof(bytes));
716 CC_SHA1_Init(&ctx);
717 CC_SHA1_Update(&ctx,
718 if_name,
719 sizeof(if_name));
720 CC_SHA1_Final(bytes.sha1_bytes, &ctx);
721
722 // create UUID string
723 uuid = CFUUIDCreateFromUUIDBytes(NULL, bytes.uuid_bytes);
724 uuid_str = CFUUIDCreateString(NULL, uuid);
725 CFRelease(uuid);
726
727 return uuid_str;
728 }
729
730
731 static void
732 updatePreConfiguredConfiguration(SCPreferencesRef prefs)
733 {
734 Boolean ok;
735 CFRange range;
736 SCNetworkSetRef set;
737 Boolean updated = FALSE;
738
739 range.length = (preconfigured != NULL) ? CFArrayGetCount(preconfigured) : 0;
740 if (range.length == 0) {
741 // if no [preconfigured] interfaces
742 return;
743 }
744 range.location = 0;
745
746 set = SCNetworkSetCopyCurrent(prefs);
747 if (set != NULL) {
748 CFArrayRef services;
749
750 /*
751 * Check for (and remove) and network services associated with
752 * a pre-configured interface from the prefs.
753 */
754 services = SCNetworkSetCopyServices(set);
755 if (services != NULL) {
756 CFIndex n;
757
758 n = CFArrayGetCount(services);
759 for (CFIndex i = 0; i < n; i++) {
760 CFStringRef bsdName;
761 SCNetworkInterfaceRef interface;
762 SCNetworkServiceRef service;
763
764 service = CFArrayGetValueAtIndex(services, i);
765
766 interface = SCNetworkServiceGetInterface(service);
767 if (interface == NULL) {
768 // if no interface
769 continue;
770 }
771
772 bsdName = SCNetworkInterfaceGetBSDName(interface);
773 if (bsdName == NULL) {
774 // if no interface name
775 continue;
776 }
777
778 if (!CFArrayContainsValue(preconfigured, range, bsdName)) {
779 // if not preconfigured
780 continue;
781 }
782
783 // remove [preconfigured] network service from the prefs
784 SC_log(LOG_NOTICE, "removing network service for %@", bsdName);
785 SCNetworkServiceRemove(service);
786 updated = TRUE;
787 }
788
789 CFRelease(services);
790 }
791
792 if (updated) {
793 // commit the updated prefs ... but don't apply
794 ok = SCPreferencesCommitChanges(prefs);
795 if (!ok) {
796 if (SCError() != EROFS) {
797 SC_log(LOG_NOTICE, "SCPreferencesCommitChanges() failed: %s",
798 SCErrorString(SCError()));
799 }
800 }
801 }
802
803 /*
804 * Now, add a new network service for each pre-configured interface
805 */
806 for (CFIndex i = 0; i < range.length; i++) {
807 CFStringRef bsdName;
808 SCNetworkInterfaceRef interface;
809 SCNetworkServiceRef service;
810
811 bsdName = CFArrayGetValueAtIndex(preconfigured, i);
812 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeNoVirtualInterfaces);
813 if (interface == NULL) {
814 SC_log(LOG_ERR, "could not create network interface for %@", bsdName);
815 continue;
816 }
817
818 if (_SCNetworkInterfaceGetIOPath(interface) == NULL) {
819 // if no [real] interface exists
820 CFRelease(interface);
821 continue;
822 }
823
824 ok = SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface);
825 CFRelease(interface);
826 if (!ok) {
827 SC_log(LOG_ERR, "could not create network service for %@", bsdName);
828 continue;
829 }
830
831 service = copyInterfaceService(set, bsdName);
832 if (service != NULL) {
833 CFStringRef serviceID;
834
835 serviceID = copyInterfaceUUID(bsdName);
836 if (serviceID != NULL) {
837 ok = _SCNetworkServiceSetServiceID(service, serviceID);
838 CFRelease(serviceID);
839 if (!ok) {
840 SC_log(LOG_ERR, "_SCNetworkServiceSetServiceID() failed: %s",
841 SCErrorString(SCError()));
842 // ... and keep whatever random UUID was created for the service
843 }
844 } else {
845 SC_log(LOG_ERR, "could not create serviceID for %@", bsdName);
846 // ... and we'll use whatever random UUID was created for the service
847 }
848
849 SC_log(LOG_INFO, "network service %@ added for %@",
850 SCNetworkServiceGetServiceID(service),
851 bsdName);
852
853 CFRelease(service);
854 } else {
855 SC_log(LOG_ERR, "could not find network service for %@", bsdName);
856 }
857 }
858
859 CFRelease(set);
860 }
861
862 return;
863 }
864
865
866 static void
867 updateSCDynamicStore(SCPreferencesRef prefs)
868 {
869 CFStringRef current = NULL;
870 CFDateRef date = NULL;
871 CFMutableDictionaryRef dict = NULL;
872 CFDictionaryRef global = NULL;
873 CFIndex i;
874 CFArrayRef keys;
875 CFIndex n;
876 CFStringRef pattern;
877 CFMutableArrayRef patterns;
878 CFDictionaryRef set = NULL;
879
880 /*
881 * initialize old preferences, new preferences, an array
882 * of keys which have not changed, and an array of keys
883 * to be removed (cleaned up).
884 */
885
886 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
887 pattern = CFStringCreateWithFormat(NULL,
888 NULL,
889 CFSTR("^%@.*"),
890 kSCDynamicStoreDomainSetup);
891 CFArrayAppendValue(patterns, pattern);
892 dict = (CFMutableDictionaryRef)SCDynamicStoreCopyMultiple(store, NULL, patterns);
893 CFRelease(patterns);
894 CFRelease(pattern);
895 if (dict) {
896 currentPrefs = CFDictionaryCreateMutableCopy(NULL, 0, dict);
897 CFRelease(dict);
898 } else {
899 currentPrefs = CFDictionaryCreateMutable(NULL,
900 0,
901 &kCFTypeDictionaryKeyCallBacks,
902 &kCFTypeDictionaryValueCallBacks);
903 }
904
905 unchangedPrefsKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
906
907 i = CFDictionaryGetCount(currentPrefs);
908 if (i > 0) {
909 const void **currentKeys;
910 CFArrayRef array;
911
912 currentKeys = CFAllocatorAllocate(NULL, i * sizeof(CFStringRef), 0);
913 CFDictionaryGetKeysAndValues(currentPrefs, currentKeys, NULL);
914 array = CFArrayCreate(NULL, currentKeys, i, &kCFTypeArrayCallBacks);
915 removedPrefsKeys = CFArrayCreateMutableCopy(NULL, 0, array);
916 CFRelease(array);
917 CFAllocatorDeallocate(NULL, currentKeys);
918 } else {
919 removedPrefsKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
920 }
921
922 /*
923 * The "newPrefs" dictionary will contain the new / updated
924 * configuration which will be written to the configuration cache.
925 */
926 newPrefs = CFDictionaryCreateMutable(NULL,
927 0,
928 &kCFTypeDictionaryKeyCallBacks,
929 &kCFTypeDictionaryValueCallBacks);
930
931 /*
932 * create status dictionary associated with current configuration
933 * information including:
934 * - current set "name" to cache
935 * - time stamp indicating when the cache preferences were
936 * last updated.
937 */
938 dict = CFDictionaryCreateMutable(NULL,
939 0,
940 &kCFTypeDictionaryKeyCallBacks,
941 &kCFTypeDictionaryValueCallBacks);
942 date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
943
944 /*
945 * load preferences
946 */
947 keys = SCPreferencesCopyKeyList(prefs);
948 if ((keys == NULL) || (CFArrayGetCount(keys) == 0)) {
949 SC_log(LOG_NOTICE, "updateConfiguration(): no preferences");
950 goto done;
951 }
952
953 /*
954 * get "global" system preferences
955 */
956 global = SCPreferencesGetValue(prefs, kSCPrefSystem);
957 if (!global) {
958 /* if no global preferences are defined */
959 goto getSet;
960 }
961
962 if (!isA_CFDictionary(global)) {
963 SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a dictionary",
964 kSCPrefSystem);
965 goto done;
966 }
967
968 /* flatten property list */
969 flatten(prefs, CFSTR("/"), global);
970
971 getSet :
972
973 /*
974 * get current set name
975 */
976 current = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
977 if (!current) {
978 /* if current set not defined */
979 goto done;
980 }
981
982 if (!isA_CFString(current)) {
983 SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a string",
984 kSCPrefCurrentSet);
985 goto done;
986 }
987
988 /*
989 * get current set
990 */
991 set = SCPreferencesPathGetValue(prefs, current);
992 if (!set) {
993 /* if error with path */
994 SC_log(LOG_NOTICE, "%@ value (%@) not valid",
995 kSCPrefCurrentSet,
996 current);
997 goto done;
998 }
999
1000 if (!isA_CFDictionary(set)) {
1001 SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a dictionary",
1002 current);
1003 goto done;
1004 }
1005
1006 /* flatten property list */
1007 flatten(prefs, CFSTR("/"), set);
1008
1009 CFDictionarySetValue(dict, kSCDynamicStorePropSetupCurrentSet, current);
1010
1011 done :
1012
1013 /* add last updated time stamp */
1014 CFDictionarySetValue(dict, kSCDynamicStorePropSetupLastUpdated, date);
1015
1016 /* add Setup: key */
1017 CFDictionarySetValue(newPrefs, kSCDynamicStoreDomainSetup, dict);
1018
1019 /* compare current and new preferences */
1020 CFDictionaryApplyFunction(newPrefs, updateCache, NULL);
1021
1022 /* remove those keys which have not changed from the update */
1023 n = CFArrayGetCount(unchangedPrefsKeys);
1024 for (i = 0; i < n; i++) {
1025 CFStringRef key;
1026
1027 key = CFArrayGetValueAtIndex(unchangedPrefsKeys, i);
1028 CFDictionaryRemoveValue(newPrefs, key);
1029 }
1030
1031 /* Update the dynamic store */
1032 #ifndef MAIN
1033 if (!SCDynamicStoreSetMultiple(store, newPrefs, removedPrefsKeys, NULL)) {
1034 SC_log(LOG_NOTICE, "SCDynamicStoreSetMultiple() failed: %s", SCErrorString(SCError()));
1035 }
1036 #else // !MAIN
1037 SC_log(LOG_DEBUG, "SCDynamicStore\nset: %@\nremove: %@",
1038 newPrefs,
1039 removedPrefsKeys);
1040 #endif // !MAIN
1041
1042 CFRelease(currentPrefs);
1043 CFRelease(newPrefs);
1044 CFRelease(unchangedPrefsKeys);
1045 CFRelease(removedPrefsKeys);
1046 if (dict) CFRelease(dict);
1047 if (date) CFRelease(date);
1048 if (keys) CFRelease(keys);
1049 return;
1050 }
1051
1052
1053 static void
1054 updateConfiguration(SCPreferencesRef prefs,
1055 SCPreferencesNotification notificationType,
1056 void *info)
1057 {
1058 os_activity_t activity;
1059
1060 activity = os_activity_create("processing [SC] preferences.plist changes",
1061 OS_ACTIVITY_CURRENT,
1062 OS_ACTIVITY_FLAG_DEFAULT);
1063 os_activity_scope(activity);
1064
1065 #if !TARGET_OS_IPHONE
1066 if ((notificationType & kSCPreferencesNotificationCommit) == kSCPreferencesNotificationCommit) {
1067 SCNetworkSetRef current;
1068
1069 current = SCNetworkSetCopyCurrent(prefs);
1070 if (current != NULL) {
1071 /* network configuration available, disable template creation */
1072 haveConfiguration = TRUE;
1073 CFRelease(current);
1074 }
1075 }
1076 #endif /* !TARGET_OS_IPHONE */
1077
1078 if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
1079 goto done;
1080 }
1081
1082 SC_log(LOG_INFO, "updating configuration");
1083
1084 /* add any [Apple] pre-configured network services */
1085 updatePreConfiguredConfiguration(prefs);
1086
1087 /* update SCDynamicStore (Setup:) */
1088 updateSCDynamicStore(prefs);
1089
1090 /* finished with current prefs, wait for changes */
1091 if (!rofs) {
1092 SCPreferencesSynchronize(prefs);
1093 }
1094
1095 done :
1096
1097 os_release(activity);
1098
1099 return;
1100 }
1101
1102
1103 __private_extern__
1104 void
1105 prime_PreferencesMonitor()
1106 {
1107 SC_log(LOG_DEBUG, "prime() called");
1108
1109 /* load the initial configuration from the database */
1110 updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
1111
1112 return;
1113 }
1114
1115
1116 __private_extern__
1117 void
1118 load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose)
1119 {
1120 SC_log(LOG_DEBUG, "load() called");
1121 SC_log(LOG_DEBUG, " bundle ID = %@", CFBundleGetIdentifier(bundle));
1122
1123 /* open a SCDynamicStore session to allow cache updates */
1124 store = SCDynamicStoreCreate(NULL,
1125 CFSTR("PreferencesMonitor.bundle"),
1126 storeCallback,
1127 NULL);
1128 if (store == NULL) {
1129 SC_log(LOG_NOTICE, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
1130 goto error;
1131 }
1132
1133 /* open a SCPreferences session */
1134 #ifndef MAIN
1135 prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL);
1136 #else // !MAIN
1137 prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist"));
1138 #endif // !MAIN
1139 if (prefs != NULL) {
1140 Boolean need_update = FALSE;
1141 CFStringRef new_model;
1142
1143 new_model = _SC_hw_model(FALSE);
1144
1145 /* Need to regenerate the new configuration for new model */
1146 if (new_model != NULL) {
1147 CFStringRef old_model;
1148
1149 old_model = SCPreferencesGetValue(prefs, MODEL);
1150 if (old_model != NULL && !_SC_CFEqual(old_model, new_model)) {
1151 // if new hardware
1152 need_update = TRUE;
1153 restorePrefs = previousConfigurationAvailable();
1154 }
1155 }
1156
1157 if (!need_update) {
1158 SCNetworkSetRef current;
1159
1160 current = SCNetworkSetCopyCurrent(prefs);
1161 if (current != NULL) {
1162 /* network configuration available, disable template creation */
1163 haveConfiguration = TRUE;
1164 CFRelease(current);
1165 }
1166 }
1167 } else {
1168 SC_log(LOG_NOTICE, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
1169 goto error;
1170 }
1171
1172 /*
1173 * register for change notifications.
1174 */
1175 if (!SCPreferencesSetCallback(prefs, updateConfiguration, NULL)) {
1176 SC_log(LOG_NOTICE, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
1177 goto error;
1178 }
1179
1180 if (!SCPreferencesScheduleWithRunLoop(prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
1181 SC_log(LOG_NOTICE, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
1182 goto error;
1183 }
1184
1185 /*
1186 * watch InterfaceNamer and KernelEventMonitor changes to know when
1187 * the IORegistry has quiesced (to create the initial configuration
1188 * template), to track any pre-configured interfaces, and to ensure
1189 * that we create a network service for any active interfaces.
1190 */
1191 watchSCDynamicStore();
1192 storeCallback(store, NULL, NULL);
1193
1194 return;
1195
1196 error :
1197
1198 if (store != NULL) CFRelease(store);
1199 if (prefs != NULL) CFRelease(prefs);
1200 haveConfiguration = TRUE;
1201
1202 return;
1203 }
1204
1205
1206 #ifdef MAIN
1207 int
1208 main(int argc, char **argv)
1209 {
1210 _sc_log = FALSE;
1211 _sc_verbose = (argc > 1) ? TRUE : FALSE;
1212
1213 load_PreferencesMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
1214 prime_PreferencesMonitor();
1215 CFRunLoopRun();
1216 /* not reached */
1217 exit(0);
1218 return 0;
1219 }
1220 #endif