2 * Copyright (c) 2003-2007,2009-2010,2013-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
32 #include <Security/SecItem.h>
34 #include <CoreFoundation/CFNumber.h>
35 #include <CoreFoundation/CFString.h>
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>
49 #include <utilities/SecCFWrappers.h>
50 #include <utilities/debugging.h>
52 #include <SecurityTool/readline.h>
55 #include "SOSCommands.h"
57 #include <Security/SecPasswordGenerate.h>
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
65 static void _printcfmsg(FILE *ff
, CFDictionaryRef formatOptions
, CFStringRef format
, ...)
68 va_start(args
, format
);
69 CFStringRef message
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, formatOptions
, format
, args
);
71 CFStringPerformWithCString(message
, ^(const char *utf8String
) { fprintf(ff
, utf8String
, ""); });
75 static bool clearAllKVS(CFErrorRef
*error
)
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
);
83 SOSCloudKeychainClearAll(processQueue
, ^(CFDictionaryRef returnedValues
, CFErrorRef cerror
)
85 result
= (cerror
!= NULL
);
86 dispatch_semaphore_signal(waitSemaphore
);
89 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
90 dispatch_release(waitSemaphore
);
95 static const char *getSOSCCStatusDescription(SOSCCStatus ccstatus
)
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";
106 return "<unknown ccstatus>";
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
);
118 printmsg(CFSTR("%s count: %ld\n"), label
, (long)CFArrayGetCount(ppi
));
119 CFArrayForEach(ppi
, ^(const void *value
) {
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
);
134 CFDictionaryRef v2Dictionary
= peer
->v2Dictionary
;
135 transportType
= CFDictionaryGetValue(v2Dictionary
, sTransportType
);
136 deviceID
= CFDictionaryGetValue(v2Dictionary
, sDeviceID
);
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>" : " ";
146 snprintf(buf
, 160, "%s %s: %-16s %-16s %-16s %-16s", me
, label
, pname
, dname
, tname
, iname
);
150 CFStringRef pid
= SOSPeerInfoGetPeerID(peer
);
151 CFIndex vers
= SOSPeerInfoGetVersion(peer
);
152 printmsg(CFSTR("%s %@ V%d OS:%s\n"), buf
, pid
, vers
, osname
);
156 printmsg(CFSTR("No %s, error: %@\n"), label
, error
);
159 CFReleaseNull(error
);
162 static void dumpCircleInfo()
164 CFErrorRef error
= NULL
;
165 CFArrayRef generations
= NULL
;
166 CFArrayRef confirmedDigests
= NULL
;
167 bool is_user_public_trusted
= false;
168 __block
int count
= 0;
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
);
175 printmsg(CFSTR("ccstatus: %s (%d)\n"), getSOSCCStatusDescription(ccstatus
), ccstatus
, error
);
177 is_user_public_trusted
= SOSCCValidateUserPublic(&error
);
178 if(is_user_public_trusted
)
179 printmsg(CFSTR("Account user public is trusted%@"),CFSTR("\n"));
181 printmsg(CFSTR("Account user public is not trusted error:(%@)\n"), error
);
182 CFReleaseNull(error
);
184 generations
= SOSCCCopyGenerationPeerInfo(&error
);
186 CFArrayForEach(generations
, ^(const void *value
) {
189 printmsg(CFSTR("Circle name: %@, "),value
);
192 CFStringRef genDesc
= SOSGenerationCountCopyDescription(value
);
193 printmsg(CFSTR("Generation Count: %@"), genDesc
);
194 CFReleaseNull(genDesc
);
196 printmsg(CFSTR("%s\n"), "");
199 printmsg(CFSTR("No generation count: %@\n"), error
);
201 CFReleaseNull(generations
);
202 CFReleaseNull(error
);
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
); });
210 confirmedDigests
= SOSCCCopyEngineState(&error
);
214 CFArrayForEach(confirmedDigests
, ^(const void *value
) {
217 printmsg(CFSTR("%@"), value
);
220 CFStringRef hexDigest
= CFDataCopyHexString(value
);
221 printmsg(CFSTR(" %@\n"), hexDigest
);
222 CFReleaseSafe(hexDigest
);
227 printmsg(CFSTR("No engine peers: %@\n"), error
);
228 CFReleaseNull(confirmedDigests
);
231 static bool enableDefaultViews()
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
);
241 result
= SOSCCViewSet(viewsToEnable
, viewsToDisable
);
242 CFRelease(viewsToEnable
);
243 CFRelease(viewsToDisable
);
247 static bool requestToJoinCircle(CFErrorRef
*error
)
249 // Set the visual state of switch based on membership in circle
250 bool hadError
= false;
251 SOSCCStatus ccstatus
= SOSCCThisDeviceIsInCircle(error
);
255 case kSOSCCCircleAbsent
:
256 hadError
= !SOSCCResetToOffering(error
);
257 hadError
&= enableDefaultViews();
259 case kSOSCCNotInCircle
:
260 hadError
= !SOSCCRequestToJoinCircle(error
);
261 hadError
&= enableDefaultViews();
264 printerr(CFSTR("Request to join circle with bad status: %@ (%d)\n"), SOSCCGetStatusDescription(ccstatus
), ccstatus
);
270 static bool setPassword(char *labelAndPassword
, CFErrorRef
*err
)
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
);
285 static bool tryPassword(char *labelAndPassword
, CFErrorRef
*err
)
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
);
300 static CFTypeRef
getObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
302 __block CFTypeRef object
= NULL
;
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
);
308 dispatch_group_enter(dgroup
);
310 CloudKeychainReplyBlock replyBlock
=
311 ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
313 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues
);
314 object
= returnedValues
;
319 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error
);
320 // CFRelease(*error);
322 dispatch_group_leave(dgroup
);
323 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object
);
324 dispatch_semaphore_signal(waitSemaphore
);
328 SOSCloudKeychainGetAllObjectsFromCloud(processQueue
, replyBlock
);
330 SOSCloudKeychainGetObjectsFromCloud(keysToGet
, processQueue
, replyBlock
);
332 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
333 dispatch_release(waitSemaphore
);
334 if (object
&& (CFGetTypeID(object
) == CFNullGetTypeID())) // return a NULL instead of a CFNull
339 secerror("returned: %@", object
);
343 static CFStringRef
printFullDataString(CFDataRef data
){
344 __block CFStringRef fullData
= NULL
;
346 BufferPerformWithHexString(CFDataGetBytePtr(data
), CFDataGetLength(data
), ^(CFStringRef dataHex
) {
347 fullData
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@"), dataHex
);
353 static void displayLastKeyParameters(CFTypeRef key
, CFTypeRef value
)
355 CFDataRef valueAsData
= asData(value
, NULL
);
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
);
364 printmsg(CFSTR("%@: %@\n"), key
, printFullDataString(value
));
365 CFReleaseNull(dateString
);
366 CFReleaseNull(keyParameterData
);
367 CFReleaseNull(dateData
);
368 CFReleaseNull(keyParameterDescription
);
371 printmsg(CFSTR("%@: %@\n"), key
, value
);
375 static void displayKeyParameters(CFTypeRef key
, CFTypeRef value
)
378 CFStringRef keyParameterDescription
= UserParametersDescription((CFDataRef
)value
);
380 if(keyParameterDescription
)
381 printmsg(CFSTR("%@: %@\n"), key
, keyParameterDescription
);
383 printmsg(CFSTR("%@: %@\n"), key
, value
);
385 CFReleaseNull(keyParameterDescription
);
388 printmsg(CFSTR("%@: %@\n"), key
, value
);
392 static void displayLastCircle(CFTypeRef key
, CFTypeRef value
)
394 CFDataRef valueAsData
= asData(value
, NULL
);
396 CFErrorRef localError
= NULL
;
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
);
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
);
413 printmsg(CFSTR("%@: %@\n"), key
, printFullDataString(circleData
));
415 CFReleaseNull(dateString
);
416 CFReleaseNull(circleData
);
417 CFReleaseSafe(circle
);
418 CFReleaseNull(dateData
);
419 CFReleaseNull(localError
);
422 printmsg(CFSTR("%@: %@\n"), key
, value
);
426 static void displayCircle(CFTypeRef key
, CFTypeRef value
)
428 CFDataRef circleData
= (CFDataRef
)value
;
430 CFErrorRef localError
= NULL
;
431 if (isData(circleData
))
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
);
444 printmsg(CFSTR("%@: %@\n"), key
, value
);
447 static void displayMessage(CFTypeRef key
, CFTypeRef value
)
449 CFDataRef message
= (CFDataRef
)value
;
451 const char* messageType
= SecOTRPacketTypeString(message
);
452 printmsg(CFSTR("%@: %s: %ld\n"), key
, messageType
, CFDataGetLength(message
));
455 printmsg(CFSTR("%@: %@\n"), key
, value
);
458 static void printEverything(CFTypeRef objects
)
460 CFDictionaryForEach(objects
, ^(const void *key
, const void *value
) {
463 printmsg(CFSTR("%@: %@\n\n"), key
, printFullDataString(value
));
466 printmsg(CFSTR("%@: %@\n"), key
, value
);
471 static void decodeForKeyType(CFTypeRef key
, CFTypeRef value
, SOSKVSKeyType type
){
474 displayCircle(key
, value
);
478 displayMessage(key
, value
);
481 displayKeyParameters(key
, value
);
483 case kLastKeyParameterKey
:
484 displayLastKeyParameters(key
, value
);
487 displayLastCircle(key
, value
);
489 case kInitialSyncKey
:
490 case kAccountChangedKey
:
495 printmsg(CFSTR("%@: %@\n"), key
, value
);
500 static void decodeAllTheValues(CFTypeRef objects
){
501 SOSKVSKeyType keyType
= 0;
502 __block
bool didPrint
= false;
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
);
512 printmsg(CFSTR("%@\n"), CFSTR(""));
516 static bool dumpKVS(char *itemName
, CFErrorRef
*err
)
518 CFArrayRef keysToGet
= NULL
;
521 CFStringRef itemStr
= CFStringCreateWithCString(kCFAllocatorDefault
, itemName
, kCFStringEncodingUTF8
);
522 printf("Retrieving %s from KVS\n", itemName
);
523 keysToGet
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, itemStr
, NULL
);
524 CFReleaseSafe(itemStr
);
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
);
532 printf("All keys and values straight from KVS\n");
533 printEverything(objects
);
534 printf("\nAll values in decoded form...\n");
535 decodeAllTheValues(objects
);
541 static bool syncAndWait(char *itemName
, CFErrorRef
*err
)
543 CFArrayRef keysToGet
= NULL
;
544 __block CFTypeRef objects
= NULL
;
547 fprintf(stderr
, "No item keys supplied\n");
551 CFStringRef itemStr
= CFStringCreateWithCString(kCFAllocatorDefault
, itemName
, kCFStringEncodingUTF8
);
552 printf("Retrieving %s from KVS\n", itemName
);
553 keysToGet
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, itemStr
, NULL
);
554 CFReleaseSafe(itemStr
);
556 dispatch_queue_t generalq
= dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL
);
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
);
562 CloudKeychainReplyBlock replyBlock
= ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
564 secinfo("sync", "SOSCloudKeychainSynchronizeAndWait returned: %@", returnedValues
);
566 secerror("SOSCloudKeychainSynchronizeAndWait returned error: %@", error
);
567 objects
= returnedValues
;
570 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", objects
);
571 dispatch_semaphore_signal(waitSemaphore
);
574 SOSCloudKeychainSynchronizeAndWait(keysToGet
, generalq
, replyBlock
);
576 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
577 dispatch_release(waitSemaphore
);
579 CFReleaseSafe(keysToGet
);
587 const CFStringRef
*viewspec
;
590 "keychain", &kSOSViewKeychainV0
592 "masterkey", &kSOSViewPCSMasterKey
,
594 "iclouddrive", &kSOSViewPCSiCloudDrive
,
596 "photos", &kSOSViewPCSPhotos
,
598 "escrow", &kSOSViewPCSEscrow
,
600 "fde", &kSOSViewPCSFDE
,
602 "maildrop", &kSOSViewPCSMailDrop
,
604 "icloudbackup", &kSOSViewPCSiCloudBackup
,
606 "notes", &kSOSViewPCSNotes
,
608 "imessage", &kSOSViewPCSiMessage
,
610 "feldspar", &kSOSViewPCSFeldspar
,
612 "appletv", &kSOSViewAppleTV
,
614 "homekit", &kSOSViewHomeKit
,
616 "wifi", &kSOSViewWiFi
,
618 "passwords", &kSOSViewAutofillPasswords
,
620 "creditcards", &kSOSViewSafariCreditCards
,
622 "icloudidentity", &kSOSViewiCloudIdentity
,
624 "othersyncable", &kSOSViewOtherSyncable
,
628 static CFStringRef
convertStringToView(char *viewname
) {
631 for (n
= 0; n
< sizeof(string2View
)/sizeof(string2View
[0]); n
++) {
632 if (strcmp(string2View
[n
].name
, viewname
) == 0)
633 return *string2View
[n
].viewspec
;
636 // Leak this, since it's a getter.
637 return CFStringCreateWithCString(kCFAllocatorDefault
, viewname
, kCFStringEncodingUTF8
);
640 static CFStringRef
convertViewReturnCodeToString(SOSViewActionCode ac
) {
641 CFStringRef retval
= NULL
;
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;
657 static bool viewcmd(char *itemName
, CFErrorRef
*err
) {
658 char *cmd
, *viewname
;
659 SOSViewActionCode ac
= kSOSCCViewQuery
;
660 CFStringRef viewspec
;
662 viewname
= strchr(itemName
, ':');
663 if(viewname
== NULL
) return false;
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
;
678 if(strchr(viewname
, ',') == NULL
) { // original single value version
679 viewspec
= convertStringToView(viewname
);
680 if(!viewspec
) return false;
682 SOSViewResultCode rc
= SOSCCView(viewspec
, ac
, err
);
683 CFStringRef resultString
= convertViewReturnCodeToString(rc
);
685 printmsg(CFSTR("View Result: %@ : %@\n"), resultString
, viewspec
);
689 if(ac
== kSOSCCViewQuery
) return false;
691 // new multi-view version
692 char *viewlist
= strdup(viewname
);
694 char *tofree
= viewlist
;
695 CFMutableSetRef viewSet
= CFSetCreateMutable(NULL
, 0, &kCFCopyStringSetCallBacks
);
697 while ((token
= strsep(&viewlist
, ",")) != NULL
) {
698 CFStringRef resultString
= convertStringToView(token
);
699 CFSetAddValue(viewSet
, resultString
);
702 printmsg(CFSTR("viewSet provided is %@\n"), viewSet
);
707 if(ac
== kSOSCCViewEnable
) retcode
= SOSCCViewSet(viewSet
, NULL
);
708 else retcode
= SOSCCViewSet(NULL
, viewSet
);
710 printf("SOSCCViewSet returned %s\n", (retcode
)? "true": "false");
715 static bool listviewcmd(CFErrorRef
*err
) {
718 for (n
= 0; n
< sizeof(string2View
)/sizeof(string2View
[0]); n
++) {
719 CFStringRef viewspec
= *string2View
[n
].viewspec
;
721 SOSViewResultCode rc
= SOSCCView(viewspec
, kSOSCCViewQuery
, err
);
722 CFStringRef resultString
= convertViewReturnCodeToString(rc
);
724 printmsg(CFSTR("View Result: %@ : %@\n"), resultString
, viewspec
);
730 static CFStringRef
convertStringToProperty(char *propertyname
) {
731 CFStringRef propertyspec
= NULL
;
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
;
746 static CFStringRef
convertPropertyReturnCodeToString(SOSSecurityPropertyResultCode ac
) {
747 CFStringRef retval
= NULL
;
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;
764 static bool SecPropertycmd(char *itemName
, CFErrorRef
*err
) {
765 char *cmd
, *propertyname
;
766 SOSSecurityPropertyActionCode ac
= kSOSCCSecurityPropertyQuery
;
767 CFStringRef propertyspec
;
769 propertyname
= strchr(itemName
, ':');
770 if(propertyname
== NULL
) return false;
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
;
785 propertyspec
= convertStringToProperty(propertyname
);
786 if(!propertyspec
) return false;
788 SOSSecurityPropertyResultCode rc
= SOSCCSecurityProperty(propertyspec
, ac
, err
);
789 CFStringRef resultString
= convertPropertyReturnCodeToString(rc
);
791 printmsg(CFSTR("Property Result: %@ : %@\n"), resultString
, propertyspec
);
796 static void dumpStringSet(CFStringRef label
, CFSetRef s
) {
797 if(!s
|| !label
) return;
799 printmsg(CFSTR("%@: { "), label
);
800 __block
bool first
= true;
801 CFSetForEach(s
, ^(const void *p
) {
802 CFStringRef fmt
= CFSTR(", %@");
806 CFStringRef string
= (CFStringRef
) p
;
807 printmsg(fmt
, string
);
810 printmsg(CFSTR(" }\n"), NULL
);
813 static bool dumpMyPeer(CFErrorRef
*error
) {
814 SOSPeerInfoRef myPeer
= SOSCCCopyMyPeerInfo(error
);
816 if (!myPeer
) return false;
818 CFStringRef peerID
= SOSPeerInfoGetPeerID(myPeer
);
819 CFStringRef peerName
= SOSPeerInfoGetPeerName(myPeer
);
820 CFIndex peerVersion
= SOSPeerInfoGetVersion(myPeer
);
821 bool retirement
= SOSPeerInfoIsRetirementTicket(myPeer
);
823 printmsg(CFSTR("Peer Name: %@ PeerID: %@ Version: %d\n"), peerName
, peerID
, peerVersion
);
825 CFDateRef retdate
= SOSPeerInfoGetRetirementDate(myPeer
);
826 printmsg(CFSTR("Retired: %@\n"), retdate
);
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
);
838 printmsg(CFSTR("Serial#: %@ PrefIDS#: %@ transportType#: %@ idsDeviceID#: %@\n"),
839 serialNumber
, preferIDS
, transportType
, idsDeviceID
);
840 dumpStringSet(CFSTR(" Views: "), views
);
841 dumpStringSet(CFSTR("SecurityProperties: "), properties
);
843 CFReleaseSafe(serialNumber
);
844 CFReleaseSafe(preferIDS
);
845 CFReleaseSafe(views
);
846 CFReleaseSafe(transportType
);
847 CFReleaseSafe(idsDeviceID
);
848 CFReleaseSafe(properties
);
852 return myPeer
!= NULL
;
855 static bool setBag(char *itemName
, CFErrorRef
*err
)
857 __block
bool success
= false;
858 __block CFErrorRef error
= NULL
;
860 CFStringRef random
= SecPasswordCreateWithRandomDigits(10, NULL
);
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
);
869 success
= SOSCCRegisterSingleRecoverySecret(aks_bag
, includeV0
, &error
);
871 printmsg(CFSTR("Failed registering single secret %@"), error
);
872 CFReleaseNull(aks_bag
);
875 printmsg(CFSTR("Failed to create aks_bag: %@"), error
);
877 CFReleaseNull(aks_bag
);
878 } else if (0 == strncasecmp(optarg
, "device", 6)) {
879 printmsg(CFSTR("Setting Device Secret using entropy from string: %@\n"), random
);
881 SOSPeerInfoRef me
= SOSCCCopyMyPeerWithNewDeviceRecoverySecret(stringAsData
, &error
);
883 success
= me
!= NULL
;
886 printmsg(CFSTR("Failed: %@\n"), err
);
889 printmsg(CFSTR("Unrecognized argument to -b %s\n"), optarg
);
897 static void prClientViewState(char *label
, bool result
) {
898 printf("Sync Status for %s: %s\n", label
, (result
) ? "enabled": "not enabled");
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());
911 static bool dumpYetToSync(CFErrorRef
*error
) {
912 CFArrayRef yetToSyncViews
= SOSCCCopyYetToSyncViewsList(error
);
914 bool hadError
= yetToSyncViews
;
916 if (yetToSyncViews
) {
917 __block CFStringRef separator
= CFSTR("");
919 printmsg(CFSTR("Yet to sync views: ["), NULL
);
921 CFArrayForEach(yetToSyncViews
, ^(const void *value
) {
922 if (isString(value
)) {
923 printmsg(CFSTR("%@%@"), separator
, value
);
925 separator
= CFSTR(", ");
928 printmsg(CFSTR("]\n"), NULL
);
935 // enable, disable, accept, reject, status, Reset, Clear
937 keychain_sync(int argc
, char * const *argv
)
942 " -e enable (join/create circle)"
943 " -i info (current status)"
945 " -s schedule sync with all peers"
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"
958 " -I Dump Ring Information\n"
960 " -N (re-)set to new account (USE WITH CARE: device will not leave circle before resetting account!)"
961 " -O reset to offering"
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"
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"
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"
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"
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"
999 CFErrorRef error
= NULL
;
1000 bool hadError
= false;
1002 while ((ch
= getopt(argc
, argv
, "ab:deg:hikl:mopq:rsv:w:x:zA:B:MNJCDEF:HG:ILOP:RT:UW:X:VY0")) != -1)
1006 printf("Signing out of circle\n");
1007 hadError
= !SOSCCSignedOut(true, &error
);
1010 int reason
= (int) strtoul(optarg
, NULL
, 10);
1012 reason
< kSOSDepartureReasonError
||
1013 reason
>= kSOSNumDepartureReasons
) {
1014 fprintf(stderr
, "Invalid custom departure reason %s\n", optarg
);
1016 printf("Setting custom departure reason %d\n", reason
);
1017 hadError
= !SOSCCSetLastDepartureReason(reason
, &error
);
1018 notify_post(kSOSCCCircleChangedNotification
);
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;
1033 printf("Please provide a \"true\" or \"false\" whether you'd like to leave the circle immediately\n");
1035 hadError
= !SOSCCSignedOut(signOutImmediately
, &error
);
1036 notify_post(kSOSCCCircleChangedNotification
);
1042 printf("Grabbing DS ID\n");
1043 CFStringRef deviceID
= SOSCCCopyDeviceID(&error
);
1048 if (!isNull(deviceID
)) {
1049 const char *id
= CFStringGetCStringPtr(deviceID
, kCFStringEncodingUTF8
);
1051 printf("IDS Device ID: %s\n", id
);
1053 printf("IDS Device ID is null!\n");
1055 CFReleaseNull(deviceID
);
1061 printf("Setting DS ID: %s\n", optarg
);
1062 CFStringRef deviceID
= CFStringCreateWithCString(kCFAllocatorDefault
, optarg
, kCFStringEncodingUTF8
);
1063 hadError
= SOSCCSetDeviceID(deviceID
, &error
);
1064 CFReleaseNull(deviceID
);
1070 printf("Attempting to send this message over IDS: %s\n", optarg
);
1071 CFStringRef message
= CFStringCreateWithCString(kCFAllocatorDefault
, optarg
, kCFStringEncodingUTF8
);
1072 hadError
= SOSCCIDSServiceRegistrationTest(message
, &error
);
1074 printerr(CFSTR("IDS is not ready: %@\n"), error
);
1077 CFReleaseNull(message
);
1083 printf("Starting ping test using this message: %s\n", optarg
);
1084 CFStringRef message
= CFStringCreateWithCString(kCFAllocatorDefault
, optarg
, kCFStringEncodingUTF8
);
1085 hadError
= SOSCCIDSPingTest(message
, &error
);
1087 printerr(CFSTR("Ping test failed to start: %@\n"), error
);
1090 CFReleaseNull(message
);
1095 hadError
= SOSCCIDSDeviceIDIsAvailableTest(&error
);
1097 printerr(CFSTR("Failed to retrieve IDS device ID: %@\n"), error
);
1103 printf("Turning ON keychain syncing\n");
1104 hadError
= requestToJoinCircle(&error
);
1108 printf("Turning OFF keychain syncing\n");
1109 hadError
= !SOSCCRemoveThisDeviceFromCircle(&error
);
1114 CFArrayRef applicants
= SOSCCCopyApplicantPeerInfo(NULL
);
1116 hadError
= !SOSCCAcceptApplicants(applicants
, &error
);
1117 CFRelease(applicants
);
1119 fprintf(stderr
, "No applicants to accept\n");
1126 CFArrayRef applicants
= SOSCCCopyApplicantPeerInfo(NULL
);
1128 hadError
= !SOSCCRejectApplicants(applicants
, &error
);
1129 CFRelease(applicants
);
1131 fprintf(stderr
, "No applicants to reject\n");
1141 notify_post("com.apple.security.cloudkeychain.forceupdate");
1146 printPeerInfos("view-unaware", ^(CFErrorRef
*error
) { return SOSCCCopyViewUnawarePeerInfo(error
); });
1152 CFArrayRef unawares
= SOSCCCopyViewUnawarePeerInfo(&error
);
1154 hadError
= !SOSCCRemovePeersFromCircle(unawares
, &error
);
1158 CFReleaseNull(unawares
);
1162 #if TARGET_OS_EMBEDDED
1163 SOSCloudKeychainRequestSyncWithAllPeers(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
1165 printf("not exported yet...\n");
1171 printf("Ensuring Fresh Parameters\n");
1172 bool result
= SOSCCRequestEnsureFreshParameters(&error
);
1178 printf("Refreshed Parameters Ensured!\n");
1180 printf("Problem trying to ensure fresh parameters\n");
1186 printf("Applying to Ring\n");
1187 CFStringRef ringName
= CFStringCreateWithCString(kCFAllocatorDefault
, (char *)optarg
, kCFStringEncodingUTF8
);
1188 hadError
= SOSCCApplyToARing(ringName
, &error
);
1193 printf("Withdrawing from Ring\n");
1194 CFStringRef ringName
= CFStringCreateWithCString(kCFAllocatorDefault
, (char *)optarg
, kCFStringEncodingUTF8
);
1195 hadError
= SOSCCWithdrawlFromARing(ringName
, &error
);
1200 printf("Status of this device in the Ring\n");
1201 CFStringRef ringName
= CFStringCreateWithCString(kCFAllocatorDefault
, (char *)optarg
, kCFStringEncodingUTF8
);
1202 hadError
= SOSCCRingStatus(ringName
, &error
);
1207 printf("Enabling Ring\n");
1208 CFStringRef ringName
= CFStringCreateWithCString(kCFAllocatorDefault
, (char *)optarg
, kCFStringEncodingUTF8
);
1209 hadError
= SOSCCEnableRing(ringName
, &error
);
1214 printf("Setting random escrow record\n");
1215 bool success
= SOSCCSetEscrowRecord(CFSTR("label"), 8, &error
);
1224 CFDictionaryRef attempts
= SOSCCCopyEscrowRecord(&error
);
1226 CFDictionaryForEach(attempts
, ^(const void *key
, const void *value
) {
1228 char *keyString
= CFStringToCString(key
);
1229 printf("%s:\n", keyString
);
1232 if(isDictionary(value
)){
1233 CFDictionaryForEach(value
, ^(const void *key
, const void *value
) {
1235 char *keyString
= CFStringToCString(key
);
1236 printf("%s: ", keyString
);
1239 if(isString(value
)){
1240 char *time
= CFStringToCString(value
);
1241 printf("timestamp: %s\n", time
);
1244 else if(isNumber(value
)){
1246 CFNumberGetValue(value
, kCFNumberLongLongType
, &tries
);
1247 printf("date: %llu\n", tries
);
1254 CFReleaseNull(attempts
);
1260 bool success
= SOSCCCheckPeerAvailability(&error
);
1269 printf("Printing all the rings\n");
1270 CFStringRef ringdescription
= SOSCCGetAllTheRings(&error
);
1271 if(!ringdescription
)
1274 printf("Rings: %s", CFStringToCString(ringdescription
));
1280 hadError
= !SOSCCAccountSetToNew(&error
);
1282 notify_post(kSOSCCCircleChangedNotification
);
1286 hadError
= !SOSCCResetToEmpty(&error
);
1290 hadError
= !SOSCCResetToOffering(&error
);
1294 hadError
= !dumpMyPeer(&error
);
1298 hadError
= clearAllKVS(&error
);
1302 hadError
= setPassword(optarg
, &error
);
1306 hadError
= tryPassword(optarg
, &error
);
1311 uint64_t limit
= strtoul(optarg
, NULL
, 10);
1312 hadError
= !SOSCCBailFromCircle_BestEffort(limit
, &error
);
1317 hadError
= !SOSCCPurgeUserCredentials(&error
);
1321 hadError
= !dumpKVS(optarg
, &error
);
1325 hadError
= syncAndWait(optarg
, &error
);
1329 hadError
= !viewcmd(optarg
, &error
);
1333 hadError
= clientViewStatus(&error
);
1336 hadError
= !listviewcmd(&error
);
1340 hadError
= !SecPropertycmd(optarg
, &error
);
1344 hadError
= setBag(optarg
, &error
);
1348 hadError
= dumpYetToSync(&error
);
1353 return 2; /* Return 2 triggers usage message. */
1357 printerr(CFSTR("Error: %@\n"), error
);