]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/Tool/keychain_sync.m
Security-59306.11.20.tar.gz
[apple/security.git] / keychain / SecureObjectSync / Tool / keychain_sync.m
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 #include <getopt.h>
35 #include <readpassphrase.h>
36
37 #include <Security/SecItem.h>
38
39 #include <CoreFoundation/CFNumber.h>
40 #include <CoreFoundation/CFString.h>
41
42 #include <Security/SecureObjectSync/SOSCloudCircle.h>
43 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
44 #include <Security/SecureObjectSync/SOSPeerInfo.h>
45 #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
46 #include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
47 #include "keychain/SecureObjectSync/SOSUserKeygen.h"
48 #include "keychain/SecureObjectSync/SOSKVSKeys.h"
49 #include <securityd/SOSCloudCircleServer.h>
50 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
51 #include <Security/SecOTRSession.h>
52 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
53
54 #include <utilities/SecCFWrappers.h>
55 #include <utilities/debugging.h>
56
57 #include "SecurityTool/sharedTool/readline.h"
58 #include <notify.h>
59
60 #include "keychain_sync.h"
61 #include "keychain_log.h"
62 #include "syncbackup.h"
63
64 #include "secToolFileIO.h"
65 #include "secViewDisplay.h"
66 #include "accountCirclesViewsPrint.h"
67
68 #include <Security/SecPasswordGenerate.h>
69
70 #define MAXKVSKEYTYPE kUnknownKey
71 #define DATE_LENGTH 18
72
73
74 static bool clearAllKVS(CFErrorRef *error)
75 {
76 __block bool result = false;
77 const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
78 dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
79 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
80 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
81
82 secnotice("circleOps", "security tool called SOSCloudKeychainClearAll to clear KVS");
83 SOSCloudKeychainClearAll(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef cerror)
84 {
85 result = (cerror != NULL);
86 dispatch_semaphore_signal(waitSemaphore);
87 });
88
89 dispatch_semaphore_wait(waitSemaphore, finishTime);
90
91 return result;
92 }
93
94 static bool enableDefaultViews()
95 {
96 bool result = false;
97 CFMutableSetRef viewsToEnable = SOSViewCopyViewSet(kViewSetV0);
98 CFMutableSetRef viewsToDisable = CFSetCreateMutable(NULL, 0, NULL);
99
100 result = SOSCCViewSet(viewsToEnable, viewsToDisable);
101 CFRelease(viewsToEnable);
102 CFRelease(viewsToDisable);
103 return result;
104 }
105
106 static bool requestToJoinCircle(CFErrorRef *error)
107 {
108 // Set the visual state of switch based on membership in circle
109 bool hadError = false;
110 SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(error);
111
112 switch (ccstatus)
113 {
114 case kSOSCCCircleAbsent:
115 hadError = !SOSCCResetToOffering(error);
116 hadError &= enableDefaultViews();
117 break;
118 case kSOSCCNotInCircle:
119 hadError = !SOSCCRequestToJoinCircle(error);
120 hadError &= enableDefaultViews();
121 break;
122 default:
123 printerr(CFSTR("Request to join circle with bad status: %@ (%d)\n"), SOSCCGetStatusDescription(ccstatus), ccstatus);
124 break;
125 }
126 return hadError;
127 }
128
129 static bool setPassword(char *labelAndPassword, CFErrorRef *err)
130 {
131 char *last = NULL;
132 char *token0 = strtok_r(labelAndPassword, ":", &last);
133 char *token1 = strtok_r(NULL, "", &last);
134 CFStringRef label = token1 ? CFStringCreateWithCString(NULL, token0, kCFStringEncodingUTF8) : CFSTR("security command line tool");
135 char *password_token = token1 ? token1 : token0;
136 password_token = password_token ? password_token : "";
137 CFDataRef password = CFDataCreate(NULL, (const UInt8*) password_token, strlen(password_token));
138 bool returned = !SOSCCSetUserCredentials(label, password, err);
139 CFRelease(label);
140 CFRelease(password);
141 return returned;
142 }
143
144 static bool tryPassword(char *labelAndPassword, CFErrorRef *err)
145 {
146 char *last = NULL;
147 char *token0 = strtok_r(labelAndPassword, ":", &last);
148 char *token1 = strtok_r(NULL, "", &last);
149 CFStringRef label = token1 ? CFStringCreateWithCString(NULL, token0, kCFStringEncodingUTF8) : CFSTR("security command line tool");
150 char *password_token = token1 ? token1 : token0;
151 password_token = password_token ? password_token : "";
152 CFDataRef password = CFDataCreate(NULL, (const UInt8*) password_token, strlen(password_token));
153 bool returned = !SOSCCTryUserCredentials(label, password, err);
154 CFRelease(label);
155 CFRelease(password);
156 return returned;
157 }
158
159 /*
160 * Prompt user, call SOSCCTryUserCredentials.
161 * Does not support optional label syntax like -T/-P.
162 * Returns true on success.
163 */
164 static bool
165 promptAndTryPassword(CFErrorRef *error)
166 {
167 bool success = false;
168 char passbuf[1024];
169 CFDataRef password;
170
171 if (readpassphrase("iCloud password: ", passbuf, sizeof(passbuf), RPP_REQUIRE_TTY) != NULL) {
172 password = CFDataCreate(NULL, (const UInt8 *)passbuf, strlen(passbuf));
173 if (password != NULL) {
174 success = SOSCCTryUserCredentials(CFSTR("security command line tool"), password, error);
175 CFReleaseNull(password);
176 }
177 }
178
179 return success;
180 }
181
182 static bool syncAndWait(CFErrorRef *err)
183 {
184 __block CFTypeRef objects = NULL;
185
186 dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
187
188 const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
189 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
190 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
191
192 CloudKeychainReplyBlock replyBlock = ^ (CFDictionaryRef returnedValues, CFErrorRef error)
193 {
194 secinfo("sync", "SOSCloudKeychainSynchronizeAndWait returned: %@", returnedValues);
195 if (error)
196 secerror("SOSCloudKeychainSynchronizeAndWait returned error: %@", error);
197 objects = CFRetainSafe(returnedValues);
198
199 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", objects);
200 dispatch_semaphore_signal(waitSemaphore);
201 };
202
203 SOSCloudKeychainSynchronizeAndWait(generalq, replyBlock);
204
205 dispatch_semaphore_wait(waitSemaphore, finishTime);
206
207 (void)SOSCCDumpCircleKVSInformation(NULL);
208 fprintf(outFile, "\n");
209 return false;
210 }
211
212 static void dumpStringSet(CFStringRef label, CFSetRef s) {
213 if(!s || !label) return;
214
215 printmsg(CFSTR("%@: { "), label);
216 __block bool first = true;
217 CFSetForEach(s, ^(const void *p) {
218 CFStringRef fmt = CFSTR(", %@");
219 if(first) {
220 fmt = CFSTR("%@");
221 }
222 CFStringRef string = (CFStringRef) p;
223 printmsg(fmt, string);
224 first=false;
225 });
226 printmsg(CFSTR(" }\n"), NULL);
227 }
228
229 static bool dumpMyPeer(CFErrorRef *error) {
230 SOSPeerInfoRef myPeer = SOSCCCopyMyPeerInfo(error);
231
232 if (!myPeer) return false;
233
234 CFStringRef peerID = SOSPeerInfoGetPeerID(myPeer);
235 CFStringRef peerName = SOSPeerInfoGetPeerName(myPeer);
236 CFIndex peerVersion = SOSPeerInfoGetVersion(myPeer);
237 bool retirement = SOSPeerInfoIsRetirementTicket(myPeer);
238
239 printmsg(CFSTR("Peer Name: %@ PeerID: %@ Version: %d\n"), peerName, peerID, peerVersion);
240 if(retirement) {
241 CFDateRef retdate = SOSPeerInfoGetRetirementDate(myPeer);
242 printmsg(CFSTR("Retired: %@\n"), retdate);
243
244 }
245
246 if(peerVersion >= 2) {
247 CFMutableSetRef views = SOSPeerInfoV2DictionaryCopySet(myPeer, sViewsKey);
248 CFStringRef serialNumber = SOSPeerInfoV2DictionaryCopyString(myPeer, sSerialNumberKey);
249 CFBooleanRef preferIDS = SOSPeerInfoV2DictionaryCopyBoolean(myPeer, sPreferIDS);
250 CFBooleanRef preferIDSFragmentation = SOSPeerInfoV2DictionaryCopyBoolean(myPeer, sPreferIDSFragmentation);
251 CFBooleanRef preferIDSACKModel = SOSPeerInfoV2DictionaryCopyBoolean(myPeer, sPreferIDSACKModel);
252 CFStringRef transportType = SOSPeerInfoV2DictionaryCopyString(myPeer, sTransportType);
253 CFStringRef idsDeviceID = SOSPeerInfoV2DictionaryCopyString(myPeer, sDeviceID);
254
255 printmsg(CFSTR("Serial#: %@ PrefIDS#: %@ PrefFragmentation#: %@ PrefACK#: %@ transportType#: %@ idsDeviceID#: %@\n"),
256 serialNumber, preferIDS, preferIDSFragmentation, preferIDSACKModel, transportType, idsDeviceID);
257
258 printmsg(CFSTR("Serial#: %@\n"),
259 serialNumber);
260 dumpStringSet(CFSTR(" Views: "), views);
261
262
263 CFReleaseSafe(serialNumber);
264 CFReleaseSafe(preferIDS);
265 CFReleaseSafe(preferIDSFragmentation);
266 CFReleaseSafe(views);
267 CFReleaseSafe(transportType);
268 CFReleaseSafe(idsDeviceID);
269 }
270
271 bool ret = myPeer != NULL;
272 CFReleaseNull(myPeer);
273 return ret;
274 }
275
276 static bool setBag(char *itemName, CFErrorRef *err)
277 {
278 __block bool success = false;
279 __block CFErrorRef error = NULL;
280
281 CFStringRef random = SecPasswordCreateWithRandomDigits(10, NULL);
282
283 CFStringPerformWithUTF8CFData(random, ^(CFDataRef stringAsData) {
284 if (0 == strncasecmp(optarg, "single", 6) || 0 == strncasecmp(optarg, "all", 3)) {
285 bool includeV0 = (0 == strncasecmp(optarg, "all", 3));
286 printmsg(CFSTR("Setting iCSC single using entropy from string: %@\n"), random);
287 CFDataRef aks_bag = SecAKSCopyBackupBagWithSecret(CFDataGetLength(stringAsData), (uint8_t*)CFDataGetBytePtr(stringAsData), &error);
288
289 if (aks_bag) {
290 success = SOSCCRegisterSingleRecoverySecret(aks_bag, includeV0, &error);
291 if (!success) {
292 printmsg(CFSTR("Failed registering single secret %@"), error);
293 CFReleaseNull(aks_bag);
294 }
295 } else {
296 printmsg(CFSTR("Failed to create aks_bag: %@"), error);
297 }
298 CFReleaseNull(aks_bag);
299 } else if (0 == strncasecmp(optarg, "device", 6)) {
300 printmsg(CFSTR("Setting Device Secret using entropy from string: %@\n"), random);
301
302 SOSPeerInfoRef me = SOSCCCopyMyPeerWithNewDeviceRecoverySecret(stringAsData, &error);
303
304 success = me != NULL;
305
306 if (!success)
307 printmsg(CFSTR("Failed: %@\n"), err);
308 CFReleaseNull(me);
309 } else {
310 printmsg(CFSTR("Unrecognized argument to -b %s\n"), optarg);
311 }
312 });
313
314
315 return success;
316 }
317
318 static void prClientViewState(char *label, bool result) {
319 fprintf(outFile, "Sync Status for %s: %s\n", label, (result) ? "enabled": "not enabled");
320 }
321
322 static bool clientViewStatus(CFErrorRef *error) {
323 prClientViewState("KeychainV0", SOSCCIsIcloudKeychainSyncing());
324 prClientViewState("Safari", SOSCCIsSafariSyncing());
325 prClientViewState("AppleTV", SOSCCIsAppleTVSyncing());
326 prClientViewState("HomeKit", SOSCCIsHomeKitSyncing());
327 prClientViewState("Wifi", SOSCCIsWiFiSyncing());
328 prClientViewState("AlwaysOnNoInitialSync", SOSCCIsContinuityUnlockSyncing());
329 return false;
330 }
331
332
333 static bool dumpYetToSync(CFErrorRef *error) {
334 CFArrayRef yetToSyncViews = SOSCCCopyYetToSyncViewsList(error);
335
336 bool hadError = yetToSyncViews;
337
338 if (yetToSyncViews) {
339 __block CFStringRef separator = CFSTR("");
340
341 printmsg(CFSTR("Yet to sync views: ["), NULL);
342
343 CFArrayForEach(yetToSyncViews, ^(const void *value) {
344 if (isString(value)) {
345 printmsg(CFSTR("%@%@"), separator, value);
346
347 separator = CFSTR(", ");
348 }
349 });
350 printmsg(CFSTR("]\n"), NULL);
351 }
352
353 return !hadError;
354 }
355
356 #pragma mark -
357 #pragma mark --remove-peer
358
359 static void
360 add_matching_peerinfos(CFMutableArrayRef list, CFArrayRef spids, CFArrayRef (*copy_peer_func)(CFErrorRef *))
361 {
362 CFErrorRef error;
363 CFArrayRef peers;
364 SOSPeerInfoRef pi;
365 CFStringRef spid;
366 CFIndex i, j;
367
368 peers = copy_peer_func(&error);
369 if (peers != NULL) {
370 for (i = 0; i < CFArrayGetCount(peers); i++) {
371 pi = (SOSPeerInfoRef)CFArrayGetValueAtIndex(peers, i);
372 for (j = 0; j < CFArrayGetCount(spids); j++) {
373 spid = (CFStringRef)CFArrayGetValueAtIndex(spids, j);
374 if (CFStringGetLength(spid) < 8) {
375 continue;
376 }
377 if (CFStringHasPrefix(SOSPeerInfoGetPeerID(pi), spid)) {
378 CFArrayAppendValue(list, pi);
379 }
380 }
381 }
382 CFRelease(peers);
383 } else {
384 // unlikely
385 CFShow(error);
386 CFRelease(error);
387 }
388 }
389
390 static CFArrayRef
391 copy_peerinfos(CFArrayRef spids)
392 {
393 CFMutableArrayRef matches;
394
395 matches = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
396 add_matching_peerinfos(matches, spids, SOSCCCopyValidPeerPeerInfo);
397 add_matching_peerinfos(matches, spids, SOSCCCopyNotValidPeerPeerInfo);
398 add_matching_peerinfos(matches, spids, SOSCCCopyRetirementPeerInfo);
399
400 return matches;
401 }
402
403 static bool
404 doRemovePeers(CFArrayRef peerids, CFErrorRef *error)
405 {
406 bool success = false;
407 CFArrayRef peers = NULL;
408 CFErrorRef localError = NULL;
409 CFIndex i;
410 char buf[16];
411
412 peers = copy_peerinfos(peerids);
413 if (peers == NULL || CFArrayGetCount(peers) == 0) {
414 fprintf(stdout, "No matching peers to remove.\n");
415 success = true;
416 goto done;
417 }
418
419 fprintf(stdout, "Matched the following devices:\n");
420 for (i = 0; i < CFArrayGetCount(peers); i++) {
421 // Ugly.
422 CFShow(CFArrayGetValueAtIndex(peers, i));
423 }
424
425 if (readpassphrase("Confirm removal (y/N): ", buf, sizeof(buf), RPP_ECHO_ON | RPP_FORCEUPPER) == NULL) {
426 goto done;
427 }
428
429 if (buf[0] != 'Y') {
430 success = true;
431 goto done;
432 }
433
434 success = SOSCCRemovePeersFromCircle(peers, &localError);
435 if (!success && isSOSErrorCoded(localError, kSOSErrorPrivateKeyAbsent)) {
436 CFReleaseNull(localError);
437
438 success = promptAndTryPassword(&localError);
439 if (success) {
440 success = SOSCCRemovePeersFromCircle(peers, &localError);
441 }
442 }
443
444 done:
445 CFReleaseNull(peers);
446
447 if (!success && error != NULL) {
448 *error = localError;
449 } else {
450 CFReleaseNull(localError);
451 }
452
453 return success;
454 }
455
456 #pragma mark -
457
458 // enable, disable, accept, reject, status, Reset, Clear
459 int
460 keychain_sync(int argc, char * const *argv)
461 {
462 /*
463 "Keychain Syncing"
464 " -d disable"
465 " -e enable (join/create circle)"
466 " -i info (current status)"
467 " -m dump my peer"
468 "
469 "Account/Circle Management"
470 " -a accept all applicants"
471 " -l [reason] sign out of circle + set custom departure reason"
472 " -q sign out of circle"
473 " -r reject all applicants"
474 " -E ensure fresh parameters"
475 " -b device|all|single Register a backup bag - THIS RESETS BACKUPS!\n"
476 " -A Apply to a ring\n"
477 " -B Withdrawl from a ring\n"
478 " -G Enable Ring\n"
479 " -F Ring Status\n"
480 " -I Dump Ring Information\n"
481
482 " -N (re-)set to new account (USE WITH CARE: device will not leave circle before resetting account!)"
483 " -O reset to offering"
484 " -R reset circle"
485 " -X [limit] best effort bail from circle in limit seconds"
486 " -o list view unaware peers in circle"
487 " -0 boot view unaware peers from circle"
488 " -1 grab account state from the keychain"
489 " -2 delete account state from the keychain"
490 " -3 grab engine state from the keychain"
491 " -4 delete engine state from the keychain"
492 " -5 cleanup old KVS keys in KVS"
493 " -6 [test]populate KVS with garbage KVS keys
494 "
495 "Password"
496 " -P [label:]password set password (optionally for a given label) for sync"
497 " -T [label:]password try password (optionally for a given label) for sync"
498 "
499 "KVS"
500 " -k pend all registered kvs keys"
501 " -C clear all values from KVS"
502 " -D [itemName] dump contents of KVS"
503 " -W sync and dump"
504 "
505 "Misc"
506 " -v [enable|disable|query:viewname] enable, disable, or query my PeerInfo's view set"
507 " viewnames are: keychain|masterkey|iclouddrive|photos|cloudkit|escrow|fde|maildrop|icloudbackup|notes|imessage|appletv|homekit|"
508 " wifi|passwords|creditcards|icloudidentity|othersyncable"
509 " -L list all known view and their status"
510 " -U purge private key material cache\n"
511 " -V Report View Sync Status on all known clients.\n"
512 " -H Set escrow record.\n"
513 " -J Get the escrow record.\n"
514 " -M Check peer availability.\n"
515 */
516 enum {
517 SYNC_REMOVE_PEER,
518 };
519 int action = -1;
520 const struct option longopts[] = {
521 { "remove-peer", required_argument, &action, SYNC_REMOVE_PEER, },
522 { NULL, 0, NULL, 0, },
523 };
524 int ch, result = 0;
525 CFErrorRef error = NULL;
526 bool hadError = false;
527 CFMutableArrayRef peers2remove = NULL;
528 SOSLogSetOutputTo(NULL, NULL);
529
530 while ((ch = getopt_long(argc, argv, "ab:deg:hikl:mopq:rSv:w:x:zA:B:MNJCDEF:HG:ILOP:RT:UWX:VY0123456", longopts, NULL)) != -1)
531 switch (ch) {
532 case 'l':
533 {
534 fprintf(outFile, "Signing out of circle\n");
535 hadError = !SOSCCSignedOut(true, &error);
536 if (!hadError) {
537 errno = 0;
538 int reason = (int) strtoul(optarg, NULL, 10);
539 if (errno != 0 ||
540 reason < kSOSDepartureReasonError ||
541 reason >= kSOSNumDepartureReasons) {
542 fprintf(errFile, "Invalid custom departure reason %s\n", optarg);
543 } else {
544 fprintf(outFile, "Setting custom departure reason %d\n", reason);
545 hadError = !SOSCCSetLastDepartureReason(reason, &error);
546 notify_post(kSOSCCCircleChangedNotification);
547 }
548 }
549 break;
550 }
551
552 case 'q':
553 {
554 fprintf(outFile, "Signing out of circle\n");
555 bool signOutImmediately = false;
556 if (strcasecmp(optarg, "true") == 0) {
557 signOutImmediately = true;
558 } else if (strcasecmp(optarg, "false") == 0) {
559 signOutImmediately = false;
560 } else {
561 fprintf(outFile, "Please provide a \"true\" or \"false\" whether you'd like to leave the circle immediately\n");
562 }
563 hadError = !SOSCCSignedOut(signOutImmediately, &error);
564 notify_post(kSOSCCCircleChangedNotification);
565 break;
566 }
567 case 'e':
568 fprintf(outFile, "Turning ON keychain syncing\n");
569 hadError = requestToJoinCircle(&error);
570 break;
571
572 case 'd':
573 fprintf(outFile, "Turning OFF keychain syncing\n");
574 hadError = !SOSCCRemoveThisDeviceFromCircle(&error);
575 break;
576
577 case 'a':
578 {
579 CFArrayRef applicants = SOSCCCopyApplicantPeerInfo(NULL);
580 if (applicants) {
581 hadError = !SOSCCAcceptApplicants(applicants, &error);
582 CFRelease(applicants);
583 } else {
584 fprintf(errFile, "No applicants to accept\n");
585 }
586 break;
587 }
588
589 case 'r':
590 {
591 CFArrayRef applicants = SOSCCCopyApplicantPeerInfo(NULL);
592 if (applicants) {
593 hadError = !SOSCCRejectApplicants(applicants, &error);
594 CFRelease(applicants);
595 } else {
596 fprintf(errFile, "No applicants to reject\n");
597 }
598 break;
599 }
600
601 case 'i':
602 SOSCCDumpCircleInformation();
603 SOSCCDumpEngineInformation();
604 break;
605
606 case 'k':
607 notify_post("com.apple.security.cloudkeychain.forceupdate");
608 break;
609
610 case 'o':
611 {
612 SOSCCDumpViewUnwarePeers();
613 break;
614 }
615
616 case '0':
617 {
618 CFArrayRef unawares = SOSCCCopyViewUnawarePeerInfo(&error);
619 if (unawares) {
620 hadError = !SOSCCRemovePeersFromCircle(unawares, &error);
621 } else {
622 hadError = true;
623 }
624 CFReleaseNull(unawares);
625 break;
626 }
627 case '1':
628 {
629 CFDataRef accountState = SOSCCCopyAccountState(&error);
630 if (accountState) {
631 printmsg(CFSTR(" %@\n"), CFDataCopyHexString(accountState));
632 } else {
633 hadError = true;
634 }
635 CFReleaseNull(accountState);
636 break;
637 }
638 case '2':
639 {
640 bool status = SOSCCDeleteAccountState(&error);
641 if (status) {
642 printmsg(CFSTR("Deleted account from the keychain %d\n"), status);
643 } else {
644 hadError = true;
645 }
646 break;
647 }
648 case '3':
649 {
650 CFDataRef engineState = SOSCCCopyEngineData(&error);
651 if (engineState) {
652 printmsg(CFSTR(" %@\n"), CFDataCopyHexString(engineState));
653 } else {
654 hadError = true;
655 }
656 CFReleaseNull(engineState);
657 break;
658 }
659 case '4':
660 {
661 bool status = SOSCCDeleteEngineState(&error);
662 if (status) {
663 printmsg(CFSTR("Deleted engine-state from the keychain %d\n"), status);
664 } else {
665 hadError = true;
666 }
667 break;
668 }
669 case '5' :
670 {
671 bool result = SOSCCCleanupKVSKeys(&error);
672 if(result)
673 {
674 printmsg(CFSTR("Got all the keys from KVS %d\n"), result);
675 }else {
676 hadError = true;
677 }
678 break;
679 }
680 case '6' :
681 {
682 bool result = SOSCCTestPopulateKVSWithBadKeys(&error);
683 if(result)
684 {
685 printmsg(CFSTR("Populated KVS with garbage %d\n"), result);
686 }else {
687 hadError = true;
688 }
689 break;
690 }
691 case 'E':
692 {
693 fprintf(outFile, "Ensuring Fresh Parameters\n");
694 bool result = SOSCCRequestEnsureFreshParameters(&error);
695 if (error) {
696 hadError = true;
697 break;
698 }
699 if (result) {
700 fprintf(outFile, "Refreshed Parameters Ensured!\n");
701 } else {
702 fprintf(outFile, "Problem trying to ensure fresh parameters\n");
703 }
704 break;
705 }
706 case 'A':
707 {
708 fprintf(outFile, "Applying to Ring\n");
709 CFStringRef ringName = CFStringCreateWithCString(kCFAllocatorDefault, (char *)optarg, kCFStringEncodingUTF8);
710 hadError = SOSCCApplyToARing(ringName, &error);
711 CFReleaseNull(ringName);
712 break;
713 }
714 case 'B':
715 {
716 fprintf(outFile, "Withdrawing from Ring\n");
717 CFStringRef ringName = CFStringCreateWithCString(kCFAllocatorDefault, (char *)optarg, kCFStringEncodingUTF8);
718 hadError = SOSCCWithdrawlFromARing(ringName, &error);
719 CFReleaseNull(ringName);
720 break;
721 }
722 case 'F':
723 {
724 fprintf(outFile, "Status of this device in the Ring\n");
725 CFStringRef ringName = CFStringCreateWithCString(kCFAllocatorDefault, (char *)optarg, kCFStringEncodingUTF8);
726 hadError = SOSCCRingStatus(ringName, &error);
727 CFReleaseNull(ringName);
728 break;
729 }
730 case 'G':
731 {
732 fprintf(outFile, "Enabling Ring\n");
733 CFStringRef ringName = CFStringCreateWithCString(kCFAllocatorDefault, (char *)optarg, kCFStringEncodingUTF8);
734 hadError = SOSCCEnableRing(ringName, &error);
735 CFReleaseNull(ringName);
736 break;
737 }
738 case 'H':
739 {
740 fprintf(outFile, "Setting random escrow record\n");
741 bool success = SOSCCSetEscrowRecord(CFSTR("label"), 8, &error);
742 if(success)
743 hadError = false;
744 else
745 hadError = true;
746 break;
747 }
748 case 'J':
749 {
750 CFDictionaryRef attempts = SOSCCCopyEscrowRecord(&error);
751 if(attempts){
752 CFDictionaryForEach(attempts, ^(const void *key, const void *value) {
753 if(isString(key)){
754 char *keyString = CFStringToCString(key);
755 fprintf(outFile, "%s:\n", keyString);
756 free(keyString);
757 }
758 if(isDictionary(value)){
759 CFDictionaryForEach(value, ^(const void *key, const void *value) {
760 if(isString(key)){
761 char *keyString = CFStringToCString(key);
762 fprintf(outFile, "%s: ", keyString);
763 free(keyString);
764 }
765 if(isString(value)){
766 char *time = CFStringToCString(value);
767 fprintf(outFile, "timestamp: %s\n", time);
768 free(time);
769 }
770 else if(isNumber(value)){
771 uint64_t tries;
772 CFNumberGetValue(value, kCFNumberLongLongType, &tries);
773 fprintf(outFile, "date: %llu\n", tries);
774 }
775 });
776 }
777
778 });
779 }
780 CFReleaseNull(attempts);
781 hadError = false;
782 break;
783 }
784 case 'I':
785 {
786 fprintf(outFile, "Printing all the rings\n");
787 CFStringRef ringdescription = SOSCCGetAllTheRings(&error);
788 if(!ringdescription)
789 hadError = true;
790 else
791 fprintf(outFile, "Rings: %s", CFStringToCString(ringdescription));
792
793 break;
794 }
795
796 case 'N':
797 hadError = !SOSCCAccountSetToNew(&error);
798 if (!hadError)
799 notify_post(kSOSCCCircleChangedNotification);
800 break;
801
802 case 'R':
803 hadError = !SOSCCResetToEmpty(&error);
804 break;
805
806 case 'O':
807 hadError = !SOSCCResetToOffering(&error);
808 break;
809
810 case 'm':
811 hadError = !dumpMyPeer(&error);
812 break;
813
814 case 'C':
815 hadError = clearAllKVS(&error);
816 break;
817
818 case 'P':
819 hadError = setPassword(optarg, &error);
820 break;
821
822 case 'T':
823 hadError = tryPassword(optarg, &error);
824 break;
825
826 case 'X':
827 {
828 uint64_t limit = strtoul(optarg, NULL, 10);
829 hadError = !SOSCCBailFromCircle_BestEffort(limit, &error);
830 break;
831 }
832
833 case 'U':
834 hadError = !SOSCCPurgeUserCredentials(&error);
835 break;
836
837 case 'D':
838 (void)SOSCCDumpCircleKVSInformation(optarg);
839 break;
840
841 case 'W':
842 hadError = syncAndWait(&error);
843 break;
844
845 case 'v':
846 hadError = !viewcmd(optarg, &error);
847 break;
848
849 case 'V':
850 hadError = clientViewStatus(&error);
851 break;
852 case 'L':
853 hadError = !listviewcmd(&error);
854 break;
855
856 case 'b':
857 hadError = setBag(optarg, &error);
858 break;
859
860 case 'Y':
861 hadError = dumpYetToSync(&error);
862 break;
863 case 0:
864 switch (action) {
865 case SYNC_REMOVE_PEER: {
866 CFStringRef optstr;
867 optstr = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
868 if (peers2remove == NULL) {
869 peers2remove = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
870 }
871 CFArrayAppendValue(peers2remove, optstr);
872 CFRelease(optstr);
873 break;
874 }
875 default:
876 return SHOW_USAGE_MESSAGE;
877 }
878 break;
879 case '?':
880 default:
881 return SHOW_USAGE_MESSAGE;
882 }
883
884 if (peers2remove != NULL) {
885 hadError = !doRemovePeers(peers2remove, &error);
886 CFRelease(peers2remove);
887 }
888
889 if (hadError) {
890 printerr(CFSTR("Error: %@\n"), error);
891 }
892
893 return result;
894 }