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