]> git.saurik.com Git - apple/security.git/blame - keychain/SecureObjectSync/SOSAccountSync.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSAccountSync.m
CommitLineData
6b200bc3
A
1
2#include "SOSAccountPriv.h"
866f8763 3#include "SOSAccount.h"
6b200bc3 4
b54c578e
A
5#include "keychain/SecureObjectSync/SOSKVSKeys.h"
6#include "keychain/SecureObjectSync/SOSTransportCircle.h"
7#include "keychain/SecureObjectSync/SOSTransportCircleKVS.h"
8#include "keychain/SecureObjectSync/SOSTransportMessage.h"
9#include "keychain/SecureObjectSync/SOSKVSKeys.h"
10#include "keychain/SecureObjectSync/SOSTransport.h"
11#include "keychain/SecureObjectSync/SOSTransportKeyParameter.h"
12#include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
13
14#import "keychain/SecureObjectSync/SOSAccountTrust.h"
15#import "keychain/SecureObjectSync/SOSTransport.h"
16#import "keychain/SecureObjectSync/SOSTransportKeyParameter.h"
17#include "keychain/SecureObjectSync/SOSTransportMessage.h"
18#import "keychain/SecureObjectSync/SOSTransportMessageKVS.h"
19#include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
20#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
21#include "keychain/SecureObjectSync/SOSInternal.h"
6b200bc3
A
22
23#include <CoreFoundation/CoreFoundation.h>
24
25#include <utilities/SecCFError.h>
26
27// MARK: Engine Logging
28#define LOG_ENGINE_STATE_INTERVAL 20
b54c578e
A
29#define LOG_CATEGORY "account-sync"
30
31static bool SOSReadyToSync(SOSAccount *account, CFErrorRef *error) {
32 if (![account isInCircle:error]) {
33 secnotice(LOG_CATEGORY, "Not performing requested sync operation: not in circle yet");
34 return false;
35 }
36 return true;
37}
6b200bc3 38
866f8763 39void SOSAccountConsiderLoggingEngineState(SOSAccountTransaction* txn) {
6b200bc3
A
40 static int engineLogCountDown = 0;
41
42 if(engineLogCountDown <= 0) {
866f8763 43 SOSAccount* acct = txn.account;
b54c578e
A
44 if(SOSReadyToSync(acct, NULL)) {
45 CFTypeRef engine = [acct.kvs_message_transport SOSTransportMessageGetEngine];
46 SOSEngineLogState((SOSEngineRef)engine);
47 engineLogCountDown = LOG_ENGINE_STATE_INTERVAL;
48 }
6b200bc3
A
49 } else {
50 engineLogCountDown--;
51 }
52}
53
866f8763
A
54bool SOSAccountInflateTransports(SOSAccount* account, CFStringRef circleName, CFErrorRef *error){
55 bool success = false;
56
57 if(account.key_transport)
58 SOSUnregisterTransportKeyParameter(account.key_transport);
59 if(account.circle_transport)
60 SOSUnregisterTransportCircle(account.circle_transport);
866f8763
A
61 if(account.kvs_message_transport)
62 SOSUnregisterTransportMessage((SOSMessage*)account.kvs_message_transport);
63
64 account.key_transport = [[CKKeyParameter alloc] initWithAccount:account];
65 account.circle_transport = [[SOSKVSCircleStorageTransport alloc]initWithAccount:account andCircleName:(__bridge NSString *)(circleName)];
6b200bc3 66
866f8763
A
67 require_quiet(account.key_transport, fail);
68 require_quiet(account.circle_transport, fail);
79b9da22 69
866f8763
A
70 account.kvs_message_transport = [[SOSMessageKVS alloc] initWithAccount:account andName:(__bridge NSString*)circleName];
71 require_quiet(account.kvs_message_transport, fail);
72
73 success = true;
74
75fail:
76 return success;
77}
78
6b200bc3
A
79//
80// MARK: KVS Syncing
81//
82
866f8763
A
83static bool SOSAccountSyncWithKVSPeers(SOSAccountTransaction* txn, CFSetRef peerIDs, CFErrorRef *error) {
84 SOSAccount* account = txn.account;
6b200bc3
A
85 CFErrorRef localError = NULL;
86 bool result = false;
87
b54c578e
A
88 if(SOSReadyToSync(account, error)) {
89 result =[account.kvs_message_transport SOSTransportMessageSyncWithPeers:account.kvs_message_transport p:peerIDs err:&localError];
90 }
6b200bc3
A
91 if (!result) {
92 // Tell account to update SOSEngine with current trusted peers
93 if (isSOSErrorCoded(localError, kSOSErrorPeerNotFound)) {
b54c578e 94 secnotice(LOG_CATEGORY, "Arming account to update SOSEngine with current trusted peers");
866f8763 95 account.engine_peer_state_needs_repair = true;
6b200bc3
A
96 }
97 CFErrorPropagate(localError, error);
98 localError = NULL;
99 }
100 return result;
101
102}
103
866f8763 104bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransaction* txn, CFStringRef peerid, CFDataRef message, CFErrorRef *error) {
b54c578e 105 //murfxx protect
866f8763 106 SOSAccount* account = txn.account;
6b200bc3
A
107 bool result = false;
108 CFErrorRef localError = NULL;
109 CFDictionaryRef encapsulatedMessage = NULL;
110
b54c578e
A
111 secnotice(LOG_CATEGORY,"Syncing with KVS capable peer: %@", peerid);
112 secnotice(LOG_CATEGORY, "message: %@", message);
6b200bc3
A
113
114 require_quiet(message, xit);
29734401 115 require_quiet(peerid && CFStringGetLength(peerid) <= kSOSPeerIDLengthMax, xit);
b54c578e
A
116 if(SOSReadyToSync(account, &localError)) {
117 encapsulatedMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerid, message, NULL);
118 result = [account.kvs_message_transport SOSTransportMessageSendMessages:account.kvs_message_transport pm:encapsulatedMessage err:&localError];
119 secnotice(LOG_CATEGORY, "KVS sync %s. (%@)", result ? "succeeded" : "failed", localError);
120 SOSAccountConsiderLoggingEngineState(txn);
121 }
6b200bc3
A
122
123xit:
124 CFReleaseNull(encapsulatedMessage);
125 CFErrorPropagate(localError, error);
126
127 return result;
128}
129
130
866f8763 131static bool SOSAccountSyncWithKVSPeer(SOSAccountTransaction* txn, CFStringRef peerID, CFErrorRef *error)
6b200bc3
A
132{
133 bool result = false;
134 CFErrorRef localError = NULL;
b54c578e 135 SOSAccount* account = txn.account;
6b200bc3 136
b54c578e
A
137 if(SOSReadyToSync(account, error)) {
138 secnotice(LOG_CATEGORY,"Syncing with KVS capable peer: %@", peerID);
139 CFMutableSetRef peerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
140 CFSetAddValue(peerIDs, peerID);
141 result = SOSAccountSyncWithKVSPeers(txn, peerIDs, &localError);
142 secnotice(LOG_CATEGORY, "KVS sync %s. (%@)", result ? "succeeded" : "failed", localError);
6b200bc3 143
b54c578e
A
144 CFReleaseNull(peerIDs);
145 CFErrorPropagate(localError, error);
146 }
6b200bc3
A
147
148 return result;
149}
150
6b200bc3 151
866f8763 152CFSetRef SOSAccountSyncWithPeersOverKVS(SOSAccountTransaction* txn, CFSetRef peers) {
6b200bc3 153 CFMutableSetRef handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
b54c578e
A
154 if(SOSReadyToSync(txn.account, NULL)) {
155 CFSetForEach(peers, ^(const void *value) {
156 CFStringRef peerID = asString(value, NULL);
157 CFErrorRef localError = NULL;
158 if (peerID && SOSAccountSyncWithKVSPeer(txn, peerID, &localError)) {
159 CFSetAddValue(handled, peerID);
160 secnotice(LOG_CATEGORY, "synced with peer: %@", peerID);
161 } else {
162 secnotice(LOG_CATEGORY, "failed to sync with peer: %@ error: %@", peerID, localError);
163 }
164 CFReleaseNull(localError);
165 });
166 }
6b200bc3
A
167
168 return handled;
169}
170
866f8763 171CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peerIDs, CFErrorRef *error) {
6b200bc3
A
172 CFMutableSetRef notMePeers = NULL;
173 CFMutableSetRef handledPeerIDs = NULL;
6b200bc3
A
174 CFMutableSetRef peersForKVS = NULL;
175
866f8763 176 SOSAccount* account = txn.account;
b54c578e 177 if(!SOSReadyToSync(account, error)) {
866f8763
A
178 handledPeerIDs = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
179 CFReleaseNull(notMePeers);
866f8763
A
180 CFReleaseNull(peersForKVS);
181 return handledPeerIDs;
182 }
6b200bc3
A
183
184 handledPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
6b200bc3
A
185 peersForKVS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
186
866f8763
A
187 SOSPeerInfoRef myPeerInfo = account.peerInfo;
188 if(!myPeerInfo)
189 {
190 CFReleaseNull(notMePeers);
866f8763
A
191 CFReleaseNull(peersForKVS);
192 return handledPeerIDs;
6b200bc3 193
866f8763 194 }
6b200bc3
A
195 CFStringRef myPeerID = SOSPeerInfoGetPeerID(myPeerInfo);
196
197 notMePeers = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
198 CFSetRemoveValue(notMePeers, myPeerID);
6b200bc3
A
199
200 CFSetForEach(notMePeers, ^(const void *value) {
201 CFErrorRef localError = NULL;
202 CFStringRef peerID = asString(value, &localError);
203 SOSPeerInfoRef peerInfo = NULL;
866f8763
A
204 SOSCircleRef circle = NULL;
205 SOSAccountTrustClassic *trust = account.trust;
206 circle = trust.trustedCircle;
6b200bc3
A
207 require_quiet(peerID, skip);
208
866f8763 209 peerInfo = SOSCircleCopyPeerWithID(circle, peerID, NULL);
79b9da22
A
210 if (peerInfo && SOSCircleHasValidSyncingPeer(circle, peerInfo, account.accountKey, NULL)){
211 CFSetAddValue(peersForKVS, peerID);
6b200bc3
A
212 } else {
213 CFSetAddValue(handledPeerIDs, peerID);
214 }
215
216 skip:
217 CFReleaseNull(peerInfo);
218 if (localError) {
b54c578e 219 secnotice(LOG_CATEGORY, "Skipped peer ID: %@ due to %@", peerID, localError);
6b200bc3
A
220 }
221 CFReleaseNull(localError);
222 });
223
6b200bc3
A
224 CFSetRef handledKVSPeerIDs = SOSAccountSyncWithPeersOverKVS(txn, peersForKVS);
225 CFSetUnion(handledPeerIDs, handledKVSPeerIDs);
226 CFReleaseNull(handledKVSPeerIDs);
227
228 SOSAccountConsiderLoggingEngineState(txn);
229
6b200bc3 230 CFReleaseNull(notMePeers);
6b200bc3
A
231 CFReleaseNull(peersForKVS);
232 return handledPeerIDs;
233}
234
866f8763 235CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peers, CFSetRef /* CFStringRef */ backupPeers, CFErrorRef *error)
6b200bc3
A
236{
237 CFErrorRef localError = NULL;
866f8763
A
238 SOSAccount* account = txn.account;
239
b54c578e
A
240 if(!SOSReadyToSync(account, error)) {
241 return CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
242 }
243
6b200bc3
A
244 CFMutableSetRef handled = SOSAccountSyncWithPeers(txn, peers, &localError);
245
6b200bc3 246 if (!handled) {
b54c578e 247 secnotice(LOG_CATEGORY, "Peer Sync failed: %@", localError);
6b200bc3
A
248 handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
249 }
250 CFReleaseNull(localError);
866f8763
A
251
252 CFTypeRef engine = [account.kvs_message_transport SOSTransportMessageGetEngine];
253 CFSetRef engineHandled = SOSEngineSyncWithBackupPeers((SOSEngineRef)engine, backupPeers, false, error);
254
6b200bc3
A
255 if (engineHandled) {
256 CFSetUnion(handled, engineHandled);
257 } else {
b54c578e 258 secnotice(LOG_CATEGORY, "Engine Backup Sync failed: %@", localError);
6b200bc3
A
259 }
260 CFReleaseNull(localError);
261 CFReleaseNull(engineHandled);
262
263 return handled;
264}
265
866f8763 266CF_RETURNS_RETAINED CFSetRef SOSAccountCopyBackupPeersAndForceSync(SOSAccountTransaction* txn, CFErrorRef *error)
6b200bc3 267{
b54c578e
A
268 SOSAccount* account = txn.account;
269
270 if(!SOSReadyToSync(account, error)) {
271 return false;
272 }
6b200bc3 273
b54c578e 274 SOSEngineRef engine = (SOSEngineRef) [txn.account.kvs_message_transport SOSTransportMessageGetEngine];
866f8763
A
275 NSArray* backupPeersArray = (NSArray*) CFBridgingRelease(SOSEngineCopyBackupPeerNames(engine, error));
276 NSSet* backupPeers = [[NSSet alloc] initWithArray: backupPeersArray];
277 return SOSEngineSyncWithBackupPeers(engine, (__bridge CFSetRef) backupPeers, true, error);
278}
6b200bc3 279
866f8763
A
280bool SOSAccountRequestSyncWithAllPeers(SOSAccountTransaction* txn, CFErrorRef *error)
281{
282 SOSAccount* account = txn.account;
283 SOSAccountTrustClassic *trust = account.trust;
6b200bc3 284
b54c578e 285 if(!SOSReadyToSync(account, error)) {
866f8763 286 return false;
b54c578e 287 }
6b200bc3 288
866f8763
A
289 NSMutableSet<NSString*>* allSyncingPeers = [NSMutableSet set];
290 SOSCircleRef circle = trust.trustedCircle;
6b200bc3 291
866f8763
A
292 SOSCircleForEachValidSyncingPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) {
293 [allSyncingPeers addObject: (__bridge NSString*) SOSPeerInfoGetPeerID(peer)];
294 });
6b200bc3 295
866f8763
A
296 [txn requestSyncWithPeers:allSyncingPeers];
297
298 return true;
6b200bc3
A
299}
300
301//
302// MARK: Syncing status functions
303//
866f8763 304bool SOSAccountMessageFromPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error) {
6b200bc3 305 bool success = false;
866f8763 306 SOSAccount* account = txn.account;
b54c578e
A
307 if(SOSReadyToSync(account, error)) {
308 // This translation belongs inside KVS..way down in CKD, but for now we reach over and do it here.
309 CFStringRef peerMessage = SOSMessageKeyCreateFromPeerToTransport([account kvs_message_transport], (__bridge CFStringRef)(account.peerID), SOSPeerInfoGetPeerID(peer));
310 success = SOSCloudKeychainHasPendingKey(peerMessage, error);
311 CFReleaseNull(peerMessage);
312 }
6b200bc3
A
313 return success;
314}
315
866f8763 316bool SOSAccountSendToPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error) {
6b200bc3 317 bool success = false;
866f8763 318 SOSAccount* account = txn.account;
b54c578e
A
319 if(SOSReadyToSync(account, error)) {
320 success = SOSCCIsSyncPendingFor(SOSPeerInfoGetPeerID(peer), error);
321 }
6b200bc3 322 return success;
6b200bc3 323}
866f8763 324