]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPOpen.c
configd-1061.141.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 = FALSE;
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 *opt_none = "";
716 const char *opt_1 = opt_none;
717 const char *opt_2 = opt_none;
718
719 if (options != NULL) {
720 opt_2 = "options";
721 }
722
723 if (authorization != NULL) {
724 if (authorization == kSCPreferencesUseEntitlementAuthorization) {
725 opt_1 = "entitlement";
726 } else {
727 opt_1 = "authorization";
728 }
729 }
730
731 SC_log(LOG_DEBUG, "create w/%s%s%s %@",
732 opt_2,
733 ((opt_2 != opt_none) && (opt_1 != opt_none)) ? " + " : "",
734 opt_1,
735 prefsPrivate);
736 }
737
738 if (authorizationData != NULL) CFRelease(authorizationData);
739
740 return (SCPreferencesRef)prefsPrivate;
741 }
742
743
744 SCPreferencesRef
745 SCPreferencesCreateCompanion(SCPreferencesRef prefs, CFStringRef companionPrefsID)
746 {
747 CFAllocatorRef allocator = CFGetAllocator(prefs);
748 SCPreferencesPrivateRef companionPrefs = NULL;
749 CFMutableStringRef newPrefsID;
750 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
751
752 if (companionPrefsID == NULL) {
753 companionPrefsID = PREFS_DEFAULT_CONFIG;
754 } else {
755 if (CFStringFindWithOptions(companionPrefsID,
756 CFSTR("/"),
757 CFRangeMake(0, CFStringGetLength(companionPrefsID)),
758 kCFCompareBackwards,
759 NULL)) {
760 // if companion prefsID contains a "/"
761 _SCErrorSet(kSCStatusInvalidArgument);
762 return NULL;
763 }
764 }
765
766 if (prefsPrivate->prefsID == NULL) {
767 if (CFEqual(companionPrefsID, PREFS_DEFAULT_CONFIG)) {
768 // if prefsID and companionPrefsID match
769 _SCErrorSet(kSCStatusInvalidArgument);
770 return NULL;
771 }
772 newPrefsID = CFStringCreateMutableCopy(allocator, 0, companionPrefsID);
773 } else {
774 CFIndex prefsIDLen = CFStringGetLength(prefsPrivate->prefsID);
775 CFRange range;
776
777 if (CFStringFindWithOptions(prefsPrivate->prefsID,
778 CFSTR("/"),
779 CFRangeMake(0, prefsIDLen),
780 kCFCompareBackwards,
781 &range)) {
782 Boolean match;
783 CFStringRef suffix;
784
785 // if slash, check suffix
786 range.location++;
787 if (range.location >= prefsIDLen) {
788 // if no suffix
789 _SCErrorSet(kSCStatusInvalidArgument);
790 return NULL;
791 }
792 range.length = prefsIDLen - range.location;
793 suffix = CFStringCreateWithSubstring(allocator, prefsPrivate->prefsID, range);
794 match = CFEqual(suffix, companionPrefsID);
795 CFRelease(suffix);
796 if (match) {
797 // if prefsID [suffix] and companionPrefsID match
798 _SCErrorSet(kSCStatusInvalidArgument);
799 return NULL;
800 }
801
802 // replace the suffix
803 newPrefsID = CFStringCreateMutableCopy(NULL, 0, prefsPrivate->prefsID);
804 CFStringReplace(newPrefsID, range, companionPrefsID);
805 } else if (!CFEqual(prefsPrivate->prefsID, companionPrefsID)) {
806 // if no slash, prefsID and companionPrefsID differ
807 newPrefsID = CFStringCreateMutableCopy(NULL, 0, companionPrefsID);
808 } else {
809 // if no slash, prefsID and companionPrefsID match
810 _SCErrorSet(kSCStatusInvalidArgument);
811 return NULL;
812 }
813 }
814 assert(newPrefsID != NULL);
815
816 pthread_mutex_lock(&prefsPrivate->lock);
817 if ((prefsPrivate->companions != NULL) &&
818 CFDictionaryGetValueIfPresent(prefsPrivate->companions,
819 newPrefsID,
820 (const void **)&companionPrefs) &&
821 (companionPrefs != NULL)) {
822 // if we already have a companion
823 SC_log(LOG_DEBUG, "create [companion] reference %@", companionPrefs);
824 CFRetain(companionPrefs);
825 } else {
826 companionPrefs = __SCPreferencesCreate(allocator,
827 prefsPrivate->name,
828 newPrefsID,
829 prefsPrivate->authorizationData,
830 prefsPrivate->options);
831 if (companionPrefs != NULL) {
832 SCPreferencesPrivateRef companionPrefsPrivate = (SCPreferencesPrivateRef)companionPrefs;
833
834 SC_log(LOG_DEBUG, "create [companion] %@", companionPrefs);
835
836 // add [strong] reference from companion to parent
837 companionPrefsPrivate->parent = CFRetain(prefs);
838
839 // add [weak] reference from parent to this companion
840 if (prefsPrivate->companions == NULL) {
841 prefsPrivate->companions = CFDictionaryCreateMutable(NULL,
842 0,
843 &kCFTypeDictionaryKeyCallBacks,
844 NULL);
845 }
846 CFDictionarySetValue(prefsPrivate->companions, newPrefsID, companionPrefs);
847 }
848 }
849 pthread_mutex_unlock(&prefsPrivate->lock);
850
851 CFRelease(newPrefsID);
852
853 return (SCPreferencesRef)companionPrefs;
854 }
855
856
857 CFTypeID
858 SCPreferencesGetTypeID(void) {
859 pthread_once(&initialized, __SCPreferencesInitialize); /* initialize runtime */
860 return __kSCPreferencesTypeID;
861 }
862
863
864 static void
865 prefsNotify(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
866 {
867 #pragma unused(store)
868 void *context_info;
869 void (*context_release)(const void *);
870 CFIndex i;
871 CFIndex n;
872 SCPreferencesNotification notify = 0;
873 SCPreferencesRef prefs = (SCPreferencesRef)info;
874 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
875 SCPreferencesCallBack rlsFunction;
876
877 n = (changedKeys != NULL) ? CFArrayGetCount(changedKeys) : 0;
878 for (i = 0; i < n; i++) {
879 CFStringRef key;
880
881 key = CFArrayGetValueAtIndex(changedKeys, i);
882
883 // check if "commit"
884 if (CFEqual(key, prefsPrivate->sessionKeyCommit)) {
885 // if preferences have been saved
886 notify |= kSCPreferencesNotificationCommit;
887 continue;
888 }
889
890 // check if "apply"
891 if (CFEqual(key, prefsPrivate->sessionKeyApply)) {
892 // if stored preferences should be applied to current configuration
893 notify |= kSCPreferencesNotificationApply;
894 continue;
895 }
896 }
897
898 if (notify == 0) {
899 // if no changes
900 return;
901 }
902
903 pthread_mutex_lock(&prefsPrivate->lock);
904
905 /* callout */
906 rlsFunction = prefsPrivate->rlsFunction;
907 if (prefsPrivate->rlsContext.retain != NULL) {
908 context_info = (void *)prefsPrivate->rlsContext.retain(prefsPrivate->rlsContext.info);
909 context_release = prefsPrivate->rlsContext.release;
910 } else {
911 context_info = prefsPrivate->rlsContext.info;
912 context_release = NULL;
913 }
914
915 pthread_mutex_unlock(&prefsPrivate->lock);
916
917 if (rlsFunction != NULL) {
918 SC_log(LOG_DEBUG, "exec SCPreferences callout: %s%s%s",
919 ((notify & kSCPreferencesNotificationCommit) != 0) ? "commit" : "",
920 (((notify & kSCPreferencesNotificationCommit) != 0) &&
921 ((notify & kSCPreferencesNotificationApply ) != 0)) ? ", " : "",
922 ((notify & kSCPreferencesNotificationApply) != 0) ? "apply" : "");
923 (*rlsFunction)(prefs, notify, context_info);
924 }
925
926 if (context_release != NULL) {
927 (*context_release)(context_info);
928 }
929
930 return;
931 }
932
933
934 __private_extern__ void
935 __SCPreferencesAddSessionKeys(SCPreferencesRef prefs)
936 {
937 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
938
939 /* create the session "commit" key */
940 if (prefsPrivate->sessionKeyCommit == NULL) {
941 prefsPrivate->sessionKeyCommit = _SCPNotificationKey(NULL,
942 prefsPrivate->prefsID,
943 kSCPreferencesKeyCommit);
944 }
945
946 /* create the session "apply" key */
947 if (prefsPrivate->sessionKeyApply == NULL) {
948 prefsPrivate->sessionKeyApply = _SCPNotificationKey(NULL,
949 prefsPrivate->prefsID,
950 kSCPreferencesKeyApply);
951 }
952
953 return;
954 }
955
956
957 __private_extern__ Boolean
958 __SCPreferencesAddSession(SCPreferencesRef prefs)
959 {
960 CFAllocatorRef allocator = CFGetAllocator(prefs);
961 SCDynamicStoreContext context = { 0
962 , (void *)prefs
963 , CFRetain
964 , CFRelease
965 , CFCopyDescription
966 };
967 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
968
969 if (prefsPrivate->sessionRefcnt == 0) {
970 /* establish a dynamic store session */
971 prefsPrivate->session = SCDynamicStoreCreate(allocator,
972 prefsPrivate->name,
973 prefsNotify,
974 &context);
975 if (prefsPrivate->session == NULL) {
976 SC_log(LOG_INFO, "SCDynamicStoreCreate() failed");
977 return FALSE;
978 }
979
980 SC_log(LOG_DEBUG, "added SCDynamicStore session (for prefs)");
981 }
982
983 prefsPrivate->sessionRefcnt++;
984 return TRUE;
985 }
986
987
988 __private_extern__ void
989 __SCPreferencesRemoveSession(SCPreferencesRef prefs)
990 {
991 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
992
993 if (prefsPrivate->sessionRefcnt > 0) {
994 if (--prefsPrivate->sessionRefcnt == 0) {
995 CFRelease(prefsPrivate->session);
996 prefsPrivate->session = NULL;
997
998 SC_log(LOG_DEBUG, "removed SCDynamicStore session (for prefs)");
999 }
1000 }
1001
1002 return;
1003 }
1004
1005
1006 static void
1007 appendLockedPreferences(const void *key, const void *value, void *context)
1008 {
1009 #pragma unused(key)
1010 CFMutableStringRef str = (CFMutableStringRef)context;
1011
1012 CFStringAppendFormat(str, NULL, CFSTR("%s%@"),
1013 (CFStringGetLength(str) > 0) ? "\n" : "",
1014 value);
1015 return;
1016 }
1017
1018
1019 __private_extern__ void
1020 __SCPreferencesUpdateLockedState(SCPreferencesRef prefs, Boolean locked)
1021 {
1022 static dispatch_queue_t lockedQueue;
1023 static CFMutableDictionaryRef lockedState;
1024 static dispatch_once_t once;
1025 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1026
1027 dispatch_once(&once, ^{
1028 os_state_block_t state_block;
1029
1030 lockedQueue = dispatch_queue_create("SCPreferences locked state queue", NULL);
1031
1032 lockedState = CFDictionaryCreateMutable(NULL,
1033 0,
1034 NULL, // NO retain/release
1035 &kCFTypeDictionaryValueCallBacks);
1036
1037 state_block = ^os_state_data_t(os_state_hints_t hints) {
1038 #pragma unused(hints)
1039 CFDataRef data = NULL;
1040 Boolean ok;
1041 os_state_data_t state_data;
1042 size_t state_data_size;
1043 CFIndex state_len;
1044 CFMutableStringRef str;
1045
1046 if (CFDictionaryGetCount(lockedState) == 0) {
1047 // if no locked preferences
1048 return NULL;
1049 }
1050
1051 str = CFStringCreateMutable(NULL, 0);
1052 CFDictionaryApplyFunction(lockedState, appendLockedPreferences, str);
1053 ok = _SCSerialize(str, &data, NULL, NULL);
1054 CFRelease(str);
1055
1056 state_len = (ok && (data != NULL)) ? CFDataGetLength(data) : 0;
1057 state_data_size = OS_STATE_DATA_SIZE_NEEDED(state_len);
1058 if (state_data_size > MAX_STATEDUMP_SIZE) {
1059 SC_log(LOG_ERR, "locked SCPreferences : state data too large (%zd > %zd)",
1060 state_data_size,
1061 (size_t)MAX_STATEDUMP_SIZE);
1062 if (data != NULL) CFRelease(data);
1063 return NULL;
1064 }
1065
1066 state_data = calloc(1, state_data_size);
1067 if (state_data == NULL) {
1068 SC_log(LOG_ERR, "locked SCPreferences: could not allocate state data");
1069 if (data != NULL) CFRelease(data);
1070 return NULL;
1071 }
1072
1073 state_data->osd_type = OS_STATE_DATA_SERIALIZED_NSCF_OBJECT;
1074 state_data->osd_data_size = (uint32_t)state_len;
1075 strlcpy(state_data->osd_title, "open/locked SCPreferences", sizeof(state_data->osd_title));
1076 if (state_len > 0) {
1077 memcpy(state_data->osd_data, CFDataGetBytePtr(data), state_len);
1078 }
1079 if (data != NULL) CFRelease(data);
1080
1081 return state_data;
1082 };
1083
1084 (void) os_state_add_handler(lockedQueue, state_block);
1085 });
1086
1087 // update the locked state
1088 prefsPrivate->locked = locked;
1089
1090 // add (or update) the locked preferences
1091 dispatch_sync(lockedQueue, ^{
1092 if (locked) {
1093 CFStringRef str;
1094
1095 str = CFCopyDescription(prefs);
1096 CFDictionarySetValue(lockedState, prefs, str);
1097 CFRelease(str);
1098 } else {
1099 CFDictionaryRemoveValue(lockedState, prefs);
1100 }
1101 });
1102
1103 return;
1104 }
1105
1106
1107 Boolean
1108 SCPreferencesSetCallback(SCPreferencesRef prefs,
1109 SCPreferencesCallBack callout,
1110 SCPreferencesContext *context)
1111 {
1112 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1113
1114 if (!isA_SCPreferences(prefs)) {
1115 /* sorry, you must provide a session */
1116 _SCErrorSet(kSCStatusNoPrefsSession);
1117 return FALSE;
1118 }
1119
1120 pthread_mutex_lock(&prefsPrivate->lock);
1121
1122 if (prefsPrivate->rlsContext.release != NULL) {
1123 /* let go of the current context */
1124 (*prefsPrivate->rlsContext.release)(prefsPrivate->rlsContext.info);
1125 }
1126
1127 prefsPrivate->rlsFunction = callout;
1128 prefsPrivate->rlsContext.info = NULL;
1129 prefsPrivate->rlsContext.retain = NULL;
1130 prefsPrivate->rlsContext.release = NULL;
1131 prefsPrivate->rlsContext.copyDescription = NULL;
1132 if (context != NULL) {
1133 memcpy(&prefsPrivate->rlsContext, context, sizeof(SCPreferencesContext));
1134 if (context->retain != NULL) {
1135 prefsPrivate->rlsContext.info = (void *)(*context->retain)(context->info);
1136 }
1137 }
1138
1139 pthread_mutex_unlock(&prefsPrivate->lock);
1140
1141 return TRUE;
1142 }
1143
1144
1145 static Boolean
1146 __SCPreferencesScheduleWithRunLoop(SCPreferencesRef prefs,
1147 CFRunLoopRef runLoop,
1148 CFStringRef runLoopMode,
1149 dispatch_queue_t queue)
1150 {
1151 Boolean ok = FALSE;
1152 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1153
1154 pthread_mutex_lock(&prefsPrivate->lock);
1155
1156 if ((prefsPrivate->dispatchQueue != NULL) || // if we are already scheduled on a dispatch queue
1157 ((queue != NULL) && prefsPrivate->scheduled)) { // if we are already scheduled on a CFRunLoop
1158 _SCErrorSet(kSCStatusInvalidArgument);
1159 goto done;
1160 }
1161
1162 if (!prefsPrivate->scheduled) {
1163 CFMutableArrayRef keys;
1164
1165 // add SCDynamicStore session (for notifications) ... and hold a 'prefs' reference
1166 if (prefsPrivate->session == NULL) {
1167 ok = __SCPreferencesAddSession(prefs);
1168 if (!ok) {
1169 goto done;
1170 }
1171 assert(prefsPrivate->session != NULL);
1172 }
1173
1174 // add SCDynamicStore "keys"
1175 __SCPreferencesAddSessionKeys(prefs);
1176
1177 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1178 CFArrayAppendValue(keys, prefsPrivate->sessionKeyCommit);
1179 CFArrayAppendValue(keys, prefsPrivate->sessionKeyApply);
1180 (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, keys, NULL);
1181 CFRelease(keys);
1182
1183 if (runLoop != NULL) {
1184 prefsPrivate->rls = SCDynamicStoreCreateRunLoopSource(NULL, prefsPrivate->session, 0);
1185 prefsPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1186 }
1187
1188 SC_log(LOG_DEBUG, "scheduled");
1189
1190 prefsPrivate->scheduled = TRUE;
1191 }
1192
1193 if (queue != NULL) {
1194 ok = SCDynamicStoreSetDispatchQueue(prefsPrivate->session, queue);
1195 if (!ok) {
1196 prefsPrivate->scheduled = FALSE;
1197 (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, NULL, NULL);
1198 __SCPreferencesRemoveSession(prefs);
1199 goto done;
1200 }
1201
1202 prefsPrivate->dispatchQueue = queue;
1203 dispatch_retain(prefsPrivate->dispatchQueue);
1204 } else {
1205 if (!_SC_isScheduled(NULL, runLoop, runLoopMode, prefsPrivate->rlList)) {
1206 /*
1207 * if we do not already have notifications scheduled with
1208 * this runLoop / runLoopMode
1209 */
1210 CFRunLoopAddSource(runLoop, prefsPrivate->rls, runLoopMode);
1211 }
1212
1213 _SC_schedule(prefs, runLoop, runLoopMode, prefsPrivate->rlList);
1214 }
1215
1216 ok = TRUE;
1217
1218 done :
1219
1220 pthread_mutex_unlock(&prefsPrivate->lock);
1221 return ok;
1222 }
1223
1224
1225 static Boolean
1226 __SCPreferencesUnscheduleFromRunLoop(SCPreferencesRef prefs,
1227 CFRunLoopRef runLoop,
1228 CFStringRef runLoopMode)
1229 {
1230 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1231 CFIndex n = 0;
1232 Boolean ok = FALSE;
1233
1234 pthread_mutex_lock(&prefsPrivate->lock);
1235
1236 if ((runLoop != NULL) && !prefsPrivate->scheduled) { // if we should be scheduled (but are not)
1237 _SCErrorSet(kSCStatusInvalidArgument);
1238 goto done;
1239 }
1240
1241 if (((runLoop == NULL) && (prefsPrivate->dispatchQueue == NULL)) || // if we should be scheduled on a dispatch queue (but are not)
1242 ((runLoop != NULL) && (prefsPrivate->dispatchQueue != NULL))) { // if we should be scheduled on a CFRunLoop (but are scheduled on a dispatch queue)
1243 _SCErrorSet(kSCStatusInvalidArgument);
1244 goto done;
1245 }
1246
1247 if (runLoop == NULL) {
1248 SCDynamicStoreSetDispatchQueue(prefsPrivate->session, NULL);
1249 dispatch_release(prefsPrivate->dispatchQueue);
1250 prefsPrivate->dispatchQueue = NULL;
1251 } else {
1252 if (!_SC_unschedule(prefs, runLoop, runLoopMode, prefsPrivate->rlList, FALSE)) {
1253 // if not currently scheduled on this runLoop / runLoopMode
1254 _SCErrorSet(kSCStatusInvalidArgument);
1255 goto done;
1256 }
1257
1258 n = CFArrayGetCount(prefsPrivate->rlList);
1259 if (n == 0 || !_SC_isScheduled(NULL, runLoop, runLoopMode, prefsPrivate->rlList)) {
1260 /*
1261 * if we are no longer scheduled to receive notifications for
1262 * this runLoop / runLoopMode
1263 */
1264 CFRunLoopRemoveSource(runLoop, prefsPrivate->rls, runLoopMode);
1265
1266 if (n == 0) {
1267 // if *all* notifications have been unscheduled
1268 CFRelease(prefsPrivate->rlList);
1269 prefsPrivate->rlList = NULL;
1270 CFRunLoopSourceInvalidate(prefsPrivate->rls);
1271 CFRelease(prefsPrivate->rls);
1272 prefsPrivate->rls = NULL;
1273 }
1274 }
1275 }
1276
1277 if (n == 0) {
1278 CFArrayRef changedKeys;
1279
1280 SC_log(LOG_DEBUG, "unscheduled");
1281
1282 // if *all* notifications have been unscheduled
1283 prefsPrivate->scheduled = FALSE;
1284
1285 // no need to track changes
1286 (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, NULL, NULL);
1287
1288 // clear out any pending notifications
1289 changedKeys = SCDynamicStoreCopyNotifiedKeys(prefsPrivate->session);
1290 if (changedKeys != NULL) {
1291 CFRelease(changedKeys);
1292 }
1293
1294 // remove SCDynamicStore session, release 'prefs' reference
1295 __SCPreferencesRemoveSession(prefs);
1296 }
1297
1298 ok = TRUE;
1299
1300 done :
1301
1302 pthread_mutex_unlock(&prefsPrivate->lock);
1303 return ok;
1304 }
1305
1306
1307 Boolean
1308 SCPreferencesScheduleWithRunLoop(SCPreferencesRef prefs,
1309 CFRunLoopRef runLoop,
1310 CFStringRef runLoopMode)
1311 {
1312 if (!isA_SCPreferences(prefs) || (runLoop == NULL) || (runLoopMode == NULL)) {
1313 _SCErrorSet(kSCStatusInvalidArgument);
1314 return FALSE;
1315 }
1316
1317 return __SCPreferencesScheduleWithRunLoop(prefs, runLoop, runLoopMode, NULL);
1318 }
1319
1320
1321 Boolean
1322 SCPreferencesUnscheduleFromRunLoop(SCPreferencesRef prefs,
1323 CFRunLoopRef runLoop,
1324 CFStringRef runLoopMode)
1325 {
1326 if (!isA_SCPreferences(prefs) || (runLoop == NULL) || (runLoopMode == NULL)) {
1327 _SCErrorSet(kSCStatusInvalidArgument);
1328 return FALSE;
1329 }
1330
1331 return __SCPreferencesUnscheduleFromRunLoop(prefs, runLoop, runLoopMode);
1332 }
1333
1334
1335 Boolean
1336 SCPreferencesSetDispatchQueue(SCPreferencesRef prefs,
1337 dispatch_queue_t queue)
1338 {
1339 Boolean ok = FALSE;
1340
1341 if (!isA_SCPreferences(prefs)) {
1342 /* sorry, you must provide a session */
1343 _SCErrorSet(kSCStatusNoPrefsSession);
1344 return FALSE;
1345 }
1346
1347 if (queue != NULL) {
1348 ok = __SCPreferencesScheduleWithRunLoop(prefs, NULL, NULL, queue);
1349 } else {
1350 ok = __SCPreferencesUnscheduleFromRunLoop(prefs, NULL, NULL);
1351 }
1352
1353 return ok;
1354 }
1355
1356
1357 static void
1358 __SCPreferencesSynchronize_helper(SCPreferencesRef prefs)
1359 {
1360 Boolean ok;
1361 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1362 uint32_t status = kSCStatusOK;
1363
1364 if (prefsPrivate->helper_port == MACH_PORT_NULL) {
1365 // if no helper
1366 return;
1367 }
1368
1369 // have the helper "synchronize" the prefs
1370 ok = _SCHelperExec(prefsPrivate->helper_port,
1371 SCHELPER_MSG_PREFS_SYNCHRONIZE,
1372 NULL,
1373 &status,
1374 NULL);
1375 if (!ok) {
1376 // close helper
1377 if (prefsPrivate->helper_port != MACH_PORT_NULL) {
1378 _SCHelperClose(&prefsPrivate->helper_port);
1379 }
1380 }
1381
1382 return;
1383 }
1384
1385
1386 void
1387 SCPreferencesSynchronize(SCPreferencesRef prefs)
1388 {
1389 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
1390
1391 if (!isA_SCPreferences(prefs)) {
1392 /* sorry, you must provide a session */
1393 _SCErrorSet(kSCStatusNoPrefsSession);
1394 return;
1395 }
1396
1397 SC_log(LOG_DEBUG, "SCPreferences() synchronize: %s",
1398 prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path);
1399
1400 if (prefsPrivate->authorizationData != NULL) {
1401 __SCPreferencesSynchronize_helper(prefs);
1402 }
1403 if (prefsPrivate->prefs != NULL) {
1404 CFRelease(prefsPrivate->prefs);
1405 prefsPrivate->prefs = NULL;
1406 }
1407 if (prefsPrivate->signature != NULL) {
1408 CFRelease(prefsPrivate->signature);
1409 prefsPrivate->signature = NULL;
1410 }
1411 prefsPrivate->accessed = FALSE;
1412 prefsPrivate->changed = FALSE;
1413
1414 return;
1415 }