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