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/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 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();
148 #endif /* !TARGET_OS_IPHONE */
151 if (getenv("SCPREFERENCES_REMOVE_WHEN_EMPTY") != NULL
) {
152 // if we have options
155 if (options
== NULL
) {
156 options
= CFDictionaryCreateMutable(NULL
,
158 &kCFTypeDictionaryKeyCallBacks
,
159 &kCFTypeDictionaryValueCallBacks
);
161 CFDictionarySetValue(options
, kSCPreferencesOptionRemoveWhenEmpty
, kCFBooleanTrue
);
164 if (!useHelper
&& !useOptions
) {
165 // if no helper/options needed
166 prefs
= SCPreferencesCreate(NULL
, name
, prefsID
);
167 } else if (!useOptions
) {
168 // if no options needed
169 prefs
= SCPreferencesCreateWithAuthorization(NULL
, name
, prefsID
, authorization
);
171 prefs
= SCPreferencesCreateWithOptions(NULL
, name
, prefsID
, authorization
, options
);
179 _prefs_changed
= FALSE
;
188 if (!SCPreferencesCommitChanges(prefs
)) {
190 case kSCStatusAccessError
:
191 SCPrint(TRUE
, stderr
, CFSTR("Permission denied.\n"));
196 CFSTR("SCPreferencesCommitChanges() failed: %s\n"),
197 SCErrorString(SCError()));
203 _prefs_changed
= FALSE
;
205 if (!SCPreferencesApplyChanges(prefs
)) {
208 CFSTR("SCPreferencesApplyChanges() failed: %s\n"),
209 SCErrorString(SCError()));
224 _prefs_changed
= FALSE
;
227 if (authorization
!= NULL
) {
228 #if !TARGET_OS_IPHONE
229 AuthorizationFree(authorization
, kAuthorizationFlagDefaults
);
230 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
231 #else /* !TARGET_OS_IPHONE */
232 // Uh...if authorization isn't NULL, something went horribly wrong.
233 #endif /* !TARGET_OS_IPHONE */
234 authorization
= NULL
;
243 _prefs_commitRequired(int argc
, char **argv
, const char *command
)
245 if (_prefs_changed
) {
246 if ((currentInput
!= NULL
) &&
247 isatty(fileno(currentInput
->fp
)) &&
248 ((argc
< 1) || (strcmp(argv
[0], "!") != 0))
250 SCPrint(TRUE
, stdout
,
251 CFSTR("preference changes have not been committed\n"
252 "use \"commit\" to save changes"));
253 if (command
!= NULL
) {
254 SCPrint(TRUE
, stdout
,
255 CFSTR(" or \"%s !\" to abandon changes"),
258 SCPrint(TRUE
, stdout
, CFSTR("\n"));
262 SCPrint(TRUE
, stdout
, CFSTR("preference changes abandoned\n"));
269 /* -------------------- */
273 get_ComputerName(int argc
, char **argv
)
275 CFStringEncoding encoding
;
276 CFStringRef hostname
;
278 hostname
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
279 if (hostname
== NULL
) {
280 int sc_status
= SCError();
283 case kSCStatusNoKey
:
286 CFSTR("ComputerName: not set\n"));
291 CFSTR("SCDynamicStoreCopyComputerName() failed: %s\n"),
292 SCErrorString(SCError()));
298 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
306 set_ComputerName(int argc
, char **argv
)
308 CFStringRef hostname
;
311 ok
= _prefs_open(CFSTR("scutil --set ComputerName"), NULL
);
315 CFSTR("Could not open prefs: %s\n"),
316 SCErrorString(SCError()));
321 hostname
= _copyStringFromSTDIN();
323 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
326 ok
= SCPreferencesSetComputerName(prefs
, hostname
, kCFStringEncodingUTF8
);
327 if (hostname
!= NULL
) CFRelease(hostname
);
331 CFSTR("Could not open prefs: %s\n"),
332 SCErrorString(SCError()));
344 get_HostName(int argc
, char **argv
)
346 CFStringRef hostname
;
349 ok
= _prefs_open(CFSTR("scutil --get HostName"), NULL
);
353 CFSTR("SCPreferencesCreate() failed: %s\n"),
354 SCErrorString(SCError()));
358 hostname
= SCPreferencesGetHostName(prefs
);
359 if (hostname
== NULL
) {
360 int sc_status
= SCError();
363 case kSCStatusNoKey
:
366 CFSTR("HostName: not set\n"));
371 CFSTR("SCPreferencesGetHostName() failed: %s\n"),
372 SCErrorString(SCError()));
379 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
386 set_HostName(int argc
, char **argv
)
388 CFStringRef hostname
= NULL
;
391 ok
= _prefs_open(CFSTR("scutil --set HostName"), NULL
);
395 CFSTR("Could not open prefs: %s\n"),
396 SCErrorString(SCError()));
401 hostname
= _copyStringFromSTDIN();
403 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
406 ok
= SCPreferencesSetHostName(prefs
, hostname
);
407 if (hostname
!= NULL
) CFRelease(hostname
);
411 CFSTR("SCPreferencesSetHostName() failed: %s\n"),
412 SCErrorString(SCError()));
424 get_LocalHostName(int argc
, char **argv
)
426 CFStringRef hostname
;
428 hostname
= SCDynamicStoreCopyLocalHostName(NULL
);
429 if (hostname
== NULL
) {
430 int sc_status
= SCError();
433 case kSCStatusNoKey
:
436 CFSTR("LocalHostName: not set\n"));
441 CFSTR("SCDynamicStoreCopyLocalHostName() failed: %s\n"),
442 SCErrorString(SCError()));
448 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
456 set_LocalHostName(int argc
, char **argv
)
458 CFStringRef hostname
= NULL
;
461 ok
= _prefs_open(CFSTR("scutil --set LocalHostName"), NULL
);
465 CFSTR("Could not open prefs: %s\n"),
466 SCErrorString(SCError()));
471 hostname
= _copyStringFromSTDIN();
473 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
476 ok
= SCPreferencesSetLocalHostName(prefs
, hostname
);
477 if (hostname
!= NULL
) CFRelease(hostname
);
481 CFSTR("SCPreferencesSetLocalHostName() failed: %s\n"),
482 SCErrorString(SCError()));
493 /* -------------------- */
496 typedef void (*pref_func
) (int argc
, char **argv
);
498 static const struct {
503 { "ComputerName", get_ComputerName
, set_ComputerName
},
504 { "HostName", get_HostName
, set_HostName
},
505 { "LocalHostName", get_LocalHostName
, set_LocalHostName
}
507 #define N_PREF_KEYS (sizeof(pref_keys) / sizeof(pref_keys[0]))
516 for (i
= 0; i
< (int)N_PREF_KEYS
; i
++) {
517 if (strcmp(pref
, pref_keys
[i
].pref
) == 0) {
528 do_getPref(char *pref
, int argc
, char **argv
)
534 (*pref_keys
[i
].get
)(argc
, argv
);
542 do_setPref(char *pref
, int argc
, char **argv
)
548 (*pref_keys
[i
].set
)(argc
, argv
);
554 /* -------------------- */
567 do_prefs_open(int argc
, char **argv
)
570 CFStringRef prefsID
= NULL
;
573 if (_prefs_commitRequired(argc
, argv
, "close")) {
577 do_prefs_close(0, NULL
);
581 prefsID
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
584 ok
= _prefs_open(CFSTR("scutil --prefs"), prefsID
);
585 if (prefsID
!= NULL
) CFRelease(prefsID
);
589 CFSTR("Could not open prefs: %s\n"),
590 SCErrorString(SCError()));
600 do_prefs_lock(int argc
, char **argv
)
602 Boolean wait
= (argc
> 0) ? TRUE
: FALSE
;
604 if (!SCPreferencesLock(prefs
, wait
)) {
605 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
615 do_prefs_unlock(int argc
, char **argv
)
617 if (!SCPreferencesUnlock(prefs
)) {
618 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
628 do_prefs_commit(int argc
, char **argv
)
630 if (!SCPreferencesCommitChanges(prefs
)) {
631 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
635 _prefs_changed
= FALSE
;
642 do_prefs_apply(int argc
, char **argv
)
644 if (!SCPreferencesApplyChanges(prefs
)) {
645 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
654 do_prefs_close(int argc
, char **argv
)
656 if (_prefs_commitRequired(argc
, argv
, "close")) {
667 do_prefs_quit(int argc
, char **argv
)
669 if (_prefs_commitRequired(argc
, argv
, "quit")) {
675 termRequested
= TRUE
;
682 do_prefs_synchronize(int argc
, char **argv
)
684 SCPreferencesSynchronize(prefs
);
689 static CFComparisonResult
690 sort_paths(const void *p1
, const void *p2
, void *context
) {
691 CFStringRef path1
= (CFStringRef
)p1
;
692 CFStringRef path2
= (CFStringRef
)p2
;
693 return CFStringCompare(path1
, path2
, 0);
699 do_prefs_list(int argc
, char **argv
)
703 CFMutableArrayRef paths
= NULL
;
705 CFDictionaryRef entity
;
707 prefix
= CFStringCreateWithCString(NULL
,
708 (argc
>= 1) ? argv
[0] : "/",
709 kCFStringEncodingUTF8
);
711 entity
= SCPreferencesPathGetValue(prefs
, prefix
);
712 if (entity
== NULL
) {
713 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
717 paths
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
719 n
= isA_CFDictionary(entity
) ? CFDictionaryGetCount(entity
) : 0;
725 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
726 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
727 CFDictionaryGetKeysAndValues(entity
, keys
, vals
);
728 for (i
= 0; i
< n
; i
++) {
729 if (isA_CFDictionary(vals
[i
])) {
730 CFArrayAppendValue(paths
, keys
[i
]);
733 CFAllocatorDeallocate(NULL
, keys
);
734 CFAllocatorDeallocate(NULL
, vals
);
737 n
= CFArrayGetCount(paths
);
738 CFArraySortValues(paths
,
744 for (i
= 0; i
< n
; i
++) {
747 CFSTR(" path [%d] = %@/%@\n"),
749 CFEqual(prefix
, CFSTR("/")) ? CFSTR("") : prefix
,
750 CFArrayGetValueAtIndex(paths
, i
));
753 SCPrint(TRUE
, stdout
, CFSTR(" no paths.\n"));
767 do_prefs_get(int argc
, char **argv
)
769 CFDictionaryRef dict
;
772 CFMutableDictionaryRef newDict
;
775 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
777 link
= SCPreferencesPathGetLink(prefs
, path
);
779 SCPrint(TRUE
, stdout
, CFSTR(" --> %@\n"), link
);
782 dict
= SCPreferencesPathGetValue(prefs
, path
);
785 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
789 newDict
= CFDictionaryCreateMutable(NULL
,
791 &kCFTypeDictionaryKeyCallBacks
,
792 &kCFTypeDictionaryValueCallBacks
);
794 // remove [path] children
795 n
= isA_CFDictionary(dict
) ? CFDictionaryGetCount(dict
) : 0;
801 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
802 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
803 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
804 for (i
= 0; i
< n
; i
++) {
805 if (!isA_CFDictionary(vals
[i
])) {
806 CFDictionaryAddValue(newDict
, keys
[i
], vals
[i
]);
809 CFAllocatorDeallocate(NULL
, keys
);
810 CFAllocatorDeallocate(NULL
, vals
);
814 CFRelease(value
); /* we have new information, release the old */
825 do_prefs_set(int argc
, char **argv
)
827 CFDictionaryRef dict
;
828 CFMutableDictionaryRef newDict
= NULL
;
831 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
832 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, value
);
834 dict
= SCPreferencesPathGetValue(prefs
, path
);
838 // retain [path] children
839 n
= CFDictionaryGetCount(dict
);
845 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
846 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
847 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
848 for (i
= 0; i
< n
; i
++) {
849 if (isA_CFDictionary(vals
[i
])) {
850 if (CFDictionaryContainsKey(newDict
, keys
[i
])) {
851 SCPrint(TRUE
, stdout
, CFSTR(" key %@ is already a path component and cannot be replaced\n"), keys
[i
]);
854 CFDictionaryAddValue(newDict
, keys
[i
], vals
[i
]);
857 CFAllocatorDeallocate(NULL
, keys
);
858 CFAllocatorDeallocate(NULL
, vals
);
860 } else if (SCError() == kSCStatusInvalidArgument
) {
861 SCPrint(TRUE
, stdout
, CFSTR(" a path component is not a dictionary\n"));
863 } else if (SCError() != kSCStatusNoKey
) {
864 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
873 link
= CFStringCreateWithCString(NULL
, argv
[1], kCFStringEncodingUTF8
);
874 ok
= SCPreferencesPathSetLink(prefs
, path
, link
);
877 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
882 if (!SCPreferencesPathSetValue(prefs
, path
, newDict
)) {
883 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
888 _prefs_changed
= TRUE
;
900 do_prefs_remove(int argc
, char **argv
)
904 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
906 if (!SCPreferencesPathRemoveValue(prefs
, path
)) {
907 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
911 _prefs_changed
= TRUE
;