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