]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c
870015ef6aabe1f7202c8e40e84c4dbfaa2ece91
[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 SOSTransportMessageSendMessage(SOSTransportMessageRef transport, CFStringRef peerID, CFDataRef message, CFErrorRef *error) {
68 CFDictionaryRef peerMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerID, message, NULL);
69
70 bool result = SOSTransportMessageSendMessages(transport, peerMessage, error);
71
72 CFReleaseNull(peerMessage);
73 return result;
74 }
75
76 bool SOSTransportMessageSendMessages(SOSTransportMessageRef transport, CFDictionaryRef peer_messages, CFErrorRef *error) {
77 return transport->sendMessages(transport, peer_messages, error);
78 }
79
80 bool SOSTransportMessageFlushChanges(SOSTransportMessageRef transport, CFErrorRef *error){
81 return transport->flushChanges(transport, error);
82 }
83
84 bool SOSTransportMessageSyncWithPeers(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error){
85 return transport->syncWithPeers(transport, peers, error);
86 }
87
88 bool SOSTransportMessageCleanupAfterPeerMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef* error){
89 return transport->cleanupAfterPeerMessages(transport, circleToPeerIDs, error);
90 }
91
92 CF_RETURNS_RETAINED
93 CFDictionaryRef SOSTransportMessageHandleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error){
94 return transport->handleMessages(transport, circle_peer_messages_table, error);
95 }
96
97 SOSEngineRef SOSTransportMessageGetEngine(SOSTransportMessageRef transport) {
98 return transport->engine;
99 }
100
101 static bool SOSEngineHandleCodedMessage(SOSEngineRef engine, CFStringRef peerID, CFDataRef codedMessage, CFErrorRef*error) {
102 __block bool result = true;
103 __block bool somethingChanged = false;
104
105 result &= SOSEngineWithPeerID(engine, peerID, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *shouldSave) {
106 CFDataRef decodedMessage = NULL;
107 enum SOSCoderUnwrapStatus uwstatus = SOSPeerHandleCoderMessage(peer, coder, peerID, codedMessage, &decodedMessage, shouldSave, error);
108 if (uwstatus == SOSCoderUnwrapDecoded) {
109 SOSMessageRef message = NULL;
110 if (decodedMessage && CFDataGetLength(decodedMessage)) {
111 // Only hand non empty messages to the engine, empty messages are an artifact
112 // of coder startup.
113 message = SOSMessageCreateWithData(kCFAllocatorDefault, decodedMessage, error);
114 }
115 if (message) {
116 bool engineHandleMessageDoesNotGetToRollbackTransactions = true;
117 result = SOSEngineHandleMessage_locked(engine, peerID, message, txn, &engineHandleMessageDoesNotGetToRollbackTransactions, &somethingChanged, error);
118 CFReleaseSafe(message);
119 }
120 } else {
121 result = uwstatus != SOSCoderUnwrapError;
122 }
123 CFReleaseNull(decodedMessage);
124 });
125
126 if (somethingChanged) {
127 SecKeychainChanged();
128 }
129
130 if (result) {
131 SOSCCRequestSyncWithPeer(peerID);
132 }
133
134 return result;
135 }
136
137 bool SOSTransportMessageHandlePeerMessage(SOSTransportMessageRef transport, CFStringRef peerID, CFDataRef codedMessage, CFErrorRef *error) {
138 bool result = false;
139 SOSEngineRef engine = SOSTransportMessageGetEngine(transport);
140 require_quiet(SecRequirementError(engine != NULL, error, CFSTR("Missing engine")), done);
141
142 result = SOSEngineHandleCodedMessage(engine, peerID, codedMessage, error);
143
144 done:
145 return result;
146 }
147
148 bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFStringRef peer_id, CFErrorRef *error) {
149 __block bool ok = true;
150 SOSEngineRef engine = SOSTransportMessageGetEngine(transport);
151
152 ok &= SOSEngineWithPeerID(engine, peer_id, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
153 // Now under engine lock do stuff
154 CFDataRef message_to_send = NULL;
155 SOSEnginePeerMessageSentBlock sent = NULL;
156 ok = SOSPeerCoderSendMessageIfNeeded(engine, txn, peer, coder, &message_to_send, peer_id, &sent, error);
157 if (message_to_send) {
158 ok = ok && SOSTransportMessageSendMessage(transport, peer_id, message_to_send, error);
159
160 SOSPeerCoderConsume(&sent, ok);
161 }else{
162 secnotice("transport", "no message to send to peer: %@", peer_id);
163 }
164
165 Block_release(sent);
166 CFReleaseSafe(message_to_send);
167
168 *forceSaveState = ok;
169 });
170
171 return ok;
172 }