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