]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCoder.c
Security-57337.20.44.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSTransportCoder.c
1
2 #include <Security/SecureObjectSync/SOSPeer.h>
3 #include <Security/SecureObjectSync/SOSTransportCoder.h>
4 #include <Security/SecureObjectSync/SOSTransportMessage.h>
5 #include <Security/SecureObjectSync/SOSCoder.h>
6 #include <Security/SecureObjectSync/SOSAccount.h>
7 #include <Security/SecureObjectSync/SOSAccountPriv.h>
8 #include <Security/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 = SOSEngineGetCoderData(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 = SOSEngineSetCoderData(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 = SOSEngineGetCoderData(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 if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(myPeerInfo), peerInfo))
77 coder = SOSCoderCreate(peerInfo, myPeerInfo, kCFBooleanTrue, error);
78 else
79 coder = SOSCoderCreate(peerInfo, myPeerInfo, kCFBooleanFalse, error);
80 if (coder) {
81 haveGoodCoder = SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, error);
82 } else {
83 secerror("Couldn't make coder for %@", peer_id);
84 }
85 }
86
87 if (coder)
88 SOSCoderDispose(coder);
89 return haveGoodCoder;
90 }
91
92 enum SOSCoderUnwrapStatus SOSTransportMessageHandleCoderMessage(SOSTransportMessageRef transport, CFStringRef peer_id, CFDataRef codedMessage, CFDataRef *decodedMessage, CFErrorRef *error){
93
94 enum SOSCoderUnwrapStatus result = SOSCoderUnwrapError;
95 CFMutableDataRef localDecodedMessage = NULL;
96
97 SOSCoderStatus coderStatus = kSOSCoderDataReturned;
98 SOSCoderRef coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
99 if(!coder){
100 SOSAccountEnsurePeerRegistration(SOSTransportMessageGetAccount(transport), error);
101 coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
102 secnotice("transport", "Building new coder!");
103 }
104 CFErrorRef localError = NULL;
105 if (coder) {
106 coderStatus = SOSCoderUnwrap(coder, codedMessage, &localDecodedMessage, peer_id, error);
107
108 switch(coderStatus) {
109 case kSOSCoderDataReturned: {
110 logRawMessage(localDecodedMessage, false, 0);
111 result = SOSCoderUnwrapDecoded;
112 break;
113 }
114 case kSOSCoderNegotiating: // Sent message already in Unwrap.
115 result = SOSCoderUnwrapHandled;
116 secnotice("transport", "%@ transport negotiating", peer_id);
117 break;
118 case kSOSCoderNegotiationCompleted:
119 if (SOSEnginePeerDidConnect(SOSTransportMessageGetEngine(transport), peer_id, error))
120 result = SOSCoderUnwrapHandled;
121 secnotice("transport", "%@ transport negotiation complete", peer_id);
122 break;
123 case kSOSCoderFailure: // Probably restart coder
124 secnotice("transport", "%@ transport failed handling message %@", peer_id, error ? *error : NULL);
125 SOSCoderReset(coder);
126 if (SOSCoderStart(coder, &localError) == kSOSCoderFailure) {
127 secerror("Attempt to recover coder failed to restart: %@", localError);
128 }
129 break;
130 case kSOSCoderStaleEvent: // We received an event we have already processed in the past.
131 result = SOSCoderUnwrapHandled;
132 secinfo("transport", "%@ transport stale event ignored", peer_id);
133 break;
134 case kSOSCoderTooNew: //We received an event from the future!
135 secnotice("transport", "%@ transport received a message too soon, time to restart", peer_id);
136 SOSCoderReset(coder);
137 if(SOSCoderStart(coder, &localError) == kSOSCoderFailure){
138 secerror("Attempt to recover coder failed to restart: %@", localError);
139 }
140
141 default:
142 assert(false);
143 break;
144 }
145 if(decodedMessage)
146 *decodedMessage = CFRetainSafe(localDecodedMessage);
147 CFReleaseNull(localDecodedMessage);
148
149 SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, NULL);
150 SOSCoderDispose(coder);
151 } else {
152 secerror("SOSTransportMessageHandleCoderMessage: Could not make a new coder!");
153 }
154
155 CFReleaseNull(localError);
156
157 return result;
158 }
159
160 // TODO: This should be SOSTransportMessage and be split up into coder/message pieces
161 /* Send a message to peer if needed. Return false if there was an error, true otherwise. */
162 bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFStringRef peer_id, CFErrorRef *error) {
163 SOSCoderRef coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
164
165 if(!coder){
166 SOSAccountEnsurePeerRegistration(SOSTransportMessageGetAccount(transport), error);
167 coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
168 }
169 CFDataRef message_to_send = NULL;
170 bool ok = false;
171 SOSEnginePeerMessageSentBlock sent = NULL;
172
173 require_action_quiet(coder, fail, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("SOSTransportMessageCopyPeerCoder failed"), *error, error));
174
175 if (SOSCoderCanWrap(coder)) {
176 secinfo("transport", "%@ Coder can wrap, getting message from engine", peer_id);
177 CFMutableDataRef codedMessage = NULL;
178 CFDataRef message = SOSEngineCreateMessageToSyncToPeer(SOSTransportMessageGetEngine(transport), peer_id, &sent, error);
179 if (!message) {
180 secnotice("transport", "%@ SOSEngineCreateMessageToSyncToPeer failed: %@",peer_id, *error);
181 }
182 ok = message && (SOSCoderWrap(coder, message, &codedMessage, peer_id, error) == kSOSCoderDataReturned);
183 if (!ok) {
184 secnotice("transport", "%@ SOSCoderWrap failed: %@",peer_id, *error);
185 }
186
187 if (ok)
188 CFRetainAssign(message_to_send, codedMessage);
189
190 CFReleaseNull(codedMessage);
191 CFReleaseNull(message);
192 } else {
193 message_to_send = SOSCoderCopyPendingResponse(coder);
194 secinfo("transport", "%@ negotiating, %@", peer_id, message_to_send ? CFSTR("sending negotiation message.") : CFSTR("waiting for negotiation message."));
195 sent = Block_copy(^(bool wasSent){
196 if (wasSent)
197 SOSCoderConsumeResponse(coder);
198 });
199 ok = true;
200 }
201
202 if (message_to_send) {
203 CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
204 peer_id, message_to_send,
205 NULL);
206 CFDictionaryRef circle_peers = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
207 circle_id, peer_dict,
208 NULL);
209
210 ok = ok && SOSTransportMessageSendMessages(transport, circle_peers, error);
211
212 if (sent)
213 sent(ok);
214
215 CFReleaseSafe(peer_dict);
216 CFReleaseSafe(circle_peers);
217 }
218
219 Block_release(sent);
220
221 CFReleaseSafe(message_to_send);
222
223 SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, NULL);
224
225 fail:
226 if (coder)
227 SOSCoderDispose(coder);
228 return ok;
229 }