2 #include <SecureObjectSync/SOSInternal.h>
3 #include <SecureObjectSync/SOSKVSKeys.h>
4 #include <SecureObjectSync/SOSAccountPriv.h>
5 #include <SecureObjectSync/SOSTransport.h>
6 #include <SecureObjectSync/SOSTransportKeyParameterKVS.h>
7 #include <SecureObjectSync/SOSTransportCircleKVS.h>
8 #include <SecureObjectSync/SOSTransportMessageKVS.h>
9 #include <SOSCloudKeychainClient.h>
10 #include <utilities/debugging.h>
12 CFStringRef kKeyParameter
= CFSTR("KeyParameter");
13 CFStringRef kCircle
= CFSTR("Circle");
14 CFStringRef kMessage
= CFSTR("Message");
15 CFStringRef kAlwaysKeys
= CFSTR("AlwaysKeys");
16 CFStringRef kFirstUnlocked
= CFSTR("FirstUnlockKeys");
17 CFStringRef kUnlocked
= CFSTR("UnlockedKeys");
21 CFStringRef
SOSInterestListCopyDescription(CFArrayRef interests
)
23 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
24 CFStringAppendFormat(description
, NULL
, CFSTR("<Interest: "));
26 CFArrayForEach(interests
, ^(const void* string
) {
28 CFStringAppendFormat(description
, NULL
, CFSTR(" '%@'"), string
);
30 CFStringAppend(description
, CFSTR(">"));
37 // MARK: Key Interest Processing
40 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportMessages
, sTransportMessages
, ^{
41 *sTransportMessages
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
44 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportKeyParameters
, sTransportKeyParameters
, ^{
45 *sTransportKeyParameters
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
48 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportCircles
, sTransportCircles
, ^{
49 *sTransportCircles
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
53 void SOSRegisterTransportMessage(SOSTransportMessageRef additional
) {
54 CFArrayAppendValue(SOSGetTransportMessages(), additional
);
57 void SOSUnregisterTransportMessage(SOSTransportMessageRef removal
) {
58 CFArrayRemoveAllValue(SOSGetTransportMessages(), removal
);
61 void SOSUnregisterAllTransportMessages() {
62 CFArrayRemoveAllValues(SOSGetTransportMessages());
65 void SOSRegisterTransportCircle(SOSTransportCircleRef additional
) {
66 CFArrayAppendValue(SOSGetTransportCircles(), additional
);
69 void SOSUnregisterTransportCircle(SOSTransportCircleRef removal
) {
70 CFArrayRemoveAllValue(SOSGetTransportCircles(), removal
);
73 void SOSUnregisterAllTransportCircles() {
74 CFArrayRemoveAllValues(SOSGetTransportCircles());
77 void SOSRegisterTransportKeyParameter(SOSTransportKeyParameterRef additional
) {
78 CFArrayAppendValue(SOSGetTransportKeyParameters(), additional
);
81 void SOSUnregisterTransportKeyParameter(SOSTransportKeyParameterRef removal
) {
82 CFArrayRemoveAllValue(SOSGetTransportKeyParameters(), removal
);
85 void SOSUnregisterAllTransportKeyParameters() {
86 CFArrayRemoveAllValues(SOSGetTransportKeyParameters());
90 // Should we be dispatching back to our queue to handle later
92 void SOSUpdateKeyInterest(void)
94 CFMutableArrayRef alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
95 CFMutableArrayRef afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
96 CFMutableArrayRef whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
97 CFMutableDictionaryRef keyDict
= CFDictionaryCreateMutableForCFTypes (kCFAllocatorDefault
);
99 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
100 SOSTransportKeyParameterKVSRef tkvs
= (SOSTransportKeyParameterKVSRef
) value
;
101 CFErrorRef localError
= NULL
;
103 if (!SOSTransportKeyParameterKVSAppendKeyInterests(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)) {
104 secerror("Error getting key parameters interests %@", localError
);
106 CFReleaseNull(localError
);
108 CFMutableDictionaryRef keyParamsDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
109 CFDictionarySetValue(keyParamsDict
, kAlwaysKeys
, alwaysKeys
);
110 CFDictionarySetValue(keyParamsDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
111 CFDictionarySetValue(keyParamsDict
, kUnlocked
, whenUnlockedKeys
);
112 CFDictionarySetValue(keyDict
, kKeyParameter
, keyParamsDict
);
113 CFErrorRef updateError
= NULL
;
114 CFReleaseNull(alwaysKeys
);
115 CFReleaseNull(afterFirstUnlockKeys
);
116 CFReleaseNull(whenUnlockedKeys
);
117 alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
118 afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
119 whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
121 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
122 SOSTransportCircleKVSRef tkvs
= (SOSTransportCircleKVSRef
) value
;
123 CFErrorRef localError
= NULL
;
125 if(!SOSTransportCircleKVSAppendKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
126 secerror("Error getting circle interests %@", localError
);
128 CFReleaseNull(localError
);
131 CFMutableDictionaryRef circleDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
132 CFDictionarySetValue(circleDict
, kAlwaysKeys
, alwaysKeys
);
133 CFDictionarySetValue(circleDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
134 CFDictionarySetValue(circleDict
, kUnlocked
, whenUnlockedKeys
);
135 CFDictionarySetValue(keyDict
, kCircle
, circleDict
);
137 CFReleaseNull(alwaysKeys
);
138 CFReleaseNull(afterFirstUnlockKeys
);
139 CFReleaseNull(whenUnlockedKeys
);
140 alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
141 afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
142 whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
144 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value
) {
145 SOSTransportMessageKVSRef tkvs
= (SOSTransportMessageKVSRef
) value
;
146 CFErrorRef localError
= NULL
;
148 if(!SOSTransportMessageKVSAppendKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
149 secerror("Error getting message interests %@", localError
);
151 CFReleaseNull(localError
);
155 CFMutableDictionaryRef messageDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
156 CFDictionarySetValue(messageDict
, kAlwaysKeys
, alwaysKeys
);
157 CFDictionarySetValue(messageDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
158 CFDictionarySetValue(messageDict
, kUnlocked
, whenUnlockedKeys
);
159 CFDictionarySetValue(keyDict
, kMessage
, messageDict
);
161 CFReleaseNull(alwaysKeys
);
162 CFReleaseNull(afterFirstUnlockKeys
);
163 CFReleaseNull(whenUnlockedKeys
);
164 alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
165 afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
166 whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
169 if (!SOSCloudKeychainUpdateKeys(keyDict
, &updateError
))
171 secerror("Error updating keys: %@", updateError
);
172 // TODO: propagate error(s) to callers.
174 if (CFArrayGetCount(whenUnlockedKeys
) == 0) {
175 secnotice("sync", "Unlocked keys were empty!");
177 // This leaks 3 CFStringRefs in DEBUG builds.
178 CFStringRef alwaysKeysDesc
= SOSInterestListCopyDescription(alwaysKeys
);
179 CFStringRef afterFirstUnlockKeysDesc
= SOSInterestListCopyDescription(afterFirstUnlockKeys
);
180 CFStringRef unlockedKeysDesc
= SOSInterestListCopyDescription(whenUnlockedKeys
);
181 secdebug("sync", "Updating interest: always: %@,\nfirstUnlock: %@,\nunlockedKeys: %@",
183 afterFirstUnlockKeysDesc
,
185 CFReleaseNull(alwaysKeysDesc
);
186 CFReleaseNull(afterFirstUnlockKeysDesc
);
187 CFReleaseNull(unlockedKeysDesc
);
190 CFReleaseNull(updateError
);
191 CFReleaseNull(alwaysKeys
);
192 CFReleaseNull(afterFirstUnlockKeys
);
193 CFReleaseNull(whenUnlockedKeys
);
194 CFReleaseNull(keyParamsDict
);
195 CFReleaseNull(circleDict
);
196 CFReleaseNull(messageDict
);
197 CFReleaseNull(keyDict
);
201 static void showWhatWasHandled(CFDictionaryRef updates
, CFMutableArrayRef handledKeys
) {
203 CFMutableStringRef updateStr
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
204 CFMutableStringRef handledKeysStr
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
206 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
208 CFStringAppendFormat(updateStr
, NULL
, CFSTR("%@ "), (CFStringRef
)key
);
211 CFArrayForEach(handledKeys
, ^(const void *value
) {
212 if (isString(value
)) {
213 CFStringAppendFormat(handledKeysStr
, NULL
, CFSTR("%@ "), (CFStringRef
)value
);
216 secnotice("updates", "Updates [%ld]: %@\n", CFDictionaryGetCount(updates
), updateStr
);
217 secnotice("updates", "Handled [%ld]: %@\n", CFArrayGetCount(handledKeys
), handledKeysStr
);
218 // secnotice("updates", "Updates: %@\n", updates);
219 // secnotice("updates", "Handled: %@\n", handledKeys);
221 CFReleaseSafe(updateStr
);
222 CFReleaseSafe(handledKeysStr
);
226 CFMutableArrayRef
SOSTransportDispatchMessages(SOSAccountRef account
, CFDictionaryRef updates
, CFErrorRef
*error
){
228 CFMutableArrayRef handledKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
230 if(CFDictionaryContainsKey(updates
, kSOSKVSAccountChangedKey
)){
231 // While changing accounts we may modify the key params array. To avoid stepping on ourselves we
232 // copy the list for iteration.
233 CFArrayRef originalKeyParams
= CFArrayCreateCopy(kCFAllocatorDefault
, SOSGetTransportKeyParameters());
234 CFArrayForEach(originalKeyParams
, ^(const void *value
) {
235 SOSTransportKeyParameterRef tkvs
= (SOSTransportKeyParameterRef
) value
;
236 if( (SOSTransportKeyParameterGetAccount((SOSTransportKeyParameterRef
)value
), account
)){
237 SOSTransportKeyParameterHandleNewAccount(tkvs
);
240 CFReleaseNull(originalKeyParams
);
241 CFArrayAppendValue(handledKeys
, kSOSKVSAccountChangedKey
);
244 // Iterate through keys in updates. Perform circle change update.
245 // Then instantiate circles and engines and peers for all peers that
246 // are receiving a message in updates.
247 CFMutableDictionaryRef circle_peer_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
248 CFMutableDictionaryRef circle_circle_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
249 CFMutableDictionaryRef circle_retirement_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
250 __block CFDataRef newParameters
= NULL
;
251 __block
bool initial_sync
= false;
252 __block
bool new_account
= false;
254 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
255 CFErrorRef localError
= NULL
;
256 CFStringRef circle_name
= NULL
;
257 CFStringRef from_name
= NULL
;
258 CFStringRef to_name
= NULL
;
259 switch (SOSKVSKeyGetKeyTypeAndParse(key
, &circle_name
, &from_name
, &to_name
)) {
261 CFDictionarySetValue(circle_circle_messages_table
, circle_name
, value
);
263 case kInitialSyncKey
:
268 newParameters
= (CFDataRef
) CFRetainSafe(value
);
272 CFMutableDictionaryRef circle_messages
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_peer_messages_table
, circle_name
);
273 CFDictionarySetValue(circle_messages
, from_name
, value
);
276 case kRetirementKey
: {
277 CFMutableDictionaryRef circle_retirements
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_retirement_messages_table
, circle_name
);
278 CFDictionarySetValue(circle_retirements
, from_name
, value
);
281 case kAccountChangedKey
:
286 secnotice("updates", "Unknown key '%@', ignoring", key
);
291 CFReleaseNull(circle_name
);
292 CFReleaseNull(from_name
);
293 CFReleaseNull(to_name
);
296 secerror("Peer message processing error for: %@ -> %@ (%@)", key
, value
, *error
);
298 secerror("Peer message local processing error for: %@ -> %@ (%@)", key
, value
, localError
);
300 CFReleaseNull(localError
);
305 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
306 SOSTransportKeyParameterRef tkvs
= (SOSTransportKeyParameterRef
) value
;
307 CFErrorRef localError
= NULL
;
308 if(CFEqualSafe(SOSTransportKeyParameterGetAccount(tkvs
), account
)){
309 if(!SOSTransportKeyParameterHandleKeyParameterChanges(tkvs
, newParameters
, localError
))
310 secerror("Transport failed to handle new key parameters: %@", localError
);
313 CFArrayAppendValue(handledKeys
, kSOSKVSKeyParametersKey
);
315 CFReleaseNull(newParameters
);
318 CFArrayAppendValue(handledKeys
, kSOSKVSInitialSyncKey
);
322 if(CFDictionaryGetCount(circle_retirement_messages_table
)) {
323 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
324 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
325 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
326 CFErrorRef localError
= NULL
;
327 CFDictionaryRef handledRetirementKeys
= SOSTransportCircleHandleRetirementMessages(tkvs
, circle_retirement_messages_table
, error
);
328 if(handledRetirementKeys
== NULL
){
329 secerror("Transport failed to handle retirement messages: %@", localError
);
331 CFDictionaryForEach(handledRetirementKeys
, ^(const void *key
, const void *value
) {
332 CFStringRef circle_name
= (CFStringRef
)key
;
333 CFArrayRef handledPeerIDs
= (CFArrayRef
)value
;
334 CFArrayForEach(handledPeerIDs
, ^(const void *value
) {
335 CFStringRef peer_id
= (CFStringRef
)value
;
336 CFStringRef keyHandled
= SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name
, peer_id
);
337 CFArrayAppendValue(handledKeys
, keyHandled
);
338 CFReleaseNull(keyHandled
);
342 CFReleaseNull(handledRetirementKeys
);
343 CFReleaseNull(localError
);
348 if(CFDictionaryGetCount(circle_circle_messages_table
)) {
349 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
350 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
351 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
352 CFArrayRef handleCircleMessages
= SOSTransportCircleHandleCircleMessages(tkvs
, circle_circle_messages_table
, error
);
353 CFErrorRef localError
= NULL
;
354 if(handleCircleMessages
== NULL
){
355 secerror("Transport failed to handle circle messages: %@", localError
);
356 } else if(CFArrayGetCount(handleCircleMessages
) == 0) {
357 if(CFDictionaryGetCount(circle_circle_messages_table
) != 0) {
358 secerror("Transport failed to process all circle messages: (%ld/%ld) %@",
359 CFArrayGetCount(handleCircleMessages
),
360 CFDictionaryGetCount(circle_circle_messages_table
), localError
);
362 secnotice("circle", "Transport handled no circle messages");
365 CFArrayForEach(handleCircleMessages
, ^(const void *value
) {
366 CFStringRef keyHandled
= SOSCircleKeyCreateWithName((CFStringRef
)value
, error
);
367 CFArrayAppendValue(handledKeys
, keyHandled
);
368 CFReleaseNull(keyHandled
);
371 CFReleaseNull(localError
);
373 if (!SOSTransportCircleFlushChanges(tkvs
, &localError
))
374 secerror("error flushing changes: %@", localError
);
376 CFReleaseNull(localError
);
377 CFReleaseNull(handleCircleMessages
);
382 // TODO: These should all produce circle -> messageTypeHandled messages
383 // That probably needs to wait for separation of transport types.
384 if(CFDictionaryGetCount(circle_peer_messages_table
)) {
385 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value
) {
386 SOSTransportMessageRef tkvs
= (SOSTransportMessageRef
) value
;
387 if(CFEqualSafe(SOSTransportMessageGetAccount((SOSTransportMessageRef
)value
), account
)){
388 CFErrorRef handleMessagesError
= NULL
;
389 CFDictionaryRef handledPeers
= SOSTransportMessageHandleMessages(tkvs
, circle_peer_messages_table
, &handleMessagesError
);
392 // We need to look for and send responses.
394 CFErrorRef syncError
= NULL
;
395 if (!SOSTransportMessageSyncWithPeers((SOSTransportMessageRef
)tkvs
, handledPeers
, &syncError
)) {
396 secerror("Sync with peers failed: %@", syncError
);
399 CFDictionaryForEach(handledPeers
, ^(const void *key
, const void *value
) {
400 if (isString(key
) && isArray(value
)) {
401 CFArrayForEach(value
, ^(const void *value
) {
402 if (isString(value
)) {
403 CFStringRef peerID
= (CFStringRef
) value
;
405 CFStringRef kvsHandledKey
= SOSMessageKeyCreateFromPeerToTransport((SOSTransportMessageKVSRef
)tkvs
, peerID
);
406 CFArrayAppendValue(handledKeys
, kvsHandledKey
);
407 CFReleaseSafe(kvsHandledKey
);
413 CFErrorRef flushError
= NULL
;
414 if (!SOSTransportMessageFlushChanges((SOSTransportMessageRef
)tkvs
, &flushError
)) {
415 secerror("Flush failed: %@", flushError
);
419 secerror("Didn't handle? : %@", handleMessagesError
);
421 CFReleaseNull(handledPeers
);
422 CFReleaseNull(handleMessagesError
);
426 CFReleaseNull(circle_retirement_messages_table
);
427 CFReleaseNull(circle_circle_messages_table
);
428 CFReleaseNull(circle_peer_messages_table
);
432 showWhatWasHandled(updates
, handledKeys
);