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