2 * Copyright (c) 2003-2008, 2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * May 29, 2003 Allan Nathanson <ajn@apple.com>
32 #include <sys/param.h>
33 #include <sys/types.h>
37 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
39 #include <Security/Authorization.h>
40 #endif /* !TARGET_OS_IPHONE */
47 /* -------------------- */
52 __loadSecurity(void) {
53 static void *image
= NULL
;
55 const char *framework
= "/System/Library/Frameworks/Security.framework/Security";
57 const char *suffix
= getenv("DYLD_IMAGE_SUFFIX");
58 char path
[MAXPATHLEN
];
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
);
65 image
= dlopen(framework
, RTLD_LAZY
| RTLD_LOCAL
);
72 __private_extern__ OSStatus
73 _AuthorizationCreate(const AuthorizationRights
*rights
, const AuthorizationEnvironment
*environment
, AuthorizationFlags flags
, AuthorizationRef
*authorization
)
75 #undef AuthorizationCreate
76 static typeof (AuthorizationCreate
) *dyfunc
= NULL
;
78 void *image
= __loadSecurity();
79 if (image
) dyfunc
= dlsym(image
, "AuthorizationCreate");
81 return dyfunc
? dyfunc(rights
, environment
, flags
, authorization
) : -1;
83 #define AuthorizationCreate _AuthorizationCreate
86 __private_extern__ OSStatus
87 _AuthorizationFree(AuthorizationRef authorization
, AuthorizationFlags flags
)
89 #undef AuthorizationFree
90 static typeof (AuthorizationFree
) *dyfunc
= NULL
;
92 void *image
= __loadSecurity();
93 if (image
) dyfunc
= dlsym(image
, "AuthorizationFree");
95 return dyfunc
? dyfunc(authorization
, flags
) : -1;
97 #define AuthorizationFree _AuthorizationFree
100 /* -------------------- */
103 static AuthorizationRef
104 _createAuthorization()
106 AuthorizationRef authorization
= NULL
;
107 AuthorizationFlags flags
= kAuthorizationFlagDefaults
;
110 status
= AuthorizationCreate(NULL
,
111 kAuthorizationEmptyEnvironment
,
114 if (status
!= errAuthorizationSuccess
) {
117 CFSTR("AuthorizationCreate() failed: status = %d\n"),
122 return authorization
;
124 #endif /* !TARGET_OS_IPHONE */
126 /* -------------------- */
129 __private_extern__ Boolean _prefs_changed
= FALSE
;
134 _prefs_open(CFStringRef name
, CFStringRef prefsID
)
136 CFMutableDictionaryRef options
= NULL
;
137 Boolean useHelper
= FALSE
;
138 Boolean useOptions
= FALSE
;
140 authorization
= NULL
;
142 if (geteuid() != 0) {
143 // if we need to use a helper
146 #if !TARGET_OS_IPHONE
147 authorization
= _createAuthorization();
149 authorization
= (AuthorizationRef
)kSCPreferencesUseEntitlementAuthorization
;
150 #endif /* !TARGET_OS_IPHONE */
153 if (getenv("SCPREFERENCES_REMOVE_WHEN_EMPTY") != NULL
) {
154 // if we have options
157 if (options
== NULL
) {
158 options
= CFDictionaryCreateMutable(NULL
,
160 &kCFTypeDictionaryKeyCallBacks
,
161 &kCFTypeDictionaryValueCallBacks
);
163 CFDictionarySetValue(options
, kSCPreferencesOptionRemoveWhenEmpty
, kCFBooleanTrue
);
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
);
173 prefs
= SCPreferencesCreateWithOptions(NULL
, name
, prefsID
, authorization
, options
);
181 _prefs_changed
= FALSE
;
190 if (!SCPreferencesCommitChanges(prefs
)) {
192 case kSCStatusAccessError
:
193 SCPrint(TRUE
, stderr
, CFSTR("Permission denied.\n"));
198 CFSTR("SCPreferencesCommitChanges() failed: %s\n"),
199 SCErrorString(SCError()));
205 _prefs_changed
= FALSE
;
207 if (!SCPreferencesApplyChanges(prefs
)) {
210 CFSTR("SCPreferencesApplyChanges() failed: %s\n"),
211 SCErrorString(SCError()));
226 _prefs_changed
= FALSE
;
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
;
245 _prefs_commitRequired(int argc
, char **argv
, const char *command
)
247 if (_prefs_changed
) {
248 if ((currentInput
!= NULL
) &&
249 isatty(fileno(currentInput
->fp
)) &&
250 ((argc
< 1) || (strcmp(argv
[0], "!") != 0))
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"),
260 SCPrint(TRUE
, stdout
, CFSTR("\n"));
264 SCPrint(TRUE
, stdout
, CFSTR("preference changes abandoned\n"));
271 /* -------------------- */
275 get_ComputerName(int argc
, char **argv
)
277 CFStringEncoding encoding
;
278 CFStringRef hostname
;
280 hostname
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
281 if (hostname
== NULL
) {
282 int sc_status
= SCError();
285 case kSCStatusNoKey
:
288 CFSTR("ComputerName: not set\n"));
293 CFSTR("SCDynamicStoreCopyComputerName() failed: %s\n"),
294 SCErrorString(SCError()));
300 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
308 set_ComputerName(int argc
, char **argv
)
310 CFStringRef hostname
;
313 ok
= _prefs_open(CFSTR("scutil --set ComputerName"), NULL
);
317 CFSTR("Could not open prefs: %s\n"),
318 SCErrorString(SCError()));
323 hostname
= _copyStringFromSTDIN();
325 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
328 ok
= SCPreferencesSetComputerName(prefs
, hostname
, kCFStringEncodingUTF8
);
329 if (hostname
!= NULL
) CFRelease(hostname
);
333 CFSTR("Could not open prefs: %s\n"),
334 SCErrorString(SCError()));
346 get_HostName(int argc
, char **argv
)
348 CFStringRef hostname
;
351 ok
= _prefs_open(CFSTR("scutil --get HostName"), NULL
);
355 CFSTR("SCPreferencesCreate() failed: %s\n"),
356 SCErrorString(SCError()));
360 hostname
= SCPreferencesGetHostName(prefs
);
361 if (hostname
== NULL
) {
362 int sc_status
= SCError();
365 case kSCStatusNoKey
:
368 CFSTR("HostName: not set\n"));
373 CFSTR("SCPreferencesGetHostName() failed: %s\n"),
374 SCErrorString(SCError()));
381 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
388 set_HostName(int argc
, char **argv
)
390 CFStringRef hostname
= NULL
;
393 ok
= _prefs_open(CFSTR("scutil --set HostName"), NULL
);
397 CFSTR("Could not open prefs: %s\n"),
398 SCErrorString(SCError()));
403 hostname
= _copyStringFromSTDIN();
405 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
408 ok
= SCPreferencesSetHostName(prefs
, hostname
);
409 if (hostname
!= NULL
) CFRelease(hostname
);
413 CFSTR("SCPreferencesSetHostName() failed: %s\n"),
414 SCErrorString(SCError()));
426 get_LocalHostName(int argc
, char **argv
)
428 CFStringRef hostname
;
430 hostname
= SCDynamicStoreCopyLocalHostName(NULL
);
431 if (hostname
== NULL
) {
432 int sc_status
= SCError();
435 case kSCStatusNoKey
:
438 CFSTR("LocalHostName: not set\n"));
443 CFSTR("SCDynamicStoreCopyLocalHostName() failed: %s\n"),
444 SCErrorString(SCError()));
450 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
458 set_LocalHostName(int argc
, char **argv
)
460 CFStringRef hostname
= NULL
;
463 ok
= _prefs_open(CFSTR("scutil --set LocalHostName"), NULL
);
467 CFSTR("Could not open prefs: %s\n"),
468 SCErrorString(SCError()));
473 hostname
= _copyStringFromSTDIN();
475 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
478 ok
= SCPreferencesSetLocalHostName(prefs
, hostname
);
479 if (hostname
!= NULL
) CFRelease(hostname
);
483 CFSTR("SCPreferencesSetLocalHostName() failed: %s\n"),
484 SCErrorString(SCError()));
495 /* -------------------- */
498 typedef void (*pref_func
) (int argc
, char **argv
);
500 static const struct {
505 { "ComputerName", get_ComputerName
, set_ComputerName
},
506 { "HostName", get_HostName
, set_HostName
},
507 { "LocalHostName", get_LocalHostName
, set_LocalHostName
}
509 #define N_PREF_KEYS (sizeof(pref_keys) / sizeof(pref_keys[0]))
518 for (i
= 0; i
< (int)N_PREF_KEYS
; i
++) {
519 if (strcmp(pref
, pref_keys
[i
].pref
) == 0) {
530 do_getPref(char *pref
, int argc
, char **argv
)
536 (*pref_keys
[i
].get
)(argc
, argv
);
544 do_setPref(char *pref
, int argc
, char **argv
)
550 (*pref_keys
[i
].set
)(argc
, argv
);
556 /* -------------------- */
569 do_prefs_open(int argc
, char **argv
)
572 CFStringRef prefsID
= NULL
;
575 if (_prefs_commitRequired(argc
, argv
, "close")) {
579 do_prefs_close(0, NULL
);
583 prefsID
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
586 ok
= _prefs_open(CFSTR("scutil --prefs"), prefsID
);
587 if (prefsID
!= NULL
) CFRelease(prefsID
);
591 CFSTR("Could not open prefs: %s\n"),
592 SCErrorString(SCError()));
602 do_prefs_lock(int argc
, char **argv
)
604 Boolean wait
= (argc
> 0) ? TRUE
: FALSE
;
606 if (!SCPreferencesLock(prefs
, wait
)) {
607 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
617 do_prefs_unlock(int argc
, char **argv
)
619 if (!SCPreferencesUnlock(prefs
)) {
620 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
630 do_prefs_commit(int argc
, char **argv
)
632 if (!SCPreferencesCommitChanges(prefs
)) {
633 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
637 _prefs_changed
= FALSE
;
644 do_prefs_apply(int argc
, char **argv
)
646 if (!SCPreferencesApplyChanges(prefs
)) {
647 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
656 do_prefs_close(int argc
, char **argv
)
658 if (_prefs_commitRequired(argc
, argv
, "close")) {
669 do_prefs_quit(int argc
, char **argv
)
671 if (_prefs_commitRequired(argc
, argv
, "quit")) {
677 termRequested
= TRUE
;
684 do_prefs_synchronize(int argc
, char **argv
)
686 SCPreferencesSynchronize(prefs
);
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);
701 do_prefs_list(int argc
, char **argv
)
705 CFMutableArrayRef paths
= NULL
;
707 CFDictionaryRef entity
;
709 prefix
= CFStringCreateWithCString(NULL
,
710 (argc
>= 1) ? argv
[0] : "/",
711 kCFStringEncodingUTF8
);
713 entity
= SCPreferencesPathGetValue(prefs
, prefix
);
714 if (entity
== NULL
) {
715 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
719 paths
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
721 n
= isA_CFDictionary(entity
) ? CFDictionaryGetCount(entity
) : 0;
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
]);
735 CFAllocatorDeallocate(NULL
, keys
);
736 CFAllocatorDeallocate(NULL
, vals
);
739 n
= CFArrayGetCount(paths
);
740 CFArraySortValues(paths
,
746 for (i
= 0; i
< n
; i
++) {
749 CFSTR(" path [%d] = %@/%@\n"),
751 CFEqual(prefix
, CFSTR("/")) ? CFSTR("") : prefix
,
752 CFArrayGetValueAtIndex(paths
, i
));
755 SCPrint(TRUE
, stdout
, CFSTR(" no paths.\n"));
769 do_prefs_get(int argc
, char **argv
)
771 CFDictionaryRef dict
;
774 CFMutableDictionaryRef newDict
;
777 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
779 link
= SCPreferencesPathGetLink(prefs
, path
);
781 SCPrint(TRUE
, stdout
, CFSTR(" --> %@\n"), link
);
784 dict
= SCPreferencesPathGetValue(prefs
, path
);
787 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
791 newDict
= CFDictionaryCreateMutable(NULL
,
793 &kCFTypeDictionaryKeyCallBacks
,
794 &kCFTypeDictionaryValueCallBacks
);
796 // remove [path] children
797 n
= isA_CFDictionary(dict
) ? CFDictionaryGetCount(dict
) : 0;
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
]);
811 CFAllocatorDeallocate(NULL
, keys
);
812 CFAllocatorDeallocate(NULL
, vals
);
816 CFRelease(value
); /* we have new information, release the old */
827 do_prefs_set(int argc
, char **argv
)
829 CFDictionaryRef dict
;
830 CFMutableDictionaryRef newDict
= NULL
;
833 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
834 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, value
);
836 dict
= SCPreferencesPathGetValue(prefs
, path
);
840 // retain [path] children
841 n
= CFDictionaryGetCount(dict
);
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
]);
856 CFDictionaryAddValue(newDict
, keys
[i
], vals
[i
]);
859 CFAllocatorDeallocate(NULL
, keys
);
860 CFAllocatorDeallocate(NULL
, vals
);
862 } else if (SCError() == kSCStatusInvalidArgument
) {
863 SCPrint(TRUE
, stdout
, CFSTR(" a path component is not a dictionary\n"));
865 } else if (SCError() != kSCStatusNoKey
) {
866 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
875 link
= CFStringCreateWithCString(NULL
, argv
[1], kCFStringEncodingUTF8
);
876 ok
= SCPreferencesPathSetLink(prefs
, path
, link
);
879 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
884 if (!SCPreferencesPathSetValue(prefs
, path
, newDict
)) {
885 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
890 _prefs_changed
= TRUE
;
902 do_prefs_remove(int argc
, char **argv
)
906 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
908 if (!SCPreferencesPathRemoveValue(prefs
, path
)) {
909 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
913 _prefs_changed
= TRUE
;