]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSSysdiagnose.c
3becdc528b93d45c0dae94dcbaa3baeb56e92340
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSSysdiagnose.c
1 //
2 // SOSSysdiagnose.c
3 // sec
4 //
5 // Created by Richard Murphy on 1/27/16.
6 //
7 //
8
9
10 #include "SOSCloudCircleInternal.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <sys/utsname.h>
16 #include <sys/stat.h>
17 #include <time.h>
18 #include <notify.h>
19 #include <pwd.h>
20
21 #include <Security/SecItem.h>
22
23 #include <CoreFoundation/CFNumber.h>
24 #include <CoreFoundation/CFString.h>
25
26 #include <Security/SecureObjectSync/SOSCloudCircle.h>
27 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
28 #include <Security/SecureObjectSync/SOSPeerInfo.h>
29 #include <Security/SecureObjectSync/SOSPeerInfoPriv.h>
30 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
31 #include <Security/SecureObjectSync/SOSUserKeygen.h>
32 #include <Security/SecureObjectSync/SOSKVSKeys.h>
33 #include <securityd/SOSCloudCircleServer.h>
34 #include <Security/SecOTRSession.h>
35 #include <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
36
37 #include <utilities/SecCFWrappers.h>
38 #include <utilities/debugging.h>
39
40 #include <SecurityTool/readline.h>
41
42 #include "keychain_log.h"
43 #include "secToolFileIO.h"
44
45 #include <Security/SecPasswordGenerate.h>
46
47 /* Copied from CFPriv.h */
48 // #include <CoreFoundation/CFPriv.h>
49
50 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
51 CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
52 CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
53 CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
54
55
56
57 static char *CFDictionaryCopyCString(CFDictionaryRef dict, const void *key) {
58 CFStringRef val = CFDictionaryGetValue(dict, key);
59 char *retval = CFStringToCString(val);
60 return retval;
61 }
62
63
64
65 #define MAXKVSKEYTYPE kUnknownKey
66 #define DATE_LENGTH 18
67
68 //
69 // secToolFileIO.c
70 // sec
71 //
72 // Created by Richard Murphy on 1/22/16.
73 //
74 //
75
76 #include <copyfile.h>
77 #include <libgen.h>
78 #include <utilities/SecCFWrappers.h>
79
80 #define printmsg(format, ...) _printcfmsg(outFile, NULL, format, __VA_ARGS__)
81 #define printmsgWithFormatOptions(formatOptions, format, ...) _printcfmsg(outFile, formatOptions, format, __VA_ARGS__)
82 #define printerr(format, ...) _printcfmsg(errFile, NULL, format, __VA_ARGS__)
83
84
85 FILE *outFile = NULL;
86 FILE *errFile = NULL;
87
88 void _printcfmsg(FILE *ff, CFDictionaryRef formatOptions, CFStringRef format, ...)
89 {
90 va_list args;
91 va_start(args, format);
92 CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, formatOptions, format, args);
93 va_end(args);
94 CFStringPerformWithCString(message, ^(const char *utf8String) { fprintf(ff, utf8String, ""); });
95 CFRelease(message);
96 }
97
98
99 int setOutputTo(char *dir, char *filename) {
100 size_t pathlen = 0;
101
102 if(dir && filename) {
103 pathlen = strlen(dir) + strlen(filename) + 2;
104 char path[pathlen];
105 snprintf(path, pathlen, "%s/%s", dir, filename);
106 outFile = fopen(path, "a");
107 } else if(dir || filename) {
108 outFile = stdout;
109 return -1;
110 } else {
111 outFile = stdout;
112 }
113 errFile = stderr;
114 return 0;
115 }
116
117 void closeOutput(void) {
118 if(outFile != stdout) {
119 fclose(outFile);
120 }
121 outFile = stdout;
122 }
123
124 int copyFileToOutputDir(char *dir, char *toCopy) {
125 char *bname = basename(toCopy);
126 char destpath[256];
127 int status;
128 copyfile_state_t cpfilestate = copyfile_state_alloc();
129
130 status = snprintf(destpath, 256, "%s/%s", dir, bname);
131 if(status < 0 || status > 256) return -1;
132
133 int retval = copyfile(toCopy, destpath, cpfilestate, COPYFILE_ALL);
134
135 copyfile_state_free(cpfilestate);
136 return retval;
137 }
138
139
140
141 static const char *getSOSCCStatusDescription(SOSCCStatus ccstatus)
142 {
143 switch (ccstatus)
144 {
145 case kSOSCCInCircle: return "In Circle";
146 case kSOSCCNotInCircle: return "Not in Circle";
147 case kSOSCCRequestPending: return "Request pending";
148 case kSOSCCCircleAbsent: return "Circle absent";
149 case kSOSCCError: return "Circle error";
150
151 default:
152 return "<unknown ccstatus>";
153 break;
154 }
155 }
156
157 static void printPeerInfos(char *label, CFArrayRef (^getArray)(CFErrorRef *error)) {
158 CFErrorRef error = NULL;
159 CFArrayRef ppi = getArray(&error);
160 SOSPeerInfoRef me = SOSCCCopyMyPeerInfo(NULL);
161 CFStringRef mypeerID = SOSPeerInfoGetPeerID(me);
162
163 if(ppi) {
164 printmsg(CFSTR("%s count: %ld\n"), label, (long)CFArrayGetCount(ppi));
165 CFArrayForEach(ppi, ^(const void *value) {
166 char buf[160];
167 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
168 CFIndex version = SOSPeerInfoGetVersion(peer);
169 CFStringRef peerName = SOSPeerInfoGetPeerName(peer);
170 CFStringRef devtype = SOSPeerInfoGetPeerDeviceType(peer);
171 CFStringRef peerID = SOSPeerInfoGetPeerID(peer);
172 CFStringRef transportType = CFSTR("KVS");
173 CFStringRef deviceID = CFSTR("");
174 CFDictionaryRef gestalt = SOSPeerInfoCopyPeerGestalt(peer);
175 CFStringRef osVersion = CFDictionaryGetValue(gestalt, CFSTR("OSVersion"));
176 CFReleaseNull(gestalt);
177
178
179 if(version >= 2){
180 CFDictionaryRef v2Dictionary = peer->v2Dictionary;
181 transportType = CFDictionaryGetValue(v2Dictionary, sTransportType);
182 deviceID = CFDictionaryGetValue(v2Dictionary, sDeviceID);
183 }
184 char *pname = CFStringToCString(peerName);
185 char *dname = CFStringToCString(devtype);
186 char *tname = CFStringToCString(transportType);
187 char *iname = CFStringToCString(deviceID);
188 char *osname = CFStringToCString(osVersion);
189 const char *me = CFEqualSafe(mypeerID, peerID) ? "me>" : " ";
190
191
192 snprintf(buf, 160, "%s %s: %-16s %-16s %-16s %-16s", me, label, pname, dname, tname, iname);
193
194 free(pname);
195 free(dname);
196 CFStringRef pid = SOSPeerInfoGetPeerID(peer);
197 CFIndex vers = SOSPeerInfoGetVersion(peer);
198 printmsg(CFSTR("%s %@ V%d OS:%s\n"), buf, pid, vers, osname);
199 free(osname);
200 });
201 } else {
202 printmsg(CFSTR("No %s, error: %@\n"), label, error);
203 }
204 CFReleaseNull(ppi);
205 CFReleaseNull(error);
206 }
207
208 static void dumpCircleInfo()
209 {
210 CFErrorRef error = NULL;
211 CFArrayRef generations = NULL;
212 CFArrayRef confirmedDigests = NULL;
213 bool is_user_public_trusted = false;
214 __block int count = 0;
215
216 SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error);
217 if(ccstatus == kSOSCCError) {
218 printmsg(CFSTR("End of Dump - unable to proceed due to ccstatus (%s) error: %@\n"), getSOSCCStatusDescription(ccstatus), error);
219 return;
220 }
221 printmsg(CFSTR("ccstatus: %s (%d)\n"), getSOSCCStatusDescription(ccstatus), ccstatus, error);
222
223 is_user_public_trusted = SOSCCValidateUserPublic(&error);
224 if(is_user_public_trusted)
225 printmsg(CFSTR("Account user public is trusted%@"),CFSTR("\n"));
226 else
227 printmsg(CFSTR("Account user public is not trusted error:(%@)\n"), error);
228 CFReleaseNull(error);
229
230 generations = SOSCCCopyGenerationPeerInfo(&error);
231 if(generations) {
232 CFArrayForEach(generations, ^(const void *value) {
233 count++;
234 if(count%2 == 0)
235 printmsg(CFSTR("Circle name: %@, "),value);
236
237 if(count%2 != 0) {
238 CFStringRef genDesc = SOSGenerationCountCopyDescription(value);
239 printmsg(CFSTR("Generation Count: %@"), genDesc);
240 CFReleaseNull(genDesc);
241 }
242 printmsg(CFSTR("%s\n"), "");
243 });
244 } else {
245 printmsg(CFSTR("No generation count: %@\n"), error);
246 }
247 CFReleaseNull(generations);
248 CFReleaseNull(error);
249
250 printPeerInfos(" Peers", ^(CFErrorRef *error) { return SOSCCCopyValidPeerPeerInfo(error); });
251 printPeerInfos(" Invalid", ^(CFErrorRef *error) { return SOSCCCopyNotValidPeerPeerInfo(error); });
252 printPeerInfos(" Retired", ^(CFErrorRef *error) { return SOSCCCopyRetirementPeerInfo(error); });
253 printPeerInfos(" Concur", ^(CFErrorRef *error) { return SOSCCCopyConcurringPeerPeerInfo(error); });
254 printPeerInfos("Applicants", ^(CFErrorRef *error) { return SOSCCCopyApplicantPeerInfo(error); });
255
256 confirmedDigests = SOSCCCopyEngineState(&error);
257 if(confirmedDigests)
258 {
259 count = 0;
260 CFArrayForEach(confirmedDigests, ^(const void *value) {
261 count++;
262 if(count % 2 != 0)
263 printmsg(CFSTR("%@"), value);
264
265 if(count % 2 == 0) {
266 CFStringRef hexDigest = CFDataCopyHexString(value);
267 printmsg(CFSTR(" %@\n"), hexDigest);
268 CFReleaseSafe(hexDigest);
269 }
270 });
271 }
272 else
273 printmsg(CFSTR("No engine peers: %@\n"), error);
274 CFReleaseNull(confirmedDigests);
275 }
276
277 static CFTypeRef getObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, dispatch_group_t dgroup)
278 {
279 __block CFTypeRef object = NULL;
280
281 const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
282 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
283 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
284
285 dispatch_group_enter(dgroup);
286
287 CloudKeychainReplyBlock replyBlock =
288 ^ (CFDictionaryRef returnedValues, CFErrorRef error)
289 {
290 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues);
291 object = returnedValues;
292 if (object)
293 CFRetain(object);
294 if (error)
295 {
296 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error);
297 // CFRelease(*error);
298 }
299 dispatch_group_leave(dgroup);
300 secinfo("sync", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object);
301 dispatch_semaphore_signal(waitSemaphore);
302 };
303
304 if (!keysToGet)
305 SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock);
306 else
307 SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock);
308
309 dispatch_semaphore_wait(waitSemaphore, finishTime);
310 dispatch_release(waitSemaphore);
311 if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull
312 {
313 CFRelease(object);
314 object = NULL;
315 }
316 secerror("returned: %@", object);
317 return object;
318 }
319
320 static CFStringRef printFullDataString(CFDataRef data){
321 __block CFStringRef fullData = NULL;
322
323 BufferPerformWithHexString(CFDataGetBytePtr(data), CFDataGetLength(data), ^(CFStringRef dataHex) {
324 fullData = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), dataHex);
325 });
326
327 return fullData;
328 }
329
330 static void displayLastKeyParameters(CFTypeRef key, CFTypeRef value)
331 {
332 CFDataRef valueAsData = asData(value, NULL);
333 if(valueAsData){
334 CFDataRef dateData = CFDataCreateCopyFromRange(kCFAllocatorDefault, valueAsData, CFRangeMake(0, DATE_LENGTH));
335 CFDataRef keyParameterData = CFDataCreateCopyFromPositions(kCFAllocatorDefault, valueAsData, DATE_LENGTH, CFDataGetLength(valueAsData));
336 CFStringRef dateString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, dateData, kCFStringEncodingUTF8);
337 CFStringRef keyParameterDescription = UserParametersDescription(keyParameterData);
338 if(keyParameterDescription)
339 printmsg(CFSTR("%@: %@: %@\n"), key, dateString, keyParameterDescription);
340 else
341 printmsg(CFSTR("%@: %@\n"), key, printFullDataString(value));
342 CFReleaseNull(dateString);
343 CFReleaseNull(keyParameterData);
344 CFReleaseNull(dateData);
345 CFReleaseNull(keyParameterDescription);
346 }
347 else{
348 printmsg(CFSTR("%@: %@\n"), key, value);
349 }
350 }
351
352 static void displayKeyParameters(CFTypeRef key, CFTypeRef value)
353 {
354 if(isData(value)){
355 CFStringRef keyParameterDescription = UserParametersDescription((CFDataRef)value);
356
357 if(keyParameterDescription)
358 printmsg(CFSTR("%@: %@\n"), key, keyParameterDescription);
359 else
360 printmsg(CFSTR("%@: %@\n"), key, value);
361
362 CFReleaseNull(keyParameterDescription);
363 }
364 else{
365 printmsg(CFSTR("%@: %@\n"), key, value);
366 }
367 }
368
369 static void displayLastCircle(CFTypeRef key, CFTypeRef value)
370 {
371 CFDataRef valueAsData = asData(value, NULL);
372 if(valueAsData){
373 CFErrorRef localError = NULL;
374
375 CFDataRef dateData = CFDataCreateCopyFromRange(kCFAllocatorDefault, valueAsData, CFRangeMake(0, DATE_LENGTH));
376 CFDataRef circleData = CFDataCreateCopyFromPositions(kCFAllocatorDefault, valueAsData, DATE_LENGTH, CFDataGetLength(valueAsData));
377 CFStringRef dateString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, dateData, kCFStringEncodingUTF8);
378 SOSCircleRef circle = SOSCircleCreateFromData(NULL, (CFDataRef) circleData, &localError);
379
380 if(circle){
381 CFIndex size = 5;
382 CFNumberRef idLength = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &size);
383 CFDictionaryRef format = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength, NULL);
384 printmsgWithFormatOptions(format, CFSTR("%@: %@: %@\n"), key, dateString, circle);
385 CFReleaseNull(idLength);
386 CFReleaseNull(format);
387
388 }
389 else
390 printmsg(CFSTR("%@: %@\n"), key, printFullDataString(circleData));
391
392 CFReleaseNull(dateString);
393 CFReleaseNull(circleData);
394 CFReleaseSafe(circle);
395 CFReleaseNull(dateData);
396 CFReleaseNull(localError);
397 }
398 else{
399 printmsg(CFSTR("%@: %@\n"), key, value);
400 }
401 }
402
403 static void displayCircle(CFTypeRef key, CFTypeRef value)
404 {
405 CFDataRef circleData = (CFDataRef)value;
406
407 CFErrorRef localError = NULL;
408 if (isData(circleData))
409 {
410 CFIndex size = 5;
411 CFNumberRef idLength = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &size);
412 CFDictionaryRef format = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("SyncD"), CFSTR("SyncD"), CFSTR("idLength"), idLength, NULL);
413 SOSCircleRef circle = SOSCircleCreateFromData(NULL, circleData, &localError);
414 printmsgWithFormatOptions(format, CFSTR("%@: %@\n"), key, circle);
415 CFReleaseSafe(circle);
416 CFReleaseNull(idLength);
417 CFReleaseNull(format);
418
419 }
420 else
421 printmsg(CFSTR("%@: %@\n"), key, value);
422 }
423
424 static void displayMessage(CFTypeRef key, CFTypeRef value)
425 {
426 CFDataRef message = (CFDataRef)value;
427 if(isData(message)){
428 const char* messageType = SecOTRPacketTypeString(message);
429 printmsg(CFSTR("%@: %s: %ld\n"), key, messageType, CFDataGetLength(message));
430 }
431 else
432 printmsg(CFSTR("%@: %@\n"), key, value);
433 }
434
435 static void printEverything(CFTypeRef objects)
436 {
437 CFDictionaryForEach(objects, ^(const void *key, const void *value) {
438 if (isData(value))
439 {
440 printmsg(CFSTR("%@: %@\n\n"), key, printFullDataString(value));
441 }
442 else
443 printmsg(CFSTR("%@: %@\n"), key, value);
444 });
445
446 }
447
448 static void decodeForKeyType(CFTypeRef key, CFTypeRef value, SOSKVSKeyType type){
449 switch (type) {
450 case kCircleKey:
451 displayCircle(key, value);
452 break;
453 case kRetirementKey:
454 case kMessageKey:
455 displayMessage(key, value);
456 break;
457 case kParametersKey:
458 displayKeyParameters(key, value);
459 break;
460 case kLastKeyParameterKey:
461 displayLastKeyParameters(key, value);
462 break;
463 case kLastCircleKey:
464 displayLastCircle(key, value);
465 break;
466 case kInitialSyncKey:
467 case kAccountChangedKey:
468 case kDebugInfoKey:
469 case kRingKey:
470 case kPeerInfoKey:
471 default:
472 printmsg(CFSTR("%@: %@\n"), key, value);
473 break;
474 }
475 }
476
477 static void decodeAllTheValues(CFTypeRef objects){
478 SOSKVSKeyType keyType = 0;
479 __block bool didPrint = false;
480
481 for (keyType = 0; keyType <= MAXKVSKEYTYPE; keyType++){
482 CFDictionaryForEach(objects, ^(const void *key, const void *value) {
483 if(SOSKVSKeyGetKeyType(key) == keyType){
484 decodeForKeyType(key, value, keyType);
485 didPrint = true;
486 }
487 });
488 if(didPrint)
489 printmsg(CFSTR("%@\n"), CFSTR(""));
490 didPrint = false;
491 }
492 }
493 static bool dumpKVS(char *itemName, CFErrorRef *err)
494 {
495 CFArrayRef keysToGet = NULL;
496 if (itemName)
497 {
498 CFStringRef itemStr = CFStringCreateWithCString(kCFAllocatorDefault, itemName, kCFStringEncodingUTF8);
499 fprintf(outFile, "Retrieving %s from KVS\n", itemName);
500 keysToGet = CFArrayCreateForCFTypes(kCFAllocatorDefault, itemStr, NULL);
501 CFReleaseSafe(itemStr);
502 }
503 dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
504 dispatch_group_t work_group = dispatch_group_create();
505 CFTypeRef objects = getObjectsFromCloud(keysToGet, generalq, work_group);
506 CFReleaseSafe(keysToGet);
507 if (objects)
508 {
509 fprintf(outFile, "All keys and values straight from KVS\n");
510 printEverything(objects);
511 fprintf(outFile, "\nAll values in decoded form...\n");
512 decodeAllTheValues(objects);
513 }
514 fprintf(outFile, "\n");
515 return true;
516 }
517
518
519 static struct foo {
520 const char *name;
521 const CFStringRef *viewspec;
522 } string2View[] = {
523 {
524 "keychain", &kSOSViewKeychainV0
525 }, {
526 "masterkey", &kSOSViewPCSMasterKey,
527 }, {
528 "iclouddrive", &kSOSViewPCSiCloudDrive,
529 }, {
530 "photos", &kSOSViewPCSPhotos,
531 }, {
532 "escrow", &kSOSViewPCSEscrow,
533 }, {
534 "fde", &kSOSViewPCSFDE,
535 }, {
536 "maildrop", &kSOSViewPCSMailDrop,
537 }, {
538 "icloudbackup", &kSOSViewPCSiCloudBackup,
539 }, {
540 "notes", &kSOSViewPCSNotes,
541 }, {
542 "imessage", &kSOSViewPCSiMessage,
543 }, {
544 "feldspar", &kSOSViewPCSFeldspar,
545 }, {
546 "appletv", &kSOSViewAppleTV,
547 }, {
548 "homekit", &kSOSViewHomeKit,
549 }, {
550 "wifi", &kSOSViewWiFi,
551 }, {
552 "passwords", &kSOSViewAutofillPasswords,
553 }, {
554 "creditcards", &kSOSViewSafariCreditCards,
555 }, {
556 "icloudidentity", &kSOSViewiCloudIdentity,
557 }, {
558 "othersyncable", &kSOSViewOtherSyncable,
559 }
560 };
561
562 static CFStringRef convertViewReturnCodeToString(SOSViewActionCode ac) {
563 CFStringRef retval = NULL;
564 switch(ac) {
565 case kSOSCCGeneralViewError:
566 retval = CFSTR("General Error"); break;
567 case kSOSCCViewMember:
568 retval = CFSTR("Is Member of View"); break;
569 case kSOSCCViewNotMember:
570 retval = CFSTR("Is Not Member of View"); break;
571 case kSOSCCViewNotQualified:
572 retval = CFSTR("Is not qualified for View"); break;
573 case kSOSCCNoSuchView:
574 retval = CFSTR("No Such View"); break;
575 }
576 return retval;
577 }
578
579 static bool listviewcmd(CFErrorRef *err) {
580 unsigned n;
581
582 for (n = 0; n < sizeof(string2View)/sizeof(string2View[0]); n++) {
583 CFStringRef viewspec = *string2View[n].viewspec;
584
585 SOSViewResultCode rc = SOSCCView(viewspec, kSOSCCViewQuery, err);
586 CFStringRef resultString = convertViewReturnCodeToString(rc);
587
588 printmsg(CFSTR("View Result: %@ : %@\n"), resultString, viewspec);
589 };
590
591 return true;
592 }
593
594
595 static char *createDateStrNow() {
596 char *retval = NULL;
597 time_t clock;
598
599 struct tm *tmstruct;
600
601 time(&clock);
602 tmstruct = localtime(&clock);
603
604 retval = malloc(15);
605 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);
606 return retval;
607 }
608
609 #if !TARGET_OS_EMBEDDED
610 static char *assemblePath(char *dir, char *fname) {
611 size_t length = strlen(dir) + strlen(fname) + 2;
612 char *outputDir = malloc(length);
613 int status = snprintf(outputDir, length, "%s/%s", dir, fname);
614 if(status < 0) return NULL;
615 return outputDir;
616 }
617
618 static char *homedirPath() {
619 char *homeDir = "";
620 struct passwd* pwd = getpwuid(getuid());
621 if (pwd) homeDir = pwd->pw_dir;
622 return homeDir;
623 }
624 #endif
625
626 static char *sysdiagnose_dir(const char *passedIn, const char *hostname, const char *productVersion, const char *now) {
627 if(passedIn) return (char *) passedIn;
628
629 // OUTPUTBASE=ckcdiagnose_snapshot_${HOSTNAME}_${PRODUCT_VERSION}_${NOW}
630 char *outputParent = NULL;
631 size_t length = strlen("ckcdiagnose_snapshot___") + strlen(hostname) + strlen(productVersion) + strlen(now) + 1;
632 char *outputBase = malloc(length);
633 int status = snprintf(outputBase, length, "ckcdiagnose_snapshot_%s_%s_%s", hostname, productVersion, now);
634 if(status < 0) outputBase = "";
635
636 #if TARGET_OS_EMBEDDED
637 outputParent = "/Library/Logs/CrashReporter";
638 #else
639 outputParent = "/var/tmp";
640 #endif
641 length = strlen(outputParent) + strlen(outputBase) + 2;
642 char *outputDir = malloc(length);
643 status = snprintf(outputDir, length, "%s/%s", outputParent, outputBase);
644 if(status < 0) return NULL;
645 return outputDir;
646 }
647
648
649
650 static char *sysdiagnose_dump(const char *dirname) {
651 char *outputDir = NULL;
652 char hostname[80];
653 char *productName = NULL;
654 char *productVersion = NULL;
655 char *buildVersion = NULL;
656 char *keysToRegister = NULL;
657 char *cloudkeychainproxy3 = NULL;
658 char *now = createDateStrNow();
659
660 CFDictionaryRef sysfdef = _CFCopySystemVersionDictionary();
661 if(sysfdef) {
662 productName = CFDictionaryCopyCString(sysfdef, _kCFSystemVersionProductNameKey);
663 productVersion = CFDictionaryCopyCString(sysfdef, _kCFSystemVersionProductVersionKey);
664 buildVersion = CFDictionaryCopyCString(sysfdef, _kCFSystemVersionBuildVersionKey);
665 }
666 if (productName == NULL)
667 productName = strdup("unknownProduct");
668 if (productVersion == NULL)
669 productVersion = strdup("unknownProductVersion");
670 if (buildVersion)
671 buildVersion = strdup("unknownVersion");
672
673 if(gethostname(hostname, 80)) {
674 strcpy(hostname, "unknownhost");
675 }
676
677 #if TARGET_OS_EMBEDDED
678 keysToRegister = "/private/var/preferences/com.apple.security.cloudkeychainproxy3.keysToRegister.plist";
679 cloudkeychainproxy3 = "/var/mobile/Library/SyncedPreferences/com.apple.security.cloudkeychainproxy3.plist";
680 #else
681 char *homeDir = homedirPath();
682 keysToRegister = assemblePath(homeDir, "Library/Preferences/com.apple.security.cloudkeychainproxy3.keysToRegister.plist");
683 cloudkeychainproxy3 = assemblePath(homeDir, "Library/SyncedPreferences/com.apple.security.cloudkeychainproxy3.plist");
684 #endif
685
686 outputDir = sysdiagnose_dir(dirname, hostname, productVersion, now);
687 if(!outputDir) return NULL;
688
689 mkdir(outputDir, 0700);
690
691 setOutputTo(outputDir, "sw_vers.log");
692 // report uname stuff + hostname
693 fprintf(outFile, "HostName: %s\n", hostname);
694 fprintf(outFile, "ProductName: %s\n", productName);
695 fprintf(outFile, "ProductVersion: %s\n", productVersion);
696 fprintf(outFile, "BuildVersion: %s\n", buildVersion);
697 closeOutput();
698
699 setOutputTo(outputDir, "syncD.log");
700 // do sync -D
701 dumpKVS(optarg, NULL);
702 closeOutput();
703
704 setOutputTo(outputDir, "synci.log");
705 // do sync -i
706 dumpCircleInfo();
707 closeOutput();
708
709 setOutputTo(outputDir, "syncL.log");
710 // do sync -L
711 listviewcmd(NULL);
712 closeOutput();
713
714 copyFileToOutputDir(outputDir, keysToRegister);
715 copyFileToOutputDir(outputDir, cloudkeychainproxy3);
716
717 if(productName) free(productName);
718 if(productVersion) free(productVersion);
719 if(buildVersion) free(buildVersion);
720
721 free(now);
722 CFReleaseNull(sysfdef);
723 #if ! TARGET_OS_EMBEDDED
724 free(keysToRegister);
725 free(cloudkeychainproxy3);
726 #endif
727 return outputDir;
728 }
729
730
731 char *SOSCCSysdiagnose(const char *directoryname) {
732 sysdiagnose_dump(directoryname);
733 return NULL;
734 }
735