]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSTransportCoder.c
Security-57031.10.10.tar.gz
[apple/security.git] / Security / sec / SOSCircle / SecureObjectSync / SOSTransportCoder.c
1
2 #include <SecureObjectSync/SOSPeer.h>
3 #include <SecureObjectSync/SOSTransportCoder.h>
4 #include <SecureObjectSync/SOSTransportMessage.h>
5 #include <SecureObjectSync/SOSCoder.h>
6 #include <SecureObjectSync/SOSAccount.h>
7 #include <SecureObjectSync/SOSAccountPriv.h>
8 #include <SecureObjectSync/SOSEngine.h>
9
10 #include <utilities/debugging.h>
11 #include <utilities/SecCFWrappers.h>
12
13 #include <AssertMacros.h>
14 #include <SOSInternal.h>
15
16
17 // For now transport (the abstract class) consumes the Transport data in engine to hold
18 // coder state.
19 static SOSCoderRef SOSTransportMessageCopyPeerCoder(SOSTransportMessageRef transport, CFStringRef peer_id){
20 SOSCoderRef coder = NULL;
21
22 CFDataRef coderData = SOSEngineGetTransportData(SOSTransportMessageGetEngine(transport), peer_id);
23
24 if (coderData) {
25 CFErrorRef localError = NULL;
26 coder = SOSCoderCreateFromData(coderData, &localError);
27
28 if (!coder) {
29 secerror("Failed to make coder from valid data for peer %@ (%@). THIS IS FATAL, WE CAN'T COMMUNICATE.", peer_id, localError);
30 }
31
32 CFReleaseNull(localError);
33 }
34 else
35 secerror("Failed to get coderData from engine for peer %@. THIS IS FATAL, WE CAN'T COMMUNICATE.", peer_id);
36
37 return coder;
38 }
39
40 bool SOSTransportMessageSavePeerCoderData(SOSTransportMessageRef transport, SOSCoderRef coder, CFStringRef peer_id, CFErrorRef *error) {
41 CFDataRef coderData = NULL;
42 bool ok = true;
43
44 if (coder) {
45 coderData = SOSCoderCopyDER(coder, error);
46 if (coderData == NULL) {
47 secerror("%@ coder data failed to export %@, zapping data", transport, error ? *error : 0);
48 }
49 }
50 require_action_quiet(coderData, exit, ok = SOSErrorCreate(kSOSErrorAllocationFailure, error, NULL, CFSTR("Creation of coder data failed")));
51
52 ok = SOSEngineSetTransportData(SOSTransportMessageGetEngine(transport), peer_id, coderData, error);
53
54 exit:
55 CFReleaseNull(coderData);
56 return ok;
57 }
58
59 bool SOSTransportCoderInitializeForPeer(SOSTransportMessageRef transport, SOSFullPeerInfoRef myPeerInfo, SOSPeerInfoRef peerInfo, CFErrorRef *error){
60 SOSCoderRef coder = NULL;
61 CFStringRef peer_id = SOSPeerInfoGetPeerID(peerInfo);
62 CFDataRef coderData = SOSEngineGetTransportData(SOSTransportMessageGetEngine(transport), peer_id);
63 if(coderData != NULL) {
64 CFErrorRef coderError = NULL;
65 coder = SOSCoderCreateFromData(coderData, &coderError);
66
67 if (!coder) {
68 secerror("Found data but couldn't make coder for %@: %@", peer_id, coderError);
69 }
70 CFReleaseNull(coderError);
71 }
72
73 bool haveGoodCoder = coder;
74 if (!haveGoodCoder) {
75 secnotice("transport", "New coder for id %@.", peer_id);
76 coder = SOSCoderCreate(peerInfo, myPeerInfo, error);
77
78 if (coder) {
79 haveGoodCoder = SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, error);
80 } else {
81 secerror("Couldn't make coder for %@", peer_id);
82 }
83 }
84
85 if (coder)
86 SOSCoderDispose(coder);
87 return haveGoodCoder;
88 }
89
90 enum SOSCoderUnwrapStatus SOSTransportMessageHandleCoderMessage(SOSTransportMessageRef transport, CFStringRef peer_id, CFDataRef codedMessage, CFDataRef *decodedMessage, CFErrorRef *error){
91
92 enum SOSCoderUnwrapStatus result = SOSCoderUnwrapError;
93 CFMutableDataRef localDecodedMessage = NULL;
94
95 SOSCoderStatus coderStatus = kSOSCoderDataReturned;
96 SOSCoderRef coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
97 if(!coder){
98 SOSAccountEnsurePeerRegistration(SOSTransportMessageGetAccount(transport), error);
99 coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
100 secnotice("transport", "Building new coder!");
101 }
102 CFErrorRef localError = NULL;
103 if (coder) {
104 coderStatus = SOSCoderUnwrap(coder, codedMessage, &localDecodedMessage, peer_id, error);
105
106 switch(coderStatus) {
107 case kSOSCoderDataReturned: {
108 logRawMessage(localDecodedMessage, false, 0);
109 result = SOSCoderUnwrapDecoded;
110 break;
111 }
112 case kSOSCoderNegotiating: // Sent message already in Unwrap.
113 result = SOSCoderUnwrapHandled;
114 secnotice("transport", "%@ transport negotiating", peer_id);
115 break;
116 case kSOSCoderNegotiationCompleted:
117 if(SOSEnginePeerDidConnect(SOSTransportMessageGetEngine(transport), peer_id, error))
118 result = SOSCoderUnwrapHandled;
119 secnotice("transport", "%@ transport negotiation complete", peer_id);
120 break;
121 case kSOSCoderFailure: // Probably restart coder
122 secnotice("transport", "%@ transport failed handling message %@", peer_id, error ? *error : NULL);
123 SOSCoderReset(coder);
124 if(SOSCoderStart(coder, &localError) == kSOSCoderFailure){
125 secerror("Attempt to recover coder failed to restart: %@", localError);
126 }
127 break;
128 case kSOSCoderStaleEvent: // We received an event we have already processed in the past.
129 secnotice("transport", "%@ transport stale event ignored", peer_id);
130 break;
131 default:
132 assert(false);
133 break;
134 }
135 if(decodedMessage)
136 *decodedMessage = CFRetainSafe(localDecodedMessage);
137 CFReleaseNull(localDecodedMessage);
138
139 SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, NULL);
140 SOSCoderDispose(coder);
141 }
142 else{
143 secerror("SOSTransportMessageHandleCoderMessage: Could not make a new coder!");
144 }
145
146 CFReleaseNull(localError);
147
148 return result;
149
150 }
151
152 #warning this should be SOSTransportMessage and be split up into coder/message pieces
153 /* Send a message to peer if needed. Return false if there was an error, true otherwise. */
154 bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFStringRef peer_id, CFErrorRef *error) {
155 SOSCoderRef coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
156
157 if(!coder){
158 SOSAccountEnsurePeerRegistration(SOSTransportMessageGetAccount(transport), error);
159 coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
160 }
161 CFDataRef message_to_send = NULL;
162 bool ok = false;
163 SOSEnginePeerMessageSentBlock sent = NULL;
164
165 require_action_quiet(coder, fail, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("SOSTransportMessageCopyPeerCoder failed"), *error, error));
166
167 if (SOSCoderCanWrap(coder)) {
168 secnotice("transport", "%@ Coder can wrap, getting message from engine", peer_id);
169 CFMutableDataRef codedMessage = NULL;
170 CFDataRef message = SOSEngineCreateMessageToSyncToPeer(SOSTransportMessageGetEngine(transport), peer_id, &sent, error);
171 if (!message) {
172 secnotice("transport", "%@ SOSEngineCreateMessageToSyncToPeer failed: %@",peer_id, *error);
173 }
174 ok = message && (SOSCoderWrap(coder, message, &codedMessage, peer_id, error) == kSOSCoderDataReturned);
175 if (!ok) {
176 secnotice("transport", "%@ SOSCoderWrap failed: %@",peer_id, *error);
177 }
178
179 if (ok)
180 CFRetainAssign(message_to_send, codedMessage);
181
182 CFReleaseNull(codedMessage);
183 CFReleaseNull(message);
184 } else {
185 message_to_send = SOSCoderCopyPendingResponse(coder);
186 secnotice("transport", "%@ Negotiating, %@", peer_id, message_to_send ? CFSTR("Sending negotiation message.") : CFSTR("waiting for negotiation message."));
187 sent = Block_copy(^(bool wasSent){
188 if (wasSent)
189 SOSCoderConsumeResponse(coder);
190 });
191 ok = true;
192 }
193
194 if (message_to_send) {
195 CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
196 peer_id, message_to_send,
197 NULL);
198 CFDictionaryRef circle_peers = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
199 circle_id, peer_dict,
200 NULL);
201
202 ok = ok && SOSTransportMessageSendMessages(transport, circle_peers, error);
203
204 if (sent)
205 sent(ok);
206
207 CFReleaseSafe(peer_dict);
208 CFReleaseSafe(circle_peers);
209 }
210
211 Block_release(sent);
212
213 CFReleaseSafe(message_to_send);
214
215 SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, NULL);
216
217 fail:
218 if (coder)
219 SOSCoderDispose(coder);
220 return ok;
221 }