2 * Copyright (c) 2003-2008 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/Versions/A/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 if (geteuid() == 0) {
137 prefs
= SCPreferencesCreate(NULL
, name
, prefsID
);
139 #if !TARGET_OS_IPHONE
140 authorization
= _createAuthorization();
141 #else /* !TARGET_OS_IPHONE */
142 authorization
= NULL
;
143 #endif /* !TARGET_OS_IPHONE */
144 prefs
= SCPreferencesCreateWithAuthorization(NULL
, name
, prefsID
, authorization
);
151 _prefs_changed
= FALSE
;
160 if (!SCPreferencesCommitChanges(prefs
)) {
162 case kSCStatusAccessError
:
163 SCPrint(TRUE
, stderr
, CFSTR("Permission denied.\n"));
168 CFSTR("SCPreferencesCommitChanges() failed: %s\n"),
169 SCErrorString(SCError()));
175 _prefs_changed
= FALSE
;
177 if (!SCPreferencesApplyChanges(prefs
)) {
180 CFSTR("SCPreferencesApplyChanges() failed: %s\n"),
181 SCErrorString(SCError()));
196 _prefs_changed
= FALSE
;
199 if (authorization
!= NULL
) {
200 #if !TARGET_OS_IPHONE
201 AuthorizationFree(authorization
, kAuthorizationFlagDefaults
);
202 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
203 #else /* !TARGET_OS_IPHONE */
204 // Uh...if authorization isn't NULL, something went horribly wrong.
205 #endif /* !TARGET_OS_IPHONE */
206 authorization
= NULL
;
215 _prefs_commitRequired(int argc
, char **argv
, const char *command
)
217 if (_prefs_changed
) {
218 if ((currentInput
!= NULL
) &&
219 isatty(fileno(currentInput
->fp
)) &&
220 ((argc
< 1) || (strcmp(argv
[0], "!") != 0))
222 SCPrint(TRUE
, stdout
,
223 CFSTR("preference changes have not been committed\n"
224 "use \"commit\" to save changes"));
225 if (command
!= NULL
) {
226 SCPrint(TRUE
, stdout
,
227 CFSTR(" or \"%s !\" to abandon changes"),
230 SCPrint(TRUE
, stdout
, CFSTR("\n"));
234 SCPrint(TRUE
, stdout
, CFSTR("preference changes abandoned\n"));
241 /* -------------------- */
245 _copyStringFromSTDIN()
251 if (fgets(buf
, sizeof(buf
), stdin
) == NULL
) {
256 if (buf
[len
-1] == '\n') {
260 utf8
= CFStringCreateWithBytes(NULL
, (UInt8
*)buf
, len
, kCFStringEncodingUTF8
, TRUE
);
266 get_ComputerName(int argc
, char **argv
)
268 CFStringEncoding encoding
;
269 CFStringRef hostname
;
271 hostname
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
272 if (hostname
== NULL
) {
273 int sc_status
= SCError();
276 case kSCStatusNoKey
:
279 CFSTR("ComputerName: not set\n"));
284 CFSTR("SCDynamicStoreCopyComputerName() failed: %s\n"),
285 SCErrorString(SCError()));
291 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
299 set_ComputerName(int argc
, char **argv
)
301 CFStringRef hostname
;
304 ok
= _prefs_open(CFSTR("scutil --set ComputerName"), NULL
);
308 CFSTR("Could not open prefs: %s\n"),
309 SCErrorString(SCError()));
314 hostname
= _copyStringFromSTDIN();
316 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
319 ok
= SCPreferencesSetComputerName(prefs
, hostname
, kCFStringEncodingUTF8
);
320 if (hostname
!= NULL
) CFRelease(hostname
);
324 CFSTR("Could not open prefs: %s\n"),
325 SCErrorString(SCError()));
337 get_HostName(int argc
, char **argv
)
339 CFStringRef hostname
;
342 ok
= _prefs_open(CFSTR("scutil --get HostName"), NULL
);
346 CFSTR("SCPreferencesCreate() failed: %s\n"),
347 SCErrorString(SCError()));
351 hostname
= SCPreferencesGetHostName(prefs
);
352 if (hostname
== NULL
) {
353 int sc_status
= SCError();
356 case kSCStatusNoKey
:
359 CFSTR("HostName: not set\n"));
364 CFSTR("SCPreferencesGetHostName() failed: %s\n"),
365 SCErrorString(SCError()));
372 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
379 set_HostName(int argc
, char **argv
)
381 CFStringRef hostname
= NULL
;
384 ok
= _prefs_open(CFSTR("scutil --set HostName"), NULL
);
388 CFSTR("Could not open prefs: %s\n"),
389 SCErrorString(SCError()));
394 hostname
= _copyStringFromSTDIN();
396 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
399 ok
= SCPreferencesSetHostName(prefs
, hostname
);
400 if (hostname
!= NULL
) CFRelease(hostname
);
404 CFSTR("SCPreferencesSetHostName() failed: %s\n"),
405 SCErrorString(SCError()));
417 get_LocalHostName(int argc
, char **argv
)
419 CFStringRef hostname
;
421 hostname
= SCDynamicStoreCopyLocalHostName(NULL
);
422 if (hostname
== NULL
) {
423 int sc_status
= SCError();
426 case kSCStatusNoKey
:
429 CFSTR("LocalHostName: not set\n"));
434 CFSTR("SCDynamicStoreCopyLocalHostName() failed: %s\n"),
435 SCErrorString(SCError()));
441 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
449 set_LocalHostName(int argc
, char **argv
)
451 CFStringRef hostname
= NULL
;
454 ok
= _prefs_open(CFSTR("scutil --set LocalHostName"), NULL
);
458 CFSTR("Could not open prefs: %s\n"),
459 SCErrorString(SCError()));
464 hostname
= _copyStringFromSTDIN();
466 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
469 ok
= SCPreferencesSetLocalHostName(prefs
, hostname
);
470 if (hostname
!= NULL
) CFRelease(hostname
);
474 CFSTR("SCPreferencesSetLocalHostName() failed: %s\n"),
475 SCErrorString(SCError()));
486 /* -------------------- */
489 typedef void (*pref_func
) (int argc
, char **argv
);
491 static const struct {
496 { "ComputerName", get_ComputerName
, set_ComputerName
},
497 { "HostName", get_HostName
, set_HostName
},
498 { "LocalHostName", get_LocalHostName
, set_LocalHostName
}
500 #define N_PREF_KEYS (sizeof(pref_keys) / sizeof(pref_keys[0]))
509 for (i
= 0; i
< (int)N_PREF_KEYS
; i
++) {
510 if (strcmp(pref
, pref_keys
[i
].pref
) == 0) {
521 do_getPref(char *pref
, int argc
, char **argv
)
527 (*pref_keys
[i
].get
)(argc
, argv
);
535 do_setPref(char *pref
, int argc
, char **argv
)
541 (*pref_keys
[i
].set
)(argc
, argv
);
547 /* -------------------- */
560 do_prefs_open(int argc
, char **argv
)
563 CFStringRef prefsID
= NULL
;
566 if (_prefs_commitRequired(argc
, argv
, "close")) {
570 do_prefs_close(0, NULL
);
574 prefsID
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
577 ok
= _prefs_open(CFSTR("scutil --prefs"), prefsID
);
578 if (prefsID
!= NULL
) CFRelease(prefsID
);
582 CFSTR("Could not open prefs: %s\n"),
583 SCErrorString(SCError()));
593 do_prefs_lock(int argc
, char **argv
)
595 Boolean wait
= (argc
> 0) ? TRUE
: FALSE
;
597 if (!SCPreferencesLock(prefs
, wait
)) {
598 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
608 do_prefs_unlock(int argc
, char **argv
)
610 if (!SCPreferencesUnlock(prefs
)) {
611 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
621 do_prefs_commit(int argc
, char **argv
)
623 if (!SCPreferencesCommitChanges(prefs
)) {
624 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
628 _prefs_changed
= FALSE
;
635 do_prefs_apply(int argc
, char **argv
)
637 if (!SCPreferencesApplyChanges(prefs
)) {
638 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
647 do_prefs_close(int argc
, char **argv
)
649 if (_prefs_commitRequired(argc
, argv
, "close")) {
660 do_prefs_quit(int argc
, char **argv
)
662 if (_prefs_commitRequired(argc
, argv
, "quit")) {
668 termRequested
= TRUE
;
675 do_prefs_synchronize(int argc
, char **argv
)
677 SCPreferencesSynchronize(prefs
);
682 static CFComparisonResult
683 sort_paths(const void *p1
, const void *p2
, void *context
) {
684 CFStringRef path1
= (CFStringRef
)p1
;
685 CFStringRef path2
= (CFStringRef
)p2
;
686 return CFStringCompare(path1
, path2
, 0);
692 do_prefs_list(int argc
, char **argv
)
696 CFMutableArrayRef paths
= NULL
;
698 CFDictionaryRef entity
;
700 prefix
= CFStringCreateWithCString(NULL
,
701 (argc
>= 1) ? argv
[0] : "/",
702 kCFStringEncodingUTF8
);
704 entity
= SCPreferencesPathGetValue(prefs
, prefix
);
705 if (entity
== NULL
) {
706 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
710 paths
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
712 n
= isA_CFDictionary(entity
) ? CFDictionaryGetCount(entity
) : 0;
718 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
719 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
720 CFDictionaryGetKeysAndValues(entity
, keys
, vals
);
721 for (i
= 0; i
< n
; i
++) {
722 if (isA_CFDictionary(vals
[i
])) {
723 CFArrayAppendValue(paths
, keys
[i
]);
726 CFAllocatorDeallocate(NULL
, keys
);
727 CFAllocatorDeallocate(NULL
, vals
);
730 n
= CFArrayGetCount(paths
);
731 CFArraySortValues(paths
,
737 for (i
= 0; i
< n
; i
++) {
740 CFSTR(" path [%d] = %@/%@\n"),
742 CFEqual(prefix
, CFSTR("/")) ? CFSTR("") : prefix
,
743 CFArrayGetValueAtIndex(paths
, i
));
746 SCPrint(TRUE
, stdout
, CFSTR(" no paths.\n"));
760 do_prefs_get(int argc
, char **argv
)
762 CFDictionaryRef dict
;
765 CFMutableDictionaryRef newDict
;
768 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
770 link
= SCPreferencesPathGetLink(prefs
, path
);
772 SCPrint(TRUE
, stdout
, CFSTR(" --> %@\n"), link
);
775 dict
= SCPreferencesPathGetValue(prefs
, path
);
778 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
782 newDict
= CFDictionaryCreateMutable(NULL
,
784 &kCFTypeDictionaryKeyCallBacks
,
785 &kCFTypeDictionaryValueCallBacks
);
787 // remove [path] children
788 n
= isA_CFDictionary(dict
) ? CFDictionaryGetCount(dict
) : 0;
794 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
795 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
796 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
797 for (i
= 0; i
< n
; i
++) {
798 if (!isA_CFDictionary(vals
[i
])) {
799 CFDictionaryAddValue(newDict
, keys
[i
], vals
[i
]);
802 CFAllocatorDeallocate(NULL
, keys
);
803 CFAllocatorDeallocate(NULL
, vals
);
807 CFRelease(value
); /* we have new information, release the old */
818 do_prefs_set(int argc
, char **argv
)
820 CFDictionaryRef dict
;
821 CFMutableDictionaryRef newDict
= NULL
;
824 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
825 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, value
);
827 dict
= SCPreferencesPathGetValue(prefs
, path
);
831 // retain [path] children
832 n
= CFDictionaryGetCount(dict
);
838 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
839 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
840 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
841 for (i
= 0; i
< n
; i
++) {
842 if (isA_CFDictionary(vals
[i
])) {
843 if (CFDictionaryContainsKey(newDict
, keys
[i
])) {
844 SCPrint(TRUE
, stdout
, CFSTR(" key %@ is already a path component and cannot be replaced\n"), keys
[i
]);
847 CFDictionaryAddValue(newDict
, keys
[i
], vals
[i
]);
850 CFAllocatorDeallocate(NULL
, keys
);
851 CFAllocatorDeallocate(NULL
, vals
);
853 } else if (SCError() == kSCStatusInvalidArgument
) {
854 SCPrint(TRUE
, stdout
, CFSTR(" a path component is not a dictionary\n"));
856 } else if (SCError() != kSCStatusNoKey
) {
857 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
866 link
= CFStringCreateWithCString(NULL
, argv
[1], kCFStringEncodingUTF8
);
867 ok
= SCPreferencesPathSetLink(prefs
, path
, link
);
870 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
875 if (!SCPreferencesPathSetValue(prefs
, path
, newDict
)) {
876 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
881 _prefs_changed
= TRUE
;
893 do_prefs_remove(int argc
, char **argv
)
897 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
899 if (!SCPreferencesPathRemoveValue(prefs
, path
)) {
900 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
904 _prefs_changed
= TRUE
;