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_accountKeyIsTrusted = 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_accountKeyIsTrusted = SOSCCValidateUserPublic(&error);
161 if(is_accountKeyIsTrusted)
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);
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:
395 printmsg(CFSTR("%@: %@\n"), key, value);
400 static void decodeAllTheValues(CFTypeRef objects){
401 SOSKVSKeyType keyType = 0;
402 __block bool didPrint = false;
404 for (keyType = 0; keyType <= MAXKVSKEYTYPE; keyType++){
405 CFDictionaryForEach(objects, ^(const void *key, const void *value) {
406 if(SOSKVSKeyGetKeyType(key) == keyType){
407 decodeForKeyType(key, value, keyType);
412 printmsg(CFSTR("%@\n"), CFSTR(""));
416 static bool dumpKVS(char *itemName, CFErrorRef *err)
418 CFArrayRef keysToGet = NULL;
421 CFStringRef itemStr = CFStringCreateWithCString(kCFAllocatorDefault, itemName, kCFStringEncodingUTF8);
422 fprintf(outFile, "Retrieving %s from KVS\n", itemName);
423 keysToGet = CFArrayCreateForCFTypes(kCFAllocatorDefault, itemStr, NULL);
424 CFReleaseSafe(itemStr);
426 dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
427 dispatch_group_t work_group = dispatch_group_create();
428 CFTypeRef objects = getObjectsFromCloud(keysToGet, generalq, work_group);
429 CFReleaseSafe(keysToGet);
432 fprintf(outFile, "All keys and values straight from KVS\n");
433 printEverything(objects);
434 fprintf(outFile, "\nAll values in decoded form...\n");
435 decodeAllTheValues(objects);
437 fprintf(outFile, "\n");
443 #define USE_NEW_SPI 1
446 static char *createDateStrNow() {
453 tmstruct = localtime(&clock);
456 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);
460 // #include <CoreFoundation/CFPriv.h>
462 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
463 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
464 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
465 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
467 static char *CFDictionaryCopyCString(CFDictionaryRef dict, const void *key) {
468 CFStringRef val = CFDictionaryGetValue(dict, key);
469 char *retval = CFStringToCString(val);
475 static void sysdiagnose_dump() {
476 char *outputBase = NULL;
477 char *outputParent = NULL;
478 char *outputDir = NULL;
480 char *productName = "NA";
481 char *productVersion = "NA";
482 char *buildVersion = "NA";
483 char *keysToRegister = NULL;
484 char *cloudkeychainproxy3 = NULL;
485 char *now = createDateStrNow();
488 CFDictionaryRef sysfdef = _CFCopySystemVersionDictionary();
490 if(gethostname(hostname, 80)) {
491 strcpy(hostname, "unknownhost");
495 productName = CFDictionaryCopyCString(sysfdef, _kCFSystemVersionProductNameKey);
496 productVersion = CFDictionaryCopyCString(sysfdef, _kCFSystemVersionProductVersionKey);
497 buildVersion = CFDictionaryCopyCString(sysfdef, _kCFSystemVersionBuildVersionKey);
500 // OUTPUTBASE=ckcdiagnose_snapshot_${HOSTNAME}_${PRODUCT_VERSION}_${NOW}
501 length = strlen("ckcdiagnose_snapshot___") + strlen(hostname) + strlen(productVersion) + strlen(now) + 1;
502 outputBase = malloc(length);
503 status = snprintf(outputBase, length, "ckcdiagnose_snapshot_%s_%s_%s", hostname, productVersion, now);
504 if(status < 0) outputBase = "";
506 #if TARGET_OS_EMBEDDED
507 outputParent = "/Library/Logs/CrashReporter";
508 keysToRegister = "/private/var/preferences/com.apple.security.cloudkeychainproxy3.keysToRegister.plist";
509 cloudkeychainproxy3 = "/var/mobile/Library/SyncedPreferences/com.apple.security.cloudkeychainproxy3.plist";
511 outputParent = "/var/tmp";
514 struct passwd* pwd = getpwuid(getuid());
515 if (pwd) homeDir = pwd->pw_dir;
517 char *k2regfmt = "%s/Library/Preferences/com.apple.security.cloudkeychainproxy3.keysToRegister.plist";
518 char *ckp3fmt = "%s/Library/SyncedPreferences/com.apple.security.cloudkeychainproxy3.plist";
519 size_t k2rlen = strlen(homeDir) + strlen(k2regfmt) + 2;
520 size_t ckp3len = strlen(homeDir) + strlen(ckp3fmt) + 2;
521 keysToRegister = malloc(k2rlen);
522 cloudkeychainproxy3 = malloc(ckp3len);
523 snprintf(keysToRegister, k2rlen, k2regfmt, homeDir);
524 snprintf(cloudkeychainproxy3, ckp3len, ckp3fmt, homeDir);
528 length = strlen(outputParent) + strlen(outputBase) + 2;
529 outputDir = malloc(length);
530 status = snprintf(outputDir, length, "%s/%s", outputParent, outputBase);
531 if(status < 0) return;
533 mkdir(outputDir, 0700);
535 SOSLogSetOutputTo(outputDir, "sw_vers.log");
536 // report uname stuff + hostname
537 fprintf(outFile, "HostName: %s\n", hostname);
538 fprintf(outFile, "ProductName: %s\n", productName);
539 fprintf(outFile, "ProductVersion: %s\n", productVersion);
540 fprintf(outFile, "BuildVersion: %s\n", buildVersion);
543 SOSLogSetOutputTo(outputDir, "syncD.log");
545 dumpKVS(optarg, NULL);
548 SOSLogSetOutputTo(outputDir, "synci.log");
553 SOSLogSetOutputTo(outputDir, "syncL.log");
558 copyFileToOutputDir(outputDir, keysToRegister);
559 copyFileToOutputDir(outputDir, cloudkeychainproxy3);
562 CFReleaseNull(sysfdef);
563 #if ! TARGET_OS_EMBEDDED
564 free(keysToRegister);
565 free(cloudkeychainproxy3);
570 static void sysdiagnose_dump() {
571 SOSCCSysdiagnose(NULL);
574 #endif /* USE_NEW_SPI */
576 static bool logmark(const char *optarg) {
577 if(!optarg) return false;
578 secnotice("mark", "%s", optarg);
583 // enable, disable, accept, reject, status, Reset, Clear
585 keychain_log(int argc, char * const *argv)
589 " -i info (current status)"
590 " -D [itemName] dump contents of KVS"
591 " -L list all known view and their status"
592 " -s sysdiagnose log dumps"
593 " -M string place a mark in the syslog - category \"mark\""
596 SOSLogSetOutputTo(NULL, NULL);
599 CFErrorRef error = NULL;
600 bool hadError = false;
602 while ((ch = getopt(argc, argv, "DiLM:s")) != -1)
615 hadError = !dumpKVS(optarg, &error);
619 hadError = !listviewcmd(&error);
623 hadError = !logmark(optarg);
628 return 2; /* Return 2 triggers usage message. */
632 printerr(CFSTR("Error: %@\n"), error);