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