2 #include "SOSAccountPriv.h"
3 #include "SOSAccount.h"
5 #include <Security/SecureObjectSync/SOSKVSKeys.h>
6 #include <Security/SecureObjectSync/SOSTransportCircle.h>
7 #include <Security/SecureObjectSync/SOSTransportCircleKVS.h>
8 #include <Security/SecureObjectSync/SOSTransportMessage.h>
9 #include <Security/SecureObjectSync/SOSKVSKeys.h>
10 #include <Security/SecureObjectSync/SOSTransport.h>
11 #include <Security/SecureObjectSync/SOSTransportKeyParameter.h>
12 #include <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
14 #import <Security/SecureObjectSync/SOSAccountTrust.h>
15 #import <Security/SecureObjectSync/SOSTransport.h>
16 #import <Security/SecureObjectSync/SOSTransportKeyParameter.h>
17 #import <Security/SecureObjectSync/SOSTransportMessage.h>
18 #import <Security/SecureObjectSync/SOSTransportMessageKVS.h>
19 #include <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
20 #include <Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h>
21 #include <Security/SecureObjectSync/SOSInternal.h>
23 #include <CoreFoundation/CoreFoundation.h>
25 #include <utilities/SecCFError.h>
27 // MARK: Engine Logging
28 #define LOG_ENGINE_STATE_INTERVAL 20
30 void SOSAccountConsiderLoggingEngineState(SOSAccountTransaction* txn) {
31 static int engineLogCountDown = 0;
33 if(engineLogCountDown <= 0) {
34 SOSAccount* acct = txn.account;
35 CFTypeRef engine = [acct.kvs_message_transport SOSTransportMessageGetEngine];
37 SOSEngineLogState((SOSEngineRef)engine);
38 engineLogCountDown = LOG_ENGINE_STATE_INTERVAL;
44 bool SOSAccountInflateTransports(SOSAccount* account, CFStringRef circleName, CFErrorRef *error){
47 if(account.key_transport)
48 SOSUnregisterTransportKeyParameter(account.key_transport);
49 if(account.circle_transport)
50 SOSUnregisterTransportCircle(account.circle_transport);
51 if(account.kvs_message_transport)
52 SOSUnregisterTransportMessage((SOSMessage*)account.kvs_message_transport);
54 account.key_transport = [[CKKeyParameter alloc] initWithAccount:account];
55 account.circle_transport = [[SOSKVSCircleStorageTransport alloc]initWithAccount:account andCircleName:(__bridge NSString *)(circleName)];
57 require_quiet(account.key_transport, fail);
58 require_quiet(account.circle_transport, fail);
60 account.kvs_message_transport = [[SOSMessageKVS alloc] initWithAccount:account andName:(__bridge NSString*)circleName];
61 require_quiet(account.kvs_message_transport, fail);
73 static bool SOSAccountSyncWithKVSPeers(SOSAccountTransaction* txn, CFSetRef peerIDs, CFErrorRef *error) {
74 SOSAccount* account = txn.account;
75 CFErrorRef localError = NULL;
78 require_quiet([account isInCircle:error], xit);
80 result =[account.kvs_message_transport SOSTransportMessageSyncWithPeers:account.kvs_message_transport p:peerIDs err:&localError];
83 SetCloudKeychainTraceValueForKey(kCloudKeychainNumberOfTimesSyncedWithPeers, 1);
87 // Tell account to update SOSEngine with current trusted peers
88 if (isSOSErrorCoded(localError, kSOSErrorPeerNotFound)) {
89 secnotice("Account", "Arming account to update SOSEngine with current trusted peers");
90 account.engine_peer_state_needs_repair = true;
92 CFErrorPropagate(localError, error);
99 bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransaction* txn, CFStringRef peerid, CFDataRef message, CFErrorRef *error) {
100 SOSAccount* account = txn.account;
102 CFErrorRef localError = NULL;
103 CFDictionaryRef encapsulatedMessage = NULL;
105 secnotice("KVS Transport","Syncing with KVS capable peer: %@", peerid);
106 secnotice("KVS Transport", "message: %@", message);
108 require_quiet(message, xit);
109 require_quiet(peerid && CFStringGetLength(peerid) <= kSOSPeerIDLengthMax, xit);
111 encapsulatedMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerid, message, NULL);
113 result = [account.kvs_message_transport SOSTransportMessageSendMessages:account.kvs_message_transport pm:encapsulatedMessage err:&localError];
114 secerror("KVS sync %s. (%@)", result ? "succeeded" : "failed", localError);
116 SOSAccountConsiderLoggingEngineState(txn);
119 CFReleaseNull(encapsulatedMessage);
120 CFErrorPropagate(localError, error);
126 static bool SOSAccountSyncWithKVSPeer(SOSAccountTransaction* txn, CFStringRef peerID, CFErrorRef *error)
129 CFErrorRef localError = NULL;
131 secnotice("KVS Transport","Syncing with KVS capable peer: %@", peerID);
133 CFMutableSetRef peerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
134 CFSetAddValue(peerIDs, peerID);
136 result = SOSAccountSyncWithKVSPeers(txn, peerIDs, &localError);
137 secerror("KVS sync %s. (%@)", result ? "succeeded" : "failed", localError);
139 CFReleaseNull(peerIDs);
140 CFErrorPropagate(localError, error);
146 CFSetRef SOSAccountSyncWithPeersOverKVS(SOSAccountTransaction* txn, CFSetRef peers) {
147 CFMutableSetRef handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
149 CFSetForEach(peers, ^(const void *value) {
150 CFStringRef peerID = asString(value, NULL);
151 CFErrorRef localError = NULL;
152 if (peerID && SOSAccountSyncWithKVSPeer(txn, peerID, &localError)) {
153 CFSetAddValue(handled, peerID);
154 secnotice("KVS Transport", "synced with peer: %@", peerID);
156 secnotice("KVS Transport", "failed to sync with peer: %@ error: %@", peerID, localError);
163 CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peerIDs, CFErrorRef *error) {
164 CFMutableSetRef notMePeers = NULL;
165 CFMutableSetRef handledPeerIDs = NULL;
166 CFMutableSetRef peersForKVS = NULL;
168 SOSAccount* account = txn.account;
170 if(![account isInCircle:error])
172 handledPeerIDs = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
173 CFReleaseNull(notMePeers);
174 CFReleaseNull(peersForKVS);
175 return handledPeerIDs;
178 handledPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
179 peersForKVS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
181 SOSPeerInfoRef myPeerInfo = account.peerInfo;
184 CFReleaseNull(notMePeers);
185 CFReleaseNull(peersForKVS);
186 return handledPeerIDs;
189 CFStringRef myPeerID = SOSPeerInfoGetPeerID(myPeerInfo);
191 notMePeers = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
192 CFSetRemoveValue(notMePeers, myPeerID);
194 CFSetForEach(notMePeers, ^(const void *value) {
195 CFErrorRef localError = NULL;
196 CFStringRef peerID = asString(value, &localError);
197 SOSPeerInfoRef peerInfo = NULL;
198 SOSCircleRef circle = NULL;
199 SOSAccountTrustClassic *trust = account.trust;
200 circle = trust.trustedCircle;
201 require_quiet(peerID, skip);
203 peerInfo = SOSCircleCopyPeerWithID(circle, peerID, NULL);
204 if (peerInfo && SOSCircleHasValidSyncingPeer(circle, peerInfo, account.accountKey, NULL)){
205 CFSetAddValue(peersForKVS, peerID);
207 CFSetAddValue(handledPeerIDs, peerID);
211 CFReleaseNull(peerInfo);
213 secnotice("sync-with-peers", "Skipped peer ID: %@ due to %@", peerID, localError);
215 CFReleaseNull(localError);
218 CFSetRef handledKVSPeerIDs = SOSAccountSyncWithPeersOverKVS(txn, peersForKVS);
219 CFSetUnion(handledPeerIDs, handledKVSPeerIDs);
220 CFReleaseNull(handledKVSPeerIDs);
222 SOSAccountConsiderLoggingEngineState(txn);
224 CFReleaseNull(notMePeers);
225 CFReleaseNull(peersForKVS);
226 return handledPeerIDs;
229 CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peers, CFSetRef /* CFStringRef */ backupPeers, CFErrorRef *error)
231 CFErrorRef localError = NULL;
232 SOSAccount* account = txn.account;
234 CFMutableSetRef handled = SOSAccountSyncWithPeers(txn, peers, &localError);
237 secnotice("account-sync", "Peer Sync failed: %@", localError);
238 handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
240 CFReleaseNull(localError);
242 CFTypeRef engine = [account.kvs_message_transport SOSTransportMessageGetEngine];
243 CFSetRef engineHandled = SOSEngineSyncWithBackupPeers((SOSEngineRef)engine, backupPeers, false, error);
246 CFSetUnion(handled, engineHandled);
248 secnotice("account-sync", "Engine Backup Sync failed: %@", localError);
250 CFReleaseNull(localError);
251 CFReleaseNull(engineHandled);
256 CF_RETURNS_RETAINED CFSetRef SOSAccountCopyBackupPeersAndForceSync(SOSAccountTransaction* txn, CFErrorRef *error)
258 SOSEngineRef engine = (SOSEngineRef) [txn.account.kvs_message_transport SOSTransportMessageGetEngine];
260 NSArray* backupPeersArray = (NSArray*) CFBridgingRelease(SOSEngineCopyBackupPeerNames(engine, error));
261 NSSet* backupPeers = [[NSSet alloc] initWithArray: backupPeersArray];
262 return SOSEngineSyncWithBackupPeers(engine, (__bridge CFSetRef) backupPeers, true, error);
265 bool SOSAccountRequestSyncWithAllPeers(SOSAccountTransaction* txn, CFErrorRef *error)
267 SOSAccount* account = txn.account;
268 SOSAccountTrustClassic *trust = account.trust;
270 if (![account isInCircle:error])
273 NSMutableSet<NSString*>* allSyncingPeers = [NSMutableSet set];
274 SOSCircleRef circle = trust.trustedCircle;
276 SOSCircleForEachValidSyncingPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) {
277 [allSyncingPeers addObject: (__bridge NSString*) SOSPeerInfoGetPeerID(peer)];
280 [txn requestSyncWithPeers:allSyncingPeers];
286 // MARK: Syncing status functions
288 bool SOSAccountMessageFromPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error) {
289 bool success = false;
290 SOSAccount* account = txn.account;
291 require_quiet([account isInCircle:error], xit);
293 // This translation belongs inside KVS..way down in CKD, but for now we reach over and do it here.
294 CFStringRef peerMessage = SOSMessageKeyCreateFromPeerToTransport([account kvs_message_transport], (__bridge CFStringRef)(account.peerID), SOSPeerInfoGetPeerID(peer));
296 success = SOSCloudKeychainHasPendingKey(peerMessage, error);
297 CFReleaseNull(peerMessage);
303 bool SOSAccountSendToPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error) {
304 bool success = false;
305 SOSAccount* account = txn.account;
306 require_quiet([account isInCircle:error], xit);
308 success = SOSCCIsSyncPendingFor(SOSPeerInfoGetPeerID(peer), error);