]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSTransportMessageIDS.c
1 //
2 // SOSTransportMessageIDS.c
3 // sec
4 //
5 //
6 #include <Security/SecBasePriv.h>
7 #include <Security/SecureObjectSync/SOSTransport.h>
8 #include <Security/SecureObjectSync/SOSTransportMessage.h>
9 #include <Security/SecureObjectSync/SOSKVSKeys.h>
10 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
11
12 #include <SOSCloudCircleServer.h>
13 #include <Security/SecureObjectSync/SOSAccountPriv.h>
14 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
15
16 #include <utilities/SecCFWrappers.h>
17 #include <SOSInternal.h>
18 #include <AssertMacros.h>
19
20 #include <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
21 #include <SOSCircle/CKBridge/SOSCloudKeychainConstants.h>
22
23
24 #define IDS "IDS transport"
25
26 struct __OpaqueSOSTransportMessageIDS {
27 struct __OpaqueSOSTransportMessage m;
28
29 };
30
31 const CFStringRef kSecIDSErrorDomain = CFSTR("com.apple.security.ids.error");
32
33
34 //
35 // V-table implementation forward declarations
36 //
37 static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, idsOperation whichOTRType, CFDataRef message, CFErrorRef *error);
38 static bool syncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error);
39 static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error);
40 static void destroy(SOSTransportMessageRef transport);
41 static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error);
42 static bool flushChanges(SOSTransportMessageRef transport, CFErrorRef *error);
43 static CF_RETURNS_RETAINED CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error);
44
45 static inline CFIndex getTransportType(SOSTransportMessageRef transport, CFErrorRef *error){
46 return kIDS;
47 }
48
49 SOSTransportMessageIDSRef SOSTransportMessageIDSCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error)
50 {
51 SOSTransportMessageIDSRef ids = (SOSTransportMessageIDSRef) SOSTransportMessageCreateForSubclass(sizeof(struct __OpaqueSOSTransportMessageIDS) - sizeof(CFRuntimeBase), account, circleName, error);
52
53 if (ids) {
54 // Fill in vtable:
55 ids->m.sendMessages = sendMessages;
56 ids->m.syncWithPeers = syncWithPeers;
57 ids->m.flushChanges = flushChanges;
58 ids->m.cleanupAfterPeerMessages = cleanupAfterPeer;
59 ids->m.destroy = destroy;
60 ids->m.handleMessages = handleMessages;
61 ids->m.getTransportType = getTransportType;
62
63 // Initialize ourselves
64 if ((whichTransportType == kSOSTransportIDS || whichTransportType == kSOSTransportFuture || whichTransportType == kSOSTransportPresent) && account->ids_message_transport) {
65 CFStringRef deviceID = SOSPeerInfoCopyDeviceID(SOSFullPeerInfoGetPeerInfo(account->my_identity));
66 if(deviceID == NULL || CFStringGetLength(deviceID) == 0){
67
68 __block bool success = false;
69
70 SOSCloudKeychainGetIDSDeviceID(^(CFDictionaryRef returnedValues, CFErrorRef sync_error){
71 success = (sync_error == NULL);
72 if (*error) {
73 CFRetainAssign(*error, sync_error);
74 }
75 });
76
77 if(!success){
78 secerror("Could not ask IDSKeychainSyncingProxy for Device ID: %@", *error);
79 }
80 else{
81 secdebug("IDS Transport", "Attempting to retrieve the IDS Device ID");
82 }
83 }
84 CFReleaseNull(deviceID);
85 }
86
87 if (whichTransportType == kSOSTransportIDS) {
88 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
89 if(myPeer){
90 __block bool success = false;
91 CFStringRef deviceIDRefreshed = SOSPeerInfoCopyDeviceID(myPeer);
92 if(!deviceIDRefreshed || 0 == CFStringGetLength(deviceIDRefreshed)){
93 SOSCloudKeychainGetIDSDeviceID(^(CFDictionaryRef returnedValues, CFErrorRef sync_error){
94 success = (sync_error == NULL);
95 if (error) {
96 CFRetainAssign(*error, sync_error);
97 }
98 });
99
100 if(!success){
101 secerror("Could not ask IDSKeychainSyncingProxy for Device ID");
102 }
103 else{
104 secdebug("IDS Transport", "Attempting to retrieve the IDS Device ID");
105 }
106 CFReleaseNull(deviceIDRefreshed);
107 }
108 }
109 }
110
111 SOSRegisterTransportMessage((SOSTransportMessageRef)ids);
112 }
113
114 return ids;
115 }
116 static void destroy(SOSTransportMessageRef transport){
117 SOSUnregisterTransportMessage(transport);
118 }
119
120 static CF_RETURNS_RETAINED CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error) {
121 // TODO: This might need to be: return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL);
122 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault);
123 }
124
125 HandleIDSMessageReason SOSTransportMessageIDSHandleMessage(SOSAccountRef account, CFDictionaryRef message, CFErrorRef *error) {
126
127 secdebug("IDS Transport", "SOSTransportMessageIDSHandleMessage!");
128
129 CFStringRef dataKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyIDSDataMessage, kCFStringEncodingASCII);
130 CFStringRef deviceIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyDeviceID, kCFStringEncodingASCII);
131
132 CFDataRef messageData = (CFDataRef)CFDictionaryGetValue(message, dataKey);
133 CFStringRef fromID = (CFStringRef)CFDictionaryGetValue(message, deviceIDKey);
134
135 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
136
137 if(!myPeer) {
138 CFReleaseNull(deviceIDKey);
139 CFReleaseNull(dataKey);
140 if(!SOSAccountHasFullPeerInfo(account, error))
141 return kHandleIDSMessageOtherFail;
142 }
143
144 __block CFStringRef peerID = NULL;
145
146 SOSCircleForEachPeer(account->trusted_circle, ^(SOSPeerInfoRef peer) {
147 CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer);
148 if(CFStringCompare(deviceID, fromID, 0) == 0)
149 peerID = SOSPeerInfoGetPeerID(peer);
150 CFReleaseNull(deviceID);
151 });
152 if(!peerID){
153 secerror("Could not find peer matching the IDS device ID, dropping message");
154 CFReleaseNull(dataKey);
155 CFReleaseNull(deviceIDKey);
156 return kHandleIDSMessageNotReady;
157 }
158
159 if(messageData){
160
161 if (SOSTransportMessageHandlePeerMessage(account->ids_message_transport, peerID, messageData, error)) {
162 CFMutableDictionaryRef peersToSyncWith = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
163 CFMutableArrayRef peerIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
164 CFArrayAppendValue(peerIDs, peerID);
165 CFDictionaryAddValue(peersToSyncWith, SOSCircleGetName(account->trusted_circle), peerIDs);
166
167 if(!SOSTransportMessageSyncWithPeers(account->ids_message_transport, peersToSyncWith, error))
168 {
169 secerror("SOSTransportMessageIDSHandleMessage Could not sync with all peers: %@", *error);
170 }
171 else{
172 secdebug("IDS Transport", "Synced with all peers!");
173 CFReleaseNull(dataKey);
174 CFReleaseNull(deviceIDKey);
175 return kHandleIDSMessageSuccess;
176 }
177
178 }
179 else{
180 CFReleaseNull(dataKey);
181 CFReleaseNull(deviceIDKey);
182 secerror("IDS Transport Could not handle message: %@", messageData);
183 return kHandleIDSMessageOtherFail;
184 }
185 }
186 secerror("Data doesn't exist: %@", messageData);
187 CFReleaseNull(deviceIDKey);
188 CFReleaseNull(dataKey);
189 return kHandleIDSMessageOtherFail;
190 }
191
192
193 static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, idsOperation whichOTRType, CFDataRef message, CFErrorRef *error)
194 {
195 __block bool success = false;
196 CFStringRef errorMessage = NULL;
197 CFDictionaryRef userInfo;
198 CFStringRef operation = NULL;
199 CFDataRef operationData = NULL;
200 CFMutableDataRef mutableData = NULL;
201 SOSAccountRef account = SOSTransportMessageGetAccount(transport);
202 CFStringRef ourPeerID = SOSPeerInfoGetPeerID(SOSAccountGetMyPeerInfo(account));
203
204 require_action_quiet((deviceID != NULL && CFStringGetLength(deviceID) >0), fail, errorMessage = CFSTR("Need an IDS Device ID to sync"));
205
206 if(whichOTRType == kIDSSyncMessagesCompact)
207 operation = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), kIDSSyncMessagesCompact);
208 else
209 operation = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), kIDSSyncMessagesRaw);
210
211 require_action_quiet(operation, fail, errorMessage = CFSTR("Failed to allocate a CFStringRef"));
212
213 operationData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, operation, kCFStringEncodingUTF8, 0);
214 require_action_quiet(operationData, fail, errorMessage = CFSTR("Failed to allocate data"));
215
216 mutableData = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(operationData) + CFDataGetLength(message));
217 require_action_quiet(mutableData, fail, errorMessage = CFSTR("Failed to allocate mutable data"));
218
219 CFDataAppend(mutableData, operationData);
220 CFDataAppend(mutableData, message);
221
222 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
223 dispatch_retain(wait_for); // Both this scope and the block own it.
224
225 secnotice("ids transport", "Starting");
226
227 SOSCloudKeychainSendIDSMessage(mutableData, deviceID, ourPeerID, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
228 success = (sync_error == NULL);
229 if (error) {
230 CFRetainAssign(*error, sync_error);
231 }
232
233 dispatch_semaphore_signal(wait_for);
234 dispatch_release(wait_for);
235 });
236
237 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
238 dispatch_release(wait_for);
239
240 if(!success){
241 if(error != NULL)
242 secerror("Failed to send message to peer! %@", *error);
243 else
244 secerror("Failed to send message to peer");
245 }
246 else{
247 secdebug("IDS Transport", "Sent message to peer!");
248 }
249
250 CFReleaseNull(operation);
251 CFReleaseNull(operationData);
252 CFReleaseNull(mutableData);
253
254 return success;
255
256 fail:
257 userInfo = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kCFErrorLocalizedDescriptionKey, errorMessage, NULL);
258 if(error != NULL){
259 *error =CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security.ids.error"), kSecIDSErrorNoDeviceID, userInfo);
260 secerror("%@", *error);
261 }
262 CFReleaseNull(operation);
263 CFReleaseNull(operationData);
264 CFReleaseNull(mutableData);
265 CFReleaseNull(userInfo);
266
267 return success;
268 }
269
270 static bool syncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error) {
271 // Each entry is keyed by circle name and contains a list of peerIDs
272 __block bool result = true;
273
274 CFDictionaryForEach(circleToPeerIDs, ^(const void *key, const void *value) {
275 if (isString(key) && isArray(value)) {
276 CFStringRef circleName = (CFStringRef) key;
277 CFArrayForEach(value, ^(const void *value) {
278 if (isString(value)) {
279 CFStringRef peerID = (CFStringRef) value;
280 result &= SOSTransportMessageSendMessageIfNeeded(transport, circleName, peerID, error);
281 }
282 });
283 }
284 });
285
286 return result;
287 }
288
289 static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error) {
290 __block bool result = true;
291 SOSCircleRef circle = SOSAccountGetCircle(transport->account, error);
292 __block SOSAccountRef account = SOSTransportMessageGetAccount(transport);
293 __block SOSPeerInfoRef myPeerInfo = SOSFullPeerInfoGetPeerInfo(SOSAccountGetMyFullPeerInfo(account));
294
295 CFDictionaryForEach(circleToPeersToMessage, ^(const void *key, const void *value) {
296 if (isString(key) && isDictionary(value)) {
297 CFStringRef circleName = (CFStringRef) key;
298 CFDictionaryForEach(value, ^(const void *key, const void *value) {
299 if (isString(key) && isData(value)) {
300 CFStringRef peerID = (CFStringRef) key;
301 CFDataRef message = (CFDataRef) value;
302 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
303 CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer);
304 if(CFEqualSafe(SOSPeerInfoGetPeerID(peer), peerID) || CFEqualSafe(deviceID, peerID)){
305 bool rx = false;
306 if(SOSPeerInfoShouldUseIDSTransport(myPeerInfo, peer))
307 rx = sendToPeer(transport, circleName, deviceID, peerID, kIDSSyncMessagesCompact, message, error);
308 else
309 rx = sendToPeer(transport, circleName, deviceID, peerID, kIDSSyncMessagesRaw, message, error);
310
311 result &= rx;
312 }
313 CFReleaseNull(deviceID);
314 });
315 }
316 });
317 }
318 });
319
320 return result;
321 }
322
323 static bool flushChanges(SOSTransportMessageRef transport, CFErrorRef *error)
324 {
325 return true;
326 }
327
328 static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
329 {
330 return true;
331 }