+++ /dev/null
-
-#include "SOSAccountPriv.h"
-
-#include <Security/SecureObjectSync/SOSTransportCircle.h>
-#include <Security/SecureObjectSync/SOSTransportMessage.h>
-#include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
-#include <Security/SecureObjectSync/SOSKVSKeys.h>
-#include <Security/SecureObjectSync/SOSTransport.h>
-#include <Security/SecureObjectSync/SOSTransportKeyParameter.h>
-#include <Security/SecureObjectSync/SOSTransportKeyParameterKVS.h>
-
-#include <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
-
-#include <CoreFoundation/CoreFoundation.h>
-
-#include <utilities/SecCFError.h>
-
-// MARK: Engine Logging
-#define LOG_ENGINE_STATE_INTERVAL 20
-
-static void SOSAccountConsiderLoggingEngineState(SOSAccountTransactionRef txn) {
- static int engineLogCountDown = 0;
-
- if(engineLogCountDown <= 0) {
- SOSEngineRef engine = SOSTransportMessageGetEngine(txn->account->kvs_message_transport);
-
- SOSEngineLogState(engine);
- engineLogCountDown = LOG_ENGINE_STATE_INTERVAL;
- } else {
- engineLogCountDown--;
- }
-}
-
-static bool SOSAccountIsThisPeerIDMe(SOSAccountRef account, CFStringRef peerID) {
- SOSPeerInfoRef mypi = SOSFullPeerInfoGetPeerInfo(account->my_identity);
- CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi);
-
- return myPeerID && CFEqualSafe(myPeerID, peerID);
-}
-
-bool SOSAccountSendIKSPSyncList(SOSAccountRef account, CFErrorRef *error){
- bool result = true;
- __block CFErrorRef localError = NULL;
- __block CFMutableArrayRef ids = NULL;
- SOSCircleRef circle = NULL;
-
- require_action_quiet(SOSAccountIsInCircle(account, NULL), xit,
- SOSCreateError(kSOSErrorNoCircle, CFSTR("This device is not in circle"),
- NULL, &localError));
-
- circle = SOSAccountGetCircle(account, error);
- ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-
- SOSCircleForEachValidPeer(circle, account->user_public, ^(SOSPeerInfoRef peer) {
- if (!SOSAccountIsThisPeerIDMe(account, SOSPeerInfoGetPeerID(peer))) {
- if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(account->my_identity), peer) &&
- SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(account->my_identity), peer) &&
- !SOSPeerInfoShouldUseACKModel(SOSFullPeerInfoGetPeerInfo(account->my_identity), peer)){
- SOSTransportMessageIDSSetFragmentationPreference(account->ids_message_transport, kCFBooleanTrue);
- CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer);
- if(deviceID != NULL){
- CFArrayAppendValue(ids, deviceID);
- }
- CFReleaseNull(deviceID);
- }
- }
- });
- require_quiet(CFArrayGetCount(ids) != 0, xit);
- secnotice("IDS Transport", "List of IDS Peers to ping: %@", ids);
-
- SOSCloudKeychainGetIDSDeviceAvailability(ids, SOSAccountGetMyPeerID(account), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
- bool success = (sync_error == NULL);
- if(!success)
- secerror("Failed to send list of IDS peers to IDSKSP: %@", sync_error);
- });
-xit:
- if(error && *error != NULL)
- secerror("SOSAccountSendIKSPSyncList had an error: %@", *error);
-
- if(localError)
- secerror("SOSAccountSendIKSPSyncList had an error: %@", localError);
-
- CFReleaseNull(ids);
- CFReleaseNull(localError);
-
- return result;
-}
-//
-// MARK: KVS Syncing
-//
-
-static bool SOSAccountSyncWithKVSPeers(SOSAccountTransactionRef txn, CFSetRef peerIDs, CFErrorRef *error) {
- SOSAccountRef account = txn->account;
- CFErrorRef localError = NULL;
- bool result = false;
-
- require_quiet(SOSAccountIsInCircle(account, &localError), xit);
-
- result = SOSTransportMessageSyncWithPeers(account->kvs_message_transport, peerIDs, &localError);
-
- if (result)
- SetCloudKeychainTraceValueForKey(kCloudKeychainNumberOfTimesSyncedWithPeers, 1);
-
-xit:
- if (!result) {
- // Tell account to update SOSEngine with current trusted peers
- if (isSOSErrorCoded(localError, kSOSErrorPeerNotFound)) {
- secnotice("Account", "Arming account to update SOSEngine with current trusted peers");
- account->engine_peer_state_needs_repair = true;
- }
- CFErrorPropagate(localError, error);
- localError = NULL;
- }
- return result;
-
-}
-
-bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransactionRef txn, CFStringRef peerid, CFDataRef message, CFErrorRef *error) {
- SOSAccountRef account = txn->account;
- bool result = false;
- CFErrorRef localError = NULL;
- CFDictionaryRef encapsulatedMessage = NULL;
-
- secnotice("KVS Transport","Syncing with KVS capable peer: %@", peerid);
- secnotice("KVS Transport", "message: %@", message);
-
- require_quiet(message, xit);
- require_quiet(peerid, xit);
-
- encapsulatedMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerid, message, NULL);
-
- result = SOSTransportMessageSendMessages(account->kvs_message_transport, encapsulatedMessage, &localError);
- secerror("KVS sync %s. (%@)", result ? "succeeded" : "failed", localError);
-
- SOSAccountConsiderLoggingEngineState(txn);
-
-xit:
- CFReleaseNull(encapsulatedMessage);
- CFErrorPropagate(localError, error);
-
- return result;
-}
-
-
-static bool SOSAccountSyncWithKVSPeer(SOSAccountTransactionRef txn, CFStringRef peerID, CFErrorRef *error)
-{
- bool result = false;
- CFErrorRef localError = NULL;
-
- secnotice("KVS Transport","Syncing with KVS capable peer: %@", peerID);
-
- CFMutableSetRef peerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
- CFSetAddValue(peerIDs, peerID);
-
- result = SOSAccountSyncWithKVSPeers(txn, peerIDs, &localError);
- secerror("KVS sync %s. (%@)", result ? "succeeded" : "failed", localError);
-
- CFReleaseNull(peerIDs);
- CFErrorPropagate(localError, error);
-
- return result;
-}
-
-
-static CFMutableArrayRef SOSAccountCopyPeerIDsForDSID(SOSAccountRef account, CFStringRef deviceID, CFErrorRef* error) {
- CFMutableArrayRef peerIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-
- SOSCircleForEachValidPeer(account->trusted_circle, account->user_public, ^(SOSPeerInfoRef peer) {
- CFStringRef peerDeviceID = SOSPeerInfoCopyDeviceID(peer);
- if(peerDeviceID != NULL && CFStringCompare(peerDeviceID, deviceID, 0) == 0){
- CFArrayAppendValue(peerIDs, SOSPeerInfoGetPeerID(peer));
- }
- CFReleaseNull(peerDeviceID);
- });
-
- if (peerIDs == NULL || CFArrayGetCount(peerIDs) == 0) {
- CFReleaseNull(peerIDs);
- SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No peer with DSID: %@"), deviceID);
- }
-
- return peerIDs;
-}
-
-static bool SOSAccountSyncWithKVSPeerFromPing(SOSAccountRef account, CFArrayRef peerIDs, CFErrorRef *error) {
-
- CFErrorRef localError = NULL;
- bool result = false;
-
- CFSetRef peerSet = CFSetCreateCopyOfArrayForCFTypes(peerIDs);
- result = SOSTransportMessageSyncWithPeers(account->kvs_message_transport, peerSet, &localError);
-
- CFReleaseNull(peerSet);
-
- return result;
-}
-
-bool SOSAccountSyncWithKVSUsingIDSID(SOSAccountRef account, CFStringRef deviceID, CFErrorRef *error) {
- bool result = false;
- CFErrorRef localError = NULL;
-
- secnotice("KVS Transport","Syncing with KVS capable peer via DSID: %@", deviceID);
-
- CFArrayRef peerIDs = SOSAccountCopyPeerIDsForDSID(account, deviceID, &localError);
- require_quiet(peerIDs, xit);
-
- CFStringArrayPerfromWithDescription(peerIDs, ^(CFStringRef peerIDList) {
- secnotice("KVS Transport", "Syncing with KVS capable peers: %@", peerIDList);
- });
-
- result = SOSAccountSyncWithKVSPeerFromPing(account, peerIDs, &localError);
- secerror("KVS sync %s. (%@)", result ? "succeeded" : "failed", localError);
-
-xit:
- CFReleaseNull(peerIDs);
- CFErrorPropagate(localError, error);
-
- return result;
-}
-
-static __nonnull CF_RETURNS_RETAINED CFSetRef SOSAccountSyncWithPeersOverKVS(SOSAccountTransactionRef txn, CFSetRef peers) {
- CFMutableSetRef handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
-
- CFSetForEach(peers, ^(const void *value) {
- CFStringRef peerID = asString(value, NULL);
- CFErrorRef localError = NULL;
- if (peerID && SOSAccountSyncWithKVSPeer(txn, peerID, &localError)) {
- CFSetAddValue(handled, peerID);
- secnotice("KVS Transport", "synced with peer: %@", peerID);
- } else {
- secnotice("KVS Transport", "failed to sync with peer: %@ error: %@", peerID, localError);
- }
- });
-
- return handled;
-}
-
-static __nonnull CF_RETURNS_RETAINED CFSetRef SOSAccountSyncWithPeersOverIDS(SOSAccountTransactionRef txn, __nonnull CFSetRef peers) {
- CFErrorRef localError = NULL;
-
- CFStringSetPerformWithDescription(peers, ^(CFStringRef peerDescription) {
- secnotice("IDS Transport","Syncing with IDS capable peers: %@", peerDescription);
- });
-
- // We should change this to return a set of peers we succeeded with, but for now assume they all worked.
- bool result = SOSTransportMessageSyncWithPeers(txn->account->ids_message_transport, peers, &localError);
- secnotice("IDS Transport", "IDS Sync result: %d", result);
-
- return CFRetainSafe(peers);
-}
-
-static CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTransactionRef txn, CFSetRef /* CFStringRef */ peerIDs, CFErrorRef *error) {
- CFMutableSetRef notMePeers = NULL;
- CFMutableSetRef handledPeerIDs = NULL;
- CFMutableSetRef peersForIDS = NULL;
- CFMutableSetRef peersForKVS = NULL;
-
- SOSAccountRef account = txn->account;
-
- require_action_quiet(SOSAccountIsInCircle(account, error), done,
- handledPeerIDs = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs));
-
- // Kick getting our device ID if we don't have it, and find out if we're setup to use IDS.
- bool canUseIDS = SOSTransportMessageIDSGetIDSDeviceID(account);
-
- handledPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
- peersForIDS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
- peersForKVS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
-
- SOSPeerInfoRef myPeerInfo = SOSAccountGetMyPeerInfo(account);
- require(myPeerInfo, done);
-
- CFStringRef myPeerID = SOSPeerInfoGetPeerID(myPeerInfo);
-
- notMePeers = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
- CFSetRemoveValue(notMePeers, myPeerID);
-
- if(!SOSAccountSendIKSPSyncList(account, error)){
- if(error != NULL)
- secnotice("IDS Transport", "Did not send list of peers to ping (pre-E): %@", *error);
- }
-
- CFSetForEach(notMePeers, ^(const void *value) {
- CFErrorRef localError = NULL;
- CFStringRef peerID = asString(value, &localError);
- SOSPeerInfoRef peerInfo = NULL;
-
- require_quiet(peerID, skip);
-
- peerInfo = SOSCircleCopyPeerWithID(account->trusted_circle, peerID, NULL);
- if (peerInfo && SOSCircleHasValidSyncingPeer(account->trusted_circle, peerInfo, account->user_public, NULL)) {
- if (canUseIDS && SOSPeerInfoShouldUseIDSTransport(myPeerInfo, peerInfo) && SOSPeerInfoShouldUseACKModel(myPeerInfo, peerInfo)) {
- CFSetAddValue(peersForIDS, peerID);
- } else {
- CFSetAddValue(peersForKVS, peerID);
- }
- } else {
- CFSetAddValue(handledPeerIDs, peerID);
- }
-
- skip:
- CFReleaseNull(peerInfo);
- if (localError) {
- secnotice("sync-with-peers", "Skipped peer ID: %@ due to %@", peerID, localError);
- }
- CFReleaseNull(localError);
- });
-
- CFSetRef handledIDSPeerIDs = SOSAccountSyncWithPeersOverIDS(txn, peersForIDS);
- CFSetUnion(handledPeerIDs, handledIDSPeerIDs);
- CFReleaseNull(handledIDSPeerIDs);
-
- CFSetRef handledKVSPeerIDs = SOSAccountSyncWithPeersOverKVS(txn, peersForKVS);
- CFSetUnion(handledPeerIDs, handledKVSPeerIDs);
- CFReleaseNull(handledKVSPeerIDs);
-
- SOSAccountConsiderLoggingEngineState(txn);
-
-done:
- CFReleaseNull(notMePeers);
- CFReleaseNull(peersForIDS);
- CFReleaseNull(peersForKVS);
- return handledPeerIDs;
-}
-
-bool SOSAccountClearPeerMessageKey(SOSAccountTransactionRef txn, CFStringRef peerID, CFErrorRef *error)
-{
- SOSAccountRef account = txn->account;
-
- secnotice("IDS Transport", "clearing peer message for %@", peerID);
- CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
-
- if(dsid == NULL)
- dsid = kCFNull;
-
- CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(account->kvs_message_transport, peerID);
- CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, kCFNull, kSOSKVSRequiredKey, dsid, NULL);
-
- CloudKeychainReplyBlock log_error = ^(CFDictionaryRef returnedValues __unused, CFErrorRef block_error) {
- if (block_error) {
- secerror("Error putting: %@", block_error);
- }
- };
-
- SOSCloudKeychainPutObjectsInCloud(a_message_to_a_peer, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), log_error);
-
- CFReleaseNull(a_message_to_a_peer);
- CFReleaseNull(message_to_peer_key);
-
- return true;
-}
-
-CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransactionRef txn, CFSetRef /* CFStringRef */ peers, CFSetRef /* CFStringRef */ backupPeers, CFErrorRef *error)
-{
- CFErrorRef localError = NULL;
- CFMutableSetRef handled = SOSAccountSyncWithPeers(txn, peers, &localError);
-
- SOSTransportMessageIDSGetIDSDeviceID(txn->account);
-
- if (!handled) {
- secnotice("account-sync", "Peer Sync failed: %@", localError);
- handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
- }
- CFReleaseNull(localError);
-
- SOSEngineRef engine = SOSTransportMessageGetEngine(txn->account->kvs_message_transport);
- CFSetRef engineHandled = SOSEngineSyncWithBackupPeers(engine, backupPeers, error);
-
- if (engineHandled) {
- CFSetUnion(handled, engineHandled);
- } else {
- secnotice("account-sync", "Engine Backup Sync failed: %@", localError);
- }
- CFReleaseNull(localError);
- CFReleaseNull(engineHandled);
-
- return handled;
-}
-
-bool SOSAccountRequestSyncWithAllPeers(SOSAccountTransactionRef txn, CFErrorRef *error)
-{
- bool success = false;
- CFMutableSetRef allSyncingPeers = NULL;
-
- require_quiet(SOSAccountIsInCircle(txn->account, error), xit);
-
- SOSTransportMessageIDSGetIDSDeviceID(txn->account);
-
- allSyncingPeers = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
-
- SOSCircleForEachValidSyncingPeer(txn->account->trusted_circle, txn->account->user_public, ^(SOSPeerInfoRef peer) {
- CFSetAddValue(allSyncingPeers, SOSPeerInfoGetPeerID(peer));
- });
-
- SOSAccountTransactionAddSyncRequestForAllPeerIDs(txn, allSyncingPeers);
-
- success = true;
-
-xit:
- CFReleaseNull(allSyncingPeers);
- return success;
-}
-
-//
-// MARK: Syncing status functions
-//
-bool SOSAccountMessageFromPeerIsPending(SOSAccountTransactionRef txn, SOSPeerInfoRef peer, CFErrorRef *error) {
- bool success = false;
- require_quiet(SOSAccountIsInCircle(txn->account, error), xit);
-
- // This translation belongs inside KVS..way down in CKD, but for now we reach over and do it here.
- CFStringRef peerMessage = SOSMessageKeyCreateFromPeerToTransport(txn->account->kvs_message_transport, SOSPeerInfoGetPeerID(peer));
-
- success = SOSCloudKeychainHasPendingKey(peerMessage, error);
-
-xit:
- return success;
-}
-
-bool SOSAccountSendToPeerIsPending(SOSAccountTransactionRef txn, SOSPeerInfoRef peer, CFErrorRef *error) {
- bool success = false;
- require_quiet(SOSAccountIsInCircle(txn->account, error), xit);
-
- success = SOSCCIsSyncPendingFor(SOSPeerInfoGetPeerID(peer), error);
-xit:
- return success;
-
-
-}