]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/Regressions/SOSTransportTestTransports.m
Security-58286.31.2.tar.gz
[apple/security.git] / OSX / sec / securityd / Regressions / SOSTransportTestTransports.m
1 #include <CoreFoundation/CoreFoundation.h>
2 #include <CoreFoundation/CFRuntime.h>
3
4 #include <Security/SecureObjectSync/SOSAccount.h>
5 #include <Security/SecureObjectSync/SOSAccountPriv.h>
6 #include <Security/SecureObjectSync/SOSTransport.h>
7 #import <Security/SecureObjectSync/SOSTransportKeyParameter.h>
8 #import <Security/SecureObjectSync/SOSTransportCircleKVS.h>
9 #import <Security/SecureObjectSync/SOSTransportMessageIDS.h>
10 #import <Security/SecureObjectSync/SOSTransportMessageKVS.h>
11 #include <Security/SecureObjectSync/SOSKVSKeys.h>
12 #include <Security/SecureObjectSync/SOSPeerCoder.h>
13 #include <utilities/SecCFWrappers.h>
14 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
15 #import <Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h>
16 #import <Security/SecureObjectSync/SOSAccountTrustClassic+Identity.h>
17
18 #include "SOSTransportTestTransports.h"
19 #include "SOSAccountTesting.h"
20
21 CFMutableArrayRef key_transports = NULL;
22 CFMutableArrayRef circle_transports = NULL;
23 CFMutableArrayRef message_transports = NULL;
24
25 ///
26 //Mark Test Key Parameter Transport
27 ///
28
29 @implementation CKKeyParameterTest
30
31 -(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) n andCircleName:(CFStringRef) cN
32 {
33 self = [super init];
34 if(self){
35 self.name = CFRetainSafe(n);
36 self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
37 self.account = acct;
38 self.circleName = CFRetainSafe(cN);
39
40 if(!key_transports)
41 key_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
42 CFArrayAppendValue(key_transports, (__bridge CFTypeRef)((CKKeyParameter*)self));
43
44 SOSRegisterTransportKeyParameter((CKKeyParameter*)self);
45 }
46 return self;
47 }
48
49 -(bool) SOSTransportKeyParameterHandleKeyParameterChanges:(CKKeyParameterTest*) transport data:(CFDataRef) data err:(CFErrorRef) error
50 {
51 SOSAccount* acct = transport.account;
52 return SOSAccountHandleParametersChange(acct, data, &error);
53 }
54
55
56 -(void) SOSTransportKeyParameterHandleNewAccount:(CKKeyParameterTest*) transport acct:(SOSAccount*) acct
57 {
58
59 if(key_transports){
60 CFArrayRemoveAllValue(key_transports, (__bridge CFTypeRef)(acct.key_transport));
61 }
62 if(message_transports){
63 CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)acct.ids_message_transport);
64 CFArrayRemoveAllValue(message_transports, (__bridge CFTypeRef)acct.kvs_message_transport);
65 }
66 if(circle_transports)
67 CFArrayRemoveAllValue(circle_transports, (__bridge CFTypeRef)(acct.circle_transport));
68
69 SOSAccountSetToNew(acct);
70 SOSAccountResetToTest(acct, transport.name);
71 }
72
73 CFStringRef SOSTransportKeyParameterTestGetName(CKKeyParameterTest* transport){
74 return transport.name;
75 }
76
77 void SOSTransportKeyParameterTestSetName(CKKeyParameterTest* transport, CFStringRef accountName){
78 transport.name = accountName;
79 }
80
81 SOSAccount* SOSTransportKeyParameterTestGetAccount(CKKeyParameterTest* transport){
82 return ((CKKeyParameter*)transport).account;
83 }
84
85 CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(CKKeyParameterTest* transport){
86 return transport.changes;
87 }
88
89 void SOSTransportKeyParameterTestClearChanges(CKKeyParameterTest* transport){
90 transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
91 }
92
93 -(bool) SOSTransportKeyParameterPublishCloudParameters:(CKKeyParameterTest*) transport data:(CFDataRef)newParameters err:(CFErrorRef*) error
94 {
95 if(!transport.changes)
96 transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
97
98 CFDictionarySetValue(transport.changes, kSOSKVSKeyParametersKey, newParameters);
99
100 return true;
101 }
102 @end
103
104
105 ///
106 //MARK: Test Circle Transport
107 ///
108 @implementation SOSCircleStorageTransportTest
109 @synthesize accountName = accountName;
110
111 -(id)init
112 {
113 return [super init];
114 }
115
116 CFStringRef SOSTransportCircleTestGetName(SOSCircleStorageTransportTest* transport){
117 return (__bridge CFStringRef)(transport.accountName);
118 }
119 void SOSTransportCircleTestSetName(SOSCircleStorageTransportTest* transport, CFStringRef name){
120 transport.accountName = nil;
121 transport.accountName = (__bridge NSString *)(name);
122 }
123
124 -(CFMutableDictionaryRef) SOSTransportCircleTestGetChanges
125 {
126 return (__bridge CFMutableDictionaryRef)(self.pending_changes);
127 }
128
129 void SOSTransportCircleTestClearChanges(SOSCircleStorageTransportTest* transport){
130 transport.pending_changes = [NSMutableDictionary dictionary];
131 }
132
133 -(id) initWithAccount:(SOSAccount *)acct andWithAccountName:(CFStringRef)acctName andCircleName:(CFStringRef)cName
134 {
135 self = [super init];
136 if(self){
137 self.account = acct;
138 self.accountName = (__bridge NSString *)(acctName);
139 self.circleName = (__bridge NSString*)cName;
140 self.pending_changes = [NSMutableDictionary dictionary];
141 if(!circle_transports)
142 circle_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
143 CFArrayAppendValue(circle_transports, (__bridge CFTypeRef)self);
144
145 SOSRegisterTransportCircle((SOSCircleStorageTransportTest*)self);
146 }
147 return self;
148 }
149
150 -(bool) kvsRingFlushChanges:(CFErrorRef*) error
151 {
152 return true;
153 }
154
155 -(bool) kvsRingPostRing:(CFStringRef) ringName ring:(CFDataRef) ring err:(CFErrorRef *)error
156 {
157 CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error);
158 CFMutableDictionaryRef changes = [self SOSTransportCircleTestGetChanges];
159 CFDictionaryAddValue(changes, ringKey, ring);
160 CFReleaseNull(ringKey);
161 return true;
162 }
163
164 -(bool) kvssendDebugInfo:(CFStringRef) type debug:(CFTypeRef) debugInfo err:(CFErrorRef *)error
165 {
166 CFMutableDictionaryRef changes = [self SOSTransportCircleTestGetChanges];
167 CFDictionaryAddValue(changes, type, debugInfo);
168 return true;
169 }
170
171 -(bool) postRetirement:(CFStringRef)cName peer:(SOSPeerInfoRef)peer err:(CFErrorRef *)error
172 {
173 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(cName, SOSPeerInfoGetPeerID(peer));
174 CFDataRef retirement_data = SOSPeerInfoCopyEncodedData(peer, kCFAllocatorDefault, error);
175
176 if (retirement_key)
177 [self testAddToChanges:retirement_key data:retirement_data];
178
179 CFReleaseNull(retirement_key);
180 CFReleaseNull(retirement_data);
181 return true;
182 }
183
184 -(bool) flushChanges:(CFErrorRef *)error
185 {
186 return true;
187 }
188
189 -(void) testAddToChanges:(CFStringRef) message_key data:(CFDataRef) message_data
190 {
191 if (self.pending_changes == NULL) {
192 self.pending_changes = [NSMutableDictionary dictionary];
193 }
194 if (message_data == NULL) {
195 [self.pending_changes setObject:[NSNull null] forKey:(__bridge NSString*)(message_key)];
196 } else {
197 [self.pending_changes setObject:(__bridge NSData*)message_data forKey:(__bridge NSString*)message_key];
198 }
199 secnotice("circle-changes", "Adding circle change %@ %@->%@", self.accountName, message_key, message_data);
200 }
201
202 -(void) SOSTransportCircleTestAddBulkToChanges:(CFDictionaryRef) updates
203 {
204 if (self.pending_changes == NULL) {
205 self.pending_changes = [[NSMutableDictionary alloc]initWithDictionary:(__bridge NSDictionary * _Nonnull)(updates)];
206
207 }
208 else{
209 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
210 [self.pending_changes setObject:(__bridge id _Nonnull)value forKey:(__bridge id _Nonnull)key];
211 });
212 }
213 }
214
215
216 -(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error
217 {
218 bool success = true;
219 CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
220
221 CFDictionaryForEach(retirements, ^(const void *key, const void *value) {
222 if (isString(key) && isArray(value)) {
223 CFStringRef circle_name = (CFStringRef) key;
224 CFArrayRef retirees = (CFArrayRef) value;
225
226 CFArrayForEach(retirees, ^(const void *value) {
227 if (isString(value)) {
228 CFStringRef retiree_id = (CFStringRef) value;
229
230 CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id);
231
232 CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull);
233
234 CFReleaseSafe(kvsKey);
235 }
236 });
237 }
238 });
239
240 if(CFDictionaryGetCount(keysToWrite)) {
241 [self SOSTransportCircleTestAddBulkToChanges:keysToWrite];
242 }
243 CFReleaseNull(keysToWrite);
244
245 return success;
246 }
247
248 bool SOSTransportCircleTestRemovePendingChange(SOSCircleStorageTransportTest* transport, CFStringRef circleName, CFErrorRef *error){
249 CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error);
250 if (circle_key)
251 [transport.pending_changes removeObjectForKey:(__bridge NSString*)circle_key];
252 CFReleaseNull(circle_key);
253 return true;
254 }
255
256 -(bool) postCircle:(CFStringRef)cName circleData:(CFDataRef)circle_data err:(CFErrorRef *)error
257 {
258 CFStringRef circle_key = SOSCircleKeyCreateWithName(cName, error);
259 if (circle_key)
260 [self testAddToChanges:circle_key data:circle_data];
261 CFReleaseNull(circle_key);
262
263 return true;
264 }
265
266 -(CFDictionaryRef)handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error
267 {
268 return SOSAccountHandleRetirementMessages(self.account, circle_retirement_messages_table, error);
269 }
270
271 -(CFArrayRef) handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error
272 {
273 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
274 CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) {
275 CFErrorRef circleMessageError = NULL;
276 if (!SOSAccountHandleCircleMessage(self.account, key, value, &circleMessageError)) {
277 secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError);
278 }
279 else{
280 CFStringRef circle_id = (CFStringRef) key;
281 CFArrayAppendValue(handledKeys, circle_id);
282 }
283 CFReleaseNull(circleMessageError);
284 });
285
286 return handledKeys;
287 }
288
289 SOSAccount* SOSTransportCircleTestGetAccount(SOSCircleStorageTransportTest* transport) {
290 return transport.account;
291 }
292
293 @end
294
295 ///
296 //MARK KVS Message Test Transport
297 ///
298
299
300
301 @implementation SOSMessageKVSTest
302
303
304 -(id) initWithAccount:(SOSAccount*)acct andName:(CFStringRef)n andCircleName:(CFStringRef) cN
305 {
306 self = [super init];
307 if(self){
308 self.engine = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, cN, NULL);
309 self.account = acct;
310 self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
311 self.name = CFRetainSafe(n);
312 self.circleName = (__bridge NSString*)cN;
313
314 if(!message_transports)
315 message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
316 CFArrayAppendValue(message_transports, (__bridge const void *)((SOSMessageKVSTest*)self));
317 SOSRegisterTransportMessage((SOSMessageKVSTest*)self);
318 }
319
320 return self;
321 }
322
323 -(CFIndex) SOSTransportMessageGetTransportType
324 {
325 return kKVSTest;
326 }
327 -(CFStringRef) SOSTransportMessageGetCircleName
328 {
329 return (__bridge CFStringRef)circleName;
330 }
331 -(CFTypeRef) SOSTransportMessageGetEngine
332 {
333 return engine;
334 }
335 -(SOSAccount*) SOSTransportMessageGetAccount
336 {
337 return self.account;
338 }
339
340 void SOSTransportMessageKVSTestSetName(SOSMessageKVSTest* transport, CFStringRef n)
341 {
342 transport.name = n;
343 }
344
345 CFStringRef SOSTransportMessageKVSTestGetName(SOSMessageKVSTest* transport)
346 {
347 return transport.name;
348 }
349
350 CFMutableDictionaryRef SOSTransportMessageKVSTestGetChanges(SOSMessageKVSTest* transport)
351 {
352 return transport.changes;
353 }
354
355 void SOSTransportMessageTestClearChanges(SOSMessageKVSTest* transport)
356 {
357 transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
358 }
359
360 static void SOSTransportMessageTestAddBulkToChanges(SOSMessageKVSTest* transport, CFDictionaryRef updates)
361 {
362 #ifndef __clang_analyzer__ // The analyzer thinks transport.changes is a leak, but I don't know why.
363 if (transport.changes == NULL) {
364 transport.changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
365 }
366 else{
367 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
368 CFDictionarySetValue(transport.changes, key, value);
369 });
370 }
371 #endif // __clang_analyzer__
372 }
373
374 static void SOSTransportMessageTestAddToChanges(SOSMessageKVSTest* transport, CFStringRef message_key, CFDataRef message_data)
375 {
376 if (transport.changes == NULL) {
377 transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
378 }
379 if (message_data == NULL) {
380 CFDictionarySetValue(transport.changes, message_key, kCFNull);
381 } else {
382 CFDictionarySetValue(transport.changes, message_key, message_data);
383 }
384 }
385
386 -(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessageKVSTest*) transport peers:(CFDictionaryRef)circle_to_peer_ids err:(CFErrorRef*) error
387 {
388 if(!transport.engine)
389 return true;
390 CFArrayRef enginePeers = SOSEngineGetPeerIDs((SOSEngineRef)transport.engine);
391
392 CFDictionaryForEach(circle_to_peer_ids, ^(const void *key, const void *value) {
393 if (isString(key) && isArray(value)) {
394 CFStringRef circle_name = (CFStringRef) key;
395 CFArrayRef peers_to_cleanup_after = (CFArrayRef) value;
396
397 CFArrayForEach(peers_to_cleanup_after, ^(const void *value) {
398 if (isString(value)) {
399 CFStringRef cleanup_id = (CFStringRef) value;
400 // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers
401 if (enginePeers) CFArrayForEach(enginePeers, ^(const void *value) {
402 if (isString(value)) {
403 CFStringRef in_circle_id = (CFStringRef) value;
404
405 CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id);
406 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
407 CFReleaseSafe(kvsKey);
408
409 kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id);
410 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
411 CFReleaseSafe(kvsKey);
412 }
413 });
414
415 }
416 });
417 }
418 });
419
420 return [transport SOSTransportMessageFlushChanges:transport err:error];
421 return true;
422 }
423
424 static bool sendToPeer(SOSMessageKVSTest* transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) {
425 bool result = true;
426 NSString* myID = transport.account.peerID;
427 CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer((SOSMessage*)transport, (__bridge CFStringRef) myID, peerID);
428 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL);
429
430 SOSTransportMessageTestAddBulkToChanges(transport, a_message_to_a_peer);
431 CFReleaseNull(a_message_to_a_peer);
432 CFReleaseNull(message_to_peer_key);
433
434 return result;
435 }
436
437 -(bool) SOSTransportMessageSyncWithPeers:(SOSMessageKVSTest*) transport p:(CFSetRef) peers err:(CFErrorRef *)error
438 {
439 // Each entry is keyed by circle name and contains a list of peerIDs
440
441 __block bool result = true;
442
443 CFSetForEach(peers, ^(const void *value) {
444 CFStringRef peerID = asString(value, NULL);
445
446 if (peerID) {
447 SOSEngineWithPeerID((SOSEngineRef)transport.engine, peerID, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
448 SOSEnginePeerMessageSentBlock sent = NULL;
449 CFDataRef message_to_send = NULL;
450 bool ok = SOSPeerCoderSendMessageIfNeeded([transport SOSTransportMessageGetAccount], (SOSEngineRef)transport.engine, txn, peer, coder, &message_to_send, peerID, false, &sent, error);
451 if (message_to_send) {
452 CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerID, message_to_send, NULL);
453 CFDictionarySetValue(SOSTransportMessageKVSTestGetChanges(transport), (__bridge CFStringRef)self->circleName, peer_dict);
454 SOSPeerCoderConsume(&sent, ok);
455 CFReleaseSafe(peer_dict);
456 }
457 CFReleaseSafe(message_to_send);
458 });
459 }
460 });
461 return result;
462 }
463
464 -(bool) SOSTransportMessageSendMessages:(SOSMessageKVSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error
465 {
466 __block bool result = true;
467
468 CFDictionaryForEach(peer_messages, ^(const void *key, const void *value) {
469 if (isString(key) && isData(value)) {
470 CFStringRef peerID = (CFStringRef) key;
471 CFDataRef message = (CFDataRef) value;
472 bool rx = sendToPeer(transport, (__bridge CFStringRef)transport->circleName, peerID, message, error);
473 result &= rx;
474 }
475 });
476
477 return result;
478 }
479
480 -(CFDictionaryRef)CF_RETURNS_RETAINED SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessageIDSTest*) transport peerMessages:(CFMutableDictionaryRef) circle_peer_messages_table err:(CFErrorRef *)error{
481 CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
482 CFDictionaryRef peerToMessage = CFDictionaryGetValue(circle_peer_messages_table, (__bridge CFStringRef)transport.circleName);
483 CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
484 CFDictionaryAddValue(handled, (__bridge CFStringRef)transport.circleName, handled_peers);
485
486 if(peerToMessage){
487 CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) {
488 CFStringRef peer_id = (CFStringRef) key;
489 CFDataRef peer_message = (CFDataRef) value;
490 CFErrorRef localError = NULL;
491
492 if ([transport SOSTransportMessageHandlePeerMessage:transport id:peer_id cm:peer_message err:&localError]){
493 CFArrayAppendValue(handled_peers, key);
494 } else {
495 secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError);
496 }
497 CFReleaseNull(localError);
498 });
499 }
500 CFReleaseNull(handled_peers);
501
502 return handled;
503 }
504
505 -(bool) SOSTransportMessageFlushChanges:(SOSMessageKVSTest*) transport err:(CFErrorRef *)error
506 {
507 return true;
508 }
509
510 SOSAccount* SOSTransportMessageKVSTestGetAccount(SOSMessageKVSTest* transport) {
511 return transport.account;
512 }
513 @end
514
515 ///
516 //MARK IDS Message Test Transport
517 ///
518
519 @implementation SOSMessageIDSTest
520 -(SOSMessageIDSTest*) initWithAccount:(SOSAccount*)acct andAccountName:(CFStringRef) aN andCircleName:(CFStringRef) cN err:(CFErrorRef *)error
521 {
522 self = [super init];
523 if(self){
524 self.engine = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, cN, NULL);
525 self.useFragmentation = kCFBooleanTrue;
526 self.account = acct;
527 self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
528 self.circleName = (__bridge NSString*)cN;
529 self.accountName = CFRetainSafe(aN);
530
531 if(!message_transports)
532 message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
533 CFArrayAppendValue(message_transports, (__bridge CFTypeRef)self);
534 SOSRegisterTransportMessage((SOSMessageIDSTest*)self);
535 }
536
537 return self;
538 }
539
540 -(bool) SOSTransportMessageIDSGetIDSDeviceID:(SOSAccount*)acct{
541 return true;
542 }
543
544 -(CFIndex) SOSTransportMessageGetTransportType
545 {
546 return kIDSTest;
547 }
548 -(CFStringRef) SOSTransportMessageGetCircleName
549 {
550 return (__bridge CFStringRef)circleName;
551 }
552 -(CFTypeRef) SOSTransportMessageGetEngine
553 {
554 return engine;
555 }
556 -(SOSAccount*) SOSTransportMessageGetAccount
557 {
558 return self.account;
559 }
560
561 void SOSTransportMessageIDSTestSetName(SOSMessageIDSTest* transport, CFStringRef acctName){
562 transport.accountName = acctName;
563 }
564
565
566 static HandleIDSMessageReason checkMessageValidity(SOSAccount* account, CFStringRef fromDeviceID, CFStringRef fromPeerID, CFStringRef *peerID, SOSPeerInfoRef *theirPeerInfo){
567 SOSAccountTrustClassic *trust = account.trust;
568 __block HandleIDSMessageReason reason = kHandleIDSMessageDontHandle;
569
570 SOSCircleForEachPeer(trust.trustedCircle, ^(SOSPeerInfoRef peer) {
571 CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer);
572 CFStringRef pID = SOSPeerInfoGetPeerID(peer);
573
574 if( deviceID && pID && fromPeerID && fromDeviceID && CFStringGetLength(fromPeerID) != 0 ){
575 if(CFStringCompare(pID, fromPeerID, 0) == 0){
576 if(CFStringGetLength(deviceID) == 0){
577 secnotice("ids transport", "device ID was empty in the peer list, holding on to message");
578 CFReleaseNull(deviceID);
579 reason = kHandleIDSMessageNotReady;
580 return;
581 }
582 else if(CFStringCompare(fromDeviceID, deviceID, 0) != 0){ //IDSids do not match, ghost
583 reason = kHandleIDSmessageDeviceIDMismatch;
584 CFReleaseNull(deviceID);
585 return;
586 }
587 else if(CFStringCompare(deviceID, fromDeviceID, 0) == 0){
588 *peerID = pID;
589 *theirPeerInfo = peer;
590 CFReleaseNull(deviceID);
591 reason = kHandleIDSMessageSuccess;
592 return;
593 }
594 }
595 }
596 CFReleaseNull(deviceID);
597 });
598
599 return reason;
600 }
601 const char *kMessageKeyIDSDataMessage = "idsDataMessage";
602 const char *kMessageKeyDeviceID = "deviceID";
603 const char *kMessageKeyPeerID = "peerID";
604 const char *kMessageKeySendersPeerID = "sendersPeerID";
605
606 -(HandleIDSMessageReason) SOSTransportMessageIDSHandleMessage:(SOSAccount*)acct m:(CFDictionaryRef) message err:(CFErrorRef *)error
607 {
608 secnotice("IDS Transport", "SOSTransportMessageIDSHandleMessage!");
609
610 CFStringRef dataKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyIDSDataMessage, kCFStringEncodingASCII);
611 CFStringRef deviceIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyDeviceID, kCFStringEncodingASCII);
612 CFStringRef sendersPeerIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeySendersPeerID, kCFStringEncodingASCII);
613 CFStringRef ourPeerIdKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyPeerID, kCFStringEncodingASCII);
614
615 HandleIDSMessageReason result = kHandleIDSMessageSuccess;
616
617 CFDataRef messageData = asData(CFDictionaryGetValue(message, dataKey), NULL);
618 __block CFStringRef fromDeviceID = asString(CFDictionaryGetValue(message, deviceIDKey), NULL);
619 __block CFStringRef fromPeerID = (CFStringRef)CFDictionaryGetValue(message, sendersPeerIDKey);
620 CFStringRef ourPeerID = asString(CFDictionaryGetValue(message, ourPeerIdKey), NULL);
621
622 CFStringRef peerID = NULL;
623 SOSPeerInfoRef theirPeer = NULL;
624
625 require_action_quiet(fromDeviceID, exit, result = kHandleIDSMessageDontHandle);
626 require_action_quiet(fromPeerID, exit, result = kHandleIDSMessageDontHandle);
627 require_action_quiet(messageData && CFDataGetLength(messageData) != 0, exit, result = kHandleIDSMessageDontHandle);
628 require_action_quiet(SOSAccountHasFullPeerInfo(account, error), exit, result = kHandleIDSMessageNotReady);
629 require_action_quiet(ourPeerID && [account.peerID isEqual: (__bridge NSString*) ourPeerID], exit, result = kHandleIDSMessageDontHandle; secnotice("IDS Transport","ignoring message for: %@", ourPeerID));
630
631 require_quiet((result = checkMessageValidity( account, fromDeviceID, fromPeerID, &peerID, &theirPeer)) == kHandleIDSMessageSuccess, exit);
632
633 if ([account.ids_message_transport SOSTransportMessageHandlePeerMessage:account.ids_message_transport id:peerID cm:messageData err:error]) {
634 CFMutableDictionaryRef peersToSyncWith = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
635 CFMutableSetRef peerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
636 CFSetAddValue(peerIDs, peerID);
637 SOSAccountTrustClassic* trust = account.trust;
638 //sync using fragmentation?
639 if(SOSPeerInfoShouldUseIDSMessageFragmentation(trust.peerInfo, theirPeer)){
640 //set useFragmentation bit
641 [account.ids_message_transport SOSTransportMessageIDSSetFragmentationPreference:account.ids_message_transport pref: kCFBooleanTrue];
642 }
643 else{
644 [account.ids_message_transport SOSTransportMessageIDSSetFragmentationPreference:account.ids_message_transport pref: kCFBooleanFalse];
645 }
646
647 if(![account.ids_message_transport SOSTransportMessageSyncWithPeers:account.ids_message_transport p:peerIDs err:error]){
648 secerror("SOSTransportMessageIDSHandleMessage Could not sync with all peers: %@", *error);
649 }else{
650 secnotice("IDS Transport", "Synced with all peers!");
651 }
652
653 CFReleaseNull(peersToSyncWith);
654 CFReleaseNull(peerIDs);
655 }else{
656 if(error && *error != NULL){
657 CFStringRef errorMessage = CFErrorCopyDescription(*error);
658 if (-25308 == CFErrorGetCode(*error)) { // tell KeychainSyncingOverIDSProxy to call us back when device unlocks
659 result = kHandleIDSMessageLocked;
660 }else{ //else drop it, couldn't handle the message
661 result = kHandleIDSMessageDontHandle;
662 }
663 secerror("IDS Transport Could not handle message: %@, %@", messageData, *error);
664 CFReleaseNull(errorMessage);
665
666 }
667 else{ //no error but failed? drop it, log message
668 secerror("IDS Transport Could not handle message: %@", messageData);
669 result = kHandleIDSMessageDontHandle;
670
671 }
672 }
673
674 exit:
675 CFReleaseNull(ourPeerIdKey);
676 CFReleaseNull(sendersPeerIDKey);
677 CFReleaseNull(deviceIDKey);
678 CFReleaseNull(dataKey);
679 return result;
680 }
681
682 -(CFDictionaryRef)CF_RETURNS_RETAINED SOSTransportMessageHandlePeerMessageReturnsHandledCopy:(SOSMessageIDSTest*) transport peerMessages:(CFMutableDictionaryRef)message err:(CFErrorRef *)error
683 {
684
685 CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
686 CFDictionaryRef peerToMessage = CFDictionaryGetValue(message, (__bridge CFTypeRef)(transport.circleName));
687 CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
688
689 secerror("Received IDS message!");
690 if(peerToMessage){
691 CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) {
692 CFStringRef peer_id = asString(key, NULL);
693 CFDataRef peer_message = asData(value, NULL);
694 CFErrorRef localError = NULL;
695
696 if (peer_id && peer_message && [transport SOSTransportMessageHandlePeerMessage:transport id:peer_id cm:peer_message err:&localError]) {
697 CFArrayAppendValue(handled_peers, key);
698 } else {
699 secnotice("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError);
700 }
701 CFReleaseNull(localError);
702 });
703 }
704 CFDictionaryAddValue(handled, (__bridge CFStringRef)(transport.circleName), handled_peers);
705 CFReleaseNull(handled_peers);
706
707 return handled;
708 }
709
710 static void SOSTransportMessageIDSTestAddBulkToChanges(SOSMessageIDSTest* transport, CFDictionaryRef updates){
711 #ifndef __clang_analyzer__ // The analyzer thinks transport.changes is a leak, but I don't know why.
712 if (transport.changes == NULL) {
713 transport.changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
714
715 }
716 else{
717 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
718 CFDictionaryAddValue(transport.changes, key, value);
719 });
720 }
721 #endif
722 }
723 static bool sendDataToPeerIDSTest(SOSMessageIDSTest* transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDataRef message, CFErrorRef *error)
724 {
725 secerror("sending message through test transport: %@", message);
726 NSString* myID = transport.account.peerID;
727 CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(transport, (__bridge CFStringRef) myID, peerID);
728 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL);
729
730 SOSTransportMessageIDSTestAddBulkToChanges(transport, a_message_to_a_peer);
731
732 CFReleaseNull(message_to_peer_key);
733 CFReleaseNull(a_message_to_a_peer);
734 return true;
735
736 }
737 static bool sendDictionaryToPeerIDSTest(SOSMessageIDSTest* transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDictionaryRef message, CFErrorRef *error)
738 {
739 secerror("sending message through test transport: %@", message);
740 NSString* myID = transport.account.peerID;
741 CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(transport, (__bridge CFStringRef) myID, peerID);
742 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL);
743
744 SOSTransportMessageIDSTestAddBulkToChanges(transport, a_message_to_a_peer);
745
746 CFReleaseNull(message_to_peer_key);
747 CFReleaseNull(a_message_to_a_peer);
748 return true;
749
750 }
751
752 -(bool) SOSTransportMessageSyncWithPeers:(SOSMessageIDSTest*) transport p:(CFSetRef)peers err:(CFErrorRef *)error
753 {
754 // Each entry is keyed by circle name and contains a list of peerIDs
755 __block bool result = true;
756
757 CFSetForEach(peers, ^(const void *value) {
758 CFStringRef peerID = asString(value, NULL);
759 if (peerID) {
760 secnotice("transport", "IDS sync with peerIDs %@", peerID);
761 result &= [transport SOSTransportMessageSendMessageIfNeeded:transport id:(__bridge CFStringRef)transport.circleName pID:peerID err:error];
762 }
763 });
764
765 return result;
766 }
767
768 -(bool) SOSTransportMessageSendMessages:(SOSMessageIDSTest*) transport pm:(CFDictionaryRef) peer_messages err:(CFErrorRef *)error
769 {
770 __block bool result = true;
771 CFDictionaryForEach(peer_messages, ^(const void *key, const void *value) {
772 CFStringRef idsDeviceID = NULL;;
773 CFStringRef peerID = asString(key, NULL);
774 SOSPeerInfoRef pi = NULL;
775 if(peerID){
776 if(!CFEqualSafe(peerID, (__bridge CFStringRef) transport.account.peerID)){
777
778 pi = SOSAccountCopyPeerWithID(transport.account, peerID, NULL);
779 if(pi){
780 idsDeviceID = SOSPeerInfoCopyDeviceID(pi);
781 if(idsDeviceID != NULL){
782
783 CFDictionaryRef messageDictionary = asDictionary(value, NULL);
784 if (messageDictionary) {
785 result &= sendDictionaryToPeerIDSTest(transport, (__bridge CFStringRef)transport.circleName, idsDeviceID, peerID, messageDictionary, error);
786 } else {
787 CFDataRef messageData = asData(value, NULL);
788 if (messageData) {
789 result &= sendDataToPeerIDSTest(transport, (__bridge CFStringRef)transport.circleName, idsDeviceID, peerID, messageData, error);
790 }
791 }
792 }
793 }
794 }
795 }
796 CFReleaseNull(idsDeviceID);
797 CFReleaseNull(pi);
798 });
799
800 return result;
801 }
802
803 -(bool) SOSTransportMessageFlushChanges:(SOSMessageIDSTest*) transport err:(CFErrorRef *)error
804 {
805 return true;
806 }
807
808 -(bool) SOSTransportMessageCleanupAfterPeerMessages:(SOSMessageIDSTest*) transport peers:(CFDictionaryRef) peers err:(CFErrorRef*) error
809 {
810 return true;
811 }
812
813 void SOSTransportMessageIDSTestClearChanges(SOSMessageIDSTest* transport)
814 {
815 transport.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
816 }
817
818 CFMutableDictionaryRef SOSTransportMessageIDSTestGetChanges(SOSMessageIDSTest* transport)
819 {
820 return transport.changes;
821 }
822
823 SOSAccount* SOSTransportMessageIDSTestGetAccount(SOSMessageIDSTest* transport)
824 {
825 return transport.account;
826 }
827
828 CFStringRef SOSTransportMessageIDSTestGetName(SOSMessageIDSTest* transport){
829 return transport.accountName;
830 }
831
832 @end
833
834
835 void SOSAccountUpdateTestTransports(SOSAccount* account, CFDictionaryRef gestalt){
836 CFStringRef new_name = (CFStringRef)CFDictionaryGetValue(gestalt, kPIUserDefinedDeviceNameKey);
837
838 SOSTransportKeyParameterTestSetName((CKKeyParameterTest*)account.key_transport, new_name);
839 SOSTransportCircleTestSetName((SOSCircleStorageTransportTest*)account.circle_transport, new_name);
840 SOSTransportMessageKVSTestSetName((SOSMessageKVSTest*)account.kvs_message_transport, new_name);
841 SOSTransportMessageIDSTestSetName((SOSMessageIDSTest*)account.ids_message_transport, new_name);
842
843 }
844
845 static SOSCircleRef SOSAccountEnsureCircleTest(SOSAccount* a, CFStringRef name, CFStringRef accountName)
846 {
847 CFErrorRef localError = NULL;
848 SOSAccountTrustClassic *trust = a.trust;
849
850 SOSCircleRef circle = [a.trust getCircle:&localError];
851 if(!circle || isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle)){
852 secnotice("circle", "Error retrieving the circle: %@", localError);
853 CFReleaseNull(localError);
854
855 circle = SOSCircleCreate(kCFAllocatorDefault, name, &localError);
856 if (circle){
857 [trust setTrustedCircle:circle];
858 }
859 else{
860 secnotice("circle", "Could not create circle: %@", localError);
861 }
862 CFReleaseNull(localError);
863 }
864
865 if(![trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(a.gestalt) deviceID:(__bridge CFStringRef)(a.deviceID) backupKey:(__bridge CFDataRef)(a.backup_key) err:&localError])
866 {
867 secnotice("circle", "had an error building full peer: %@", localError);
868 CFReleaseNull(localError);
869 return circle;
870 }
871
872 CFReleaseNull(localError);
873 return circle;
874 }
875
876 bool SOSAccountEnsureFactoryCirclesTest(SOSAccount* a, CFStringRef accountName)
877 {
878 bool result = false;
879 if (a)
880 {
881 if(!a.factory)
882 return result;
883 CFStringRef circle_name = SOSDataSourceFactoryCopyName(a.factory);
884 if(!circle_name)
885 return result;
886 SOSAccountEnsureCircleTest(a, (CFStringRef)circle_name, accountName);
887
888 CFReleaseNull(circle_name);
889 result = true;
890 }
891 return result;
892 }
893
894 bool SOSAccountInflateTestTransportsForCircle(SOSAccount* account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error){
895 bool success = false;
896
897 if(account.key_transport == nil){
898 account.key_transport = (CKKeyParameter*)[[CKKeyParameterTest alloc] initWithAccount:account andName:accountName andCircleName:circleName];
899 require_quiet(account.key_transport, fail);
900 }
901
902 if(account.circle_transport == nil){
903 account.circle_transport = (SOSKVSCircleStorageTransport*)[[SOSCircleStorageTransportTest alloc] initWithAccount:account andWithAccountName:accountName andCircleName:circleName];
904 require_quiet(account.circle_transport, fail);
905 }
906 if(account.kvs_message_transport == nil){
907 account.kvs_message_transport = (SOSMessageKVS*)[[SOSMessageKVSTest alloc] initWithAccount:account andName:accountName andCircleName:circleName];
908 }
909 if(account.ids_message_transport == nil){
910 account.ids_message_transport = (SOSMessageIDS*)[[SOSMessageIDSTest alloc] initWithAccount:account andAccountName:accountName andCircleName:circleName err:NULL];
911 }
912
913 success = true;
914 fail:
915 return success;
916 }
917
918