]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.c
Security-57031.10.10.tar.gz
[apple/security.git] / Security / sec / SOSCircle / SecureObjectSync / SOSTransportCircleKVS.c
1 //
2 // SOSTransportCircleKVS.c
3 // sec
4 //
5 #include <SecureObjectSync/SOSTransport.h>
6 #include <SecureObjectSync/SOSTransportCircle.h>
7 #include <SecureObjectSync/SOSTransportCircleKVS.h>
8 #include <SecureObjectSync/SOSKVSKeys.h>
9 #include <utilities/SecCFWrappers.h>
10 #include <SecureObjectSync/SOSInternal.h>
11 #include <SecureObjectSync/SOSAccountPriv.h>
12 #include <SOSCloudKeychainClient.h>
13
14 static bool SOSTransportCircleKVSUpdateRetirementRecords(SOSTransportCircleKVSRef transport, CFDictionaryRef updates, CFErrorRef* error);
15 static bool SOSTransportCircleKVSUpdateKVS(SOSTransportCircleRef transport, CFDictionaryRef changes, CFErrorRef *error);
16 static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error);
17 static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error);
18 static void destroy(SOSTransportCircleRef transport);
19 static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error);
20 static CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error);
21 static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error);
22 static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error);
23
24
25 struct __OpaqueSOSTransportCircleKVS{
26 struct __OpaqueSOSTransportCircle c;
27 CFMutableDictionaryRef pending_changes;
28 CFStringRef circleName;
29 };
30
31
32 SOSTransportCircleKVSRef SOSTransportCircleKVSCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error){
33 SOSTransportCircleKVSRef t = (SOSTransportCircleKVSRef) SOSTransportCircleCreateForSubclass(sizeof(struct __OpaqueSOSTransportCircleKVS) - sizeof(CFRuntimeBase), account, error);
34 if(t){
35 t->circleName = CFRetainSafe(circleName);
36 t->c.expireRetirementRecords = expireRetirementRecords;
37 t->c.postCircle = postCircle;
38 t->c.postRetirement = postRetirement;
39 t->c.flushChanges = flushChanges;
40 t->pending_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
41 t->c.handleRetirementMessages = handleRetirementMessages;
42 t->c.handleCircleMessages = handleCircleMessages;
43 t->c.destroy = destroy;
44 SOSRegisterTransportCircle((SOSTransportCircleRef)t);
45 }
46 return t;
47 }
48
49 static CFStringRef SOSTransportCircleKVSGetCircleName(SOSTransportCircleKVSRef transport){
50 return transport->circleName;
51 }
52
53 static void destroy(SOSTransportCircleRef transport){
54 SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef)transport;
55 CFReleaseNull(tkvs->pending_changes);
56 CFReleaseNull(tkvs->circleName);
57
58 SOSUnregisterTransportCircle((SOSTransportCircleRef)tkvs);
59 }
60
61 bool SOSTransportCircleKVSSendPendingChanges(SOSTransportCircleKVSRef transport, CFErrorRef *error) {
62 CFErrorRef changeError = NULL;
63
64 if (transport->pending_changes == NULL || CFDictionaryGetCount(transport->pending_changes) == 0) {
65 CFReleaseNull(transport->pending_changes);
66 return true;
67 }
68
69 bool success = SOSTransportCircleKVSUpdateKVS((SOSTransportCircleRef)transport, transport->pending_changes, &changeError);
70 if (success) {
71 CFDictionaryRemoveAllValues(transport->pending_changes);
72 } else {
73 SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL,
74 CFSTR("Send changes block failed [%@]"), transport->pending_changes);
75 }
76
77 return success;
78 }
79
80 void SOSTransportCircleKVSAddToPendingChanges(SOSTransportCircleKVSRef transport, CFStringRef message_key, CFDataRef message_data){
81
82 if (transport->pending_changes == NULL) {
83 transport->pending_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
84 }
85 if (message_data == NULL) {
86 CFDictionarySetValue(transport->pending_changes, message_key, kCFNull);
87 } else {
88 CFDictionarySetValue(transport->pending_changes, message_key, message_data);
89 }
90 }
91
92 static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error) {
93
94 bool success = true;
95 CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
96
97 CFDictionaryForEach(retirements, ^(const void *key, const void *value) {
98 if (isString(key) && isArray(value)) {
99 CFStringRef circle_name = (CFStringRef) key;
100 CFArrayRef retirees = (CFArrayRef) value;
101
102 CFArrayForEach(retirees, ^(const void *value) {
103 if (isString(value)) {
104 CFStringRef retiree_id = (CFStringRef) value;
105
106 CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id);
107
108 CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull);
109
110 CFReleaseSafe(kvsKey);
111 }
112 });
113 }
114 });
115
116 if(CFDictionaryGetCount(keysToWrite)) {
117 success = SOSTransportCircleKVSUpdateRetirementRecords((SOSTransportCircleKVSRef)transport, keysToWrite, error);
118 }
119 CFReleaseNull(keysToWrite);
120
121 return success;
122 }
123
124 static bool SOSTransportCircleKVSUpdateRetirementRecords(SOSTransportCircleKVSRef transport, CFDictionaryRef updates, CFErrorRef* error){
125 CFErrorRef updateError = NULL;
126 bool success = false;
127 if (SOSTransportCircleKVSUpdateKVS((SOSTransportCircleRef)transport, updates, &updateError)){
128 success = true;
129 } else {
130 SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL,
131 CFSTR("update parameters key failed [%@]"), updates);
132 }
133 return success;
134 }
135
136 static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error)
137 {
138 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circleName, peer_id);
139 if (retirement_key)
140 SOSTransportCircleKVSAddToPendingChanges((SOSTransportCircleKVSRef)transport, retirement_key, retirement_data);
141
142 CFReleaseNull(retirement_key);
143 return true;
144 }
145
146 static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error)
147 {
148 SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef) transport;
149
150 return SOSTransportCircleKVSSendPendingChanges(tkvs, error);
151 }
152
153 static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error){
154 SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef)transport;
155 CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error);
156 if (circle_key)
157 SOSTransportCircleKVSAddToPendingChanges(tkvs, circle_key, circle_data);
158 CFReleaseNull(circle_key);
159
160 return true;
161 }
162
163 static CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error){
164 SOSAccountRef account = SOSTransportCircleGetAccount(transport);
165 CFMutableDictionaryRef handledRetirementMessages = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
166 CFDictionaryForEach(circle_retirement_messages_table, ^(const void *key, const void *value) {
167 if (isString(key) && isDictionary(value)) {
168 CFStringRef circle_name = (CFStringRef) key;
169
170 CFDictionaryRef retirment_dictionary = (CFDictionaryRef) value;
171 CFDictionaryForEach(retirment_dictionary, ^(const void *key, const void *value) {
172 if(isData(value)) {
173 SOSPeerInfoRef pi = SOSPeerInfoCreateFromData(NULL, error, (CFDataRef) value);
174 if(pi && CFEqual(key, SOSPeerInfoGetPeerID(pi)) && SOSPeerInfoInspectRetirementTicket(pi, error)) {
175 CFMutableDictionaryRef circle_retirements = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(account->retired_peers, circle_name);
176 CFDictionarySetValue(circle_retirements, key, value);
177
178 SOSAccountRecordRetiredPeerInCircleNamed(account, circle_name, pi);
179
180 CFMutableArrayRef handledRetirementIDs = CFDictionaryEnsureCFArrayAndGetCurrentValue(handledRetirementMessages, circle_name);
181 CFArrayAppendValue(handledRetirementIDs, SOSPeerInfoGetPeerID(pi));
182 }
183 CFReleaseSafe(pi);
184 }
185 });
186 }
187 });
188 return handledRetirementMessages;
189 }
190
191 static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error){
192 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
193 CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) {
194 CFErrorRef circleMessageError = NULL;
195 if (!SOSAccountHandleCircleMessage(SOSTransportCircleGetAccount(transport), key, value, &circleMessageError)) {
196 secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError);
197 }
198 else{
199 CFStringRef circle_id = (CFStringRef) key;
200 CFArrayAppendValue(handledKeys, circle_id);
201 }
202 CFReleaseNull(circleMessageError);
203 });
204
205 return handledKeys;
206 }
207
208 bool SOSTransportCircleKVSAppendKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error){
209
210 CFStringRef circle_name = NULL;
211 CFStringRef circle_key = NULL;
212
213 if(SOSAccountHasPublicKey(SOSTransportCircleGetAccount((SOSTransportCircleRef)transport), NULL)){
214 require_quiet(circle_name = SOSTransportCircleKVSGetCircleName(transport), fail);
215 require_quiet(circle_key = SOSCircleKeyCreateWithName(circle_name, error), fail);
216
217 SOSAccountRef account = SOSTransportCircleGetAccount((SOSTransportCircleRef)transport);
218 require_quiet(account, fail);
219 SOSCircleRef circle = SOSAccountFindCircle(account, circle_name, error);
220 require_quiet(circle, fail);
221
222 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
223 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, SOSPeerInfoGetPeerID(peer));
224 CFArrayAppendValue(alwaysKeys, retirement_key);
225 CFReleaseNull(retirement_key);
226 });
227
228 CFArrayAppendValue(alwaysKeys, circle_key);
229
230 CFReleaseNull(circle_key);
231 }
232 return true;
233
234 fail:
235 CFReleaseNull(circle_key);
236 return false;
237 }
238
239 static bool SOSTransportCircleKVSUpdateKVS(SOSTransportCircleRef transport, CFDictionaryRef changes, CFErrorRef *error){
240 CloudKeychainReplyBlock log_error = ^(CFDictionaryRef returnedValues __unused, CFErrorRef error) {
241 if (error) {
242 secerror("Error putting: %@", error);
243 CFReleaseSafe(error);
244 }
245 };
246
247 SOSCloudKeychainPutObjectsInCloud(changes, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), log_error);
248 return true;
249 }