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 bool is_user_public_trusted
= false;
151 __block
int count
= 0;
153 SOSCCStatus ccstatus
= SOSCCThisDeviceIsInCircle(&error
);
154 if(ccstatus
== kSOSCCError
) {
155 printmsg(CFSTR("End of Dump - unable to proceed due to ccstatus (%s) error: %@\n"), getSOSCCStatusDescription(ccstatus
), error
);
158 printmsg(CFSTR("ccstatus: %s (%d)\n"), getSOSCCStatusDescription(ccstatus
), ccstatus
, error
);
160 is_user_public_trusted
= SOSCCValidateUserPublic(&error
);
161 if(is_user_public_trusted
)
162 printmsg(CFSTR("Account user public is trusted%@"),CFSTR("\n"));
164 printmsg(CFSTR("Account user public is not trusted error:(%@)\n"), error
);
165 CFReleaseNull(error
);
167 generations
= SOSCCCopyGenerationPeerInfo(&error
);
169 CFArrayForEach(generations
, ^(const void *value
) {
172 printmsg(CFSTR("Circle name: %@, "),value
);
175 CFStringRef genDesc
= SOSGenerationCountCopyDescription(value
);
176 printmsg(CFSTR("Generation Count: %@"), genDesc
);
177 CFReleaseNull(genDesc
);
179 printmsg(CFSTR("%s\n"), "");
182 printmsg(CFSTR("No generation count: %@\n"), error
);
184 CFReleaseNull(generations
);
185 CFReleaseNull(error
);
187 printPeerInfos(" Peers", ^(CFErrorRef
*error
) { return SOSCCCopyValidPeerPeerInfo(error
); });
188 printPeerInfos(" Invalid", ^(CFErrorRef
*error
) { return SOSCCCopyNotValidPeerPeerInfo(error
); });
189 printPeerInfos(" Retired", ^(CFErrorRef
*error
) { return SOSCCCopyRetirementPeerInfo(error
); });
190 printPeerInfos(" Concur", ^(CFErrorRef
*error
) { return SOSCCCopyConcurringPeerPeerInfo(error
); });
191 printPeerInfos("Applicants", ^(CFErrorRef
*error
) { return SOSCCCopyApplicantPeerInfo(error
); });
193 if (!SOSCCForEachEngineStateAsString(&error
, ^(CFStringRef oneStateString
) {
194 printmsg(CFSTR("%@\n"), oneStateString
);
196 printmsg(CFSTR("No engine peers: %@\n"), error
);
199 CFReleaseNull(error
);
202 static CFTypeRef
getObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
204 __block CFTypeRef object
= NULL
;
206 const uint64_t maxTimeToWaitInSeconds
= 30ull * NSEC_PER_SEC
;
207 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
208 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
210 dispatch_group_enter(dgroup
);
212 CloudKeychainReplyBlock replyBlock
=
213 ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
215 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues
);
216 object
= returnedValues
;
221 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error
);
223 dispatch_group_leave(dgroup
);
224 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object
);
225 dispatch_semaphore_signal(waitSemaphore
);
229 SOSCloudKeychainGetAllObjectsFromCloud(processQueue
, replyBlock
);
231 SOSCloudKeychainGetObjectsFromCloud(keysToGet
, processQueue
, replyBlock
);
233 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
234 dispatch_release(waitSemaphore
);
235 if (object
&& (CFGetTypeID(object
) == CFNullGetTypeID())) // return a NULL instead of a CFNull
240 secerror("returned: %@", object
);
244 static CFStringRef
printFullDataString(CFDataRef data
){
245 __block CFStringRef fullData
= NULL
;
247 BufferPerformWithHexString(CFDataGetBytePtr(data
), CFDataGetLength(data
), ^(CFStringRef dataHex
) {
248 fullData
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@"), dataHex
);
254 static void displayLastKeyParameters(CFTypeRef key
, CFTypeRef value
)
256 CFDataRef valueAsData
= asData(value
, NULL
);
258 CFDataRef dateData
= CFDataCreateCopyFromRange(kCFAllocatorDefault
, valueAsData
, CFRangeMake(0, DATE_LENGTH
));
259 CFDataRef keyParameterData
= CFDataCreateCopyFromPositions(kCFAllocatorDefault
, valueAsData
, DATE_LENGTH
, CFDataGetLength(valueAsData
));
260 CFStringRef dateString
= CFStringCreateFromExternalRepresentation(kCFAllocatorDefault
, dateData
, kCFStringEncodingUTF8
);
261 CFStringRef keyParameterDescription
= UserParametersDescription(keyParameterData
);
262 if(keyParameterDescription
)
263 printmsg(CFSTR("%@: %@: %@\n"), key
, dateString
, keyParameterDescription
);
265 printmsg(CFSTR("%@: %@\n"), key
, printFullDataString(value
));
266 CFReleaseNull(dateString
);
267 CFReleaseNull(keyParameterData
);
268 CFReleaseNull(dateData
);
269 CFReleaseNull(keyParameterDescription
);
272 printmsg(CFSTR("%@: %@\n"), key
, value
);
276 static void displayKeyParameters(CFTypeRef key
, CFTypeRef value
)
279 CFStringRef keyParameterDescription
= UserParametersDescription((CFDataRef
)value
);
281 if(keyParameterDescription
)
282 printmsg(CFSTR("%@: %@\n"), key
, keyParameterDescription
);
284 printmsg(CFSTR("%@: %@\n"), key
, value
);
286 CFReleaseNull(keyParameterDescription
);
289 printmsg(CFSTR("%@: %@\n"), key
, value
);
293 static void displayLastCircle(CFTypeRef key
, CFTypeRef value
)
295 CFDataRef valueAsData
= asData(value
, NULL
);
297 CFErrorRef localError
= NULL
;
299 CFDataRef dateData
= CFDataCreateCopyFromRange(kCFAllocatorDefault
, valueAsData
, CFRangeMake(0, DATE_LENGTH
));
300 CFDataRef circleData
= CFDataCreateCopyFromPositions(kCFAllocatorDefault
, valueAsData
, DATE_LENGTH
, CFDataGetLength(valueAsData
));
301 CFStringRef dateString
= CFStringCreateFromExternalRepresentation(kCFAllocatorDefault
, dateData
, kCFStringEncodingUTF8
);
302 SOSCircleRef circle
= SOSCircleCreateFromData(NULL
, (CFDataRef
) circleData
, &localError
);
306 CFNumberRef idLength
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &size
);
307 CFDictionaryRef format
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength
, NULL
);
308 printmsgWithFormatOptions(format
, CFSTR("%@: %@: %@\n"), key
, dateString
, circle
);
309 CFReleaseNull(idLength
);
310 CFReleaseNull(format
);
314 printmsg(CFSTR("%@: %@\n"), key
, printFullDataString(circleData
));
316 CFReleaseNull(dateString
);
317 CFReleaseNull(circleData
);
318 CFReleaseSafe(circle
);
319 CFReleaseNull(dateData
);
320 CFReleaseNull(localError
);
323 printmsg(CFSTR("%@: %@\n"), key
, value
);
327 static void displayCircle(CFTypeRef key
, CFTypeRef value
)
329 CFDataRef circleData
= (CFDataRef
)value
;
331 CFErrorRef localError
= NULL
;
332 if (isData(circleData
))
335 CFNumberRef idLength
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &size
);
336 CFDictionaryRef format
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength
, NULL
);
337 SOSCircleRef circle
= SOSCircleCreateFromData(NULL
, circleData
, &localError
);
338 printmsgWithFormatOptions(format
, CFSTR("%@: %@\n"), key
, circle
);
339 CFReleaseSafe(circle
);
340 CFReleaseNull(idLength
);
341 CFReleaseNull(format
);
345 printmsg(CFSTR("%@: %@\n"), key
, value
);
348 static void displayMessage(CFTypeRef key
, CFTypeRef value
)
350 CFDataRef message
= (CFDataRef
)value
;
352 const char* messageType
= SecOTRPacketTypeString(message
);
353 printmsg(CFSTR("%@: %s: %ld\n"), key
, messageType
, CFDataGetLength(message
));
356 printmsg(CFSTR("%@: %@\n"), key
, value
);
359 static void printEverything(CFTypeRef objects
)
361 CFDictionaryForEach(objects
, ^(const void *key
, const void *value
) {
364 printmsg(CFSTR("%@: %@\n\n"), key
, printFullDataString(value
));
367 printmsg(CFSTR("%@: %@\n"), key
, value
);
372 static void decodeForKeyType(CFTypeRef key
, CFTypeRef value
, SOSKVSKeyType type
){
375 displayCircle(key
, value
);
379 displayMessage(key
, value
);
382 displayKeyParameters(key
, value
);
384 case kLastKeyParameterKey
:
385 displayLastKeyParameters(key
, value
);
388 displayLastCircle(key
, value
);
390 case kInitialSyncKey
:
391 case kAccountChangedKey
:
396 printmsg(CFSTR("%@: %@\n"), key
, value
);
401 static void decodeAllTheValues(CFTypeRef objects
){
402 SOSKVSKeyType keyType
= 0;
403 __block
bool didPrint
= false;
405 for (keyType
= 0; keyType
<= MAXKVSKEYTYPE
; keyType
++){
406 CFDictionaryForEach(objects
, ^(const void *key
, const void *value
) {
407 if(SOSKVSKeyGetKeyType(key
) == keyType
){
408 decodeForKeyType(key
, value
, keyType
);
413 printmsg(CFSTR("%@\n"), CFSTR(""));
417 static bool dumpKVS(char *itemName
, CFErrorRef
*err
)
419 CFArrayRef keysToGet
= NULL
;
422 CFStringRef itemStr
= CFStringCreateWithCString(kCFAllocatorDefault
, itemName
, kCFStringEncodingUTF8
);
423 fprintf(outFile
, "Retrieving %s from KVS\n", itemName
);
424 keysToGet
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, itemStr
, NULL
);
425 CFReleaseSafe(itemStr
);
427 dispatch_queue_t generalq
= dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL
);
428 dispatch_group_t work_group
= dispatch_group_create();
429 CFTypeRef objects
= getObjectsFromCloud(keysToGet
, generalq
, work_group
);
430 CFReleaseSafe(keysToGet
);
433 fprintf(outFile
, "All keys and values straight from KVS\n");
434 printEverything(objects
);
435 fprintf(outFile
, "\nAll values in decoded form...\n");
436 decodeAllTheValues(objects
);
438 fprintf(outFile
, "\n");
444 #define USE_NEW_SPI 1
447 static char *createDateStrNow() {
454 tmstruct
= localtime(&clock
);
457 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
);
461 // #include <CoreFoundation/CFPriv.h>
463 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
464 CF_EXPORT
const CFStringRef _kCFSystemVersionProductNameKey
;
465 CF_EXPORT
const CFStringRef _kCFSystemVersionProductVersionKey
;
466 CF_EXPORT
const CFStringRef _kCFSystemVersionBuildVersionKey
;
468 static char *CFDictionaryCopyCString(CFDictionaryRef dict
, const void *key
) {
469 CFStringRef val
= CFDictionaryGetValue(dict
, key
);
470 char *retval
= CFStringToCString(val
);
476 static void sysdiagnose_dump() {
477 char *outputBase
= NULL
;
478 char *outputParent
= NULL
;
479 char *outputDir
= NULL
;
481 char *productName
= "NA";
482 char *productVersion
= "NA";
483 char *buildVersion
= "NA";
484 char *keysToRegister
= NULL
;
485 char *cloudkeychainproxy3
= NULL
;
486 char *now
= createDateStrNow();
489 CFDictionaryRef sysfdef
= _CFCopySystemVersionDictionary();
491 if(gethostname(hostname
, 80)) {
492 strcpy(hostname
, "unknownhost");
496 productName
= CFDictionaryCopyCString(sysfdef
, _kCFSystemVersionProductNameKey
);
497 productVersion
= CFDictionaryCopyCString(sysfdef
, _kCFSystemVersionProductVersionKey
);
498 buildVersion
= CFDictionaryCopyCString(sysfdef
, _kCFSystemVersionBuildVersionKey
);
501 // OUTPUTBASE=ckcdiagnose_snapshot_${HOSTNAME}_${PRODUCT_VERSION}_${NOW}
502 length
= strlen("ckcdiagnose_snapshot___") + strlen(hostname
) + strlen(productVersion
) + strlen(now
) + 1;
503 outputBase
= malloc(length
);
504 status
= snprintf(outputBase
, length
, "ckcdiagnose_snapshot_%s_%s_%s", hostname
, productVersion
, now
);
505 if(status
< 0) outputBase
= "";
507 #if TARGET_OS_EMBEDDED
508 outputParent
= "/Library/Logs/CrashReporter";
509 keysToRegister
= "/private/var/preferences/com.apple.security.cloudkeychainproxy3.keysToRegister.plist";
510 cloudkeychainproxy3
= "/var/mobile/Library/SyncedPreferences/com.apple.security.cloudkeychainproxy3.plist";
512 outputParent
= "/var/tmp";
515 struct passwd
* pwd
= getpwuid(getuid());
516 if (pwd
) homeDir
= pwd
->pw_dir
;
518 char *k2regfmt
= "%s/Library/Preferences/com.apple.security.cloudkeychainproxy3.keysToRegister.plist";
519 char *ckp3fmt
= "%s/Library/SyncedPreferences/com.apple.security.cloudkeychainproxy3.plist";
520 size_t k2rlen
= strlen(homeDir
) + strlen(k2regfmt
) + 2;
521 size_t ckp3len
= strlen(homeDir
) + strlen(ckp3fmt
) + 2;
522 keysToRegister
= malloc(k2rlen
);
523 cloudkeychainproxy3
= malloc(ckp3len
);
524 snprintf(keysToRegister
, k2rlen
, k2regfmt
, homeDir
);
525 snprintf(cloudkeychainproxy3
, ckp3len
, ckp3fmt
, homeDir
);
529 length
= strlen(outputParent
) + strlen(outputBase
) + 2;
530 outputDir
= malloc(length
);
531 status
= snprintf(outputDir
, length
, "%s/%s", outputParent
, outputBase
);
532 if(status
< 0) return;
534 mkdir(outputDir
, 0700);
536 SOSLogSetOutputTo(outputDir
, "sw_vers.log");
537 // report uname stuff + hostname
538 fprintf(outFile
, "HostName: %s\n", hostname
);
539 fprintf(outFile
, "ProductName: %s\n", productName
);
540 fprintf(outFile
, "ProductVersion: %s\n", productVersion
);
541 fprintf(outFile
, "BuildVersion: %s\n", buildVersion
);
544 SOSLogSetOutputTo(outputDir
, "syncD.log");
546 dumpKVS(optarg
, NULL
);
549 SOSLogSetOutputTo(outputDir
, "synci.log");
554 SOSLogSetOutputTo(outputDir
, "syncL.log");
559 copyFileToOutputDir(outputDir
, keysToRegister
);
560 copyFileToOutputDir(outputDir
, cloudkeychainproxy3
);
563 CFReleaseNull(sysfdef
);
564 #if ! TARGET_OS_EMBEDDED
565 free(keysToRegister
);
566 free(cloudkeychainproxy3
);
571 static void sysdiagnose_dump() {
572 SOSCCSysdiagnose(NULL
);
575 #endif /* USE_NEW_SPI */
577 static bool logmark(const char *optarg
) {
578 if(!optarg
) return false;
579 secnotice("mark", "%s", optarg
);
584 // enable, disable, accept, reject, status, Reset, Clear
586 keychain_log(int argc
, char * const *argv
)
590 " -i info (current status)"
591 " -D [itemName] dump contents of KVS"
592 " -L list all known view and their status"
593 " -s sysdiagnose log dumps"
594 " -M string place a mark in the syslog - category \"mark\""
597 SOSLogSetOutputTo(NULL
, NULL
);
600 CFErrorRef error
= NULL
;
601 bool hadError
= false;
603 while ((ch
= getopt(argc
, argv
, "DiLM:s")) != -1)
616 hadError
= !dumpKVS(optarg
, &error
);
620 hadError
= !listviewcmd(&error
);
624 hadError
= !logmark(optarg
);
629 return 2; /* Return 2 triggers usage message. */
633 printerr(CFSTR("Error: %@\n"), error
);