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