2 // accountCirclesViewsPrint.c
5 // Created by Richard Murphy on 12/8/16.
9 #include "accountCirclesViewsPrint.h"
15 // Created by Richard Murphy on 1/27/16.
24 #include <sys/utsname.h>
30 #include <Security/SecItem.h>
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFPriv.h>
35 #include <Security/SecureObjectSync/SOSCloudCircle.h>
36 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
37 #include <Security/SecureObjectSync/SOSPeerInfo.h>
38 #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
39 #include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
40 #include "keychain/SecureObjectSync/SOSUserKeygen.h"
41 #include "keychain/SecureObjectSync/SOSKVSKeys.h"
42 #include "keychain/securityd/SOSCloudCircleServer.h"
43 #include <Security/SecOTRSession.h>
44 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
46 #include <utilities/SecCFWrappers.h>
47 #include <utilities/debugging.h>
49 #include "SecurityTool/sharedTool/readline.h"
51 #include "keychain_log.h"
52 #include "secToolFileIO.h"
53 #include "secViewDisplay.h"
56 #include <Security/SecPasswordGenerate.h>
58 #define MAXKVSKEYTYPE kUnknownKey
59 #define DATE_LENGTH 18
61 #include <utilities/SecCFWrappers.h>
64 static const char *getSOSCCStatusDescription(SOSCCStatus ccstatus)
68 case kSOSCCInCircle: return "In Circle";
69 case kSOSCCNotInCircle: return "Not in Circle";
70 case kSOSCCRequestPending: return "Request pending";
71 case kSOSCCCircleAbsent: return "Circle absent";
72 case kSOSCCError: return "Circle error";
75 return "<unknown ccstatus>";
81 getSOSCCLastDepartureReasonDescription(enum DepartureReason reason)
84 #define CASE_REASON(x) case kSOS##x: return #x
85 CASE_REASON(DepartureReasonError);
86 CASE_REASON(NeverLeftCircle);
87 CASE_REASON(WithdrewMembership);
88 CASE_REASON(MembershipRevoked);
89 CASE_REASON(LeftUntrustedCircle);
90 CASE_REASON(NeverAppliedToCircle);
91 CASE_REASON(DiscoveredRetirement); // we should all be so lucky
92 CASE_REASON(LostPrivateKey);
93 CASE_REASON(PasswordChanged);
100 static void printPeerInfos(char *label, CFStringRef mypeerID, CFArrayRef (^copyPeers)(CFErrorRef *error)) {
101 CFErrorRef error = NULL;
102 CFArrayRef ppi = copyPeers(&error);
105 printmsg(CFSTR("%s count: %ld\n"), label, (long)CFArrayGetCount(ppi));
106 CFArrayForEach(ppi, ^(const void *value) {
108 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
109 if(!peer) { return; }
110 CFStringRef peerName = SOSPeerInfoGetPeerName(peer);
111 CFStringRef devtype = SOSPeerInfoGetPeerDeviceType(peer);
112 CFStringRef peerID = SOSPeerInfoGetPeerID(peer);
113 CFStringRef transportType = CFSTR("KVS");
114 CFStringRef deviceID = CFSTR("");
115 CFStringRef machineID = CFSTR("");
116 CFDictionaryRef gestalt = SOSPeerInfoCopyPeerGestalt(peer);
117 CFStringRef osVersion = NULL;
119 osVersion = CFDictionaryGetValue(gestalt, CFSTR("OSVersion"));
121 osVersion = CFSTR("Unknown");
124 if(SOSPeerInfoVersionHasV2Data(peer)){
125 CFDictionaryRef v2Dictionary = peer->v2Dictionary;
127 transportType = CFDictionaryGetValue(v2Dictionary, CFSTR("TransportType"));
128 deviceID = CFDictionaryGetValue(v2Dictionary, CFSTR("DeviceID"));
129 machineID = CFDictionaryGetValue(v2Dictionary, CFSTR("MachineIDKey"));
132 char *pname = CFStringToCString(peerName);
133 char *dname = CFStringToCString(devtype);
134 char *tname = CFStringToCString(transportType);
135 char *iname = CFStringToCString(deviceID);
136 char *mname = CFStringToCString(machineID);
137 const char *me = CFEqualSafe(mypeerID, peerID) ? "me>" : " ";
140 snprintf(buf, 160, "%s %s: %-16s dev:%-16s trn:%-16s devid:%-36s mid: %-36s", me, label, pname, dname, tname, iname, mname);
148 // %s in (Core)Foundation format strings treats the string as MacRoman, need to do this to guarantee UTF8 handling
149 CFStringRef bufstr = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
150 CFStringRef pid = SOSPeerInfoGetPeerID(peer);
151 CFIndex vers = SOSPeerInfoGetVersion(peer);
152 bool isCKKSForAll = SOSPeerInfoSupportsCKKSForAll(peer);
153 printmsg(CFSTR("%@ pid:%@ V%d %@ OS:%@\n"), bufstr, pid, vers, isCKKSForAll ? CFSTR("c4a") : CFSTR("SOS"), osVersion ?: CFSTR(""));
156 CFReleaseNull(gestalt);
159 printmsg(CFSTR("No %s, error: %@\n"), label, error);
162 CFReleaseNull(error);
165 void SOSCCDumpCircleInformation()
167 CFErrorRef error = NULL;
168 CFArrayRef generations = NULL;
169 bool is_accountKeyIsTrusted = false;
170 __block int count = 0;
173 SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error);
174 printmsg(CFSTR("ccstatus: %s (%d)\n"), getSOSCCStatusDescription(ccstatus), ccstatus);
176 printmsg(CFSTR("Error checking circle status: %@\n"), error);
178 CFReleaseNull(error);
180 enum DepartureReason departureReason = SOSCCGetLastDepartureReason(&error);
181 printmsg(CFSTR("LastDepartureReason: %s (%d)\n"), getSOSCCLastDepartureReasonDescription(departureReason), departureReason);
183 printmsg(CFSTR("Error checking last departure reason error: %@\n"), error);
185 CFReleaseNull(error);
187 is_accountKeyIsTrusted = SOSCCValidateUserPublic(&error);
188 if(is_accountKeyIsTrusted)
189 printmsg(CFSTR("Account user public is trusted\n"));
191 printmsg(CFSTR("Account user public is not trusted error:(%@)\n"), error);
192 CFReleaseNull(error);
194 generations = SOSCCCopyGenerationPeerInfo(&error);
196 CFArrayForEach(generations, ^(const void *value) {
199 printmsg(CFSTR("Circle name: %@, "),value);
202 CFStringRef genDesc = SOSGenerationCountCopyDescription(value);
203 printmsg(CFSTR("Generation Count: %@"), genDesc);
204 CFReleaseNull(genDesc);
206 printmsg(CFSTR("%s\n"), "");
209 printmsg(CFSTR("No generation count: %@\n"), error);
211 CFReleaseNull(generations);
212 CFReleaseNull(error);
214 SOSPeerInfoRef me = SOSCCCopyMyPeerInfo(NULL);
215 CFStringRef mypeerID = SOSPeerInfoGetPeerID(me);
217 printPeerInfos(" Peers", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyValidPeerPeerInfo(error); });
218 printPeerInfos(" Invalid", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyNotValidPeerPeerInfo(error); });
219 printPeerInfos(" Retired", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyRetirementPeerInfo(error); });
220 printPeerInfos(" Concur", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyConcurringPeerPeerInfo(error); });
221 printPeerInfos("Applicants", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyApplicantPeerInfo(error); });
224 CFReleaseNull(error);
228 SOSCCDumpEngineInformation(void)
230 CFErrorRef error = NULL;
232 printmsg(CFSTR("Engine state:\n"));
233 if (!SOSCCForEachEngineStateAsString(&error, ^(CFStringRef oneStateString) {
234 printmsg(CFSTR("%@\n"), oneStateString);
236 printmsg(CFSTR("No engine state, got error: %@\n"), error);
242 SOSCCDumpViewUnwarePeers(void)
244 SOSPeerInfoRef me = SOSCCCopyMyPeerInfo(NULL);
245 CFStringRef mypeerID = SOSPeerInfoGetPeerID(me);
247 printPeerInfos("view-unaware", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyViewUnawarePeerInfo(error); });
252 /* KVS Dumping Support for iCloud Keychain */
254 static CFTypeRef getObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, dispatch_group_t dgroup)
256 __block CFTypeRef object = NULL;
258 const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
259 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
260 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
262 dispatch_group_enter(dgroup);
264 CloudKeychainReplyBlock replyBlock =
265 ^ (CFDictionaryRef returnedValues, CFErrorRef error)
267 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues);
268 object = returnedValues;
273 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error);
275 dispatch_group_leave(dgroup);
276 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object);
277 dispatch_semaphore_signal(waitSemaphore);
281 SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock);
283 SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock);
285 dispatch_semaphore_wait(waitSemaphore, finishTime);
286 if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull
291 secerror("returned: %@", object);
295 static CFStringRef printFullDataString(CFDataRef data){
296 __block CFStringRef fullData = NULL;
298 BufferPerformWithHexString(CFDataGetBytePtr(data), CFDataGetLength(data), ^(CFStringRef dataHex) {
299 fullData = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), dataHex);
305 static void displayLastKeyParameters(CFTypeRef key, CFTypeRef value)
307 CFDataRef valueAsData = asData(value, NULL);
309 CFDataRef dateData = CFDataCreateCopyFromRange(kCFAllocatorDefault, valueAsData, CFRangeMake(0, DATE_LENGTH));
310 CFDataRef keyParameterData = CFDataCreateCopyFromPositions(kCFAllocatorDefault, valueAsData, DATE_LENGTH, CFDataGetLength(valueAsData));
311 CFStringRef dateString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, dateData, kCFStringEncodingUTF8);
312 CFStringRef keyParameterDescription = UserParametersDescription(keyParameterData);
313 if(keyParameterDescription)
314 printmsg(CFSTR("%@: %@: %@\n"), key, dateString, keyParameterDescription);
316 printmsg(CFSTR("%@: %@\n"), key, printFullDataString(value));
317 CFReleaseNull(dateString);
318 CFReleaseNull(keyParameterData);
319 CFReleaseNull(dateData);
320 CFReleaseNull(keyParameterDescription);
323 printmsg(CFSTR("%@: %@\n"), key, value);
327 static void displayKeyParameters(CFTypeRef key, CFTypeRef value)
330 CFStringRef keyParameterDescription = UserParametersDescription((CFDataRef)value);
332 if(keyParameterDescription)
333 printmsg(CFSTR("%@: %@\n"), key, keyParameterDescription);
335 printmsg(CFSTR("%@: %@\n"), key, value);
337 CFReleaseNull(keyParameterDescription);
340 printmsg(CFSTR("%@: %@\n"), key, value);
344 static void displayLastCircle(CFTypeRef key, CFTypeRef value)
346 CFDataRef valueAsData = asData(value, NULL);
348 CFErrorRef localError = NULL;
350 CFDataRef dateData = CFDataCreateCopyFromRange(kCFAllocatorDefault, valueAsData, CFRangeMake(0, DATE_LENGTH));
351 CFDataRef circleData = CFDataCreateCopyFromPositions(kCFAllocatorDefault, valueAsData, DATE_LENGTH, CFDataGetLength(valueAsData));
352 CFStringRef dateString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, dateData, kCFStringEncodingUTF8);
353 SOSCircleRef circle = SOSCircleCreateFromData(NULL, (CFDataRef) circleData, &localError);
357 CFNumberRef idLength = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &size);
358 CFDictionaryRef format = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength, NULL);
359 printmsgWithFormatOptions(format, CFSTR("%@: %@: %@\n"), key, dateString, circle);
360 CFReleaseNull(idLength);
361 CFReleaseNull(format);
365 printmsg(CFSTR("%@: %@\n"), key, printFullDataString(circleData));
367 CFReleaseNull(dateString);
368 CFReleaseNull(circleData);
369 CFReleaseSafe(circle);
370 CFReleaseNull(dateData);
371 CFReleaseNull(localError);
374 printmsg(CFSTR("%@: %@\n"), key, value);
378 static void displayCircle(CFTypeRef key, CFTypeRef value)
380 CFDataRef circleData = (CFDataRef)value;
382 CFErrorRef localError = NULL;
383 if (isData(circleData))
386 CFNumberRef idLength = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &size);
387 CFDictionaryRef format = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength, NULL);
388 SOSCircleRef circle = SOSCircleCreateFromData(NULL, circleData, &localError);
389 printmsgWithFormatOptions(format, CFSTR("%@: %@\n"), key, circle);
390 CFReleaseSafe(circle);
391 CFReleaseNull(idLength);
392 CFReleaseNull(format);
396 printmsg(CFSTR("%@: %@\n"), key, value);
399 static void displayMessage(CFTypeRef key, CFTypeRef value)
401 CFDataRef message = (CFDataRef)value;
403 const char* messageType = SecOTRPacketTypeString(message);
404 printmsg(CFSTR("%@: %s: %ld\n"), key, messageType, CFDataGetLength(message));
407 printmsg(CFSTR("%@: %@\n"), key, value);
410 static void printEverything(CFTypeRef objects)
412 CFDictionaryForEach(objects, ^(const void *key, const void *value) {
415 printmsg(CFSTR("%@: %@\n\n"), key, printFullDataString(value));
418 printmsg(CFSTR("%@: %@\n"), key, value);
423 static void decodeForKeyType(CFTypeRef key, CFTypeRef value, SOSKVSKeyType type){
426 displayCircle(key, value);
430 displayMessage(key, value);
433 displayKeyParameters(key, value);
435 case kLastKeyParameterKey:
436 displayLastKeyParameters(key, value);
439 displayLastCircle(key, value);
441 case kInitialSyncKey:
442 case kAccountChangedKey:
446 printmsg(CFSTR("%@: %@\n"), key, value);
451 static void decodeAllTheValues(CFTypeRef objects){
452 SOSKVSKeyType keyType = 0;
453 __block bool didPrint = false;
455 for (keyType = 0; keyType <= MAXKVSKEYTYPE; keyType++){
456 CFDictionaryForEach(objects, ^(const void *key, const void *value) {
457 if(SOSKVSKeyGetKeyType(key) == keyType){
458 decodeForKeyType(key, value, keyType);
463 printmsg(CFSTR("%@\n"), CFSTR(""));
468 bool SOSCCDumpCircleKVSInformation(char *itemName) {
469 CFArrayRef keysToGet = NULL;
472 CFStringRef itemStr = CFStringCreateWithCString(kCFAllocatorDefault, itemName, kCFStringEncodingUTF8);
473 fprintf(outFile, "Retrieving %s from KVS\n", itemName);
474 keysToGet = CFArrayCreateForCFTypes(kCFAllocatorDefault, itemStr, NULL);
475 CFReleaseSafe(itemStr);
477 dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
478 dispatch_group_t work_group = dispatch_group_create();
479 CFTypeRef objects = getObjectsFromCloud(keysToGet, generalq, work_group);
480 CFReleaseSafe(keysToGet);
483 fprintf(outFile, "All keys and values straight from KVS\n");
484 printEverything(objects);
485 fprintf(outFile, "\nAll values in decoded form...\n");
486 decodeAllTheValues(objects);
488 fprintf(outFile, "\n");