2 * Copyright (c) 2005, 2006 Apple Computer, 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 memcpy(extForm
.bytes
, CFDataGetBytePtr(data
), 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
);
376 SCPreferencesSynchronize(prefs
);
383 * (in) data = client prefs signature (NULL if check not needed)
384 * (out) status = SCError()
388 do_prefs_Lock(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
390 CFDataRef clientSignature
= (CFDataRef
)data
;
392 Boolean wait
= (info
== (void *)FALSE
) ? FALSE
: TRUE
;
398 ok
= SCPreferencesLock(prefs
, wait
);
404 if (clientSignature
!= NULL
) {
405 CFDataRef serverSignature
;
407 serverSignature
= SCPreferencesGetSignature(prefs
);
408 if (!CFEqual(clientSignature
, serverSignature
)) {
409 (void)SCPreferencesUnlock(prefs
);
410 *status
= kSCStatusStale
;
420 * (in) data = new preferences (NULL if commit w/no changes)
421 * (out) status = SCError()
422 * (out) reply = new signature
425 do_prefs_Commit(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
428 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
435 if (prefsPrivate
->prefs
!= NULL
) {
436 CFRelease(prefsPrivate
->prefs
);
439 ok
= _SCUnserialize((CFPropertyListRef
*)&prefsPrivate
->prefs
, data
, NULL
, 0);
444 prefsPrivate
->accessed
= TRUE
;
445 prefsPrivate
->changed
= TRUE
;
448 ok
= SCPreferencesCommitChanges(prefs
);
450 *reply
= SCPreferencesGetSignature(prefs
);
456 SCPreferencesSynchronize(prefs
);
464 * (out) status = SCError()
468 do_prefs_Apply(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
476 ok
= SCPreferencesApplyChanges(prefs
);
488 * (out) status = SCError()
492 do_prefs_Unlock(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
500 ok
= SCPreferencesUnlock(prefs
);
512 * (out) status = SCError()
516 do_prefs_Close(void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
532 AuthorizationFlags flags
;
533 AuthorizationItem items
[1];
534 AuthorizationRights rights
;
537 if (authorization
== NULL
) {
541 items
[0].name
= "system.preferences";
542 items
[0].value
= NULL
;
543 items
[0].valueLength
= 0;
546 rights
.count
= sizeof(items
) / sizeof(items
[0]);
547 rights
.items
= items
;
549 flags
= kAuthorizationFlagDefaults
;
550 flags
|= kAuthorizationFlagExtendRights
;
551 flags
|= kAuthorizationFlagInteractionAllowed
;
552 // flags |= kAuthorizationFlagPartialRights;
553 // flags |= kAuthorizationFlagPreAuthorize;
555 status
= AuthorizationCopyRights(authorization
,
557 kAuthorizationEmptyEnvironment
,
560 if (status
!= errAuthorizationSuccess
) {
564 if (items
[0].flags
!= 0) SCLog(TRUE
, LOG_DEBUG
, CFSTR("***** success w/flags (%u) != 0"), items
[0].flags
);
569 typedef Boolean (*helperFunction
) (void *info
,
575 static const struct helper
{
577 const char *commandName
;
578 Boolean needsAuthorization
;
582 { SCHELPER_MSG_AUTH
, "AUTH", FALSE
, do_Auth
, NULL
},
584 { SCHELPER_MSG_PREFS_OPEN
, "PREFS open", FALSE
, do_prefs_Open
, NULL
},
585 { SCHELPER_MSG_PREFS_ACCESS
, "PREFS access", TRUE
, do_prefs_Access
, NULL
},
586 { SCHELPER_MSG_PREFS_LOCK
, "PREFS lock", TRUE
, do_prefs_Lock
, (void *)FALSE
},
587 { SCHELPER_MSG_PREFS_LOCKWAIT
, "PREFS lock/wait", TRUE
, do_prefs_Lock
, (void *)TRUE
},
588 { SCHELPER_MSG_PREFS_COMMIT
, "PREFS commit", TRUE
, do_prefs_Commit
, NULL
},
589 { SCHELPER_MSG_PREFS_APPLY
, "PREFS apply", TRUE
, do_prefs_Apply
, NULL
},
590 { SCHELPER_MSG_PREFS_UNLOCK
, "PREFS unlock", FALSE
, do_prefs_Unlock
, NULL
},
591 { SCHELPER_MSG_PREFS_CLOSE
, "PREFS close", FALSE
, do_prefs_Close
, NULL
},
593 { SCHELPER_MSG_INTERFACE_REFRESH
, "INTERFACE refresh", TRUE
, do_interface_refresh
, NULL
},
595 { SCHELPER_MSG_KEYCHAIN_COPY
, "KEYCHAIN copy", TRUE
, do_keychain_copy
, NULL
},
596 { SCHELPER_MSG_KEYCHAIN_EXISTS
, "KEYCHAIN exists", TRUE
, do_keychain_exists
, NULL
},
597 { SCHELPER_MSG_KEYCHAIN_REMOVE
, "KEYCHAIN remove", TRUE
, do_keychain_remove
, NULL
},
598 { SCHELPER_MSG_KEYCHAIN_SET
, "KEYCHAIN set", TRUE
, do_keychain_set
, NULL
},
600 { SCHELPER_MSG_EXIT
, "EXIT", FALSE
, do_Exit
, NULL
}
602 #define nHELPERS (sizeof(helpers)/sizeof(struct helper))
610 for (i
= 0; i
< (int)nHELPERS
; i
++) {
611 if (helpers
[i
].command
== command
) {
621 main(int argc
, char **argv
)
626 openlog("SCHelper", LOG_CONS
|LOG_PID
, LOG_DAEMON
);
628 if (geteuid() != 0) {
629 (void)__SCHelper_txMessage(STDOUT_FILENO
, EACCES
, NULL
);
633 // send "we are here" message
634 if (!__SCHelper_txMessage(STDOUT_FILENO
, 0, NULL
)) {
647 if (!__SCHelper_rxMessage(STDIN_FILENO
, &command
, &data
)) {
648 SCLog(TRUE
, LOG_ERR
, CFSTR("no command"));
653 i
= findHelper(command
);
655 SCLog(TRUE
, LOG_ERR
, CFSTR("received unknown command : %u"), command
);
660 SCLog(TRUE
, LOG_DEBUG
,
661 CFSTR("processing command \"%s\"%s"),
662 helpers
[i
].commandName
,
663 (data
!= NULL
) ? " w/data" : "");
665 status
= kSCStatusOK
;
668 if (helpers
[i
].needsAuthorization
&& !hasAuthorization()) {
669 SCLog(TRUE
, LOG_DEBUG
,
670 CFSTR("command \"%s\" : not authorized"),
671 helpers
[i
].commandName
);
672 status
= kSCStatusAccessError
;
675 if (status
== kSCStatusOK
) {
676 ok
= (*helpers
[i
].func
)(helpers
[i
].info
, data
, &status
, &reply
);
679 SCLog(TRUE
, LOG_DEBUG
,
680 CFSTR("sending status %u%s"),
682 (reply
!= NULL
) ? " w/reply" : "");
684 if (!__SCHelper_txMessage(STDOUT_FILENO
, status
, reply
)) {
698 if (authorization
!= NULL
) {
699 AuthorizationFree(authorization
, kAuthorizationFlagDefaults
);
700 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);