]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSTransportMessageIDS.c
Security-57337.50.23.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, CFDictionaryRef 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
65 SOSTransportMessageIDSGetIDSDeviceID(account);
66 SOSRegisterTransportMessage((SOSTransportMessageRef)ids);
67 }
68
69 return ids;
70 }
71 static void destroy(SOSTransportMessageRef transport){
72 SOSUnregisterTransportMessage(transport);
73 }
74
75 static CF_RETURNS_RETAINED CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error) {
76 // TODO: This might need to be: return CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL);
77 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault);
78 }
79
80 HandleIDSMessageReason SOSTransportMessageIDSHandleMessage(SOSAccountRef account, CFDictionaryRef message, CFErrorRef *error) {
81
82 secdebug("IDS Transport", "SOSTransportMessageIDSHandleMessage!");
83
84 CFStringRef dataKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyIDSDataMessage, kCFStringEncodingASCII);
85 CFStringRef deviceIDKey = CFStringCreateWithCString(kCFAllocatorDefault, kMessageKeyDeviceID, kCFStringEncodingASCII);
86
87 CFDataRef messageData = (CFDataRef)CFDictionaryGetValue(message, dataKey);
88 CFStringRef fromID = (CFStringRef)CFDictionaryGetValue(message, deviceIDKey);
89
90 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
91
92 if(!myPeer) {
93 CFReleaseNull(deviceIDKey);
94 CFReleaseNull(dataKey);
95 if(!SOSAccountHasFullPeerInfo(account, error))
96 return kHandleIDSMessageOtherFail;
97 }
98
99 __block CFStringRef peerID = NULL;
100
101 SOSCircleForEachPeer(account->trusted_circle, ^(SOSPeerInfoRef peer) {
102 CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer);
103 if(deviceID && CFStringCompare(deviceID, fromID, 0) == 0)
104 peerID = SOSPeerInfoGetPeerID(peer);
105 CFReleaseNull(deviceID);
106 });
107 if(!peerID){
108 secerror("Could not find peer matching the IDS device ID, dropping message");
109 CFReleaseNull(dataKey);
110 CFReleaseNull(deviceIDKey);
111 return kHandleIDSMessageNotReady;
112 }
113
114 if(messageData != NULL && CFDataGetLength(messageData) > 0){
115
116 if (SOSTransportMessageHandlePeerMessage(account->ids_message_transport, peerID, messageData, error)) {
117 CFMutableDictionaryRef peersToSyncWith = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
118 CFMutableArrayRef peerIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
119 CFArrayAppendValue(peerIDs, peerID);
120 CFDictionaryAddValue(peersToSyncWith, SOSCircleGetName(account->trusted_circle), peerIDs);
121
122 if(!SOSTransportMessageSyncWithPeers(account->ids_message_transport, peersToSyncWith, error))
123 {
124 secerror("SOSTransportMessageIDSHandleMessage Could not sync with all peers: %@", *error);
125 }
126 else{
127 secdebug("IDS Transport", "Synced with all peers!");
128 CFReleaseNull(dataKey);
129 CFReleaseNull(deviceIDKey);
130 return kHandleIDSMessageSuccess;
131 }
132
133 }
134 else{
135 CFReleaseNull(dataKey);
136 CFReleaseNull(deviceIDKey);
137 secerror("IDS Transport Could not handle message: %@", messageData);
138 return kHandleIDSMessageOtherFail;
139 }
140 }
141 secerror("Data doesn't exist: %@", messageData);
142 CFReleaseNull(deviceIDKey);
143 CFReleaseNull(dataKey);
144 return kHandleIDSMessageOtherFail;
145 }
146
147
148 static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID,CFDictionaryRef message, CFErrorRef *error)
149 {
150 __block bool success = false;
151 CFStringRef errorMessage = NULL;
152 CFDictionaryRef userInfo;
153 CFStringRef operation = NULL;
154 CFDataRef operationData = NULL;
155 CFMutableDataRef mutableData = NULL;
156 SOSAccountRef account = SOSTransportMessageGetAccount(transport);
157 CFStringRef ourPeerID = SOSPeerInfoGetPeerID(SOSAccountGetMyPeerInfo(account));
158
159 require_action_quiet((deviceID != NULL && CFStringGetLength(deviceID) >0), fail, errorMessage = CFSTR("Need an IDS Device ID to sync"));
160
161 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
162 dispatch_retain(wait_for); // Both this scope and the block own it.
163
164 secnotice("ids transport", "Starting");
165
166 SOSCloudKeychainSendIDSMessage(message, deviceID, ourPeerID, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
167 success = (sync_error == NULL);
168 if (sync_error && error) {
169 CFRetainAssign(*error, sync_error);
170 }
171
172 dispatch_semaphore_signal(wait_for);
173 dispatch_release(wait_for);
174 });
175
176 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
177 dispatch_release(wait_for);
178
179 if(!success){
180 if(error != NULL)
181 secerror("Failed to send message to peer! %@", *error);
182 else
183 secerror("Failed to send message to peer");
184 }
185 else{
186 secdebug("IDS Transport", "Sent message to peer!");
187 }
188
189 CFReleaseNull(operation);
190 CFReleaseNull(operationData);
191 CFReleaseNull(mutableData);
192
193 return success;
194
195 fail:
196 userInfo = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kCFErrorLocalizedDescriptionKey, errorMessage, NULL);
197 if(error != NULL){
198 *error =CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security.ids.error"), kSecIDSErrorNoDeviceID, userInfo);
199 secerror("%@", *error);
200 }
201 CFReleaseNull(operation);
202 CFReleaseNull(operationData);
203 CFReleaseNull(mutableData);
204 CFReleaseNull(userInfo);
205
206 return success;
207 }
208
209 static bool syncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error) {
210 // Each entry is keyed by circle name and contains a list of peerIDs
211 __block bool result = true;
212
213 CFDictionaryForEach(circleToPeerIDs, ^(const void *key, const void *value) {
214 if (isString(key) && isArray(value)) {
215 CFStringRef circleName = (CFStringRef) key;
216 CFArrayForEach(value, ^(const void *value) {
217 if (isString(value)) {
218 CFStringRef peerID = (CFStringRef) value;
219 result &= SOSTransportMessageSendMessageIfNeeded(transport, circleName, peerID, error);
220 }
221 });
222 }
223 });
224
225 return result;
226 }
227
228 static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error) {
229 __block bool result = true;
230 SOSCircleRef circle = SOSAccountGetCircle(transport->account, error);
231 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(transport->account);
232 __block CFDictionaryRef message = NULL;
233 __block CFStringRef peerID = NULL;
234 require_quiet(myPeer, fail);
235
236
237 CFDictionaryForEach(circleToPeersToMessage, ^(const void *key, const void *value) {
238 if (isString(key) && isDictionary(value)) {
239 CFStringRef circleName = (CFStringRef) key;
240
241 CFDictionaryForEach(value, ^(const void *key1, const void *value1) {
242 if (isString(key1) && isDictionary(value1)) {
243 peerID = (CFStringRef) key1;
244 message = CFRetainSafe((CFDictionaryRef) value1);
245 }
246 else{
247 peerID = (CFStringRef) key1;
248 message = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, key1, value1, NULL);
249 }
250 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
251 if(!CFEqualSafe(myPeer, peer)){
252 CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer);
253 if(CFStringCompare(SOSPeerInfoGetPeerID(peer), peerID, 0) == 0){
254 bool rx = false;
255 rx = sendToPeer(transport, circleName, deviceID, peerID, message, error);
256 result &= rx;
257 }
258 CFReleaseNull(deviceID);
259 }
260 });
261 });
262 }
263 });
264 fail:
265 return result;
266 }
267
268 static bool flushChanges(SOSTransportMessageRef transport, CFErrorRef *error)
269 {
270 return true;
271 }
272
273 static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
274 {
275 return true;
276 }
277
278 void SOSTransportMessageIDSGetIDSDeviceID(SOSAccountRef account){
279
280 CFStringRef deviceID = SOSPeerInfoCopyDeviceID(SOSFullPeerInfoGetPeerInfo(account->my_identity));
281 if( deviceID == NULL || CFStringGetLength(deviceID) == 0){
282 SOSCloudKeychainGetIDSDeviceID(^(CFDictionaryRef returnedValues, CFErrorRef sync_error){
283 bool success = (sync_error == NULL);
284 if (!success) {
285 secerror("Could not ask IDSKeychainSyncingProxy for Device ID: %@", sync_error);
286 }
287 else{
288 secdebug("IDS Transport", "Successfully attempting to retrieve the IDS Device ID");
289 }
290 });
291 }
292 CFReleaseNull(deviceID);
293 }