5 // Created by Richard Murphy on 1/26/16.
9 #include "keychain_log.h"
12 * Copyright (c) 2003-2007,2009-2010,2013-2014 Apple Inc. All Rights Reserved.
14 * @APPLE_LICENSE_HEADER_START@
16 * This file contains Original Code and/or Modifications of Original Code
17 * as defined in and that are subject to the Apple Public Source License
18 * Version 2.0 (the 'License'). You may not use this file except in
19 * compliance with the License. Please obtain a copy of the License at
20 * http://www.opensource.apple.com/apsl/ and read it before using this
23 * The Original Code and all software distributed under the License are
24 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
25 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
26 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
28 * Please see the License for the specific language governing rights and
29 * limitations under the License.
31 * @APPLE_LICENSE_HEADER_END@
41 #include <sys/utsname.h>
45 #include <Security/SecItem.h>
47 #include <CoreFoundation/CFNumber.h>
48 #include <CoreFoundation/CFString.h>
50 #include <Security/SecureObjectSync/SOSCloudCircle.h>
51 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
52 #include <Security/SecureObjectSync/SOSPeerInfo.h>
53 #include <Security/SecureObjectSync/SOSPeerInfoPriv.h>
54 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
55 #include <Security/SecureObjectSync/SOSUserKeygen.h>
56 #include <Security/SecureObjectSync/SOSKVSKeys.h>
57 #include <securityd/SOSCloudCircleServer.h>
58 #include <Security/SecOTRSession.h>
59 #include <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
61 #include <utilities/SecCFWrappers.h>
62 #include <utilities/debugging.h>
64 #include <SecurityTool/readline.h>
67 #include "keychain_log.h"
68 #include "secToolFileIO.h"
69 #include "secViewDisplay.h"
70 #include <utilities/debugging.h>
73 #include <Security/SecPasswordGenerate.h>
75 #define MAXKVSKEYTYPE kUnknownKey
76 #define DATE_LENGTH 18
79 static const char *getSOSCCStatusDescription(SOSCCStatus ccstatus
)
83 case kSOSCCInCircle
: return "In Circle";
84 case kSOSCCNotInCircle
: return "Not in Circle";
85 case kSOSCCRequestPending
: return "Request pending";
86 case kSOSCCCircleAbsent
: return "Circle absent";
87 case kSOSCCError
: return "Circle error";
90 return "<unknown ccstatus>";
95 static void printPeerInfos(char *label
, CFArrayRef (^getArray
)(CFErrorRef
*error
)) {
96 CFErrorRef error
= NULL
;
97 CFArrayRef ppi
= getArray(&error
);
98 SOSPeerInfoRef me
= SOSCCCopyMyPeerInfo(NULL
);
99 CFStringRef mypeerID
= SOSPeerInfoGetPeerID(me
);
102 printmsg(CFSTR("%s count: %ld\n"), label
, (long)CFArrayGetCount(ppi
));
103 CFArrayForEach(ppi
, ^(const void *value
) {
105 SOSPeerInfoRef peer
= (SOSPeerInfoRef
)value
;
106 CFIndex version
= SOSPeerInfoGetVersion(peer
);
107 CFStringRef peerName
= SOSPeerInfoGetPeerName(peer
);
108 CFStringRef devtype
= SOSPeerInfoGetPeerDeviceType(peer
);
109 CFStringRef peerID
= SOSPeerInfoGetPeerID(peer
);
110 CFStringRef transportType
= CFSTR("KVS");
111 CFStringRef deviceID
= CFSTR("");
112 CFDictionaryRef gestalt
= SOSPeerInfoCopyPeerGestalt(peer
);
113 CFStringRef osVersion
= CFDictionaryGetValue(gestalt
, CFSTR("OSVersion"));
114 CFReleaseNull(gestalt
);
118 CFDictionaryRef v2Dictionary
= peer
->v2Dictionary
;
119 transportType
= CFDictionaryGetValue(v2Dictionary
, sTransportType
);
120 deviceID
= CFDictionaryGetValue(v2Dictionary
, sDeviceID
);
122 char *pname
= CFStringToCString(peerName
);
123 char *dname
= CFStringToCString(devtype
);
124 char *tname
= CFStringToCString(transportType
);
125 char *iname
= CFStringToCString(deviceID
);
126 char *osname
= CFStringToCString(osVersion
);
127 const char *me
= CFEqualSafe(mypeerID
, peerID
) ? "me>" : " ";
130 snprintf(buf
, 160, "%s %s: %-16s %-16s %-16s %-16s", me
, label
, pname
, dname
, tname
, iname
);
134 CFStringRef pid
= SOSPeerInfoGetPeerID(peer
);
135 CFIndex vers
= SOSPeerInfoGetVersion(peer
);
136 printmsg(CFSTR("%s %@ V%d OS:%s\n"), buf
, pid
, vers
, osname
);
140 printmsg(CFSTR("No %s, error: %@\n"), label
, error
);
143 CFReleaseNull(error
);
146 static void dumpCircleInfo()
148 CFErrorRef error
= NULL
;
149 CFArrayRef generations
= NULL
;
150 CFArrayRef confirmedDigests
= NULL
;
151 bool is_user_public_trusted
= false;
152 __block
int count
= 0;
154 SOSCCStatus ccstatus
= SOSCCThisDeviceIsInCircle(&error
);
155 if(ccstatus
== kSOSCCError
) {
156 printmsg(CFSTR("End of Dump - unable to proceed due to ccstatus (%s) error: %@\n"), getSOSCCStatusDescription(ccstatus
), error
);
159 printmsg(CFSTR("ccstatus: %s (%d)\n"), getSOSCCStatusDescription(ccstatus
), ccstatus
, error
);
161 is_user_public_trusted
= SOSCCValidateUserPublic(&error
);
162 if(is_user_public_trusted
)
163 printmsg(CFSTR("Account user public is trusted%@"),CFSTR("\n"));
165 printmsg(CFSTR("Account user public is not trusted error:(%@)\n"), error
);
166 CFReleaseNull(error
);
168 generations
= SOSCCCopyGenerationPeerInfo(&error
);
170 CFArrayForEach(generations
, ^(const void *value
) {
173 printmsg(CFSTR("Circle name: %@, "),value
);
176 CFStringRef genDesc
= SOSGenerationCountCopyDescription(value
);
177 printmsg(CFSTR("Generation Count: %@"), genDesc
);
178 CFReleaseNull(genDesc
);
180 printmsg(CFSTR("%s\n"), "");
183 printmsg(CFSTR("No generation count: %@\n"), error
);
185 CFReleaseNull(generations
);
186 CFReleaseNull(error
);
188 printPeerInfos(" Peers", ^(CFErrorRef
*error
) { return SOSCCCopyValidPeerPeerInfo(error
); });
189 printPeerInfos(" Invalid", ^(CFErrorRef
*error
) { return SOSCCCopyNotValidPeerPeerInfo(error
); });
190 printPeerInfos(" Retired", ^(CFErrorRef
*error
) { return SOSCCCopyRetirementPeerInfo(error
); });
191 printPeerInfos(" Concur", ^(CFErrorRef
*error
) { return SOSCCCopyConcurringPeerPeerInfo(error
); });
192 printPeerInfos("Applicants", ^(CFErrorRef
*error
) { return SOSCCCopyApplicantPeerInfo(error
); });
194 confirmedDigests
= SOSCCCopyEngineState(&error
);
198 CFArrayForEach(confirmedDigests
, ^(const void *value
) {
201 printmsg(CFSTR("%@"), value
);
204 CFStringRef hexDigest
= CFDataCopyHexString(value
);
205 printmsg(CFSTR(" %@\n"), hexDigest
);
206 CFReleaseSafe(hexDigest
);
211 printmsg(CFSTR("No engine peers: %@\n"), error
);
212 CFReleaseNull(confirmedDigests
);
215 static CFTypeRef
getObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
217 __block CFTypeRef object
= NULL
;
219 const uint64_t maxTimeToWaitInSeconds
= 30ull * NSEC_PER_SEC
;
220 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
221 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
223 dispatch_group_enter(dgroup
);
225 CloudKeychainReplyBlock replyBlock
=
226 ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
228 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues
);
229 object
= returnedValues
;
234 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error
);
235 // CFRelease(*error);
237 dispatch_group_leave(dgroup
);
238 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object
);
239 dispatch_semaphore_signal(waitSemaphore
);
243 SOSCloudKeychainGetAllObjectsFromCloud(processQueue
, replyBlock
);
245 SOSCloudKeychainGetObjectsFromCloud(keysToGet
, processQueue
, replyBlock
);
247 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
248 dispatch_release(waitSemaphore
);
249 if (object
&& (CFGetTypeID(object
) == CFNullGetTypeID())) // return a NULL instead of a CFNull
254 secerror("returned: %@", object
);
258 static CFStringRef
printFullDataString(CFDataRef data
){
259 __block CFStringRef fullData
= NULL
;
261 BufferPerformWithHexString(CFDataGetBytePtr(data
), CFDataGetLength(data
), ^(CFStringRef dataHex
) {
262 fullData
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@"), dataHex
);
268 static void displayLastKeyParameters(CFTypeRef key
, CFTypeRef value
)
270 CFDataRef valueAsData
= asData(value
, NULL
);
272 CFDataRef dateData
= CFDataCreateCopyFromRange(kCFAllocatorDefault
, valueAsData
, CFRangeMake(0, DATE_LENGTH
));
273 CFDataRef keyParameterData
= CFDataCreateCopyFromPositions(kCFAllocatorDefault
, valueAsData
, DATE_LENGTH
, CFDataGetLength(valueAsData
));
274 CFStringRef dateString
= CFStringCreateFromExternalRepresentation(kCFAllocatorDefault
, dateData
, kCFStringEncodingUTF8
);
275 CFStringRef keyParameterDescription
= UserParametersDescription(keyParameterData
);
276 if(keyParameterDescription
)
277 printmsg(CFSTR("%@: %@: %@\n"), key
, dateString
, keyParameterDescription
);
279 printmsg(CFSTR("%@: %@\n"), key
, printFullDataString(value
));
280 CFReleaseNull(dateString
);
281 CFReleaseNull(keyParameterData
);
282 CFReleaseNull(dateData
);
283 CFReleaseNull(keyParameterDescription
);
286 printmsg(CFSTR("%@: %@\n"), key
, value
);
290 static void displayKeyParameters(CFTypeRef key
, CFTypeRef value
)
293 CFStringRef keyParameterDescription
= UserParametersDescription((CFDataRef
)value
);
295 if(keyParameterDescription
)
296 printmsg(CFSTR("%@: %@\n"), key
, keyParameterDescription
);
298 printmsg(CFSTR("%@: %@\n"), key
, value
);
300 CFReleaseNull(keyParameterDescription
);
303 printmsg(CFSTR("%@: %@\n"), key
, value
);
307 static void displayLastCircle(CFTypeRef key
, CFTypeRef value
)
309 CFDataRef valueAsData
= asData(value
, NULL
);
311 CFErrorRef localError
= NULL
;
313 CFDataRef dateData
= CFDataCreateCopyFromRange(kCFAllocatorDefault
, valueAsData
, CFRangeMake(0, DATE_LENGTH
));
314 CFDataRef circleData
= CFDataCreateCopyFromPositions(kCFAllocatorDefault
, valueAsData
, DATE_LENGTH
, CFDataGetLength(valueAsData
));
315 CFStringRef dateString
= CFStringCreateFromExternalRepresentation(kCFAllocatorDefault
, dateData
, kCFStringEncodingUTF8
);
316 SOSCircleRef circle
= SOSCircleCreateFromData(NULL
, (CFDataRef
) circleData
, &localError
);
320 CFNumberRef idLength
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &size
);
321 CFDictionaryRef format
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength
, NULL
);
322 printmsgWithFormatOptions(format
, CFSTR("%@: %@: %@\n"), key
, dateString
, circle
);
323 CFReleaseNull(idLength
);
324 CFReleaseNull(format
);
328 printmsg(CFSTR("%@: %@\n"), key
, printFullDataString(circleData
));
330 CFReleaseNull(dateString
);
331 CFReleaseNull(circleData
);
332 CFReleaseSafe(circle
);
333 CFReleaseNull(dateData
);
334 CFReleaseNull(localError
);
337 printmsg(CFSTR("%@: %@\n"), key
, value
);
341 static void displayCircle(CFTypeRef key
, CFTypeRef value
)
343 CFDataRef circleData
= (CFDataRef
)value
;
345 CFErrorRef localError
= NULL
;
346 if (isData(circleData
))
349 CFNumberRef idLength
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &size
);
350 CFDictionaryRef format
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength
, NULL
);
351 SOSCircleRef circle
= SOSCircleCreateFromData(NULL
, circleData
, &localError
);
352 printmsgWithFormatOptions(format
, CFSTR("%@: %@\n"), key
, circle
);
353 CFReleaseSafe(circle
);
354 CFReleaseNull(idLength
);
355 CFReleaseNull(format
);
359 printmsg(CFSTR("%@: %@\n"), key
, value
);
362 static void displayMessage(CFTypeRef key
, CFTypeRef value
)
364 CFDataRef message
= (CFDataRef
)value
;
366 const char* messageType
= SecOTRPacketTypeString(message
);
367 printmsg(CFSTR("%@: %s: %ld\n"), key
, messageType
, CFDataGetLength(message
));
370 printmsg(CFSTR("%@: %@\n"), key
, value
);
373 static void printEverything(CFTypeRef objects
)
375 CFDictionaryForEach(objects
, ^(const void *key
, const void *value
) {
378 printmsg(CFSTR("%@: %@\n\n"), key
, printFullDataString(value
));
381 printmsg(CFSTR("%@: %@\n"), key
, value
);
386 static void decodeForKeyType(CFTypeRef key
, CFTypeRef value
, SOSKVSKeyType type
){
389 displayCircle(key
, value
);
393 displayMessage(key
, value
);
396 displayKeyParameters(key
, value
);
398 case kLastKeyParameterKey
:
399 displayLastKeyParameters(key
, value
);
402 displayLastCircle(key
, value
);
404 case kInitialSyncKey
:
405 case kAccountChangedKey
:
410 printmsg(CFSTR("%@: %@\n"), key
, value
);
415 static void decodeAllTheValues(CFTypeRef objects
){
416 SOSKVSKeyType keyType
= 0;
417 __block
bool didPrint
= false;
419 for (keyType
= 0; keyType
<= MAXKVSKEYTYPE
; keyType
++){
420 CFDictionaryForEach(objects
, ^(const void *key
, const void *value
) {
421 if(SOSKVSKeyGetKeyType(key
) == keyType
){
422 decodeForKeyType(key
, value
, keyType
);
427 printmsg(CFSTR("%@\n"), CFSTR(""));
431 static bool dumpKVS(char *itemName
, CFErrorRef
*err
)
433 CFArrayRef keysToGet
= NULL
;
436 CFStringRef itemStr
= CFStringCreateWithCString(kCFAllocatorDefault
, itemName
, kCFStringEncodingUTF8
);
437 fprintf(outFile
, "Retrieving %s from KVS\n", itemName
);
438 keysToGet
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, itemStr
, NULL
);
439 CFReleaseSafe(itemStr
);
441 dispatch_queue_t generalq
= dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL
);
442 dispatch_group_t work_group
= dispatch_group_create();
443 CFTypeRef objects
= getObjectsFromCloud(keysToGet
, generalq
, work_group
);
444 CFReleaseSafe(keysToGet
);
447 fprintf(outFile
, "All keys and values straight from KVS\n");
448 printEverything(objects
);
449 fprintf(outFile
, "\nAll values in decoded form...\n");
450 decodeAllTheValues(objects
);
452 fprintf(outFile
, "\n");
458 #define USE_NEW_SPI 1
461 static char *createDateStrNow() {
468 tmstruct
= localtime(&clock
);
471 sprintf(retval
, "%04d%02d%02d%02d%02d%02d", tmstruct
->tm_year
+1900, tmstruct
->tm_mon
+1, tmstruct
->tm_mday
, tmstruct
->tm_hour
, tmstruct
->tm_min
, tmstruct
->tm_sec
);
475 // #include <CoreFoundation/CFPriv.h>
477 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
478 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
479 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
480 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
482 static char *CFDictionaryCopyCString(CFDictionaryRef dict
, const void *key
) {
483 CFStringRef val
= CFDictionaryGetValue(dict
, key
);
484 char *retval
= CFStringToCString(val
);
490 static void sysdiagnose_dump() {
491 char *outputBase
= NULL
;
492 char *outputParent
= NULL
;
493 char *outputDir
= NULL
;
495 char *productName
= "NA";
496 char *productVersion
= "NA";
497 char *buildVersion
= "NA";
498 char *keysToRegister
= NULL
;
499 char *cloudkeychainproxy3
= NULL
;
500 char *now
= createDateStrNow();
503 CFDictionaryRef sysfdef
= _CFCopySystemVersionDictionary();
505 if(gethostname(hostname
, 80)) {
506 strcpy(hostname
, "unknownhost");
510 productName
= CFDictionaryCopyCString(sysfdef
, _kCFSystemVersionProductNameKey
);
511 productVersion
= CFDictionaryCopyCString(sysfdef
, _kCFSystemVersionProductVersionKey
);
512 buildVersion
= CFDictionaryCopyCString(sysfdef
, _kCFSystemVersionBuildVersionKey
);
515 // OUTPUTBASE=ckcdiagnose_snapshot_${HOSTNAME}_${PRODUCT_VERSION}_${NOW}
516 length
= strlen("ckcdiagnose_snapshot___") + strlen(hostname
) + strlen(productVersion
) + strlen(now
) + 1;
517 outputBase
= malloc(length
);
518 status
= snprintf(outputBase
, length
, "ckcdiagnose_snapshot_%s_%s_%s", hostname
, productVersion
, now
);
519 if(status
< 0) outputBase
= "";
521 #if TARGET_OS_EMBEDDED
522 outputParent
= "/Library/Logs/CrashReporter";
523 keysToRegister
= "/private/var/preferences/com.apple.security.cloudkeychainproxy3.keysToRegister.plist";
524 cloudkeychainproxy3
= "/var/mobile/Library/SyncedPreferences/com.apple.security.cloudkeychainproxy3.plist";
526 outputParent
= "/var/tmp";
529 struct passwd
* pwd
= getpwuid(getuid());
530 if (pwd
) homeDir
= pwd
->pw_dir
;
532 char *k2regfmt
= "%s/Library/Preferences/com.apple.security.cloudkeychainproxy3.keysToRegister.plist";
533 char *ckp3fmt
= "%s/Library/SyncedPreferences/com.apple.security.cloudkeychainproxy3.plist";
534 size_t k2rlen
= strlen(homeDir
) + strlen(k2regfmt
) + 2;
535 size_t ckp3len
= strlen(homeDir
) + strlen(ckp3fmt
) + 2;
536 keysToRegister
= malloc(k2rlen
);
537 cloudkeychainproxy3
= malloc(ckp3len
);
538 snprintf(keysToRegister
, k2rlen
, k2regfmt
, homeDir
);
539 snprintf(cloudkeychainproxy3
, ckp3len
, ckp3fmt
, homeDir
);
543 length
= strlen(outputParent
) + strlen(outputBase
) + 2;
544 outputDir
= malloc(length
);
545 status
= snprintf(outputDir
, length
, "%s/%s", outputParent
, outputBase
);
546 if(status
< 0) return;
548 mkdir(outputDir
, 0700);
550 setOutputTo(outputDir
, "sw_vers.log");
551 // report uname stuff + hostname
552 fprintf(outFile
, "HostName: %s\n", hostname
);
553 fprintf(outFile
, "ProductName: %s\n", productName
);
554 fprintf(outFile
, "ProductVersion: %s\n", productVersion
);
555 fprintf(outFile
, "BuildVersion: %s\n", buildVersion
);
558 setOutputTo(outputDir
, "syncD.log");
560 dumpKVS(optarg
, NULL
);
563 setOutputTo(outputDir
, "synci.log");
568 setOutputTo(outputDir
, "syncL.log");
573 copyFileToOutputDir(outputDir
, keysToRegister
);
574 copyFileToOutputDir(outputDir
, cloudkeychainproxy3
);
577 CFReleaseNull(sysfdef
);
578 #if ! TARGET_OS_EMBEDDED
579 free(keysToRegister
);
580 free(cloudkeychainproxy3
);
585 static void sysdiagnose_dump() {
586 SOSCCSysdiagnose(NULL
);
589 #endif /* USE_NEW_SPI */
591 static bool logmark(const char *optarg
) {
592 if(!optarg
) return false;
593 secnotice("mark", "%s", optarg
);
598 // enable, disable, accept, reject, status, Reset, Clear
600 keychain_log(int argc
, char * const *argv
)
604 " -i info (current status)"
605 " -D [itemName] dump contents of KVS"
606 " -L list all known view and their status"
607 " -s sysdiagnose log dumps"
608 " -M string place a mark in the syslog - category \"mark\""
611 setOutputTo(NULL
, NULL
);
614 CFErrorRef error
= NULL
;
615 bool hadError
= false;
617 while ((ch
= getopt(argc
, argv
, "DiLM:s")) != -1)
630 hadError
= !dumpKVS(optarg
, &error
);
634 hadError
= !listviewcmd(&error
);
638 hadError
= !logmark(optarg
);
643 return 2; /* Return 2 triggers usage message. */
647 printerr(CFSTR("Error: %@\n"), error
);