]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/prefs.c
605cd2a07828183d06fbdb8adfa795174a706495
[apple/configd.git] / scutil.tproj / prefs.c
1 /*
2 * Copyright (c) 2003-2008, 2011-2016 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 <dlfcn.h>
32 #include <unistd.h>
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36
37 #include "scutil.h"
38 #include "commands.h"
39 #include "prefs.h"
40
41 #include "SCNetworkConfigurationInternal.h"
42
43 #if !TARGET_OS_IPHONE
44 #include <Security/Authorization.h>
45 #endif /* !TARGET_OS_IPHONE */
46
47
48 /* -------------------- */
49
50
51 #if !TARGET_OS_IPHONE
52 static void *
53 __loadSecurity(void) {
54 static void *image = NULL;
55 static dispatch_once_t once;
56
57 dispatch_once(&once, ^{
58 image = _SC_dlopen("/System/Library/Frameworks/Security.framework/Security");
59 });
60
61 return image;
62 }
63
64
65 static OSStatus
66 _AuthorizationCreate(const AuthorizationRights *rights, const AuthorizationEnvironment *environment, AuthorizationFlags flags, AuthorizationRef *authorization)
67 {
68 #undef AuthorizationCreate
69 static typeof (AuthorizationCreate) *dyfunc = NULL;
70 if (dyfunc == NULL) {
71 void *image = __loadSecurity();
72 if (image) dyfunc = dlsym(image, "AuthorizationCreate");
73 }
74 return dyfunc ? dyfunc(rights, environment, flags, authorization) : -1;
75 }
76 #define AuthorizationCreate _AuthorizationCreate
77
78
79 static OSStatus
80 _AuthorizationFree(AuthorizationRef authorization, AuthorizationFlags flags)
81 {
82 #undef AuthorizationFree
83 static typeof (AuthorizationFree) *dyfunc = NULL;
84 if (dyfunc == NULL) {
85 void *image = __loadSecurity();
86 if (image) dyfunc = dlsym(image, "AuthorizationFree");
87 }
88 return dyfunc ? dyfunc(authorization, flags) : -1;
89 }
90 #define AuthorizationFree _AuthorizationFree
91
92
93 /* -------------------- */
94
95 __private_extern__
96 AuthorizationRef
97 _prefs_AuthorizationCreate()
98 {
99 AuthorizationRef authorization = NULL;
100
101 if (getenv("SCPREFERENCES_USE_ENTITLEMENTS") != NULL) {
102 authorization = kSCPreferencesUseEntitlementAuthorization;
103 } else {
104 AuthorizationFlags flags = kAuthorizationFlagDefaults;
105 OSStatus status;
106
107 status = AuthorizationCreate(NULL,
108 kAuthorizationEmptyEnvironment,
109 flags,
110 &authorization);
111 if (status != errAuthorizationSuccess) {
112 SCPrint(TRUE,
113 stdout,
114 CFSTR("AuthorizationCreate() failed: status = %d\n"),
115 (int)status);
116 return NULL;
117 }
118 }
119
120 return authorization;
121 }
122
123
124 __private_extern__
125 void
126 _prefs_AuthorizationFree(AuthorizationRef authorization)
127 {
128 if (authorization != kSCPreferencesUseEntitlementAuthorization) {
129 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
130 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
131 }
132
133 return;
134 }
135
136 #endif /* !TARGET_OS_IPHONE */
137
138 /* -------------------- */
139
140
141 __private_extern__ Boolean _prefs_changed = FALSE;
142
143
144 __private_extern__
145 Boolean
146 _prefs_open(CFStringRef name, CFStringRef prefsID)
147 {
148 CFMutableDictionaryRef options = NULL;
149 Boolean useHelper = FALSE;
150 Boolean useOptions = FALSE;
151
152 authorization = NULL;
153
154 if (geteuid() != 0) {
155 // if we need to use a helper
156 useHelper = TRUE;
157
158 #if !TARGET_OS_IPHONE
159 authorization = _prefs_AuthorizationCreate();
160 #else
161 authorization = kSCPreferencesUseEntitlementAuthorization;
162 #endif /* !TARGET_OS_IPHONE */
163 }
164
165 if (getenv("SCPREFERENCES_REMOVE_WHEN_EMPTY") != NULL) {
166 // if we have options
167 useOptions = TRUE;
168
169 if (options == NULL) {
170 options = CFDictionaryCreateMutable(NULL,
171 0,
172 &kCFTypeDictionaryKeyCallBacks,
173 &kCFTypeDictionaryValueCallBacks);
174 }
175 CFDictionarySetValue(options, kSCPreferencesOptionRemoveWhenEmpty, kCFBooleanTrue);
176 }
177
178 if (!useHelper && !useOptions) {
179 // if no helper/options needed
180 prefs = SCPreferencesCreate(NULL, name, prefsID);
181 } else if (!useOptions) {
182 // if no options needed
183 prefs = SCPreferencesCreateWithAuthorization(NULL, name, prefsID, authorization);
184 } else {
185 prefs = SCPreferencesCreateWithOptions(NULL, name, prefsID, authorization, options);
186 CFRelease(options);
187 }
188
189 if (prefs == NULL) {
190 return FALSE;
191 }
192
193 _prefs_changed = FALSE;
194 return TRUE;
195 }
196
197
198 __private_extern__
199 void
200 _prefs_save()
201 {
202 if (!SCPreferencesCommitChanges(prefs)) {
203 switch (SCError()) {
204 case kSCStatusAccessError :
205 SCPrint(TRUE, stderr, CFSTR("Permission denied.\n"));
206 break;
207 default :
208 SCPrint(TRUE,
209 stdout,
210 CFSTR("SCPreferencesCommitChanges() failed: %s\n"),
211 SCErrorString(SCError()));
212 break;
213 }
214 exit (1);
215 }
216
217 _prefs_changed = FALSE;
218
219 if (!SCPreferencesApplyChanges(prefs)) {
220 SCPrint(TRUE,
221 stdout,
222 CFSTR("SCPreferencesApplyChanges() failed: %s\n"),
223 SCErrorString(SCError()));
224 exit (1);
225 }
226
227 return;
228 }
229
230
231 __private_extern__
232 void
233 _prefs_close()
234 {
235 if (prefs != NULL) {
236 CFRelease(prefs);
237 prefs = NULL;
238 _prefs_changed = FALSE;
239 }
240
241 if (authorization != NULL) {
242 #if !TARGET_OS_IPHONE
243 _prefs_AuthorizationFree(authorization);
244 #else /* !TARGET_OS_IPHONE */
245 // Uh...if authorization isn't NULL, something went horribly wrong.
246 #endif /* !TARGET_OS_IPHONE */
247 authorization = NULL;
248 }
249
250 return;
251 }
252
253
254 __private_extern__
255 Boolean
256 _prefs_commitRequired(int argc, char **argv, const char *command)
257 {
258 if (_prefs_changed) {
259 if ((currentInput != NULL) &&
260 isatty(fileno(currentInput->fp)) &&
261 ((argc < 1) || (strcmp(argv[0], "!") != 0))
262 ) {
263 SCPrint(TRUE, stdout,
264 CFSTR("preference changes have not been committed\n"
265 "use \"commit\" to save changes"));
266 if (command != NULL) {
267 SCPrint(TRUE, stdout,
268 CFSTR(" or \"%s !\" to abandon changes"),
269 command);
270 }
271 SCPrint(TRUE, stdout, CFSTR("\n"));
272 return TRUE;
273 }
274
275 SCPrint(TRUE, stdout, CFSTR("preference changes abandoned\n"));
276 }
277
278 return FALSE;
279 }
280
281
282 /* -------------------- */
283
284
285 static void
286 get_ComputerName(int argc, char **argv)
287 {
288 CFStringEncoding encoding;
289 CFStringRef hostname;
290
291 hostname = SCDynamicStoreCopyComputerName(NULL, &encoding);
292 if (hostname == NULL) {
293 int sc_status = SCError();
294
295 switch (sc_status) {
296 case kSCStatusNoKey :
297 SCPrint(TRUE,
298 stderr,
299 CFSTR("ComputerName: not set\n"));
300 break;
301 default :
302 SCPrint(TRUE,
303 stderr,
304 CFSTR("SCDynamicStoreCopyComputerName() failed: %s\n"),
305 SCErrorString(SCError()));
306 break;
307 }
308 exit (1);
309 }
310
311 SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname);
312 CFRelease(hostname);
313
314 exit(0);
315 }
316
317
318 static void
319 set_ComputerName(int argc, char **argv)
320 {
321 CFStringRef hostname = NULL;
322 Boolean ok;
323
324 ok = _prefs_open(CFSTR("scutil --set ComputerName"), NULL);
325 if (!ok) {
326 SCPrint(TRUE,
327 stdout,
328 CFSTR("Could not open prefs: %s\n"),
329 SCErrorString(SCError()));
330 exit(1);
331 }
332
333 if (argc == 0) {
334 CFStringEncoding old_encoding;
335 CFStringRef old_hostname;
336
337 old_hostname = SCDynamicStoreCopyComputerName(NULL, &old_encoding);
338 hostname = _copyStringFromSTDIN(CFSTR("ComputerName"), old_hostname);
339 if (old_hostname) CFRelease(old_hostname);
340 } else if (strlen(argv[0]) > 0) {
341 hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
342 }
343
344 ok = SCPreferencesSetComputerName(prefs, hostname, kCFStringEncodingUTF8);
345 if (hostname != NULL) CFRelease(hostname);
346 if (!ok) {
347 SCPrint(TRUE,
348 stdout,
349 CFSTR("Could not open prefs: %s\n"),
350 SCErrorString(SCError()));
351 _prefs_close();
352 exit (1);
353 }
354
355 _prefs_save();
356 _prefs_close();
357 exit(0);
358 }
359
360
361 static void
362 get_HostName(int argc, char **argv)
363 {
364 CFStringRef hostname;
365 Boolean ok;
366
367 ok = _prefs_open(CFSTR("scutil --get HostName"), NULL);
368 if (!ok) {
369 SCPrint(TRUE,
370 stdout,
371 CFSTR("SCPreferencesCreate() failed: %s\n"),
372 SCErrorString(SCError()));
373 exit(1);
374 }
375
376 hostname = SCPreferencesGetHostName(prefs);
377 if (hostname == NULL) {
378 int sc_status = SCError();
379
380 switch (sc_status) {
381 case kSCStatusNoKey :
382 SCPrint(TRUE,
383 stderr,
384 CFSTR("HostName: not set\n"));
385 break;
386 default :
387 SCPrint(TRUE,
388 stderr,
389 CFSTR("SCPreferencesGetHostName() failed: %s\n"),
390 SCErrorString(SCError()));
391 break;
392 }
393 _prefs_close();
394 exit (1);
395 }
396
397 SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname);
398 _prefs_close();
399 exit(0);
400 }
401
402
403 static void
404 set_HostName(int argc, char **argv)
405 {
406 CFStringRef hostname = NULL;
407 Boolean ok;
408
409 ok = _prefs_open(CFSTR("scutil --set HostName"), NULL);
410 if (!ok) {
411 SCPrint(TRUE,
412 stdout,
413 CFSTR("Could not open prefs: %s\n"),
414 SCErrorString(SCError()));
415 exit(1);
416 }
417
418 if (argc == 0) {
419 hostname = _copyStringFromSTDIN(CFSTR("HostName"), SCPreferencesGetHostName(prefs));
420 } else if (strlen(argv[0]) > 0) {
421 hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
422 }
423
424 ok = SCPreferencesSetHostName(prefs, hostname);
425 if (hostname != NULL) CFRelease(hostname);
426 if (!ok) {
427 SCPrint(TRUE,
428 stderr,
429 CFSTR("SCPreferencesSetHostName() failed: %s\n"),
430 SCErrorString(SCError()));
431 _prefs_close();
432 exit (1);
433 }
434
435 _prefs_save();
436 _prefs_close();
437 exit(0);
438 }
439
440
441 static void
442 get_LocalHostName(int argc, char **argv)
443 {
444 CFStringRef hostname;
445
446 hostname = SCDynamicStoreCopyLocalHostName(NULL);
447 if (hostname == NULL) {
448 int sc_status = SCError();
449
450 switch (sc_status) {
451 case kSCStatusNoKey :
452 SCPrint(TRUE,
453 stderr,
454 CFSTR("LocalHostName: not set\n"));
455 break;
456 default :
457 SCPrint(TRUE,
458 stderr,
459 CFSTR("SCDynamicStoreCopyLocalHostName() failed: %s\n"),
460 SCErrorString(SCError()));
461 break;
462 }
463 exit (1);
464 }
465
466 SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname);
467 CFRelease(hostname);
468
469 exit(0);
470 }
471
472
473 static void
474 set_LocalHostName(int argc, char **argv)
475 {
476 CFStringRef hostname = NULL;
477 Boolean ok;
478
479 ok = _prefs_open(CFSTR("scutil --set LocalHostName"), NULL);
480 if (!ok) {
481 SCPrint(TRUE,
482 stdout,
483 CFSTR("Could not open prefs: %s\n"),
484 SCErrorString(SCError()));
485 exit(1);
486 }
487
488 if (argc == 0) {
489 CFStringRef old_hostname;
490
491 old_hostname = SCDynamicStoreCopyLocalHostName(NULL);
492 hostname = _copyStringFromSTDIN(CFSTR("LocalHostName"), old_hostname);
493 if (old_hostname) CFRelease(old_hostname);
494 } else if (strlen(argv[0]) > 0) {
495 hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
496 }
497
498 ok = SCPreferencesSetLocalHostName(prefs, hostname);
499 if (hostname != NULL) CFRelease(hostname);
500 if (!ok) {
501 SCPrint(TRUE,
502 stderr,
503 CFSTR("SCPreferencesSetLocalHostName() failed: %s\n"),
504 SCErrorString(SCError()));
505 _prefs_close();
506 exit (1);
507 }
508
509 _prefs_save();
510 _prefs_close();
511 exit(0);
512 }
513
514
515 /* -------------------- */
516
517
518 typedef void (*pref_func) (int argc, char **argv);
519
520 static const struct {
521 char *pref;
522 pref_func get;
523 pref_func set;
524 } pref_keys[] = {
525 { "ComputerName", get_ComputerName, set_ComputerName },
526 { "HostName", get_HostName, set_HostName },
527 { "LocalHostName", get_LocalHostName, set_LocalHostName }
528 };
529 #define N_PREF_KEYS (sizeof(pref_keys) / sizeof(pref_keys[0]))
530
531
532 __private_extern__
533 int
534 findPref(char *pref)
535 {
536 int i;
537
538 for (i = 0; i < (int)N_PREF_KEYS; i++) {
539 if (strcmp(pref, pref_keys[i].pref) == 0) {
540 return i;
541 }
542 }
543
544 return -1;
545 }
546
547
548 __private_extern__
549 void
550 do_getPref(char *pref, int argc, char **argv)
551 {
552 int i;
553
554 if (argc == 0) {
555 i = findPref(pref);
556 if (i >= 0) {
557 (*pref_keys[i].get)(argc, argv);
558 }
559 return;
560 }
561
562 // process extended get
563 // ie. scutil --get <filename> <prefs path> <key>
564 do_prefs_init();
565
566 do_prefs_open(argc, argv);
567 if (SCError() != kSCStatusOK) {
568 SCPrint(TRUE, stderr, CFSTR("%s\n"), SCErrorString(SCError()));
569 _prefs_close();
570 exit(1);
571 }
572
573 do_prefs_get(--argc, ++argv);
574 if (value != NULL) {
575 CFStringRef key;
576 CFStringRef prefs_val;
577
578 key = CFStringCreateWithCString(NULL, *(++argv), kCFStringEncodingUTF8);
579 prefs_val = CFDictionaryGetValue(value, key);
580 CFRelease(key);
581
582 if (prefs_val != NULL) {
583 SCPrint(TRUE, stdout, CFSTR("%@\n"), prefs_val);
584 _prefs_close();
585 exit(0);
586 }
587 }
588
589 // if path or key not found
590 _prefs_close();
591 exit(1);
592 }
593
594
595 __private_extern__
596 void
597 do_setPref(char *pref, int argc, char **argv)
598 {
599 int i;
600
601 i = findPref(pref);
602 if (i >= 0) {
603 (*pref_keys[i].set)(argc, argv);
604 }
605 return;
606 }
607
608
609 /* -------------------- */
610
611
612 __private_extern__
613 void
614 do_prefs_init()
615 {
616 return;
617 }
618
619
620 __private_extern__
621 void
622 do_prefs_open(int argc, char **argv)
623 {
624 Boolean ok;
625 CFStringRef prefsID = NULL;
626
627 if (prefs != NULL) {
628 if (_prefs_commitRequired(argc, argv, "close")) {
629 return;
630 }
631
632 do_prefs_close(0, NULL);
633 }
634
635 if (argc > 0) {
636 prefsID = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
637 }
638
639 ok = _prefs_open(CFSTR("scutil --prefs"), prefsID);
640 if (prefsID != NULL) CFRelease(prefsID);
641 if (!ok) {
642 SCPrint(TRUE,
643 stdout,
644 CFSTR("Could not open prefs: %s\n"),
645 SCErrorString(SCError()));
646 return;
647 }
648
649 return;
650 }
651
652
653 __private_extern__
654 void
655 do_prefs_lock(int argc, char **argv)
656 {
657 Boolean wait = (argc > 0) ? TRUE : FALSE;
658
659 if (!SCPreferencesLock(prefs, wait)) {
660 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
661 return;
662 }
663
664 return;
665 }
666
667
668 __private_extern__
669 void
670 do_prefs_unlock(int argc, char **argv)
671 {
672 if (!SCPreferencesUnlock(prefs)) {
673 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
674 return;
675 }
676
677 return;
678 }
679
680
681 __private_extern__
682 void
683 do_prefs_commit(int argc, char **argv)
684 {
685 if (!SCPreferencesCommitChanges(prefs)) {
686 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
687 return;
688 }
689
690 _prefs_changed = FALSE;
691 return;
692 }
693
694
695 __private_extern__
696 void
697 do_prefs_apply(int argc, char **argv)
698 {
699 if (!SCPreferencesApplyChanges(prefs)) {
700 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
701 }
702
703 return;
704 }
705
706
707 __private_extern__
708 void
709 do_prefs_close(int argc, char **argv)
710 {
711 if (_prefs_commitRequired(argc, argv, "close")) {
712 return;
713 }
714
715 _prefs_close();
716 return;
717 }
718
719
720 __private_extern__
721 void
722 do_prefs_quit(int argc, char **argv)
723 {
724 if (_prefs_commitRequired(argc, argv, "quit")) {
725 return;
726 }
727
728 _prefs_close();
729
730 termRequested = TRUE;
731 return;
732 }
733
734
735 __private_extern__
736 void
737 do_prefs_synchronize(int argc, char **argv)
738 {
739 SCPreferencesSynchronize(prefs);
740 return;
741 }
742
743
744 static CFComparisonResult
745 sort_paths(const void *p1, const void *p2, void *context) {
746 CFStringRef path1 = (CFStringRef)p1;
747 CFStringRef path2 = (CFStringRef)p2;
748 return CFStringCompare(path1, path2, 0);
749 }
750
751
752 __private_extern__
753 void
754 do_prefs_list(int argc, char **argv)
755 {
756 int i;
757 CFIndex n;
758 CFMutableArrayRef paths = NULL;
759 CFStringRef prefix;
760 CFDictionaryRef entity;
761
762 prefix = CFStringCreateWithCString(NULL,
763 (argc >= 1) ? argv[0] : "/",
764 kCFStringEncodingUTF8);
765
766 entity = SCPreferencesPathGetValue(prefs, prefix);
767 if (entity == NULL) {
768 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
769 goto done;
770 }
771
772 paths = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
773
774 n = isA_CFDictionary(entity) ? CFDictionaryGetCount(entity) : 0;
775 if (n > 0) {
776 CFIndex i;
777 const void ** keys;
778 const void ** vals;
779
780 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
781 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
782 CFDictionaryGetKeysAndValues(entity, keys, vals);
783 for (i = 0; i < n; i++) {
784 if (isA_CFDictionary(vals[i])) {
785 CFArrayAppendValue(paths, keys[i]);
786 }
787 }
788 CFAllocatorDeallocate(NULL, keys);
789 CFAllocatorDeallocate(NULL, vals);
790 }
791
792 n = CFArrayGetCount(paths);
793 CFArraySortValues(paths,
794 CFRangeMake(0, n),
795 sort_paths,
796 NULL);
797
798 if (n > 0) {
799 for (i = 0; i < n; i++) {
800 SCPrint(TRUE,
801 stdout,
802 CFSTR(" path [%d] = %@/%@\n"),
803 i,
804 CFEqual(prefix, CFSTR("/")) ? CFSTR("") : prefix,
805 CFArrayGetValueAtIndex(paths, i));
806 }
807 } else {
808 SCPrint(TRUE, stdout, CFSTR(" no paths.\n"));
809 }
810
811 CFRelease(paths);
812
813 done :
814
815 CFRelease(prefix);
816 return;
817 }
818
819
820 __private_extern__
821 void
822 do_prefs_get(int argc, char **argv)
823 {
824 CFDictionaryRef dict;
825 CFStringRef link;
826 CFIndex n;
827 CFMutableDictionaryRef newDict;
828 CFStringRef path;
829
830 path = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
831
832 link = SCPreferencesPathGetLink(prefs, path);
833 if (link != NULL) {
834 SCPrint(TRUE, stdout, CFSTR(" --> %@\n"), link);
835 }
836
837 dict = SCPreferencesPathGetValue(prefs, path);
838 CFRelease(path);
839 if (dict == NULL) {
840 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
841 return;
842 }
843
844 newDict = CFDictionaryCreateMutable(NULL,
845 0,
846 &kCFTypeDictionaryKeyCallBacks,
847 &kCFTypeDictionaryValueCallBacks);
848
849 // remove [path] children
850 n = isA_CFDictionary(dict) ? CFDictionaryGetCount(dict) : 0;
851 if (n > 0) {
852 CFIndex i;
853 const void ** keys;
854 const void ** vals;
855
856 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
857 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
858 CFDictionaryGetKeysAndValues(dict, keys, vals);
859 for (i = 0; i < n; i++) {
860 if (!isA_CFDictionary(vals[i])) {
861 CFDictionaryAddValue(newDict, keys[i], vals[i]);
862 }
863 }
864 CFAllocatorDeallocate(NULL, keys);
865 CFAllocatorDeallocate(NULL, vals);
866 }
867
868 if (value != NULL) {
869 CFRelease(value); /* we have new information, release the old */
870 }
871
872 value = newDict;
873
874 return;
875 }
876
877
878 __private_extern__
879 void
880 do_prefs_set(int argc, char **argv)
881 {
882 CFDictionaryRef dict;
883 CFMutableDictionaryRef newDict = NULL;
884 CFStringRef path;
885
886 path = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
887 newDict = CFDictionaryCreateMutableCopy(NULL, 0, value);
888
889 dict = SCPreferencesPathGetValue(prefs, path);
890 if (dict != NULL) {
891 CFIndex n;
892
893 // retain [path] children
894 n = CFDictionaryGetCount(dict);
895 if (n > 0) {
896 CFIndex i;
897 const void ** keys;
898 const void ** vals;
899
900 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
901 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
902 CFDictionaryGetKeysAndValues(dict, keys, vals);
903 for (i = 0; i < n; i++) {
904 if (isA_CFDictionary(vals[i])) {
905 if (CFDictionaryContainsKey(newDict, keys[i])) {
906 SCPrint(TRUE, stdout, CFSTR(" key %@ is already a path component and cannot be replaced\n"), keys[i]);
907 goto done;
908 }
909 CFDictionaryAddValue(newDict, keys[i], vals[i]);
910 }
911 }
912 CFAllocatorDeallocate(NULL, keys);
913 CFAllocatorDeallocate(NULL, vals);
914 }
915 } else if (SCError() == kSCStatusInvalidArgument) {
916 SCPrint(TRUE, stdout, CFSTR(" a path component is not a dictionary\n"));
917 goto done;
918 } else if (SCError() != kSCStatusNoKey) {
919 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
920 goto done;
921 }
922
923 if (argc > 1) {
924 CFStringRef link;
925 Boolean ok;
926
927 // set link
928 link = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8);
929 ok = SCPreferencesPathSetLink(prefs, path, link);
930 CFRelease(link);
931 if (!ok) {
932 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
933 goto done;
934 }
935 } else {
936 // set value
937 if (!SCPreferencesPathSetValue(prefs, path, newDict)) {
938 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
939 goto done;
940 }
941 }
942
943 _prefs_changed = TRUE;
944
945 done :
946
947 CFRelease(newDict);
948 CFRelease(path);
949 return;
950 }
951
952
953 __private_extern__
954 void
955 do_prefs_remove(int argc, char **argv)
956 {
957 CFStringRef path;
958
959 path = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
960
961 if (!SCPreferencesPathRemoveValue(prefs, path)) {
962 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
963 goto done;
964 }
965
966 _prefs_changed = TRUE;
967
968 done :
969
970 CFRelease(path);
971 return;
972 }
973
974 static const char *
975 on_off_str(Boolean on)
976 {
977 return (on ? "on" : "off");
978 }
979
980 /* -------------------- */
981
982 #include "IPMonitorControlPrefs.h"
983
984 __private_extern__
985 void
986 do_log(char * log, int argc, char **argv)
987 {
988 Boolean verbose = FALSE;
989
990 if (strcmp(log, "IPMonitor")) {
991 exit(0);
992 }
993
994 if (argc == 0) {
995 SCPrint(TRUE, stdout, CFSTR("IPMonitor log is %s\n"),
996 on_off_str(IPMonitorControlPrefsIsVerbose()));
997 exit(0);
998 }
999
1000 if ((strcasecmp(argv[0], "disable") == 0) ||
1001 (strcasecmp(argv[0], "no" ) == 0) ||
1002 (strcasecmp(argv[0], "off" ) == 0) ||
1003 (strcasecmp(argv[0], "0" ) == 0)) {
1004 verbose = FALSE;
1005 } else if ((strcasecmp(argv[0], "enable") == 0) ||
1006 (strcasecmp(argv[0], "yes" ) == 0) ||
1007 (strcasecmp(argv[0], "on" ) == 0) ||
1008 (strcasecmp(argv[0], "1" ) == 0)) {
1009 verbose = TRUE;
1010 } else {
1011 SCPrint(TRUE, stdout, CFSTR("invalid value, must be 'on' or 'off'\n"));
1012 exit(1);
1013 }
1014
1015 if (!IPMonitorControlPrefsSetVerbose(verbose)) {
1016 SCPrint(TRUE, stderr, CFSTR("failed to set preferences\n"));
1017 exit(2);
1018 }
1019
1020 exit(0);
1021 return;
1022 }
1023
1024
1025 /* -------------------- */
1026
1027 static SCNetworkInterfaceRef
1028 copy_configured_interface(SCPreferencesRef prefs, CFStringRef if_name)
1029 {
1030 SCNetworkSetRef current_set = NULL;
1031 CFIndex count;
1032 CFIndex i;
1033 SCNetworkInterfaceRef ret_if = NULL;
1034 CFArrayRef services = NULL;
1035
1036 if (prefs == NULL) {
1037 goto done;
1038 }
1039 current_set = SCNetworkSetCopyCurrent(prefs);
1040 if (current_set == NULL) {
1041 goto done;
1042 }
1043 services = SCNetworkSetCopyServices(current_set);
1044 if (services == NULL) {
1045 goto done;
1046 }
1047
1048 count = CFArrayGetCount(services);
1049 for (i = 0; i < count; i++) {
1050 CFStringRef this_if_name;
1051 SCNetworkInterfaceRef this_if;
1052 SCNetworkServiceRef s;
1053
1054 s = (SCNetworkServiceRef)CFArrayGetValueAtIndex(services, i);
1055 if (!SCNetworkServiceGetEnabled(s)) {
1056 /* skip disabled services */
1057 continue;
1058 }
1059 this_if = SCNetworkServiceGetInterface(s);
1060 if (this_if == NULL) {
1061 continue;
1062 }
1063 this_if_name = SCNetworkInterfaceGetBSDName(this_if);
1064 if (this_if_name == NULL) {
1065 continue;
1066 }
1067 if (CFEqual(this_if_name, if_name)) {
1068 CFRetain(this_if);
1069 ret_if = this_if;
1070 break;
1071 }
1072 }
1073
1074 done:
1075 if (current_set != NULL) {
1076 CFRelease(current_set);
1077 }
1078 if (services != NULL) {
1079 CFRelease(services);
1080 }
1081 return (ret_if);
1082 }
1083
1084 static void
1085 disable_until_needed_usage(void)
1086 {
1087 fprintf(stderr, "usage: scutil --disable-until-needed <interfaceName> [on|off|default]\n");
1088 return;
1089 }
1090
1091 #include <SystemConfiguration/SCNetworkConfigurationPrivate.h>
1092
1093 __private_extern__
1094 void
1095 do_disable_until_needed(int argc, char **argv)
1096 {
1097 const char * if_name;
1098 CFStringRef if_name_cf;
1099 SCNetworkInterfaceRef net_if;
1100 Boolean on = FALSE;
1101 const char * on_off = "?";
1102 Boolean ok;
1103 Boolean set_default = FALSE;
1104 Boolean set_value = FALSE;
1105
1106 if (argc < 1 || argc > 2) {
1107 disable_until_needed_usage();
1108 exit(1);
1109 }
1110 if_name = argv[0];
1111 if (argc > 1) {
1112 on_off = argv[1];
1113 if (strcasecmp(on_off, "on") == 0) {
1114 on = TRUE;
1115 } else if (strcasecmp(on_off, "off") == 0) {
1116 on = FALSE;
1117 } else if ((strcmp(on_off, "") == 0) || (strcasecmp(on_off, "default") == 0)) {
1118 set_default = TRUE;
1119 on_off = "default";
1120 } else {
1121 disable_until_needed_usage();
1122 exit(1);
1123 }
1124 set_value = TRUE;
1125 }
1126 ok = _prefs_open(CFSTR("scutil --disable-until-needed"), NULL);
1127 if (!ok) {
1128 SCPrint(TRUE,
1129 stdout,
1130 CFSTR("Could not open prefs: %s\n"),
1131 SCErrorString(SCError()));
1132 exit(1);
1133 }
1134 if_name_cf = CFStringCreateWithCStringNoCopy(NULL,
1135 if_name,
1136 kCFStringEncodingASCII,
1137 kCFAllocatorNull);
1138 net_if = copy_configured_interface(prefs, if_name_cf);
1139 if (net_if == NULL) {
1140 fprintf(stderr, "%s is not configured\n", if_name);
1141 exit(1);
1142 }
1143 if (set_value) {
1144 if (!set_default) {
1145 ok = SCNetworkInterfaceSetDisableUntilNeeded(net_if, on);
1146 } else {
1147 ok = __SCNetworkInterfaceSetDisableUntilNeededValue(net_if, NULL);
1148 }
1149 if (!ok) {
1150 fprintf(stderr, "failed to turn disable-until-needed %s\n",
1151 on_off);
1152 exit(1);
1153 }
1154 _prefs_save();
1155 } else {
1156 on = SCNetworkInterfaceGetDisableUntilNeeded(net_if);
1157 printf("%s disable-until-needed is %s\n", if_name, on_off_str(on));
1158 }
1159 _prefs_close();
1160 exit(0);
1161 return;
1162 }