--- /dev/null
+/*
+ * clang cloud_keychain_diagnose.c -laks -framework CoreFoundation -framework IOKit -framework Security -o /tmp/cloud_keychain_diagnose
+ */
+
+
+#if !TARGET_OS_EMBEDDED
+#include "sec/Security/SecBase.h"
+#include "sec/Security/SecKey.h"
+#endif
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFPriv.h>
+
+#if !TARGET_IPHONE_SIMULATOR
+
+/* Header Declarations */
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <asl.h>
+#include <asl_msg.h>
+
+#if TARGET_OS_EMBEDDED
+#include <asl_core.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <libaks.h>
+
+#include "SOSCloudCircle.h"
+#include "SOSPeerInfo.h"
+
+
+/* Constant Declarations */
+#define SUCCESS 0
+#define FAILURE -1
+
+#define MAX_PATH_LEN 1024
+#define SUFFIX_LENGTH 4
+#define BUFFER_SIZE 1024
+#define MAX_DATA_RATE 32
+
+/* External CloudKeychain Bridge Types */
+typedef void (^CloudKeychainReplyBlock)(CFDictionaryRef returnedValues, CFErrorRef error);
+extern void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock);
+
+/* External AppleKeyStore Types */
+enum {
+ my_keybag_state_bio_unlock = 1 << 3
+};
+
+
+/* Dictionary Dump State */
+struct dict_dump_state
+{
+ FILE *log_file;
+ CFDictionaryRef dict;
+ unsigned int indent_level;
+};
+
+/* Static Function Declarations */
+static
+void
+usage();
+
+static
+int
+gather_diagnostics();
+
+static
+int
+enable_cloud_keychain_diagnostics(
+ const unsigned int enable_flag);
+
+static
+int
+build_log_path(
+ char *log_path);
+
+static
+int
+dump_system_information(
+ FILE *log_file);
+
+static
+int
+dump_circle_state(
+ FILE *log_file);
+
+static
+int
+dump_keychain_sync_kvs(
+ FILE *log_file);
+
+static
+void
+dump_dict(
+ FILE *log_file,
+ CFDictionaryRef dict,
+ const unsigned int indent_level);
+
+static
+void
+dump_dict_applier(
+ const void *key,
+ const void *value,
+ void *context);
+
+static
+int
+dump_asl_sender(
+ FILE *log_file,
+ const char *asl_sender);
+
+static
+void
+dump_cferror(
+ FILE *log_file,
+ const char *description,
+ CFErrorRef error);
+
+/* Function Definitions */
+int
+main(
+ int argc,
+ char **argv)
+{
+ int result = EXIT_FAILURE;
+
+ /* Parse the arguments. */
+ if (argc > 2) {
+
+ usage();
+ }
+
+ /* Should we just gather logs and status? */
+ if (argc == 1) {
+
+ if (gather_diagnostics()) {
+
+ fprintf(stderr, "Could not gather diagnostics\n");
+ goto BAIL;
+ }
+ } else {
+
+ /* Should we enable or disable logging? */
+ if (strncmp(argv[1], "enable", 6) == 0) {
+
+ /* Enable. */
+ if (enable_cloud_keychain_diagnostics(1)) {
+
+ fprintf(stderr, "Could not enable additional cloud keychain diagnostics\n");
+ goto BAIL;
+ }
+ } else if (strncmp(argv[1], "disable", 7) == 0) {
+
+ /* Enable. */
+ if (enable_cloud_keychain_diagnostics(1)) {
+
+ fprintf(stderr, "Could not disable additional cloud keychain diagnostics\n");
+ goto BAIL;
+ }
+ } else {
+
+ /* Get a job, hippy. */
+ usage();
+ }
+ }
+
+ /* Set the exit status to success. */
+ result = EXIT_FAILURE;
+
+BAIL:
+
+ return result;
+}
+
+/* Static Function Definitions */
+static
+void
+usage()
+{
+ fprintf(stderr, "usage: cloud_keychain_diagnose [enable|disable]\n");
+ exit(EXIT_FAILURE);
+}
+
+static
+int
+gather_diagnostics()
+{
+ int result = FAILURE;
+ char log_path[MAX_PATH_LEN] = "";
+ int log_fd = -1;
+ FILE *log_file = NULL;
+
+ /*
+ * Create the diagnostics file.
+ *
+ * Dump the system information.
+ * on OS X, defaults read if the shim is active
+ * Dump the circle state.
+ * Dump the raw KVS data.
+ * Dump known ASL logs
+ *
+ * Remaining work to do from rdar://12479351
+ * grab the syslog
+ * query for all items with sync=1
+ * enable KVS logging
+ * enable push notification logging
+ */
+
+ /* Build the log path. */
+ if (build_log_path(log_path)) {
+
+ fprintf(stderr, "Could not build the log path\n");
+ goto BAIL;
+ }
+
+ /* Create it with a randomized suffix. */
+ log_fd = mkstemps(log_path, SUFFIX_LENGTH);
+ if (log_fd == -1) {
+
+ fprintf(stderr, "Could not create the log file: %s\n", strerror(errno));
+ goto BAIL;
+ }
+
+ /* Create a file object from the descriptor. */
+ log_file = fdopen(log_fd, "w");
+ if (log_file == NULL) {
+
+ fprintf(stderr, "Could not recreate the log file: %s\n", strerror(errno));
+ goto BAIL;
+ }
+
+ log_fd = -1;
+
+ printf("Writing cloud keychain diagnostics to %s\n", log_path);
+
+ /* Dump the system information. */
+ if (dump_system_information(log_file)) {
+
+ fprintf(stderr, "Could not dump the system information\n");
+ goto BAIL;
+ }
+
+ /* Dump the SOS circle state. */
+ if (dump_circle_state(log_file)) {
+
+ fprintf(stderr, "Could not dump the SOS circle state\n");
+ goto BAIL;
+ }
+
+ /* Dump the raw keychain syncing KVS. */
+ if (dump_keychain_sync_kvs(log_file)) {
+
+ fprintf(stderr, "Could not the raw keychain syncing KVS\n");
+ goto BAIL;
+ }
+
+ /*
+ * Dump the various and sundry ASL logs.
+ */
+
+ if (dump_asl_sender(log_file, "com.apple.kb-service")) {
+
+ fprintf(stderr, "Could not dump the ASL log for com.apple.kb-service\n");
+ goto BAIL;
+ }
+
+ if (dump_asl_sender(log_file, "com.apple.securityd")) {
+
+ fprintf(stderr, "Could not dump the ASL log for com.apple.securityd\n");
+ goto BAIL;
+ }
+
+ if (dump_asl_sender(log_file, "com.apple.secd")) {
+
+ fprintf(stderr, "Could not dump the ASL log for com.apple.secd\n");
+ goto BAIL;
+ }
+
+ if (dump_asl_sender(log_file, "CloudKeychainProxy")) {
+
+ fprintf(stderr, "Could not dump the ASL log for CloudKeychainProxy\n");
+ goto BAIL;
+ }
+
+ if (dump_asl_sender(log_file, "securityd")) {
+
+ fprintf(stderr, "Could not dump the ASL log for securityd\n");
+ goto BAIL;
+ }
+
+ if (dump_asl_sender(log_file, "secd")) {
+
+ fprintf(stderr, "Could not dump the ASL log for secd\n");
+ goto BAIL;
+ }
+
+ /* Set the result to success. */
+ result = SUCCESS;
+
+BAIL:
+
+ /* Close the diagnostics file? */
+ if (log_file != NULL) {
+
+ fclose(log_file);
+ log_file = NULL;
+ }
+
+ /* Close the diagnostics file descriptor? */
+ if (log_fd != -1) {
+
+ close(log_fd);
+ log_fd = -1;
+ }
+
+ return result;
+}
+
+static
+int
+enable_cloud_keychain_diagnostics(
+ const unsigned int enable_flag)
+{
+ int result = FAILURE;
+
+ /* Set the result to success. */
+ result = SUCCESS;
+
+ return result;
+}
+
+static
+int
+build_log_path(
+ char *log_path)
+{
+ int result = FAILURE;
+ time_t now;
+ struct tm *time_cube;
+ CFDictionaryRef system_version_dict = NULL;
+ CFStringRef product_name = NULL;
+
+ /* Get the current time. */
+ now = time(NULL);
+
+ /* Convert the time into something usable. */
+ time_cube = localtime(&now);
+ if (time_cube == NULL) {
+
+ fprintf(stderr, "I don't know what time it is.\n");
+ goto BAIL;
+ }
+
+ /* Copy the system version dictionary. */
+ system_version_dict = _CFCopySystemVersionDictionary();
+ if (system_version_dict == NULL) {
+
+ fprintf(stderr, "Could not copy the system version dictionary\n");
+ goto BAIL;
+ }
+
+ /* Extract the product name. */
+ product_name = CFDictionaryGetValue(system_version_dict, _kCFSystemVersionProductNameKey);
+ if (product_name == NULL) {
+
+ fprintf(stderr, "Could not extract the product name from the system version dictionary\n");
+ goto BAIL;
+ }
+
+ /* Is this a Mac? */
+ if (CFEqual(product_name, CFSTR("Mac OS X"))) {
+
+ /* Prepare the file template to go into /tmp. */
+ snprintf(
+ log_path,
+ MAX_PATH_LEN,
+ "/tmp/cloud_keychain_diagnostics.%d_%d_%d.%d%d%d.XXXX.txt",
+ 1900 + time_cube->tm_year,
+ time_cube->tm_mon,
+ time_cube->tm_mday,
+ time_cube->tm_hour,
+ time_cube->tm_min,
+ time_cube->tm_sec);
+ } else {
+
+ /* Prepare the file template to go into CrashReporter. */
+ snprintf(
+ log_path,
+ MAX_PATH_LEN,
+ "/Library/Logs/CrashReporter/cloud_keychain_diagnostics.%d_%d_%d.%d%d%d.XXXX.txt",
+ 1900 + time_cube->tm_year,
+ time_cube->tm_mon,
+ time_cube->tm_mday,
+ time_cube->tm_hour,
+ time_cube->tm_min,
+ time_cube->tm_sec);
+ }
+
+ /* Set the result to success. */
+ result = SUCCESS;
+
+BAIL:
+
+ /* Release the system version dictionary? */
+ if (system_version_dict != NULL) {
+
+ CFRelease(system_version_dict);
+ system_version_dict = NULL;
+ }
+
+ return result;
+}
+
+static
+int
+dump_system_information(
+ FILE *log_file)
+{
+ int result = FAILURE;
+ CFDictionaryRef dict = NULL;
+ char buffer[BUFFER_SIZE];
+ CFStringRef product_name;
+ CFStringRef product_version;
+ CFStringRef product_build_version;
+ time_t now;
+ CFTypeRef shim_flag = NULL;
+ int keybag_handle = bad_keybag_handle;
+ kern_return_t kr = 0;
+ keybag_state_t keybag_state = 0;
+
+ /*
+ * Dump the system information.
+ * ProductName
+ * ProductVersion
+ * ProductBuildVersion
+ * Host name
+ */
+
+ /* Dump a header. */
+ fprintf(log_file, "Host Information:\n");
+ fprintf(log_file, "=================\n");
+
+ /* Copy the system version dictionary. */
+ dict = _CFCopySystemVersionDictionary();
+ if (dict == NULL) {
+
+ fprintf(stderr, "Could not copy the system version dictionary\n");
+ goto BAIL;
+ }
+
+ /* Extract the product name. */
+ product_name = CFDictionaryGetValue(dict, _kCFSystemVersionProductNameKey);
+ if (product_name == NULL) {
+
+ fprintf(stderr, "Could not extract the product name from the system version dictionary\n");
+ goto BAIL;
+ }
+
+ /* Convert the product name to a C string. */
+ if (!CFStringGetCString(product_name, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the product name to a C string\n");
+ goto BAIL;
+ }
+
+ /* Dump the product name. */
+ fprintf(log_file, "Product Name: %s\n", buffer);
+
+ /* Extract the product version. */
+ product_version = CFDictionaryGetValue(dict, _kCFSystemVersionProductVersionKey);
+ if (product_version == NULL) {
+
+ fprintf(stderr, "Could not extract the product version from the system version dictionary\n");
+ goto BAIL;
+ }
+
+ /* Convert the product version to a C string. */
+ if (!CFStringGetCString(product_version, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the product version to a C string\n");
+ goto BAIL;
+ }
+
+ /* Dump the product version */
+ fprintf(log_file, "Product Version: %s\n", buffer);
+
+ /* Extract the product build version. */
+ product_build_version = CFDictionaryGetValue(dict, _kCFSystemVersionBuildVersionKey);
+ if (product_build_version == NULL) {
+
+ fprintf(stderr, "Could not extract the product build version from the system version dictionary\n");
+ goto BAIL;
+ }
+
+ /* Convert the product build version to a C string. */
+ if (!CFStringGetCString(product_build_version, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the product build version to a C string\n");
+ goto BAIL;
+ }
+
+ /* Dump the product build version. */
+ fprintf(log_file, "Product Build Version: %s\n", buffer);
+
+ /* Lookup the host name. */
+ if (gethostname(buffer, BUFFER_SIZE) == -1) {
+
+ fprintf(stderr, "Could not lookup the host name\n");
+ goto BAIL;
+ }
+
+ /* Dump the host name. */
+ fprintf(log_file, "Host Name: %s\n", buffer);
+
+ /* Lookup the current time. */
+ if (gethostname(buffer, BUFFER_SIZE) == -1) {
+
+ fprintf(stderr, "Could not lookup the host name\n");
+ goto BAIL;
+ }
+
+ /* Get the current time. */
+ now = time(NULL);
+
+ /* Dump the current time. */
+ fprintf(log_file, "Time: %s", ctime(&now));
+
+ /* Is this a Mac? */
+ if (CFEqual(product_name, CFSTR("Mac OS X"))) {
+
+ /* Set the keybag handle. */
+ keybag_handle = session_keybag_handle;
+
+ /* Lookup the state of the shim. */
+ shim_flag = (CFNumberRef)CFPreferencesCopyValue(CFSTR("SecItemSynchronizable"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
+ if (shim_flag && CFGetTypeID(shim_flag) == CFBooleanGetTypeID()) {
+
+ /* Is the shim enabled? */
+ if (CFBooleanGetValue((CFBooleanRef)shim_flag)) {
+
+ fprintf(log_file, "The SecItem shim is enabled\n");
+ } else {
+
+ fprintf(log_file, "The SecItem shim is disabled\n");
+ }
+ } else {
+
+ fprintf(log_file, "The SecItem shim is disabled\n");
+ }
+ } else {
+
+ /* Set the keybag handle. */
+ keybag_handle = device_keybag_handle;
+ }
+
+ /* Get the keybag state. */
+ kr = aks_get_lock_state(keybag_handle, &keybag_state);
+ if (kr) {
+
+ fprintf(stderr, "Could not call aks_get_lock_state\n");
+ } else {
+
+ switch (keybag_state) {
+
+ case keybag_state_unlocked: {
+
+ fprintf(log_file, "Keybag State: Unlocked\n");
+ }break;
+
+ case keybag_state_locked: {
+
+ fprintf(log_file, "Keybag State: Locked\n");
+ }break;
+
+ case keybag_state_no_pin: {
+
+ fprintf(log_file, "Keybag State: No Passcode\n");
+ }break;
+
+ case keybag_state_been_unlocked: {
+
+ fprintf(log_file, "Keybag State: Been Unlocked\n");
+ }break;
+
+ case my_keybag_state_bio_unlock: {
+
+ fprintf(log_file, "Keybag State: Bio Unlock\n");
+ }break;
+
+ default: {
+
+ fprintf(log_file, "Keybag State: UNKNOWN\n");
+ }break;
+ }
+ }
+
+ /* Dump a footer. */
+ fprintf(log_file, "=================\n\n");
+
+ /* Set the result to success. */
+ result = SUCCESS;
+
+BAIL:
+
+ /* Release the shim flag? */
+ if (shim_flag) {
+
+ CFRelease(shim_flag);
+ shim_flag = NULL;
+ }
+
+ /* Release the system version dictionary? */
+ if (dict != NULL) {
+
+ CFRelease(dict);
+ dict = NULL;
+ }
+
+ return result;
+}
+
+static
+int
+dump_circle_state(
+ FILE *log_file)
+{
+ int result = FAILURE;
+ CFErrorRef error = NULL;
+ SOSCCStatus circle_status;
+ char *circle_state_string = NULL;
+ CFArrayRef peer_list = NULL;
+ CFIndex num_peers;
+ CFIndex i;
+ SOSPeerInfoRef peer_info;
+ CFDictionaryRef peer_gestalt = NULL;
+ CFStringRef peer_name;
+ CFStringRef peer_device_type;
+ CFStringRef peerID;
+ char buffer[BUFFER_SIZE];
+
+ /*
+ * Dump the SOS circle state.
+ */
+
+ /* Dump a header. */
+ fprintf(log_file, "SOS Circle State:\n");
+ fprintf(log_file, "=================\n");
+
+ /* Are we in a circle? */
+ circle_status = SOSCCThisDeviceIsInCircle(&error);
+ if (error != NULL) {
+
+ /* Dump and consume the error. */
+ dump_cferror(log_file, "Could not call SOSCCThisDeviceIsInCircle", error);
+ } else {
+
+ switch (circle_status) {
+
+ case kSOSCCInCircle: {
+ circle_state_string = "kSOSCCInCircle";
+ }break;
+
+ case kSOSCCNotInCircle: {
+ circle_state_string = "kSOSCCNotInCircle";
+ }break;
+
+ case kSOSCCRequestPending: {
+ circle_state_string = "kSOSCCRequestPending";
+ }break;
+
+ case kSOSCCCircleAbsent: {
+ circle_state_string = "kSOSCCCircleAbsent";
+ }break;
+
+ case kSOSCCError: {
+ circle_state_string = "kSOSCCError";
+ }break;
+
+ case kSOSCCParamErr: {
+ circle_state_string = "kSOSCCParamErr";
+ }break;
+
+ case kSOSCCMemoryErr: {
+ circle_state_string = "kSOSCCMemoryErr";
+ }break;
+
+ default: {
+ circle_state_string = "Unknown circle status?";
+ }
+ }
+
+ fprintf(log_file, "Circle Status: %s\n", circle_state_string);
+ }
+
+ /* Can we authenticate? */
+ if (!SOSCCCanAuthenticate(&error)) {
+
+ if (error) {
+
+ /* Dump and consume the error. */
+ dump_cferror(log_file, "Could not call SOSCCCanAuthenticate", error);
+ } else {
+
+ fprintf(log_file, "Can Authenticate: NO\n");
+ }
+ } else {
+
+ fprintf(log_file, "Can Authenticate: YES\n");
+ }
+
+ /* Copy the peers. */
+ peer_list = SOSCCCopyPeerPeerInfo(&error);
+ if (error) {
+
+ /* Dump the error. */
+ dump_cferror(log_file, "Could not call SOSCCCopyPeerPeerInfo", error);
+ } else {
+
+ /* Get the number of peers. */
+ num_peers = CFArrayGetCount(peer_list);
+
+ fprintf(log_file, "Number of syncing peers: %ld\n", num_peers);
+
+ if (num_peers > 0) {
+
+ fprintf(log_file, "\n");
+ }
+
+ /* Enumerate the peers. */
+ for (i = 0; i < num_peers; i++) {
+
+ peer_info = (SOSPeerInfoRef) CFArrayGetValueAtIndex(peer_list, i);
+ if (peer_info == NULL) {
+
+ fprintf(stderr, "Could not extract peer %ld of %ld\n", i, num_peers);
+ goto BAIL;
+ }
+
+ /*
+ peer_gestalt = SOSPeerInfoCopyPeerGestalt(peer_info);
+ if (peer_gestalt == NULL) {
+
+ fprintf(stderr, "Could not copy peer gestalt %ld of %ld\n", i, num_peers);
+ goto BAIL;
+ }
+ */
+
+ /* Get the peer name. */
+ peer_name = SOSPeerInfoGetPeerName(peer_info);
+ if (peer_name == NULL) {
+
+ fprintf(stderr, "Could not extract peer name %ld of %ld\n", i, num_peers);
+ goto BAIL;
+ }
+
+ /* Convert the peer name to a C string. */
+ if (!CFStringGetCString(peer_name, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the peer name to a C string\n");
+ goto BAIL;
+ }
+
+ /* Dump the peer name. */
+ fprintf(log_file, " Peer Name: %s\n", buffer);
+
+ /* Get the peer device type. */
+ peer_device_type = SOSPeerInfoGetPeerDeviceType(peer_info);
+ if (peer_device_type == NULL) {
+
+ fprintf(stderr, "Could not extract peer device type %ld of %ld\n", i, num_peers);
+ goto BAIL;
+ }
+
+ /* Convert the peer device type to a C string. */
+ if (!CFStringGetCString(peer_device_type, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the peer device type to a C string\n");
+ goto BAIL;
+ }
+
+ /* Dump the peer name. */
+ fprintf(log_file, " Peer Device Type: %s\n", buffer);
+
+ /* Get the peer ID. */
+ peerID = SOSPeerInfoGetPeerID(peer_info);
+ if (peerID == NULL) {
+
+ fprintf(stderr, "Could not extract peer ID %ld of %ld\n", i, num_peers);
+ goto BAIL;
+ }
+
+ /* Dump the peer name. */
+ fprintf(log_file, " Peer ID: %s\n", buffer);
+
+ /* Convert the peer ID to a C string. */
+ if (!CFStringGetCString(peerID, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the peer ID to a C string\n");
+ goto BAIL;
+ }
+
+ /* Make it pretty. */
+ fprintf(log_file, "\n");
+ }
+
+ /* Release the peer list. */
+ CFRelease(peer_list);
+ peer_list = NULL;
+ }
+
+ /* Copy the applicant peers. */
+ peer_list = SOSCCCopyApplicantPeerInfo(&error);
+ if (error) {
+
+ /* Dump the error. */
+ dump_cferror(log_file, "Could not call SOSCCCopyApplicantPeerInfo", error);
+ } else {
+
+ /* Get the number of peers. */
+ num_peers = CFArrayGetCount(peer_list);
+
+ fprintf(log_file, "Number of applicant peers: %ld\n", num_peers);
+
+ if (num_peers > 0) {
+
+ fprintf(log_file, "\n");
+ }
+
+ /* Enumerate the peers. */
+ for (i = 0; i < num_peers; i++) {
+
+ peer_info = (SOSPeerInfoRef) CFArrayGetValueAtIndex(peer_list, i);
+ if (peer_info == NULL) {
+
+ fprintf(stderr, "Could not extract peer %ld of %ld\n", i, num_peers);
+ goto BAIL;
+ }
+
+ /*
+ peer_gestalt = SOSPeerInfoCopyPeerGestalt(peer_info);
+ if (peer_gestalt == NULL) {
+
+ fprintf(stderr, "Could not copy peer gestalt %ld of %ld\n", i, num_peers);
+ goto BAIL;
+ }
+ */
+
+ /* Get the peer name. */
+ peer_name = SOSPeerInfoGetPeerName(peer_info);
+ if (peer_name == NULL) {
+
+ fprintf(stderr, "Could not extract peer name %ld of %ld\n", i, num_peers);
+ goto BAIL;
+ }
+
+ /* Convert the peer name to a C string. */
+ if (!CFStringGetCString(peer_name, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the peer name to a C string\n");
+ goto BAIL;
+ }
+
+ /* Dump the peer name. */
+ fprintf(log_file, " Applicant Name: %s\n", buffer);
+
+ /* Get the peer device type. */
+ peer_device_type = SOSPeerInfoGetPeerDeviceType(peer_info);
+ if (peer_device_type == NULL) {
+
+ fprintf(stderr, "Could not extract peer device type %ld of %ld\n", i, num_peers);
+ goto BAIL;
+ }
+
+ /* Convert the peer device type to a C string. */
+ if (!CFStringGetCString(peer_device_type, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the peer device type to a C string\n");
+ goto BAIL;
+ }
+
+ /* Dump the peer name. */
+ fprintf(log_file, " Applicant Device Type: %s\n", buffer);
+
+ /* Get the peer ID. */
+ peerID = SOSPeerInfoGetPeerID(peer_info);
+ if (peerID == NULL) {
+
+ fprintf(stderr, "Could not extract peer ID %ld of %ld\n", i, num_peers);
+ goto BAIL;
+ }
+
+ /* Dump the peer name. */
+ fprintf(log_file, " Applicant ID: %s\n", buffer);
+
+ /* Convert the peer ID to a C string. */
+ if (!CFStringGetCString(peerID, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the peer ID to a C string\n");
+ goto BAIL;
+ }
+
+ /* Make it pretty. */
+ if (i < num_peers - 1) {
+
+ fprintf(log_file, "\n");
+ }
+ }
+
+ /* Release the peer list. */
+ CFRelease(peer_list);
+ peer_list = NULL;
+ }
+
+ /* Dump a footer. */
+ fprintf(log_file, "=================\n\n");
+
+ /* Set the result to success. */
+ result = SUCCESS;
+
+BAIL:
+
+ /* Release the peer gestalt? */
+ if (peer_gestalt != NULL) {
+
+ CFRelease(peer_gestalt);
+ peer_gestalt = NULL;
+ }
+
+ /* Release the peer list? */
+ if (peer_list != NULL) {
+
+ CFRelease(peer_list);
+ peer_list = NULL;
+ }
+
+ /* Release the error string? */
+ if (error != NULL) {
+
+ CFRelease(error);
+ error = NULL;
+ }
+
+ return result;
+}
+
+static
+int
+dump_keychain_sync_kvs(
+ FILE *log_file)
+{
+ int result = FAILURE;
+ dispatch_group_t cloud_group;
+ dispatch_queue_t cloud_queue;
+ dispatch_semaphore_t waitSemaphore;
+ dispatch_time_t finishTime;
+ __block CFDictionaryRef kvs_dict = NULL;
+
+ /*
+ * Dump the keychain syncing KVS.
+ */
+
+ /* Dump a header. */
+ fprintf(log_file, "Keychain Syncing KVS:\n");
+ fprintf(log_file, "=================\n");
+
+ /* Create the serial dispatch queue to talk to CloudKeychainProxy. */
+ cloud_queue = dispatch_queue_create("cloud_queue", DISPATCH_QUEUE_SERIAL);
+
+ /* Create a semaphore. */
+ waitSemaphore = dispatch_semaphore_create(0);
+
+ /* Create the finish time. */
+ finishTime = dispatch_time(DISPATCH_TIME_NOW, 30ull * NSEC_PER_SEC);
+
+ /* Create the dispatch group. */
+ cloud_group = dispatch_group_create();
+
+ /* Enter the dispatch group. */
+ dispatch_group_enter(cloud_group);
+
+ /* Establish the CloudKeychainProxy reply hander. */
+ CloudKeychainReplyBlock replyBlock = ^(CFDictionaryRef returnedValues, CFErrorRef error)
+ {
+ /* Did we get back some values? */
+ if (returnedValues) {
+
+ kvs_dict = (returnedValues);
+ CFRetain(kvs_dict);
+ }
+
+ /* Leave the cloud group. */
+ dispatch_group_leave(cloud_group);
+
+ /* Signal the other queue we're done. */
+ dispatch_semaphore_signal(waitSemaphore);
+ };
+
+ /* Ask CloudKeychainProxy for all of the raw KVS data. */
+ SOSCloudKeychainGetAllObjectsFromCloud(cloud_queue, replyBlock);
+
+ /* Wait for CloudKeychainProxy to respond, up to 30 seconds. */
+ dispatch_semaphore_wait(waitSemaphore, finishTime);
+
+ /* Release the semaphore. */
+ dispatch_release(waitSemaphore);
+
+ /* Did we get any raw KVS data from CloudKeychainProxy? */
+ if (kvs_dict) {
+
+ dump_dict(log_file, kvs_dict, 0);
+ }
+
+ /* Dump a footer. */
+ fprintf(log_file, "=================\n\n");
+
+ /* Set the result to success. */
+ result = SUCCESS;
+
+ /* Release the KVS dictionary? */
+ if (kvs_dict != NULL) {
+
+ CFRelease(kvs_dict);
+ kvs_dict = NULL;
+ }
+
+ return result;
+}
+
+static
+void
+dump_dict(
+ FILE *log_file,
+ CFDictionaryRef dict,
+ const unsigned int indent_level)
+{
+ struct dict_dump_state dump_state;
+
+ /* Setup the context. */
+ dump_state.log_file = log_file;
+ dump_state.dict = dict;
+ dump_state.indent_level = indent_level;
+
+ /* Apply the dumper to each element in the dictionary. */
+ CFDictionaryApplyFunction(dict, dump_dict_applier, (void *)&dump_state);
+}
+
+static
+void
+dump_dict_applier(
+ const void *key,
+ const void *value,
+ void *context)
+{
+ CFTypeRef key_object;
+ CFTypeRef value_object;
+ struct dict_dump_state *dump_state;
+ unsigned int i;
+ char buffer[BUFFER_SIZE];
+ CFIndex length;
+ const UInt8* bytes;
+
+ /* Assign the CF types. */
+ key_object = (CFTypeRef) key;
+ value_object = (CFTypeRef) value;
+
+ /* Get the context. */
+ dump_state = (struct dict_dump_state *)context;
+
+ /* Indent appropriately. */
+ for (i = 0; i < dump_state->indent_level; i++) {
+
+ fprintf(dump_state->log_file, " ");
+ }
+
+ /* Determine the key type. */
+ if (CFGetTypeID(key_object) == CFStringGetTypeID()) {
+
+ /* Convert the key to a C string. */
+ if (!CFStringGetCString((CFStringRef) key_object, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the key to a C string\n");
+ fprintf(dump_state->log_file, "[Failed Key Type]: ");
+ } else {
+
+ fprintf(dump_state->log_file, "%s: ", buffer);
+ }
+ }
+
+ /* Determine the value type. */
+ if (CFGetTypeID(value_object) == CFStringGetTypeID()) {
+
+ /* Convert the value to a C string. */
+ if (!CFStringGetCString((CFStringRef) value_object, buffer, BUFFER_SIZE, kCFStringEncodingUTF8)) {
+
+ fprintf(stderr, "Could not convert the value to a C string\n");
+ fprintf(dump_state->log_file, "[Failed Value Type]: ");
+ } else {
+
+ fprintf(dump_state->log_file, "%s\n", buffer);
+ }
+ } else if (CFGetTypeID(value_object) == CFDataGetTypeID()) {
+
+ length = CFDataGetLength((CFDataRef)value_object);
+ bytes = CFDataGetBytePtr((CFDataRef) value_object);
+
+ fprintf(dump_state->log_file, "0x");
+
+ for (i = 0; i < (unsigned int)length && i < MAX_DATA_RATE; i++) {
+
+ fprintf(dump_state->log_file, "%02x", (unsigned char)bytes[i]);
+ }
+
+ fprintf(dump_state->log_file, " (%ld bytes)\n", length);
+
+
+ } else if (CFGetTypeID(value_object) == CFDictionaryGetTypeID()) {
+
+ fprintf(dump_state->log_file, "\n");
+ dump_dict(dump_state->log_file, (CFDictionaryRef) value_object, dump_state->indent_level + 1);
+ } else {
+
+ fprintf(dump_state->log_file, "[Unknown Value Type]\n");
+ }
+}
+
+static
+int
+dump_asl_sender(
+ FILE *log_file,
+ const char *asl_sender)
+{
+ int result = FAILURE;
+ aslmsg log_query = NULL;
+ aslresponse log_response = NULL;
+ aslmsg log_message;
+ char *message_string;
+ uint32_t message_length;
+
+ /*
+ * Dump the ASL logs for the given sender.
+ */
+
+ /* Dump a header. */
+ fprintf(log_file, "ASL: %s\n", asl_sender);
+ fprintf(log_file, "=================\n");
+
+ /* Create the ASL query. */
+ log_query = asl_new(ASL_TYPE_QUERY);
+ if (log_query == NULL) {
+
+ fprintf(stderr, "Could not create ASL query\n");
+ goto BAIL;
+ }
+
+ /* Setup the ASL query. */
+ asl_set_query(log_query, ASL_KEY_SENDER, asl_sender, ASL_QUERY_OP_EQUAL);
+
+ /* Perform the ASL search. */
+ log_response = asl_search(NULL, log_query);
+ if (log_response == NULL) {
+
+ fprintf(log_file, "Could not perform ASL search for %s\n", asl_sender);
+ } else {
+
+ /* Enumerate the ASL messages in the response. */
+ while ((log_message = aslresponse_next(log_response)) != NULL) {
+
+ /* Format the message entry. */
+ message_string = asl_format_message((asl_msg_t *)log_message, ASL_MSG_FMT_STD, ASL_TIME_FMT_LCL, ASL_ENCODE_SAFE, &message_length);
+ if (message_string == NULL) {
+
+ fprintf(stderr, "Could not create ASL message string\n");
+ goto BAIL;
+ }
+
+ fprintf(log_file, "%s", message_string);
+
+ /* Release the message string. */
+ free(message_string);
+ message_string = NULL;
+ }
+ }
+
+ /* Dump a footer. */
+ fprintf(log_file, "=================\n\n");
+
+ /* Set the result to success. */
+ result = SUCCESS;
+
+BAIL:
+
+ /* Release the ASL response? */
+ if (log_response != NULL) {
+
+ aslresponse_free(log_response);
+ log_response = NULL;
+ }
+
+ /* Release the ASL query? */
+ if (log_query != NULL) {
+
+ asl_free(log_query);
+ log_query = NULL;
+ }
+
+ return result;
+}
+
+static
+void
+dump_cferror(
+ FILE *log_file,
+ const char *description,
+ CFErrorRef error)
+{
+ CFStringRef error_string = NULL;
+ char buffer[BUFFER_SIZE];
+
+ error_string = CFErrorCopyDescription(error);
+ if (error_string == NULL) {
+
+ fprintf(stderr, "Could not copy error description?\n");
+ goto BAIL;
+ }
+
+ (void) CFStringGetCString(error_string, buffer, BUFFER_SIZE, kCFStringEncodingUTF8);
+
+ fprintf(stderr, "%s: %s\n", description, buffer);
+ fprintf(log_file, "%s: %s\n", description, buffer);
+
+BAIL:
+
+ /* Release the error string? */
+ if (error_string != NULL) {
+
+ CFRelease(error_string);
+ error_string = NULL;
+ }
+}
+
+#else // TARGET_IPHONE_SIMULATOR
+
+int
+main(
+ int argc,
+ char **argv)
+{
+#pragma unused (argc, argv)
+ return 0;
+}
+
+#endif