2 * Copyright (c) 2005-2007 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@
26 #include <sys/types.h>
28 #include <CoreFoundation/CoreFoundation.h>
29 #include <SystemConfiguration/SystemConfiguration.h>
30 #include <SystemConfiguration/SCPrivate.h>
31 #include <Security/Security.h>
33 #include "SCPreferencesInternal.h"
34 #include "SCHelper_client.h"
35 #include "helper_comm.h"
38 static AuthorizationRef authorization
= NULL
;
39 static SCPreferencesRef prefs
= NULL
;
45 * (out) status = SCError()
49 do_Exit(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
57 * (in) data = AuthorizationExternalForm
58 * (out) status = OSStatus
62 do_Auth(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
64 if (authorization
!= NULL
) {
65 AuthorizationFree(authorization
, kAuthorizationFlagDefaults
);
66 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
71 AuthorizationExternalForm extForm
;
73 if (CFDataGetLength(data
) == sizeof(extForm
.bytes
)) {
76 bcopy(CFDataGetBytePtr(data
), extForm
.bytes
, sizeof(extForm
.bytes
));
77 err
= AuthorizationCreateFromExternalForm(&extForm
, &authorization
);
78 if (err
!= errAuthorizationSuccess
) {
80 CFSTR("AuthorizationCreateFromExternalForm() failed: status = %d"),
88 *status
= (authorization
!= NULL
) ? 0 : 1;
95 * SCHELPER_MSG_KEYCHAIN_COPY
96 * (in) data = unique_id
97 * (out) status = SCError()
98 * (out) reply = password
101 do_keychain_copy(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
103 CFStringRef unique_id
= NULL
;
105 if ((data
!= NULL
) && !_SCUnserializeString(&unique_id
, data
, NULL
, 0)) {
109 if (!isA_CFString(unique_id
)) {
113 *reply
= _SCPreferencesSystemKeychainPasswordItemCopy(prefs
, unique_id
);
114 CFRelease(unique_id
);
115 if (*reply
== NULL
) {
124 * SCHELPER_MSG_KEYCHAIN_EXISTS
125 * (in) data = unique_id
126 * (out) status = SCError()
130 do_keychain_exists(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
133 CFStringRef unique_id
= NULL
;
135 if ((data
!= NULL
) && !_SCUnserializeString(&unique_id
, data
, NULL
, 0)) {
139 if (!isA_CFString(unique_id
)) {
143 ok
= _SCPreferencesSystemKeychainPasswordItemExists(prefs
, unique_id
);
144 CFRelease(unique_id
);
155 * SCHELPER_MSG_KEYCHAIN_REMOVE
156 * (in) data = unique_id
157 * (out) status = SCError()
161 do_keychain_remove(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
164 CFStringRef unique_id
= NULL
;
166 if ((data
!= NULL
) && !_SCUnserializeString(&unique_id
, data
, NULL
, 0)) {
170 if (!isA_CFString(unique_id
)) {
174 ok
= _SCPreferencesSystemKeychainPasswordItemRemove(prefs
, unique_id
);
175 CFRelease(unique_id
);
186 * SCHELPER_MSG_KEYCHAIN_SET
187 * (in) data = options dictionary
188 * (out) status = SCError()
192 do_keychain_set(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
195 CFStringRef description
;
196 CFArrayRef executablePaths
= NULL
;
199 CFDictionaryRef options
= NULL
;
201 CFStringRef unique_id
;
203 if ((data
!= NULL
) && !_SCUnserialize((CFPropertyListRef
*)&options
, data
, NULL
, 0)) {
207 if (!isA_CFDictionary(options
)) {
211 if (CFDictionaryGetValueIfPresent(options
,
212 kSCKeychainOptionsAllowedExecutables
,
213 (const void **)&executablePaths
)) {
214 CFMutableArrayRef executableURLs
;
217 CFMutableDictionaryRef newOptions
;
219 executableURLs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
220 n
= CFArrayGetCount(executablePaths
);
221 for (i
= 0; i
< n
; i
++) {
225 path
= CFArrayGetValueAtIndex(executablePaths
, i
);
226 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
227 CFDataGetBytePtr(path
),
228 CFDataGetLength(path
),
231 CFArrayAppendValue(executableURLs
, url
);
236 newOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, options
);
237 CFDictionarySetValue(newOptions
, kSCKeychainOptionsAllowedExecutables
, executableURLs
);
238 CFRelease(executableURLs
);
241 options
= newOptions
;
244 unique_id
= CFDictionaryGetValue(options
, kSCKeychainOptionsUniqueID
);
245 label
= CFDictionaryGetValue(options
, kSCKeychainOptionsLabel
);
246 description
= CFDictionaryGetValue(options
, kSCKeychainOptionsDescription
);
247 account
= CFDictionaryGetValue(options
, kSCKeychainOptionsAccount
);
248 password
= CFDictionaryGetValue(options
, kSCKeychainOptionsPassword
);
250 ok
= _SCPreferencesSystemKeychainPasswordItemSet(prefs
,
268 * SCHELPER_MSG_INTERFACE_REFRESH
270 * (out) status = SCError()
274 do_interface_refresh(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
276 CFStringRef ifName
= NULL
;
279 if ((data
!= NULL
) && !_SCUnserializeString(&ifName
, data
, NULL
, 0)) {
280 SCLog(TRUE
, LOG_ERR
, CFSTR("interface name not valid"));
284 if (!isA_CFString(ifName
)) {
285 SCLog(TRUE
, LOG_ERR
, CFSTR("interface name not valid"));
289 ok
= _SCNetworkInterfaceForceConfigurationRefresh(ifName
);
302 * (in) data = prefsID
303 * (out) status = SCError()
307 do_prefs_Open(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
309 CFStringRef prefsID
= NULL
;
315 if ((data
!= NULL
) && !_SCUnserializeString(&prefsID
, data
, NULL
, 0)) {
316 SCLog(TRUE
, LOG_ERR
, CFSTR("prefsID not valid"));
320 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCHelper"), prefsID
);
321 if (prefsID
!= NULL
) CFRelease(prefsID
);
334 * (out) status = SCError()
335 * (out) reply = current signature + current preferences
338 do_prefs_Access(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
341 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
348 signature
= SCPreferencesGetSignature(prefs
);
349 if (signature
!= NULL
) {
350 const void * dictKeys
[2];
351 const void * dictVals
[2];
352 CFDictionaryRef replyDict
;
354 dictKeys
[0] = CFSTR("signature");
355 dictVals
[0] = signature
;
357 dictKeys
[1] = CFSTR("preferences");
358 dictVals
[1] = prefsPrivate
->prefs
;
360 replyDict
= CFDictionaryCreate(NULL
,
361 (const void **)&dictKeys
,
362 (const void **)&dictVals
,
363 sizeof(dictKeys
)/sizeof(dictKeys
[0]),
364 &kCFTypeDictionaryKeyCallBacks
,
365 &kCFTypeDictionaryValueCallBacks
);
367 ok
= _SCSerialize(replyDict
, reply
, NULL
, NULL
);
368 CFRelease(replyDict
);
382 * (in) data = client prefs signature (NULL if check not needed)
383 * (out) status = SCError()
387 do_prefs_Lock(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
389 CFDataRef clientSignature
= (CFDataRef
)data
;
391 Boolean wait
= (info
== (void *)FALSE
) ? FALSE
: TRUE
;
397 ok
= SCPreferencesLock(prefs
, wait
);
403 if (clientSignature
!= NULL
) {
404 CFDataRef serverSignature
;
406 serverSignature
= SCPreferencesGetSignature(prefs
);
407 if (!CFEqual(clientSignature
, serverSignature
)) {
408 (void)SCPreferencesUnlock(prefs
);
409 *status
= kSCStatusStale
;
419 * (in) data = new preferences (NULL if commit w/no changes)
420 * (out) status = SCError()
421 * (out) reply = new signature
424 do_prefs_Commit(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
427 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
434 if (prefsPrivate
->prefs
!= NULL
) {
435 CFRelease(prefsPrivate
->prefs
);
438 ok
= _SCUnserialize((CFPropertyListRef
*)&prefsPrivate
->prefs
, data
, NULL
, 0);
443 prefsPrivate
->accessed
= TRUE
;
444 prefsPrivate
->changed
= TRUE
;
447 ok
= SCPreferencesCommitChanges(prefs
);
449 *reply
= SCPreferencesGetSignature(prefs
);
462 * (out) status = SCError()
466 do_prefs_Apply(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
474 ok
= SCPreferencesApplyChanges(prefs
);
486 * (out) status = SCError()
490 do_prefs_Unlock(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
498 ok
= SCPreferencesUnlock(prefs
);
510 * (out) status = SCError()
514 do_prefs_Close(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
530 * (out) status = kSCStatusOK
534 do_prefs_Synchronize(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
540 SCPreferencesSynchronize(prefs
);
541 *status
= kSCStatusOK
;
549 AuthorizationFlags flags
;
550 AuthorizationItem items
[1];
551 AuthorizationRights rights
;
554 if (authorization
== NULL
) {
558 items
[0].name
= "system.preferences";
559 items
[0].value
= NULL
;
560 items
[0].valueLength
= 0;
563 rights
.count
= sizeof(items
) / sizeof(items
[0]);
564 rights
.items
= items
;
566 flags
= kAuthorizationFlagDefaults
;
567 flags
|= kAuthorizationFlagExtendRights
;
568 flags
|= kAuthorizationFlagInteractionAllowed
;
569 // flags |= kAuthorizationFlagPartialRights;
570 // flags |= kAuthorizationFlagPreAuthorize;
572 status
= AuthorizationCopyRights(authorization
,
574 kAuthorizationEmptyEnvironment
,
577 if (status
!= errAuthorizationSuccess
) {
581 if (items
[0].flags
!= 0) SCLog(TRUE
, LOG_DEBUG
, CFSTR("***** success w/flags (%u) != 0"), items
[0].flags
);
586 typedef Boolean (*helperFunction
) (void *info
,
592 static const struct helper
{
594 const char *commandName
;
595 Boolean needsAuthorization
;
599 { SCHELPER_MSG_AUTH
, "AUTH", FALSE
, do_Auth
, NULL
},
601 { SCHELPER_MSG_PREFS_OPEN
, "PREFS open", FALSE
, do_prefs_Open
, NULL
},
602 { SCHELPER_MSG_PREFS_ACCESS
, "PREFS access", TRUE
, do_prefs_Access
, NULL
},
603 { SCHELPER_MSG_PREFS_LOCK
, "PREFS lock", TRUE
, do_prefs_Lock
, (void *)FALSE
},
604 { SCHELPER_MSG_PREFS_LOCKWAIT
, "PREFS lock/wait", TRUE
, do_prefs_Lock
, (void *)TRUE
},
605 { SCHELPER_MSG_PREFS_COMMIT
, "PREFS commit", TRUE
, do_prefs_Commit
, NULL
},
606 { SCHELPER_MSG_PREFS_APPLY
, "PREFS apply", TRUE
, do_prefs_Apply
, NULL
},
607 { SCHELPER_MSG_PREFS_UNLOCK
, "PREFS unlock", FALSE
, do_prefs_Unlock
, NULL
},
608 { SCHELPER_MSG_PREFS_CLOSE
, "PREFS close", FALSE
, do_prefs_Close
, NULL
},
609 { SCHELPER_MSG_PREFS_SYNCHRONIZE
, "PREFS synchronize", FALSE
, do_prefs_Synchronize
, NULL
},
611 { SCHELPER_MSG_INTERFACE_REFRESH
, "INTERFACE refresh", TRUE
, do_interface_refresh
, NULL
},
613 { SCHELPER_MSG_KEYCHAIN_COPY
, "KEYCHAIN copy", TRUE
, do_keychain_copy
, NULL
},
614 { SCHELPER_MSG_KEYCHAIN_EXISTS
, "KEYCHAIN exists", TRUE
, do_keychain_exists
, NULL
},
615 { SCHELPER_MSG_KEYCHAIN_REMOVE
, "KEYCHAIN remove", TRUE
, do_keychain_remove
, NULL
},
616 { SCHELPER_MSG_KEYCHAIN_SET
, "KEYCHAIN set", TRUE
, do_keychain_set
, NULL
},
618 { SCHELPER_MSG_EXIT
, "EXIT", FALSE
, do_Exit
, NULL
}
620 #define nHELPERS (sizeof(helpers)/sizeof(struct helper))
628 for (i
= 0; i
< (int)nHELPERS
; i
++) {
629 if (helpers
[i
].command
== command
) {
639 main(int argc
, char **argv
)
644 openlog("SCHelper", LOG_CONS
|LOG_PID
, LOG_DAEMON
);
646 if (geteuid() != 0) {
647 (void)__SCHelper_txMessage(STDOUT_FILENO
, EACCES
, NULL
);
651 // send "we are here" message
652 if (!__SCHelper_txMessage(STDOUT_FILENO
, 0, NULL
)) {
665 if (!__SCHelper_rxMessage(STDIN_FILENO
, &command
, &data
)) {
666 SCLog(TRUE
, LOG_ERR
, CFSTR("no command"));
671 i
= findHelper(command
);
673 SCLog(TRUE
, LOG_ERR
, CFSTR("received unknown command : %u"), command
);
678 SCLog(TRUE
, LOG_DEBUG
,
679 CFSTR("processing command \"%s\"%s"),
680 helpers
[i
].commandName
,
681 (data
!= NULL
) ? " w/data" : "");
683 status
= kSCStatusOK
;
686 if (helpers
[i
].needsAuthorization
&& !hasAuthorization()) {
687 SCLog(TRUE
, LOG_DEBUG
,
688 CFSTR("command \"%s\" : not authorized"),
689 helpers
[i
].commandName
);
690 status
= kSCStatusAccessError
;
693 if (status
== kSCStatusOK
) {
694 ok
= (*helpers
[i
].func
)(helpers
[i
].info
, data
, &status
, &reply
);
697 SCLog(TRUE
, LOG_DEBUG
,
698 CFSTR("sending status %u%s"),
700 (reply
!= NULL
) ? " w/reply" : "");
702 if (!__SCHelper_txMessage(STDOUT_FILENO
, status
, reply
)) {
716 if (authorization
!= NULL
) {
717 AuthorizationFree(authorization
, kAuthorizationFlagDefaults
);
718 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);