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