]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.m
Security-58286.60.28.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSTransportCircleKVS.m
1 //
2 // SOSTransportCircleKVS.c
3 // sec
4 //
5 #include <Security/SecureObjectSync/SOSTransport.h>
6 #include <Security/SecureObjectSync/SOSTransportCircle.h>
7 #include <Security/SecureObjectSync/SOSTransportCircleKVS.h>
8 #include <Security/SecureObjectSync/SOSKVSKeys.h>
9 #include <Security/SecureObjectSync/SOSInternal.h>
10 #include <SOSCloudKeychainClient.h>
11 #include <utilities/SecCFWrappers.h>
12 #import "Security/SecureObjectSync/SOSAccountTrustClassic.h"
13
14
15 @implementation SOSKVSCircleStorageTransport
16
17 @synthesize pending_changes = pending_changes;
18 @synthesize circleName = circleName;
19 extern CFStringRef kSOSAccountDebugScope;
20
21 -(id)init
22 {
23 return [super init];
24 }
25
26 -(id)initWithAccount:(SOSAccount*)acct andCircleName:(NSString*)name
27 {
28 self = [super init];
29 if(self){
30 self.pending_changes = [NSMutableDictionary dictionary];
31 self.circleName = [[NSString alloc] initWithString:name];
32 self.account = acct;
33 SOSRegisterTransportCircle(self);
34 }
35 return self;
36 }
37
38 -(NSString*) getCircleName
39 {
40 return self.circleName;
41 }
42
43 -(CFIndex) getTransportType{
44 return kKVS;
45 }
46
47 static bool SOSTransportCircleKVSUpdateKVS(NSDictionary *changes, CFErrorRef *error)
48 {
49 CloudKeychainReplyBlock log_error = ^(CFDictionaryRef returnedValues __unused, CFErrorRef block_error) {
50 if (block_error) {
51 secerror("Error putting: %@", block_error);
52 }
53 };
54
55 SOSCloudKeychainPutObjectsInCloud((__bridge CFDictionaryRef)(changes), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), log_error);
56 return true;
57 }
58
59 -(bool)kvsSendPendingChanges:(CFErrorRef *)error
60 {
61 CFErrorRef changeError = NULL;
62
63 if (self.pending_changes == NULL || [self.pending_changes count] == 0) {
64 return true;
65 }
66
67 CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
68 if(dsid == NULL)
69 dsid = kCFNull;
70
71 [self.pending_changes setObject:(__bridge id _Nonnull)((void*)(dsid)) forKey:(__bridge NSString*)kSOSKVSRequiredKey];
72
73 bool success = SOSTransportCircleKVSUpdateKVS(self.pending_changes, &changeError);
74 if (success) {
75 [self.pending_changes removeAllObjects];
76 } else {
77 SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL,
78 CFSTR("Send changes block failed [%@]"), self.pending_changes);
79 }
80
81 return success;
82 }
83
84 -(void)kvsAddToPendingChanges:(CFStringRef) message_key data:(CFDataRef)message_data
85 {
86 if (self.pending_changes == NULL) {
87 self.pending_changes = [NSMutableDictionary dictionary];
88 }
89 if (message_data == NULL) {
90 [self.pending_changes setObject:[NSNull null] forKey:(__bridge NSString*)message_key];
91 } else {
92 [self.pending_changes setObject:(__bridge NSData*)message_data forKey:(__bridge NSString*)message_key];
93 }
94 }
95
96 static bool SOSTransportCircleKVSUpdateRetirementRecords(CFDictionaryRef updates, CFErrorRef* error){
97 CFErrorRef updateError = NULL;
98 bool success = false;
99 if (SOSTransportCircleKVSUpdateKVS((__bridge NSDictionary*)updates, &updateError)){
100 success = true;
101 } else {
102 SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL,
103 CFSTR("update parameters key failed [%@]"), updates);
104 }
105 return success;
106 }
107 -(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error
108 {
109 bool success = true;
110 CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
111
112 CFDictionaryForEach(retirements, ^(const void *key, const void *value) {
113 if (isString(key) && isArray(value)) {
114 CFStringRef circle_name = (CFStringRef) key;
115 CFArrayRef retirees = (CFArrayRef) value;
116
117 CFArrayForEach(retirees, ^(const void *value) {
118 if (isString(value)) {
119 CFStringRef retiree_id = (CFStringRef) value;
120
121 CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id);
122
123 CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull);
124
125 CFReleaseSafe(kvsKey);
126 }
127 });
128 }
129 });
130
131 if(CFDictionaryGetCount(keysToWrite)) {
132 success = SOSTransportCircleKVSUpdateRetirementRecords(keysToWrite, error);
133 }
134 CFReleaseNull(keysToWrite);
135
136 return success;
137 }
138
139 -(bool) flushChanges:(CFErrorRef *)error
140 {
141 return [self kvsSendPendingChanges:error];
142
143 }
144
145 -(bool) postCircle:(CFStringRef)name circleData:(CFDataRef)circle_data err:(CFErrorRef *)error
146 {
147 CFStringRef circle_key = SOSCircleKeyCreateWithName(name, error);
148 if (circle_key)
149 [self kvsAddToPendingChanges:circle_key data:circle_data];
150
151 CFReleaseNull(circle_key);
152
153 return true;
154 }
155
156 -(CFDictionaryRef)CF_RETURNS_RETAINED handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error
157 {
158 return SOSAccountHandleRetirementMessages(self.account, circle_retirement_messages_table, error);
159 }
160
161 -(CFArrayRef)CF_RETURNS_RETAINED handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error
162 {
163 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
164 CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) {
165 CFErrorRef circleMessageError = NULL;
166 if(!isString(key) || !isData(value)) {
167 secerror("Error, Key-Value for CircleMessage was not CFString/CFData");
168 } if (!SOSAccountHandleCircleMessage(self.account, key, value, &circleMessageError)) {
169 secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError);
170 } else{
171 CFStringRef circle_id = (CFStringRef) key;
172 CFArrayAppendValue(handledKeys, circle_id);
173 }
174 CFReleaseNull(circleMessageError);
175 });
176
177 return handledKeys;
178 }
179
180 -(bool)kvsAppendKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef) afterFirstUnlockKeys unlocked:(CFMutableArrayRef)unlockedKeys err:(CFErrorRef *)error
181 {
182 CFStringRef circle_name = NULL;
183 CFStringRef circle_key = NULL;
184
185 if(SOSAccountHasPublicKey(self.account, NULL)){
186 require_quiet(circle_name = (__bridge CFStringRef)self.circleName, fail);
187 require_quiet(circle_key = SOSCircleKeyCreateWithName(circle_name, error), fail);
188
189 require_quiet(account, fail);
190 SOSAccountTrustClassic *trust = account.trust;
191 SOSCircleRef circle = trust.trustedCircle;
192 require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail);
193
194 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
195 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, SOSPeerInfoGetPeerID(peer));
196 CFArrayAppendValue(alwaysKeys, retirement_key);
197 CFReleaseNull(retirement_key);
198 });
199
200 CFArrayAppendValue(alwaysKeys, circle_key);
201
202 CFReleaseNull(circle_key);
203 }
204 return true;
205
206 fail:
207 CFReleaseNull(circle_key);
208 return false;
209 }
210
211 //register ring key
212 -(bool)kvsAppendRingKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error
213 {
214 if(SOSAccountHasPublicKey(self.account, NULL)){
215 require_quiet(account, fail);
216 SOSAccountTrustClassic *trust = account.trust;
217 SOSCircleRef circle = trust.trustedCircle;
218 require_quiet(circle, fail);
219
220 // Always interested in backup rings:
221 SOSAccountForEachRingName(account, ^(CFStringRef ringName) {
222 CFStringRef ring_key = SOSRingKeyCreateWithRingName(ringName);
223 CFArrayAppendValue(unlockedKeys, ring_key);
224 CFReleaseNull(ring_key);
225 });
226 }
227 return true;
228 fail:
229 return false;
230 }
231
232 //register debug scope key
233 -(bool)kvsAppendDebugKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error
234 {
235 CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope);
236 CFArrayAppendValue(alwaysKeys, key);
237 CFReleaseNull(key);
238 return true;
239 }
240
241 //send debug info over KVS
242 -(bool) kvssendDebugInfo:(CFStringRef) type debug:(CFTypeRef) debugInfo err:(CFErrorRef *)error
243 {
244 CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(type);
245 NSDictionary *changes = @{(__bridge NSString*)key:(__bridge id _Nonnull)debugInfo};
246
247 CFReleaseNull(key);
248 bool success = SOSTransportCircleKVSUpdateKVS(changes, error);
249
250 return success;
251 }
252
253 -(bool) kvsSendAccountChangedWithDSID:(CFStringRef) dsid err:(CFErrorRef *)error
254 {
255 NSDictionary *changes = @{(__bridge NSString*)kSOSKVSAccountChangedKey:(__bridge NSString*)dsid};
256
257 bool success = SOSTransportCircleKVSUpdateKVS(changes, error);
258
259
260 return success;
261 }
262
263 //send the Ring over KVS
264 -(bool) kvsRingPostRing:(CFStringRef) ringName ring:(CFDataRef) ring err:(CFErrorRef *)error
265 {
266 CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error);
267
268 if(ringKey)
269 [self kvsAddToPendingChanges:ringKey data:ring];
270
271 CFReleaseNull(ringKey);
272
273 return true;
274 }
275
276 -(bool) kvsRingFlushChanges:(CFErrorRef*) error
277 {
278 return [self kvsSendPendingChanges:error];
279 }
280
281 -(bool) kvsSendOfficialDSID:(CFStringRef) dsid err:(CFErrorRef *)error
282 {
283 NSDictionary *changes = @{(__bridge NSString*)kSOSKVSOfficialDSIDKey : (__bridge NSString*)dsid};
284 bool success = SOSTransportCircleKVSUpdateKVS(changes, error);
285 return success;
286 }
287
288 -(bool) postRetirement:(CFStringRef)circleName peer:(SOSPeerInfoRef)peer err:(CFErrorRef *)error
289 {
290 CFDataRef retirement_data = SOSPeerInfoCopyEncodedData(peer, kCFAllocatorDefault, error);
291
292 require_quiet(retirement_data, fail);
293
294 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer((__bridge CFStringRef)(self.circleName), SOSPeerInfoGetPeerID(peer));
295 if (retirement_key)
296 [self kvsAddToPendingChanges:retirement_key data:retirement_data];
297
298 CFReleaseNull(retirement_key);
299 CFReleaseNull(retirement_data);
300 return true;
301 fail:
302 CFReleaseNull(retirement_data);
303 return true;
304 }
305 @end
306