2 * Copyright (c) 2005-2009 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@
27 #include <sys/types.h>
29 #include <CoreFoundation/CoreFoundation.h>
30 #include <CoreFoundation/CFRuntime.h>
31 #include <SystemConfiguration/SystemConfiguration.h>
32 #include <SystemConfiguration/SCPrivate.h>
33 #include <SystemConfiguration/SCValidation.h>
37 #include "SCPreferencesInternal.h"
38 #include "SCHelper_client.h"
39 #include "helper_comm.h"
45 __private_extern__
int
46 getgrnam_r(const char *name
, __unused
struct group
*grp
, __unused
char *buf
, __unused
size_t bufsize
, struct group
**grpP
)
48 *grpP
= getgrnam(name
);
49 return (*grpP
== NULL
) ? -1 : 0;
51 #endif // TARGET_OS_IPHONE
55 #pragma mark Session managment
58 typedef const struct __SCHelperSession
* SCHelperSessionRef
;
62 // base CFType information
66 AuthorizationRef authorization
;
70 #endif // TARGET_OS_IPHONE
73 SCPreferencesRef prefs
;
75 } SCHelperSessionPrivate
, *SCHelperSessionPrivateRef
;
78 static AuthorizationRef
79 __SCHelperSessionGetAuthorization(SCHelperSessionRef session
)
81 SCHelperSessionPrivateRef sessionPrivate
= (SCHelperSessionPrivateRef
)session
;
83 return sessionPrivate
->authorization
;
88 __SCHelperSessionSetAuthorization(SCHelperSessionRef session
, CFTypeRef authorizationData
)
91 SCHelperSessionPrivateRef sessionPrivate
= (SCHelperSessionPrivateRef
)session
;
94 if (sessionPrivate
->authorization
!= NULL
) {
95 AuthorizationFree(sessionPrivate
->authorization
, kAuthorizationFlagDefaults
);
96 // AuthorizationFree(sessionPrivate->authorization, kAuthorizationFlagDestroyRights);
97 sessionPrivate
->authorization
= NULL
;
100 if (isA_CFData(authorizationData
)) {
101 AuthorizationExternalForm extForm
;
103 if (CFDataGetLength(authorizationData
) == sizeof(extForm
.bytes
)) {
106 bcopy(CFDataGetBytePtr(authorizationData
), extForm
.bytes
, sizeof(extForm
.bytes
));
107 err
= AuthorizationCreateFromExternalForm(&extForm
,
108 &sessionPrivate
->authorization
);
109 if (err
!= errAuthorizationSuccess
) {
111 CFSTR("AuthorizationCreateFromExternalForm() failed: status = %d"),
113 sessionPrivate
->authorization
= NULL
;
118 #else // !TARGET_OS_IPHONE
119 if (sessionPrivate
->authorization
!= NULL
) {
120 CFRelease(sessionPrivate
->authorization
);
121 sessionPrivate
->authorization
= NULL
;
124 if (isA_CFString(authorizationData
)) {
125 sessionPrivate
->authorization
= (void *)CFRetain(authorizationData
);
127 #endif // !TARGET_OS_IPHONE
135 __SCHelperSessionGetCredentials(SCHelperSessionRef session
, uid_t
*euid
, gid_t
*egid
)
137 SCHelperSessionPrivateRef sessionPrivate
= (SCHelperSessionPrivateRef
)session
;
139 if (euid
!= NULL
) *euid
= sessionPrivate
->peer_euid
;
140 if (egid
!= NULL
) *egid
= sessionPrivate
->peer_egid
;
146 __SCHelperSessionSetCredentials(SCHelperSessionRef session
, uid_t euid
, gid_t egid
)
148 SCHelperSessionPrivateRef sessionPrivate
= (SCHelperSessionPrivateRef
)session
;
150 sessionPrivate
->peer_euid
= euid
;
151 sessionPrivate
->peer_egid
= egid
;
154 #endif // TARGET_OS_IPHONE
156 static SCPreferencesRef
157 __SCHelperSessionGetPreferences(SCHelperSessionRef session
)
159 SCHelperSessionPrivateRef sessionPrivate
= (SCHelperSessionPrivateRef
)session
;
161 return sessionPrivate
->prefs
;
166 __SCHelperSessionSetPreferences(SCHelperSessionRef session
, SCPreferencesRef prefs
)
168 SCHelperSessionPrivateRef sessionPrivate
= (SCHelperSessionPrivateRef
)session
;
173 if (sessionPrivate
->prefs
!= NULL
) {
174 CFRelease(sessionPrivate
->prefs
);
176 sessionPrivate
->prefs
= prefs
;
182 static CFStringRef
__SCHelperSessionCopyDescription (CFTypeRef cf
);
183 static void __SCHelperSessionDeallocate (CFTypeRef cf
);
186 static CFTypeID __kSCHelperSessionTypeID
= _kCFRuntimeNotATypeID
;
187 static Boolean debug
= FALSE
;
188 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
189 static CFRunLoopRef main_runLoop
= NULL
;
190 static CFMutableSetRef sessions
= NULL
;
191 static int sessions_closed
= 0; // count of sessions recently closed
192 static pthread_mutex_t sessions_lock
= PTHREAD_MUTEX_INITIALIZER
;
195 static const CFRuntimeClass __SCHelperSessionClass
= {
197 "SCHelperSession", // className
200 __SCHelperSessionDeallocate
, // dealloc
203 NULL
, // copyFormattingDesc
204 __SCHelperSessionCopyDescription
// copyDebugDesc
209 __SCHelperSessionCopyDescription(CFTypeRef cf
)
211 CFAllocatorRef allocator
= CFGetAllocator(cf
);
212 CFMutableStringRef result
;
213 SCHelperSessionPrivateRef sessionPrivate
= (SCHelperSessionPrivateRef
)cf
;
215 result
= CFStringCreateMutable(allocator
, 0);
216 CFStringAppendFormat(result
, NULL
, CFSTR("<SCHelperSession %p [%p]> {"), cf
, allocator
);
217 CFStringAppendFormat(result
, NULL
, CFSTR("authorization = %p"), sessionPrivate
->authorization
);
218 CFStringAppendFormat(result
, NULL
, CFSTR(", prefs = %p"), sessionPrivate
->prefs
);
219 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
226 __SCHelperSessionDeallocate(CFTypeRef cf
)
228 SCHelperSessionPrivateRef sessionPrivate
= (SCHelperSessionPrivateRef
)cf
;
231 __SCHelperSessionSetAuthorization((SCHelperSessionRef
)sessionPrivate
, NULL
);
232 __SCHelperSessionSetPreferences ((SCHelperSessionRef
)sessionPrivate
, NULL
);
234 // we no longer need/want to track this session
235 pthread_mutex_lock(&sessions_lock
);
236 CFSetRemoveValue(sessions
, sessionPrivate
);
238 pthread_mutex_unlock(&sessions_lock
);
239 CFRunLoopWakeUp(main_runLoop
);
246 __SCHelperSessionInitialize(void)
248 __kSCHelperSessionTypeID
= _CFRuntimeRegisterClass(&__SCHelperSessionClass
);
253 static SCHelperSessionRef
254 __SCHelperSessionCreate(CFAllocatorRef allocator
)
256 SCHelperSessionPrivateRef sessionPrivate
;
259 /* initialize runtime */
260 pthread_once(&initialized
, __SCHelperSessionInitialize
);
262 /* allocate session */
263 size
= sizeof(SCHelperSessionPrivate
) - sizeof(CFRuntimeBase
);
264 sessionPrivate
= (SCHelperSessionPrivateRef
)_CFRuntimeCreateInstance(allocator
,
265 __kSCHelperSessionTypeID
,
268 if (sessionPrivate
== NULL
) {
272 sessionPrivate
->authorization
= NULL
;
274 sessionPrivate
->peer_euid
= 0;
275 sessionPrivate
->peer_egid
= 0;
276 #endif // TARGET_OS_IPHONE
277 sessionPrivate
->prefs
= NULL
;
279 // keep track this session
280 pthread_mutex_lock(&sessions_lock
);
281 if (sessions
== NULL
) {
282 sessions
= CFSetCreateMutable(NULL
, 0, NULL
); // create a non-retaining set
284 CFSetAddValue(sessions
, sessionPrivate
);
285 pthread_mutex_unlock(&sessions_lock
);
287 return (SCHelperSessionRef
)sessionPrivate
;
298 * (out) status = SCError()
302 do_Exit(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
311 * (in) data = AuthorizationExternalForm
312 * (out) status = OSStatus
316 do_Auth(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
320 #if !TARGET_OS_IPHONE
322 ok
= __SCHelperSessionSetAuthorization(session
, data
);
324 #else //!TARGET_OS_IPHONE
326 CFStringRef authorizationInfo
= NULL
;
328 if ((data
!= NULL
) && !_SCUnserializeString(&authorizationInfo
, data
, NULL
, 0)) {
332 if (!isA_CFString(authorizationInfo
)) {
333 if (authorizationInfo
!= NULL
) CFRelease(authorizationInfo
);
337 ok
= __SCHelperSessionSetAuthorization(session
, authorizationInfo
);
338 if (authorizationInfo
!= NULL
) CFRelease(authorizationInfo
);
340 #endif // !TARGET_OS_IPHONE
342 *status
= ok
? 0 : 1;
347 #if !TARGET_OS_IPHONE
351 * SCHELPER_MSG_KEYCHAIN_COPY
352 * (in) data = unique_id
353 * (out) status = SCError()
354 * (out) reply = password
357 do_keychain_copy(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
359 SCPreferencesRef prefs
;
360 CFStringRef unique_id
= NULL
;
362 if ((data
!= NULL
) && !_SCUnserializeString(&unique_id
, data
, NULL
, 0)) {
366 if (!isA_CFString(unique_id
)) {
370 prefs
= __SCHelperSessionGetPreferences(session
);
371 *reply
= _SCPreferencesSystemKeychainPasswordItemCopy(prefs
, unique_id
);
372 CFRelease(unique_id
);
373 if (*reply
== NULL
) {
382 * SCHELPER_MSG_KEYCHAIN_EXISTS
383 * (in) data = unique_id
384 * (out) status = SCError()
388 do_keychain_exists(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
391 SCPreferencesRef prefs
;
392 CFStringRef unique_id
= NULL
;
394 if ((data
!= NULL
) && !_SCUnserializeString(&unique_id
, data
, NULL
, 0)) {
398 if (!isA_CFString(unique_id
)) {
399 if (unique_id
!= NULL
) CFRelease(unique_id
);
403 prefs
= __SCHelperSessionGetPreferences(session
);
404 ok
= _SCPreferencesSystemKeychainPasswordItemExists(prefs
, unique_id
);
405 CFRelease(unique_id
);
415 * SCHELPER_MSG_KEYCHAIN_REMOVE
416 * (in) data = unique_id
417 * (out) status = SCError()
421 do_keychain_remove(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
424 SCPreferencesRef prefs
;
425 CFStringRef unique_id
= NULL
;
427 if ((data
!= NULL
) && !_SCUnserializeString(&unique_id
, data
, NULL
, 0)) {
431 if (!isA_CFString(unique_id
)) {
432 if (unique_id
!= NULL
) CFRelease(unique_id
);
436 prefs
= __SCHelperSessionGetPreferences(session
);
437 ok
= _SCPreferencesSystemKeychainPasswordItemRemove(prefs
, unique_id
);
438 CFRelease(unique_id
);
448 * SCHELPER_MSG_KEYCHAIN_SET
449 * (in) data = options dictionary
450 * (out) status = SCError()
454 do_keychain_set(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
457 CFStringRef description
;
458 CFArrayRef executablePaths
= NULL
;
461 CFDictionaryRef options
= NULL
;
463 SCPreferencesRef prefs
;
464 CFStringRef unique_id
;
466 if ((data
!= NULL
) && !_SCUnserialize((CFPropertyListRef
*)&options
, data
, NULL
, 0)) {
470 if (!isA_CFDictionary(options
)) {
471 if (options
!= NULL
) CFRelease(options
);
475 if (CFDictionaryGetValueIfPresent(options
,
476 kSCKeychainOptionsAllowedExecutables
,
477 (const void **)&executablePaths
)) {
478 CFMutableArrayRef executableURLs
;
481 CFMutableDictionaryRef newOptions
;
483 executableURLs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
484 n
= CFArrayGetCount(executablePaths
);
485 for (i
= 0; i
< n
; i
++) {
489 path
= CFArrayGetValueAtIndex(executablePaths
, i
);
490 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
491 CFDataGetBytePtr(path
),
492 CFDataGetLength(path
),
495 CFArrayAppendValue(executableURLs
, url
);
500 newOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, options
);
501 CFDictionarySetValue(newOptions
, kSCKeychainOptionsAllowedExecutables
, executableURLs
);
502 CFRelease(executableURLs
);
505 options
= newOptions
;
508 unique_id
= CFDictionaryGetValue(options
, kSCKeychainOptionsUniqueID
);
509 label
= CFDictionaryGetValue(options
, kSCKeychainOptionsLabel
);
510 description
= CFDictionaryGetValue(options
, kSCKeychainOptionsDescription
);
511 account
= CFDictionaryGetValue(options
, kSCKeychainOptionsAccount
);
512 password
= CFDictionaryGetValue(options
, kSCKeychainOptionsPassword
);
514 prefs
= __SCHelperSessionGetPreferences(session
);
515 ok
= _SCPreferencesSystemKeychainPasswordItemSet(prefs
,
531 #endif // !TARGET_OS_IPHONE
535 * SCHELPER_MSG_INTERFACE_REFRESH
537 * (out) status = SCError()
541 do_interface_refresh(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
543 CFStringRef ifName
= NULL
;
546 if ((data
!= NULL
) && !_SCUnserializeString(&ifName
, data
, NULL
, 0)) {
547 SCLog(TRUE
, LOG_ERR
, CFSTR("interface name not valid"));
551 if (!isA_CFString(ifName
)) {
552 SCLog(TRUE
, LOG_ERR
, CFSTR("interface name not valid"));
553 if (ifName
!= NULL
) CFRelease(ifName
);
557 ok
= _SCNetworkInterfaceForceConfigurationRefresh(ifName
);
569 * (in) data = prefsID
570 * (out) status = SCError()
574 do_prefs_Open(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
578 SCPreferencesRef prefs
= __SCHelperSessionGetPreferences(session
);
579 CFDictionaryRef prefsInfo
= NULL
;
581 CFStringRef prefsName
;
587 if ((data
!= NULL
) && !_SCUnserialize((CFPropertyListRef
*)&prefsInfo
, data
, NULL
, 0)) {
588 SCLog(TRUE
, LOG_ERR
, CFSTR("data not valid, %@"), data
);
592 if ((prefsInfo
== NULL
) || !isA_CFDictionary(prefsInfo
)) {
593 SCLog(TRUE
, LOG_ERR
, CFSTR("info not valid"));
594 if (prefsInfo
!= NULL
) CFRelease(prefsInfo
);
598 // get [optional] prefsID
599 prefsID
= CFDictionaryGetValue(prefsInfo
, CFSTR("prefsID"));
600 prefsID
= isA_CFString(prefsID
);
601 if (prefsID
!= NULL
) {
602 if (CFStringHasPrefix(prefsID
, CFSTR("/")) ||
603 CFStringHasPrefix(prefsID
, CFSTR("../")) ||
604 CFStringHasSuffix(prefsID
, CFSTR("/..")) ||
605 (CFStringFind(prefsID
, CFSTR("/../"), 0).location
!= kCFNotFound
)) {
606 // if we're trying to escape from the preferences directory
607 SCLog(TRUE
, LOG_ERR
, CFSTR("prefsID (%@) not valid"), prefsID
);
608 CFRelease(prefsInfo
);
609 *status
= kSCStatusInvalidArgument
;
614 // get preferences session "name"
615 name
= CFDictionaryGetValue(prefsInfo
, CFSTR("name"));
616 if (!isA_CFString(name
)) {
617 SCLog(TRUE
, LOG_ERR
, CFSTR("session \"name\" not valid"));
618 CFRelease(prefsInfo
);
623 pid
= CFDictionaryGetValue(prefsInfo
, CFSTR("PID"));
624 if (!isA_CFNumber(pid
)) {
625 SCLog(TRUE
, LOG_ERR
, CFSTR("PID not valid"));
626 CFRelease(prefsInfo
);
630 // build [helper] preferences "name" (used for debugging) and estabish
631 // a preferences session.
632 prefsName
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:%@"), pid
, name
);
633 prefs
= SCPreferencesCreate(NULL
, prefsName
, prefsID
);
634 CFRelease(prefsName
);
635 CFRelease(prefsInfo
);
637 __SCHelperSessionSetPreferences(session
, prefs
);
651 * (out) status = SCError()
652 * (out) reply = current signature + current preferences
655 do_prefs_Access(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
658 SCPreferencesRef prefs
= __SCHelperSessionGetPreferences(session
);
665 signature
= SCPreferencesGetSignature(prefs
);
666 if (signature
!= NULL
) {
667 const void * dictKeys
[2];
668 const void * dictVals
[2];
669 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
670 CFDictionaryRef replyDict
;
672 dictKeys
[0] = CFSTR("signature");
673 dictVals
[0] = signature
;
675 dictKeys
[1] = CFSTR("preferences");
676 dictVals
[1] = prefsPrivate
->prefs
;
678 replyDict
= CFDictionaryCreate(NULL
,
679 (const void **)&dictKeys
,
680 (const void **)&dictVals
,
681 sizeof(dictKeys
)/sizeof(dictKeys
[0]),
682 &kCFTypeDictionaryKeyCallBacks
,
683 &kCFTypeDictionaryValueCallBacks
);
685 ok
= _SCSerialize(replyDict
, reply
, NULL
, NULL
);
686 CFRelease(replyDict
);
700 * (in) data = client prefs signature (NULL if check not needed)
701 * (out) status = SCError()
705 do_prefs_Lock(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
707 CFDataRef clientSignature
= (CFDataRef
)data
;
709 SCPreferencesRef prefs
= __SCHelperSessionGetPreferences(session
);
710 Boolean wait
= (info
== (void *)FALSE
) ? FALSE
: TRUE
;
716 ok
= SCPreferencesLock(prefs
, wait
);
722 if (clientSignature
!= NULL
) {
723 CFDataRef serverSignature
;
725 serverSignature
= SCPreferencesGetSignature(prefs
);
726 if (!CFEqual(clientSignature
, serverSignature
)) {
727 (void)SCPreferencesUnlock(prefs
);
728 *status
= kSCStatusStale
;
738 * (in) data = new preferences (NULL if commit w/no changes)
739 * (out) status = SCError()
740 * (out) reply = new signature
743 do_prefs_Commit(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
746 SCPreferencesRef prefs
= __SCHelperSessionGetPreferences(session
);
753 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
755 if (prefsPrivate
->prefs
!= NULL
) {
756 CFRelease(prefsPrivate
->prefs
);
759 ok
= _SCUnserialize((CFPropertyListRef
*)&prefsPrivate
->prefs
, data
, NULL
, 0);
764 prefsPrivate
->accessed
= TRUE
;
765 prefsPrivate
->changed
= TRUE
;
768 ok
= SCPreferencesCommitChanges(prefs
);
770 *reply
= SCPreferencesGetSignature(prefs
);
783 * (out) status = SCError()
787 do_prefs_Apply(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
790 SCPreferencesRef prefs
= __SCHelperSessionGetPreferences(session
);
796 ok
= SCPreferencesApplyChanges(prefs
);
808 * (out) status = SCError()
812 do_prefs_Unlock(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
815 SCPreferencesRef prefs
= __SCHelperSessionGetPreferences(session
);
821 ok
= SCPreferencesUnlock(prefs
);
833 * (out) status = SCError()
837 do_prefs_Close(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
839 SCPreferencesRef prefs
= __SCHelperSessionGetPreferences(session
);
845 __SCHelperSessionSetPreferences(session
, NULL
);
854 * (out) status = kSCStatusOK
858 do_prefs_Synchronize(SCHelperSessionRef session
, void *info
, CFDataRef data
, uint32_t *status
, CFDataRef
*reply
)
860 SCPreferencesRef prefs
= __SCHelperSessionGetPreferences(session
);
866 SCPreferencesSynchronize(prefs
);
867 *status
= kSCStatusOK
;
873 #pragma mark Process commands
877 hasAuthorization(SCHelperSessionRef session
)
879 AuthorizationRef authorization
= __SCHelperSessionGetAuthorization(session
);
881 #if !TARGET_OS_IPHONE
882 AuthorizationFlags flags
;
883 AuthorizationItem items
[1];
884 AuthorizationRights rights
;
887 if (authorization
== NULL
) {
891 items
[0].name
= "system.preferences";
892 items
[0].value
= NULL
;
893 items
[0].valueLength
= 0;
896 rights
.count
= sizeof(items
) / sizeof(items
[0]);
897 rights
.items
= items
;
899 flags
= kAuthorizationFlagDefaults
;
900 flags
|= kAuthorizationFlagExtendRights
;
901 flags
|= kAuthorizationFlagInteractionAllowed
;
902 // flags |= kAuthorizationFlagPartialRights;
903 // flags |= kAuthorizationFlagPreAuthorize;
905 status
= AuthorizationCopyRights(authorization
,
907 kAuthorizationEmptyEnvironment
,
910 if (status
!= errAuthorizationSuccess
) {
913 #else // !TARGET_OS_IPHONE
917 if (authorization
== NULL
) {
921 __SCHelperSessionGetCredentials(session
, &peer_euid
, &peer_egid
);
922 if ((peer_euid
!= 0) && (peer_egid
!= 0)) {
923 static gid_t mobile_gid
= -1;
926 * if peer is not user "root" nor group "wheel" then
927 * we check to see if we are one of the authorized
930 if (mobile_gid
== -1) {
935 if (getgrnam_r("mobile", &grp
, buffer
, sizeof(buffer
), &grpP
) == 0) {
936 mobile_gid
= grpP
->gr_gid
;
940 if (peer_egid
!= mobile_gid
) {
944 #endif // !TARGET_OS_IPHONE
946 // if (items[0].flags != 0) SCLog(TRUE, LOG_DEBUG, CFSTR("***** success w/flags (%u) != 0"), items[0].flags);
951 typedef Boolean (*helperFunction
) (SCHelperSessionRef session
,
958 static const struct helper
{
960 const char *commandName
;
961 Boolean needsAuthorization
;
965 { SCHELPER_MSG_AUTH
, "AUTH", FALSE
, do_Auth
, NULL
},
967 { SCHELPER_MSG_PREFS_OPEN
, "PREFS open", FALSE
, do_prefs_Open
, NULL
},
968 { SCHELPER_MSG_PREFS_ACCESS
, "PREFS access", TRUE
, do_prefs_Access
, NULL
},
969 { SCHELPER_MSG_PREFS_LOCK
, "PREFS lock", TRUE
, do_prefs_Lock
, (void *)FALSE
},
970 { SCHELPER_MSG_PREFS_LOCKWAIT
, "PREFS lock/wait", TRUE
, do_prefs_Lock
, (void *)TRUE
},
971 { SCHELPER_MSG_PREFS_COMMIT
, "PREFS commit", TRUE
, do_prefs_Commit
, NULL
},
972 { SCHELPER_MSG_PREFS_APPLY
, "PREFS apply", TRUE
, do_prefs_Apply
, NULL
},
973 { SCHELPER_MSG_PREFS_UNLOCK
, "PREFS unlock", FALSE
, do_prefs_Unlock
, NULL
},
974 { SCHELPER_MSG_PREFS_CLOSE
, "PREFS close", FALSE
, do_prefs_Close
, NULL
},
975 { SCHELPER_MSG_PREFS_SYNCHRONIZE
, "PREFS synchronize", FALSE
, do_prefs_Synchronize
, NULL
},
977 { SCHELPER_MSG_INTERFACE_REFRESH
, "INTERFACE refresh", TRUE
, do_interface_refresh
, NULL
},
979 #if !TARGET_OS_IPHONE
980 { SCHELPER_MSG_KEYCHAIN_COPY
, "KEYCHAIN copy", TRUE
, do_keychain_copy
, NULL
},
981 { SCHELPER_MSG_KEYCHAIN_EXISTS
, "KEYCHAIN exists", TRUE
, do_keychain_exists
, NULL
},
982 { SCHELPER_MSG_KEYCHAIN_REMOVE
, "KEYCHAIN remove", TRUE
, do_keychain_remove
, NULL
},
983 { SCHELPER_MSG_KEYCHAIN_SET
, "KEYCHAIN set", TRUE
, do_keychain_set
, NULL
},
984 #endif // !TARGET_OS_IPHONE
986 { SCHELPER_MSG_EXIT
, "EXIT", FALSE
, do_Exit
, NULL
}
988 #define nHELPERS (sizeof(helpers)/sizeof(struct helper))
992 findHelper(uint32_t command
)
996 for (i
= 0; i
< (int)nHELPERS
; i
++) {
997 if (helpers
[i
].command
== command
) {
1007 process_command(SCHelperSessionRef session
, int fd
, int *err
)
1009 uint32_t command
= 0;
1010 CFDataRef data
= NULL
;
1013 CFDataRef reply
= NULL
;
1014 uint32_t status
= kSCStatusOK
;
1016 if (!__SCHelper_rxMessage(fd
, &command
, &data
)) {
1017 SCLog(TRUE
, LOG_ERR
, CFSTR("no command"));
1022 i
= findHelper(command
);
1024 SCLog(TRUE
, LOG_ERR
, CFSTR("received unknown command : %u"), command
);
1029 SCLog(debug
, LOG_DEBUG
,
1030 CFSTR("processing command \"%s\"%s"),
1031 helpers
[i
].commandName
,
1032 (data
!= NULL
) ? " w/data" : "");
1034 if (helpers
[i
].needsAuthorization
&& !hasAuthorization(session
)) {
1035 SCLog(debug
, LOG_DEBUG
,
1036 CFSTR("command \"%s\" : not authorized"),
1037 helpers
[i
].commandName
);
1038 status
= kSCStatusAccessError
;
1041 if (status
== kSCStatusOK
) {
1042 ok
= (*helpers
[i
].func
)(session
, helpers
[i
].info
, data
, &status
, &reply
);
1045 if ((status
!= -1) || (reply
!= NULL
)) {
1046 SCLog(debug
, LOG_DEBUG
,
1047 CFSTR("sending status %u%s"),
1049 (reply
!= NULL
) ? " w/reply" : "");
1051 if (!__SCHelper_txMessage(fd
, status
, reply
)) {
1064 if (reply
!= NULL
) {
1073 #pragma mark Main loop
1077 readCallback(CFSocketRef s
,
1078 CFSocketCallBackType callbackType
,
1083 CFSocketNativeHandle fd
;
1086 SCHelperSessionRef session
= (SCHelperSessionRef
)info
;
1088 if (callbackType
!= kCFSocketReadCallBack
) {
1089 SCLog(TRUE
, LOG_ERR
, CFSTR("readCallback w/callbackType = %d"), callbackType
);
1093 fd
= CFSocketGetNative(s
);
1094 ok
= process_command(session
, fd
, &err
);
1096 SCLog(debug
, LOG_DEBUG
, CFSTR("per-session socket : invalidate fd %d"), fd
);
1097 CFSocketInvalidate(s
);
1105 newHelper(void *arg
)
1107 CFSocketContext context
= { 0, NULL
, CFRetain
, CFRelease
, CFCopyDescription
};
1108 CFSocketNativeHandle fd
= (CFSocketNativeHandle
)(intptr_t)arg
;
1109 CFRunLoopSourceRef rls
;
1110 SCHelperSessionRef session
;
1113 #if TARGET_OS_IPHONE
1116 #endif // TARGET_OS_IPHONE
1118 session
= __SCHelperSessionCreate(NULL
);
1119 #if TARGET_OS_IPHONE
1120 if (getpeereid(fd
, &peer_euid
, &peer_egid
) == 0) {
1121 __SCHelperSessionSetCredentials(session
, peer_euid
, peer_egid
);
1123 SCLog(TRUE
, LOG_ERR
, CFSTR("getpeereid() failed: %s"), strerror(errno
));
1125 #endif // TARGET_OS_IPHONE
1127 context
.info
= (void *)session
;
1128 sock
= CFSocketCreateWithNative(NULL
,
1130 kCFSocketReadCallBack
,
1135 rls
= CFSocketCreateRunLoopSource(NULL
, sock
, 0);
1138 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
1147 acceptCallback(CFSocketRef s
,
1148 CFSocketCallBackType callbackType
,
1153 CFSocketNativeHandle fd
;
1154 pthread_attr_t tattr
;
1158 if (callbackType
!= kCFSocketAcceptCallBack
) {
1159 SCLog(TRUE
, LOG_ERR
, CFSTR("acceptCallback w/callbackType = %d"), callbackType
);
1163 if ((data
== NULL
) ||
1164 ((fd
= *((CFSocketNativeHandle
*)data
)) == -1)) {
1165 SCLog(TRUE
, LOG_ERR
, CFSTR("accept w/no FD"));
1169 if (setsockopt(fd
, SOL_SOCKET
, SO_NOSIGPIPE
, (const void *)&yes
, sizeof(yes
)) == -1) {
1170 SCLog(TRUE
, LOG_ERR
, CFSTR("setsockopt(SO_NOSIGPIPE) failed: %s"), strerror(errno
));
1174 // start per-session thread
1175 pthread_attr_init(&tattr
);
1176 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
1177 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
1178 pthread_attr_setstacksize(&tattr
, 96 * 1024); // each thread gets a 96K stack
1179 pthread_create(&tid
, &tattr
, newHelper
, (void *)(intptr_t)fd
);
1180 pthread_attr_destroy(&tattr
);
1189 static const struct option longopts
[] = {
1190 { "debug", no_argument
, 0, 'd' },
1196 main(int argc
, char **argv
)
1198 Boolean done
= FALSE
;
1201 launch_data_t l_listeners
;
1202 launch_data_t l_msg
;
1203 launch_data_t l_reply
;
1204 launch_data_t l_sockets
;
1205 launch_data_type_t l_type
;
1211 openlog("SCHelper", LOG_CONS
|LOG_PID
, LOG_DAEMON
);
1213 // process any arguments
1214 while ((opt
= getopt_long(argc
, argv
, "d", longopts
, &opti
)) != -1) {
1220 // if (strcmp(longopts[opti].name, "debug") == 1) {
1225 SCLog(TRUE
, LOG_ERR
,
1226 CFSTR("ignoring unknown or ambiguous command line option"));
1233 if (geteuid() != 0) {
1234 SCLog(TRUE
, LOG_ERR
, CFSTR("%s"), strerror(EACCES
));
1238 main_runLoop
= CFRunLoopGetCurrent();
1240 l_msg
= launch_data_new_string(LAUNCH_KEY_CHECKIN
);
1241 l_reply
= launch_msg(l_msg
);
1242 launch_data_free(l_msg
);
1243 l_type
= (l_reply
!= NULL
) ? launch_data_get_type(l_reply
) : 0;
1244 if (l_type
!= LAUNCH_DATA_DICTIONARY
) {
1245 SCLog(TRUE
, LOG_ERR
,
1246 CFSTR("SCHelper: error w/launchd " LAUNCH_KEY_CHECKIN
" dictionary (%p, %d)"),
1253 l_sockets
= launch_data_dict_lookup(l_reply
, LAUNCH_JOBKEY_SOCKETS
);
1254 l_type
= (l_sockets
!= NULL
) ? launch_data_get_type(l_sockets
) : 0;
1255 if (l_type
!= LAUNCH_DATA_DICTIONARY
) {
1256 SCLog(TRUE
, LOG_ERR
,
1257 CFSTR("SCHelper: error w/" LAUNCH_JOBKEY_SOCKETS
" (%p, %d)"),
1264 l_listeners
= launch_data_dict_lookup(l_sockets
, "Listeners");
1265 l_type
= (l_listeners
!= NULL
) ? launch_data_get_type(l_listeners
) : 0;
1266 if (l_type
!= LAUNCH_DATA_ARRAY
) {
1267 SCLog(TRUE
, LOG_ERR
, CFSTR("SCHelper: error w/Listeners (%p, %d)"),
1273 n
= launch_data_array_get_count(l_listeners
);
1274 for (i
= 0; i
< n
; i
++) {
1275 CFSocketNativeHandle fd
;
1277 CFRunLoopSourceRef rls
;
1280 l_fd
= launch_data_array_get_index(l_listeners
, i
);
1281 l_type
= (l_fd
!= NULL
) ? launch_data_get_type(l_fd
) : 0;
1282 if (l_type
!= LAUNCH_DATA_FD
) {
1283 SCLog(TRUE
, LOG_ERR
, CFSTR("SCHelper: error w/Listeners[%d] (%p, %d)"),
1291 fd
= launch_data_get_fd(l_fd
);
1292 sock
= CFSocketCreateWithNative(NULL
,
1294 kCFSocketAcceptCallBack
,
1297 rls
= CFSocketCreateRunLoopSource(NULL
, sock
, 0);
1298 CFRunLoopAddSource(main_runLoop
, rls
, kCFRunLoopDefaultMode
);
1305 if (l_reply
!= NULL
) launch_data_free(l_reply
);
1307 if ((err
!= 0) || (n
== 0)) {
1314 rlStatus
= CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 15.0, TRUE
);
1315 if (rlStatus
== kCFRunLoopRunTimedOut
) {
1316 pthread_mutex_lock(&sessions_lock
);
1317 done
= ((sessions
!= NULL
) &&
1318 (CFSetGetCount(sessions
) == 0) &&
1319 (sessions_closed
== 0));
1320 sessions_closed
= 0;
1321 pthread_mutex_unlock(&sessions_lock
);