]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSAccountSync.m
Security-59306.11.20.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSAccountSync.m
1
2 #include "SOSAccountPriv.h"
3 #include "SOSAccount.h"
4
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"
22
23 #include <CoreFoundation/CoreFoundation.h>
24
25 #include <utilities/SecCFError.h>
26
27 // MARK: Engine Logging
28 #define LOG_ENGINE_STATE_INTERVAL 20
29 #define LOG_CATEGORY "account-sync"
30
31 static 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 }
38
39 void SOSAccountConsiderLoggingEngineState(SOSAccountTransaction* txn) {
40 static int engineLogCountDown = 0;
41
42 if(engineLogCountDown <= 0) {
43 SOSAccount* acct = txn.account;
44 if(SOSReadyToSync(acct, NULL)) {
45 CFTypeRef engine = [acct.kvs_message_transport SOSTransportMessageGetEngine];
46 SOSEngineLogState((SOSEngineRef)engine);
47 engineLogCountDown = LOG_ENGINE_STATE_INTERVAL;
48 }
49 } else {
50 engineLogCountDown--;
51 }
52 }
53
54 bool 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);
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)];
66
67 require_quiet(account.key_transport, fail);
68 require_quiet(account.circle_transport, fail);
69
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
75 fail:
76 return success;
77 }
78
79 //
80 // MARK: KVS Syncing
81 //
82
83 static bool SOSAccountSyncWithKVSPeers(SOSAccountTransaction* txn, CFSetRef peerIDs, CFErrorRef *error) {
84 SOSAccount* account = txn.account;
85 CFErrorRef localError = NULL;
86 bool result = false;
87
88 if(SOSReadyToSync(account, error)) {
89 result =[account.kvs_message_transport SOSTransportMessageSyncWithPeers:account.kvs_message_transport p:peerIDs err:&localError];
90 }
91 if (!result) {
92 // Tell account to update SOSEngine with current trusted peers
93 if (isSOSErrorCoded(localError, kSOSErrorPeerNotFound)) {
94 secnotice(LOG_CATEGORY, "Arming account to update SOSEngine with current trusted peers");
95 account.engine_peer_state_needs_repair = true;
96 }
97 CFErrorPropagate(localError, error);
98 localError = NULL;
99 }
100 return result;
101
102 }
103
104 bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransaction* txn, CFStringRef peerid, CFDataRef message, CFErrorRef *error) {
105 //murfxx protect
106 SOSAccount* account = txn.account;
107 bool result = false;
108 CFErrorRef localError = NULL;
109 CFDictionaryRef encapsulatedMessage = NULL;
110
111 secnotice(LOG_CATEGORY,"Syncing with KVS capable peer: %@", peerid);
112 secnotice(LOG_CATEGORY, "message: %@", message);
113
114 require_quiet(message, xit);
115 require_quiet(peerid && CFStringGetLength(peerid) <= kSOSPeerIDLengthMax, xit);
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 }
122
123 xit:
124 CFReleaseNull(encapsulatedMessage);
125 CFErrorPropagate(localError, error);
126
127 return result;
128 }
129
130
131 static bool SOSAccountSyncWithKVSPeer(SOSAccountTransaction* txn, CFStringRef peerID, CFErrorRef *error)
132 {
133 bool result = false;
134 CFErrorRef localError = NULL;
135 SOSAccount* account = txn.account;
136
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);
143
144 CFReleaseNull(peerIDs);
145 CFErrorPropagate(localError, error);
146 }
147
148 return result;
149 }
150
151
152 CFSetRef SOSAccountSyncWithPeersOverKVS(SOSAccountTransaction* txn, CFSetRef peers) {
153 CFMutableSetRef handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
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 }
167
168 return handled;
169 }
170
171 CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peerIDs, CFErrorRef *error) {
172 CFMutableSetRef notMePeers = NULL;
173 CFMutableSetRef handledPeerIDs = NULL;
174 CFMutableSetRef peersForKVS = NULL;
175
176 SOSAccount* account = txn.account;
177 if(!SOSReadyToSync(account, error)) {
178 handledPeerIDs = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
179 CFReleaseNull(notMePeers);
180 CFReleaseNull(peersForKVS);
181 return handledPeerIDs;
182 }
183
184 handledPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
185 peersForKVS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
186
187 SOSPeerInfoRef myPeerInfo = account.peerInfo;
188 if(!myPeerInfo)
189 {
190 CFReleaseNull(notMePeers);
191 CFReleaseNull(peersForKVS);
192 return handledPeerIDs;
193
194 }
195 CFStringRef myPeerID = SOSPeerInfoGetPeerID(myPeerInfo);
196
197 notMePeers = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
198 CFSetRemoveValue(notMePeers, myPeerID);
199
200 CFSetForEach(notMePeers, ^(const void *value) {
201 CFErrorRef localError = NULL;
202 CFStringRef peerID = asString(value, &localError);
203 SOSPeerInfoRef peerInfo = NULL;
204 SOSCircleRef circle = NULL;
205 SOSAccountTrustClassic *trust = account.trust;
206 circle = trust.trustedCircle;
207 require_quiet(peerID, skip);
208
209 peerInfo = SOSCircleCopyPeerWithID(circle, peerID, NULL);
210 if (peerInfo && SOSCircleHasValidSyncingPeer(circle, peerInfo, account.accountKey, NULL)){
211 CFSetAddValue(peersForKVS, peerID);
212 } else {
213 CFSetAddValue(handledPeerIDs, peerID);
214 }
215
216 skip:
217 CFReleaseNull(peerInfo);
218 if (localError) {
219 secnotice(LOG_CATEGORY, "Skipped peer ID: %@ due to %@", peerID, localError);
220 }
221 CFReleaseNull(localError);
222 });
223
224 CFSetRef handledKVSPeerIDs = SOSAccountSyncWithPeersOverKVS(txn, peersForKVS);
225 CFSetUnion(handledPeerIDs, handledKVSPeerIDs);
226 CFReleaseNull(handledKVSPeerIDs);
227
228 SOSAccountConsiderLoggingEngineState(txn);
229
230 CFReleaseNull(notMePeers);
231 CFReleaseNull(peersForKVS);
232 return handledPeerIDs;
233 }
234
235 CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peers, CFSetRef /* CFStringRef */ backupPeers, CFErrorRef *error)
236 {
237 CFErrorRef localError = NULL;
238 SOSAccount* account = txn.account;
239
240 if(!SOSReadyToSync(account, error)) {
241 return CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
242 }
243
244 CFMutableSetRef handled = SOSAccountSyncWithPeers(txn, peers, &localError);
245
246 if (!handled) {
247 secnotice(LOG_CATEGORY, "Peer Sync failed: %@", localError);
248 handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
249 }
250 CFReleaseNull(localError);
251
252 CFTypeRef engine = [account.kvs_message_transport SOSTransportMessageGetEngine];
253 CFSetRef engineHandled = SOSEngineSyncWithBackupPeers((SOSEngineRef)engine, backupPeers, false, error);
254
255 if (engineHandled) {
256 CFSetUnion(handled, engineHandled);
257 } else {
258 secnotice(LOG_CATEGORY, "Engine Backup Sync failed: %@", localError);
259 }
260 CFReleaseNull(localError);
261 CFReleaseNull(engineHandled);
262
263 return handled;
264 }
265
266 CF_RETURNS_RETAINED CFSetRef SOSAccountCopyBackupPeersAndForceSync(SOSAccountTransaction* txn, CFErrorRef *error)
267 {
268 SOSAccount* account = txn.account;
269
270 if(!SOSReadyToSync(account, error)) {
271 return false;
272 }
273
274 SOSEngineRef engine = (SOSEngineRef) [txn.account.kvs_message_transport SOSTransportMessageGetEngine];
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 }
279
280 bool SOSAccountRequestSyncWithAllPeers(SOSAccountTransaction* txn, CFErrorRef *error)
281 {
282 SOSAccount* account = txn.account;
283 SOSAccountTrustClassic *trust = account.trust;
284
285 if(!SOSReadyToSync(account, error)) {
286 return false;
287 }
288
289 NSMutableSet<NSString*>* allSyncingPeers = [NSMutableSet set];
290 SOSCircleRef circle = trust.trustedCircle;
291
292 SOSCircleForEachValidSyncingPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) {
293 [allSyncingPeers addObject: (__bridge NSString*) SOSPeerInfoGetPeerID(peer)];
294 });
295
296 [txn requestSyncWithPeers:allSyncingPeers];
297
298 return true;
299 }
300
301 //
302 // MARK: Syncing status functions
303 //
304 bool SOSAccountMessageFromPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error) {
305 bool success = false;
306 SOSAccount* account = txn.account;
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 }
313 return success;
314 }
315
316 bool SOSAccountSendToPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error) {
317 bool success = false;
318 SOSAccount* account = txn.account;
319 if(SOSReadyToSync(account, error)) {
320 success = SOSCCIsSyncPendingFor(SOSPeerInfoGetPeerID(peer), error);
321 }
322 return success;
323 }
324