1/* 2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24// 25// SOSCloudCircle.m 26// 27 28#include <stdio.h> 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> 40 41#include <securityd/SecItemServer.h> 42 43#include <utilities/SecDispatchRelease.h> 44#include <utilities/SecCFRelease.h> 45#include <utilities/SecCFWrappers.h> 46#include <utilities/SecXPCError.h> 47 48#include <utilities/debugging.h> 49 50#include <CoreFoundation/CoreFoundation.h> 51 52#include <xpc/xpc.h> 53#define MINIMIZE_INCLUDES MINIMIZE_INCLUDES 54#include <ipc/securityd_client.h> 55#include <securityd/spi.h> 56 57#include "SOSRegressionUtilities.h" 58 59 60const char * kSOSCCCircleChangedNotification = "com.apple.security.secureobjectsync.circlechanged"; 61 62#define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); } 63 64static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary, const char *key, xpc_type_t type) 65{ 66 xpc_object_t value = xpc_dictionary_get_value(dictionary, key); 67 68 return value && (xpc_get_type(value) == type); 69} 70 71SOSCCStatus SOSCCThisDeviceIsInCircle(CFErrorRef *error) 72{ 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; 78 79 do_if_registered(soscc_ThisDeviceIsInCircle, error); 80 81 xpc_object_t message = securityd_create_message(kSecXPCOpDeviceInCircle, error); 82 if (message) { 83 xpc_object_t response = securityd_message_with_reply_sync(message, error); 84 85 if (response && xpc_dictionary_entry_is_type(response, kSecXPCKeyResult, XPC_TYPE_INT64)) { 86 result = (SOSCCStatus) xpc_dictionary_get_int64(response, kSecXPCKeyResult); 87 } else { 88 result = kSOSCCError; 89 } 90 91 if (result < 0) { 92 if (response && securityd_message_no_error(response, error)) 93 { 94 char *desc = xpc_copy_description(response); 95 SecCFCreateErrorWithFormat(0, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("Remote error occurred/no info: %s"), desc); 96 free((void *)desc); 97 } 98 } 99 if(response) 100 xpc_release(response); 101 if(message) 102 xpc_release(message); 103 } 104 105 106 return result; 107 }, CFSTR("SOSCCStatus=%d")) 108} 109 110static CFStringRef simple_cfstring_error_request(enum SecXPCOperation op, CFErrorRef* error) 111{ 112 __block CFStringRef result = NULL; 113 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); 117 118 if (c_string) { 119 result = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)c_string, strlen(c_string), kCFStringEncodingUTF8, false); 120 } 121 122 return c_string != NULL; 123 }); 124 return result; 125} 126 127static bool simple_bool_error_request(enum SecXPCOperation op, CFErrorRef* error) 128{ 129 __block bool result = false; 130 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); 134 return result; 135 }); 136 return result; 137} 138 139static CFArrayRef simple_array_error_request(enum SecXPCOperation op, CFErrorRef* error) 140{ 141 __block CFArrayRef result = false; 142 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; 148 }); 149 return result; 150} 151 152static int simple_int_error_request(enum SecXPCOperation op, CFErrorRef* error) 153{ 154 __block int result = 0; 155 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; 161 } 162 return result; 163 }); 164 return result; 165} 166 167static CFArrayRef array_of_info_error_request(enum SecXPCOperation op, CFErrorRef* error) 168{ 169 __block CFArrayRef result = NULL; 170 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); 176 } 177 return result != NULL; 178 }); 179 180 return result; 181} 182 183static bool info_array_to_bool_error_request(enum SecXPCOperation op, CFArrayRef peer_infos, CFErrorRef* error) 184{ 185 __block bool result = false; 186 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); 190 if (encoded_peers) 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); 195 return result; 196 }); 197 return result; 198} 199 200static bool uint64_t_to_bool_error_request(enum SecXPCOperation op, 201 uint64_t number, 202 CFErrorRef* error) 203{ 204 __block bool result = false; 205 206 securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { 207 xpc_dictionary_set_uint64(message, kSecXPCLimitInMinutes, number); 208 return true; 209 }, ^bool(xpc_object_t response, __unused CFErrorRef *error) { 210 result = xpc_dictionary_get_bool(response, kSecXPCKeyResult); 211 return result; 212 }); 213 214 return result; 215} 216 217bool SOSCCRequestToJoinCircle(CFErrorRef* error) 218{ 219 sec_trace_enter_api(NULL); 220 sec_trace_return_bool_api(^{ 221 do_if_registered(soscc_RequestToJoinCircle, error); 222 223 return simple_bool_error_request(kSecXPCOpRequestToJoin, error); 224 }, NULL) 225} 226 227bool SOSCCRequestToJoinCircleAfterRestore(CFErrorRef* error) 228{ 229 sec_trace_enter_api(NULL); 230 sec_trace_return_bool_api(^{ 231 do_if_registered(soscc_RequestToJoinCircleAfterRestore, error); 232 233 return simple_bool_error_request(kSecXPCOpRequestToJoinAfterRestore, error); 234 }, NULL) 235} 236 237bool SOSCCRequestEnsureFreshParameters(CFErrorRef* error) 238{ 239 sec_trace_enter_api(NULL); 240 sec_trace_return_bool_api(^{ 241 do_if_registered(soscc_RequestEnsureFreshParameters, error); 242 243 return simple_bool_error_request(kSecXPCOpRequestEnsureFreshParameters, error); 244 }, NULL) 245} 246 247bool SOSCCResetToOffering(CFErrorRef* error) 248{ 249 secwarning("SOSCCResetToOffering called"); 250 sec_trace_enter_api(NULL); 251 sec_trace_return_bool_api(^{ 252 do_if_registered(soscc_ResetToOffering, error); 253 254 return simple_bool_error_request(kSecXPCOpResetToOffering, error); 255 }, NULL) 256} 257 258bool SOSCCResetToEmpty(CFErrorRef* error) 259{ 260 secwarning("SOSCCResetToEmpty called"); 261 sec_trace_enter_api(NULL); 262 sec_trace_return_bool_api(^{ 263 do_if_registered(soscc_ResetToEmpty, error); 264 265 return simple_bool_error_request(kSecXPCOpResetToEmpty, error); 266 }, NULL) 267} 268 269bool SOSCCRemoveThisDeviceFromCircle(CFErrorRef* error) 270{ 271 sec_trace_enter_api(NULL); 272 sec_trace_return_bool_api(^{ 273 do_if_registered(soscc_RemoveThisDeviceFromCircle, error); 274 275 return simple_bool_error_request(kSecXPCOpRemoveThisDeviceFromCircle, error); 276 }, NULL) 277} 278 279bool SOSCCBailFromCircle_BestEffort(uint64_t limit_in_seconds, CFErrorRef* error) 280{ 281 sec_trace_enter_api(NULL); 282 sec_trace_return_bool_api(^{ 283 do_if_registered(soscc_BailFromCircle, limit_in_seconds, error); 284 285 return uint64_t_to_bool_error_request(kSecXPCOpBailFromCircle, limit_in_seconds, error); 286 }, NULL) 287} 288 289bool SOSCCSignedOut(bool immediate, CFErrorRef* error) 290{ 291 uint64_t limit = strtoul(optarg, NULL, 10); 292 293 if(immediate) 294 return SOSCCRemoveThisDeviceFromCircle(error); 295 else 296 return SOSCCBailFromCircle_BestEffort(limit, error); 297 298} 299 300CFArrayRef SOSCCCopyPeerPeerInfo(CFErrorRef* error) 301{ 302 sec_trace_enter_api(NULL); 303 sec_trace_return_api(CFArrayRef, ^{ 304 do_if_registered(soscc_CopyPeerInfo, error); 305 306 return array_of_info_error_request(kSecXPCOpCopyPeerPeerInfo, error); 307 }, CFSTR("return=%@")); 308} 309 310CFArrayRef SOSCCCopyConcurringPeerPeerInfo(CFErrorRef* error) 311{ 312 sec_trace_enter_api(NULL); 313 sec_trace_return_api(CFArrayRef, ^{ 314 do_if_registered(soscc_CopyConcurringPeerInfo, error); 315 316 return array_of_info_error_request(kSecXPCOpCopyConcurringPeerPeerInfo, error); 317 }, CFSTR("return=%@")); 318} 319 320CFArrayRef SOSCCCopyGenerationPeerInfo(CFErrorRef* error) 321{ 322 sec_trace_enter_api(NULL); 323 sec_trace_return_api(CFArrayRef, ^{ 324 do_if_registered(soscc_CopyGenerationPeerInfo, error); 325 326 return simple_array_error_request(kSecXPCOpCopyGenerationPeerInfo, error); 327 }, CFSTR("return=%@")); 328} 329 330CFArrayRef SOSCCCopyApplicantPeerInfo(CFErrorRef* error) 331{ 332 sec_trace_enter_api(NULL); 333 sec_trace_return_api(CFArrayRef, ^{ 334 do_if_registered(soscc_CopyApplicantPeerInfo, error); 335 336 return array_of_info_error_request(kSecXPCOpCopyApplicantPeerInfo, error); 337 }, CFSTR("return=%@")); 338} 339bool SOSCCValidateUserPublic(CFErrorRef* error){ 340 sec_trace_enter_api(NULL); 341 sec_trace_return_api(bool, ^{ 342 do_if_registered(soscc_ValidateUserPublic, error); 343 344 return simple_bool_error_request(kSecXPCOpValidateUserPublic, error); 345 }, NULL); 346} 347 348CFArrayRef SOSCCCopyValidPeerPeerInfo(CFErrorRef* error) 349{ 350 sec_trace_enter_api(NULL); 351 sec_trace_return_api(CFArrayRef, ^{ 352 do_if_registered(soscc_CopyValidPeerPeerInfo, error); 353 354 return array_of_info_error_request(kSecXPCOpCopyValidPeerPeerInfo, error); 355 }, CFSTR("return=%@")); 356} 357 358CFArrayRef SOSCCCopyNotValidPeerPeerInfo(CFErrorRef* error) 359{ 360 sec_trace_enter_api(NULL); 361 sec_trace_return_api(CFArrayRef, ^{ 362 do_if_registered(soscc_CopyNotValidPeerPeerInfo, error); 363 364 return array_of_info_error_request(kSecXPCOpCopyNotValidPeerPeerInfo, error); 365 }, CFSTR("return=%@")); 366} 367 368CFArrayRef SOSCCCopyRetirementPeerInfo(CFErrorRef* error) 369{ 370 sec_trace_enter_api(NULL); 371 sec_trace_return_api(CFArrayRef, ^{ 372 do_if_registered(soscc_CopyRetirementPeerInfo, error); 373 374 return array_of_info_error_request(kSecXPCOpCopyRetirementPeerInfo, error); 375 }, CFSTR("return=%@")); 376} 377 378bool SOSCCAcceptApplicants(CFArrayRef applicants, CFErrorRef* error) 379{ 380 sec_trace_enter_api(NULL); 381 sec_trace_return_bool_api(^{ 382 do_if_registered(soscc_AcceptApplicants, applicants, error); 383 384 return info_array_to_bool_error_request(kSecXPCOpAcceptApplicants, applicants, error); 385 }, NULL) 386} 387 388bool SOSCCRejectApplicants(CFArrayRef applicants, CFErrorRef *error) 389{ 390 sec_trace_enter_api(CFSTR("applicants=%@"), applicants); 391 sec_trace_return_bool_api(^{ 392 do_if_registered(soscc_RejectApplicants, applicants, error); 393 394 return info_array_to_bool_error_request(kSecXPCOpRejectApplicants, applicants, error); 395 }, NULL) 396} 397 398static bool label_and_password_to_bool_error_request(enum SecXPCOperation op, 399 CFStringRef user_label, CFDataRef user_password, 400 CFErrorRef* error) 401{ 402 __block bool result = false; 403 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); 407 }); 408 xpc_dictionary_set_data(message, kSecXPCKeyUserPassword, CFDataGetBytePtr(user_password), CFDataGetLength(user_password)); 409 return true; 410 }, ^bool(xpc_object_t response, __unused CFErrorRef *error) { 411 result = xpc_dictionary_get_bool(response, kSecXPCKeyResult); 412 return result; 413 }); 414 415 return result; 416} 417 418static bool deviceid_to_bool_error_request(enum SecXPCOperation op, 419 CFStringRef IDS, 420 CFErrorRef* error) 421{ 422 __block bool result = false; 423 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); 427 }); 428 return true; 429 }, ^bool(xpc_object_t response, __unused CFErrorRef *error) { 430 result = xpc_dictionary_get_bool(response, kSecXPCKeyDeviceID); 431 return result; 432 }); 433 434 return result; 435} 436 437bool SOSCCRegisterUserCredentials(CFStringRef user_label, CFDataRef user_password, CFErrorRef* error) 438{ 439 secerror("SOSCCRegisterUserCredentials - calling SOSCCSetUserCredentials!! %@\n", user_label); 440 return SOSCCSetUserCredentials(user_label, user_password, error); 441} 442 443bool SOSCCSetUserCredentials(CFStringRef user_label, CFDataRef user_password, CFErrorRef* error) 444{ 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); 449 450 return label_and_password_to_bool_error_request(kSecXPCOpSetUserCredentials, user_label, user_password, error); 451 }, NULL) 452} 453bool SOSCCSetDeviceID(CFStringRef IDS, CFErrorRef* error) 454{ 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); 460 }, NULL) 461} 462bool SOSCCTryUserCredentials(CFStringRef user_label, CFDataRef user_password, CFErrorRef* error) 463{ 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); 467 468 return label_and_password_to_bool_error_request(kSecXPCOpTryUserCredentials, user_label, user_password, error); 469 }, NULL) 470} 471 472 473bool SOSCCCanAuthenticate(CFErrorRef* error) { 474 sec_trace_enter_api(NULL); 475 sec_trace_return_bool_api(^{ 476 do_if_registered(soscc_CanAuthenticate, error); 477 478 return simple_bool_error_request(kSecXPCOpCanAuthenticate, error); 479 }, NULL) 480} 481 482bool SOSCCPurgeUserCredentials(CFErrorRef* error) { 483 sec_trace_enter_api(NULL); 484 sec_trace_return_bool_api(^{ 485 do_if_registered(soscc_PurgeUserCredentials, error); 486 487 return simple_bool_error_request(kSecXPCOpPurgeUserCredentials, error); 488 }, NULL) 489} 490 491enum DepartureReason SOSCCGetLastDepartureReason(CFErrorRef *error) { 492 sec_trace_enter_api(NULL); 493 sec_trace_return_api(enum DepartureReason, ^{ 494 do_if_registered(soscc_GetLastDepartureReason, error); 495 496 return (enum DepartureReason) simple_int_error_request(kSecXPCOpGetLastDepartureReason, error); 497 }, NULL) 498} 499 500CFStringRef SOSCCCopyIncompatibilityInfo(CFErrorRef* error) { 501 sec_trace_enter_api(NULL); 502 sec_trace_return_api(CFStringRef, ^{ 503 do_if_registered(soscc_CopyIncompatibilityInfo, error); 504 505 return simple_cfstring_error_request(kSecXPCOpCopyIncompatibilityInfo, error); 506 }, NULL) 507} 508 509CFStringRef SOSCCRequestDeviceID(CFErrorRef* error) 510{ 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); 515 return deviceID; 516 }, NULL) 517} 518 519bool 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); 524 525 return simple_bool_error_request(soscc_EnsurePeerRegistration_id, error); 526 }, NULL) 527} 528 529 530SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers(CFErrorRef* error) 531{ 532 sec_trace_enter_api(NULL); 533 sec_trace_return_api(SyncWithAllPeersReason, ^{ 534 do_if_registered(soscc_ProcessSyncWithAllPeers, error); 535 536 return (SyncWithAllPeersReason) simple_int_error_request(kSecXPCOpProcessSyncWithAllPeers, error); 537 }, NULL) 538} 539 540CFStringRef SOSCCGetStatusDescription(SOSCCStatus status) 541{ 542 switch (status) { 543 case kSOSCCInCircle: 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"); 551 case kSOSCCError: 552 return CFSTR("InternalError"); 553 default: 554 return CFSTR("Unknown Status (%d)"); 555 }; 556} 557