]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountSync.m
Security-58286.270.3.0.1.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountSync.m
1
2 #include "SOSAccountPriv.h"
3 #include "SOSAccount.h"
4
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>
13
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>
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
30 void SOSAccountConsiderLoggingEngineState(SOSAccountTransaction* txn) {
31 static int engineLogCountDown = 0;
32
33 if(engineLogCountDown <= 0) {
34 SOSAccount* acct = txn.account;
35 CFTypeRef engine = [acct.kvs_message_transport SOSTransportMessageGetEngine];
36
37 SOSEngineLogState((SOSEngineRef)engine);
38 engineLogCountDown = LOG_ENGINE_STATE_INTERVAL;
39 } else {
40 engineLogCountDown--;
41 }
42 }
43
44 bool SOSAccountInflateTransports(SOSAccount* account, CFStringRef circleName, CFErrorRef *error){
45 bool success = false;
46
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);
53
54 account.key_transport = [[CKKeyParameter alloc] initWithAccount:account];
55 account.circle_transport = [[SOSKVSCircleStorageTransport alloc]initWithAccount:account andCircleName:(__bridge NSString *)(circleName)];
56
57 require_quiet(account.key_transport, fail);
58 require_quiet(account.circle_transport, fail);
59
60 account.kvs_message_transport = [[SOSMessageKVS alloc] initWithAccount:account andName:(__bridge NSString*)circleName];
61 require_quiet(account.kvs_message_transport, fail);
62
63 success = true;
64
65 fail:
66 return success;
67 }
68
69 //
70 // MARK: KVS Syncing
71 //
72
73 static bool SOSAccountSyncWithKVSPeers(SOSAccountTransaction* txn, CFSetRef peerIDs, CFErrorRef *error) {
74 SOSAccount* account = txn.account;
75 CFErrorRef localError = NULL;
76 bool result = false;
77
78 require_quiet([account isInCircle:error], xit);
79
80 result =[account.kvs_message_transport SOSTransportMessageSyncWithPeers:account.kvs_message_transport p:peerIDs err:&localError];
81
82 if (result)
83 SetCloudKeychainTraceValueForKey(kCloudKeychainNumberOfTimesSyncedWithPeers, 1);
84
85 xit:
86 if (!result) {
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;
91 }
92 CFErrorPropagate(localError, error);
93 localError = NULL;
94 }
95 return result;
96
97 }
98
99 bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransaction* txn, CFStringRef peerid, CFDataRef message, CFErrorRef *error) {
100 SOSAccount* account = txn.account;
101 bool result = false;
102 CFErrorRef localError = NULL;
103 CFDictionaryRef encapsulatedMessage = NULL;
104
105 secnotice("KVS Transport","Syncing with KVS capable peer: %@", peerid);
106 secnotice("KVS Transport", "message: %@", message);
107
108 require_quiet(message, xit);
109 require_quiet(peerid && CFStringGetLength(peerid) <= kSOSPeerIDLengthMax, xit);
110
111 encapsulatedMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerid, message, NULL);
112
113 result = [account.kvs_message_transport SOSTransportMessageSendMessages:account.kvs_message_transport pm:encapsulatedMessage err:&localError];
114 secerror("KVS sync %s. (%@)", result ? "succeeded" : "failed", localError);
115
116 SOSAccountConsiderLoggingEngineState(txn);
117
118 xit:
119 CFReleaseNull(encapsulatedMessage);
120 CFErrorPropagate(localError, error);
121
122 return result;
123 }
124
125
126 static bool SOSAccountSyncWithKVSPeer(SOSAccountTransaction* txn, CFStringRef peerID, CFErrorRef *error)
127 {
128 bool result = false;
129 CFErrorRef localError = NULL;
130
131 secnotice("KVS Transport","Syncing with KVS capable peer: %@", peerID);
132
133 CFMutableSetRef peerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
134 CFSetAddValue(peerIDs, peerID);
135
136 result = SOSAccountSyncWithKVSPeers(txn, peerIDs, &localError);
137 secerror("KVS sync %s. (%@)", result ? "succeeded" : "failed", localError);
138
139 CFReleaseNull(peerIDs);
140 CFErrorPropagate(localError, error);
141
142 return result;
143 }
144
145
146 CFSetRef SOSAccountSyncWithPeersOverKVS(SOSAccountTransaction* txn, CFSetRef peers) {
147 CFMutableSetRef handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
148
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);
155 } else {
156 secnotice("KVS Transport", "failed to sync with peer: %@ error: %@", peerID, localError);
157 }
158 });
159
160 return handled;
161 }
162
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;
167
168 SOSAccount* account = txn.account;
169
170 if(![account isInCircle:error])
171 {
172 handledPeerIDs = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
173 CFReleaseNull(notMePeers);
174 CFReleaseNull(peersForKVS);
175 return handledPeerIDs;
176 }
177
178 handledPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
179 peersForKVS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
180
181 SOSPeerInfoRef myPeerInfo = account.peerInfo;
182 if(!myPeerInfo)
183 {
184 CFReleaseNull(notMePeers);
185 CFReleaseNull(peersForKVS);
186 return handledPeerIDs;
187
188 }
189 CFStringRef myPeerID = SOSPeerInfoGetPeerID(myPeerInfo);
190
191 notMePeers = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs);
192 CFSetRemoveValue(notMePeers, myPeerID);
193
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);
202
203 peerInfo = SOSCircleCopyPeerWithID(circle, peerID, NULL);
204 if (peerInfo && SOSCircleHasValidSyncingPeer(circle, peerInfo, account.accountKey, NULL)){
205 CFSetAddValue(peersForKVS, peerID);
206 } else {
207 CFSetAddValue(handledPeerIDs, peerID);
208 }
209
210 skip:
211 CFReleaseNull(peerInfo);
212 if (localError) {
213 secnotice("sync-with-peers", "Skipped peer ID: %@ due to %@", peerID, localError);
214 }
215 CFReleaseNull(localError);
216 });
217
218 CFSetRef handledKVSPeerIDs = SOSAccountSyncWithPeersOverKVS(txn, peersForKVS);
219 CFSetUnion(handledPeerIDs, handledKVSPeerIDs);
220 CFReleaseNull(handledKVSPeerIDs);
221
222 SOSAccountConsiderLoggingEngineState(txn);
223
224 CFReleaseNull(notMePeers);
225 CFReleaseNull(peersForKVS);
226 return handledPeerIDs;
227 }
228
229 CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peers, CFSetRef /* CFStringRef */ backupPeers, CFErrorRef *error)
230 {
231 CFErrorRef localError = NULL;
232 SOSAccount* account = txn.account;
233
234 CFMutableSetRef handled = SOSAccountSyncWithPeers(txn, peers, &localError);
235
236 if (!handled) {
237 secnotice("account-sync", "Peer Sync failed: %@", localError);
238 handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
239 }
240 CFReleaseNull(localError);
241
242 CFTypeRef engine = [account.kvs_message_transport SOSTransportMessageGetEngine];
243 CFSetRef engineHandled = SOSEngineSyncWithBackupPeers((SOSEngineRef)engine, backupPeers, false, error);
244
245 if (engineHandled) {
246 CFSetUnion(handled, engineHandled);
247 } else {
248 secnotice("account-sync", "Engine Backup Sync failed: %@", localError);
249 }
250 CFReleaseNull(localError);
251 CFReleaseNull(engineHandled);
252
253 return handled;
254 }
255
256 CF_RETURNS_RETAINED CFSetRef SOSAccountCopyBackupPeersAndForceSync(SOSAccountTransaction* txn, CFErrorRef *error)
257 {
258 SOSEngineRef engine = (SOSEngineRef) [txn.account.kvs_message_transport SOSTransportMessageGetEngine];
259
260 NSArray* backupPeersArray = (NSArray*) CFBridgingRelease(SOSEngineCopyBackupPeerNames(engine, error));
261 NSSet* backupPeers = [[NSSet alloc] initWithArray: backupPeersArray];
262 return SOSEngineSyncWithBackupPeers(engine, (__bridge CFSetRef) backupPeers, true, error);
263 }
264
265 bool SOSAccountRequestSyncWithAllPeers(SOSAccountTransaction* txn, CFErrorRef *error)
266 {
267 SOSAccount* account = txn.account;
268 SOSAccountTrustClassic *trust = account.trust;
269
270 if (![account isInCircle:error])
271 return false;
272
273 NSMutableSet<NSString*>* allSyncingPeers = [NSMutableSet set];
274 SOSCircleRef circle = trust.trustedCircle;
275
276 SOSCircleForEachValidSyncingPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) {
277 [allSyncingPeers addObject: (__bridge NSString*) SOSPeerInfoGetPeerID(peer)];
278 });
279
280 [txn requestSyncWithPeers:allSyncingPeers];
281
282 return true;
283 }
284
285 //
286 // MARK: Syncing status functions
287 //
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);
292
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));
295
296 success = SOSCloudKeychainHasPendingKey(peerMessage, error);
297 CFReleaseNull(peerMessage);
298
299 xit:
300 return success;
301 }
302
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);
307
308 success = SOSCCIsSyncPendingFor(SOSPeerInfoGetPeerID(peer), error);
309 xit:
310 return success;
311
312
313 }
314