]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
5c19dc3a | 24 | #include <Security/SecureObjectSync/SOSKVSKeys.h> |
d8f41ccd | 25 | #include <utilities/SecCFWrappers.h> |
5c19dc3a A |
26 | #include <Security/SecureObjectSync/SOSAccountPriv.h> |
27 | #include <CoreFoundation/CFDate.h> | |
d8f41ccd A |
28 | |
29 | void AppendCircleKeyName(CFMutableArrayRef array, CFStringRef name) { | |
30 | CFStringRef circle_key = SOSCircleKeyCreateWithName(name, NULL); | |
31 | CFArrayAppendValue(array, circle_key); | |
32 | CFReleaseNull(circle_key); | |
33 | } | |
34 | ||
35 | // | |
36 | // | |
37 | // MARK: KVS Keys | |
38 | // TODO: Handle '|' and "¬" in other strings. | |
39 | // | |
40 | const CFStringRef kSOSKVSKeyParametersKey = CFSTR(">KeyParameters"); | |
41 | const CFStringRef kSOSKVSInitialSyncKey = CFSTR("^InitialSync"); | |
42 | const CFStringRef kSOSKVSAccountChangedKey = CFSTR("^AccountChanged"); | |
5c19dc3a A |
43 | const CFStringRef kSOSKVSRequiredKey = CFSTR("^Required"); |
44 | const CFStringRef kSOSKVSOfficialDSIDKey = CFSTR("^OfficialDSID"); | |
45 | ||
46 | const CFStringRef kSOSKVSDebugScope = CFSTR("^DebugScope"); | |
47 | ||
48 | const CFStringRef sPeerInfoPrefix = CFSTR("+"); | |
49 | const CFStringRef sRingPrefix = CFSTR("~"); | |
50 | const CFStringRef sDebugInfoPrefix = CFSTR("dbg-"); | |
d8f41ccd A |
51 | |
52 | const CFStringRef sWarningPrefix = CFSTR("!"); | |
53 | const CFStringRef sAncientCirclePrefix = CFSTR("@"); | |
54 | const CFStringRef sCirclePrefix = CFSTR("o"); | |
55 | const CFStringRef sRetirementPrefix = CFSTR("-"); | |
5c19dc3a A |
56 | const CFStringRef sLastCirclePushedPrefix = CFSTR("p"); |
57 | const CFStringRef sLastKeyParametersPushedPrefix = CFSTR("k"); | |
d8f41ccd A |
58 | const CFStringRef sCircleSeparator = CFSTR("|"); |
59 | const CFStringRef sFromToSeparator = CFSTR(":"); | |
60 | ||
61 | static CFStringRef copyStringEndingIn(CFMutableStringRef in, CFStringRef token) { | |
62 | if(token == NULL) return CFStringCreateCopy(NULL, in); | |
63 | CFRange tokenAt = CFStringFind(in, token, 0); | |
64 | if(tokenAt.location == kCFNotFound) return NULL; | |
65 | CFStringRef retval = CFStringCreateWithSubstring(NULL, in, CFRangeMake(0, tokenAt.location)); | |
66 | CFStringDelete(in, CFRangeMake(0, tokenAt.location+1)); | |
67 | return retval; | |
68 | } | |
69 | ||
fa7225c8 | 70 | SOSKVSKeyType SOSKVSKeyGetKeyType(CFStringRef key) { |
d8f41ccd A |
71 | SOSKVSKeyType retval = kUnknownKey; |
72 | ||
73 | if(CFStringHasPrefix(key, sCirclePrefix)) retval = kCircleKey; | |
5c19dc3a A |
74 | else if (CFStringHasPrefix(key, sRingPrefix)) retval = kRingKey; |
75 | else if(CFStringHasPrefix(key, sPeerInfoPrefix)) retval = kPeerInfoKey; | |
d8f41ccd A |
76 | else if(CFStringHasPrefix(key, sRetirementPrefix)) retval = kRetirementKey; |
77 | else if(CFStringHasPrefix(key, kSOSKVSKeyParametersKey)) retval = kParametersKey; | |
78 | else if(CFStringHasPrefix(key, kSOSKVSInitialSyncKey)) retval = kInitialSyncKey; | |
79 | else if(CFStringHasPrefix(key, kSOSKVSAccountChangedKey)) retval = kAccountChangedKey; | |
5c19dc3a A |
80 | else if(CFStringHasPrefix(key, sDebugInfoPrefix)) retval = kDebugInfoKey; |
81 | else if(CFStringHasPrefix(key, sLastCirclePushedPrefix)) retval = kLastCircleKey; | |
82 | else if(CFStringHasPrefix(key, sLastKeyParametersPushedPrefix)) retval = kLastKeyParameterKey; | |
d8f41ccd | 83 | else retval = kMessageKey; |
fa7225c8 A |
84 | |
85 | return retval; | |
86 | } | |
87 | ||
88 | bool SOSKVSKeyParse(SOSKVSKeyType keyType, CFStringRef key, CFStringRef *circle, CFStringRef *peerInfo, CFStringRef *ring, CFStringRef *backupName, CFStringRef *from, CFStringRef *to) { | |
89 | bool retval = true; | |
d8f41ccd | 90 | |
fa7225c8 | 91 | switch(keyType) { |
d8f41ccd A |
92 | case kCircleKey: |
93 | if (circle) { | |
94 | CFRange fromRange = CFRangeMake(1, CFStringGetLength(key)-1); | |
95 | *circle = CFStringCreateWithSubstring(NULL, key, fromRange); | |
96 | } | |
97 | break; | |
98 | case kMessageKey: { | |
99 | CFStringRef mCircle = NULL; | |
100 | CFStringRef mFrom = NULL; | |
101 | CFStringRef mTo = NULL; | |
102 | CFMutableStringRef keycopy = CFStringCreateMutableCopy(NULL, 128, key); | |
103 | ||
104 | if( ((mCircle = copyStringEndingIn(keycopy, sCircleSeparator)) != NULL) && | |
105 | ((mFrom = copyStringEndingIn(keycopy, sFromToSeparator)) != NULL) && | |
106 | (CFStringGetLength(mFrom) > 0) ) { | |
107 | mTo = copyStringEndingIn(keycopy, NULL); | |
108 | if (circle && mCircle) *circle = CFStringCreateCopy(NULL, mCircle); | |
109 | if (from && mFrom) *from = CFStringCreateCopy(NULL, mFrom); | |
110 | if (to && mTo) *to = CFStringCreateCopy(NULL, mTo); | |
111 | } else { | |
fa7225c8 | 112 | retval = false; |
d8f41ccd A |
113 | } |
114 | CFReleaseNull(mCircle); | |
115 | CFReleaseNull(mFrom); | |
116 | CFReleaseNull(mTo); | |
117 | CFReleaseNull(keycopy); | |
118 | } | |
119 | break; | |
120 | case kRetirementKey: { | |
121 | CFStringRef mCircle = NULL; | |
122 | CFStringRef mPeer = NULL; | |
123 | CFMutableStringRef keycopy = CFStringCreateMutableCopy(NULL, 128, key); | |
124 | CFStringDelete(keycopy, CFRangeMake(0, 1)); | |
125 | if( ((mCircle = copyStringEndingIn(keycopy, sCircleSeparator)) != NULL) && | |
126 | ((mPeer = copyStringEndingIn(keycopy, NULL)) != NULL)) { | |
127 | if (circle) *circle = CFStringCreateCopy(NULL, mCircle); | |
128 | if (from) *from = CFStringCreateCopy(NULL, mPeer); | |
129 | } else { | |
fa7225c8 | 130 | retval = false; |
d8f41ccd | 131 | } |
d8f41ccd A |
132 | CFReleaseNull(mCircle); |
133 | CFReleaseNull(mPeer); | |
134 | CFReleaseNull(keycopy); | |
135 | } | |
136 | break; | |
5c19dc3a A |
137 | case kRingKey: |
138 | if (ring) { | |
139 | CFRange fromRange = CFRangeMake(1, CFStringGetLength(key)-1); | |
140 | *ring = CFStringCreateWithSubstring(NULL, key, fromRange); | |
141 | } | |
142 | break; | |
143 | case kPeerInfoKey: | |
144 | if (peerInfo) { | |
145 | CFRange fromRange = CFRangeMake(1, CFStringGetLength(key)-1); | |
146 | *peerInfo = CFStringCreateWithSubstring(NULL, key, fromRange); | |
147 | } | |
148 | break; | |
149 | case kDebugInfoKey: | |
150 | /* piggybacking on peerinfo */ | |
151 | if (peerInfo) { | |
152 | CFRange dbgRange = CFRangeMake(CFStringGetLength(sDebugInfoPrefix), | |
153 | CFStringGetLength(key)-CFStringGetLength(sDebugInfoPrefix)); | |
154 | *peerInfo = CFStringCreateWithSubstring(NULL, key, dbgRange); | |
155 | } | |
156 | break; | |
d8f41ccd A |
157 | case kAccountChangedKey: |
158 | case kParametersKey: | |
159 | case kInitialSyncKey: | |
160 | case kUnknownKey: | |
fa7225c8 | 161 | break; |
5c19dc3a | 162 | case kLastKeyParameterKey: |
fa7225c8 A |
163 | if(from) { |
164 | CFStringRef mPrefix = NULL; | |
165 | CFStringRef mFrom = NULL; | |
166 | CFMutableStringRef keycopy = CFStringCreateMutableCopy(NULL, 128, key); | |
167 | ||
168 | if( ((mPrefix = copyStringEndingIn(keycopy, sCircleSeparator)) != NULL) && | |
169 | ((mFrom = copyStringEndingIn(keycopy, NULL)) != NULL)) { | |
170 | if (from && mFrom) *from = CFStringCreateCopy(NULL, mFrom); | |
171 | } else { | |
172 | retval = false; | |
173 | } | |
174 | CFReleaseNull(mPrefix); | |
175 | CFReleaseNull(mFrom); | |
176 | CFReleaseNull(keycopy); | |
177 | } | |
178 | break; | |
5c19dc3a | 179 | case kLastCircleKey: |
fa7225c8 A |
180 | if (circle && from) { |
181 | CFStringRef mCircle = NULL; | |
182 | CFStringRef mFrom = NULL; | |
183 | CFMutableStringRef keycopy = CFStringCreateMutableCopy(NULL, 128, key); | |
184 | ||
185 | if( ((mCircle = copyStringEndingIn(keycopy, sCircleSeparator)) != NULL) && | |
186 | ((mFrom = copyStringEndingIn(keycopy, NULL)) != NULL)) { | |
187 | if (circle && mCircle) *circle = CFStringCreateCopy(NULL, mCircle); | |
188 | if (from && mFrom) *from = CFStringCreateCopy(NULL, mFrom); | |
189 | } else { | |
190 | retval = false; | |
191 | } | |
192 | CFReleaseNull(mCircle); | |
193 | CFReleaseNull(mFrom); | |
194 | CFReleaseNull(keycopy); | |
195 | } | |
196 | ||
d8f41ccd A |
197 | break; |
198 | } | |
d8f41ccd A |
199 | return retval; |
200 | } | |
201 | ||
fa7225c8 | 202 | SOSKVSKeyType SOSKVSKeyGetKeyTypeAndParse(CFStringRef key, CFStringRef *circle, CFStringRef *peerInfo, CFStringRef *ring, CFStringRef *backupName, CFStringRef *from, CFStringRef *to) |
d8f41ccd | 203 | { |
fa7225c8 A |
204 | SOSKVSKeyType retval = SOSKVSKeyGetKeyType(key); |
205 | bool parsed = SOSKVSKeyParse(retval, key, circle, peerInfo, ring, backupName, from, to); | |
206 | if(!parsed) retval = kUnknownKey; | |
207 | ||
208 | return retval; | |
d8f41ccd A |
209 | } |
210 | ||
fa7225c8 | 211 | |
d8f41ccd A |
212 | CFStringRef SOSCircleKeyCreateWithCircle(SOSCircleRef circle, CFErrorRef *error) |
213 | { | |
214 | return SOSCircleKeyCreateWithName(SOSCircleGetName(circle), error); | |
215 | } | |
216 | ||
217 | ||
218 | CFStringRef SOSCircleKeyCreateWithName(CFStringRef circleName, CFErrorRef *error) | |
219 | { | |
220 | if(!circleName) return NULL; | |
221 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), sCirclePrefix, circleName); | |
222 | } | |
223 | ||
5c19dc3a A |
224 | CFStringRef SOSPeerInfoKeyCreateWithName(CFStringRef peer_info_name, CFErrorRef *error) |
225 | { | |
226 | if(!peer_info_name) return NULL; | |
227 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), sPeerInfoPrefix, peer_info_name); | |
228 | } | |
229 | ||
230 | CFStringRef SOSRingKeyCreateWithName(CFStringRef ring_name, CFErrorRef *error) | |
231 | { | |
232 | if(!ring_name) return NULL; | |
233 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), sRingPrefix, ring_name); | |
234 | } | |
235 | ||
d8f41ccd A |
236 | CFStringRef SOSCircleKeyCopyCircleName(CFStringRef key, CFErrorRef *error) |
237 | { | |
238 | CFStringRef circleName = NULL; | |
239 | ||
5c19dc3a | 240 | if (kCircleKey != SOSKVSKeyGetKeyTypeAndParse(key, &circleName, NULL, NULL, NULL, NULL, NULL)) { |
d8f41ccd A |
241 | SOSCreateErrorWithFormat(kSOSErrorNoCircleName, NULL, error, NULL, CFSTR("Couldn't find circle name in key '%@'"), key); |
242 | ||
243 | CFReleaseNull(circleName); | |
244 | } | |
245 | ||
246 | return circleName; | |
247 | } | |
248 | ||
249 | CFStringRef SOSMessageKeyCopyCircleName(CFStringRef key, CFErrorRef *error) | |
250 | { | |
251 | CFStringRef circleName = NULL; | |
252 | ||
5c19dc3a | 253 | if (SOSKVSKeyGetKeyTypeAndParse(key, &circleName, NULL, NULL, NULL, NULL, NULL) != kMessageKey) { |
d8f41ccd A |
254 | SOSCreateErrorWithFormat(kSOSErrorNoCircleName, NULL, error, NULL, CFSTR("Couldn't find circle name in key '%@'"), key); |
255 | ||
256 | CFReleaseNull(circleName); | |
257 | } | |
258 | return circleName; | |
259 | } | |
260 | ||
261 | CFStringRef SOSMessageKeyCopyFromPeerName(CFStringRef messageKey, CFErrorRef *error) | |
262 | { | |
263 | CFStringRef fromPeer = NULL; | |
264 | ||
5c19dc3a | 265 | if (SOSKVSKeyGetKeyTypeAndParse(messageKey, NULL, NULL, NULL, NULL, &fromPeer, NULL) != kMessageKey) { |
d8f41ccd A |
266 | SOSCreateErrorWithFormat(kSOSErrorNoCircleName, NULL, error, NULL, CFSTR("Couldn't find from peer in key '%@'"), messageKey); |
267 | ||
268 | CFReleaseNull(fromPeer); | |
269 | } | |
270 | return fromPeer; | |
271 | } | |
272 | ||
273 | CFStringRef SOSMessageKeyCreateWithCircleNameAndPeerNames(CFStringRef circleName, CFStringRef from_peer_name, CFStringRef to_peer_name) | |
274 | { | |
275 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@%@"), | |
276 | circleName, sCircleSeparator, from_peer_name, sFromToSeparator, to_peer_name); | |
277 | } | |
278 | ||
5c19dc3a A |
279 | CFStringRef SOSMessageKeyCreateWithCircleNameAndTransportType(CFStringRef circleName, CFStringRef transportType) |
280 | { | |
281 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@%@"), | |
fa7225c8 | 282 | circleName, sCircleSeparator, transportType, sFromToSeparator, SOSTransportMessageTypeIDSV2); |
5c19dc3a A |
283 | } |
284 | ||
d8f41ccd A |
285 | CFStringRef SOSMessageKeyCreateWithCircleAndPeerNames(SOSCircleRef circle, CFStringRef from_peer_name, CFStringRef to_peer_name) |
286 | { | |
287 | return SOSMessageKeyCreateWithCircleNameAndPeerNames(SOSCircleGetName(circle), from_peer_name, to_peer_name); | |
288 | } | |
289 | ||
290 | CFStringRef SOSMessageKeyCreateWithCircleAndPeerInfos(SOSCircleRef circle, SOSPeerInfoRef from_peer, SOSPeerInfoRef to_peer) | |
291 | { | |
292 | return SOSMessageKeyCreateWithCircleAndPeerNames(circle, SOSPeerInfoGetPeerID(from_peer), SOSPeerInfoGetPeerID(to_peer)); | |
293 | } | |
294 | ||
fa7225c8 | 295 | CFStringRef SOSMessageKeyCreateFromPeerToTransport(SOSTransportMessageRef transport, CFStringRef peer_name) { |
d8f41ccd A |
296 | CFErrorRef error = NULL; |
297 | SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport); | |
298 | ||
5c19dc3a | 299 | CFStringRef circleName = SOSTransportMessageGetCircleName((SOSTransportMessageRef)transport); |
d8f41ccd | 300 | CFStringRef my_id = SOSEngineGetMyID(engine); |
fa7225c8 A |
301 | if(my_id == NULL) |
302 | { | |
303 | secerror("cannot create message keys, SOSEngineGetMyID returned NULL"); | |
304 | return NULL; | |
305 | } | |
d8f41ccd A |
306 | CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, peer_name, my_id); |
307 | CFReleaseSafe(error); | |
308 | return result; | |
309 | } | |
310 | ||
fa7225c8 | 311 | CFStringRef SOSMessageKeyCreateFromTransportToPeer(SOSTransportMessageRef transport, CFStringRef peer_name) { |
d8f41ccd A |
312 | CFErrorRef error = NULL; |
313 | SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport); | |
314 | ||
5c19dc3a | 315 | CFStringRef circleName = SOSTransportMessageGetCircleName((SOSTransportMessageRef)transport); |
d8f41ccd A |
316 | CFStringRef my_id = SOSEngineGetMyID(engine); |
317 | ||
318 | CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, my_id, peer_name); | |
319 | CFReleaseSafe(error); | |
320 | return result; | |
321 | } | |
322 | ||
323 | CFStringRef SOSRetirementKeyCreateWithCircleNameAndPeer(CFStringRef circle_name, CFStringRef retirement_peer_name) | |
324 | { | |
325 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@"), | |
326 | sRetirementPrefix, circle_name, sCircleSeparator, retirement_peer_name); | |
327 | } | |
328 | ||
5c19dc3a A |
329 | CFStringRef SOSPeerInfoV2KeyCreateWithPeerName(CFStringRef peer_name) |
330 | { | |
331 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), | |
332 | sPeerInfoPrefix, peer_name); | |
333 | } | |
334 | ||
335 | CFStringRef SOSRingKeyCreateWithRingName(CFStringRef ring_name) | |
336 | { | |
337 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), | |
338 | sRingPrefix, ring_name); | |
339 | } | |
340 | ||
d8f41ccd A |
341 | CFStringRef SOSRetirementKeyCreateWithCircleAndPeer(SOSCircleRef circle, CFStringRef retirement_peer_name) |
342 | { | |
343 | return SOSRetirementKeyCreateWithCircleNameAndPeer(SOSCircleGetName(circle), retirement_peer_name); | |
344 | } | |
345 | ||
5c19dc3a A |
346 | //should be poak|ourPeerID |
347 | CFStringRef SOSLastCirclePushedKeyCreateWithCircleNameAndPeerID(CFStringRef circleName, CFStringRef peerID){ | |
348 | ||
349 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@%@"), | |
350 | sLastCirclePushedPrefix, sCirclePrefix, circleName, sCircleSeparator, peerID); | |
351 | } | |
352 | ||
353 | CFStringRef SOSLastCirclePushedKeyCreateWithAccountGestalt(SOSAccountRef account){ | |
354 | CFStringRef gestaltInfo = SOSAccountCreateCompactDescription(account); | |
355 | CFStringRef key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@"), | |
356 | sLastCirclePushedPrefix, sCirclePrefix, gestaltInfo); | |
357 | CFReleaseNull(gestaltInfo); | |
358 | return key; | |
359 | } | |
360 | ||
361 | //should be >KeyParameters|ourPeerID | |
362 | CFStringRef SOSLastKeyParametersPushedKeyCreateWithPeerID(CFStringRef peerID){ | |
363 | ||
364 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@"), | |
365 | sLastKeyParametersPushedPrefix,kSOSKVSKeyParametersKey, sCircleSeparator, peerID); | |
366 | } | |
367 | ||
368 | ||
369 | //should be >KeyParameters|ourPeerID | |
370 | CFStringRef SOSLastKeyParametersPushedKeyCreateWithAccountGestalt(SOSAccountRef account){ | |
371 | ||
372 | CFStringRef gestaltInfo = SOSAccountCreateCompactDescription(account); | |
373 | CFStringRef key= CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@"), | |
374 | sLastKeyParametersPushedPrefix, kSOSKVSKeyParametersKey, sCircleSeparator, gestaltInfo); | |
375 | CFReleaseNull(gestaltInfo); | |
376 | return key; | |
377 | } | |
378 | ||
379 | CFStringRef SOSDebugInfoKeyCreateWithTypeName(CFStringRef type_name) | |
380 | { | |
381 | return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), | |
382 | sDebugInfoPrefix, type_name); | |
383 | } | |
384 |