]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c
Security-57337.50.23.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSTransportMessage.c
1 #include <Security/SecureObjectSync/SOSTransport.h>
2 #include <Security/SecureObjectSync/SOSTransportMessage.h>
3 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
4 #include <Security/SecureObjectSync/SOSKVSKeys.h>
5 #include <Security/SecureObjectSync/SOSPeerCoder.h>
6 #include <Security/SecureObjectSync/SOSEngine.h>
7 #include <utilities/SecCFWrappers.h>
8 #include <SOSInternal.h>
9 #include <Security/SecureObjectSync/SOSAccountPriv.h>
10 #include <SOSCloudKeychainClient.h>
11 #include <securityd/SecItemServer.h> // TODO: Remove this layer violation.
12
13 CFGiblisWithHashFor(SOSTransportMessage);
14
15 SOSTransportMessageRef SOSTransportMessageCreateForSubclass(size_t size,
16 SOSAccountRef account, CFStringRef circleName,
17 CFErrorRef *error)
18 {
19 SOSTransportMessageRef tpt = CFTypeAllocateWithSpace(SOSTransportMessage, size, kCFAllocatorDefault);
20
21 SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, circleName, error);
22
23 tpt->engine = CFRetainSafe(engine);
24 tpt->account = CFRetainSafe(account);
25 tpt->circleName = CFRetainSafe(circleName);
26 return tpt;
27 }
28
29
30 static CFStringRef SOSTransportMessageCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions){
31 SOSTransportMessageRef t = (SOSTransportMessageRef) aObj;
32
33 return t->copyDescription ? t->copyDescription(t)
34 : CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSTransportMessage@%p\n>"), t);
35 }
36
37 static void SOSTransportMessageDestroy(CFTypeRef aObj){
38 SOSTransportMessageRef transport = (SOSTransportMessageRef) aObj;
39
40 if (transport->destroy)
41 transport->destroy(transport);
42
43 CFReleaseSafe(transport->account);
44 }
45
46 CFStringRef SOSTransportMessageGetCircleName(SOSTransportMessageRef transport){
47 return transport->circleName;
48 }
49
50 CFIndex SOSTransportMessageGetTransportType(SOSTransportMessageRef transport, CFErrorRef *error){
51 return transport->getTransportType ? transport->getTransportType(transport, error) : kUnknown;
52 }
53
54
55 SOSAccountRef SOSTransportMessageGetAccount(SOSTransportMessageRef transport){
56 return transport->account;
57 }
58
59 static CFHashCode SOSTransportMessageHash(CFTypeRef obj){
60 return (intptr_t) obj;
61 }
62
63 static Boolean SOSTransportMessageCompare(CFTypeRef lhs, CFTypeRef rhs){
64 return SOSTransportMessageHash(lhs) == SOSTransportMessageHash(rhs);
65 }
66
67 bool SOSTransportMessageSendMessages(SOSTransportMessageRef transport, CFDictionaryRef circle_messages, CFErrorRef *error) {
68 return transport->sendMessages(transport, circle_messages, error);
69 }
70
71 bool SOSTransportMessageFlushChanges(SOSTransportMessageRef transport, CFErrorRef *error){
72 return transport->flushChanges(transport, error);
73 }
74
75 bool SOSTransportMessageSyncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error){
76 return transport->syncWithPeers(transport, circleToPeerIDs, error);
77 }
78
79 bool SOSTransportMessageCleanupAfterPeerMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef* error){
80 return transport->cleanupAfterPeerMessages(transport, circleToPeerIDs, error);
81 }
82
83 CF_RETURNS_RETAINED
84 CFDictionaryRef SOSTransportMessageHandleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error){
85 return transport->handleMessages(transport, circle_peer_messages_table, error);
86 }
87
88 SOSEngineRef SOSTransportMessageGetEngine(SOSTransportMessageRef transport) {
89 return transport->engine;
90 }
91
92 bool SOSTransportMessageHandlePeerMessage(SOSTransportMessageRef transport, CFStringRef peerID, CFDataRef codedMessage, CFErrorRef *error) {
93 __block bool result = true;
94 __block bool somethingChanged = false;
95 SOSEngineRef engine = SOSTransportMessageGetEngine(transport);
96 result &= SOSEngineWithPeerID(engine, peerID, error, ^(SOSPeerRef peer, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *shouldSave) {
97 CFDataRef decodedMessage = NULL;
98 enum SOSCoderUnwrapStatus uwstatus = SOSPeerHandleCoderMessage(peer, peerID, codedMessage, &decodedMessage, shouldSave, error);
99 if (uwstatus == SOSCoderUnwrapDecoded) {
100 SOSMessageRef message = NULL;
101 if (decodedMessage && CFDataGetLength(decodedMessage)) {
102 // Only hand non empty messages to the engine, empty messages are an artifact
103 // of coder startup.
104 message = SOSMessageCreateWithData(kCFAllocatorDefault, decodedMessage, error);
105 }
106 if (message) {
107 bool engineHandleMessageDoesNotGetToRollbackTransactions = true;
108 result = SOSEngineHandleMessage_locked(engine, peerID, message, txn, &engineHandleMessageDoesNotGetToRollbackTransactions, &somethingChanged, error);
109 CFReleaseSafe(message);
110 }
111 } else {
112 result = uwstatus != SOSCoderUnwrapError;
113 }
114 CFReleaseNull(decodedMessage);
115 });
116 // TODO: Wish this wasn't here but alas. See the comment for SOSEngineHandleMessage_locked() on why this is needed.
117 if (somethingChanged)
118 SecKeychainChanged(false);
119
120 return result;
121 }
122
123 bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFStringRef peer_id, CFErrorRef *error) {
124 __block bool ok = true;
125 SOSEngineRef engine = SOSTransportMessageGetEngine(transport);
126
127 ok &= SOSEngineForPeerID(engine, peer_id, error, ^(SOSPeerRef peer) {
128 // Now under engine lock do stuff
129 CFDataRef message_to_send = NULL;
130 SOSEnginePeerMessageSentBlock sent = NULL;
131 ok = SOSPeerCoderSendMessageIfNeeded(engine, peer, &message_to_send, circle_id, peer_id, &sent, error);
132 if (message_to_send) {
133 CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
134 peer_id, message_to_send,
135 NULL);
136 CFDictionaryRef circle_peers = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
137 circle_id, peer_dict,
138 NULL);
139 ok = ok && SOSTransportMessageSendMessages(transport, circle_peers, error);
140
141 SOSPeerCoderConsume(&sent, ok);
142
143 CFReleaseSafe(peer_dict);
144 CFReleaseSafe(circle_peers);
145 }
146
147 Block_release(sent);
148 CFReleaseSafe(message_to_send);
149 });
150 return ok;
151 }