]>
Commit | Line | Data |
---|---|---|
427c49bc A |
1 | /* |
2 | * clang cloud_keychain_diagnose.c -laks -framework CoreFoundation -framework IOKit -framework Security -o /tmp/cloud_keychain_diagnose | |
3 | */ | |
4 | ||
5 | ||
6 | #if !TARGET_OS_EMBEDDED | |
7 | #include "sec/Security/SecBase.h" | |
8 | #include "sec/Security/SecKey.h" | |
9 | #endif | |
10 | ||
11 | #include <CoreFoundation/CoreFoundation.h> | |
12 | #include <CoreFoundation/CFPriv.h> | |
13 | ||
14 | #if !TARGET_IPHONE_SIMULATOR | |
15 | ||
16 | /* Header Declarations */ | |
17 | #include <stdlib.h> | |
18 | #include <stdio.h> | |
19 | #include <unistd.h> | |
20 | #include <asl.h> | |
21 | #include <asl_msg.h> | |
22 | ||
23 | #if TARGET_OS_EMBEDDED | |
24 | #include <asl_core.h> | |
25 | #endif | |
26 | ||
27 | #include <string.h> | |
28 | #include <errno.h> | |
29 | #include <libaks.h> | |
30 | ||
31 | #include "SOSCloudCircle.h" | |
32 | #include "SOSPeerInfo.h" | |
33 | ||
34 | ||
35 | /* Constant Declarations */ | |
36 | #define SUCCESS 0 | |
37 | #define FAILURE -1 | |
38 | ||
39 | #define MAX_PATH_LEN 1024 | |
40 | #define SUFFIX_LENGTH 4 | |
41 | #define BUFFER_SIZE 1024 | |
42 | #define MAX_DATA_RATE 32 | |
43 | ||
44 | /* External CloudKeychain Bridge Types */ | |
45 | typedef void (^CloudKeychainReplyBlock)(CFDictionaryRef returnedValues, CFErrorRef error); | |
46 | extern void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock); | |
47 | ||
48 | /* External AppleKeyStore Types */ | |
49 | enum { | |
50 | my_keybag_state_bio_unlock = 1 << 3 | |
51 | }; | |
52 | ||
53 | ||
54 | /* Dictionary Dump State */ | |
55 | struct dict_dump_state | |
56 | { | |
57 | FILE *log_file; | |
58 | CFDictionaryRef dict; | |
59 | unsigned int indent_level; | |
60 | }; | |
61 | ||
62 | /* Static Function Declarations */ | |
63 | static | |
64 | void | |
65 | usage(); | |
66 | ||
67 | static | |
68 | int | |
69 | gather_diagnostics(); | |
70 | ||
71 | static | |
72 | int | |
73 | enable_cloud_keychain_diagnostics( | |
74 | const unsigned int enable_flag); | |
75 | ||
76 | static | |
77 | int | |
78 | build_log_path( | |
79 | char *log_path); | |
80 | ||
81 | static | |
82 | int | |
83 | dump_system_information( | |
84 | FILE *log_file); | |
85 | ||
86 | static | |
87 | int | |
88 | dump_circle_state( | |
89 | FILE *log_file); | |
90 | ||
91 | static | |
92 | int | |
93 | dump_keychain_sync_kvs( | |
94 | FILE *log_file); | |
95 | ||
96 | static | |
97 | void | |
98 | dump_dict( | |
99 | FILE *log_file, | |
100 | CFDictionaryRef dict, | |
101 | const unsigned int indent_level); | |
102 | ||
103 | static | |
104 | void | |
105 | dump_dict_applier( | |
106 | const void *key, | |
107 | const void *value, | |
108 | void *context); | |
109 | ||
110 | static | |
111 | int | |
112 | dump_asl_sender( | |
113 | FILE *log_file, | |
114 | const char *asl_sender); | |
115 | ||
116 | static | |
117 | void | |
118 | dump_cferror( | |
119 | FILE *log_file, | |
120 | const char *description, | |
121 | CFErrorRef error); | |
122 | ||
123 | /* Function Definitions */ | |
124 | int | |
125 | main( | |
126 | int argc, | |
127 | char **argv) | |
128 | { | |
129 | int result = EXIT_FAILURE; | |
130 | ||
131 | /* Parse the arguments. */ | |
132 | if (argc > 2) { | |
133 | ||
134 | usage(); | |
135 | } | |
136 | ||
137 | /* Should we just gather logs and status? */ | |
138 | if (argc == 1) { | |
139 | ||
140 | if (gather_diagnostics()) { | |
141 | ||
142 | fprintf(stderr, "Could not gather diagnostics\n"); | |
143 | goto BAIL; | |
144 | } | |
145 | } else { | |
146 | ||
147 | /* Should we enable or disable logging? */ | |
148 | if (strncmp(argv[1], "enable", 6) == 0) { | |
149 | ||
150 | /* Enable. */ | |
151 | if (enable_cloud_keychain_diagnostics(1)) { | |
152 | ||
153 | fprintf(stderr, "Could not enable additional cloud keychain diagnostics\n"); | |
154 | goto BAIL; | |
155 | } | |
156 | } else if (strncmp(argv[1], "disable", 7) == 0) { | |
157 | ||
158 | /* Enable. */ | |
159 | if (enable_cloud_keychain_diagnostics(1)) { | |
160 | ||
161 | fprintf(stderr, "Could not disable additional cloud keychain diagnostics\n"); | |
162 | goto BAIL; | |
163 | } | |
164 | } else { | |
165 | ||
166 | /* Get a job, hippy. */ | |
167 | usage(); | |
168 | } | |
169 | } | |
170 | ||
171 | /* Set the exit status to success. */ | |
172 | result = EXIT_FAILURE; | |
173 | ||
174 | BAIL: | |
175 | ||
176 | return result; | |
177 | } | |
178 | ||
179 | /* Static Function Definitions */ | |
180 | static | |
181 | void | |
182 | usage() | |
183 | { | |
184 | fprintf(stderr, "usage: cloud_keychain_diagnose [enable|disable]\n"); | |
185 | exit(EXIT_FAILURE); | |
186 | } | |
187 | ||
188 | static | |
189 | int | |
190 | gather_diagnostics() | |
191 | { | |
192 | int result = FAILURE; | |
193 | char log_path[MAX_PATH_LEN] = ""; | |
194 | int log_fd = -1; | |
195 | FILE *log_file = NULL; | |
196 | ||
197 | /* | |
198 | * Create the diagnostics file. | |
199 | * | |
200 | * Dump the system information. | |
201 | * on OS X, defaults read if the shim is active | |
202 | * Dump the circle state. | |
203 | * Dump the raw KVS data. | |
204 | * Dump known ASL logs | |
205 | * | |
206 | * Remaining work to do from rdar://12479351 | |
207 | * grab the syslog | |
208 | * query for all items with sync=1 | |
209 | * enable KVS logging | |
210 | * enable push notification logging | |
211 | */ | |
212 | ||
213 | /* Build the log path. */ | |
214 | if (build_log_path(log_path)) { | |
215 | ||
216 | fprintf(stderr, "Could not build the log path\n"); | |
217 | goto BAIL; | |
218 | } | |
219 | ||
220 | /* Create it with a randomized suffix. */ | |
221 | log_fd = mkstemps(log_path, SUFFIX_LENGTH); | |
222 | if (log_fd == -1) { | |
223 | ||
224 | fprintf(stderr, "Could not create the log file: %s\n", strerror(errno)); | |
225 | goto BAIL; | |
226 | } | |
227 | ||
228 | /* Create a file object from the descriptor. */ | |
229 | log_file = fdopen(log_fd, "w"); | |
230 | if (log_file == NULL) { | |
231 | ||
232 | fprintf(stderr, "Could not recreate the log file: %s\n", strerror(errno)); | |
233 | goto BAIL; | |
234 | } | |
235 | ||
236 | log_fd = -1; | |
237 | ||
238 | printf("Writing cloud keychain diagnostics to %s\n", log_path); | |
239 | ||
240 | /* Dump the system information. */ | |
241 | if (dump_system_information(log_file)) { | |
242 | ||
243 | fprintf(stderr, "Could not dump the system information\n"); | |
244 | goto BAIL; | |
245 | } | |
246 | ||
247 | /* Dump the SOS circle state. */ | |
248 | if (dump_circle_state(log_file)) { | |
249 | ||
250 | fprintf(stderr, "Could not dump the SOS circle state\n"); | |
251 | goto BAIL; | |
252 | } | |
253 | ||
254 | /* Dump the raw keychain syncing KVS. */ | |
255 | if (dump_keychain_sync_kvs(log_file)) { | |
256 | ||
257 | fprintf(stderr, "Could not the raw keychain syncing KVS\n"); | |
258 | goto BAIL; | |
259 | } | |
260 | ||
261 | /* | |
262 | * Dump the various and sundry ASL logs. | |
263 | */ | |
264 | ||
265 | if (dump_asl_sender(log_file, "com.apple.kb-service")) { | |
266 | ||
267 | fprintf(stderr, "Could not dump the ASL log for com.apple.kb-service\n"); | |
268 | goto BAIL; | |
269 | } | |
270 | ||
271 | if (dump_asl_sender(log_file, "com.apple.securityd")) { | |
272 | ||
273 | fprintf(stderr, "Could not dump the ASL log for com.apple.securityd\n"); | |
274 | goto BAIL; | |
275 | } | |
276 | ||
277 | if (dump_asl_sender(log_file, "com.apple.secd")) { | |
278 | ||
279 | fprintf(stderr, "Could not dump the ASL log for com.apple.secd\n"); | |
280 | goto BAIL; | |
281 | } | |
282 | ||
283 | if (dump_asl_sender(log_file, "CloudKeychainProxy")) { | |
284 | ||
285 | fprintf(stderr, "Could not dump the ASL log for CloudKeychainProxy\n"); | |
286 | goto BAIL; | |
287 | } | |
288 | ||
289 | if (dump_asl_sender(log_file, "securityd")) { | |
290 | ||
291 | fprintf(stderr, "Could not dump the ASL log for securityd\n"); | |
292 | goto BAIL; | |
293 | } | |
294 | ||
295 | if (dump_asl_sender(log_file, "secd")) { | |
296 | ||
297 | fprintf(stderr, "Could not dump the ASL log for secd\n"); | |
298 | goto BAIL; | |
299 | } | |
300 | ||
301 | /* Set the result to success. */ | |
302 | result = SUCCESS; | |
303 | ||
304 | BAIL: | |
305 | ||
306 | /* Close the diagnostics file? */ | |
307 | if (log_file != NULL) { | |
308 | ||
309 | fclose(log_file); | |
310 | log_file = NULL; | |
311 | } | |
312 | ||
313 | /* Close the diagnostics file descriptor? */ | |
314 | if (log_fd != -1) { | |
315 | ||
316 | close(log_fd); | |
317 | log_fd = -1; | |
318 | } | |
319 | ||
320 | return result; | |
321 | } | |
322 | ||
323 | static | |
324 | int | |
325 | enable_cloud_keychain_diagnostics( | |
326 | const unsigned int enable_flag) | |
327 | { | |
328 | int result = FAILURE; | |
329 | ||
330 | /* Set the result to success. */ | |
331 | result = SUCCESS; | |
332 | ||
333 | return result; | |
334 | } | |
335 | ||
336 | static | |
337 | int | |
338 | build_log_path( | |
339 | char *log_path) | |
340 | { | |
341 | int result = FAILURE; | |
342 | time_t now; | |
343 | struct tm *time_cube; | |
344 | CFDictionaryRef system_version_dict = NULL; | |
345 | CFStringRef product_name = NULL; | |
346 | ||
347 | /* Get the current time. */ | |
348 | now = time(NULL); | |
349 | ||
350 | /* Convert the time into something usable. */ | |
351 | time_cube = localtime(&now); | |
352 | if (time_cube == NULL) { | |
353 | ||
354 | fprintf(stderr, "I don't know what time it is.\n"); | |
355 | goto BAIL; | |
356 | } | |
357 | ||
358 | /* Copy the system version dictionary. */ | |
359 | system_version_dict = _CFCopySystemVersionDictionary(); | |
360 | if (system_version_dict == NULL) { | |
361 | ||
362 | fprintf(stderr, "Could not copy the system version dictionary\n"); | |
363 | goto BAIL; | |
364 | } | |
365 | ||
366 | /* Extract the product name. */ | |
367 | product_name = CFDictionaryGetValue(system_version_dict, _kCFSystemVersionProductNameKey); | |
368 | if (product_name == NULL) { | |
369 | ||
370 | fprintf(stderr, "Could not extract the product name from the system version dictionary\n"); | |
371 | goto BAIL; | |
372 | } | |
373 | ||
374 | /* Is this a Mac? */ | |
375 | if (CFEqual(product_name, CFSTR("Mac OS X"))) { | |
376 | ||
377 | /* Prepare the file template to go into /tmp. */ | |
378 | snprintf( | |
379 | log_path, | |
380 | MAX_PATH_LEN, | |
381 | "/tmp/cloud_keychain_diagnostics.%d_%d_%d.%d%d%d.XXXX.txt", | |
382 | 1900 + time_cube->tm_year, | |
383 | time_cube->tm_mon, | |
384 | time_cube->tm_mday, | |
385 | time_cube->tm_hour, | |
386 | time_cube->tm_min, | |
387 | time_cube->tm_sec); | |
388 | } else { | |
389 | ||
390 | /* Prepare the file template to go into CrashReporter. */ | |
391 | snprintf( | |
392 | log_path, | |
393 | MAX_PATH_LEN, | |
394 | "/Library/Logs/CrashReporter/cloud_keychain_diagnostics.%d_%d_%d.%d%d%d.XXXX.txt", | |
395 | 1900 + time_cube->tm_year, | |
396 | time_cube->tm_mon, | |
397 | time_cube->tm_mday, | |
398 | time_cube->tm_hour, | |
399 | time_cube->tm_min, | |
400 | time_cube->tm_sec); | |
401 | } | |
402 | ||
403 | /* Set the result to success. */ | |
404 | result = SUCCESS; | |
405 | ||
406 | BAIL: | |
407 | ||
408 | /* Release the system version dictionary? */ | |
409 | if (system_version_dict != NULL) { | |
410 | ||
411 | CFRelease(system_version_dict); | |
412 | system_version_dict = NULL; | |
413 | } | |
414 | ||
415 | return result; | |
416 | } | |
417 | ||
418 | static | |
419 | int | |
420 | dump_system_information( | |
421 | FILE *log_file) | |
422 | { | |
423 | int result = FAILURE; | |
424 | CFDictionaryRef dict = NULL; | |
425 | char buffer[BUFFER_SIZE]; | |
426 | CFStringRef product_name; | |
427 | CFStringRef product_version; | |
428 | CFStringRef product_build_version; | |
429 | time_t now; | |
430 | CFTypeRef shim_flag = NULL; | |
431 | int keybag_handle = bad_keybag_handle; | |
432 | kern_return_t kr = 0; | |
433 | keybag_state_t keybag_state = 0; | |
434 | ||
435 | /* | |
436 | * Dump the system information. | |
437 | * ProductName | |
438 | * ProductVersion | |
439 | * ProductBuildVersion | |
440 | * Host name | |
441 | */ | |
442 | ||
443 | /* Dump a header. */ | |
444 | fprintf(log_file, "Host Information:\n"); | |
445 | fprintf(log_file, "=================\n"); | |
446 | ||
447 | /* Copy the system version dictionary. */ | |
448 | dict = _CFCopySystemVersionDictionary(); | |
449 | if (dict == NULL) { | |
450 | ||
451 | fprintf(stderr, "Could not copy the system version dictionary\n"); | |
452 | goto BAIL; | |
453 | } | |
454 | ||
455 | /* Extract the product name. */ | |
456 | product_name = CFDictionaryGetValue(dict, _kCFSystemVersionProductNameKey); | |
457 | if (product_name == NULL) { | |
458 | ||
459 | fprintf(stderr, "Could not extract the product name from the system version dictionary\n"); | |
460 | goto BAIL; | |
461 | } | |
462 | ||
463 | /* Convert the product name to a C string. */ | |
464 | if (!CFStringGetCString(product_name, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
465 | ||
466 | fprintf(stderr, "Could not convert the product name to a C string\n"); | |
467 | goto BAIL; | |
468 | } | |
469 | ||
470 | /* Dump the product name. */ | |
471 | fprintf(log_file, "Product Name: %s\n", buffer); | |
472 | ||
473 | /* Extract the product version. */ | |
474 | product_version = CFDictionaryGetValue(dict, _kCFSystemVersionProductVersionKey); | |
475 | if (product_version == NULL) { | |
476 | ||
477 | fprintf(stderr, "Could not extract the product version from the system version dictionary\n"); | |
478 | goto BAIL; | |
479 | } | |
480 | ||
481 | /* Convert the product version to a C string. */ | |
482 | if (!CFStringGetCString(product_version, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
483 | ||
484 | fprintf(stderr, "Could not convert the product version to a C string\n"); | |
485 | goto BAIL; | |
486 | } | |
487 | ||
488 | /* Dump the product version */ | |
489 | fprintf(log_file, "Product Version: %s\n", buffer); | |
490 | ||
491 | /* Extract the product build version. */ | |
492 | product_build_version = CFDictionaryGetValue(dict, _kCFSystemVersionBuildVersionKey); | |
493 | if (product_build_version == NULL) { | |
494 | ||
495 | fprintf(stderr, "Could not extract the product build version from the system version dictionary\n"); | |
496 | goto BAIL; | |
497 | } | |
498 | ||
499 | /* Convert the product build version to a C string. */ | |
500 | if (!CFStringGetCString(product_build_version, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
501 | ||
502 | fprintf(stderr, "Could not convert the product build version to a C string\n"); | |
503 | goto BAIL; | |
504 | } | |
505 | ||
506 | /* Dump the product build version. */ | |
507 | fprintf(log_file, "Product Build Version: %s\n", buffer); | |
508 | ||
509 | /* Lookup the host name. */ | |
510 | if (gethostname(buffer, BUFFER_SIZE) == -1) { | |
511 | ||
512 | fprintf(stderr, "Could not lookup the host name\n"); | |
513 | goto BAIL; | |
514 | } | |
515 | ||
516 | /* Dump the host name. */ | |
517 | fprintf(log_file, "Host Name: %s\n", buffer); | |
518 | ||
519 | /* Lookup the current time. */ | |
520 | if (gethostname(buffer, BUFFER_SIZE) == -1) { | |
521 | ||
522 | fprintf(stderr, "Could not lookup the host name\n"); | |
523 | goto BAIL; | |
524 | } | |
525 | ||
526 | /* Get the current time. */ | |
527 | now = time(NULL); | |
528 | ||
529 | /* Dump the current time. */ | |
530 | fprintf(log_file, "Time: %s", ctime(&now)); | |
531 | ||
532 | /* Is this a Mac? */ | |
533 | if (CFEqual(product_name, CFSTR("Mac OS X"))) { | |
534 | ||
535 | /* Set the keybag handle. */ | |
536 | keybag_handle = session_keybag_handle; | |
537 | ||
538 | /* Lookup the state of the shim. */ | |
539 | shim_flag = (CFNumberRef)CFPreferencesCopyValue(CFSTR("SecItemSynchronizable"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost); | |
540 | if (shim_flag && CFGetTypeID(shim_flag) == CFBooleanGetTypeID()) { | |
541 | ||
542 | /* Is the shim enabled? */ | |
543 | if (CFBooleanGetValue((CFBooleanRef)shim_flag)) { | |
544 | ||
545 | fprintf(log_file, "The SecItem shim is enabled\n"); | |
546 | } else { | |
547 | ||
548 | fprintf(log_file, "The SecItem shim is disabled\n"); | |
549 | } | |
550 | } else { | |
551 | ||
552 | fprintf(log_file, "The SecItem shim is disabled\n"); | |
553 | } | |
554 | } else { | |
555 | ||
556 | /* Set the keybag handle. */ | |
557 | keybag_handle = device_keybag_handle; | |
558 | } | |
559 | ||
560 | /* Get the keybag state. */ | |
561 | kr = aks_get_lock_state(keybag_handle, &keybag_state); | |
562 | if (kr) { | |
563 | ||
564 | fprintf(stderr, "Could not call aks_get_lock_state\n"); | |
565 | } else { | |
566 | ||
567 | switch (keybag_state) { | |
568 | ||
569 | case keybag_state_unlocked: { | |
570 | ||
571 | fprintf(log_file, "Keybag State: Unlocked\n"); | |
572 | }break; | |
573 | ||
574 | case keybag_state_locked: { | |
575 | ||
576 | fprintf(log_file, "Keybag State: Locked\n"); | |
577 | }break; | |
578 | ||
579 | case keybag_state_no_pin: { | |
580 | ||
581 | fprintf(log_file, "Keybag State: No Passcode\n"); | |
582 | }break; | |
583 | ||
584 | case keybag_state_been_unlocked: { | |
585 | ||
586 | fprintf(log_file, "Keybag State: Been Unlocked\n"); | |
587 | }break; | |
588 | ||
589 | case my_keybag_state_bio_unlock: { | |
590 | ||
591 | fprintf(log_file, "Keybag State: Bio Unlock\n"); | |
592 | }break; | |
593 | ||
594 | default: { | |
595 | ||
596 | fprintf(log_file, "Keybag State: UNKNOWN\n"); | |
597 | }break; | |
598 | } | |
599 | } | |
600 | ||
601 | /* Dump a footer. */ | |
602 | fprintf(log_file, "=================\n\n"); | |
603 | ||
604 | /* Set the result to success. */ | |
605 | result = SUCCESS; | |
606 | ||
607 | BAIL: | |
608 | ||
609 | /* Release the shim flag? */ | |
610 | if (shim_flag) { | |
611 | ||
612 | CFRelease(shim_flag); | |
613 | shim_flag = NULL; | |
614 | } | |
615 | ||
616 | /* Release the system version dictionary? */ | |
617 | if (dict != NULL) { | |
618 | ||
619 | CFRelease(dict); | |
620 | dict = NULL; | |
621 | } | |
622 | ||
623 | return result; | |
624 | } | |
625 | ||
626 | static | |
627 | int | |
628 | dump_circle_state( | |
629 | FILE *log_file) | |
630 | { | |
631 | int result = FAILURE; | |
632 | CFErrorRef error = NULL; | |
633 | SOSCCStatus circle_status; | |
634 | char *circle_state_string = NULL; | |
635 | CFArrayRef peer_list = NULL; | |
636 | CFIndex num_peers; | |
637 | CFIndex i; | |
638 | SOSPeerInfoRef peer_info; | |
639 | CFDictionaryRef peer_gestalt = NULL; | |
640 | CFStringRef peer_name; | |
641 | CFStringRef peer_device_type; | |
642 | CFStringRef peerID; | |
643 | char buffer[BUFFER_SIZE]; | |
644 | ||
645 | /* | |
646 | * Dump the SOS circle state. | |
647 | */ | |
648 | ||
649 | /* Dump a header. */ | |
650 | fprintf(log_file, "SOS Circle State:\n"); | |
651 | fprintf(log_file, "=================\n"); | |
652 | ||
653 | /* Are we in a circle? */ | |
654 | circle_status = SOSCCThisDeviceIsInCircle(&error); | |
655 | if (error != NULL) { | |
656 | ||
657 | /* Dump and consume the error. */ | |
658 | dump_cferror(log_file, "Could not call SOSCCThisDeviceIsInCircle", error); | |
659 | } else { | |
660 | ||
661 | switch (circle_status) { | |
662 | ||
663 | case kSOSCCInCircle: { | |
664 | circle_state_string = "kSOSCCInCircle"; | |
665 | }break; | |
666 | ||
667 | case kSOSCCNotInCircle: { | |
668 | circle_state_string = "kSOSCCNotInCircle"; | |
669 | }break; | |
670 | ||
671 | case kSOSCCRequestPending: { | |
672 | circle_state_string = "kSOSCCRequestPending"; | |
673 | }break; | |
674 | ||
675 | case kSOSCCCircleAbsent: { | |
676 | circle_state_string = "kSOSCCCircleAbsent"; | |
677 | }break; | |
678 | ||
679 | case kSOSCCError: { | |
680 | circle_state_string = "kSOSCCError"; | |
681 | }break; | |
682 | ||
683 | case kSOSCCParamErr: { | |
684 | circle_state_string = "kSOSCCParamErr"; | |
685 | }break; | |
686 | ||
687 | case kSOSCCMemoryErr: { | |
688 | circle_state_string = "kSOSCCMemoryErr"; | |
689 | }break; | |
690 | ||
691 | default: { | |
692 | circle_state_string = "Unknown circle status?"; | |
693 | } | |
694 | } | |
695 | ||
696 | fprintf(log_file, "Circle Status: %s\n", circle_state_string); | |
697 | } | |
698 | ||
699 | /* Can we authenticate? */ | |
700 | if (!SOSCCCanAuthenticate(&error)) { | |
701 | ||
702 | if (error) { | |
703 | ||
704 | /* Dump and consume the error. */ | |
705 | dump_cferror(log_file, "Could not call SOSCCCanAuthenticate", error); | |
706 | } else { | |
707 | ||
708 | fprintf(log_file, "Can Authenticate: NO\n"); | |
709 | } | |
710 | } else { | |
711 | ||
712 | fprintf(log_file, "Can Authenticate: YES\n"); | |
713 | } | |
714 | ||
715 | /* Copy the peers. */ | |
716 | peer_list = SOSCCCopyPeerPeerInfo(&error); | |
717 | if (error) { | |
718 | ||
719 | /* Dump the error. */ | |
720 | dump_cferror(log_file, "Could not call SOSCCCopyPeerPeerInfo", error); | |
721 | } else { | |
722 | ||
723 | /* Get the number of peers. */ | |
724 | num_peers = CFArrayGetCount(peer_list); | |
725 | ||
726 | fprintf(log_file, "Number of syncing peers: %ld\n", num_peers); | |
727 | ||
728 | if (num_peers > 0) { | |
729 | ||
730 | fprintf(log_file, "\n"); | |
731 | } | |
732 | ||
733 | /* Enumerate the peers. */ | |
734 | for (i = 0; i < num_peers; i++) { | |
735 | ||
736 | peer_info = (SOSPeerInfoRef) CFArrayGetValueAtIndex(peer_list, i); | |
737 | if (peer_info == NULL) { | |
738 | ||
739 | fprintf(stderr, "Could not extract peer %ld of %ld\n", i, num_peers); | |
740 | goto BAIL; | |
741 | } | |
742 | ||
743 | /* | |
744 | peer_gestalt = SOSPeerInfoCopyPeerGestalt(peer_info); | |
745 | if (peer_gestalt == NULL) { | |
746 | ||
747 | fprintf(stderr, "Could not copy peer gestalt %ld of %ld\n", i, num_peers); | |
748 | goto BAIL; | |
749 | } | |
750 | */ | |
751 | ||
752 | /* Get the peer name. */ | |
753 | peer_name = SOSPeerInfoGetPeerName(peer_info); | |
754 | if (peer_name == NULL) { | |
755 | ||
756 | fprintf(stderr, "Could not extract peer name %ld of %ld\n", i, num_peers); | |
757 | goto BAIL; | |
758 | } | |
759 | ||
760 | /* Convert the peer name to a C string. */ | |
761 | if (!CFStringGetCString(peer_name, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
762 | ||
763 | fprintf(stderr, "Could not convert the peer name to a C string\n"); | |
764 | goto BAIL; | |
765 | } | |
766 | ||
767 | /* Dump the peer name. */ | |
768 | fprintf(log_file, " Peer Name: %s\n", buffer); | |
769 | ||
770 | /* Get the peer device type. */ | |
771 | peer_device_type = SOSPeerInfoGetPeerDeviceType(peer_info); | |
772 | if (peer_device_type == NULL) { | |
773 | ||
774 | fprintf(stderr, "Could not extract peer device type %ld of %ld\n", i, num_peers); | |
775 | goto BAIL; | |
776 | } | |
777 | ||
778 | /* Convert the peer device type to a C string. */ | |
779 | if (!CFStringGetCString(peer_device_type, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
780 | ||
781 | fprintf(stderr, "Could not convert the peer device type to a C string\n"); | |
782 | goto BAIL; | |
783 | } | |
784 | ||
785 | /* Dump the peer name. */ | |
786 | fprintf(log_file, " Peer Device Type: %s\n", buffer); | |
787 | ||
788 | /* Get the peer ID. */ | |
789 | peerID = SOSPeerInfoGetPeerID(peer_info); | |
790 | if (peerID == NULL) { | |
791 | ||
792 | fprintf(stderr, "Could not extract peer ID %ld of %ld\n", i, num_peers); | |
793 | goto BAIL; | |
794 | } | |
795 | ||
796 | /* Dump the peer name. */ | |
797 | fprintf(log_file, " Peer ID: %s\n", buffer); | |
798 | ||
799 | /* Convert the peer ID to a C string. */ | |
800 | if (!CFStringGetCString(peerID, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
801 | ||
802 | fprintf(stderr, "Could not convert the peer ID to a C string\n"); | |
803 | goto BAIL; | |
804 | } | |
805 | ||
806 | /* Make it pretty. */ | |
807 | fprintf(log_file, "\n"); | |
808 | } | |
809 | ||
810 | /* Release the peer list. */ | |
811 | CFRelease(peer_list); | |
812 | peer_list = NULL; | |
813 | } | |
814 | ||
815 | /* Copy the applicant peers. */ | |
816 | peer_list = SOSCCCopyApplicantPeerInfo(&error); | |
817 | if (error) { | |
818 | ||
819 | /* Dump the error. */ | |
820 | dump_cferror(log_file, "Could not call SOSCCCopyApplicantPeerInfo", error); | |
821 | } else { | |
822 | ||
823 | /* Get the number of peers. */ | |
824 | num_peers = CFArrayGetCount(peer_list); | |
825 | ||
826 | fprintf(log_file, "Number of applicant peers: %ld\n", num_peers); | |
827 | ||
828 | if (num_peers > 0) { | |
829 | ||
830 | fprintf(log_file, "\n"); | |
831 | } | |
832 | ||
833 | /* Enumerate the peers. */ | |
834 | for (i = 0; i < num_peers; i++) { | |
835 | ||
836 | peer_info = (SOSPeerInfoRef) CFArrayGetValueAtIndex(peer_list, i); | |
837 | if (peer_info == NULL) { | |
838 | ||
839 | fprintf(stderr, "Could not extract peer %ld of %ld\n", i, num_peers); | |
840 | goto BAIL; | |
841 | } | |
842 | ||
843 | /* | |
844 | peer_gestalt = SOSPeerInfoCopyPeerGestalt(peer_info); | |
845 | if (peer_gestalt == NULL) { | |
846 | ||
847 | fprintf(stderr, "Could not copy peer gestalt %ld of %ld\n", i, num_peers); | |
848 | goto BAIL; | |
849 | } | |
850 | */ | |
851 | ||
852 | /* Get the peer name. */ | |
853 | peer_name = SOSPeerInfoGetPeerName(peer_info); | |
854 | if (peer_name == NULL) { | |
855 | ||
856 | fprintf(stderr, "Could not extract peer name %ld of %ld\n", i, num_peers); | |
857 | goto BAIL; | |
858 | } | |
859 | ||
860 | /* Convert the peer name to a C string. */ | |
861 | if (!CFStringGetCString(peer_name, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
862 | ||
863 | fprintf(stderr, "Could not convert the peer name to a C string\n"); | |
864 | goto BAIL; | |
865 | } | |
866 | ||
867 | /* Dump the peer name. */ | |
868 | fprintf(log_file, " Applicant Name: %s\n", buffer); | |
869 | ||
870 | /* Get the peer device type. */ | |
871 | peer_device_type = SOSPeerInfoGetPeerDeviceType(peer_info); | |
872 | if (peer_device_type == NULL) { | |
873 | ||
874 | fprintf(stderr, "Could not extract peer device type %ld of %ld\n", i, num_peers); | |
875 | goto BAIL; | |
876 | } | |
877 | ||
878 | /* Convert the peer device type to a C string. */ | |
879 | if (!CFStringGetCString(peer_device_type, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
880 | ||
881 | fprintf(stderr, "Could not convert the peer device type to a C string\n"); | |
882 | goto BAIL; | |
883 | } | |
884 | ||
885 | /* Dump the peer name. */ | |
886 | fprintf(log_file, " Applicant Device Type: %s\n", buffer); | |
887 | ||
888 | /* Get the peer ID. */ | |
889 | peerID = SOSPeerInfoGetPeerID(peer_info); | |
890 | if (peerID == NULL) { | |
891 | ||
892 | fprintf(stderr, "Could not extract peer ID %ld of %ld\n", i, num_peers); | |
893 | goto BAIL; | |
894 | } | |
895 | ||
896 | /* Dump the peer name. */ | |
897 | fprintf(log_file, " Applicant ID: %s\n", buffer); | |
898 | ||
899 | /* Convert the peer ID to a C string. */ | |
900 | if (!CFStringGetCString(peerID, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
901 | ||
902 | fprintf(stderr, "Could not convert the peer ID to a C string\n"); | |
903 | goto BAIL; | |
904 | } | |
905 | ||
906 | /* Make it pretty. */ | |
907 | if (i < num_peers - 1) { | |
908 | ||
909 | fprintf(log_file, "\n"); | |
910 | } | |
911 | } | |
912 | ||
913 | /* Release the peer list. */ | |
914 | CFRelease(peer_list); | |
915 | peer_list = NULL; | |
916 | } | |
917 | ||
918 | /* Dump a footer. */ | |
919 | fprintf(log_file, "=================\n\n"); | |
920 | ||
921 | /* Set the result to success. */ | |
922 | result = SUCCESS; | |
923 | ||
924 | BAIL: | |
925 | ||
926 | /* Release the peer gestalt? */ | |
927 | if (peer_gestalt != NULL) { | |
928 | ||
929 | CFRelease(peer_gestalt); | |
930 | peer_gestalt = NULL; | |
931 | } | |
932 | ||
933 | /* Release the peer list? */ | |
934 | if (peer_list != NULL) { | |
935 | ||
936 | CFRelease(peer_list); | |
937 | peer_list = NULL; | |
938 | } | |
939 | ||
940 | /* Release the error string? */ | |
941 | if (error != NULL) { | |
942 | ||
943 | CFRelease(error); | |
944 | error = NULL; | |
945 | } | |
946 | ||
947 | return result; | |
948 | } | |
949 | ||
950 | static | |
951 | int | |
952 | dump_keychain_sync_kvs( | |
953 | FILE *log_file) | |
954 | { | |
955 | int result = FAILURE; | |
956 | dispatch_group_t cloud_group; | |
957 | dispatch_queue_t cloud_queue; | |
958 | dispatch_semaphore_t waitSemaphore; | |
959 | dispatch_time_t finishTime; | |
960 | __block CFDictionaryRef kvs_dict = NULL; | |
961 | ||
962 | /* | |
963 | * Dump the keychain syncing KVS. | |
964 | */ | |
965 | ||
966 | /* Dump a header. */ | |
967 | fprintf(log_file, "Keychain Syncing KVS:\n"); | |
968 | fprintf(log_file, "=================\n"); | |
969 | ||
970 | /* Create the serial dispatch queue to talk to CloudKeychainProxy. */ | |
971 | cloud_queue = dispatch_queue_create("cloud_queue", DISPATCH_QUEUE_SERIAL); | |
972 | ||
973 | /* Create a semaphore. */ | |
974 | waitSemaphore = dispatch_semaphore_create(0); | |
975 | ||
976 | /* Create the finish time. */ | |
977 | finishTime = dispatch_time(DISPATCH_TIME_NOW, 30ull * NSEC_PER_SEC); | |
978 | ||
979 | /* Create the dispatch group. */ | |
980 | cloud_group = dispatch_group_create(); | |
981 | ||
982 | /* Enter the dispatch group. */ | |
983 | dispatch_group_enter(cloud_group); | |
984 | ||
985 | /* Establish the CloudKeychainProxy reply hander. */ | |
986 | CloudKeychainReplyBlock replyBlock = ^(CFDictionaryRef returnedValues, CFErrorRef error) | |
987 | { | |
988 | /* Did we get back some values? */ | |
989 | if (returnedValues) { | |
990 | ||
991 | kvs_dict = (returnedValues); | |
992 | CFRetain(kvs_dict); | |
993 | } | |
994 | ||
995 | /* Leave the cloud group. */ | |
996 | dispatch_group_leave(cloud_group); | |
997 | ||
998 | /* Signal the other queue we're done. */ | |
999 | dispatch_semaphore_signal(waitSemaphore); | |
1000 | }; | |
1001 | ||
1002 | /* Ask CloudKeychainProxy for all of the raw KVS data. */ | |
1003 | SOSCloudKeychainGetAllObjectsFromCloud(cloud_queue, replyBlock); | |
1004 | ||
1005 | /* Wait for CloudKeychainProxy to respond, up to 30 seconds. */ | |
1006 | dispatch_semaphore_wait(waitSemaphore, finishTime); | |
1007 | ||
1008 | /* Release the semaphore. */ | |
1009 | dispatch_release(waitSemaphore); | |
1010 | ||
1011 | /* Did we get any raw KVS data from CloudKeychainProxy? */ | |
1012 | if (kvs_dict) { | |
1013 | ||
1014 | dump_dict(log_file, kvs_dict, 0); | |
1015 | } | |
1016 | ||
1017 | /* Dump a footer. */ | |
1018 | fprintf(log_file, "=================\n\n"); | |
1019 | ||
1020 | /* Set the result to success. */ | |
1021 | result = SUCCESS; | |
1022 | ||
1023 | /* Release the KVS dictionary? */ | |
1024 | if (kvs_dict != NULL) { | |
1025 | ||
1026 | CFRelease(kvs_dict); | |
1027 | kvs_dict = NULL; | |
1028 | } | |
1029 | ||
1030 | return result; | |
1031 | } | |
1032 | ||
1033 | static | |
1034 | void | |
1035 | dump_dict( | |
1036 | FILE *log_file, | |
1037 | CFDictionaryRef dict, | |
1038 | const unsigned int indent_level) | |
1039 | { | |
1040 | struct dict_dump_state dump_state; | |
1041 | ||
1042 | /* Setup the context. */ | |
1043 | dump_state.log_file = log_file; | |
1044 | dump_state.dict = dict; | |
1045 | dump_state.indent_level = indent_level; | |
1046 | ||
1047 | /* Apply the dumper to each element in the dictionary. */ | |
1048 | CFDictionaryApplyFunction(dict, dump_dict_applier, (void *)&dump_state); | |
1049 | } | |
1050 | ||
1051 | static | |
1052 | void | |
1053 | dump_dict_applier( | |
1054 | const void *key, | |
1055 | const void *value, | |
1056 | void *context) | |
1057 | { | |
1058 | CFTypeRef key_object; | |
1059 | CFTypeRef value_object; | |
1060 | struct dict_dump_state *dump_state; | |
1061 | unsigned int i; | |
1062 | char buffer[BUFFER_SIZE]; | |
1063 | CFIndex length; | |
1064 | const UInt8* bytes; | |
1065 | ||
1066 | /* Assign the CF types. */ | |
1067 | key_object = (CFTypeRef) key; | |
1068 | value_object = (CFTypeRef) value; | |
1069 | ||
1070 | /* Get the context. */ | |
1071 | dump_state = (struct dict_dump_state *)context; | |
1072 | ||
1073 | /* Indent appropriately. */ | |
1074 | for (i = 0; i < dump_state->indent_level; i++) { | |
1075 | ||
1076 | fprintf(dump_state->log_file, " "); | |
1077 | } | |
1078 | ||
1079 | /* Determine the key type. */ | |
1080 | if (CFGetTypeID(key_object) == CFStringGetTypeID()) { | |
1081 | ||
1082 | /* Convert the key to a C string. */ | |
1083 | if (!CFStringGetCString((CFStringRef) key_object, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
1084 | ||
1085 | fprintf(stderr, "Could not convert the key to a C string\n"); | |
1086 | fprintf(dump_state->log_file, "[Failed Key Type]: "); | |
1087 | } else { | |
1088 | ||
1089 | fprintf(dump_state->log_file, "%s: ", buffer); | |
1090 | } | |
1091 | } | |
1092 | ||
1093 | /* Determine the value type. */ | |
1094 | if (CFGetTypeID(value_object) == CFStringGetTypeID()) { | |
1095 | ||
1096 | /* Convert the value to a C string. */ | |
1097 | if (!CFStringGetCString((CFStringRef) value_object, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) { | |
1098 | ||
1099 | fprintf(stderr, "Could not convert the value to a C string\n"); | |
1100 | fprintf(dump_state->log_file, "[Failed Value Type]: "); | |
1101 | } else { | |
1102 | ||
1103 | fprintf(dump_state->log_file, "%s\n", buffer); | |
1104 | } | |
1105 | } else if (CFGetTypeID(value_object) == CFDataGetTypeID()) { | |
1106 | ||
1107 | length = CFDataGetLength((CFDataRef)value_object); | |
1108 | bytes = CFDataGetBytePtr((CFDataRef) value_object); | |
1109 | ||
1110 | fprintf(dump_state->log_file, "0x"); | |
1111 | ||
1112 | for (i = 0; i < (unsigned int)length && i < MAX_DATA_RATE; i++) { | |
1113 | ||
1114 | fprintf(dump_state->log_file, "%02x", (unsigned char)bytes[i]); | |
1115 | } | |
1116 | ||
1117 | fprintf(dump_state->log_file, " (%ld bytes)\n", length); | |
1118 | ||
1119 | ||
1120 | } else if (CFGetTypeID(value_object) == CFDictionaryGetTypeID()) { | |
1121 | ||
4d3cab3d | 1122 | /* Recurse motherfucker! */ |
427c49bc A |
1123 | fprintf(dump_state->log_file, "\n"); |
1124 | dump_dict(dump_state->log_file, (CFDictionaryRef) value_object, dump_state->indent_level + 1); | |
1125 | } else { | |
1126 | ||
1127 | fprintf(dump_state->log_file, "[Unknown Value Type]\n"); | |
1128 | } | |
1129 | } | |
1130 | ||
1131 | static | |
1132 | int | |
1133 | dump_asl_sender( | |
1134 | FILE *log_file, | |
1135 | const char *asl_sender) | |
1136 | { | |
1137 | int result = FAILURE; | |
1138 | aslmsg log_query = NULL; | |
1139 | aslresponse log_response = NULL; | |
1140 | aslmsg log_message; | |
1141 | char *message_string; | |
1142 | uint32_t message_length; | |
1143 | ||
1144 | /* | |
1145 | * Dump the ASL logs for the given sender. | |
1146 | */ | |
1147 | ||
1148 | /* Dump a header. */ | |
1149 | fprintf(log_file, "ASL: %s\n", asl_sender); | |
1150 | fprintf(log_file, "=================\n"); | |
1151 | ||
1152 | /* Create the ASL query. */ | |
1153 | log_query = asl_new(ASL_TYPE_QUERY); | |
1154 | if (log_query == NULL) { | |
1155 | ||
1156 | fprintf(stderr, "Could not create ASL query\n"); | |
1157 | goto BAIL; | |
1158 | } | |
1159 | ||
1160 | /* Setup the ASL query. */ | |
1161 | asl_set_query(log_query, ASL_KEY_SENDER, asl_sender, ASL_QUERY_OP_EQUAL); | |
1162 | ||
1163 | /* Perform the ASL search. */ | |
1164 | log_response = asl_search(NULL, log_query); | |
1165 | if (log_response == NULL) { | |
1166 | ||
1167 | fprintf(log_file, "Could not perform ASL search for %s\n", asl_sender); | |
1168 | } else { | |
1169 | ||
1170 | /* Enumerate the ASL messages in the response. */ | |
1171 | while ((log_message = aslresponse_next(log_response)) != NULL) { | |
1172 | ||
1173 | /* Format the message entry. */ | |
1174 | message_string = asl_format_message((asl_msg_t *)log_message, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &message_length); | |
1175 | if (message_string == NULL) { | |
1176 | ||
1177 | fprintf(stderr, "Could not create ASL message string\n"); | |
1178 | goto BAIL; | |
1179 | } | |
1180 | ||
1181 | fprintf(log_file, "%s", message_string); | |
1182 | ||
1183 | /* Release the message string. */ | |
1184 | free(message_string); | |
1185 | message_string = NULL; | |
1186 | } | |
1187 | } | |
1188 | ||
1189 | /* Dump a footer. */ | |
1190 | fprintf(log_file, "=================\n\n"); | |
1191 | ||
1192 | /* Set the result to success. */ | |
1193 | result = SUCCESS; | |
1194 | ||
1195 | BAIL: | |
1196 | ||
1197 | /* Release the ASL response? */ | |
1198 | if (log_response != NULL) { | |
1199 | ||
1200 | aslresponse_free(log_response); | |
1201 | log_response = NULL; | |
1202 | } | |
1203 | ||
1204 | /* Release the ASL query? */ | |
1205 | if (log_query != NULL) { | |
1206 | ||
1207 | asl_free(log_query); | |
1208 | log_query = NULL; | |
1209 | } | |
1210 | ||
1211 | return result; | |
1212 | } | |
1213 | ||
1214 | static | |
1215 | void | |
1216 | dump_cferror( | |
1217 | FILE *log_file, | |
1218 | const char *description, | |
1219 | CFErrorRef error) | |
1220 | { | |
1221 | CFStringRef error_string = NULL; | |
1222 | char buffer[BUFFER_SIZE]; | |
1223 | ||
1224 | error_string = CFErrorCopyDescription(error); | |
1225 | if (error_string == NULL) { | |
1226 | ||
1227 | fprintf(stderr, "Could not copy error description?\n"); | |
1228 | goto BAIL; | |
1229 | } | |
1230 | ||
1231 | (void) CFStringGetCString(error_string, buffer, BUFFER_SIZE, kCFStringEncodingUTF8); | |
1232 | ||
1233 | fprintf(stderr, "%s: %s\n", description, buffer); | |
1234 | fprintf(log_file, "%s: %s\n", description, buffer); | |
1235 | ||
1236 | BAIL: | |
1237 | ||
1238 | /* Release the error string? */ | |
1239 | if (error_string != NULL) { | |
1240 | ||
1241 | CFRelease(error_string); | |
1242 | error_string = NULL; | |
1243 | } | |
1244 | } | |
1245 | ||
1246 | #else // TARGET_IPHONE_SIMULATOR | |
1247 | ||
1248 | int | |
1249 | main( | |
1250 | int argc, | |
1251 | char **argv) | |
1252 | { | |
1253 | #pragma unused (argc, argv) | |
1254 | return 0; | |
1255 | } | |
1256 | ||
1257 | #endif |