--- /dev/null
+/*
+ * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "iCloudKeychainTrace.h"
+#include <TargetConditionals.h>
+#include <inttypes.h>
+#include "SecCFWrappers.h"
+#include <sys/time.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+const CFStringRef kNumberOfiCloudKeychainPeers = CFSTR("numberOfPeers");
+const CFStringRef kNumberOfiCloudKeychainItemsBeingSynced = CFSTR("numberOfItemsBeingSynced");
+const CFStringRef kCloudKeychainNumberOfSyncingConflicts = CFSTR("conflictsCount");
+const CFStringRef kCloudKeychainNumberOfTimesSyncFailed = CFSTR("syncFailureCount");
+const CFStringRef kCloudKeychainNumberOfConflictsResolved = CFSTR("conflictsResolved");
+const CFStringRef kCloudKeychainNumberOfTimesSyncedWithPeers = CFSTR("syncedWithPeers");
+
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+static const char* gTopLevelKeyForiCloudKeychainTracing = "com.apple.cloudkeychain";
+#endif
+
+#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
+static const char* gTopLevelKeyForiCloudKeychainTracing = "com.apple.cloudkeychain";
+#endif
+
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
+#include <asl.h>
+
+static const char* gMessageTracerSetPrefix = "com.apple.message.";
+
+static const char* gMessageTracerDomainField = "com.apple.message.domain";
+
+/* --------------------------------------------------------------------------
+ Function: OSX_BeginCloudKeychainLoggingTransaction
+
+ Description: For OSX the message tracer back end wants its logging
+ done in "bunches". This function allows for beginning
+ a 'transaction' of logging which will allow for putting
+ all of the transactions items into a single log making
+ the message tracer folks happy.
+
+ The work of this function is to create the aslmsg context
+ and set the domain field and then return the aslmsg
+ context as a void*
+ -------------------------------------------------------------------------- */
+static void* OSX_BeginCloudKeychainLoggingTransaction()
+{
+ void* result = NULL;
+ aslmsg mAsl = NULL;
+ mAsl = asl_new(ASL_TYPE_MSG);
+ if (NULL == mAsl)
+ {
+ return result;
+ }
+
+ asl_set(mAsl, gMessageTracerDomainField, gTopLevelKeyForiCloudKeychainTracing);
+
+ result = (void *)mAsl;
+ return result;
+}
+
+/* --------------------------------------------------------------------------
+ Function: OSX_AddKeyValuePairToKeychainLoggingTransaction
+
+ Description: Once a call to OSX_BeginCloudKeychainLoggingTransaction
+ is done, this call all allow for adding items to the
+ "bunch" of items being logged.
+
+ NOTE: The key should be a simple key such as
+ "numberOfPeers". This is because this function will
+ apptend the required prefix of "com.apple.message."
+ -------------------------------------------------------------------------- */
+static bool OSX_AddKeyValuePairToKeychainLoggingTransaction(void* token, CFStringRef key, int64_t value)
+{
+ if (NULL == token || NULL == key)
+ {
+ return false;
+ }
+
+ aslmsg mAsl = (aslmsg)token;
+
+ // Fix up the key
+ CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%@"), gMessageTracerSetPrefix, key);
+ if (NULL == real_key)
+ {
+ return false;
+ }
+
+ CFIndex key_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key), kCFStringEncodingUTF8);
+ key_length += 1; // For null
+ char key_buffer[key_length];
+ memset(key_buffer, 0,key_length);
+ if (!CFStringGetCString(real_key, key_buffer, key_length, kCFStringEncodingUTF8))
+ {
+ CFRelease(real_key);
+ return false;
+ }
+ CFRelease(real_key);
+
+ CFStringRef value_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lld"), value);
+ if (NULL == value_str)
+ {
+ return false;
+ }
+
+ CFIndex value_str_numBytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str), kCFStringEncodingUTF8);
+ value_str_numBytes += 1; // For null
+ char value_buffer[value_str_numBytes];
+ memset(value_buffer, 0, value_str_numBytes);
+ if (!CFStringGetCString(value_str, value_buffer, value_str_numBytes, kCFStringEncodingUTF8))
+ {
+ CFRelease(value_str);
+ return false;
+ }
+ CFRelease(value_str);
+
+ asl_set(mAsl, key_buffer, value_buffer);
+ return true;
+}
+
+/* --------------------------------------------------------------------------
+ Function: OSX_CloseCloudKeychainLoggingTransaction
+
+ Description: Once a call to OSX_BeginCloudKeychainLoggingTransaction
+ is done, and all of the items that are to be in the
+ "bunch" of items being logged, this function will do the
+ real logging and free the aslmsg context.
+ -------------------------------------------------------------------------- */
+static void OSX_CloseCloudKeychainLoggingTransaction(void* token)
+{
+ if (NULL != token)
+ {
+ aslmsg mAsl = (aslmsg)token;
+ asl_log(NULL, mAsl, ASL_LEVEL_NOTICE, "");
+ asl_free(mAsl);
+ }
+}
+
+/* --------------------------------------------------------------------------
+ Function: OSX_SetCloudKeychainTraceValueForKey
+
+ Description: If "bunching" of items either cannot be done or is not
+ desired, then this 'single shot' function shold be used.
+ It will create the aslmsg context, register the domain
+ fix up the key and log the key value pair and then
+ do the real logging and free the aslmsg context.
+ -------------------------------------------------------------------------- */
+static bool OSX_SetCloudKeychainTraceValueForKey(CFStringRef key, int64_t value)
+{
+ bool result = false;
+
+ if (NULL == key)
+ {
+ return result;
+ }
+
+ aslmsg mAsl = NULL;
+ mAsl = asl_new(ASL_TYPE_MSG);
+ if (NULL == mAsl)
+ {
+ return result;
+ }
+
+ // Fix up the key
+ CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%@"), gMessageTracerSetPrefix, key);
+ if (NULL == real_key)
+ {
+ return false;
+ }
+
+ CFIndex key_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key), kCFStringEncodingUTF8);
+ key_length += 1; // For null
+ char key_buffer[key_length];
+ memset(key_buffer, 0,key_length);
+ if (!CFStringGetCString(real_key, key_buffer, key_length, kCFStringEncodingUTF8))
+ {
+ CFRelease(real_key);
+ return false;
+ }
+ CFRelease(real_key);
+
+
+ CFStringRef value_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lld"), value);
+ if (NULL == value_str)
+ {
+ asl_free(mAsl);
+ return result;
+ }
+
+ CFIndex value_str_numBytes = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str), kCFStringEncodingUTF8);
+ value_str_numBytes += 1; // For null
+ char value_buffer[value_str_numBytes];
+ memset(value_buffer, 0, value_str_numBytes);
+ if (!CFStringGetCString(value_str, value_buffer, value_str_numBytes, kCFStringEncodingUTF8))
+ {
+ asl_free(mAsl);
+ CFRelease(value_str);
+ return result;
+ }
+ CFRelease(value_str);
+
+ asl_set(mAsl, gMessageTracerDomainField, gTopLevelKeyForiCloudKeychainTracing);
+
+ asl_set(mAsl, key_buffer, value_buffer);
+ asl_log(NULL, mAsl, ASL_LEVEL_NOTICE, "%s is %lld", key_buffer, value);
+ asl_free(mAsl);
+ return true;
+
+}
+#endif
+
+#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
+
+typedef void (*type_ADClientClearScalarKey)(CFStringRef key);
+typedef void (*type_ADClientAddValueForScalarKey)(CFStringRef key, int64_t value);
+
+static type_ADClientClearScalarKey gADClientClearScalarKey = NULL;
+static type_ADClientAddValueForScalarKey gADClientAddValueForScalarKey = NULL;
+
+static dispatch_once_t gADFunctionPointersSet = 0;
+static CFBundleRef gAggdBundleRef = NULL;
+static bool gFunctionPointersAreLoaded = false;
+
+/* --------------------------------------------------------------------------
+ Function: InitializeADFunctionPointers
+
+ Description: Linking to the Aggregate library causes a build cycle so
+ This function will dynamically load the needed function
+ pointers.
+ -------------------------------------------------------------------------- */
+static bool InitializeADFunctionPointers()
+{
+ if (gFunctionPointersAreLoaded)
+ {
+ return gFunctionPointersAreLoaded;
+ }
+
+ dispatch_once(&gADFunctionPointersSet,
+ ^{
+ CFStringRef path_to_aggd_framework = CFSTR("/System/Library/PrivateFrameworks/AggregateDictionary.framework");
+
+ CFURLRef aggd_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_to_aggd_framework, kCFURLPOSIXPathStyle, true);
+
+ if (NULL != aggd_url)
+ {
+ gAggdBundleRef = CFBundleCreate(kCFAllocatorDefault, aggd_url);
+ if (NULL != gAggdBundleRef)
+ {
+ gADClientClearScalarKey = (type_ADClientClearScalarKey)
+ CFBundleGetFunctionPointerForName(gAggdBundleRef, CFSTR("ADClientClearScalarKey"));
+
+ gADClientAddValueForScalarKey = (type_ADClientAddValueForScalarKey)
+ CFBundleGetFunctionPointerForName(gAggdBundleRef, CFSTR("ADClientAddValueForScalarKey"));
+ }
+ CFRelease(aggd_url);
+ }
+ });
+
+ gFunctionPointersAreLoaded = ((NULL != gADClientClearScalarKey) && (NULL != gADClientAddValueForScalarKey));
+ return gFunctionPointersAreLoaded;
+}
+
+/* --------------------------------------------------------------------------
+ Function: Internal_ADClientClearScalarKey
+
+ Description: This fucntion is a wrapper around calling the
+ ADClientClearScalarKey function.
+
+ NOTE: The key should be a simple key such as
+ "numberOfPeers". This is because this function will
+ apptend the required prefix of "com.apple.cloudkeychain"
+ -------------------------------------------------------------------------- */
+static void Internal_ADClientClearScalarKey(CFStringRef key)
+{
+ if (InitializeADFunctionPointers())
+ {
+ CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%@"), gTopLevelKeyForiCloudKeychainTracing, key);
+ if (NULL == real_key)
+ {
+ return;
+ }
+
+ gADClientClearScalarKey(real_key);
+ CFRelease(real_key);
+ }
+}
+
+/* --------------------------------------------------------------------------
+ Function: Internal_ADClientAddValueForScalarKey
+
+ Description: This fucntion is a wrapper around calling the
+ ADClientAddValueForScalarKey function.
+
+ NOTE: The key should be a simple key such as
+ "numberOfPeers". This is because this function will
+ apptend the required prefix of "com.apple.cloudkeychain"
+ -------------------------------------------------------------------------- */
+static void Internal_ADClientAddValueForScalarKey(CFStringRef key, int64_t value)
+{
+ if (InitializeADFunctionPointers())
+ {
+ CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%@"), gTopLevelKeyForiCloudKeychainTracing, key);
+ if (NULL == real_key)
+ {
+ return;
+ }
+
+ gADClientAddValueForScalarKey(real_key, value);
+ CFRelease(real_key);
+ }
+}
+
+
+/* --------------------------------------------------------------------------
+ Function: iOS_SetCloudKeychainTraceValueForKey
+
+ Description: This fucntion is a wrapper around calling either
+ ADClientAddValueForScalarKey or ADClientClearScalarKey
+ depending on if the value is 0.
+
+ NOTE: The key should be a simple key such as
+ "numberOfPeers". This is because this function will
+ apptend the required prefix of "com.apple.cloudkeychain"
+ -------------------------------------------------------------------------- */
+static bool iOS_SetCloudKeychainTraceValueForKey(CFStringRef key, int64_t value)
+{
+ if (NULL == key)
+ {
+ return false;
+ }
+
+ if (0LL == value)
+ {
+ Internal_ADClientClearScalarKey(key);
+ }
+ else
+ {
+ Internal_ADClientAddValueForScalarKey(key, value);
+ }
+ return true;
+}
+
+/* --------------------------------------------------------------------------
+ Function: iOS_AddKeyValuePairToKeychainLoggingTransaction
+
+ Description: For iOS the is no "bunching" This function will simply
+ call iOS_SetCloudKeychainTraceValueForKey to log the
+ key value pair
+ -------------------------------------------------------------------------- */
+static bool iOS_AddKeyValuePairToKeychainLoggingTransaction(void* token, CFStringRef key, int64_t value)
+{
+#pragma unused(token)
+ return iOS_SetCloudKeychainTraceValueForKey(key, value);
+}
+#endif
+
+/* --------------------------------------------------------------------------
+ Function: SetCloudKeychainTraceValueForKey
+
+ Description: SPI to log a single key value pair with the logging system
+ -------------------------------------------------------------------------- */
+bool SetCloudKeychainTraceValueForKey(CFStringRef key, int64_t value)
+{
+#if (TARGET_IPHONE_SIMULATOR)
+ return false;
+#endif
+
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+ return OSX_SetCloudKeychainTraceValueForKey(key, value);
+#endif
+
+#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
+ return iOS_SetCloudKeychainTraceValueForKey(key, value);
+#endif
+}
+
+/* --------------------------------------------------------------------------
+ Function: BeginCloudKeychainLoggingTransaction
+
+ Description: SPI to begin a logging transaction
+ -------------------------------------------------------------------------- */
+void* BeginCloudKeychainLoggingTransaction()
+{
+#if (TARGET_IPHONE_SIMULATOR)
+ return (void *)-1;
+#endif
+
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+ return OSX_BeginCloudKeychainLoggingTransaction();
+#endif
+
+#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
+ return NULL;
+#endif
+}
+
+/* --------------------------------------------------------------------------
+ Function: AddKeyValuePairToKeychainLoggingTransaction
+
+ Description: SPI to add a key value pair to an outstanding logging
+ tansaction
+ -------------------------------------------------------------------------- */
+bool AddKeyValuePairToKeychainLoggingTransaction(void* token, CFStringRef key, int64_t value)
+{
+#if (TARGET_IPHONE_SIMULATOR)
+ return false;
+#endif
+
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+ return OSX_AddKeyValuePairToKeychainLoggingTransaction(token, key, value);
+#endif
+
+#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
+ return iOS_AddKeyValuePairToKeychainLoggingTransaction(token, key, value);
+#endif
+}
+
+/* --------------------------------------------------------------------------
+ Function: CloseCloudKeychainLoggingTransaction
+
+ Description: SPI to complete a logging transaction and clean up the
+ context
+ -------------------------------------------------------------------------- */
+void CloseCloudKeychainLoggingTransaction(void* token)
+{
+#if (TARGET_IPHONE_SIMULATOR)
+ ; // nothing
+#endif
+
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+ OSX_CloseCloudKeychainLoggingTransaction(token);
+#endif
+
+#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
+ ; // nothing
+#endif
+}
+