]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/Tool/keychain_sync.c
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / Tool / keychain_sync.c
1 /*
2 * Copyright (c) 2003-2007,2009-2010,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 * keychain_add.c
24 */
25
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/utsname.h>
32 #include <sys/stat.h>
33 #include <time.h>
34
35 #include <Security/SecItem.h>
36
37 #include <CoreFoundation/CFNumber.h>
38 #include <CoreFoundation/CFString.h>
39
40 #include <Security/SecureObjectSync/SOSCloudCircle.h>
41 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
42 #include <Security/SecureObjectSync/SOSPeerInfo.h>
43 #include <Security/SecureObjectSync/SOSPeerInfoPriv.h>
44 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
45 #include <Security/SecureObjectSync/SOSUserKeygen.h>
46 #include <Security/SecureObjectSync/SOSKVSKeys.h>
47 #include <securityd/SOSCloudCircleServer.h>
48 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
49 #include <Security/SecOTRSession.h>
50 #include <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
51
52 #include <utilities/SecCFWrappers.h>
53 #include <utilities/debugging.h>
54
55 #include <SecurityTool/readline.h>
56 #include <notify.h>
57
58 #include "keychain_sync.h"
59 #include "keychain_log.h"
60 #include "secToolFileIO.h"
61
62 #include <Security/SecPasswordGenerate.h>
63
64 #define MAXKVSKEYTYPE kUnknownKey
65 #define DATE_LENGTH 18
66
67
68 static bool clearAllKVS(CFErrorRef *error)
69 {
70 __block bool result = false;
71 const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
72 dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
73 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
74 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
75
76 SOSCloudKeychainClearAll(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef cerror)
77 {
78 result = (cerror != NULL);
79 dispatch_semaphore_signal(waitSemaphore);
80 });
81
82 dispatch_semaphore_wait(waitSemaphore, finishTime);
83 dispatch_release(waitSemaphore);
84
85 return result;
86 }
87
88 static const char *getSOSCCStatusDescription(SOSCCStatus ccstatus)
89 {
90 switch (ccstatus)
91 {
92 case kSOSCCInCircle: return "In Circle";
93 case kSOSCCNotInCircle: return "Not in Circle";
94 case kSOSCCRequestPending: return "Request pending";
95 case kSOSCCCircleAbsent: return "Circle absent";
96 case kSOSCCError: return "Circle error";
97
98 default:
99 return "<unknown ccstatus>";
100 break;
101 }
102 }
103
104 static void printPeerInfos(char *label, CFArrayRef (^getArray)(CFErrorRef *error)) {
105 CFErrorRef error = NULL;
106 CFArrayRef ppi = getArray(&error);
107 SOSPeerInfoRef me = SOSCCCopyMyPeerInfo(NULL);
108 CFStringRef mypeerID = SOSPeerInfoGetPeerID(me);
109
110 if(ppi) {
111 printmsg(CFSTR("%s count: %ld\n"), label, (long)CFArrayGetCount(ppi));
112 CFArrayForEach(ppi, ^(const void *value) {
113 char buf[160];
114 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
115 CFIndex version = SOSPeerInfoGetVersion(peer);
116 CFStringRef peerName = SOSPeerInfoGetPeerName(peer);
117 CFStringRef devtype = SOSPeerInfoGetPeerDeviceType(peer);
118 CFStringRef peerID = SOSPeerInfoGetPeerID(peer);
119 CFStringRef transportType = CFSTR("KVS");
120 CFStringRef deviceID = CFSTR("");
121 CFDictionaryRef gestalt = SOSPeerInfoCopyPeerGestalt(peer);
122 CFStringRef osVersion = CFDictionaryGetValue(gestalt, CFSTR("OSVersion"));
123 CFReleaseNull(gestalt);
124
125
126 if(version >= 2){
127 CFDictionaryRef v2Dictionary = peer->v2Dictionary;
128 transportType = CFDictionaryGetValue(v2Dictionary, sTransportType);
129 deviceID = CFDictionaryGetValue(v2Dictionary, sDeviceID);
130 }
131 char *pname = CFStringToCString(peerName);
132 char *dname = CFStringToCString(devtype);
133 char *tname = CFStringToCString(transportType);
134 char *iname = CFStringToCString(deviceID);
135 char *osname = CFStringToCString(osVersion);
136 const char *me = CFEqualSafe(mypeerID, peerID) ? "me>" : " ";
137
138
139 snprintf(buf, 160, "%s %s: %-16s %-16s %-16s %-16s", me, label, pname, dname, tname, iname);
140
141 free(pname);
142 free(dname);
143 CFStringRef pid = SOSPeerInfoGetPeerID(peer);
144 CFIndex vers = SOSPeerInfoGetVersion(peer);
145 printmsg(CFSTR("%s %@ V%d OS:%s\n"), buf, pid, vers, osname);
146 free(osname);
147 });
148 } else {
149 printmsg(CFSTR("No %s, error: %@\n"), label, error);
150 }
151 CFReleaseNull(ppi);
152 CFReleaseNull(error);
153 }
154
155 static void dumpCircleInfo()
156 {
157 CFErrorRef error = NULL;
158 CFArrayRef generations = NULL;
159 CFArrayRef confirmedDigests = NULL;
160 bool is_user_public_trusted = false;
161 __block int count = 0;
162
163 SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error);
164 if(ccstatus == kSOSCCError) {
165 printmsg(CFSTR("End of Dump - unable to proceed due to ccstatus (%s) error: %@\n"), getSOSCCStatusDescription(ccstatus), error);
166 return;
167 }
168 printmsg(CFSTR("ccstatus: %s (%d)\n"), getSOSCCStatusDescription(ccstatus), ccstatus, error);
169
170 is_user_public_trusted = SOSCCValidateUserPublic(&error);
171 if(is_user_public_trusted)
172 printmsg(CFSTR("Account user public is trusted%@"),CFSTR("\n"));
173 else
174 printmsg(CFSTR("Account user public is not trusted error:(%@)\n"), error);
175 CFReleaseNull(error);
176
177 generations = SOSCCCopyGenerationPeerInfo(&error);
178 if(generations) {
179 CFArrayForEach(generations, ^(const void *value) {
180 count++;
181 if(count%2 == 0)
182 printmsg(CFSTR("Circle name: %@, "),value);
183
184 if(count%2 != 0) {
185 CFStringRef genDesc = SOSGenerationCountCopyDescription(value);
186 printmsg(CFSTR("Generation Count: %@"), genDesc);
187 CFReleaseNull(genDesc);
188 }
189 printmsg(CFSTR("%s\n"), "");
190 });
191 } else {
192 printmsg(CFSTR("No generation count: %@\n"), error);
193 }
194 CFReleaseNull(generations);
195 CFReleaseNull(error);
196
197 printPeerInfos(" Peers", ^(CFErrorRef *error) { return SOSCCCopyValidPeerPeerInfo(error); });
198 printPeerInfos(" Invalid", ^(CFErrorRef *error) { return SOSCCCopyNotValidPeerPeerInfo(error); });
199 printPeerInfos(" Retired", ^(CFErrorRef *error) { return SOSCCCopyRetirementPeerInfo(error); });
200 printPeerInfos(" Concur", ^(CFErrorRef *error) { return SOSCCCopyConcurringPeerPeerInfo(error); });
201 printPeerInfos("Applicants", ^(CFErrorRef *error) { return SOSCCCopyApplicantPeerInfo(error); });
202
203 confirmedDigests = SOSCCCopyEngineState(&error);
204 if(confirmedDigests)
205 {
206 count = 0;
207 CFArrayForEach(confirmedDigests, ^(const void *value) {
208 count++;
209 if(count % 2 != 0)
210 printmsg(CFSTR("%@"), value);
211
212 if(count % 2 == 0) {
213 CFStringRef hexDigest = CFDataCopyHexString(value);
214 printmsg(CFSTR(" %@\n"), hexDigest);
215 CFReleaseSafe(hexDigest);
216 }
217 });
218 }
219 else
220 printmsg(CFSTR("No engine peers: %@\n"), error);
221 CFReleaseNull(confirmedDigests);
222 }
223
224 static bool enableDefaultViews()
225 {
226 bool result = false;
227 CFMutableSetRef viewsToEnable = CFSetCreateMutable(NULL, 0, NULL);
228 CFMutableSetRef viewsToDisable = CFSetCreateMutable(NULL, 0, NULL);
229 CFSetAddValue(viewsToEnable, (void*)kSOSViewWiFi);
230 CFSetAddValue(viewsToEnable, (void*)kSOSViewAutofillPasswords);
231 CFSetAddValue(viewsToEnable, (void*)kSOSViewSafariCreditCards);
232 CFSetAddValue(viewsToEnable, (void*)kSOSViewOtherSyncable);
233
234 result = SOSCCViewSet(viewsToEnable, viewsToDisable);
235 CFRelease(viewsToEnable);
236 CFRelease(viewsToDisable);
237 return result;
238 }
239
240 static bool requestToJoinCircle(CFErrorRef *error)
241 {
242 // Set the visual state of switch based on membership in circle
243 bool hadError = false;
244 SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(error);
245
246 switch (ccstatus)
247 {
248 case kSOSCCCircleAbsent:
249 hadError = !SOSCCResetToOffering(error);
250 hadError &= enableDefaultViews();
251 break;
252 case kSOSCCNotInCircle:
253 hadError = !SOSCCRequestToJoinCircle(error);
254 hadError &= enableDefaultViews();
255 break;
256 default:
257 printerr(CFSTR("Request to join circle with bad status: %@ (%d)\n"), SOSCCGetStatusDescription(ccstatus), ccstatus);
258 break;
259 }
260 return hadError;
261 }
262
263 static bool setPassword(char *labelAndPassword, CFErrorRef *err)
264 {
265 char *last = NULL;
266 char *token0 = strtok_r(labelAndPassword, ":", &last);
267 char *token1 = strtok_r(NULL, "", &last);
268 CFStringRef label = token1 ? CFStringCreateWithCString(NULL, token0, kCFStringEncodingUTF8) : CFSTR("security command line tool");
269 char *password_token = token1 ? token1 : token0;
270 password_token = password_token ? password_token : "";
271 CFDataRef password = CFDataCreate(NULL, (const UInt8*) password_token, strlen(password_token));
272 bool returned = !SOSCCSetUserCredentials(label, password, err);
273 CFRelease(label);
274 CFRelease(password);
275 return returned;
276 }
277
278 static bool tryPassword(char *labelAndPassword, CFErrorRef *err)
279 {
280 char *last = NULL;
281 char *token0 = strtok_r(labelAndPassword, ":", &last);
282 char *token1 = strtok_r(NULL, "", &last);
283 CFStringRef label = token1 ? CFStringCreateWithCString(NULL, token0, kCFStringEncodingUTF8) : CFSTR("security command line tool");
284 char *password_token = token1 ? token1 : token0;
285 password_token = password_token ? password_token : "";
286 CFDataRef password = CFDataCreate(NULL, (const UInt8*) password_token, strlen(password_token));
287 bool returned = !SOSCCTryUserCredentials(label, password, err);
288 CFRelease(label);
289 CFRelease(password);
290 return returned;
291 }
292
293 static CFTypeRef getObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, dispatch_group_t dgroup)
294 {
295 __block CFTypeRef object = NULL;
296
297 const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
298 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
299 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
300
301 dispatch_group_enter(dgroup);
302
303 CloudKeychainReplyBlock replyBlock =
304 ^ (CFDictionaryRef returnedValues, CFErrorRef error)
305 {
306 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues);
307 object = returnedValues;
308 if (object)
309 CFRetain(object);
310 if (error)
311 {
312 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error);
313 // CFRelease(*error);
314 }
315 dispatch_group_leave(dgroup);
316 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object);
317 dispatch_semaphore_signal(waitSemaphore);
318 };
319
320 if (!keysToGet)
321 SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock);
322 else
323 SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock);
324
325 dispatch_semaphore_wait(waitSemaphore, finishTime);
326 dispatch_release(waitSemaphore);
327 if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull
328 {
329 CFRelease(object);
330 object = NULL;
331 }
332 secerror("returned: %@", object);
333 return object;
334 }
335
336 static CFStringRef printFullDataString(CFDataRef data){
337 __block CFStringRef fullData = NULL;
338
339 BufferPerformWithHexString(CFDataGetBytePtr(data), CFDataGetLength(data), ^(CFStringRef dataHex) {
340 fullData = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), dataHex);
341 });
342
343 return fullData;
344 }
345
346 static void displayLastKeyParameters(CFTypeRef key, CFTypeRef value)
347 {
348 CFDataRef valueAsData = asData(value, NULL);
349 if(valueAsData){
350 CFDataRef dateData = CFDataCreateCopyFromRange(kCFAllocatorDefault, valueAsData, CFRangeMake(0, DATE_LENGTH));
351 CFDataRef keyParameterData = CFDataCreateCopyFromPositions(kCFAllocatorDefault, valueAsData, DATE_LENGTH, CFDataGetLength(valueAsData));
352 CFStringRef dateString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, dateData, kCFStringEncodingUTF8);
353 CFStringRef keyParameterDescription = UserParametersDescription(keyParameterData);
354 if(keyParameterDescription)
355 printmsg(CFSTR("%@: %@: %@\n"), key, dateString, keyParameterDescription);
356 else
357 printmsg(CFSTR("%@: %@\n"), key, printFullDataString(value));
358 CFReleaseNull(dateString);
359 CFReleaseNull(keyParameterData);
360 CFReleaseNull(dateData);
361 CFReleaseNull(keyParameterDescription);
362 }
363 else{
364 printmsg(CFSTR("%@: %@\n"), key, value);
365 }
366 }
367
368 static void displayKeyParameters(CFTypeRef key, CFTypeRef value)
369 {
370 if(isData(value)){
371 CFStringRef keyParameterDescription = UserParametersDescription((CFDataRef)value);
372
373 if(keyParameterDescription)
374 printmsg(CFSTR("%@: %@\n"), key, keyParameterDescription);
375 else
376 printmsg(CFSTR("%@: %@\n"), key, value);
377
378 CFReleaseNull(keyParameterDescription);
379 }
380 else{
381 printmsg(CFSTR("%@: %@\n"), key, value);
382 }
383 }
384
385 static void displayLastCircle(CFTypeRef key, CFTypeRef value)
386 {
387 CFDataRef valueAsData = asData(value, NULL);
388 if(valueAsData){
389 CFErrorRef localError = NULL;
390
391 CFDataRef dateData = CFDataCreateCopyFromRange(kCFAllocatorDefault, valueAsData, CFRangeMake(0, DATE_LENGTH));
392 CFDataRef circleData = CFDataCreateCopyFromPositions(kCFAllocatorDefault, valueAsData, DATE_LENGTH, CFDataGetLength(valueAsData));
393 CFStringRef dateString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, dateData, kCFStringEncodingUTF8);
394 SOSCircleRef circle = SOSCircleCreateFromData(NULL, (CFDataRef) circleData, &localError);
395
396 if(circle){
397 CFIndex size = 5;
398 CFNumberRef idLength = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &size);
399 CFDictionaryRef format = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength, NULL);
400 printmsgWithFormatOptions(format, CFSTR("%@: %@: %@\n"), key, dateString, circle);
401 CFReleaseNull(idLength);
402 CFReleaseNull(format);
403
404 }
405 else
406 printmsg(CFSTR("%@: %@\n"), key, printFullDataString(circleData));
407
408 CFReleaseNull(dateString);
409 CFReleaseNull(circleData);
410 CFReleaseSafe(circle);
411 CFReleaseNull(dateData);
412 CFReleaseNull(localError);
413 }
414 else{
415 printmsg(CFSTR("%@: %@\n"), key, value);
416 }
417 }
418
419 static void displayCircle(CFTypeRef key, CFTypeRef value)
420 {
421 CFDataRef circleData = (CFDataRef)value;
422
423 CFErrorRef localError = NULL;
424 if (isData(circleData))
425 {
426 CFIndex size = 5;
427 CFNumberRef idLength = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &size);
428 CFDictionaryRef format = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength, NULL);
429 SOSCircleRef circle = SOSCircleCreateFromData(NULL, circleData, &localError);
430 printmsgWithFormatOptions(format, CFSTR("%@: %@\n"), key, circle);
431 CFReleaseSafe(circle);
432 CFReleaseNull(idLength);
433 CFReleaseNull(format);
434
435 }
436 else
437 printmsg(CFSTR("%@: %@\n"), key, value);
438 }
439
440 static void displayMessage(CFTypeRef key, CFTypeRef value)
441 {
442 CFDataRef message = (CFDataRef)value;
443 if(isData(message)){
444 const char* messageType = SecOTRPacketTypeString(message);
445 printmsg(CFSTR("%@: %s: %ld\n"), key, messageType, CFDataGetLength(message));
446 }
447 else
448 printmsg(CFSTR("%@: %@\n"), key, value);
449 }
450
451 static void printEverything(CFTypeRef objects)
452 {
453 CFDictionaryForEach(objects, ^(const void *key, const void *value) {
454 if (isData(value))
455 {
456 printmsg(CFSTR("%@: %@\n\n"), key, printFullDataString(value));
457 }
458 else
459 printmsg(CFSTR("%@: %@\n"), key, value);
460 });
461
462 }
463
464 static void decodeForKeyType(CFTypeRef key, CFTypeRef value, SOSKVSKeyType type){
465 switch (type) {
466 case kCircleKey:
467 displayCircle(key, value);
468 break;
469 case kRetirementKey:
470 case kMessageKey:
471 displayMessage(key, value);
472 break;
473 case kParametersKey:
474 displayKeyParameters(key, value);
475 break;
476 case kLastKeyParameterKey:
477 displayLastKeyParameters(key, value);
478 break;
479 case kLastCircleKey:
480 displayLastCircle(key, value);
481 break;
482 case kInitialSyncKey:
483 case kAccountChangedKey:
484 case kDebugInfoKey:
485 case kRingKey:
486 case kPeerInfoKey:
487 default:
488 printmsg(CFSTR("%@: %@\n"), key, value);
489 break;
490 }
491 }
492
493 static void decodeAllTheValues(CFTypeRef objects){
494 SOSKVSKeyType keyType = 0;
495 __block bool didPrint = false;
496
497 for (keyType = 0; keyType <= MAXKVSKEYTYPE; keyType++){
498 CFDictionaryForEach(objects, ^(const void *key, const void *value) {
499 if(SOSKVSKeyGetKeyType(key) == keyType){
500 decodeForKeyType(key, value, keyType);
501 didPrint = true;
502 }
503 });
504 if(didPrint)
505 printmsg(CFSTR("%@\n"), CFSTR(""));
506 didPrint = false;
507 }
508 }
509 static bool dumpKVS(char *itemName, CFErrorRef *err)
510 {
511 CFArrayRef keysToGet = NULL;
512 if (itemName)
513 {
514 CFStringRef itemStr = CFStringCreateWithCString(kCFAllocatorDefault, itemName, kCFStringEncodingUTF8);
515 fprintf(outFile, "Retrieving %s from KVS\n", itemName);
516 keysToGet = CFArrayCreateForCFTypes(kCFAllocatorDefault, itemStr, NULL);
517 CFReleaseSafe(itemStr);
518 }
519 dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
520 dispatch_group_t work_group = dispatch_group_create();
521 CFTypeRef objects = getObjectsFromCloud(keysToGet, generalq, work_group);
522 CFReleaseSafe(keysToGet);
523 if (objects)
524 {
525 fprintf(outFile, "All keys and values straight from KVS\n");
526 printEverything(objects);
527 fprintf(outFile, "\nAll values in decoded form...\n");
528 decodeAllTheValues(objects);
529 }
530 fprintf(outFile, "\n");
531 return true;
532 }
533
534 static bool syncAndWait(char *itemName, CFErrorRef *err)
535 {
536 CFArrayRef keysToGet = NULL;
537 __block CFTypeRef objects = NULL;
538 if (!itemName)
539 {
540 fprintf(errFile, "No item keys supplied\n");
541 return false;
542 }
543
544 CFStringRef itemStr = CFStringCreateWithCString(kCFAllocatorDefault, itemName, kCFStringEncodingUTF8);
545 fprintf(outFile, "Retrieving %s from KVS\n", itemName);
546 keysToGet = CFArrayCreateForCFTypes(kCFAllocatorDefault, itemStr, NULL);
547 CFReleaseSafe(itemStr);
548
549 dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
550
551 const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
552 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
553 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
554
555 CloudKeychainReplyBlock replyBlock = ^ (CFDictionaryRef returnedValues, CFErrorRef error)
556 {
557 secinfo("sync", "SOSCloudKeychainSynchronizeAndWait returned: %@", returnedValues);
558 if (error)
559 secerror("SOSCloudKeychainSynchronizeAndWait returned error: %@", error);
560 objects = returnedValues;
561 if (objects)
562 CFRetain(objects);
563 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", objects);
564 dispatch_semaphore_signal(waitSemaphore);
565 };
566
567 SOSCloudKeychainSynchronizeAndWait(keysToGet, generalq, replyBlock);
568
569 dispatch_semaphore_wait(waitSemaphore, finishTime);
570 dispatch_release(waitSemaphore);
571
572 CFReleaseSafe(keysToGet);
573 dumpKVS(NULL, NULL);
574 fprintf(outFile, "\n");
575 return false;
576 }
577
578 static struct foo {
579 const char *name;
580 const CFStringRef *viewspec;
581 } string2View[] = {
582 {
583 "keychain", &kSOSViewKeychainV0
584 }, {
585 "masterkey", &kSOSViewPCSMasterKey,
586 }, {
587 "iclouddrive", &kSOSViewPCSiCloudDrive,
588 }, {
589 "photos", &kSOSViewPCSPhotos,
590 }, {
591 "escrow", &kSOSViewPCSEscrow,
592 }, {
593 "fde", &kSOSViewPCSFDE,
594 }, {
595 "maildrop", &kSOSViewPCSMailDrop,
596 }, {
597 "icloudbackup", &kSOSViewPCSiCloudBackup,
598 }, {
599 "notes", &kSOSViewPCSNotes,
600 }, {
601 "imessage", &kSOSViewPCSiMessage,
602 }, {
603 "feldspar", &kSOSViewPCSFeldspar,
604 }, {
605 "appletv", &kSOSViewAppleTV,
606 }, {
607 "homekit", &kSOSViewHomeKit,
608 }, {
609 "wifi", &kSOSViewWiFi,
610 }, {
611 "passwords", &kSOSViewAutofillPasswords,
612 }, {
613 "creditcards", &kSOSViewSafariCreditCards,
614 }, {
615 "icloudidentity", &kSOSViewiCloudIdentity,
616 }, {
617 "othersyncable", &kSOSViewOtherSyncable,
618 }
619 };
620
621 static CFStringRef convertStringToView(char *viewname) {
622 unsigned n;
623
624 for (n = 0; n < sizeof(string2View)/sizeof(string2View[0]); n++) {
625 if (strcmp(string2View[n].name, viewname) == 0)
626 return *string2View[n].viewspec;
627 }
628
629 // Leak this, since it's a getter.
630 return CFStringCreateWithCString(kCFAllocatorDefault, viewname, kCFStringEncodingUTF8);
631 }
632
633 static CFStringRef convertViewReturnCodeToString(SOSViewActionCode ac) {
634 CFStringRef retval = NULL;
635 switch(ac) {
636 case kSOSCCGeneralViewError:
637 retval = CFSTR("General Error"); break;
638 case kSOSCCViewMember:
639 retval = CFSTR("Is Member of View"); break;
640 case kSOSCCViewNotMember:
641 retval = CFSTR("Is Not Member of View"); break;
642 case kSOSCCViewNotQualified:
643 retval = CFSTR("Is not qualified for View"); break;
644 case kSOSCCNoSuchView:
645 retval = CFSTR("No Such View"); break;
646 }
647 return retval;
648 }
649
650 static bool viewcmd(char *itemName, CFErrorRef *err) {
651 char *cmd, *viewname;
652 SOSViewActionCode ac = kSOSCCViewQuery;
653 CFStringRef viewspec;
654
655 viewname = strchr(itemName, ':');
656 if(viewname == NULL) return false;
657 *viewname = 0;
658 viewname++;
659 cmd = itemName;
660
661 if(strcmp(cmd, "enable") == 0) {
662 ac = kSOSCCViewEnable;
663 } else if(strcmp(cmd, "disable") == 0) {
664 ac = kSOSCCViewDisable;
665 } else if(strcmp(cmd, "query") == 0) {
666 ac = kSOSCCViewQuery;
667 } else {
668 return false;
669 }
670
671 if(strchr(viewname, ',') == NULL) { // original single value version
672 viewspec = convertStringToView(viewname);
673 if(!viewspec) return false;
674
675 SOSViewResultCode rc = SOSCCView(viewspec, ac, err);
676 CFStringRef resultString = convertViewReturnCodeToString(rc);
677
678 printmsg(CFSTR("View Result: %@ : %@\n"), resultString, viewspec);
679 return true;
680 }
681
682 if(ac == kSOSCCViewQuery) return false;
683
684 // new multi-view version
685 char *viewlist = strdup(viewname);
686 char *token;
687 char *tofree = viewlist;
688 CFMutableSetRef viewSet = CFSetCreateMutable(NULL, 0, &kCFCopyStringSetCallBacks);
689
690 while ((token = strsep(&viewlist, ",")) != NULL) {
691 CFStringRef resultString = convertStringToView(token);
692 CFSetAddValue(viewSet, resultString);
693 }
694
695 printmsg(CFSTR("viewSet provided is %@\n"), viewSet);
696
697 free(tofree);
698
699 bool retcode;
700 if(ac == kSOSCCViewEnable) retcode = SOSCCViewSet(viewSet, NULL);
701 else retcode = SOSCCViewSet(NULL, viewSet);
702
703 fprintf(outFile, "SOSCCViewSet returned %s\n", (retcode)? "true": "false");
704
705 return true;
706 }
707
708 static bool listviewcmd(CFErrorRef *err) {
709 unsigned n;
710
711 for (n = 0; n < sizeof(string2View)/sizeof(string2View[0]); n++) {
712 CFStringRef viewspec = *string2View[n].viewspec;
713
714 SOSViewResultCode rc = SOSCCView(viewspec, kSOSCCViewQuery, err);
715 CFStringRef resultString = convertViewReturnCodeToString(rc);
716
717 printmsg(CFSTR("View Result: %@ : %@\n"), resultString, viewspec);
718 };
719
720 return true;
721 }
722
723 static CFStringRef convertStringToProperty(char *propertyname) {
724 CFStringRef propertyspec = NULL;
725
726 if(strcmp(propertyname, "hasentropy") == 0) {
727 propertyspec = kSOSSecPropertyHasEntropy;
728 } else if(strcmp(propertyname, "screenlock") == 0) {
729 propertyspec = kSOSSecPropertyScreenLock;
730 } else if(strcmp(propertyname, "SEP") == 0) {
731 propertyspec = kSOSSecPropertySEP;
732 } else if(strcmp(propertyname, "IOS") == 0) {
733 propertyspec = kSOSSecPropertyIOS;
734 }
735 return propertyspec;
736 }
737
738
739 static CFStringRef convertPropertyReturnCodeToString(SOSSecurityPropertyResultCode ac) {
740 CFStringRef retval = NULL;
741 switch(ac) {
742 case kSOSCCGeneralSecurityPropertyError:
743 retval = CFSTR("General Error"); break;
744 case kSOSCCSecurityPropertyValid:
745 retval = CFSTR("Is Member of Security Property"); break;
746 case kSOSCCSecurityPropertyNotValid:
747 retval = CFSTR("Is Not Member of Security Property"); break;
748 case kSOSCCSecurityPropertyNotQualified:
749 retval = CFSTR("Is not qualified for Security Property"); break;
750 case kSOSCCNoSuchSecurityProperty:
751 retval = CFSTR("No Such Security Property"); break;
752 }
753 return retval;
754 }
755
756
757 static bool SecPropertycmd(char *itemName, CFErrorRef *err) {
758 char *cmd, *propertyname;
759 SOSSecurityPropertyActionCode ac = kSOSCCSecurityPropertyQuery;
760 CFStringRef propertyspec;
761
762 propertyname = strchr(itemName, ':');
763 if(propertyname == NULL) return false;
764 *propertyname = 0;
765 propertyname++;
766 cmd = itemName;
767
768 if(strcmp(cmd, "enable") == 0) {
769 ac = kSOSCCSecurityPropertyEnable;
770 } else if(strcmp(cmd, "disable") == 0) {
771 ac = kSOSCCSecurityPropertyDisable;
772 } else if(strcmp(cmd, "query") == 0) {
773 ac = kSOSCCSecurityPropertyQuery;
774 } else {
775 return false;
776 }
777
778 propertyspec = convertStringToProperty(propertyname);
779 if(!propertyspec) return false;
780
781 SOSSecurityPropertyResultCode rc = SOSCCSecurityProperty(propertyspec, ac, err);
782 CFStringRef resultString = convertPropertyReturnCodeToString(rc);
783
784 printmsg(CFSTR("Property Result: %@ : %@\n"), resultString, propertyspec);
785 return true;
786 }
787
788
789 static void dumpStringSet(CFStringRef label, CFSetRef s) {
790 if(!s || !label) return;
791
792 printmsg(CFSTR("%@: { "), label);
793 __block bool first = true;
794 CFSetForEach(s, ^(const void *p) {
795 CFStringRef fmt = CFSTR(", %@");
796 if(first) {
797 fmt = CFSTR("%@");
798 }
799 CFStringRef string = (CFStringRef) p;
800 printmsg(fmt, string);
801 first=false;
802 });
803 printmsg(CFSTR(" }\n"), NULL);
804 }
805
806 static bool dumpMyPeer(CFErrorRef *error) {
807 SOSPeerInfoRef myPeer = SOSCCCopyMyPeerInfo(error);
808
809 if (!myPeer) return false;
810
811 CFStringRef peerID = SOSPeerInfoGetPeerID(myPeer);
812 CFStringRef peerName = SOSPeerInfoGetPeerName(myPeer);
813 CFIndex peerVersion = SOSPeerInfoGetVersion(myPeer);
814 bool retirement = SOSPeerInfoIsRetirementTicket(myPeer);
815
816 printmsg(CFSTR("Peer Name: %@ PeerID: %@ Version: %d\n"), peerName, peerID, peerVersion);
817 if(retirement) {
818 CFDateRef retdate = SOSPeerInfoGetRetirementDate(myPeer);
819 printmsg(CFSTR("Retired: %@\n"), retdate);
820
821 }
822
823 if(peerVersion >= 2) {
824 CFMutableSetRef views = SOSPeerInfoV2DictionaryCopySet(myPeer, sViewsKey);
825 CFStringRef serialNumber = SOSPeerInfoV2DictionaryCopyString(myPeer, sSerialNumberKey);
826 CFBooleanRef preferIDS = SOSPeerInfoV2DictionaryCopyBoolean(myPeer, sPreferIDS);
827 CFStringRef transportType = SOSPeerInfoV2DictionaryCopyString(myPeer, sTransportType);
828 CFStringRef idsDeviceID = SOSPeerInfoV2DictionaryCopyString(myPeer, sDeviceID);
829 CFMutableSetRef properties = SOSPeerInfoV2DictionaryCopySet(myPeer, sSecurityPropertiesKey);
830
831 printmsg(CFSTR("Serial#: %@ PrefIDS#: %@ transportType#: %@ idsDeviceID#: %@\n"),
832 serialNumber, preferIDS, transportType, idsDeviceID);
833 dumpStringSet(CFSTR(" Views: "), views);
834 dumpStringSet(CFSTR("SecurityProperties: "), properties);
835
836 CFReleaseSafe(serialNumber);
837 CFReleaseSafe(preferIDS);
838 CFReleaseSafe(views);
839 CFReleaseSafe(transportType);
840 CFReleaseSafe(idsDeviceID);
841 CFReleaseSafe(properties);
842
843 }
844
845 return myPeer != NULL;
846 }
847
848 static bool setBag(char *itemName, CFErrorRef *err)
849 {
850 __block bool success = false;
851 __block CFErrorRef error = NULL;
852
853 CFStringRef random = SecPasswordCreateWithRandomDigits(10, NULL);
854
855 CFStringPerformWithUTF8CFData(random, ^(CFDataRef stringAsData) {
856 if (0 == strncasecmp(optarg, "single", 6) || 0 == strncasecmp(optarg, "all", 3)) {
857 bool includeV0 = (0 == strncasecmp(optarg, "all", 3));
858 printmsg(CFSTR("Setting iCSC single using entropy from string: %@\n"), random);
859 CFDataRef aks_bag = SecAKSCopyBackupBagWithSecret(CFDataGetLength(stringAsData), (uint8_t*)CFDataGetBytePtr(stringAsData), &error);
860
861 if (aks_bag) {
862 success = SOSCCRegisterSingleRecoverySecret(aks_bag, includeV0, &error);
863 if (!success) {
864 printmsg(CFSTR("Failed registering single secret %@"), error);
865 CFReleaseNull(aks_bag);
866 }
867 } else {
868 printmsg(CFSTR("Failed to create aks_bag: %@"), error);
869 }
870 CFReleaseNull(aks_bag);
871 } else if (0 == strncasecmp(optarg, "device", 6)) {
872 printmsg(CFSTR("Setting Device Secret using entropy from string: %@\n"), random);
873
874 SOSPeerInfoRef me = SOSCCCopyMyPeerWithNewDeviceRecoverySecret(stringAsData, &error);
875
876 success = me != NULL;
877
878 if (!success)
879 printmsg(CFSTR("Failed: %@\n"), err);
880 CFReleaseNull(me);
881 } else {
882 printmsg(CFSTR("Unrecognized argument to -b %s\n"), optarg);
883 }
884 });
885
886
887 return success;
888 }
889
890 static void prClientViewState(char *label, bool result) {
891 fprintf(outFile, "Sync Status for %s: %s\n", label, (result) ? "enabled": "not enabled");
892 }
893
894 static bool clientViewStatus(CFErrorRef *error) {
895 prClientViewState("KeychainV0", SOSCCIsIcloudKeychainSyncing());
896 prClientViewState("Safari", SOSCCIsSafariSyncing());
897 prClientViewState("AppleTV", SOSCCIsAppleTVSyncing());
898 prClientViewState("HomeKit", SOSCCIsHomeKitSyncing());
899 prClientViewState("Wifi", SOSCCIsWiFiSyncing());
900 return false;
901 }
902
903
904 static bool dumpYetToSync(CFErrorRef *error) {
905 CFArrayRef yetToSyncViews = SOSCCCopyYetToSyncViewsList(error);
906
907 bool hadError = yetToSyncViews;
908
909 if (yetToSyncViews) {
910 __block CFStringRef separator = CFSTR("");
911
912 printmsg(CFSTR("Yet to sync views: ["), NULL);
913
914 CFArrayForEach(yetToSyncViews, ^(const void *value) {
915 if (isString(value)) {
916 printmsg(CFSTR("%@%@"), separator, value);
917
918 separator = CFSTR(", ");
919 }
920 });
921 printmsg(CFSTR("]\n"), NULL);
922 }
923
924 return !hadError;
925 }
926
927
928 // enable, disable, accept, reject, status, Reset, Clear
929 int
930 keychain_sync(int argc, char * const *argv)
931 {
932 /*
933 "Keychain Syncing"
934 " -d disable"
935 " -e enable (join/create circle)"
936 " -i info (current status)"
937 " -m dump my peer"
938 " -S schedule sync with all peers"
939 "
940 "Account/Circle Management"
941 " -a accept all applicants"
942 " -l [reason] sign out of circle + set custom departure reason"
943 " -q sign out of circle"
944 " -r reject all applicants"
945 " -E ensure fresh parameters"
946 " -b device|all|single Register a backup bag - THIS RESETS BACKUPS!\n"
947 " -A Apply to a ring\n"
948 " -B Withdrawl from a ring\n"
949 " -G Enable Ring\n"
950 " -F Ring Status\n"
951 " -I Dump Ring Information\n"
952
953 " -N (re-)set to new account (USE WITH CARE: device will not leave circle before resetting account!)"
954 " -O reset to offering"
955 " -R reset circle"
956 " -X [limit] best effort bail from circle in limit seconds"
957 " -o list view unaware peers in circle"
958 " -0 boot view unaware peers from circle"
959 " -1 grab account state from the keychain"
960 " -2 delete account state from the keychain"
961 " -3 grab engine state from the keychain"
962 " -4 delete engine state from the keychain"
963 "
964 "IDS"
965 " -g set IDS device id"
966 " -p retrieve IDS device id"
967 " -x ping all devices in an IDS account"
968 " -w check IDS availability"
969 " -z retrieve IDS id through IDSKeychainSyncingProxy"
970 "
971 "Password"
972 " -P [label:]password set password (optionally for a given label) for sync"
973 " -T [label:]password try password (optionally for a given label) for sync"
974 "
975 "KVS"
976 " -k pend all registered kvs keys"
977 " -C clear all values from KVS"
978 " -D [itemName] dump contents of KVS"
979 " -W itemNames sync and dump"
980 "
981 "Misc"
982 " -v [enable|disable|query:viewname] enable, disable, or query my PeerInfo's view set"
983 " viewnames are: keychain|masterkey|iclouddrive|photos|cloudkit|escrow|fde|maildrop|icloudbackup|notes|imessage|appletv|homekit|"
984 " wifi|passwords|creditcards|icloudidentity|othersyncable"
985 " -L list all known view and their status"
986 " -S [enable|disable|propertyname] enable, disable, or query my PeerInfo's Security Property set"
987 " propertynames are: hasentropy|screenlock|SEP|IOS\n"
988 " -U purge private key material cache\n"
989 " -V Report View Sync Status on all known clients.\n"
990 " -H Set escrow record.\n"
991 " -J Get the escrow record.\n"
992 " -M Check peer availability.\n"
993
994 */
995 int ch, result = 0;
996 CFErrorRef error = NULL;
997 bool hadError = false;
998 setOutputTo(NULL, NULL);
999
1000 while ((ch = getopt(argc, argv, "ab:deg:hikl:mopq:rsSv:w:x:zA:B:MNJCDEF:HG:ILOP:RT:UW:X:VY01234")) != -1)
1001 switch (ch) {
1002 case 'l':
1003 {
1004 fprintf(outFile, "Signing out of circle\n");
1005 hadError = !SOSCCSignedOut(true, &error);
1006 if (!hadError) {
1007 errno = 0;
1008 int reason = (int) strtoul(optarg, NULL, 10);
1009 if (errno != 0 ||
1010 reason < kSOSDepartureReasonError ||
1011 reason >= kSOSNumDepartureReasons) {
1012 fprintf(errFile, "Invalid custom departure reason %s\n", optarg);
1013 } else {
1014 fprintf(outFile, "Setting custom departure reason %d\n", reason);
1015 hadError = !SOSCCSetLastDepartureReason(reason, &error);
1016 notify_post(kSOSCCCircleChangedNotification);
1017 }
1018 }
1019 break;
1020 }
1021
1022 case 'q':
1023 {
1024 fprintf(outFile, "Signing out of circle\n");
1025 bool signOutImmediately = false;
1026 if (strcasecmp(optarg, "true") == 0) {
1027 signOutImmediately = true;
1028 } else if (strcasecmp(optarg, "false") == 0) {
1029 signOutImmediately = false;
1030 } else {
1031 fprintf(outFile, "Please provide a \"true\" or \"false\" whether you'd like to leave the circle immediately\n");
1032 }
1033 hadError = !SOSCCSignedOut(signOutImmediately, &error);
1034 notify_post(kSOSCCCircleChangedNotification);
1035 break;
1036 }
1037
1038 case 'p':
1039 {
1040 fprintf(outFile, "Grabbing DS ID\n");
1041 CFStringRef deviceID = SOSCCCopyDeviceID(&error);
1042 if (error) {
1043 hadError = true;
1044 break;
1045 }
1046 if (!isNull(deviceID)) {
1047 const char *id = CFStringGetCStringPtr(deviceID, kCFStringEncodingUTF8);
1048 if (id)
1049 fprintf(outFile, "IDS Device ID: %s\n", id);
1050 else
1051 fprintf(outFile, "IDS Device ID is null!\n");
1052 }
1053 CFReleaseNull(deviceID);
1054 break;
1055 }
1056
1057 case 'g':
1058 {
1059 fprintf(outFile, "Setting DS ID: %s\n", optarg);
1060 CFStringRef deviceID = CFStringCreateWithCString(kCFAllocatorDefault, optarg, kCFStringEncodingUTF8);
1061 hadError = SOSCCSetDeviceID(deviceID, &error);
1062 CFReleaseNull(deviceID);
1063 break;
1064 }
1065
1066 case 'w':
1067 {
1068 fprintf(outFile, "Attempting to send this message over IDS: %s\n", optarg);
1069 CFStringRef message = CFStringCreateWithCString(kCFAllocatorDefault, optarg, kCFStringEncodingUTF8);
1070 hadError = SOSCCIDSServiceRegistrationTest(message, &error);
1071 if (error) {
1072 printerr(CFSTR("IDS is not ready: %@\n"), error);
1073 CFRelease(error);
1074 }
1075 CFReleaseNull(message);
1076 break;
1077 }
1078
1079 case 'x':
1080 {
1081 fprintf(outFile, "Starting ping test using this message: %s\n", optarg);
1082 CFStringRef message = CFStringCreateWithCString(kCFAllocatorDefault, optarg, kCFStringEncodingUTF8);
1083 hadError = SOSCCIDSPingTest(message, &error);
1084 if (error) {
1085 printerr(CFSTR("Ping test failed to start: %@\n"), error);
1086 CFRelease(error);
1087 }
1088 CFReleaseNull(message);
1089 break;
1090 }
1091
1092 case 'z':
1093 hadError = SOSCCIDSDeviceIDIsAvailableTest(&error);
1094 if (error) {
1095 printerr(CFSTR("Failed to retrieve IDS device ID: %@\n"), error);
1096 CFRelease(error);
1097 }
1098 break;
1099
1100 case 'e':
1101 fprintf(outFile, "Turning ON keychain syncing\n");
1102 hadError = requestToJoinCircle(&error);
1103 break;
1104
1105 case 'd':
1106 fprintf(outFile, "Turning OFF keychain syncing\n");
1107 hadError = !SOSCCRemoveThisDeviceFromCircle(&error);
1108 break;
1109
1110 case 'a':
1111 {
1112 CFArrayRef applicants = SOSCCCopyApplicantPeerInfo(NULL);
1113 if (applicants) {
1114 hadError = !SOSCCAcceptApplicants(applicants, &error);
1115 CFRelease(applicants);
1116 } else {
1117 fprintf(errFile, "No applicants to accept\n");
1118 }
1119 break;
1120 }
1121
1122 case 'r':
1123 {
1124 CFArrayRef applicants = SOSCCCopyApplicantPeerInfo(NULL);
1125 if (applicants) {
1126 hadError = !SOSCCRejectApplicants(applicants, &error);
1127 CFRelease(applicants);
1128 } else {
1129 fprintf(errFile, "No applicants to reject\n");
1130 }
1131 break;
1132 }
1133
1134 case 'i':
1135 dumpCircleInfo();
1136 break;
1137
1138 case 'k':
1139 notify_post("com.apple.security.cloudkeychain.forceupdate");
1140 break;
1141
1142 case 'o':
1143 {
1144 printPeerInfos("view-unaware", ^(CFErrorRef *error) { return SOSCCCopyViewUnawarePeerInfo(error); });
1145 break;
1146 }
1147
1148 case '0':
1149 {
1150 CFArrayRef unawares = SOSCCCopyViewUnawarePeerInfo(&error);
1151 if (unawares) {
1152 hadError = !SOSCCRemovePeersFromCircle(unawares, &error);
1153 } else {
1154 hadError = true;
1155 }
1156 CFReleaseNull(unawares);
1157 break;
1158 }
1159 case '1':
1160 {
1161 CFDataRef accountState = SOSCCCopyAccountState(&error);
1162 if (accountState) {
1163 printmsg(CFSTR(" %@\n"), CFDataCopyHexString(accountState));
1164 } else {
1165 hadError = true;
1166 }
1167 CFReleaseNull(accountState);
1168 break;
1169 }
1170 case '2':
1171 {
1172 bool status = SOSCCDeleteAccountState(&error);
1173 if (status) {
1174 printmsg(CFSTR("Deleted account from the keychain %d\n"), status);
1175 } else {
1176 hadError = true;
1177 }
1178 break;
1179 }
1180 case '3':
1181 {
1182 CFDataRef engineState = SOSCCCopyEngineData(&error);
1183 if (engineState) {
1184 printmsg(CFSTR(" %@\n"), CFDataCopyHexString(engineState));
1185 } else {
1186 hadError = true;
1187 }
1188 CFReleaseNull(engineState);
1189 break;
1190 }
1191 case '4':
1192 {
1193 bool status = SOSCCDeleteEngineState(&error);
1194 if (status) {
1195 printmsg(CFSTR("Deleted engine-state from the keychain %d\n"), status);
1196 } else {
1197 hadError = true;
1198 }
1199 break;
1200 }
1201
1202 case 's':
1203 #if TARGET_OS_EMBEDDED
1204 SOSCloudKeychainRequestSyncWithAllPeers(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
1205 #else
1206 fprintf(outFile, "not exported yet...\n");
1207 #endif
1208 break;
1209
1210 case 'E':
1211 {
1212 fprintf(outFile, "Ensuring Fresh Parameters\n");
1213 bool result = SOSCCRequestEnsureFreshParameters(&error);
1214 if (error) {
1215 hadError = true;
1216 break;
1217 }
1218 if (result) {
1219 fprintf(outFile, "Refreshed Parameters Ensured!\n");
1220 } else {
1221 fprintf(outFile, "Problem trying to ensure fresh parameters\n");
1222 }
1223 break;
1224 }
1225 case 'A':
1226 {
1227 fprintf(outFile, "Applying to Ring\n");
1228 CFStringRef ringName = CFStringCreateWithCString(kCFAllocatorDefault, (char *)optarg, kCFStringEncodingUTF8);
1229 hadError = SOSCCApplyToARing(ringName, &error);
1230 break;
1231 }
1232 case 'B':
1233 {
1234 fprintf(outFile, "Withdrawing from Ring\n");
1235 CFStringRef ringName = CFStringCreateWithCString(kCFAllocatorDefault, (char *)optarg, kCFStringEncodingUTF8);
1236 hadError = SOSCCWithdrawlFromARing(ringName, &error);
1237 break;
1238 }
1239 case 'F':
1240 {
1241 fprintf(outFile, "Status of this device in the Ring\n");
1242 CFStringRef ringName = CFStringCreateWithCString(kCFAllocatorDefault, (char *)optarg, kCFStringEncodingUTF8);
1243 hadError = SOSCCRingStatus(ringName, &error);
1244 break;
1245 }
1246 case 'G':
1247 {
1248 fprintf(outFile, "Enabling Ring\n");
1249 CFStringRef ringName = CFStringCreateWithCString(kCFAllocatorDefault, (char *)optarg, kCFStringEncodingUTF8);
1250 hadError = SOSCCEnableRing(ringName, &error);
1251 break;
1252 }
1253 case 'H':
1254 {
1255 fprintf(outFile, "Setting random escrow record\n");
1256 bool success = SOSCCSetEscrowRecord(CFSTR("label"), 8, &error);
1257 if(success)
1258 hadError = false;
1259 else
1260 hadError = true;
1261 break;
1262 }
1263 case 'J':
1264 {
1265 CFDictionaryRef attempts = SOSCCCopyEscrowRecord(&error);
1266 if(attempts){
1267 CFDictionaryForEach(attempts, ^(const void *key, const void *value) {
1268 if(isString(key)){
1269 char *keyString = CFStringToCString(key);
1270 fprintf(outFile, "%s:\n", keyString);
1271 free(keyString);
1272 }
1273 if(isDictionary(value)){
1274 CFDictionaryForEach(value, ^(const void *key, const void *value) {
1275 if(isString(key)){
1276 char *keyString = CFStringToCString(key);
1277 fprintf(outFile, "%s: ", keyString);
1278 free(keyString);
1279 }
1280 if(isString(value)){
1281 char *time = CFStringToCString(value);
1282 fprintf(outFile, "timestamp: %s\n", time);
1283 free(time);
1284 }
1285 else if(isNumber(value)){
1286 uint64_t tries;
1287 CFNumberGetValue(value, kCFNumberLongLongType, &tries);
1288 fprintf(outFile, "date: %llu\n", tries);
1289 }
1290 });
1291 }
1292
1293 });
1294 }
1295 CFReleaseNull(attempts);
1296 hadError = false;
1297 break;
1298 }
1299 case 'M':
1300 {
1301 bool success = SOSCCCheckPeerAvailability(&error);
1302 if(success)
1303 hadError = false;
1304 else
1305 hadError = true;
1306 break;
1307 }
1308 case 'I':
1309 {
1310 fprintf(outFile, "Printing all the rings\n");
1311 CFStringRef ringdescription = SOSCCGetAllTheRings(&error);
1312 if(!ringdescription)
1313 hadError = true;
1314 else
1315 fprintf(outFile, "Rings: %s", CFStringToCString(ringdescription));
1316
1317 break;
1318 }
1319
1320 case 'N':
1321 hadError = !SOSCCAccountSetToNew(&error);
1322 if (!hadError)
1323 notify_post(kSOSCCCircleChangedNotification);
1324 break;
1325
1326 case 'R':
1327 hadError = !SOSCCResetToEmpty(&error);
1328 break;
1329
1330 case 'O':
1331 hadError = !SOSCCResetToOffering(&error);
1332 break;
1333
1334 case 'm':
1335 hadError = !dumpMyPeer(&error);
1336 break;
1337
1338 case 'C':
1339 hadError = clearAllKVS(&error);
1340 break;
1341
1342 case 'P':
1343 hadError = setPassword(optarg, &error);
1344 break;
1345
1346 case 'T':
1347 hadError = tryPassword(optarg, &error);
1348 break;
1349
1350 case 'X':
1351 {
1352 uint64_t limit = strtoul(optarg, NULL, 10);
1353 hadError = !SOSCCBailFromCircle_BestEffort(limit, &error);
1354 break;
1355 }
1356
1357 case 'U':
1358 hadError = !SOSCCPurgeUserCredentials(&error);
1359 break;
1360
1361 case 'D':
1362 hadError = !dumpKVS(optarg, &error);
1363 break;
1364
1365 case 'W':
1366 hadError = syncAndWait(optarg, &error);
1367 break;
1368
1369 case 'v':
1370 hadError = !viewcmd(optarg, &error);
1371 break;
1372
1373 case 'V':
1374 hadError = clientViewStatus(&error);
1375 break;
1376 case 'L':
1377 hadError = !listviewcmd(&error);
1378 break;
1379
1380 case 'S':
1381 hadError = !SecPropertycmd(optarg, &error);
1382 break;
1383
1384 case 'b':
1385 hadError = setBag(optarg, &error);
1386 break;
1387
1388 case 'Y':
1389 hadError = dumpYetToSync(&error);
1390 break;
1391
1392 case '?':
1393 default:
1394 return 2; /* Return 2 triggers usage message. */
1395 }
1396
1397 if (hadError)
1398 printerr(CFSTR("Error: %@\n"), error);
1399
1400 return result;
1401 }