]> git.saurik.com Git - apple/configd.git/blob - Plugins/PreferencesMonitor/prefsmon.c
configd-963.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 CFIndex n;
429 CFArrayRef preconfigured;
430
431 if (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Quiet)) {
432 quiet = TRUE;
433 }
434 if (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Timeout)) {
435 timeout = TRUE;
436 }
437
438 preconfigured = CFDictionaryGetValue(dict, kInterfaceNamerKey_PreConfiguredInterfaces);
439 preconfigured = isA_CFArray(preconfigured);
440
441 n = (preconfigured != NULL) ? CFArrayGetCount(preconfigured) : 0;
442 for (CFIndex i = 0; i < n; i++) {
443 CFStringRef bsdName = CFArrayGetValueAtIndex(preconfigured, i);
444 SCNetworkInterfaceRef interface;
445 CFRange range;
446
447 range.location = 0;
448 range.length = (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0;
449 if ((range.length > 0) &&
450 CFArrayContainsValue(preconfigured_names, range, bsdName)) {
451 // if we already know about this interface
452 continue;
453 }
454
455 for (int retry = 0; retry < 10; retry++) {
456 if (retry != 0) {
457 // add short delay (before retry)
458 usleep(20 * 1000); // 20ms
459 }
460
461 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeNoVirtualInterfaces);
462 if (interface == NULL) {
463 SC_log(LOG_ERR, "could not create network interface for %@", bsdName);
464 } else if (_SCNetworkInterfaceGetIOPath(interface) == NULL) {
465 SC_log(LOG_ERR, "could not get IOPath for %@", bsdName);
466 CFRelease(interface);
467 interface = NULL;
468 }
469
470 if (interface != NULL) {
471 // if we have an interface
472 break;
473 }
474 }
475
476 if (interface == NULL) {
477 // if SCNetworkInterface not [currently] available
478 continue;
479 }
480
481 // keep track of the interface name (quicker than having to iterate the list
482 // of SCNetworkInterfaces, extract the name, and compare).
483 if (preconfigured_names == NULL) {
484 preconfigured_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
485 }
486 CFArrayAppendValue(preconfigured_names, bsdName);
487
488 if (preconfigured_interfaces == NULL) {
489 preconfigured_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
490 }
491 CFArrayAppendValue(preconfigured_interfaces, interface);
492 CFRelease(interface);
493
494 updated = TRUE;
495 }
496
497 if (updated) {
498 CFStringRef interfaces = CFSTR("<empty>");
499
500 // report [new] pre-configured interfaces
501 if (preconfigured_names != NULL) {
502 interfaces = CFStringCreateByCombiningStrings(NULL, preconfigured_names, CFSTR(","));
503 } else {
504 CFRetain(interfaces);
505 }
506 SC_log(LOG_INFO, "pre-configured interface list changed: %@", interfaces);
507 CFRelease(interfaces);
508 }
509 }
510
511 CFRelease(dict);
512 }
513
514 if (!haveConfiguration && (quiet || timeout)) {
515 static int logged = 0;
516
517 if (quiet
518 #if !TARGET_OS_IPHONE
519 || timeout
520 #endif /* !TARGET_OS_IPHONE */
521 ) {
522 haveConfiguration = TRUE;
523 }
524
525 (void) establishNewPreferences();
526
527 if (restorePrefs) {
528 (void) restorePreferences();
529 restorePrefs = FALSE;
530 }
531
532 if (timeout && (logged++ == 0)) {
533 SC_log(LOG_ERR, "Network configuration creation timed out waiting for IORegistry");
534 }
535 }
536
537 if (updated && (changedKeys != NULL)) {
538 // if pre-configured interface list changed
539 updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
540 }
541
542 return;
543 }
544
545
546 static void
547 updateCache(const void *key, const void *value, void *context)
548 {
549 #pragma unused(context)
550 CFStringRef configKey = (CFStringRef)key;
551 CFPropertyListRef configData = (CFPropertyListRef)value;
552 CFPropertyListRef cacheData;
553 CFIndex i;
554
555 cacheData = CFDictionaryGetValue(currentPrefs, configKey);
556 if (cacheData) {
557 /* key exists */
558 if (CFEqual(cacheData, configData)) {
559 /*
560 * if the old & new property list values have
561 * not changed then we don't need to update
562 * the preference.
563 */
564 CFArrayAppendValue(unchangedPrefsKeys, configKey);
565 }
566 }
567
568 /* in any case, this key should not be removed */
569 i = CFArrayGetFirstIndexOfValue(removedPrefsKeys,
570 CFRangeMake(0, CFArrayGetCount(removedPrefsKeys)),
571 configKey);
572 if (i != kCFNotFound) {
573 CFArrayRemoveValueAtIndex(removedPrefsKeys, i);
574 }
575
576 return;
577 }
578
579
580 static void
581 flatten(SCPreferencesRef prefs,
582 CFStringRef key,
583 CFDictionaryRef base)
584 {
585 CFDictionaryRef subset;
586 CFStringRef link;
587 CFMutableDictionaryRef myDict;
588 CFStringRef myKey;
589 CFIndex i;
590 CFIndex nKeys;
591 const void **keys;
592 const void **vals;
593
594 if (!CFDictionaryGetValueIfPresent(base, kSCResvLink, (const void **)&link)) {
595 /* if this dictionary is not linked */
596 subset = base;
597 } else {
598 /* if __LINK__ key is present */
599 subset = SCPreferencesPathGetValue(prefs, link);
600 if (!subset) {
601 /* if error with link */
602 SC_log(LOG_NOTICE, "SCPreferencesPathGetValue(,%@,) failed: %s",
603 link,
604 SCErrorString(SCError()));
605 return;
606 }
607 }
608
609 if (CFDictionaryContainsKey(subset, kSCResvInactive)) {
610 /* if __INACTIVE__ key is present */
611 return;
612 }
613
614 myKey = CFStringCreateWithFormat(NULL,
615 NULL,
616 CFSTR("%@%@"),
617 kSCDynamicStoreDomainSetup,
618 key);
619
620 myDict = (CFMutableDictionaryRef)CFDictionaryGetValue(newPrefs, myKey);
621 if (myDict) {
622 myDict = CFDictionaryCreateMutableCopy(NULL,
623 0,
624 (CFDictionaryRef)myDict);
625 } else {
626 myDict = CFDictionaryCreateMutable(NULL,
627 0,
628 &kCFTypeDictionaryKeyCallBacks,
629 &kCFTypeDictionaryValueCallBacks);
630 }
631
632 nKeys = CFDictionaryGetCount(subset);
633 if (nKeys > 0) {
634 keys = CFAllocatorAllocate(NULL, nKeys * sizeof(CFStringRef) , 0);
635 vals = CFAllocatorAllocate(NULL, nKeys * sizeof(CFPropertyListRef), 0);
636 CFDictionaryGetKeysAndValues(subset, keys, vals);
637 for (i = 0; i < nKeys; i++) {
638 if (CFGetTypeID((CFTypeRef)vals[i]) != CFDictionaryGetTypeID()) {
639 /* add this key/value to the current dictionary */
640 CFDictionarySetValue(myDict, keys[i], vals[i]);
641 } else {
642 CFStringRef subKey;
643
644 /* flatten [sub]dictionaries */
645 subKey = CFStringCreateWithFormat(NULL,
646 NULL,
647 CFSTR("%@%s%@"),
648 key,
649 CFEqual(key, CFSTR("/")) ? "" : "/",
650 keys[i]);
651 flatten(prefs, subKey, vals[i]);
652 CFRelease(subKey);
653 }
654 }
655 CFAllocatorDeallocate(NULL, keys);
656 CFAllocatorDeallocate(NULL, vals);
657 }
658
659 if (CFDictionaryGetCount(myDict) > 0) {
660 /* add this dictionary to the new preferences */
661 CFDictionarySetValue(newPrefs, myKey, myDict);
662 }
663
664 CFRelease(myDict);
665 CFRelease(myKey);
666
667 return;
668 }
669
670
671 static CF_RETURNS_RETAINED SCNetworkServiceRef
672 copyInterfaceService(SCNetworkSetRef set, CFStringRef matchName)
673 {
674 CFIndex i;
675 CFIndex n;
676 SCNetworkServiceRef service = NULL;
677 CFArrayRef services;
678
679 services = SCNetworkSetCopyServices(set);
680 assert(services != NULL);
681
682 n = CFArrayGetCount(services);
683 for (i = 0; i < n; i++) {
684 SCNetworkInterfaceRef interface;
685
686 service = CFArrayGetValueAtIndex(services, i);
687 interface = SCNetworkServiceGetInterface(service);
688 if (interface != NULL) {
689 CFStringRef bsdName;
690
691 bsdName = SCNetworkInterfaceGetBSDName(interface);
692 if (_SC_CFEqual(bsdName, matchName)) {
693 // if match
694 CFRetain(service);
695 break;
696 }
697 }
698
699 service = NULL;
700 }
701
702 CFRelease(services);
703 return service;
704 }
705
706
707 static CF_RETURNS_RETAINED CFStringRef
708 copyInterfaceUUID(CFStringRef bsdName)
709 {
710 union {
711 unsigned char sha1_bytes[CC_SHA1_DIGEST_LENGTH];
712 CFUUIDBytes uuid_bytes;
713 } bytes;
714 CC_SHA1_CTX ctx;
715 char if_name[IF_NAMESIZE];
716 CFUUIDRef uuid;
717 CFStringRef uuid_str;
718
719 // start with interface name
720 bzero(&if_name, sizeof(if_name));
721 (void) _SC_cfstring_to_cstring(bsdName,
722 if_name,
723 sizeof(if_name),
724 kCFStringEncodingASCII);
725
726 // create SHA1 hash
727 bzero(&bytes, sizeof(bytes));
728 CC_SHA1_Init(&ctx);
729 CC_SHA1_Update(&ctx,
730 if_name,
731 sizeof(if_name));
732 CC_SHA1_Final(bytes.sha1_bytes, &ctx);
733
734 // create UUID string
735 uuid = CFUUIDCreateFromUUIDBytes(NULL, bytes.uuid_bytes);
736 uuid_str = CFUUIDCreateString(NULL, uuid);
737 CFRelease(uuid);
738
739 return uuid_str;
740 }
741
742
743 static void
744 updatePreConfiguredConfiguration(SCPreferencesRef prefs)
745 {
746 Boolean ok;
747 CFRange range;
748 SCNetworkSetRef set;
749 Boolean updated = FALSE;
750
751 range.length = (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0;
752 if (range.length == 0) {
753 // if no [preconfigured] interfaces
754 return;
755 }
756 range.location = 0;
757
758 set = SCNetworkSetCopyCurrent(prefs);
759 if (set != NULL) {
760 CFArrayRef services;
761
762 /*
763 * Check for (and remove) any network services associated with
764 * a pre-configured interface from the prefs.
765 */
766 services = SCNetworkServiceCopyAll(prefs);
767 if (services != NULL) {
768 CFIndex n;
769
770 n = CFArrayGetCount(services);
771 for (CFIndex i = 0; i < n; i++) {
772 CFStringRef bsdName;
773 SCNetworkInterfaceRef interface;
774 SCNetworkServiceRef service;
775
776 service = CFArrayGetValueAtIndex(services, i);
777
778 interface = SCNetworkServiceGetInterface(service);
779 if (interface == NULL) {
780 // if no interface
781 continue;
782 }
783
784 bsdName = SCNetworkInterfaceGetBSDName(interface);
785 if (bsdName == NULL) {
786 // if no interface name
787 continue;
788 }
789
790 if (!CFArrayContainsValue(preconfigured_names, range, bsdName)) {
791 // if not preconfigured
792 continue;
793 }
794
795 // remove [preconfigured] network service from the prefs
796 SC_log(LOG_NOTICE, "removing network service for %@", bsdName);
797 ok = SCNetworkServiceRemove(service);
798 if (!ok) {
799 SC_log(LOG_ERR, "SCNetworkServiceRemove() failed: %s",
800 SCErrorString(SCError()));
801 }
802 updated = TRUE;
803 }
804
805 CFRelease(services);
806 }
807
808 if (updated) {
809 // commit the updated prefs ... but don't apply
810 ok = SCPreferencesCommitChanges(prefs);
811 if (!ok) {
812 if (SCError() != EROFS) {
813 SC_log(LOG_ERR, "SCPreferencesCommitChanges() failed: %s",
814 SCErrorString(SCError()));
815 }
816 }
817 }
818
819 /*
820 * Now, add a new network service for each pre-configured interface
821 */
822 range.length = (preconfigured_interfaces != NULL) ? CFArrayGetCount(preconfigured_interfaces) : 0;
823 for (CFIndex i = 0; i < range.length; i++) {
824 CFStringRef bsdName;
825 SCNetworkInterfaceRef interface = CFArrayGetValueAtIndex(preconfigured_interfaces, i);
826 SCNetworkServiceRef service;
827
828 bsdName = SCNetworkInterfaceGetBSDName(interface);
829 ok = SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface);
830 if (!ok) {
831 SC_log(LOG_ERR, "could not establish network service for %@: %s",
832 bsdName,
833 SCErrorString(SCError()));
834 continue;
835 }
836
837 service = copyInterfaceService(set, bsdName);
838 if (service != NULL) {
839 CFStringRef serviceID;
840
841 serviceID = copyInterfaceUUID(bsdName);
842 if (serviceID != NULL) {
843 ok = _SCNetworkServiceSetServiceID(service, serviceID);
844 CFRelease(serviceID);
845 if (!ok) {
846 SC_log(LOG_ERR, "_SCNetworkServiceSetServiceID() failed: %s",
847 SCErrorString(SCError()));
848 // ... and keep whatever random UUID was created for the service
849 }
850 } else {
851 SC_log(LOG_ERR, "could not create serviceID for %@", bsdName);
852 // ... and we'll use whatever random UUID was created for the service
853 }
854
855 SC_log(LOG_INFO, "network service %@ added for %@",
856 SCNetworkServiceGetServiceID(service),
857 bsdName);
858
859 CFRelease(service);
860 } else {
861 SC_log(LOG_ERR, "could not find network service for %@", bsdName);
862 }
863 }
864
865 CFRelease(set);
866 }
867
868 return;
869 }
870
871
872 static void
873 updateSCDynamicStore(SCPreferencesRef prefs)
874 {
875 CFStringRef current = NULL;
876 CFDateRef date = NULL;
877 CFMutableDictionaryRef dict = NULL;
878 CFDictionaryRef global = NULL;
879 CFIndex i;
880 CFArrayRef keys;
881 CFIndex n;
882 CFStringRef pattern;
883 CFMutableArrayRef patterns;
884 CFDictionaryRef set = NULL;
885
886 /*
887 * initialize old preferences, new preferences, an array
888 * of keys which have not changed, and an array of keys
889 * to be removed (cleaned up).
890 */
891
892 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
893 pattern = CFStringCreateWithFormat(NULL,
894 NULL,
895 CFSTR("^%@.*"),
896 kSCDynamicStoreDomainSetup);
897 CFArrayAppendValue(patterns, pattern);
898 dict = (CFMutableDictionaryRef)SCDynamicStoreCopyMultiple(store, NULL, patterns);
899 CFRelease(patterns);
900 CFRelease(pattern);
901 if (dict) {
902 currentPrefs = CFDictionaryCreateMutableCopy(NULL, 0, dict);
903 CFRelease(dict);
904 } else {
905 currentPrefs = CFDictionaryCreateMutable(NULL,
906 0,
907 &kCFTypeDictionaryKeyCallBacks,
908 &kCFTypeDictionaryValueCallBacks);
909 }
910
911 unchangedPrefsKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
912
913 i = CFDictionaryGetCount(currentPrefs);
914 if (i > 0) {
915 const void **currentKeys;
916 CFArrayRef array;
917
918 currentKeys = CFAllocatorAllocate(NULL, i * sizeof(CFStringRef), 0);
919 CFDictionaryGetKeysAndValues(currentPrefs, currentKeys, NULL);
920 array = CFArrayCreate(NULL, currentKeys, i, &kCFTypeArrayCallBacks);
921 removedPrefsKeys = CFArrayCreateMutableCopy(NULL, 0, array);
922 CFRelease(array);
923 CFAllocatorDeallocate(NULL, currentKeys);
924 } else {
925 removedPrefsKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
926 }
927
928 /*
929 * The "newPrefs" dictionary will contain the new / updated
930 * configuration which will be written to the configuration cache.
931 */
932 newPrefs = CFDictionaryCreateMutable(NULL,
933 0,
934 &kCFTypeDictionaryKeyCallBacks,
935 &kCFTypeDictionaryValueCallBacks);
936
937 /*
938 * create status dictionary associated with current configuration
939 * information including:
940 * - current set "name" to cache
941 * - time stamp indicating when the cache preferences were
942 * last updated.
943 */
944 dict = CFDictionaryCreateMutable(NULL,
945 0,
946 &kCFTypeDictionaryKeyCallBacks,
947 &kCFTypeDictionaryValueCallBacks);
948 date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
949
950 /*
951 * load preferences
952 */
953 keys = SCPreferencesCopyKeyList(prefs);
954 if ((keys == NULL) || (CFArrayGetCount(keys) == 0)) {
955 SC_log(LOG_NOTICE, "updateConfiguration(): no preferences");
956 goto done;
957 }
958
959 /*
960 * get "global" system preferences
961 */
962 global = SCPreferencesGetValue(prefs, kSCPrefSystem);
963 if (!global) {
964 /* if no global preferences are defined */
965 goto getSet;
966 }
967
968 if (!isA_CFDictionary(global)) {
969 SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a dictionary",
970 kSCPrefSystem);
971 goto done;
972 }
973
974 /* flatten property list */
975 flatten(prefs, CFSTR("/"), global);
976
977 getSet :
978
979 /*
980 * get current set name
981 */
982 current = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
983 if (!current) {
984 /* if current set not defined */
985 goto done;
986 }
987
988 if (!isA_CFString(current)) {
989 SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a string",
990 kSCPrefCurrentSet);
991 goto done;
992 }
993
994 /*
995 * get current set
996 */
997 set = SCPreferencesPathGetValue(prefs, current);
998 if (!set) {
999 /* if error with path */
1000 SC_log(LOG_NOTICE, "%@ value (%@) not valid",
1001 kSCPrefCurrentSet,
1002 current);
1003 goto done;
1004 }
1005
1006 if (!isA_CFDictionary(set)) {
1007 SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a dictionary",
1008 current);
1009 goto done;
1010 }
1011
1012 /* flatten property list */
1013 flatten(prefs, CFSTR("/"), set);
1014
1015 CFDictionarySetValue(dict, kSCDynamicStorePropSetupCurrentSet, current);
1016
1017 done :
1018
1019 /* add last updated time stamp */
1020 CFDictionarySetValue(dict, kSCDynamicStorePropSetupLastUpdated, date);
1021
1022 /* add Setup: key */
1023 CFDictionarySetValue(newPrefs, kSCDynamicStoreDomainSetup, dict);
1024
1025 /* compare current and new preferences */
1026 CFDictionaryApplyFunction(newPrefs, updateCache, NULL);
1027
1028 /* remove those keys which have not changed from the update */
1029 n = CFArrayGetCount(unchangedPrefsKeys);
1030 for (i = 0; i < n; i++) {
1031 CFStringRef key;
1032
1033 key = CFArrayGetValueAtIndex(unchangedPrefsKeys, i);
1034 CFDictionaryRemoveValue(newPrefs, key);
1035 }
1036
1037 /* Update the dynamic store */
1038 #ifndef MAIN
1039 if (!SCDynamicStoreSetMultiple(store, newPrefs, removedPrefsKeys, NULL)) {
1040 SC_log(LOG_NOTICE, "SCDynamicStoreSetMultiple() failed: %s", SCErrorString(SCError()));
1041 }
1042 #else // !MAIN
1043 SC_log(LOG_DEBUG, "SCDynamicStore\nset: %@\nremove: %@",
1044 newPrefs,
1045 removedPrefsKeys);
1046 #endif // !MAIN
1047
1048 CFRelease(currentPrefs);
1049 CFRelease(newPrefs);
1050 CFRelease(unchangedPrefsKeys);
1051 CFRelease(removedPrefsKeys);
1052 if (dict) CFRelease(dict);
1053 if (date) CFRelease(date);
1054 if (keys) CFRelease(keys);
1055 return;
1056 }
1057
1058
1059 static void
1060 updateConfiguration(SCPreferencesRef prefs,
1061 SCPreferencesNotification notificationType,
1062 void *info)
1063 {
1064 #pragma unused(info)
1065 os_activity_t activity;
1066
1067 activity = os_activity_create("processing [SC] preferences.plist changes",
1068 OS_ACTIVITY_CURRENT,
1069 OS_ACTIVITY_FLAG_DEFAULT);
1070 os_activity_scope(activity);
1071
1072 #if !TARGET_OS_IPHONE
1073 if ((notificationType & kSCPreferencesNotificationCommit) == kSCPreferencesNotificationCommit) {
1074 SCNetworkSetRef current;
1075
1076 current = SCNetworkSetCopyCurrent(prefs);
1077 if (current != NULL) {
1078 /* network configuration available, disable template creation */
1079 haveConfiguration = TRUE;
1080 CFRelease(current);
1081 }
1082 }
1083 #endif /* !TARGET_OS_IPHONE */
1084
1085 if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
1086 goto done;
1087 }
1088
1089 SC_log(LOG_INFO, "updating configuration");
1090
1091 /* add any [Apple] pre-configured network services */
1092 updatePreConfiguredConfiguration(prefs);
1093
1094 /* update SCDynamicStore (Setup:) */
1095 updateSCDynamicStore(prefs);
1096
1097 /* finished with current prefs, wait for changes */
1098 if (!rofs) {
1099 SCPreferencesSynchronize(prefs);
1100 }
1101
1102 done :
1103
1104 os_release(activity);
1105
1106 return;
1107 }
1108
1109
1110 __private_extern__
1111 void
1112 prime_PreferencesMonitor()
1113 {
1114 SC_log(LOG_DEBUG, "prime() called");
1115
1116 /* load the initial configuration from the database */
1117 updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
1118
1119 return;
1120 }
1121
1122
1123 __private_extern__
1124 void
1125 load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose)
1126 {
1127 #pragma unused(bundle)
1128 #pragma unused(bundleVerbose)
1129 SC_log(LOG_DEBUG, "load() called");
1130 SC_log(LOG_DEBUG, " bundle ID = %@", CFBundleGetIdentifier(bundle));
1131
1132 /* open a SCDynamicStore session to allow cache updates */
1133 store = SCDynamicStoreCreate(NULL,
1134 CFSTR("PreferencesMonitor.bundle"),
1135 storeCallback,
1136 NULL);
1137 if (store == NULL) {
1138 SC_log(LOG_NOTICE, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
1139 goto error;
1140 }
1141
1142 /* open a SCPreferences session */
1143 #ifndef MAIN
1144 prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL);
1145 #else // !MAIN
1146 prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist"));
1147 #endif // !MAIN
1148 if (prefs != NULL) {
1149 Boolean need_update = FALSE;
1150 CFStringRef new_model;
1151
1152 new_model = _SC_hw_model(FALSE);
1153
1154 /* Need to regenerate the new configuration for new model */
1155 if (new_model != NULL) {
1156 CFStringRef old_model;
1157
1158 old_model = SCPreferencesGetValue(prefs, MODEL);
1159 if (old_model != NULL && !_SC_CFEqual(old_model, new_model)) {
1160 // if new hardware
1161 need_update = TRUE;
1162 restorePrefs = previousConfigurationAvailable();
1163 }
1164 }
1165
1166 if (!need_update) {
1167 SCNetworkSetRef current;
1168
1169 current = SCNetworkSetCopyCurrent(prefs);
1170 if (current != NULL) {
1171 /* network configuration available, disable template creation */
1172 haveConfiguration = TRUE;
1173 CFRelease(current);
1174 }
1175 }
1176 } else {
1177 SC_log(LOG_NOTICE, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
1178 goto error;
1179 }
1180
1181 /*
1182 * register for change notifications.
1183 */
1184 if (!SCPreferencesSetCallback(prefs, updateConfiguration, NULL)) {
1185 SC_log(LOG_NOTICE, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
1186 goto error;
1187 }
1188
1189 if (!SCPreferencesScheduleWithRunLoop(prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
1190 SC_log(LOG_NOTICE, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
1191 goto error;
1192 }
1193
1194 /*
1195 * watch InterfaceNamer and KernelEventMonitor changes to know when
1196 * the IORegistry has quiesced (to create the initial configuration
1197 * template), to track any pre-configured interfaces, and to ensure
1198 * that we create a network service for any active interfaces.
1199 */
1200 watchSCDynamicStore();
1201 storeCallback(store, NULL, NULL);
1202
1203 return;
1204
1205 error :
1206
1207 if (store != NULL) CFRelease(store);
1208 if (prefs != NULL) CFRelease(prefs);
1209 haveConfiguration = TRUE;
1210
1211 return;
1212 }
1213
1214
1215 #ifdef MAIN
1216 int
1217 main(int argc, char **argv)
1218 {
1219 _sc_log = FALSE;
1220 _sc_verbose = (argc > 1) ? TRUE : FALSE;
1221
1222 load_PreferencesMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
1223 prime_PreferencesMonitor();
1224 CFRunLoopRun();
1225 /* not reached */
1226 exit(0);
1227 return 0;
1228 }
1229 #endif