2 * Copyright (c) 2012-2014 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@
29 #include <AssertMacros.h>
30 #include <SecureObjectSync/SOSCloudCircle.h>
31 #include <SecureObjectSync/SOSCloudCircleInternal.h>
32 #include <SecureObjectSync/SOSCircle.h>
33 #include <SecureObjectSync/SOSAccount.h>
34 #include <SecureObjectSync/SOSFullPeerInfo.h>
35 #include <SecureObjectSync/SOSPeerInfoCollections.h>
36 #include <SecureObjectSync/SOSInternal.h>
37 #include <Security/SecKeyPriv.h>
38 #include <Security/SecFramework.h>
39 #include <CoreFoundation/CFXPCBridge.h>
41 #include <securityd/SecItemServer.h>
43 #include <utilities/SecDispatchRelease.h>
44 #include <utilities/SecCFRelease.h>
45 #include <utilities/SecCFWrappers.h>
46 #include <utilities/SecXPCError.h>
48 #include <utilities/debugging.h>
50 #include <CoreFoundation/CoreFoundation.h>
53 #define MINIMIZE_INCLUDES MINIMIZE_INCLUDES
54 #include <ipc/securityd_client.h>
55 #include <securityd/spi.h>
57 #include "SOSRegressionUtilities.h"
60 const char * kSOSCCCircleChangedNotification
= "com.apple.security.secureobjectsync.circlechanged";
62 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
64 static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary
, const char *key
, xpc_type_t type
)
66 xpc_object_t value
= xpc_dictionary_get_value(dictionary
, key
);
68 return value
&& (xpc_get_type(value
) == type
);
71 SOSCCStatus
SOSCCThisDeviceIsInCircle(CFErrorRef
*error
)
73 static int counter
= 0;
74 if(counter
++ > 5) secerror("SOSCCThisDeviceIsInCircle!! %d\n", counter
);
75 sec_trace_enter_api(NULL
);
76 sec_trace_return_api(SOSCCStatus
, ^{
77 SOSCCStatus result
= kSOSCCError
;
79 do_if_registered(soscc_ThisDeviceIsInCircle
, error
);
81 xpc_object_t message
= securityd_create_message(kSecXPCOpDeviceInCircle
, error
);
83 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
85 if (response
&& xpc_dictionary_entry_is_type(response
, kSecXPCKeyResult
, XPC_TYPE_INT64
)) {
86 result
= (SOSCCStatus
) xpc_dictionary_get_int64(response
, kSecXPCKeyResult
);
92 if (response
&& securityd_message_no_error(response
, error
))
94 char *desc
= xpc_copy_description(response
);
95 SecCFCreateErrorWithFormat(0, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Remote error occurred/no info: %s"), desc
);
100 xpc_release(response
);
102 xpc_release(message
);
107 }, CFSTR("SOSCCStatus=%d"))
110 static CFStringRef
simple_cfstring_error_request(enum SecXPCOperation op
, CFErrorRef
* error
)
112 __block CFStringRef result
= NULL
;
114 secdebug("sosops","enter - operation: %d", op
);
115 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
116 const char *c_string
= xpc_dictionary_get_string(response
, kSecXPCKeyResult
);
119 result
= CFStringCreateWithBytes(kCFAllocatorDefault
, (const UInt8
*)c_string
, strlen(c_string
), kCFStringEncodingUTF8
, false);
122 return c_string
!= NULL
;
127 static bool simple_bool_error_request(enum SecXPCOperation op
, CFErrorRef
* error
)
129 __block
bool result
= false;
131 secdebug("sosops","enter - operation: %d", op
);
132 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
133 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
139 static CFArrayRef
simple_array_error_request(enum SecXPCOperation op
, CFErrorRef
* error
)
141 __block CFArrayRef result
= false;
143 secdebug("sosops","enter - operation: %d", op
);
144 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
145 xpc_object_t temp_result
= xpc_dictionary_get_value(response
, kSecXPCKeyResult
);
146 result
= _CFXPCCreateCFObjectFromXPCObject(temp_result
);
147 return result
!= NULL
;
152 static int simple_int_error_request(enum SecXPCOperation op
, CFErrorRef
* error
)
154 __block
int result
= 0;
156 secdebug("sosops","enter - operation: %d", op
);
157 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
158 int64_t temp_result
= xpc_dictionary_get_int64(response
, kSecXPCKeyResult
);
159 if ((temp_result
>= INT32_MIN
) && (temp_result
<= INT32_MAX
)) {
160 result
= (int)temp_result
;
167 static CFArrayRef
array_of_info_error_request(enum SecXPCOperation op
, CFErrorRef
* error
)
169 __block CFArrayRef result
= NULL
;
171 secdebug("sosops","enter - operation: %d", op
);
172 securityd_send_sync_and_do(op
, error
, NULL
, ^bool(xpc_object_t response
, CFErrorRef
*error
) {
173 xpc_object_t encoded_array
= xpc_dictionary_get_value(response
, kSecXPCKeyResult
);
174 if (response
&& (NULL
!= encoded_array
)) {
175 result
= CreateArrayOfPeerInfoWithXPCObject(encoded_array
, error
);
177 return result
!= NULL
;
183 static bool info_array_to_bool_error_request(enum SecXPCOperation op
, CFArrayRef peer_infos
, CFErrorRef
* error
)
185 __block
bool result
= false;
187 secdebug("sosops", "enter - operation: %d", op
);
188 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
189 xpc_object_t encoded_peers
= CreateXPCObjectWithArrayOfPeerInfo(peer_infos
, error
);
191 xpc_dictionary_set_value(message
, kSecXPCKeyPeerInfos
, encoded_peers
);
192 return encoded_peers
!= NULL
;
193 }, ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
194 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
200 static bool uint64_t_to_bool_error_request(enum SecXPCOperation op
,
204 __block
bool result
= false;
206 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
207 xpc_dictionary_set_uint64(message
, kSecXPCLimitInMinutes
, number
);
209 }, ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
210 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
217 bool SOSCCRequestToJoinCircle(CFErrorRef
* error
)
219 sec_trace_enter_api(NULL
);
220 sec_trace_return_bool_api(^{
221 do_if_registered(soscc_RequestToJoinCircle
, error
);
223 return simple_bool_error_request(kSecXPCOpRequestToJoin
, error
);
227 bool SOSCCRequestToJoinCircleAfterRestore(CFErrorRef
* error
)
229 sec_trace_enter_api(NULL
);
230 sec_trace_return_bool_api(^{
231 do_if_registered(soscc_RequestToJoinCircleAfterRestore
, error
);
233 return simple_bool_error_request(kSecXPCOpRequestToJoinAfterRestore
, error
);
237 bool SOSCCRequestEnsureFreshParameters(CFErrorRef
* error
)
239 sec_trace_enter_api(NULL
);
240 sec_trace_return_bool_api(^{
241 do_if_registered(soscc_RequestEnsureFreshParameters
, error
);
243 return simple_bool_error_request(kSecXPCOpRequestEnsureFreshParameters
, error
);
247 bool SOSCCResetToOffering(CFErrorRef
* error
)
249 secwarning("SOSCCResetToOffering called");
250 sec_trace_enter_api(NULL
);
251 sec_trace_return_bool_api(^{
252 do_if_registered(soscc_ResetToOffering
, error
);
254 return simple_bool_error_request(kSecXPCOpResetToOffering
, error
);
258 bool SOSCCResetToEmpty(CFErrorRef
* error
)
260 secwarning("SOSCCResetToEmpty called");
261 sec_trace_enter_api(NULL
);
262 sec_trace_return_bool_api(^{
263 do_if_registered(soscc_ResetToEmpty
, error
);
265 return simple_bool_error_request(kSecXPCOpResetToEmpty
, error
);
269 bool SOSCCRemoveThisDeviceFromCircle(CFErrorRef
* error
)
271 sec_trace_enter_api(NULL
);
272 sec_trace_return_bool_api(^{
273 do_if_registered(soscc_RemoveThisDeviceFromCircle
, error
);
275 return simple_bool_error_request(kSecXPCOpRemoveThisDeviceFromCircle
, error
);
279 bool SOSCCBailFromCircle_BestEffort(uint64_t limit_in_seconds
, CFErrorRef
* error
)
281 sec_trace_enter_api(NULL
);
282 sec_trace_return_bool_api(^{
283 do_if_registered(soscc_BailFromCircle
, limit_in_seconds
, error
);
285 return uint64_t_to_bool_error_request(kSecXPCOpBailFromCircle
, limit_in_seconds
, error
);
289 bool SOSCCSignedOut(bool immediate
, CFErrorRef
* error
)
291 uint64_t limit
= strtoul(optarg
, NULL
, 10);
294 return SOSCCRemoveThisDeviceFromCircle(error
);
296 return SOSCCBailFromCircle_BestEffort(limit
, error
);
300 CFArrayRef
SOSCCCopyPeerPeerInfo(CFErrorRef
* error
)
302 sec_trace_enter_api(NULL
);
303 sec_trace_return_api(CFArrayRef
, ^{
304 do_if_registered(soscc_CopyPeerInfo
, error
);
306 return array_of_info_error_request(kSecXPCOpCopyPeerPeerInfo
, error
);
307 }, CFSTR("return=%@"));
310 CFArrayRef
SOSCCCopyConcurringPeerPeerInfo(CFErrorRef
* error
)
312 sec_trace_enter_api(NULL
);
313 sec_trace_return_api(CFArrayRef
, ^{
314 do_if_registered(soscc_CopyConcurringPeerInfo
, error
);
316 return array_of_info_error_request(kSecXPCOpCopyConcurringPeerPeerInfo
, error
);
317 }, CFSTR("return=%@"));
320 CFArrayRef
SOSCCCopyGenerationPeerInfo(CFErrorRef
* error
)
322 sec_trace_enter_api(NULL
);
323 sec_trace_return_api(CFArrayRef
, ^{
324 do_if_registered(soscc_CopyGenerationPeerInfo
, error
);
326 return simple_array_error_request(kSecXPCOpCopyGenerationPeerInfo
, error
);
327 }, CFSTR("return=%@"));
330 CFArrayRef
SOSCCCopyApplicantPeerInfo(CFErrorRef
* error
)
332 sec_trace_enter_api(NULL
);
333 sec_trace_return_api(CFArrayRef
, ^{
334 do_if_registered(soscc_CopyApplicantPeerInfo
, error
);
336 return array_of_info_error_request(kSecXPCOpCopyApplicantPeerInfo
, error
);
337 }, CFSTR("return=%@"));
339 bool SOSCCValidateUserPublic(CFErrorRef
* error
){
340 sec_trace_enter_api(NULL
);
341 sec_trace_return_api(bool, ^{
342 do_if_registered(soscc_ValidateUserPublic
, error
);
344 return simple_bool_error_request(kSecXPCOpValidateUserPublic
, error
);
348 CFArrayRef
SOSCCCopyValidPeerPeerInfo(CFErrorRef
* error
)
350 sec_trace_enter_api(NULL
);
351 sec_trace_return_api(CFArrayRef
, ^{
352 do_if_registered(soscc_CopyValidPeerPeerInfo
, error
);
354 return array_of_info_error_request(kSecXPCOpCopyValidPeerPeerInfo
, error
);
355 }, CFSTR("return=%@"));
358 CFArrayRef
SOSCCCopyNotValidPeerPeerInfo(CFErrorRef
* error
)
360 sec_trace_enter_api(NULL
);
361 sec_trace_return_api(CFArrayRef
, ^{
362 do_if_registered(soscc_CopyNotValidPeerPeerInfo
, error
);
364 return array_of_info_error_request(kSecXPCOpCopyNotValidPeerPeerInfo
, error
);
365 }, CFSTR("return=%@"));
368 CFArrayRef
SOSCCCopyRetirementPeerInfo(CFErrorRef
* error
)
370 sec_trace_enter_api(NULL
);
371 sec_trace_return_api(CFArrayRef
, ^{
372 do_if_registered(soscc_CopyRetirementPeerInfo
, error
);
374 return array_of_info_error_request(kSecXPCOpCopyRetirementPeerInfo
, error
);
375 }, CFSTR("return=%@"));
378 bool SOSCCAcceptApplicants(CFArrayRef applicants
, CFErrorRef
* error
)
380 sec_trace_enter_api(NULL
);
381 sec_trace_return_bool_api(^{
382 do_if_registered(soscc_AcceptApplicants
, applicants
, error
);
384 return info_array_to_bool_error_request(kSecXPCOpAcceptApplicants
, applicants
, error
);
388 bool SOSCCRejectApplicants(CFArrayRef applicants
, CFErrorRef
*error
)
390 sec_trace_enter_api(CFSTR("applicants=%@"), applicants
);
391 sec_trace_return_bool_api(^{
392 do_if_registered(soscc_RejectApplicants
, applicants
, error
);
394 return info_array_to_bool_error_request(kSecXPCOpRejectApplicants
, applicants
, error
);
398 static bool label_and_password_to_bool_error_request(enum SecXPCOperation op
,
399 CFStringRef user_label
, CFDataRef user_password
,
402 __block
bool result
= false;
404 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
405 CFStringPerformWithCString(user_label
, ^(const char *utf8Str
) {
406 xpc_dictionary_set_string(message
, kSecXPCKeyUserLabel
, utf8Str
);
408 xpc_dictionary_set_data(message
, kSecXPCKeyUserPassword
, CFDataGetBytePtr(user_password
), CFDataGetLength(user_password
));
410 }, ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
411 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
418 static bool deviceid_to_bool_error_request(enum SecXPCOperation op
,
422 __block
bool result
= false;
424 securityd_send_sync_and_do(op
, error
, ^bool(xpc_object_t message
, CFErrorRef
*error
) {
425 CFStringPerformWithCString(IDS
, ^(const char *utf8Str
) {
426 xpc_dictionary_set_string(message
, kSecXPCKeyDeviceID
, utf8Str
);
429 }, ^bool(xpc_object_t response
, __unused CFErrorRef
*error
) {
430 result
= xpc_dictionary_get_bool(response
, kSecXPCKeyDeviceID
);
437 bool SOSCCRegisterUserCredentials(CFStringRef user_label
, CFDataRef user_password
, CFErrorRef
* error
)
439 secerror("SOSCCRegisterUserCredentials - calling SOSCCSetUserCredentials!! %@\n", user_label
);
440 return SOSCCSetUserCredentials(user_label
, user_password
, error
);
443 bool SOSCCSetUserCredentials(CFStringRef user_label
, CFDataRef user_password
, CFErrorRef
* error
)
445 secerror("SOSCCSetUserCredentials!! %@\n", user_label
);
446 sec_trace_enter_api(CFSTR("user_label=%@"), user_label
);
447 sec_trace_return_bool_api(^{
448 do_if_registered(soscc_SetUserCredentials
, user_label
, user_password
, error
);
450 return label_and_password_to_bool_error_request(kSecXPCOpSetUserCredentials
, user_label
, user_password
, error
);
453 bool SOSCCSetDeviceID(CFStringRef IDS
, CFErrorRef
* error
)
455 secerror("SOSCCSetDeviceID!! %@\n", IDS
);
456 sec_trace_enter_api(NULL
);
457 sec_trace_return_bool_api(^{
458 do_if_registered(soscc_SetDeviceID
, IDS
, error
);
459 return deviceid_to_bool_error_request(kSecXPCOpSetDeviceID
, IDS
, error
);
462 bool SOSCCTryUserCredentials(CFStringRef user_label
, CFDataRef user_password
, CFErrorRef
* error
)
464 sec_trace_enter_api(CFSTR("user_label=%@"), user_label
);
465 sec_trace_return_bool_api(^{
466 do_if_registered(soscc_TryUserCredentials
, user_label
, user_password
, error
);
468 return label_and_password_to_bool_error_request(kSecXPCOpTryUserCredentials
, user_label
, user_password
, error
);
473 bool SOSCCCanAuthenticate(CFErrorRef
* error
) {
474 sec_trace_enter_api(NULL
);
475 sec_trace_return_bool_api(^{
476 do_if_registered(soscc_CanAuthenticate
, error
);
478 return simple_bool_error_request(kSecXPCOpCanAuthenticate
, error
);
482 bool SOSCCPurgeUserCredentials(CFErrorRef
* error
) {
483 sec_trace_enter_api(NULL
);
484 sec_trace_return_bool_api(^{
485 do_if_registered(soscc_PurgeUserCredentials
, error
);
487 return simple_bool_error_request(kSecXPCOpPurgeUserCredentials
, error
);
491 enum DepartureReason
SOSCCGetLastDepartureReason(CFErrorRef
*error
) {
492 sec_trace_enter_api(NULL
);
493 sec_trace_return_api(enum DepartureReason
, ^{
494 do_if_registered(soscc_GetLastDepartureReason
, error
);
496 return (enum DepartureReason
) simple_int_error_request(kSecXPCOpGetLastDepartureReason
, error
);
500 CFStringRef
SOSCCCopyIncompatibilityInfo(CFErrorRef
* error
) {
501 sec_trace_enter_api(NULL
);
502 sec_trace_return_api(CFStringRef
, ^{
503 do_if_registered(soscc_CopyIncompatibilityInfo
, error
);
505 return simple_cfstring_error_request(kSecXPCOpCopyIncompatibilityInfo
, error
);
509 CFStringRef
SOSCCRequestDeviceID(CFErrorRef
* error
)
511 sec_trace_enter_api(NULL
);
512 sec_trace_return_api(CFStringRef
, ^{
513 do_if_registered(soscc_RequestDeviceID
, error
);
514 CFStringRef deviceID
= simple_cfstring_error_request(kSecXPCOpRequestDeviceID
, error
);
519 bool SOSCCProcessEnsurePeerRegistration(CFErrorRef
* error
){
520 secnotice("updates", "enter SOSCCProcessEnsurePeerRegistration");
521 sec_trace_enter_api(NULL
);
522 sec_trace_return_bool_api(^{
523 do_if_registered(soscc_EnsurePeerRegistration
, error
);
525 return simple_bool_error_request(soscc_EnsurePeerRegistration_id
, error
);
530 SyncWithAllPeersReason
SOSCCProcessSyncWithAllPeers(CFErrorRef
* error
)
532 sec_trace_enter_api(NULL
);
533 sec_trace_return_api(SyncWithAllPeersReason
, ^{
534 do_if_registered(soscc_ProcessSyncWithAllPeers
, error
);
536 return (SyncWithAllPeersReason
) simple_int_error_request(kSecXPCOpProcessSyncWithAllPeers
, error
);
540 CFStringRef
SOSCCGetStatusDescription(SOSCCStatus status
)
544 return CFSTR("InCircle");
545 case kSOSCCNotInCircle
:
546 return CFSTR("NotInCircle");
547 case kSOSCCRequestPending
:
548 return CFSTR("RequestPending");
549 case kSOSCCCircleAbsent
:
550 return CFSTR("CircleAbsent");
552 return CFSTR("InternalError");
554 return CFSTR("Unknown Status (%d)");