1 #include <Security/SecureObjectSync/SOSTransport.h>
2 #include <Security/SecureObjectSync/SOSTransportMessage.h>
3 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
4 #include <Security/SecureObjectSync/SOSKVSKeys.h>
5 #include <Security/SecureObjectSync/SOSPeerCoder.h>
6 #include <Security/SecureObjectSync/SOSEngine.h>
7 #include <utilities/SecCFWrappers.h>
8 #include <SOSInternal.h>
9 #include <Security/SecureObjectSync/SOSAccountPriv.h>
10 #include <SOSCloudKeychainClient.h>
11 #include <securityd/SecItemServer.h> // TODO: Remove this layer violation.
13 CFGiblisWithHashFor(SOSTransportMessage
);
15 SOSTransportMessageRef
SOSTransportMessageCreateForSubclass(size_t size
,
16 SOSAccountRef account
, CFStringRef circleName
,
19 SOSTransportMessageRef tpt
= CFTypeAllocateWithSpace(SOSTransportMessage
, size
, kCFAllocatorDefault
);
21 SOSEngineRef engine
= SOSDataSourceFactoryGetEngineForDataSourceName(account
->factory
, circleName
, error
);
23 tpt
->engine
= CFRetainSafe(engine
);
24 tpt
->account
= CFRetainSafe(account
);
25 tpt
->circleName
= CFRetainSafe(circleName
);
30 static CFStringRef
SOSTransportMessageCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOptions
){
31 SOSTransportMessageRef t
= (SOSTransportMessageRef
) aObj
;
33 return t
->copyDescription
? t
->copyDescription(t
)
34 : CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SOSTransportMessage@%p\n>"), t
);
37 static void SOSTransportMessageDestroy(CFTypeRef aObj
){
38 SOSTransportMessageRef transport
= (SOSTransportMessageRef
) aObj
;
40 if (transport
->destroy
)
41 transport
->destroy(transport
);
43 CFReleaseSafe(transport
->account
);
46 CFStringRef
SOSTransportMessageGetCircleName(SOSTransportMessageRef transport
){
47 return transport
->circleName
;
50 CFIndex
SOSTransportMessageGetTransportType(SOSTransportMessageRef transport
, CFErrorRef
*error
){
51 return transport
->getTransportType
? transport
->getTransportType(transport
, error
) : kUnknown
;
55 SOSAccountRef
SOSTransportMessageGetAccount(SOSTransportMessageRef transport
){
56 return transport
->account
;
59 static CFHashCode
SOSTransportMessageHash(CFTypeRef obj
){
60 return (intptr_t) obj
;
63 static Boolean
SOSTransportMessageCompare(CFTypeRef lhs
, CFTypeRef rhs
){
64 return SOSTransportMessageHash(lhs
) == SOSTransportMessageHash(rhs
);
67 bool SOSTransportMessageSendMessages(SOSTransportMessageRef transport
, CFDictionaryRef circle_messages
, CFErrorRef
*error
) {
68 return transport
->sendMessages(transport
, circle_messages
, error
);
71 bool SOSTransportMessageFlushChanges(SOSTransportMessageRef transport
, CFErrorRef
*error
){
72 return transport
->flushChanges(transport
, error
);
75 bool SOSTransportMessageSyncWithPeers(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
*error
){
76 return transport
->syncWithPeers(transport
, circleToPeerIDs
, error
);
79 bool SOSTransportMessageCleanupAfterPeerMessages(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
* error
){
80 return transport
->cleanupAfterPeerMessages(transport
, circleToPeerIDs
, error
);
84 CFDictionaryRef
SOSTransportMessageHandleMessages(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
){
85 return transport
->handleMessages(transport
, circle_peer_messages_table
, error
);
88 SOSEngineRef
SOSTransportMessageGetEngine(SOSTransportMessageRef transport
) {
89 return transport
->engine
;
92 bool SOSTransportMessageHandlePeerMessage(SOSTransportMessageRef transport
, CFStringRef peerID
, CFDataRef codedMessage
, CFErrorRef
*error
) {
93 __block
bool result
= true;
94 __block
bool somethingChanged
= false;
95 SOSEngineRef engine
= SOSTransportMessageGetEngine(transport
);
96 result
&= SOSEngineWithPeerID(engine
, peerID
, error
, ^(SOSPeerRef peer
, SOSDataSourceRef dataSource
, SOSTransactionRef txn
, bool *shouldSave
) {
97 CFDataRef decodedMessage
= NULL
;
98 enum SOSCoderUnwrapStatus uwstatus
= SOSPeerHandleCoderMessage(peer
, peerID
, codedMessage
, &decodedMessage
, shouldSave
, error
);
99 if (uwstatus
== SOSCoderUnwrapDecoded
) {
100 SOSMessageRef message
= NULL
;
101 if (decodedMessage
&& CFDataGetLength(decodedMessage
)) {
102 // Only hand non empty messages to the engine, empty messages are an artifact
104 message
= SOSMessageCreateWithData(kCFAllocatorDefault
, decodedMessage
, error
);
107 bool engineHandleMessageDoesNotGetToRollbackTransactions
= true;
108 result
= SOSEngineHandleMessage_locked(engine
, peerID
, message
, txn
, &engineHandleMessageDoesNotGetToRollbackTransactions
, &somethingChanged
, error
);
109 CFReleaseSafe(message
);
112 result
= uwstatus
!= SOSCoderUnwrapError
;
114 CFReleaseNull(decodedMessage
);
116 // TODO: Wish this wasn't here but alas. See the comment for SOSEngineHandleMessage_locked() on why this is needed.
117 if (somethingChanged
)
118 SecKeychainChanged(false);
123 bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport
, CFStringRef circle_id
, CFStringRef peer_id
, CFErrorRef
*error
) {
124 __block
bool ok
= true;
125 SOSEngineRef engine
= SOSTransportMessageGetEngine(transport
);
127 ok
&= SOSEngineForPeerID(engine
, peer_id
, error
, ^(SOSPeerRef peer
) {
128 // Now under engine lock do stuff
129 CFDataRef message_to_send
= NULL
;
130 SOSEnginePeerMessageSentBlock sent
= NULL
;
131 ok
= SOSPeerCoderSendMessageIfNeeded(engine
, peer
, &message_to_send
, circle_id
, peer_id
, &sent
, error
);
132 if (message_to_send
) {
133 CFDictionaryRef peer_dict
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
134 peer_id
, message_to_send
,
136 CFDictionaryRef circle_peers
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
137 circle_id
, peer_dict
,
139 ok
= ok
&& SOSTransportMessageSendMessages(transport
, circle_peers
, error
);
141 SOSPeerCoderConsume(&sent
, ok
);
143 CFReleaseSafe(peer_dict
);
144 CFReleaseSafe(circle_peers
);
148 CFReleaseSafe(message_to_send
);