]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/prefs.c
configd-453.19.tar.gz
[apple/configd.git] / scutil.tproj / prefs.c
1 /*
2 * Copyright (c) 2003-2008, 2011 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 * May 29, 2003 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <unistd.h>
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <dlfcn.h>
36
37 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
38 #if !TARGET_OS_IPHONE
39 #include <Security/Authorization.h>
40 #endif /* !TARGET_OS_IPHONE */
41
42 #include "scutil.h"
43 #include "commands.h"
44 #include "prefs.h"
45
46
47 /* -------------------- */
48
49
50 #if !TARGET_OS_IPHONE
51 static void *
52 __loadSecurity(void) {
53 static void *image = NULL;
54 if (NULL == image) {
55 const char *framework = "/System/Library/Frameworks/Security.framework/Security";
56 struct stat statbuf;
57 const char *suffix = getenv("DYLD_IMAGE_SUFFIX");
58 char path[MAXPATHLEN];
59
60 strlcpy(path, framework, sizeof(path));
61 if (suffix) strlcat(path, suffix, sizeof(path));
62 if (0 <= stat(path, &statbuf)) {
63 image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
64 } else {
65 image = dlopen(framework, RTLD_LAZY | RTLD_LOCAL);
66 }
67 }
68 return (void *)image;
69 }
70
71
72 __private_extern__ OSStatus
73 _AuthorizationCreate(const AuthorizationRights *rights, const AuthorizationEnvironment *environment, AuthorizationFlags flags, AuthorizationRef *authorization)
74 {
75 #undef AuthorizationCreate
76 static typeof (AuthorizationCreate) *dyfunc = NULL;
77 if (dyfunc == NULL) {
78 void *image = __loadSecurity();
79 if (image) dyfunc = dlsym(image, "AuthorizationCreate");
80 }
81 return dyfunc ? dyfunc(rights, environment, flags, authorization) : -1;
82 }
83 #define AuthorizationCreate _AuthorizationCreate
84
85
86 __private_extern__ OSStatus
87 _AuthorizationFree(AuthorizationRef authorization, AuthorizationFlags flags)
88 {
89 #undef AuthorizationFree
90 static typeof (AuthorizationFree) *dyfunc = NULL;
91 if (dyfunc == NULL) {
92 void *image = __loadSecurity();
93 if (image) dyfunc = dlsym(image, "AuthorizationFree");
94 }
95 return dyfunc ? dyfunc(authorization, flags) : -1;
96 }
97 #define AuthorizationFree _AuthorizationFree
98
99
100 /* -------------------- */
101
102
103 static AuthorizationRef
104 _createAuthorization()
105 {
106 AuthorizationRef authorization = NULL;
107 AuthorizationFlags flags = kAuthorizationFlagDefaults;
108 OSStatus status;
109
110 status = AuthorizationCreate(NULL,
111 kAuthorizationEmptyEnvironment,
112 flags,
113 &authorization);
114 if (status != errAuthorizationSuccess) {
115 SCPrint(TRUE,
116 stdout,
117 CFSTR("AuthorizationCreate() failed: status = %d\n"),
118 status);
119 return NULL;
120 }
121
122 return authorization;
123 }
124 #endif /* !TARGET_OS_IPHONE */
125
126 /* -------------------- */
127
128
129 __private_extern__ Boolean _prefs_changed = FALSE;
130
131
132 __private_extern__
133 Boolean
134 _prefs_open(CFStringRef name, CFStringRef prefsID)
135 {
136 CFMutableDictionaryRef options = NULL;
137 Boolean useHelper = FALSE;
138 Boolean useOptions = FALSE;
139
140 authorization = NULL;
141
142 if (geteuid() != 0) {
143 // if we need to use a helper
144 useHelper = TRUE;
145
146 #if !TARGET_OS_IPHONE
147 authorization = _createAuthorization();
148 #else
149 authorization = (AuthorizationRef)kSCPreferencesUseEntitlementAuthorization;
150 #endif /* !TARGET_OS_IPHONE */
151 }
152
153 if (getenv("SCPREFERENCES_REMOVE_WHEN_EMPTY") != NULL) {
154 // if we have options
155 useOptions = TRUE;
156
157 if (options == NULL) {
158 options = CFDictionaryCreateMutable(NULL,
159 0,
160 &kCFTypeDictionaryKeyCallBacks,
161 &kCFTypeDictionaryValueCallBacks);
162 }
163 CFDictionarySetValue(options, kSCPreferencesOptionRemoveWhenEmpty, kCFBooleanTrue);
164 }
165
166 if (!useHelper && !useOptions) {
167 // if no helper/options needed
168 prefs = SCPreferencesCreate(NULL, name, prefsID);
169 } else if (!useOptions) {
170 // if no options needed
171 prefs = SCPreferencesCreateWithAuthorization(NULL, name, prefsID, authorization);
172 } else {
173 prefs = SCPreferencesCreateWithOptions(NULL, name, prefsID, authorization, options);
174 CFRelease(options);
175 }
176
177 if (prefs == NULL) {
178 return FALSE;
179 }
180
181 _prefs_changed = FALSE;
182 return TRUE;
183 }
184
185
186 __private_extern__
187 void
188 _prefs_save()
189 {
190 if (!SCPreferencesCommitChanges(prefs)) {
191 switch (SCError()) {
192 case kSCStatusAccessError :
193 SCPrint(TRUE, stderr, CFSTR("Permission denied.\n"));
194 break;
195 default :
196 SCPrint(TRUE,
197 stdout,
198 CFSTR("SCPreferencesCommitChanges() failed: %s\n"),
199 SCErrorString(SCError()));
200 break;
201 }
202 exit (1);
203 }
204
205 _prefs_changed = FALSE;
206
207 if (!SCPreferencesApplyChanges(prefs)) {
208 SCPrint(TRUE,
209 stdout,
210 CFSTR("SCPreferencesApplyChanges() failed: %s\n"),
211 SCErrorString(SCError()));
212 exit (1);
213 }
214
215 return;
216 }
217
218
219 __private_extern__
220 void
221 _prefs_close()
222 {
223 if (prefs != NULL) {
224 CFRelease(prefs);
225 prefs = NULL;
226 _prefs_changed = FALSE;
227 }
228
229 if (authorization != NULL) {
230 #if !TARGET_OS_IPHONE
231 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
232 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
233 #else /* !TARGET_OS_IPHONE */
234 // Uh...if authorization isn't NULL, something went horribly wrong.
235 #endif /* !TARGET_OS_IPHONE */
236 authorization = NULL;
237 }
238
239 return;
240 }
241
242
243 __private_extern__
244 Boolean
245 _prefs_commitRequired(int argc, char **argv, const char *command)
246 {
247 if (_prefs_changed) {
248 if ((currentInput != NULL) &&
249 isatty(fileno(currentInput->fp)) &&
250 ((argc < 1) || (strcmp(argv[0], "!") != 0))
251 ) {
252 SCPrint(TRUE, stdout,
253 CFSTR("preference changes have not been committed\n"
254 "use \"commit\" to save changes"));
255 if (command != NULL) {
256 SCPrint(TRUE, stdout,
257 CFSTR(" or \"%s !\" to abandon changes"),
258 command);
259 }
260 SCPrint(TRUE, stdout, CFSTR("\n"));
261 return TRUE;
262 }
263
264 SCPrint(TRUE, stdout, CFSTR("preference changes abandoned\n"));
265 }
266
267 return FALSE;
268 }
269
270
271 /* -------------------- */
272
273
274 static void
275 get_ComputerName(int argc, char **argv)
276 {
277 CFStringEncoding encoding;
278 CFStringRef hostname;
279
280 hostname = SCDynamicStoreCopyComputerName(NULL, &encoding);
281 if (hostname == NULL) {
282 int sc_status = SCError();
283
284 switch (sc_status) {
285 case kSCStatusNoKey :
286 SCPrint(TRUE,
287 stderr,
288 CFSTR("ComputerName: not set\n"));
289 break;
290 default :
291 SCPrint(TRUE,
292 stderr,
293 CFSTR("SCDynamicStoreCopyComputerName() failed: %s\n"),
294 SCErrorString(SCError()));
295 break;
296 }
297 exit (1);
298 }
299
300 SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname);
301 CFRelease(hostname);
302
303 exit(0);
304 }
305
306
307 static void
308 set_ComputerName(int argc, char **argv)
309 {
310 CFStringRef hostname;
311 Boolean ok;
312
313 ok = _prefs_open(CFSTR("scutil --set ComputerName"), NULL);
314 if (!ok) {
315 SCPrint(TRUE,
316 stdout,
317 CFSTR("Could not open prefs: %s\n"),
318 SCErrorString(SCError()));
319 exit(1);
320 }
321
322 if (argc == 0) {
323 hostname = _copyStringFromSTDIN();
324 } else {
325 hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
326 }
327
328 ok = SCPreferencesSetComputerName(prefs, hostname, kCFStringEncodingUTF8);
329 if (hostname != NULL) CFRelease(hostname);
330 if (!ok) {
331 SCPrint(TRUE,
332 stdout,
333 CFSTR("Could not open prefs: %s\n"),
334 SCErrorString(SCError()));
335 _prefs_close();
336 exit (1);
337 }
338
339 _prefs_save();
340 _prefs_close();
341 exit(0);
342 }
343
344
345 static void
346 get_HostName(int argc, char **argv)
347 {
348 CFStringRef hostname;
349 Boolean ok;
350
351 ok = _prefs_open(CFSTR("scutil --get HostName"), NULL);
352 if (!ok) {
353 SCPrint(TRUE,
354 stdout,
355 CFSTR("SCPreferencesCreate() failed: %s\n"),
356 SCErrorString(SCError()));
357 exit(1);
358 }
359
360 hostname = SCPreferencesGetHostName(prefs);
361 if (hostname == NULL) {
362 int sc_status = SCError();
363
364 switch (sc_status) {
365 case kSCStatusNoKey :
366 SCPrint(TRUE,
367 stderr,
368 CFSTR("HostName: not set\n"));
369 break;
370 default :
371 SCPrint(TRUE,
372 stderr,
373 CFSTR("SCPreferencesGetHostName() failed: %s\n"),
374 SCErrorString(SCError()));
375 break;
376 }
377 _prefs_close();
378 exit (1);
379 }
380
381 SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname);
382 _prefs_close();
383 exit(0);
384 }
385
386
387 static void
388 set_HostName(int argc, char **argv)
389 {
390 CFStringRef hostname = NULL;
391 Boolean ok;
392
393 ok = _prefs_open(CFSTR("scutil --set HostName"), NULL);
394 if (!ok) {
395 SCPrint(TRUE,
396 stdout,
397 CFSTR("Could not open prefs: %s\n"),
398 SCErrorString(SCError()));
399 exit(1);
400 }
401
402 if (argc == 0) {
403 hostname = _copyStringFromSTDIN();
404 } else {
405 hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
406 }
407
408 ok = SCPreferencesSetHostName(prefs, hostname);
409 if (hostname != NULL) CFRelease(hostname);
410 if (!ok) {
411 SCPrint(TRUE,
412 stderr,
413 CFSTR("SCPreferencesSetHostName() failed: %s\n"),
414 SCErrorString(SCError()));
415 _prefs_close();
416 exit (1);
417 }
418
419 _prefs_save();
420 _prefs_close();
421 exit(0);
422 }
423
424
425 static void
426 get_LocalHostName(int argc, char **argv)
427 {
428 CFStringRef hostname;
429
430 hostname = SCDynamicStoreCopyLocalHostName(NULL);
431 if (hostname == NULL) {
432 int sc_status = SCError();
433
434 switch (sc_status) {
435 case kSCStatusNoKey :
436 SCPrint(TRUE,
437 stderr,
438 CFSTR("LocalHostName: not set\n"));
439 break;
440 default :
441 SCPrint(TRUE,
442 stderr,
443 CFSTR("SCDynamicStoreCopyLocalHostName() failed: %s\n"),
444 SCErrorString(SCError()));
445 break;
446 }
447 exit (1);
448 }
449
450 SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname);
451 CFRelease(hostname);
452
453 exit(0);
454 }
455
456
457 static void
458 set_LocalHostName(int argc, char **argv)
459 {
460 CFStringRef hostname = NULL;
461 Boolean ok;
462
463 ok = _prefs_open(CFSTR("scutil --set LocalHostName"), NULL);
464 if (!ok) {
465 SCPrint(TRUE,
466 stdout,
467 CFSTR("Could not open prefs: %s\n"),
468 SCErrorString(SCError()));
469 exit(1);
470 }
471
472 if (argc == 0) {
473 hostname = _copyStringFromSTDIN();
474 } else {
475 hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
476 }
477
478 ok = SCPreferencesSetLocalHostName(prefs, hostname);
479 if (hostname != NULL) CFRelease(hostname);
480 if (!ok) {
481 SCPrint(TRUE,
482 stderr,
483 CFSTR("SCPreferencesSetLocalHostName() failed: %s\n"),
484 SCErrorString(SCError()));
485 _prefs_close();
486 exit (1);
487 }
488
489 _prefs_save();
490 _prefs_close();
491 exit(0);
492 }
493
494
495 /* -------------------- */
496
497
498 typedef void (*pref_func) (int argc, char **argv);
499
500 static const struct {
501 char *pref;
502 pref_func get;
503 pref_func set;
504 } pref_keys[] = {
505 { "ComputerName", get_ComputerName, set_ComputerName },
506 { "HostName", get_HostName, set_HostName },
507 { "LocalHostName", get_LocalHostName, set_LocalHostName }
508 };
509 #define N_PREF_KEYS (sizeof(pref_keys) / sizeof(pref_keys[0]))
510
511
512 __private_extern__
513 int
514 findPref(char *pref)
515 {
516 int i;
517
518 for (i = 0; i < (int)N_PREF_KEYS; i++) {
519 if (strcmp(pref, pref_keys[i].pref) == 0) {
520 return i;
521 }
522 }
523
524 return -1;
525 }
526
527
528 __private_extern__
529 void
530 do_getPref(char *pref, int argc, char **argv)
531 {
532 int i;
533
534 i = findPref(pref);
535 if (i >= 0) {
536 (*pref_keys[i].get)(argc, argv);
537 }
538 return;
539 }
540
541
542 __private_extern__
543 void
544 do_setPref(char *pref, int argc, char **argv)
545 {
546 int i;
547
548 i = findPref(pref);
549 if (i >= 0) {
550 (*pref_keys[i].set)(argc, argv);
551 }
552 return;
553 }
554
555
556 /* -------------------- */
557
558
559 __private_extern__
560 void
561 do_prefs_init()
562 {
563 return;
564 }
565
566
567 __private_extern__
568 void
569 do_prefs_open(int argc, char **argv)
570 {
571 Boolean ok;
572 CFStringRef prefsID = NULL;
573
574 if (prefs != NULL) {
575 if (_prefs_commitRequired(argc, argv, "close")) {
576 return;
577 }
578
579 do_prefs_close(0, NULL);
580 }
581
582 if (argc > 0) {
583 prefsID = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
584 }
585
586 ok = _prefs_open(CFSTR("scutil --prefs"), prefsID);
587 if (prefsID != NULL) CFRelease(prefsID);
588 if (!ok) {
589 SCPrint(TRUE,
590 stdout,
591 CFSTR("Could not open prefs: %s\n"),
592 SCErrorString(SCError()));
593 return;
594 }
595
596 return;
597 }
598
599
600 __private_extern__
601 void
602 do_prefs_lock(int argc, char **argv)
603 {
604 Boolean wait = (argc > 0) ? TRUE : FALSE;
605
606 if (!SCPreferencesLock(prefs, wait)) {
607 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
608 return;
609 }
610
611 return;
612 }
613
614
615 __private_extern__
616 void
617 do_prefs_unlock(int argc, char **argv)
618 {
619 if (!SCPreferencesUnlock(prefs)) {
620 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
621 return;
622 }
623
624 return;
625 }
626
627
628 __private_extern__
629 void
630 do_prefs_commit(int argc, char **argv)
631 {
632 if (!SCPreferencesCommitChanges(prefs)) {
633 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
634 return;
635 }
636
637 _prefs_changed = FALSE;
638 return;
639 }
640
641
642 __private_extern__
643 void
644 do_prefs_apply(int argc, char **argv)
645 {
646 if (!SCPreferencesApplyChanges(prefs)) {
647 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
648 }
649
650 return;
651 }
652
653
654 __private_extern__
655 void
656 do_prefs_close(int argc, char **argv)
657 {
658 if (_prefs_commitRequired(argc, argv, "close")) {
659 return;
660 }
661
662 _prefs_close();
663 return;
664 }
665
666
667 __private_extern__
668 void
669 do_prefs_quit(int argc, char **argv)
670 {
671 if (_prefs_commitRequired(argc, argv, "quit")) {
672 return;
673 }
674
675 _prefs_close();
676
677 termRequested = TRUE;
678 return;
679 }
680
681
682 __private_extern__
683 void
684 do_prefs_synchronize(int argc, char **argv)
685 {
686 SCPreferencesSynchronize(prefs);
687 return;
688 }
689
690
691 static CFComparisonResult
692 sort_paths(const void *p1, const void *p2, void *context) {
693 CFStringRef path1 = (CFStringRef)p1;
694 CFStringRef path2 = (CFStringRef)p2;
695 return CFStringCompare(path1, path2, 0);
696 }
697
698
699 __private_extern__
700 void
701 do_prefs_list(int argc, char **argv)
702 {
703 int i;
704 CFIndex n;
705 CFMutableArrayRef paths = NULL;
706 CFStringRef prefix;
707 CFDictionaryRef entity;
708
709 prefix = CFStringCreateWithCString(NULL,
710 (argc >= 1) ? argv[0] : "/",
711 kCFStringEncodingUTF8);
712
713 entity = SCPreferencesPathGetValue(prefs, prefix);
714 if (entity == NULL) {
715 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
716 goto done;
717 }
718
719 paths = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
720
721 n = isA_CFDictionary(entity) ? CFDictionaryGetCount(entity) : 0;
722 if (n > 0) {
723 CFIndex i;
724 const void ** keys;
725 const void ** vals;
726
727 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
728 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
729 CFDictionaryGetKeysAndValues(entity, keys, vals);
730 for (i = 0; i < n; i++) {
731 if (isA_CFDictionary(vals[i])) {
732 CFArrayAppendValue(paths, keys[i]);
733 }
734 }
735 CFAllocatorDeallocate(NULL, keys);
736 CFAllocatorDeallocate(NULL, vals);
737 }
738
739 n = CFArrayGetCount(paths);
740 CFArraySortValues(paths,
741 CFRangeMake(0, n),
742 sort_paths,
743 NULL);
744
745 if (n > 0) {
746 for (i = 0; i < n; i++) {
747 SCPrint(TRUE,
748 stdout,
749 CFSTR(" path [%d] = %@/%@\n"),
750 i,
751 CFEqual(prefix, CFSTR("/")) ? CFSTR("") : prefix,
752 CFArrayGetValueAtIndex(paths, i));
753 }
754 } else {
755 SCPrint(TRUE, stdout, CFSTR(" no paths.\n"));
756 }
757
758 CFRelease(paths);
759
760 done :
761
762 CFRelease(prefix);
763 return;
764 }
765
766
767 __private_extern__
768 void
769 do_prefs_get(int argc, char **argv)
770 {
771 CFDictionaryRef dict;
772 CFStringRef link;
773 CFIndex n;
774 CFMutableDictionaryRef newDict;
775 CFStringRef path;
776
777 path = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
778
779 link = SCPreferencesPathGetLink(prefs, path);
780 if (link != NULL) {
781 SCPrint(TRUE, stdout, CFSTR(" --> %@\n"), link);
782 }
783
784 dict = SCPreferencesPathGetValue(prefs, path);
785 CFRelease(path);
786 if (dict == NULL) {
787 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
788 return;
789 }
790
791 newDict = CFDictionaryCreateMutable(NULL,
792 0,
793 &kCFTypeDictionaryKeyCallBacks,
794 &kCFTypeDictionaryValueCallBacks);
795
796 // remove [path] children
797 n = isA_CFDictionary(dict) ? CFDictionaryGetCount(dict) : 0;
798 if (n > 0) {
799 CFIndex i;
800 const void ** keys;
801 const void ** vals;
802
803 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
804 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
805 CFDictionaryGetKeysAndValues(dict, keys, vals);
806 for (i = 0; i < n; i++) {
807 if (!isA_CFDictionary(vals[i])) {
808 CFDictionaryAddValue(newDict, keys[i], vals[i]);
809 }
810 }
811 CFAllocatorDeallocate(NULL, keys);
812 CFAllocatorDeallocate(NULL, vals);
813 }
814
815 if (value != NULL) {
816 CFRelease(value); /* we have new information, release the old */
817 }
818
819 value = newDict;
820
821 return;
822 }
823
824
825 __private_extern__
826 void
827 do_prefs_set(int argc, char **argv)
828 {
829 CFDictionaryRef dict;
830 CFMutableDictionaryRef newDict = NULL;
831 CFStringRef path;
832
833 path = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
834 newDict = CFDictionaryCreateMutableCopy(NULL, 0, value);
835
836 dict = SCPreferencesPathGetValue(prefs, path);
837 if (dict != NULL) {
838 CFIndex n;
839
840 // retain [path] children
841 n = CFDictionaryGetCount(dict);
842 if (n > 0) {
843 CFIndex i;
844 const void ** keys;
845 const void ** vals;
846
847 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
848 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
849 CFDictionaryGetKeysAndValues(dict, keys, vals);
850 for (i = 0; i < n; i++) {
851 if (isA_CFDictionary(vals[i])) {
852 if (CFDictionaryContainsKey(newDict, keys[i])) {
853 SCPrint(TRUE, stdout, CFSTR(" key %@ is already a path component and cannot be replaced\n"), keys[i]);
854 goto done;
855 }
856 CFDictionaryAddValue(newDict, keys[i], vals[i]);
857 }
858 }
859 CFAllocatorDeallocate(NULL, keys);
860 CFAllocatorDeallocate(NULL, vals);
861 }
862 } else if (SCError() == kSCStatusInvalidArgument) {
863 SCPrint(TRUE, stdout, CFSTR(" a path component is not a dictionary\n"));
864 goto done;
865 } else if (SCError() != kSCStatusNoKey) {
866 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
867 goto done;
868 }
869
870 if (argc > 1) {
871 CFStringRef link;
872 Boolean ok;
873
874 // set link
875 link = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8);
876 ok = SCPreferencesPathSetLink(prefs, path, link);
877 CFRelease(link);
878 if (!ok) {
879 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
880 goto done;
881 }
882 } else {
883 // set value
884 if (!SCPreferencesPathSetValue(prefs, path, newDict)) {
885 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
886 goto done;
887 }
888 }
889
890 _prefs_changed = TRUE;
891
892 done :
893
894 CFRelease(newDict);
895 CFRelease(path);
896 return;
897 }
898
899
900 __private_extern__
901 void
902 do_prefs_remove(int argc, char **argv)
903 {
904 CFStringRef path;
905
906 path = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
907
908 if (!SCPreferencesPathRemoveValue(prefs, path)) {
909 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
910 goto done;
911 }
912
913 _prefs_changed = TRUE;
914
915 done :
916
917 CFRelease(path);
918 return;
919 }