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