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 requestToJoinCircle(CFErrorRef
*error
)
233 // Set the visual state of switch based on membership in circle
234 bool hadError
= false;
235 SOSCCStatus ccstatus
= SOSCCThisDeviceIsInCircle(error
);
239 case kSOSCCCircleAbsent
:
240 hadError
= !SOSCCResetToOffering(error
);
242 case kSOSCCNotInCircle
:
243 hadError
= !SOSCCRequestToJoinCircle(error
);
246 printerr(CFSTR("Request to join circle with bad status: %@ (%d)\n"), SOSCCGetStatusDescription(ccstatus
), ccstatus
);
252 static bool setPassword(char *labelAndPassword
, CFErrorRef
*err
)
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
);
267 static bool tryPassword(char *labelAndPassword
, CFErrorRef
*err
)
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
);
282 static CFTypeRef
getObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
284 __block CFTypeRef object
= NULL
;
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
);
290 dispatch_group_enter(dgroup
);
292 CloudKeychainReplyBlock replyBlock
=
293 ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
295 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues
);
296 object
= returnedValues
;
301 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error
);
302 // CFRelease(*error);
304 dispatch_group_leave(dgroup
);
305 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object
);
306 dispatch_semaphore_signal(waitSemaphore
);
310 SOSCloudKeychainGetAllObjectsFromCloud(processQueue
, replyBlock
);
312 SOSCloudKeychainGetObjectsFromCloud(keysToGet
, processQueue
, replyBlock
);
314 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
315 dispatch_release(waitSemaphore
);
316 if (object
&& (CFGetTypeID(object
) == CFNullGetTypeID())) // return a NULL instead of a CFNull
321 secerror("returned: %@", object
);
325 static CFStringRef
printFullDataString(CFDataRef data
){
326 __block CFStringRef fullData
= NULL
;
328 BufferPerformWithHexString(CFDataGetBytePtr(data
), CFDataGetLength(data
), ^(CFStringRef dataHex
) {
329 fullData
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@"), dataHex
);
335 static void displayLastKeyParameters(CFTypeRef key
, CFTypeRef value
)
337 CFDataRef valueAsData
= asData(value
, NULL
);
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
);
346 printmsg(CFSTR("%@: %@\n"), key
, printFullDataString(value
));
347 CFReleaseNull(dateString
);
348 CFReleaseNull(keyParameterData
);
349 CFReleaseNull(dateData
);
350 CFReleaseNull(keyParameterDescription
);
353 printmsg(CFSTR("%@: %@\n"), key
, value
);
357 static void displayKeyParameters(CFTypeRef key
, CFTypeRef value
)
360 CFStringRef keyParameterDescription
= UserParametersDescription((CFDataRef
)value
);
362 if(keyParameterDescription
)
363 printmsg(CFSTR("%@: %@\n"), key
, keyParameterDescription
);
365 printmsg(CFSTR("%@: %@\n"), key
, value
);
367 CFReleaseNull(keyParameterDescription
);
370 printmsg(CFSTR("%@: %@\n"), key
, value
);
374 static void displayLastCircle(CFTypeRef key
, CFTypeRef value
)
376 CFDataRef valueAsData
= asData(value
, NULL
);
378 CFErrorRef localError
= NULL
;
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
);
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
);
395 printmsg(CFSTR("%@: %@\n"), key
, printFullDataString(circleData
));
397 CFReleaseNull(dateString
);
398 CFReleaseNull(circleData
);
399 CFReleaseSafe(circle
);
400 CFReleaseNull(dateData
);
401 CFReleaseNull(localError
);
404 printmsg(CFSTR("%@: %@\n"), key
, value
);
408 static void displayCircle(CFTypeRef key
, CFTypeRef value
)
410 CFDataRef circleData
= (CFDataRef
)value
;
412 CFErrorRef localError
= NULL
;
413 if (isData(circleData
))
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
);
426 printmsg(CFSTR("%@: %@\n"), key
, value
);
429 static void displayMessage(CFTypeRef key
, CFTypeRef value
)
431 CFDataRef message
= (CFDataRef
)value
;
433 const char* messageType
= SecOTRPacketTypeString(message
);
434 printmsg(CFSTR("%@: %s: %ld\n"), key
, messageType
, CFDataGetLength(message
));
437 printmsg(CFSTR("%@: %@\n"), key
, value
);
440 static void printEverything(CFTypeRef objects
)
442 CFDictionaryForEach(objects
, ^(const void *key
, const void *value
) {
445 printmsg(CFSTR("%@: %@\n\n"), key
, printFullDataString(value
));
448 printmsg(CFSTR("%@: %@\n"), key
, value
);
453 static void decodeForKeyType(CFTypeRef key
, CFTypeRef value
, SOSKVSKeyType type
){
456 displayCircle(key
, value
);
460 displayMessage(key
, value
);
463 displayKeyParameters(key
, value
);
465 case kLastKeyParameterKey
:
466 displayLastKeyParameters(key
, value
);
469 displayLastCircle(key
, value
);
471 case kInitialSyncKey
:
472 case kAccountChangedKey
:
477 printmsg(CFSTR("%@: %@\n"), key
, value
);
482 static void decodeAllTheValues(CFTypeRef objects
){
483 SOSKVSKeyType keyType
= 0;
484 __block
bool didPrint
= false;
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
);
494 printmsg(CFSTR("%@\n"), CFSTR(""));
498 static bool dumpKVS(char *itemName
, CFErrorRef
*err
)
500 CFArrayRef keysToGet
= NULL
;
503 CFStringRef itemStr
= CFStringCreateWithCString(kCFAllocatorDefault
, itemName
, kCFStringEncodingUTF8
);
504 printf("Retrieving %s from KVS\n", itemName
);
505 keysToGet
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, itemStr
, NULL
);
506 CFReleaseSafe(itemStr
);
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
);
514 printf("All keys and values straight from KVS\n");
515 printEverything(objects
);
516 printf("\nAll values in decoded form...\n");
517 decodeAllTheValues(objects
);
523 static bool syncAndWait(char *itemName
, CFErrorRef
*err
)
525 CFArrayRef keysToGet
= NULL
;
526 __block CFTypeRef objects
= NULL
;
529 fprintf(stderr
, "No item keys supplied\n");
533 CFStringRef itemStr
= CFStringCreateWithCString(kCFAllocatorDefault
, itemName
, kCFStringEncodingUTF8
);
534 printf("Retrieving %s from KVS\n", itemName
);
535 keysToGet
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, itemStr
, NULL
);
536 CFReleaseSafe(itemStr
);
538 dispatch_queue_t generalq
= dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL
);
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
);
544 CloudKeychainReplyBlock replyBlock
= ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
546 secinfo("sync", "SOSCloudKeychainSynchronizeAndWait returned: %@", returnedValues
);
548 secerror("SOSCloudKeychainSynchronizeAndWait returned error: %@", error
);
549 objects
= returnedValues
;
552 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", objects
);
553 dispatch_semaphore_signal(waitSemaphore
);
556 SOSCloudKeychainSynchronizeAndWait(keysToGet
, generalq
, replyBlock
);
558 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
559 dispatch_release(waitSemaphore
);
561 CFReleaseSafe(keysToGet
);
569 const CFStringRef
*viewspec
;
572 "keychain", &kSOSViewKeychainV0
574 "masterkey", &kSOSViewPCSMasterKey
,
576 "iclouddrive", &kSOSViewPCSiCloudDrive
,
578 "photos", &kSOSViewPCSPhotos
,
580 "escrow", &kSOSViewPCSEscrow
,
582 "fde", &kSOSViewPCSFDE
,
584 "maildrop", &kSOSViewPCSMailDrop
,
586 "icloudbackup", &kSOSViewPCSiCloudBackup
,
588 "notes", &kSOSViewPCSNotes
,
590 "imessage", &kSOSViewPCSiMessage
,
592 "feldspar", &kSOSViewPCSFeldspar
,
594 "appletv", &kSOSViewAppleTV
,
596 "homekit", &kSOSViewHomeKit
,
598 "wifi", &kSOSViewWiFi
,
600 "passwords", &kSOSViewAutofillPasswords
,
602 "creditcards", &kSOSViewSafariCreditCards
,
604 "icloudidentity", &kSOSViewiCloudIdentity
,
606 "othersyncable", &kSOSViewOtherSyncable
,
610 static CFStringRef
convertStringToView(char *viewname
) {
613 for (n
= 0; n
< sizeof(string2View
)/sizeof(string2View
[0]); n
++) {
614 if (strcmp(string2View
[n
].name
, viewname
) == 0)
615 return *string2View
[n
].viewspec
;
618 // Leak this, since it's a getter.
619 return CFStringCreateWithCString(kCFAllocatorDefault
, viewname
, kCFStringEncodingUTF8
);
622 static CFStringRef
convertViewReturnCodeToString(SOSViewActionCode ac
) {
623 CFStringRef retval
= NULL
;
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;
639 static bool viewcmd(char *itemName
, CFErrorRef
*err
) {
640 char *cmd
, *viewname
;
641 SOSViewActionCode ac
= kSOSCCViewQuery
;
642 CFStringRef viewspec
;
644 viewname
= strchr(itemName
, ':');
645 if(viewname
== NULL
) return false;
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
;
660 if(strchr(viewname
, ',') == NULL
) { // original single value version
661 viewspec
= convertStringToView(viewname
);
662 if(!viewspec
) return false;
664 SOSViewResultCode rc
= SOSCCView(viewspec
, ac
, err
);
665 CFStringRef resultString
= convertViewReturnCodeToString(rc
);
667 printmsg(CFSTR("View Result: %@ : %@\n"), resultString
, viewspec
);
671 if(ac
== kSOSCCViewQuery
) return false;
673 // new multi-view version
674 char *viewlist
= strdup(viewname
);
676 char *tofree
= viewlist
;
677 CFMutableSetRef viewSet
= CFSetCreateMutable(NULL
, 0, &kCFCopyStringSetCallBacks
);
679 while ((token
= strsep(&viewlist
, ",")) != NULL
) {
680 CFStringRef resultString
= convertStringToView(token
);
681 CFSetAddValue(viewSet
, resultString
);
684 printmsg(CFSTR("viewSet provided is %@\n"), viewSet
);
689 if(ac
== kSOSCCViewEnable
) retcode
= SOSCCViewSet(viewSet
, NULL
);
690 else retcode
= SOSCCViewSet(NULL
, viewSet
);
692 printf("SOSCCViewSet returned %s\n", (retcode
)? "true": "false");
697 static bool listviewcmd(CFErrorRef
*err
) {
700 for (n
= 0; n
< sizeof(string2View
)/sizeof(string2View
[0]); n
++) {
701 CFStringRef viewspec
= *string2View
[n
].viewspec
;
703 SOSViewResultCode rc
= SOSCCView(viewspec
, kSOSCCViewQuery
, err
);
704 CFStringRef resultString
= convertViewReturnCodeToString(rc
);
706 printmsg(CFSTR("View Result: %@ : %@\n"), resultString
, viewspec
);
712 static CFStringRef
convertStringToProperty(char *propertyname
) {
713 CFStringRef propertyspec
= NULL
;
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
;
728 static CFStringRef
convertPropertyReturnCodeToString(SOSSecurityPropertyResultCode ac
) {
729 CFStringRef retval
= NULL
;
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;
746 static bool SecPropertycmd(char *itemName
, CFErrorRef
*err
) {
747 char *cmd
, *propertyname
;
748 SOSSecurityPropertyActionCode ac
= kSOSCCSecurityPropertyQuery
;
749 CFStringRef propertyspec
;
751 propertyname
= strchr(itemName
, ':');
752 if(propertyname
== NULL
) return false;
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
;
767 propertyspec
= convertStringToProperty(propertyname
);
768 if(!propertyspec
) return false;
770 SOSSecurityPropertyResultCode rc
= SOSCCSecurityProperty(propertyspec
, ac
, err
);
771 CFStringRef resultString
= convertPropertyReturnCodeToString(rc
);
773 printmsg(CFSTR("Property Result: %@ : %@\n"), resultString
, propertyspec
);
778 static void dumpStringSet(CFStringRef label
, CFSetRef s
) {
779 if(!s
|| !label
) return;
781 printmsg(CFSTR("%@: { "), label
);
782 __block
bool first
= true;
783 CFSetForEach(s
, ^(const void *p
) {
784 CFStringRef fmt
= CFSTR(", %@");
788 CFStringRef string
= (CFStringRef
) p
;
789 printmsg(fmt
, string
);
792 printmsg(CFSTR(" }\n"), NULL
);
795 static bool dumpMyPeer(CFErrorRef
*error
) {
796 SOSPeerInfoRef myPeer
= SOSCCCopyMyPeerInfo(error
);
798 if (!myPeer
) return false;
800 CFStringRef peerID
= SOSPeerInfoGetPeerID(myPeer
);
801 CFStringRef peerName
= SOSPeerInfoGetPeerName(myPeer
);
802 CFIndex peerVersion
= SOSPeerInfoGetVersion(myPeer
);
803 bool retirement
= SOSPeerInfoIsRetirementTicket(myPeer
);
805 printmsg(CFSTR("Peer Name: %@ PeerID: %@ Version: %d\n"), peerName
, peerID
, peerVersion
);
807 CFDateRef retdate
= SOSPeerInfoGetRetirementDate(myPeer
);
808 printmsg(CFSTR("Retired: %@\n"), retdate
);
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
);
820 printmsg(CFSTR("Serial#: %@ PrefIDS#: %@ transportType#: %@ idsDeviceID#: %@\n"),
821 serialNumber
, preferIDS
, transportType
, idsDeviceID
);
822 dumpStringSet(CFSTR(" Views: "), views
);
823 dumpStringSet(CFSTR("SecurityProperties: "), properties
);
825 CFReleaseSafe(serialNumber
);
826 CFReleaseSafe(preferIDS
);
827 CFReleaseSafe(views
);
828 CFReleaseSafe(transportType
);
829 CFReleaseSafe(idsDeviceID
);
830 CFReleaseSafe(properties
);
834 return myPeer
!= NULL
;
837 static bool setBag(char *itemName
, CFErrorRef
*err
)
839 __block
bool success
= false;
840 __block CFErrorRef error
= NULL
;
842 CFStringRef random
= SecPasswordCreateWithRandomDigits(10, NULL
);
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
);
851 success
= SOSCCRegisterSingleRecoverySecret(aks_bag
, includeV0
, &error
);
853 printmsg(CFSTR("Failed registering single secret %@"), error
);
854 CFReleaseNull(aks_bag
);
857 printmsg(CFSTR("Failed to create aks_bag: %@"), error
);
859 CFReleaseNull(aks_bag
);
860 } else if (0 == strncasecmp(optarg
, "device", 6)) {
861 printmsg(CFSTR("Setting Device Secret using entropy from string: %@\n"), random
);
863 SOSPeerInfoRef me
= SOSCCCopyMyPeerWithNewDeviceRecoverySecret(stringAsData
, &error
);
865 success
= me
!= NULL
;
868 printmsg(CFSTR("Failed: %@\n"), err
);
871 printmsg(CFSTR("Unrecognized argument to -b %s\n"), optarg
);
879 static void prClientViewState(char *label
, bool result
) {
880 printf("Sync Status for %s: %s\n", label
, (result
) ? "enabled": "not enabled");
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());
893 static bool dumpYetToSync(CFErrorRef
*error
) {
894 CFArrayRef yetToSyncViews
= SOSCCCopyYetToSyncViewsList(error
);
896 bool hadError
= yetToSyncViews
;
898 if (yetToSyncViews
) {
899 __block CFStringRef separator
= CFSTR("");
901 printmsg(CFSTR("Yet to sync views: ["), NULL
);
903 CFArrayForEach(yetToSyncViews
, ^(const void *value
) {
904 if (isString(value
)) {
905 printmsg(CFSTR("%@%@"), separator
, value
);
907 separator
= CFSTR(", ");
910 printmsg(CFSTR("]\n"), NULL
);
917 // enable, disable, accept, reject, status, Reset, Clear
919 keychain_sync(int argc
, char * const *argv
)
924 " -e enable (join/create circle)"
925 " -i info (current status)"
927 " -s schedule sync with all peers"
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"
940 " -I Dump Ring Information\n"
942 " -N (re-)set to new account (USE WITH CARE: device will not leave circle before resetting account!)"
943 " -O reset to offering"
945 " -X [limit] best effort bail from circle in limit seconds"
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"
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"
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"
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"
975 CFErrorRef error
= NULL
;
976 bool hadError
= false;
978 while ((ch
= getopt(argc
, argv
, "ab:deg:hikl:mpq:rsv:w:x:zA:B:CDEF:G:ILOP:RT:UW:X:VY")) != -1)
982 printf("Signing out of circle\n");
983 hadError
= !SOSCCSignedOut(true, &error
);
986 int reason
= (int) strtoul(optarg
, NULL
, 10);
988 reason
< kSOSDepartureReasonError
||
989 reason
>= kSOSNumDepartureReasons
) {
990 fprintf(stderr
, "Invalid custom departure reason %s\n", optarg
);
992 printf("Setting custom departure reason %d\n", reason
);
993 hadError
= !SOSCCSetLastDepartureReason(reason
, &error
);
994 notify_post(kSOSCCCircleChangedNotification
);
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;
1009 printf("Please provide a \"true\" or \"false\" whether you'd like to leave the circle immediately\n");
1011 hadError
= !SOSCCSignedOut(signOutImmediately
, &error
);
1012 notify_post(kSOSCCCircleChangedNotification
);
1018 printf("Grabbing DS ID\n");
1019 CFStringRef deviceID
= SOSCCRequestDeviceID(&error
);
1024 if (!isNull(deviceID
)) {
1025 const char *id
= CFStringGetCStringPtr(deviceID
, kCFStringEncodingUTF8
);
1027 printf("IDS Device ID: %s\n", id
);
1029 printf("IDS Device ID is null!\n");
1030 CFRelease(deviceID
);
1037 printf("Setting DS ID: %s\n", optarg
);
1038 CFStringRef deviceID
= CFStringCreateWithCString(kCFAllocatorDefault
, optarg
, kCFStringEncodingUTF8
);
1039 hadError
= SOSCCSetDeviceID(deviceID
, &error
);
1040 CFReleaseNull(deviceID
);
1046 printf("Attempting to send this message over IDS: %s\n", optarg
);
1047 CFStringRef message
= CFStringCreateWithCString(kCFAllocatorDefault
, optarg
, kCFStringEncodingUTF8
);
1048 hadError
= SOSCCIDSServiceRegistrationTest(message
, &error
);
1050 printerr(CFSTR("IDS is not ready: %@\n"), error
);
1053 CFReleaseNull(message
);
1059 printf("Starting ping test using this message: %s\n", optarg
);
1060 CFStringRef message
= CFStringCreateWithCString(kCFAllocatorDefault
, optarg
, kCFStringEncodingUTF8
);
1061 hadError
= SOSCCIDSPingTest(message
, &error
);
1063 printerr(CFSTR("Ping test failed to start: %@\n"), error
);
1066 CFReleaseNull(message
);
1071 hadError
= SOSCCIDSDeviceIDIsAvailableTest(&error
);
1073 printerr(CFSTR("Failed to retrieve IDS device ID: %@\n"), error
);
1079 printf("Turning ON keychain syncing\n");
1080 hadError
= requestToJoinCircle(&error
);
1084 printf("Turning OFF keychain syncing\n");
1085 hadError
= !SOSCCRemoveThisDeviceFromCircle(&error
);
1090 CFArrayRef applicants
= SOSCCCopyApplicantPeerInfo(NULL
);
1092 hadError
= !SOSCCAcceptApplicants(applicants
, &error
);
1093 CFRelease(applicants
);
1095 fprintf(stderr
, "No applicants to accept\n");
1102 CFArrayRef applicants
= SOSCCCopyApplicantPeerInfo(NULL
);
1104 hadError
= !SOSCCRejectApplicants(applicants
, &error
);
1105 CFRelease(applicants
);
1107 fprintf(stderr
, "No applicants to reject\n");
1117 notify_post("com.apple.security.cloudkeychain.forceupdate");
1121 #if TARGET_OS_EMBEDDED
1122 SOSCloudKeychainRequestSyncWithAllPeers(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
1124 printf("not exported yet...\n");
1130 printf("Ensuring Fresh Parameters\n");
1131 bool result
= SOSCCRequestEnsureFreshParameters(&error
);
1137 printf("Refreshed Parameters Ensured!\n");
1139 printf("Problem trying to ensure fresh parameters\n");
1145 printf("Applying to Ring\n");
1146 CFStringRef ringName
= CFStringCreateWithCString(kCFAllocatorDefault
, (char *)optarg
, kCFStringEncodingUTF8
);
1147 hadError
= SOSCCApplyToARing(ringName
, &error
);
1152 printf("Withdrawing from Ring\n");
1153 CFStringRef ringName
= CFStringCreateWithCString(kCFAllocatorDefault
, (char *)optarg
, kCFStringEncodingUTF8
);
1154 hadError
= SOSCCWithdrawlFromARing(ringName
, &error
);
1159 printf("Status of this device in the Ring\n");
1160 CFStringRef ringName
= CFStringCreateWithCString(kCFAllocatorDefault
, (char *)optarg
, kCFStringEncodingUTF8
);
1161 hadError
= SOSCCRingStatus(ringName
, &error
);
1166 printf("Enabling Ring\n");
1167 CFStringRef ringName
= CFStringCreateWithCString(kCFAllocatorDefault
, (char *)optarg
, kCFStringEncodingUTF8
);
1168 hadError
= SOSCCEnableRing(ringName
, &error
);
1173 printf("Printing all the rings\n");
1174 CFStringRef ringdescription
= SOSCCGetAllTheRings(&error
);
1175 if(!ringdescription
)
1178 printf("Rings: %s", CFStringToCString(ringdescription
));
1184 hadError
= !SOSCCAccountSetToNew(&error
);
1186 notify_post(kSOSCCCircleChangedNotification
);
1190 hadError
= !SOSCCResetToEmpty(&error
);
1194 hadError
= !SOSCCResetToOffering(&error
);
1198 hadError
= !dumpMyPeer(&error
);
1202 hadError
= clearAllKVS(&error
);
1206 hadError
= setPassword(optarg
, &error
);
1210 hadError
= tryPassword(optarg
, &error
);
1215 uint64_t limit
= strtoul(optarg
, NULL
, 10);
1216 hadError
= !SOSCCBailFromCircle_BestEffort(limit
, &error
);
1221 hadError
= !SOSCCPurgeUserCredentials(&error
);
1225 hadError
= !dumpKVS(optarg
, &error
);
1229 hadError
= syncAndWait(optarg
, &error
);
1233 hadError
= !viewcmd(optarg
, &error
);
1237 hadError
= clientViewStatus(&error
);
1240 hadError
= !listviewcmd(&error
);
1244 hadError
= !SecPropertycmd(optarg
, &error
);
1248 hadError
= setBag(optarg
, &error
);
1252 hadError
= dumpYetToSync(&error
);
1257 return 2; /* Return 2 triggers usage message. */
1261 printerr(CFSTR("Error: %@\n"), error
);