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>
38 #include <Security/Authorization.h>
45 /* -------------------- */
49 __loadSecurity(void) {
50 static void *image
= NULL
;
52 const char *framework
= "/System/Library/Frameworks/Security.framework/Versions/A/Security";
54 const char *suffix
= getenv("DYLD_IMAGE_SUFFIX");
55 char path
[MAXPATHLEN
];
57 strlcpy(path
, framework
, sizeof(path
));
58 if (suffix
) strlcat(path
, suffix
, sizeof(path
));
59 if (0 <= stat(path
, &statbuf
)) {
60 image
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
62 image
= dlopen(framework
, RTLD_LAZY
| RTLD_LOCAL
);
69 __private_extern__ OSStatus
70 _AuthorizationCreate(const AuthorizationRights
*rights
, const AuthorizationEnvironment
*environment
, AuthorizationFlags flags
, AuthorizationRef
*authorization
)
72 #undef AuthorizationCreate
73 static typeof (AuthorizationCreate
) *dyfunc
= NULL
;
75 void *image
= __loadSecurity();
76 if (image
) dyfunc
= dlsym(image
, "AuthorizationCreate");
78 return dyfunc
? dyfunc(rights
, environment
, flags
, authorization
) : -1;
80 #define AuthorizationCreate _AuthorizationCreate
83 __private_extern__ OSStatus
84 _AuthorizationFree(AuthorizationRef authorization
, AuthorizationFlags flags
)
86 #undef AuthorizationFree
87 static typeof (AuthorizationFree
) *dyfunc
= NULL
;
89 void *image
= __loadSecurity();
90 if (image
) dyfunc
= dlsym(image
, "AuthorizationFree");
92 return dyfunc
? dyfunc(authorization
, flags
) : -1;
94 #define AuthorizationFree _AuthorizationFree
97 /* -------------------- */
100 static AuthorizationRef
101 _createAuthorization()
103 AuthorizationRef authorization
= NULL
;
104 AuthorizationFlags flags
= kAuthorizationFlagDefaults
;
107 status
= AuthorizationCreate(NULL
,
108 kAuthorizationEmptyEnvironment
,
111 if (status
!= errAuthorizationSuccess
) {
114 CFSTR("AuthorizationCreate() failed: status = %d\n"),
119 return authorization
;
123 /* -------------------- */
126 __private_extern__ Boolean _prefs_changed
= FALSE
;
131 _prefs_open(CFStringRef name
, CFStringRef prefsID
)
133 if (geteuid() == 0) {
134 prefs
= SCPreferencesCreate(NULL
, name
, prefsID
);
136 authorization
= _createAuthorization();
137 prefs
= SCPreferencesCreateWithAuthorization(NULL
, name
, prefsID
, authorization
);
144 _prefs_changed
= FALSE
;
153 if (!SCPreferencesCommitChanges(prefs
)) {
155 case kSCStatusAccessError
:
156 SCPrint(TRUE
, stderr
, CFSTR("Permission denied.\n"));
161 CFSTR("SCPreferencesCommitChanges() failed: %s\n"),
162 SCErrorString(SCError()));
168 _prefs_changed
= FALSE
;
170 if (!SCPreferencesApplyChanges(prefs
)) {
173 CFSTR("SCPreferencesApplyChanges() failed: %s\n"),
174 SCErrorString(SCError()));
189 _prefs_changed
= FALSE
;
192 if (authorization
!= NULL
) {
193 AuthorizationFree(authorization
, kAuthorizationFlagDefaults
);
194 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
195 authorization
= NULL
;
204 _prefs_commitRequired(int argc
, char **argv
, const char *command
)
206 if (_prefs_changed
) {
207 if ((currentInput
!= NULL
) &&
208 isatty(fileno(currentInput
->fp
)) &&
209 ((argc
< 1) || (strcmp(argv
[0], "!") != 0))
211 SCPrint(TRUE
, stdout
,
212 CFSTR("preference changes have not been committed\n"
213 "use \"commit\" to save changes"));
214 if (command
!= NULL
) {
215 SCPrint(TRUE
, stdout
,
216 CFSTR(" or \"%s !\" to abandon changes"),
219 SCPrint(TRUE
, stdout
, CFSTR("\n"));
223 SCPrint(TRUE
, stdout
, CFSTR("preference changes abandoned\n"));
230 /* -------------------- */
234 _copyStringFromSTDIN()
240 if (fgets(buf
, sizeof(buf
), stdin
) == NULL
) {
245 if (buf
[len
-1] == '\n') {
249 utf8
= CFStringCreateWithBytes(NULL
, (UInt8
*)buf
, len
, kCFStringEncodingUTF8
, TRUE
);
255 get_ComputerName(int argc
, char **argv
)
257 CFStringEncoding encoding
;
258 CFStringRef hostname
;
260 hostname
= SCDynamicStoreCopyComputerName(NULL
, &encoding
);
261 if (hostname
== NULL
) {
262 int sc_status
= SCError();
265 case kSCStatusNoKey
:
268 CFSTR("ComputerName: not set\n"));
273 CFSTR("SCDynamicStoreCopyComputerName() failed: %s\n"),
274 SCErrorString(SCError()));
280 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
288 set_ComputerName(int argc
, char **argv
)
290 CFStringEncoding encoding
;
291 CFStringRef hostname
;
294 ok
= _prefs_open(CFSTR("scutil --set ComputerName"), NULL
);
298 CFSTR("Could not open prefs: %s\n"),
299 SCErrorString(SCError()));
304 hostname
= _copyStringFromSTDIN();
305 encoding
= kCFStringEncodingUTF8
;
307 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingASCII
);
308 encoding
= kCFStringEncodingASCII
;
311 ok
= SCPreferencesSetComputerName(prefs
, hostname
, encoding
);
312 if (hostname
!= NULL
) CFRelease(hostname
);
316 CFSTR("Could not open prefs: %s\n"),
317 SCErrorString(SCError()));
329 get_HostName(int argc
, char **argv
)
331 CFStringRef hostname
;
334 ok
= _prefs_open(CFSTR("scutil --get HostName"), NULL
);
338 CFSTR("SCPreferencesCreate() failed: %s\n"),
339 SCErrorString(SCError()));
343 hostname
= SCPreferencesGetHostName(prefs
);
344 if (hostname
== NULL
) {
345 int sc_status
= SCError();
348 case kSCStatusNoKey
:
351 CFSTR("HostName: not set\n"));
356 CFSTR("SCPreferencesGetHostName() failed: %s\n"),
357 SCErrorString(SCError()));
364 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
371 set_HostName(int argc
, char **argv
)
373 CFStringRef hostname
= NULL
;
376 ok
= _prefs_open(CFSTR("scutil --set HostName"), NULL
);
380 CFSTR("Could not open prefs: %s\n"),
381 SCErrorString(SCError()));
386 hostname
= _copyStringFromSTDIN();
388 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingASCII
);
391 ok
= SCPreferencesSetHostName(prefs
, hostname
);
392 if (hostname
!= NULL
) CFRelease(hostname
);
396 CFSTR("SCPreferencesSetHostName() failed: %s\n"),
397 SCErrorString(SCError()));
409 get_LocalHostName(int argc
, char **argv
)
411 CFStringRef hostname
;
413 hostname
= SCDynamicStoreCopyLocalHostName(NULL
);
414 if (hostname
== NULL
) {
415 int sc_status
= SCError();
418 case kSCStatusNoKey
:
421 CFSTR("LocalHostName: not set\n"));
426 CFSTR("SCDynamicStoreCopyLocalHostName() failed: %s\n"),
427 SCErrorString(SCError()));
433 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), hostname
);
441 set_LocalHostName(int argc
, char **argv
)
443 CFStringRef hostname
= NULL
;
446 ok
= _prefs_open(CFSTR("scutil --set LocalHostName"), NULL
);
450 CFSTR("Could not open prefs: %s\n"),
451 SCErrorString(SCError()));
456 hostname
= _copyStringFromSTDIN();
458 hostname
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingASCII
);
461 ok
= SCPreferencesSetLocalHostName(prefs
, hostname
);
462 if (hostname
!= NULL
) CFRelease(hostname
);
466 CFSTR("SCPreferencesSetLocalHostName() failed: %s\n"),
467 SCErrorString(SCError()));
478 /* -------------------- */
481 typedef void (*pref_func
) (int argc
, char **argv
);
483 static const struct {
488 { "ComputerName", get_ComputerName
, set_ComputerName
},
489 { "HostName", get_HostName
, set_HostName
},
490 { "LocalHostName", get_LocalHostName
, set_LocalHostName
}
492 #define N_PREF_KEYS (sizeof(pref_keys) / sizeof(pref_keys[0]))
501 for (i
= 0; i
< (int)N_PREF_KEYS
; i
++) {
502 if (strcmp(pref
, pref_keys
[i
].pref
) == 0) {
513 do_getPref(char *pref
, int argc
, char **argv
)
519 (*pref_keys
[i
].get
)(argc
, argv
);
527 do_setPref(char *pref
, int argc
, char **argv
)
533 (*pref_keys
[i
].set
)(argc
, argv
);
539 /* -------------------- */
552 do_prefs_open(int argc
, char **argv
)
555 CFStringRef prefsID
= NULL
;
558 if (_prefs_commitRequired(argc
, argv
, "close")) {
562 do_prefs_close(0, NULL
);
566 prefsID
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
569 ok
= _prefs_open(CFSTR("scutil --prefs"), prefsID
);
570 if (prefsID
!= NULL
) CFRelease(prefsID
);
574 CFSTR("Could not open prefs: %s\n"),
575 SCErrorString(SCError()));
585 do_prefs_lock(int argc
, char **argv
)
587 Boolean wait
= (argc
> 0) ? TRUE
: FALSE
;
589 if (!SCPreferencesLock(prefs
, wait
)) {
590 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
600 do_prefs_unlock(int argc
, char **argv
)
602 if (!SCPreferencesUnlock(prefs
)) {
603 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
613 do_prefs_commit(int argc
, char **argv
)
615 if (!SCPreferencesCommitChanges(prefs
)) {
616 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
620 _prefs_changed
= FALSE
;
627 do_prefs_apply(int argc
, char **argv
)
629 if (!SCPreferencesApplyChanges(prefs
)) {
630 SCPrint(TRUE
, stdout
, CFSTR("%s\n"), SCErrorString(SCError()));
639 do_prefs_close(int argc
, char **argv
)
641 if (_prefs_commitRequired(argc
, argv
, "close")) {
652 do_prefs_quit(int argc
, char **argv
)
654 if (_prefs_commitRequired(argc
, argv
, "quit")) {
660 termRequested
= TRUE
;
667 do_prefs_synchronize(int argc
, char **argv
)
669 SCPreferencesSynchronize(prefs
);
674 static CFComparisonResult
675 sort_paths(const void *p1
, const void *p2
, void *context
) {
676 CFStringRef path1
= (CFStringRef
)p1
;
677 CFStringRef path2
= (CFStringRef
)p2
;
678 return CFStringCompare(path1
, path2
, 0);
684 do_prefs_list(int argc
, char **argv
)
688 CFMutableArrayRef paths
= NULL
;
690 CFDictionaryRef entity
;
692 prefix
= CFStringCreateWithCString(NULL
,
693 (argc
>= 1) ? argv
[0] : "/",
694 kCFStringEncodingUTF8
);
696 entity
= SCPreferencesPathGetValue(prefs
, prefix
);
697 if (entity
== NULL
) {
698 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
702 paths
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
704 n
= isA_CFDictionary(entity
) ? CFDictionaryGetCount(entity
) : 0;
710 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
711 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
712 CFDictionaryGetKeysAndValues(entity
, keys
, vals
);
713 for (i
= 0; i
< n
; i
++) {
714 if (isA_CFDictionary(vals
[i
])) {
715 CFArrayAppendValue(paths
, keys
[i
]);
718 CFAllocatorDeallocate(NULL
, keys
);
719 CFAllocatorDeallocate(NULL
, vals
);
722 n
= CFArrayGetCount(paths
);
723 CFArraySortValues(paths
,
729 for (i
= 0; i
< n
; i
++) {
732 CFSTR(" path [%d] = %@/%@\n"),
734 CFEqual(prefix
, CFSTR("/")) ? CFSTR("") : prefix
,
735 CFArrayGetValueAtIndex(paths
, i
));
738 SCPrint(TRUE
, stdout
, CFSTR(" no paths.\n"));
752 do_prefs_get(int argc
, char **argv
)
754 CFDictionaryRef dict
;
757 CFMutableDictionaryRef newDict
;
760 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
762 link
= SCPreferencesPathGetLink(prefs
, path
);
764 SCPrint(TRUE
, stdout
, CFSTR(" --> %@\n"), link
);
767 dict
= SCPreferencesPathGetValue(prefs
, path
);
770 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
774 newDict
= CFDictionaryCreateMutable(NULL
,
776 &kCFTypeDictionaryKeyCallBacks
,
777 &kCFTypeDictionaryValueCallBacks
);
779 // remove [path] children
780 n
= isA_CFDictionary(dict
) ? CFDictionaryGetCount(dict
) : 0;
786 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
787 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
788 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
789 for (i
= 0; i
< n
; i
++) {
790 if (!isA_CFDictionary(vals
[i
])) {
791 CFDictionaryAddValue(newDict
, keys
[i
], vals
[i
]);
794 CFAllocatorDeallocate(NULL
, keys
);
795 CFAllocatorDeallocate(NULL
, vals
);
799 CFRelease(value
); /* we have new information, release the old */
810 do_prefs_set(int argc
, char **argv
)
812 CFDictionaryRef dict
;
813 CFMutableDictionaryRef newDict
= NULL
;
816 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
817 newDict
= CFDictionaryCreateMutableCopy(NULL
, 0, value
);
819 dict
= SCPreferencesPathGetValue(prefs
, path
);
823 // retain [path] children
824 n
= CFDictionaryGetCount(dict
);
830 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
831 vals
= CFAllocatorAllocate(NULL
, n
* sizeof(CFPropertyListRef
), 0);
832 CFDictionaryGetKeysAndValues(dict
, keys
, vals
);
833 for (i
= 0; i
< n
; i
++) {
834 if (isA_CFDictionary(vals
[i
])) {
835 if (CFDictionaryContainsKey(newDict
, keys
[i
])) {
836 SCPrint(TRUE
, stdout
, CFSTR(" key %@ is already a path component and cannot be replaced\n"), keys
[i
]);
839 CFDictionaryAddValue(newDict
, keys
[i
], vals
[i
]);
842 CFAllocatorDeallocate(NULL
, keys
);
843 CFAllocatorDeallocate(NULL
, vals
);
845 } else if (SCError() == kSCStatusInvalidArgument
) {
846 SCPrint(TRUE
, stdout
, CFSTR(" a path component is not a dictionary\n"));
848 } else if (SCError() != kSCStatusNoKey
) {
849 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
858 link
= CFStringCreateWithCString(NULL
, argv
[1], kCFStringEncodingUTF8
);
859 ok
= SCPreferencesPathSetLink(prefs
, path
, link
);
862 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
867 if (!SCPreferencesPathSetValue(prefs
, path
, newDict
)) {
868 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
873 _prefs_changed
= TRUE
;
885 do_prefs_remove(int argc
, char **argv
)
889 path
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
891 if (!SCPreferencesPathRemoveValue(prefs
, path
)) {
892 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
896 _prefs_changed
= TRUE
;