]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/Tool/accountCirclesViewsPrint.m
Security-59306.101.1.tar.gz
[apple/security.git] / keychain / SecureObjectSync / Tool / accountCirclesViewsPrint.m
1 //
2 // accountCirclesViewsPrint.c
3 // Security
4 //
5 // Created by Richard Murphy on 12/8/16.
6 //
7 //
8
9 #include "accountCirclesViewsPrint.h"
10
11 //
12 // SOSSysdiagnose.c
13 // sec
14 //
15 // Created by Richard Murphy on 1/27/16.
16 //
17 //
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/utsname.h>
25 #include <sys/stat.h>
26 #include <time.h>
27 #include <notify.h>
28 #include <pwd.h>
29
30 #include <Security/SecItem.h>
31
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <CoreFoundation/CFPriv.h>
34
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"
45
46 #include <utilities/SecCFWrappers.h>
47 #include <utilities/debugging.h>
48
49 #include "SecurityTool/sharedTool/readline.h"
50
51 #include "keychain_log.h"
52 #include "secToolFileIO.h"
53 #include "secViewDisplay.h"
54
55
56 #include <Security/SecPasswordGenerate.h>
57
58 #define MAXKVSKEYTYPE kUnknownKey
59 #define DATE_LENGTH 18
60
61 #include <utilities/SecCFWrappers.h>
62
63
64 static const char *getSOSCCStatusDescription(SOSCCStatus ccstatus)
65 {
66 switch (ccstatus)
67 {
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";
73
74 default:
75 return "<unknown ccstatus>";
76 break;
77 }
78 }
79
80 static const char *
81 getSOSCCLastDepartureReasonDescription(enum DepartureReason reason)
82 {
83 switch (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);
94 #undef CASE_REASON
95 default:
96 return "Unknown";
97 }
98 }
99
100 static void printPeerInfos(char *label, CFStringRef mypeerID, CFArrayRef (^copyPeers)(CFErrorRef *error)) {
101 CFErrorRef error = NULL;
102 CFArrayRef ppi = copyPeers(&error);
103
104 if(ppi) {
105 printmsg(CFSTR("%s count: %ld\n"), label, (long)CFArrayGetCount(ppi));
106 CFArrayForEach(ppi, ^(const void *value) {
107 char buf[160];
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;
118 if(gestalt) {
119 osVersion = CFDictionaryGetValue(gestalt, CFSTR("OSVersion"));
120 } else {
121 osVersion = CFSTR("Unknown");
122 }
123
124 if(SOSPeerInfoVersionHasV2Data(peer)){
125 CFDictionaryRef v2Dictionary = peer->v2Dictionary;
126 if(v2Dictionary) {
127 transportType = CFDictionaryGetValue(v2Dictionary, CFSTR("TransportType"));
128 deviceID = CFDictionaryGetValue(v2Dictionary, CFSTR("DeviceID"));
129 machineID = CFDictionaryGetValue(v2Dictionary, CFSTR("MachineIDKey"));
130 }
131 }
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>" : " ";
138
139
140 snprintf(buf, 160, "%s %s: %-16s dev:%-16s trn:%-16s devid:%-36s mid: %-36s", me, label, pname, dname, tname, iname, mname);
141
142 free(pname);
143 free(dname);
144 free(tname);
145 free(iname);
146 free(mname);
147
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 printmsg(CFSTR("%@ pid:%@ V%d OS:%@\n"), bufstr, pid, vers, osVersion ?: CFSTR(""));
153 CFRelease(bufstr);
154
155 CFReleaseNull(gestalt);
156 });
157 } else {
158 printmsg(CFSTR("No %s, error: %@\n"), label, error);
159 }
160 CFReleaseNull(ppi);
161 CFReleaseNull(error);
162 }
163
164 void SOSCCDumpCircleInformation()
165 {
166 CFErrorRef error = NULL;
167 CFArrayRef generations = NULL;
168 bool is_accountKeyIsTrusted = false;
169 __block int count = 0;
170
171
172 SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error);
173 printmsg(CFSTR("ccstatus: %s (%d)\n"), getSOSCCStatusDescription(ccstatus), ccstatus);
174 if (error != NULL) {
175 printmsg(CFSTR("Error checking circle status: %@\n"), error);
176 }
177 CFReleaseNull(error);
178
179 enum DepartureReason departureReason = SOSCCGetLastDepartureReason(&error);
180 printmsg(CFSTR("LastDepartureReason: %s (%d)\n"), getSOSCCLastDepartureReasonDescription(departureReason), departureReason);
181 if (error != NULL) {
182 printmsg(CFSTR("Error checking last departure reason error: %@\n"), error);
183 }
184 CFReleaseNull(error);
185
186 is_accountKeyIsTrusted = SOSCCValidateUserPublic(&error);
187 if(is_accountKeyIsTrusted)
188 printmsg(CFSTR("Account user public is trusted\n"));
189 else
190 printmsg(CFSTR("Account user public is not trusted error:(%@)\n"), error);
191 CFReleaseNull(error);
192
193 generations = SOSCCCopyGenerationPeerInfo(&error);
194 if(generations) {
195 CFArrayForEach(generations, ^(const void *value) {
196 count++;
197 if(count%2 == 0)
198 printmsg(CFSTR("Circle name: %@, "),value);
199
200 if(count%2 != 0) {
201 CFStringRef genDesc = SOSGenerationCountCopyDescription(value);
202 printmsg(CFSTR("Generation Count: %@"), genDesc);
203 CFReleaseNull(genDesc);
204 }
205 printmsg(CFSTR("%s\n"), "");
206 });
207 } else {
208 printmsg(CFSTR("No generation count: %@\n"), error);
209 }
210 CFReleaseNull(generations);
211 CFReleaseNull(error);
212
213 SOSPeerInfoRef me = SOSCCCopyMyPeerInfo(NULL);
214 CFStringRef mypeerID = SOSPeerInfoGetPeerID(me);
215
216 printPeerInfos(" Peers", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyValidPeerPeerInfo(error); });
217 printPeerInfos(" Invalid", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyNotValidPeerPeerInfo(error); });
218 printPeerInfos(" Retired", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyRetirementPeerInfo(error); });
219 printPeerInfos(" Concur", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyConcurringPeerPeerInfo(error); });
220 printPeerInfos("Applicants", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyApplicantPeerInfo(error); });
221
222 CFReleaseNull(me);
223 CFReleaseNull(error);
224 }
225
226 void
227 SOSCCDumpEngineInformation(void)
228 {
229 CFErrorRef error = NULL;
230
231 printmsg(CFSTR("Engine state:\n"));
232 if (!SOSCCForEachEngineStateAsString(&error, ^(CFStringRef oneStateString) {
233 printmsg(CFSTR("%@\n"), oneStateString);
234 })) {
235 printmsg(CFSTR("No engine state, got error: %@\n"), error);
236 }
237 }
238
239 // security sync -o
240 void
241 SOSCCDumpViewUnwarePeers(void)
242 {
243 SOSPeerInfoRef me = SOSCCCopyMyPeerInfo(NULL);
244 CFStringRef mypeerID = SOSPeerInfoGetPeerID(me);
245
246 printPeerInfos("view-unaware", mypeerID, ^(CFErrorRef *error) { return SOSCCCopyViewUnawarePeerInfo(error); });
247
248 CFReleaseNull(me);
249 }
250
251 /* KVS Dumping Support for iCloud Keychain */
252
253 static CFTypeRef getObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, dispatch_group_t dgroup)
254 {
255 __block CFTypeRef object = NULL;
256
257 const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
258 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
259 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
260
261 dispatch_group_enter(dgroup);
262
263 CloudKeychainReplyBlock replyBlock =
264 ^ (CFDictionaryRef returnedValues, CFErrorRef error)
265 {
266 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues);
267 object = returnedValues;
268 if (object)
269 CFRetain(object);
270 if (error)
271 {
272 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error);
273 }
274 dispatch_group_leave(dgroup);
275 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object);
276 dispatch_semaphore_signal(waitSemaphore);
277 };
278
279 if (!keysToGet)
280 SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock);
281 else
282 SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock);
283
284 dispatch_semaphore_wait(waitSemaphore, finishTime);
285 if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull
286 {
287 CFRelease(object);
288 object = NULL;
289 }
290 secerror("returned: %@", object);
291 return object;
292 }
293
294 static CFStringRef printFullDataString(CFDataRef data){
295 __block CFStringRef fullData = NULL;
296
297 BufferPerformWithHexString(CFDataGetBytePtr(data), CFDataGetLength(data), ^(CFStringRef dataHex) {
298 fullData = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), dataHex);
299 });
300
301 return fullData;
302 }
303
304 static void displayLastKeyParameters(CFTypeRef key, CFTypeRef value)
305 {
306 CFDataRef valueAsData = asData(value, NULL);
307 if(valueAsData){
308 CFDataRef dateData = CFDataCreateCopyFromRange(kCFAllocatorDefault, valueAsData, CFRangeMake(0, DATE_LENGTH));
309 CFDataRef keyParameterData = CFDataCreateCopyFromPositions(kCFAllocatorDefault, valueAsData, DATE_LENGTH, CFDataGetLength(valueAsData));
310 CFStringRef dateString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, dateData, kCFStringEncodingUTF8);
311 CFStringRef keyParameterDescription = UserParametersDescription(keyParameterData);
312 if(keyParameterDescription)
313 printmsg(CFSTR("%@: %@: %@\n"), key, dateString, keyParameterDescription);
314 else
315 printmsg(CFSTR("%@: %@\n"), key, printFullDataString(value));
316 CFReleaseNull(dateString);
317 CFReleaseNull(keyParameterData);
318 CFReleaseNull(dateData);
319 CFReleaseNull(keyParameterDescription);
320 }
321 else{
322 printmsg(CFSTR("%@: %@\n"), key, value);
323 }
324 }
325
326 static void displayKeyParameters(CFTypeRef key, CFTypeRef value)
327 {
328 if(isData(value)){
329 CFStringRef keyParameterDescription = UserParametersDescription((CFDataRef)value);
330
331 if(keyParameterDescription)
332 printmsg(CFSTR("%@: %@\n"), key, keyParameterDescription);
333 else
334 printmsg(CFSTR("%@: %@\n"), key, value);
335
336 CFReleaseNull(keyParameterDescription);
337 }
338 else{
339 printmsg(CFSTR("%@: %@\n"), key, value);
340 }
341 }
342
343 static void displayLastCircle(CFTypeRef key, CFTypeRef value)
344 {
345 CFDataRef valueAsData = asData(value, NULL);
346 if(valueAsData){
347 CFErrorRef localError = NULL;
348
349 CFDataRef dateData = CFDataCreateCopyFromRange(kCFAllocatorDefault, valueAsData, CFRangeMake(0, DATE_LENGTH));
350 CFDataRef circleData = CFDataCreateCopyFromPositions(kCFAllocatorDefault, valueAsData, DATE_LENGTH, CFDataGetLength(valueAsData));
351 CFStringRef dateString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, dateData, kCFStringEncodingUTF8);
352 SOSCircleRef circle = SOSCircleCreateFromData(NULL, (CFDataRef) circleData, &localError);
353
354 if(circle){
355 CFIndex size = 5;
356 CFNumberRef idLength = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &size);
357 CFDictionaryRef format = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength, NULL);
358 printmsgWithFormatOptions(format, CFSTR("%@: %@: %@\n"), key, dateString, circle);
359 CFReleaseNull(idLength);
360 CFReleaseNull(format);
361
362 }
363 else
364 printmsg(CFSTR("%@: %@\n"), key, printFullDataString(circleData));
365
366 CFReleaseNull(dateString);
367 CFReleaseNull(circleData);
368 CFReleaseSafe(circle);
369 CFReleaseNull(dateData);
370 CFReleaseNull(localError);
371 }
372 else{
373 printmsg(CFSTR("%@: %@\n"), key, value);
374 }
375 }
376
377 static void displayCircle(CFTypeRef key, CFTypeRef value)
378 {
379 CFDataRef circleData = (CFDataRef)value;
380
381 CFErrorRef localError = NULL;
382 if (isData(circleData))
383 {
384 CFIndex size = 5;
385 CFNumberRef idLength = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &size);
386 CFDictionaryRef format = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength, NULL);
387 SOSCircleRef circle = SOSCircleCreateFromData(NULL, circleData, &localError);
388 printmsgWithFormatOptions(format, CFSTR("%@: %@\n"), key, circle);
389 CFReleaseSafe(circle);
390 CFReleaseNull(idLength);
391 CFReleaseNull(format);
392
393 }
394 else
395 printmsg(CFSTR("%@: %@\n"), key, value);
396 }
397
398 static void displayMessage(CFTypeRef key, CFTypeRef value)
399 {
400 CFDataRef message = (CFDataRef)value;
401 if(isData(message)){
402 const char* messageType = SecOTRPacketTypeString(message);
403 printmsg(CFSTR("%@: %s: %ld\n"), key, messageType, CFDataGetLength(message));
404 }
405 else
406 printmsg(CFSTR("%@: %@\n"), key, value);
407 }
408
409 static void printEverything(CFTypeRef objects)
410 {
411 CFDictionaryForEach(objects, ^(const void *key, const void *value) {
412 if (isData(value))
413 {
414 printmsg(CFSTR("%@: %@\n\n"), key, printFullDataString(value));
415 }
416 else
417 printmsg(CFSTR("%@: %@\n"), key, value);
418 });
419
420 }
421
422 static void decodeForKeyType(CFTypeRef key, CFTypeRef value, SOSKVSKeyType type){
423 switch (type) {
424 case kCircleKey:
425 displayCircle(key, value);
426 break;
427 case kRetirementKey:
428 case kMessageKey:
429 displayMessage(key, value);
430 break;
431 case kParametersKey:
432 displayKeyParameters(key, value);
433 break;
434 case kLastKeyParameterKey:
435 displayLastKeyParameters(key, value);
436 break;
437 case kLastCircleKey:
438 displayLastCircle(key, value);
439 break;
440 case kInitialSyncKey:
441 case kAccountChangedKey:
442 case kDebugInfoKey:
443 case kRingKey:
444 default:
445 printmsg(CFSTR("%@: %@\n"), key, value);
446 break;
447 }
448 }
449
450 static void decodeAllTheValues(CFTypeRef objects){
451 SOSKVSKeyType keyType = 0;
452 __block bool didPrint = false;
453
454 for (keyType = 0; keyType <= MAXKVSKEYTYPE; keyType++){
455 CFDictionaryForEach(objects, ^(const void *key, const void *value) {
456 if(SOSKVSKeyGetKeyType(key) == keyType){
457 decodeForKeyType(key, value, keyType);
458 didPrint = true;
459 }
460 });
461 if(didPrint)
462 printmsg(CFSTR("%@\n"), CFSTR(""));
463 didPrint = false;
464 }
465 }
466
467 bool SOSCCDumpCircleKVSInformation(char *itemName) {
468 CFArrayRef keysToGet = NULL;
469 if (itemName)
470 {
471 CFStringRef itemStr = CFStringCreateWithCString(kCFAllocatorDefault, itemName, kCFStringEncodingUTF8);
472 fprintf(outFile, "Retrieving %s from KVS\n", itemName);
473 keysToGet = CFArrayCreateForCFTypes(kCFAllocatorDefault, itemStr, NULL);
474 CFReleaseSafe(itemStr);
475 }
476 dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
477 dispatch_group_t work_group = dispatch_group_create();
478 CFTypeRef objects = getObjectsFromCloud(keysToGet, generalq, work_group);
479 CFReleaseSafe(keysToGet);
480 if (objects)
481 {
482 fprintf(outFile, "All keys and values straight from KVS\n");
483 printEverything(objects);
484 fprintf(outFile, "\nAll values in decoded form...\n");
485 decodeAllTheValues(objects);
486 }
487 fprintf(outFile, "\n");
488 return true;
489 }