]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPOpen.c
configd-1061.101.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCPOpen.c
1 /*
2 * Copyright(c) 2000-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * February 16, 2004 Allan Nathanson <ajn@apple.com>
28 * - add preference notification APIs
29 *
30 * June 1, 2001 Allan Nathanson <ajn@apple.com>
31 * - public API conversion
32 *
33 * November 9, 2000 Allan Nathanson <ajn@apple.com>
34 * - initial revision
35 */
36
37 #include <TargetConditionals.h>
38 #include <fcntl.h>
39 #include <pthread.h>
40 #include <sandbox.h>
41 #include <unistd.h>
42 #include <sys/errno.h>
43 #include <sys/cdefs.h>
44 #include <dispatch/dispatch.h>
45
46 #include "SCPreferencesInternal.h"
47 #include "SCD.h"
48 #include "SCHelper_client.h"
49 #include "dy_framework.h"
50
51
52 const AuthorizationRef kSCPreferencesUseEntitlementAuthorization = (AuthorizationRef)CFSTR("UseEntitlement");
53
54
55 __private_extern__ os_log_t
56 __log_SCPreferences(void)
57 {
58 static os_log_t log = NULL;
59
60 if (log == NULL) {
61 log = os_log_create("com.apple.SystemConfiguration", "SCPreferences");
62 }
63
64 return log;
65 }
66
67
68 static CFStringRef
69 __SCPreferencesCopyDescription(CFTypeRef cf) {
70 CFAllocatorRef allocator = CFGetAllocator(cf);
71 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)cf;
72 CFMutableStringRef result;
73
74 result = CFStringCreateMutable(allocator, 0);
75 CFStringAppendFormat(result, NULL, CFSTR("<SCPreferences %p [%p]> {"), cf, allocator);
76 CFStringAppendFormat(result, NULL, CFSTR("name = %@"), prefsPrivate->name);
77 CFStringAppendFormat(result, NULL, CFSTR(", id = %@"),
78 prefsPrivate->prefsID != NULL ? prefsPrivate->prefsID : CFSTR("[default]"));
79 CFStringAppendFormat(result, NULL, CFSTR(", path = %s"),
80 prefsPrivate->newPath != NULL ? prefsPrivate->newPath : prefsPrivate->path);
81 if (prefsPrivate->accessed) {
82 CFStringAppendFormat(result, NULL, CFSTR(", accessed"));
83 }
84 if (prefsPrivate->changed) {
85 CFStringAppendFormat(result, NULL, CFSTR(", changed"));
86 }
87 if (prefsPrivate->locked) {
88 CFStringAppendFormat(result, NULL, CFSTR(", locked"));
89 }
90 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
91 CFStringAppendFormat(result, NULL, CFSTR(", helper port = 0x%x"), prefsPrivate->helper_port);
92 }
93 CFStringAppendFormat(result, NULL, CFSTR("}"));
94
95 return result;
96 }
97
98
99 static void
100 __SCPreferencesDeallocate(CFTypeRef cf)
101 {
102 SCPreferencesRef prefs = (SCPreferencesRef)cf;
103 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
104
105 SC_log(LOG_DEBUG, "release %@", prefsPrivate);
106
107 if (prefsPrivate->locked) {
108 __SCPreferencesUpdateLockedState(prefs, FALSE);
109 }
110
111 /* release resources */
112
113 pthread_mutex_destroy(&prefsPrivate->lock);
114
115 if (prefsPrivate->parent != NULL) {
116 SCPreferencesPrivateRef parentPrivate = (SCPreferencesPrivateRef)prefsPrivate->parent;
117
118 // remove [weak] reference from parent to this companion
119 pthread_mutex_lock(&parentPrivate->lock);
120 CFDictionaryRemoveValue(parentPrivate->companions, prefsPrivate->prefsID);
121 pthread_mutex_unlock(&parentPrivate->lock);
122
123 // remove [strong] reference from companion to parent
124 CFRelease(prefsPrivate->parent);
125 }
126 if (prefsPrivate->companions != NULL) CFRelease(prefsPrivate->companions);
127
128 if (prefsPrivate->name) CFRelease(prefsPrivate->name);
129 if (prefsPrivate->prefsID) CFRelease(prefsPrivate->prefsID);
130 if (prefsPrivate->options) CFRelease(prefsPrivate->options);
131 if (prefsPrivate->path) CFAllocatorDeallocate(NULL, prefsPrivate->path);
132 if (prefsPrivate->newPath) CFAllocatorDeallocate(NULL, prefsPrivate->newPath);
133 if (prefsPrivate->lockFD != -1) {
134 if (prefsPrivate->lockPath != NULL) {
135 unlink(prefsPrivate->lockPath);
136 }
137 close(prefsPrivate->lockFD);
138 }
139 if (prefsPrivate->lockPath) CFAllocatorDeallocate(NULL, prefsPrivate->lockPath);
140 if (prefsPrivate->signature) CFRelease(prefsPrivate->signature);
141 if (prefsPrivate->sessionNoO_EXLOCK != NULL) {
142 CFRelease(prefsPrivate->sessionNoO_EXLOCK);
143 }
144 if (prefsPrivate->sessionKeyLock) CFRelease(prefsPrivate->sessionKeyLock);
145 if (prefsPrivate->sessionKeyCommit) CFRelease(prefsPrivate->sessionKeyCommit);
146 if (prefsPrivate->sessionKeyApply) CFRelease(prefsPrivate->sessionKeyApply);
147 if (prefsPrivate->rlsContext.release != NULL) {
148 (*prefsPrivate->rlsContext.release)(prefsPrivate->rlsContext.info);
149 }
150 if (prefsPrivate->prefs) CFRelease(prefsPrivate->prefs);
151 if (prefsPrivate->authorizationData != NULL) CFRelease(prefsPrivate->authorizationData);
152 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
153 (void) _SCHelperExec(prefsPrivate->helper_port,
154 SCHELPER_MSG_PREFS_CLOSE,
155 NULL,
156 NULL,
157 NULL);
158 _SCHelperClose(&prefsPrivate->helper_port);
159 }
160
161 return;
162 }
163
164
165 static CFTypeID __kSCPreferencesTypeID = _kCFRuntimeNotATypeID;
166
167
168 static const CFRuntimeClass __SCPreferencesClass = {
169 0, // version
170 "SCPreferences", // className
171 NULL, // init
172 NULL, // copy
173 __SCPreferencesDeallocate, // dealloc
174 NULL, // equal
175 NULL, // hash
176 NULL, // copyFormattingDesc
177 __SCPreferencesCopyDescription // copyDebugDesc
178 };
179
180
181 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
182
183 static void
184 __SCPreferencesInitialize(void) {
185 /* register with CoreFoundation */
186 __kSCPreferencesTypeID = _CFRuntimeRegisterClass(&__SCPreferencesClass);
187 return;
188 }
189
190
191 static SCPreferencesPrivateRef
192 __SCPreferencesCreatePrivate(CFAllocatorRef allocator)
193 {
194 SCPreferencesPrivateRef prefsPrivate;
195 uint32_t size;
196
197 /* initialize runtime */
198 pthread_once(&initialized, __SCPreferencesInitialize);
199
200 /* allocate prefs session */
201 size = sizeof(SCPreferencesPrivate) - sizeof(CFRuntimeBase);
202 prefsPrivate = (SCPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
203 __kSCPreferencesTypeID,
204 size,
205 NULL);
206 if (prefsPrivate == NULL) {
207 return NULL;
208 }
209
210 /* initialize non-zero/NULL members */
211 pthread_mutex_init(&prefsPrivate->lock, NULL);
212 prefsPrivate->lockFD = -1;
213 prefsPrivate->isRoot = (geteuid() == 0);
214
215 return prefsPrivate;
216 }
217
218
219 __private_extern__ Boolean
220 __SCPreferencesCreate_helper(SCPreferencesRef prefs)
221 {
222 CFDataRef data = NULL;
223 CFMutableDictionaryRef info;
224 CFNumberRef num;
225 Boolean ok;
226 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
227 uint32_t status = kSCStatusOK;
228 CFStringRef str;
229 uint32_t pid = getpid();
230
231 // start helper
232 ok = _SCHelperOpen(prefsPrivate->authorizationData,
233 &prefsPrivate->helper_port);
234 if (!ok) {
235 goto fail;
236 }
237
238 // create a dictionary of information to pass to the helper
239 info = CFDictionaryCreateMutable(NULL,
240 0,
241 &kCFTypeDictionaryKeyCallBacks,
242 &kCFTypeDictionaryValueCallBacks);
243
244 // save prefsID
245 if (prefsPrivate->prefsID != NULL) {
246 CFDictionarySetValue(info, CFSTR("prefsID"), prefsPrivate->prefsID);
247 }
248
249 // save options
250 if (prefsPrivate->options != NULL) {
251 CFDictionarySetValue(info, CFSTR("options"), prefsPrivate->options);
252 }
253
254 // save preferences session "name"
255 CFDictionarySetValue(info, CFSTR("name"), prefsPrivate->name);
256
257 // save PID
258 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &pid);
259 CFDictionarySetValue(info, CFSTR("PID"), num);
260 CFRelease(num);
261
262 // save process name
263 str = CFStringCreateWithCString(NULL, getprogname(), kCFStringEncodingUTF8);
264 CFDictionarySetValue(info, CFSTR("PROC_NAME"), str);
265 CFRelease(str);
266
267 // serialize the info
268 ok = _SCSerialize(info, &data, NULL, NULL);
269 CFRelease(info);
270 if (data == NULL || !ok) {
271 goto fail;
272 }
273
274 // have the helper "open" the prefs
275 ok = _SCHelperExec(prefsPrivate->helper_port,
276 SCHELPER_MSG_PREFS_OPEN,
277 data,
278 &status,
279 NULL);
280 if (data != NULL) CFRelease(data);
281 if (!ok) {
282 goto fail;
283 }
284
285 if (status != kSCStatusOK) {
286 goto error;
287 }
288
289 return TRUE;
290
291 fail :
292
293 // close helper
294 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
295 _SCHelperClose(&prefsPrivate->helper_port);
296 }
297
298 status = kSCStatusAccessError;
299
300 error :
301
302 // return error
303 _SCErrorSet(status);
304 return FALSE;
305 }
306
307
308 static Boolean
309 __SCPreferencesAccess_helper(SCPreferencesRef prefs)
310 {
311 Boolean ok;
312 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
313 CFDictionaryRef serverDict = NULL;
314 CFDictionaryRef serverPrefs = NULL;
315 CFDictionaryRef serverSignature = NULL;
316 uint32_t status = kSCStatusOK;
317 CFDataRef reply = NULL;
318
319 if (prefsPrivate->helper_port == MACH_PORT_NULL) {
320 ok = __SCPreferencesCreate_helper(prefs);
321 if (!ok) {
322 return FALSE;
323 }
324 }
325
326 // have the helper "access" the prefs
327 ok = _SCHelperExec(prefsPrivate->helper_port,
328 SCHELPER_MSG_PREFS_ACCESS,
329 NULL,
330 &status,
331 &reply);
332 if (!ok) {
333 goto fail;
334 }
335
336 if (status != kSCStatusOK) {
337 goto error;
338 }
339
340 if (reply == NULL) {
341 goto fail;
342 }
343
344 ok = _SCUnserialize((CFPropertyListRef *)&serverDict, reply, NULL, 0);
345 CFRelease(reply);
346 if (!ok) {
347 goto fail;
348 }
349
350 if (isA_CFDictionary(serverDict)) {
351 serverPrefs = CFDictionaryGetValue(serverDict, CFSTR("preferences"));
352 serverPrefs = isA_CFDictionary(serverPrefs);
353
354 serverSignature = CFDictionaryGetValue(serverDict, CFSTR("signature"));
355 serverSignature = isA_CFData(serverSignature);
356 }
357
358 if ((serverPrefs == NULL) || (serverSignature == NULL)) {
359 if (serverDict != NULL) CFRelease(serverDict);
360 goto fail;
361 }
362
363 prefsPrivate->prefs = CFDictionaryCreateMutableCopy(NULL, 0, serverPrefs);
364 prefsPrivate->signature = CFRetain(serverSignature);
365 prefsPrivate->accessed = TRUE;
366 CFRelease(serverDict);
367
368 return TRUE;
369
370 fail :
371
372 // close helper
373 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
374 _SCHelperClose(&prefsPrivate->helper_port);
375 }
376
377 status = kSCStatusAccessError;
378
379 error :
380
381 // return error
382 _SCErrorSet(status);
383 return FALSE;
384 }
385
386
387 static SCPreferencesPrivateRef
388 __SCPreferencesCreate(CFAllocatorRef allocator,
389 CFStringRef name,
390 CFStringRef prefsID,
391 CFDataRef authorizationData,
392 CFDictionaryRef options)
393 {
394 SCPreferencesPrivateRef prefsPrivate;
395 int sc_status = kSCStatusOK;
396
397 /*
398 * allocate and initialize a new prefs session
399 */
400 prefsPrivate = __SCPreferencesCreatePrivate(allocator);
401 if (prefsPrivate == NULL) {
402 return NULL;
403 }
404
405 prefsPrivate->name = CFStringCreateCopy(allocator, name);
406 if (prefsID != NULL) {
407 prefsPrivate->prefsID = CFStringCreateCopy(allocator, prefsID);
408 }
409 if (authorizationData != NULL) {
410 prefsPrivate->authorizationData = CFRetain(authorizationData);
411 }
412 if (options != NULL) {
413 prefsPrivate->options = CFDictionaryCreateCopy(allocator, options);
414 }
415
416 retry :
417
418 /*
419 * convert prefsID to path
420 */
421 prefsPrivate->path = __SCPreferencesPath(allocator,
422 prefsID,
423 (prefsPrivate->newPath == NULL));
424 if (prefsPrivate->path == NULL) {
425 sc_status = kSCStatusFailed;
426 goto error;
427 }
428
429 if (access(prefsPrivate->path, R_OK) == 0) {
430 goto done;
431 }
432
433 switch (errno) {
434 case ENOENT :
435 /* no prefs file */
436 if ((prefsID == NULL) || !CFStringHasPrefix(prefsID, CFSTR("/"))) {
437 /* if default preference ID or relative path */
438 if (prefsPrivate->newPath == NULL) {
439 /*
440 * we've looked in the "new" prefs directory
441 * without success. Save the "new" path and
442 * look in the "old" prefs directory.
443 */
444 prefsPrivate->newPath = prefsPrivate->path;
445 goto retry;
446 } else {
447 /*
448 * we've looked in both the "new" and "old"
449 * prefs directories without success. Use
450 * the "new" path.
451 */
452 CFAllocatorDeallocate(NULL, prefsPrivate->path);
453 prefsPrivate->path = prefsPrivate->newPath;
454 prefsPrivate->newPath = NULL;
455 }
456 }
457
458 /* no preference data, start fresh */
459 sc_status = kSCStatusNoConfigFile;
460 goto done;
461 case EPERM :
462 case EACCES :
463 if (prefsPrivate->authorizationData != NULL) {
464 /* no problem, we'll be using the helper */
465 goto done;
466 }
467
468 SC_log(LOG_NOTICE, "open() failed: %s", strerror(errno));
469 sc_status = kSCStatusAccessError;
470 break;
471 default :
472 SC_log(LOG_NOTICE, "open() failed: %s", strerror(errno));
473 sc_status = kSCStatusFailed;
474 break;
475 }
476
477 error:
478
479 CFRelease(prefsPrivate);
480 _SCErrorSet(sc_status);
481 return NULL;
482
483 done :
484
485 /* all OK */
486 _SCErrorSet(sc_status);
487 return prefsPrivate;
488 }
489
490
491 __private_extern__ void
492 __SCPreferencesAccess(SCPreferencesRef prefs)
493 {
494 CFAllocatorRef allocator = CFGetAllocator(prefs);
495 int fd = -1;
496 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
497 struct stat statBuf;
498
499 if (prefsPrivate->accessed) {
500 // if preference data has already been accessed
501 return;
502 }
503
504 if (access(prefsPrivate->path, R_OK) == 0) {
505 fd = open(prefsPrivate->path, O_RDONLY, 0644);
506 } else {
507 fd = -1;
508 }
509 if (fd != -1) {
510 // create signature
511 if (fstat(fd, &statBuf) == -1) {
512 SC_log(LOG_NOTICE, "fstat() failed: %s", strerror(errno));
513 memset(&statBuf, 0, sizeof(statBuf));
514 }
515 } else {
516 switch (errno) {
517 case ENOENT :
518 /* no preference data, start fresh */
519 break;
520 case EPERM :
521 case EACCES :
522 if (prefsPrivate->authorizationData != NULL) {
523 if (__SCPreferencesAccess_helper(prefs)) {
524 goto done;
525 } else {
526 SC_log(LOG_NOTICE, "__SCPreferencesAccess_helper() failed: %s",
527 SCErrorString(SCError()));
528 }
529 break;
530 }
531 // fall through
532 default :
533 SC_log(LOG_NOTICE, "open() failed: %s", strerror(errno));
534 break;
535 }
536 memset(&statBuf, 0, sizeof(statBuf));
537 }
538
539 if (prefsPrivate->signature != NULL) CFRelease(prefsPrivate->signature);
540 prefsPrivate->signature = __SCPSignatureFromStatbuf(&statBuf);
541
542 if (statBuf.st_size > 0) {
543 CFDictionaryRef dict;
544 CFErrorRef error = NULL;
545 CFMutableDataRef xmlData;
546
547 /*
548 * extract property list
549 */
550 xmlData = CFDataCreateMutable(allocator, (CFIndex)statBuf.st_size);
551 CFDataSetLength(xmlData, (CFIndex)statBuf.st_size);
552 if (read(fd, (void *)CFDataGetBytePtr(xmlData), (CFIndex)statBuf.st_size) != (CFIndex)statBuf.st_size) {
553 /* corrupt prefs file, start fresh */
554 SC_log(LOG_INFO, "read(): could not load preference data");
555 CFRelease(xmlData);
556 xmlData = NULL;
557 goto done;
558 }
559
560 /*
561 * load preferences
562 */
563 dict = CFPropertyListCreateWithData(allocator, xmlData, kCFPropertyListImmutable, NULL, &error);
564 CFRelease(xmlData);
565 if (dict == NULL) {
566 /* corrupt prefs file, start fresh */
567 if (error != NULL) {
568 SC_log(LOG_NOTICE, "CFPropertyListCreateWithData(): %@", error);
569 CFRelease(error);
570 }
571 goto done;
572 }
573
574 /*
575 * make sure that we've got a dictionary
576 */
577 if (!isA_CFDictionary(dict)) {
578 /* corrupt prefs file, start fresh */
579 SC_log(LOG_INFO, "CFGetTypeID(): not a dictionary");
580 CFRelease(dict);
581 goto done;
582 }
583
584 prefsPrivate->prefs = CFDictionaryCreateMutableCopy(allocator, 0, dict);
585 CFRelease(dict);
586 }
587
588 done :
589
590 if (fd != -1) {
591 (void) close(fd);
592 }
593
594 if (prefsPrivate->prefs == NULL) {
595 /*
596 * new file, create empty preferences
597 */
598 // SC_log(LOG_INFO, "creating new preferences file");
599 prefsPrivate->prefs = CFDictionaryCreateMutable(allocator,
600 0,
601 &kCFTypeDictionaryKeyCallBacks,
602 &kCFTypeDictionaryValueCallBacks);
603 prefsPrivate->changed = TRUE;
604 }
605
606 SC_log(LOG_DEBUG, "SCPreferences() access: %s, size=%lld",
607 prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path,
608 __SCPreferencesPrefsSize(prefs));
609
610 prefsPrivate->accessed = TRUE;
611 return;
612 }
613
614
615 SCPreferencesRef
616 SCPreferencesCreate(CFAllocatorRef allocator,
617 CFStringRef name,
618 CFStringRef prefsID)
619 {
620 SCPreferencesPrivateRef prefsPrivate;
621
622 prefsPrivate = __SCPreferencesCreate(allocator, name, prefsID, NULL, NULL);
623 if (prefsPrivate != NULL) {
624 SC_log(LOG_DEBUG, "create %@", prefsPrivate);
625 }
626
627 return (SCPreferencesRef)prefsPrivate;
628 }
629
630
631 SCPreferencesRef
632 SCPreferencesCreateWithAuthorization(CFAllocatorRef allocator,
633 CFStringRef name,
634 CFStringRef prefsID,
635 AuthorizationRef authorization)
636 {
637 SCPreferencesRef prefs;
638
639 #if !TARGET_OS_IPHONE
640 if (authorization == NULL) {
641 authorization = kSCPreferencesUseEntitlementAuthorization;
642 }
643 #else // !TARGET_OS_IPHONE
644 authorization = kSCPreferencesUseEntitlementAuthorization;
645 #endif // !TARGET_OS_IPHONE
646
647 prefs = SCPreferencesCreateWithOptions(allocator, name, prefsID, authorization, NULL);
648 return prefs;
649 }
650
651
652 SCPreferencesRef
653 SCPreferencesCreateWithOptions(CFAllocatorRef allocator,
654 CFStringRef name,
655 CFStringRef prefsID,
656 AuthorizationRef authorization,
657 CFDictionaryRef options)
658 {
659 CFDataRef authorizationData = NULL;
660 SCPreferencesPrivateRef prefsPrivate;
661
662 if (options != NULL) {
663 if (!isA_CFDictionary(options)) {
664 _SCErrorSet(kSCStatusInvalidArgument);
665 return NULL;
666 }
667 }
668
669 if (authorization != NULL) {
670 CFMutableDictionaryRef authorizationDict;
671 CFStringRef bundleID;
672
673 authorizationDict = CFDictionaryCreateMutable(NULL,
674 0,
675 &kCFTypeDictionaryKeyCallBacks,
676 &kCFTypeDictionaryValueCallBacks);
677 #if !TARGET_OS_IPHONE
678 if (authorization != kSCPreferencesUseEntitlementAuthorization) {
679 CFDataRef data;
680 AuthorizationExternalForm extForm;
681 OSStatus os_status;
682
683 os_status = AuthorizationMakeExternalForm(authorization, &extForm);
684 if (os_status != errAuthorizationSuccess) {
685 SC_log(LOG_INFO, "AuthorizationMakeExternalForm() failed");
686 _SCErrorSet(kSCStatusInvalidArgument);
687 CFRelease(authorizationDict);
688 return NULL;
689 }
690
691 data = CFDataCreate(NULL, (const UInt8 *)extForm.bytes, sizeof(extForm.bytes));
692 CFDictionaryAddValue(authorizationDict,
693 kSCHelperAuthAuthorization,
694 data);
695 CFRelease(data);
696 }
697 #endif // !TARGET_OS_IPHONE
698
699 bundleID = _SC_getApplicationBundleID();
700 CFDictionaryAddValue(authorizationDict,
701 kSCHelperAuthCallerInfo,
702 bundleID);
703
704 if (authorizationDict != NULL) {
705 (void) _SCSerialize((CFPropertyListRef)authorizationDict,
706 &authorizationData,
707 NULL,
708 NULL);
709 CFRelease(authorizationDict);
710 }
711 }
712
713 prefsPrivate = __SCPreferencesCreate(allocator, name, prefsID, authorizationData, options);
714 if (prefsPrivate != NULL) {
715 const char *astr = "";
716 const char *ostr = "";
717
718 if (options != NULL) {
719 ostr = "options";
720 }
721
722 if (authorization != NULL) {
723 if (authorization == kSCPreferencesUseEntitlementAuthorization) {
724 astr = "entitlement";
725 } else {
726 astr = "authorization";
727 }
728 }
729
730 SC_log(LOG_DEBUG, "create w/%s%s%s %@",
731 ostr,
732 ((ostr != "") && (astr != "")) ? " + " : "",
733 astr,
734 prefsPrivate);
735 }
736
737 if (authorizationData != NULL) CFRelease(authorizationData);
738
739 return (SCPreferencesRef)prefsPrivate;
740 }
741
742
743 SCPreferencesRef
744 SCPreferencesCreateCompanion(SCPreferencesRef prefs, CFStringRef companionPrefsID)
745 {
746 CFAllocatorRef allocator = CFGetAllocator(prefs);
747 SCPreferencesPrivateRef companionPrefs = NULL;
748 CFMutableStringRef newPrefsID;
749 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
750
751 if (companionPrefsID == NULL) {
752 companionPrefsID = PREFS_DEFAULT_CONFIG;
753 } else {
754 if (CFStringFindWithOptions(companionPrefsID,
755 CFSTR("/"),
756 CFRangeMake(0, CFStringGetLength(companionPrefsID)),
757 kCFCompareBackwards,
758 NULL)) {
759 // if companion prefsID contains a "/"
760 _SCErrorSet(kSCStatusInvalidArgument);
761 return NULL;
762 }
763 }
764
765 if (prefsPrivate->prefsID == NULL) {
766 if (CFEqual(companionPrefsID, PREFS_DEFAULT_CONFIG)) {
767 // if prefsID and companionPrefsID match
768 _SCErrorSet(kSCStatusInvalidArgument);
769 return NULL;
770 }
771 newPrefsID = CFStringCreateMutableCopy(allocator, 0, companionPrefsID);
772 } else {
773 CFIndex prefsIDLen = CFStringGetLength(prefsPrivate->prefsID);
774 CFRange range;
775
776 if (CFStringFindWithOptions(prefsPrivate->prefsID,
777 CFSTR("/"),
778 CFRangeMake(0, prefsIDLen),
779 kCFCompareBackwards,
780 &range)) {
781 Boolean match;
782 CFStringRef suffix;
783
784 // if slash, check suffix
785 range.location++;
786 if (range.location >= prefsIDLen) {
787 // if no suffix
788 _SCErrorSet(kSCStatusInvalidArgument);
789 return NULL;
790 }
791 range.length = prefsIDLen - range.location;
792 suffix = CFStringCreateWithSubstring(allocator, prefsPrivate->prefsID, range);
793 match = CFEqual(suffix, companionPrefsID);
794 CFRelease(suffix);
795 if (match) {
796 // if prefsID [suffix] and companionPrefsID match
797 _SCErrorSet(kSCStatusInvalidArgument);
798 return NULL;
799 }
800
801 // replace the suffix
802 newPrefsID = CFStringCreateMutableCopy(NULL, 0, prefsPrivate->prefsID);
803 CFStringReplace(newPrefsID, range, companionPrefsID);
804 } else if (!CFEqual(prefsPrivate->prefsID, companionPrefsID)) {
805 // if no slash, prefsID and companionPrefsID differ
806 newPrefsID = CFStringCreateMutableCopy(NULL, 0, companionPrefsID);
807 } else {
808 // if no slash, prefsID and companionPrefsID match
809 _SCErrorSet(kSCStatusInvalidArgument);
810 return NULL;
811 }
812 }
813 assert(newPrefsID != NULL);
814
815 pthread_mutex_lock(&prefsPrivate->lock);
816 if ((prefsPrivate->companions != NULL) &&
817 CFDictionaryGetValueIfPresent(prefsPrivate->companions,
818 newPrefsID,
819 (const void **)&companionPrefs) &&
820 (companionPrefs != NULL)) {
821 // if we already have a companion
822 SC_log(LOG_DEBUG, "create [companion] reference %@", companionPrefs);
823 CFRetain(companionPrefs);
824 } else {
825 companionPrefs = __SCPreferencesCreate(allocator,
826 prefsPrivate->name,
827 newPrefsID,
828 prefsPrivate->authorizationData,
829 prefsPrivate->options);
830 if (companionPrefs != NULL) {
831 SCPreferencesPrivateRef companionPrefsPrivate = (SCPreferencesPrivateRef)companionPrefs;
832
833 SC_log(LOG_DEBUG, "create [companion] %@", companionPrefs);
834
835 // add [strong] reference from companion to parent
836 companionPrefsPrivate->parent = CFRetain(prefs);
837
838 // add [weak] reference from parent to this companion
839 if (prefsPrivate->companions == NULL) {
840 prefsPrivate->companions = CFDictionaryCreateMutable(NULL,
841 0,
842 &kCFTypeDictionaryKeyCallBacks,
843 NULL);
844 }
845 CFDictionarySetValue(prefsPrivate->companions, newPrefsID, companionPrefs);
846 }
847 }
848 pthread_mutex_unlock(&prefsPrivate->lock);
849
850 CFRelease(newPrefsID);
851
852 return (SCPreferencesRef)companionPrefs;
853 }
854
855
856 CFTypeID
857 SCPreferencesGetTypeID(void) {
858 pthread_once(&initialized, __SCPreferencesInitialize); /* initialize runtime */
859 return __kSCPreferencesTypeID;
860 }
861
862
863 static void
864 prefsNotify(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
865 {
866 #pragma unused(store)
867 void *context_info;
868 void (*context_release)(const void *);
869 CFIndex i;
870 CFIndex n;
871 SCPreferencesNotification notify = 0;
872 SCPreferencesRef prefs = (SCPreferencesRef)info;
873 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
874 SCPreferencesCallBack rlsFunction;
875
876 n = (changedKeys != NULL) ? CFArrayGetCount(changedKeys) : 0;
877 for (i = 0; i < n; i++) {
878 CFStringRef key;
879
880 key = CFArrayGetValueAtIndex(changedKeys, i);
881
882 // check if "commit"
883 if (CFEqual(key, prefsPrivate->sessionKeyCommit)) {
884 // if preferences have been saved
885 notify |= kSCPreferencesNotificationCommit;
886 continue;
887 }
888
889 // check if "apply"
890 if (CFEqual(key, prefsPrivate->sessionKeyApply)) {
891 // if stored preferences should be applied to current configuration
892 notify |= kSCPreferencesNotificationApply;
893 continue;
894 }
895 }
896
897 if (notify == 0) {
898 // if no changes
899 return;
900 }
901
902 pthread_mutex_lock(&prefsPrivate->lock);
903
904 /* callout */
905 rlsFunction = prefsPrivate->rlsFunction;
906 if (prefsPrivate->rlsContext.retain != NULL) {
907 context_info = (void *)prefsPrivate->rlsContext.retain(prefsPrivate->rlsContext.info);
908 context_release = prefsPrivate->rlsContext.release;
909 } else {
910 context_info = prefsPrivate->rlsContext.info;
911 context_release = NULL;
912 }
913
914 pthread_mutex_unlock(&prefsPrivate->lock);
915
916 if (rlsFunction != NULL) {
917 SC_log(LOG_DEBUG, "exec SCPreferences callout: %s%s%s",
918 ((notify & kSCPreferencesNotificationCommit) != 0) ? "commit" : "",
919 (((notify & kSCPreferencesNotificationCommit) != 0) &&
920 ((notify & kSCPreferencesNotificationApply ) != 0)) ? ", " : "",
921 ((notify & kSCPreferencesNotificationApply) != 0) ? "apply" : "");
922 (*rlsFunction)(prefs, notify, context_info);
923 }
924
925 if (context_release != NULL) {
926 (*context_release)(context_info);
927 }
928
929 return;
930 }
931
932
933 __private_extern__ void
934 __SCPreferencesAddSessionKeys(SCPreferencesRef prefs)
935 {
936 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
937
938 /* create the session "commit" key */
939 if (prefsPrivate->sessionKeyCommit == NULL) {
940 prefsPrivate->sessionKeyCommit = _SCPNotificationKey(NULL,
941 prefsPrivate->prefsID,
942 kSCPreferencesKeyCommit);
943 }
944
945 /* create the session "apply" key */
946 if (prefsPrivate->sessionKeyApply == NULL) {
947 prefsPrivate->sessionKeyApply = _SCPNotificationKey(NULL,
948 prefsPrivate->prefsID,
949 kSCPreferencesKeyApply);
950 }
951
952 return;
953 }
954
955
956 __private_extern__ Boolean
957 __SCPreferencesAddSession(SCPreferencesRef prefs)
958 {
959 CFAllocatorRef allocator = CFGetAllocator(prefs);
960 SCDynamicStoreContext context = { 0
961 , (void *)prefs
962 , CFRetain
963 , CFRelease
964 , CFCopyDescription
965 };
966 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
967
968 if (prefsPrivate->sessionRefcnt == 0) {
969 /* establish a dynamic store session */
970 prefsPrivate->session = SCDynamicStoreCreate(allocator,
971 prefsPrivate->name,
972 prefsNotify,
973 &context);
974 if (prefsPrivate->session == NULL) {
975 SC_log(LOG_INFO, "SCDynamicStoreCreate() failed");
976 return FALSE;
977 }
978
979 SC_log(LOG_DEBUG, "added SCDynamicStore session (for prefs)");
980 }
981
982 prefsPrivate->sessionRefcnt++;
983 return TRUE;
984 }
985
986
987 __private_extern__ void
988 __SCPreferencesRemoveSession(SCPreferencesRef prefs)
989 {
990 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
991
992 if (prefsPrivate->sessionRefcnt > 0) {
993 if (--prefsPrivate->sessionRefcnt == 0) {
994 CFRelease(prefsPrivate->session);
995 prefsPrivate->session = NULL;
996
997 SC_log(LOG_DEBUG, "removed SCDynamicStore session (for prefs)");
998 }
999 }
1000
1001 return;
1002 }
1003
1004
1005 static void
1006 appendLockedPreferences(const void *key, const void *value, void *context)
1007 {
1008 #pragma unused(key)
1009 CFMutableStringRef str = (CFMutableStringRef)context;
1010
1011 CFStringAppendFormat(str, NULL, CFSTR("%s%@"),
1012 (CFStringGetLength(str) > 0) ? "\n" : "",
1013 value);
1014 return;
1015 }
1016
1017
1018 __private_extern__ void
1019 __SCPreferencesUpdateLockedState(SCPreferencesRef prefs, Boolean locked)
1020 {
1021 static dispatch_queue_t lockedQueue;
1022 static CFMutableDictionaryRef lockedState;
1023 static dispatch_once_t once;
1024 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1025
1026 dispatch_once(&once, ^{
1027 os_state_block_t state_block;
1028
1029 lockedQueue = dispatch_queue_create("SCPreferences locked state queue", NULL);
1030
1031 lockedState = CFDictionaryCreateMutable(NULL,
1032 0,
1033 NULL, // NO retain/release
1034 &kCFTypeDictionaryValueCallBacks);
1035
1036 state_block = ^os_state_data_t(os_state_hints_t hints) {
1037 #pragma unused(hints)
1038 CFDataRef data = NULL;
1039 Boolean ok;
1040 os_state_data_t state_data;
1041 size_t state_data_size;
1042 CFIndex state_len;
1043 CFMutableStringRef str;
1044
1045 if (CFDictionaryGetCount(lockedState) == 0) {
1046 // if no locked preferences
1047 return NULL;
1048 }
1049
1050 str = CFStringCreateMutable(NULL, 0);
1051 CFDictionaryApplyFunction(lockedState, appendLockedPreferences, str);
1052 ok = _SCSerialize(str, &data, NULL, NULL);
1053 CFRelease(str);
1054
1055 state_len = (ok && (data != NULL)) ? CFDataGetLength(data) : 0;
1056 state_data_size = OS_STATE_DATA_SIZE_NEEDED(state_len);
1057 if (state_data_size > MAX_STATEDUMP_SIZE) {
1058 SC_log(LOG_ERR, "locked SCPreferences : state data too large (%zd > %zd)",
1059 state_data_size,
1060 (size_t)MAX_STATEDUMP_SIZE);
1061 if (data != NULL) CFRelease(data);
1062 return NULL;
1063 }
1064
1065 state_data = calloc(1, state_data_size);
1066 if (state_data == NULL) {
1067 SC_log(LOG_ERR, "locked SCPreferences: could not allocate state data");
1068 if (data != NULL) CFRelease(data);
1069 return NULL;
1070 }
1071
1072 state_data->osd_type = OS_STATE_DATA_SERIALIZED_NSCF_OBJECT;
1073 state_data->osd_data_size = (uint32_t)state_len;
1074 strlcpy(state_data->osd_title, "open/locked SCPreferences", sizeof(state_data->osd_title));
1075 if (state_len > 0) {
1076 memcpy(state_data->osd_data, CFDataGetBytePtr(data), state_len);
1077 }
1078 if (data != NULL) CFRelease(data);
1079
1080 return state_data;
1081 };
1082
1083 (void) os_state_add_handler(lockedQueue, state_block);
1084 });
1085
1086 // update the locked state
1087 prefsPrivate->locked = locked;
1088
1089 // add (or update) the locked preferences
1090 dispatch_sync(lockedQueue, ^{
1091 if (locked) {
1092 CFStringRef str;
1093
1094 str = CFCopyDescription(prefs);
1095 CFDictionarySetValue(lockedState, prefs, str);
1096 CFRelease(str);
1097 } else {
1098 CFDictionaryRemoveValue(lockedState, prefs);
1099 }
1100 });
1101
1102 return;
1103 }
1104
1105
1106 Boolean
1107 SCPreferencesSetCallback(SCPreferencesRef prefs,
1108 SCPreferencesCallBack callout,
1109 SCPreferencesContext *context)
1110 {
1111 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1112
1113 if (!isA_SCPreferences(prefs)) {
1114 /* sorry, you must provide a session */
1115 _SCErrorSet(kSCStatusNoPrefsSession);
1116 return FALSE;
1117 }
1118
1119 pthread_mutex_lock(&prefsPrivate->lock);
1120
1121 if (prefsPrivate->rlsContext.release != NULL) {
1122 /* let go of the current context */
1123 (*prefsPrivate->rlsContext.release)(prefsPrivate->rlsContext.info);
1124 }
1125
1126 prefsPrivate->rlsFunction = callout;
1127 prefsPrivate->rlsContext.info = NULL;
1128 prefsPrivate->rlsContext.retain = NULL;
1129 prefsPrivate->rlsContext.release = NULL;
1130 prefsPrivate->rlsContext.copyDescription = NULL;
1131 if (context != NULL) {
1132 memcpy(&prefsPrivate->rlsContext, context, sizeof(SCPreferencesContext));
1133 if (context->retain != NULL) {
1134 prefsPrivate->rlsContext.info = (void *)(*context->retain)(context->info);
1135 }
1136 }
1137
1138 pthread_mutex_unlock(&prefsPrivate->lock);
1139
1140 return TRUE;
1141 }
1142
1143
1144 static Boolean
1145 __SCPreferencesScheduleWithRunLoop(SCPreferencesRef prefs,
1146 CFRunLoopRef runLoop,
1147 CFStringRef runLoopMode,
1148 dispatch_queue_t queue)
1149 {
1150 Boolean ok = FALSE;
1151 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1152
1153 pthread_mutex_lock(&prefsPrivate->lock);
1154
1155 if ((prefsPrivate->dispatchQueue != NULL) || // if we are already scheduled on a dispatch queue
1156 ((queue != NULL) && prefsPrivate->scheduled)) { // if we are already scheduled on a CFRunLoop
1157 _SCErrorSet(kSCStatusInvalidArgument);
1158 goto done;
1159 }
1160
1161 if (!prefsPrivate->scheduled) {
1162 CFMutableArrayRef keys;
1163
1164 // add SCDynamicStore session (for notifications) ... and hold a 'prefs' reference
1165 if (prefsPrivate->session == NULL) {
1166 ok = __SCPreferencesAddSession(prefs);
1167 if (!ok) {
1168 goto done;
1169 }
1170 assert(prefsPrivate->session != NULL);
1171 }
1172
1173 // add SCDynamicStore "keys"
1174 __SCPreferencesAddSessionKeys(prefs);
1175
1176 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1177 CFArrayAppendValue(keys, prefsPrivate->sessionKeyCommit);
1178 CFArrayAppendValue(keys, prefsPrivate->sessionKeyApply);
1179 (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, keys, NULL);
1180 CFRelease(keys);
1181
1182 if (runLoop != NULL) {
1183 prefsPrivate->rls = SCDynamicStoreCreateRunLoopSource(NULL, prefsPrivate->session, 0);
1184 prefsPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1185 }
1186
1187 SC_log(LOG_DEBUG, "scheduled");
1188
1189 prefsPrivate->scheduled = TRUE;
1190 }
1191
1192 if (queue != NULL) {
1193 ok = SCDynamicStoreSetDispatchQueue(prefsPrivate->session, queue);
1194 if (!ok) {
1195 prefsPrivate->scheduled = FALSE;
1196 (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, NULL, NULL);
1197 __SCPreferencesRemoveSession(prefs);
1198 goto done;
1199 }
1200
1201 prefsPrivate->dispatchQueue = queue;
1202 dispatch_retain(prefsPrivate->dispatchQueue);
1203 } else {
1204 if (!_SC_isScheduled(NULL, runLoop, runLoopMode, prefsPrivate->rlList)) {
1205 /*
1206 * if we do not already have notifications scheduled with
1207 * this runLoop / runLoopMode
1208 */
1209 CFRunLoopAddSource(runLoop, prefsPrivate->rls, runLoopMode);
1210 }
1211
1212 _SC_schedule(prefs, runLoop, runLoopMode, prefsPrivate->rlList);
1213 }
1214
1215 ok = TRUE;
1216
1217 done :
1218
1219 pthread_mutex_unlock(&prefsPrivate->lock);
1220 return ok;
1221 }
1222
1223
1224 static Boolean
1225 __SCPreferencesUnscheduleFromRunLoop(SCPreferencesRef prefs,
1226 CFRunLoopRef runLoop,
1227 CFStringRef runLoopMode)
1228 {
1229 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1230 CFIndex n = 0;
1231 Boolean ok = FALSE;
1232
1233 pthread_mutex_lock(&prefsPrivate->lock);
1234
1235 if ((runLoop != NULL) && !prefsPrivate->scheduled) { // if we should be scheduled (but are not)
1236 _SCErrorSet(kSCStatusInvalidArgument);
1237 goto done;
1238 }
1239
1240 if (((runLoop == NULL) && (prefsPrivate->dispatchQueue == NULL)) || // if we should be scheduled on a dispatch queue (but are not)
1241 ((runLoop != NULL) && (prefsPrivate->dispatchQueue != NULL))) { // if we should be scheduled on a CFRunLoop (but are scheduled on a dispatch queue)
1242 _SCErrorSet(kSCStatusInvalidArgument);
1243 goto done;
1244 }
1245
1246 if (runLoop == NULL) {
1247 SCDynamicStoreSetDispatchQueue(prefsPrivate->session, NULL);
1248 dispatch_release(prefsPrivate->dispatchQueue);
1249 prefsPrivate->dispatchQueue = NULL;
1250 } else {
1251 if (!_SC_unschedule(prefs, runLoop, runLoopMode, prefsPrivate->rlList, FALSE)) {
1252 // if not currently scheduled on this runLoop / runLoopMode
1253 _SCErrorSet(kSCStatusInvalidArgument);
1254 goto done;
1255 }
1256
1257 n = CFArrayGetCount(prefsPrivate->rlList);
1258 if (n == 0 || !_SC_isScheduled(NULL, runLoop, runLoopMode, prefsPrivate->rlList)) {
1259 /*
1260 * if we are no longer scheduled to receive notifications for
1261 * this runLoop / runLoopMode
1262 */
1263 CFRunLoopRemoveSource(runLoop, prefsPrivate->rls, runLoopMode);
1264
1265 if (n == 0) {
1266 // if *all* notifications have been unscheduled
1267 CFRelease(prefsPrivate->rlList);
1268 prefsPrivate->rlList = NULL;
1269 CFRunLoopSourceInvalidate(prefsPrivate->rls);
1270 CFRelease(prefsPrivate->rls);
1271 prefsPrivate->rls = NULL;
1272 }
1273 }
1274 }
1275
1276 if (n == 0) {
1277 CFArrayRef changedKeys;
1278
1279 SC_log(LOG_DEBUG, "unscheduled");
1280
1281 // if *all* notifications have been unscheduled
1282 prefsPrivate->scheduled = FALSE;
1283
1284 // no need to track changes
1285 (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, NULL, NULL);
1286
1287 // clear out any pending notifications
1288 changedKeys = SCDynamicStoreCopyNotifiedKeys(prefsPrivate->session);
1289 if (changedKeys != NULL) {
1290 CFRelease(changedKeys);
1291 }
1292
1293 // remove SCDynamicStore session, release 'prefs' reference
1294 __SCPreferencesRemoveSession(prefs);
1295 }
1296
1297 ok = TRUE;
1298
1299 done :
1300
1301 pthread_mutex_unlock(&prefsPrivate->lock);
1302 return ok;
1303 }
1304
1305
1306 Boolean
1307 SCPreferencesScheduleWithRunLoop(SCPreferencesRef prefs,
1308 CFRunLoopRef runLoop,
1309 CFStringRef runLoopMode)
1310 {
1311 if (!isA_SCPreferences(prefs) || (runLoop == NULL) || (runLoopMode == NULL)) {
1312 _SCErrorSet(kSCStatusInvalidArgument);
1313 return FALSE;
1314 }
1315
1316 return __SCPreferencesScheduleWithRunLoop(prefs, runLoop, runLoopMode, NULL);
1317 }
1318
1319
1320 Boolean
1321 SCPreferencesUnscheduleFromRunLoop(SCPreferencesRef prefs,
1322 CFRunLoopRef runLoop,
1323 CFStringRef runLoopMode)
1324 {
1325 if (!isA_SCPreferences(prefs) || (runLoop == NULL) || (runLoopMode == NULL)) {
1326 _SCErrorSet(kSCStatusInvalidArgument);
1327 return FALSE;
1328 }
1329
1330 return __SCPreferencesUnscheduleFromRunLoop(prefs, runLoop, runLoopMode);
1331 }
1332
1333
1334 Boolean
1335 SCPreferencesSetDispatchQueue(SCPreferencesRef prefs,
1336 dispatch_queue_t queue)
1337 {
1338 Boolean ok = FALSE;
1339
1340 if (!isA_SCPreferences(prefs)) {
1341 /* sorry, you must provide a session */
1342 _SCErrorSet(kSCStatusNoPrefsSession);
1343 return FALSE;
1344 }
1345
1346 if (queue != NULL) {
1347 ok = __SCPreferencesScheduleWithRunLoop(prefs, NULL, NULL, queue);
1348 } else {
1349 ok = __SCPreferencesUnscheduleFromRunLoop(prefs, NULL, NULL);
1350 }
1351
1352 return ok;
1353 }
1354
1355
1356 static void
1357 __SCPreferencesSynchronize_helper(SCPreferencesRef prefs)
1358 {
1359 Boolean ok;
1360 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1361 uint32_t status = kSCStatusOK;
1362
1363 if (prefsPrivate->helper_port == MACH_PORT_NULL) {
1364 // if no helper
1365 return;
1366 }
1367
1368 // have the helper "synchronize" the prefs
1369 ok = _SCHelperExec(prefsPrivate->helper_port,
1370 SCHELPER_MSG_PREFS_SYNCHRONIZE,
1371 NULL,
1372 &status,
1373 NULL);
1374 if (!ok) {
1375 // close helper
1376 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
1377 _SCHelperClose(&prefsPrivate->helper_port);
1378 }
1379 }
1380
1381 return;
1382 }
1383
1384
1385 void
1386 SCPreferencesSynchronize(SCPreferencesRef prefs)
1387 {
1388 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1389
1390 if (!isA_SCPreferences(prefs)) {
1391 /* sorry, you must provide a session */
1392 _SCErrorSet(kSCStatusNoPrefsSession);
1393 return;
1394 }
1395
1396 SC_log(LOG_DEBUG, "SCPreferences() synchronize: %s",
1397 prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path);
1398
1399 if (prefsPrivate->authorizationData != NULL) {
1400 __SCPreferencesSynchronize_helper(prefs);
1401 }
1402 if (prefsPrivate->prefs != NULL) {
1403 CFRelease(prefsPrivate->prefs);
1404 prefsPrivate->prefs = NULL;
1405 }
1406 if (prefsPrivate->signature != NULL) {
1407 CFRelease(prefsPrivate->signature);
1408 prefsPrivate->signature = NULL;
1409 }
1410 prefsPrivate->accessed = FALSE;
1411 prefsPrivate->changed = FALSE;
1412
1413 return;
1414 }