2  * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25 #include "iCloudKeychainTrace.h" 
  26 #include <TargetConditionals.h> 
  28 #include "SecCFWrappers.h" 
  30 #include <CoreFoundation/CoreFoundation.h> 
  32 const CFStringRef kNumberOfiCloudKeychainPeers 
= CFSTR("numberOfPeers"); 
  33 const CFStringRef kNumberOfiCloudKeychainItemsBeingSynced 
= CFSTR("numberOfItemsBeingSynced"); 
  34 const CFStringRef kCloudKeychainNumberOfSyncingConflicts 
= CFSTR("conflictsCount"); 
  35 const CFStringRef kCloudKeychainNumberOfTimesSyncFailed 
= CFSTR("syncFailureCount"); 
  36 const CFStringRef kCloudKeychainNumberOfConflictsResolved 
= CFSTR("conflictsResolved"); 
  37 const CFStringRef kCloudKeychainNumberOfTimesSyncedWithPeers 
= CFSTR("syncedWithPeers"); 
  39 #if !TARGET_IPHONE_SIMULATOR 
  41 static const char* gTopLevelKeyForiCloudKeychainTracing 
= "com.apple.icdp"; 
  43 static const char* gTopLevelKeyForiCloudKeychainTracing 
= "com.apple.icdp.KeychainStats"; 
  47 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)) 
  50 static const char* gMessageTracerSetPrefix 
= "com.apple.message."; 
  52 static const char* gMessageTracerDomainField 
= "com.apple.message.domain"; 
  54 /* -------------------------------------------------------------------------- 
  55         Function:               OSX_BeginCloudKeychainLoggingTransaction 
  57         Description:    For OSX the message tracer back end wants its logging  
  58                                         done in "bunches".  This function allows for beginning 
  59                                         a 'transaction' of logging which will allow for putting 
  60                                         all of the transactions items into a single log making 
  61                                         the message tracer folks happy. 
  63                                         The work of this function is to create the aslmsg context 
  64                                         and set the domain field and then return the aslmsg 
  66    -------------------------------------------------------------------------- */                                         
  67 static void* OSX_BeginCloudKeychainLoggingTransaction() 
  71         mAsl 
= asl_new(ASL_TYPE_MSG
); 
  77         asl_set(mAsl
, gMessageTracerDomainField
, gTopLevelKeyForiCloudKeychainTracing
); 
  79         result 
= (void *)mAsl
; 
  83 /* -------------------------------------------------------------------------- 
  84         Function:               OSX_AddKeyValuePairToKeychainLoggingTransaction 
  86         Description:    Once a call to OSX_BeginCloudKeychainLoggingTransaction  
  87                                         is done, this call all allow for adding items to the 
  88                                         "bunch" of items being logged. 
  90                                         NOTE: The key should be a simple key such as  
  91                                         "numberOfPeers".  This is because this function will  
  92                                         apptend the required prefix of "com.apple.message." 
  93    -------------------------------------------------------------------------- */ 
  94 static bool OSX_AddKeyValuePairToKeychainLoggingTransaction(void* token
, CFStringRef key
, int64_t value
) 
  96         if (NULL 
== token 
|| NULL 
== key
) 
 101         aslmsg mAsl 
= (aslmsg
)token
; 
 104         CFStringRef real_key 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%@"), gMessageTracerSetPrefix
, key
); 
 105         if (NULL 
== real_key
) 
 110         CFIndex key_length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key
), kCFStringEncodingUTF8
); 
 111     key_length 
+= 1; // For null 
 112     char key_buffer
[key_length
]; 
 113     memset(key_buffer
, 0,key_length
); 
 114     if (!CFStringGetCString(real_key
, key_buffer
, key_length
, kCFStringEncodingUTF8
)) 
 121         CFStringRef value_str 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%lld"), value
); 
 122     if (NULL 
== value_str
) 
 127     CFIndex value_str_numBytes 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str
), kCFStringEncodingUTF8
); 
 128     value_str_numBytes 
+= 1; // For null 
 129     char value_buffer
[value_str_numBytes
]; 
 130     memset(value_buffer
, 0, value_str_numBytes
); 
 131     if (!CFStringGetCString(value_str
, value_buffer
, value_str_numBytes
, kCFStringEncodingUTF8
)) 
 133         CFRelease(value_str
); 
 136     CFRelease(value_str
); 
 138         asl_set(mAsl
, key_buffer
, value_buffer
); 
 142 /* -------------------------------------------------------------------------- 
 143         Function:               OSX_CloseCloudKeychainLoggingTransaction 
 145         Description:    Once a call to OSX_BeginCloudKeychainLoggingTransaction  
 146                                         is done, and all of the items that are to be in the  
 147                                         "bunch" of items being logged, this function will do the 
 148                                         real logging and free the aslmsg context. 
 149    -------------------------------------------------------------------------- */ 
 150 static void OSX_CloseCloudKeychainLoggingTransaction(void* token
) 
 154                 aslmsg mAsl 
= (aslmsg
)token
; 
 155                 asl_log(NULL
, mAsl
, ASL_LEVEL_NOTICE
, ""); 
 160 /* -------------------------------------------------------------------------- 
 161         Function:               OSX_SetCloudKeychainTraceValueForKey 
 163         Description:    If "bunching" of items either cannot be done or is not 
 164                                         desired, then this 'single shot' function shold be used. 
 165                                         It will create the aslmsg context, register the domain 
 166                                         fix up the key and log the key value pair and then  
 167                                         do the real logging and free the aslmsg context. 
 168    -------------------------------------------------------------------------- */ 
 169 static bool OSX_SetCloudKeychainTraceValueForKey(CFStringRef key
, int64_t value
) 
 179         mAsl 
= asl_new(ASL_TYPE_MSG
); 
 186         CFStringRef real_key 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%@"), gMessageTracerSetPrefix
, key
); 
 187         if (NULL 
== real_key
) 
 192         CFIndex key_length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key
), kCFStringEncodingUTF8
); 
 193     key_length 
+= 1; // For null 
 194     char key_buffer
[key_length
]; 
 195     memset(key_buffer
, 0,key_length
); 
 196     if (!CFStringGetCString(real_key
, key_buffer
, key_length
, kCFStringEncodingUTF8
)) 
 204         CFStringRef value_str 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%lld"), value
); 
 205     if (NULL 
== value_str
) 
 211     CFIndex value_str_numBytes 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str
), kCFStringEncodingUTF8
); 
 212     value_str_numBytes 
+= 1; // For null 
 213     char value_buffer
[value_str_numBytes
]; 
 214     memset(value_buffer
, 0, value_str_numBytes
); 
 215     if (!CFStringGetCString(value_str
, value_buffer
, value_str_numBytes
, kCFStringEncodingUTF8
)) 
 218         CFRelease(value_str
); 
 221     CFRelease(value_str
); 
 223     asl_set(mAsl
, gMessageTracerDomainField
, gTopLevelKeyForiCloudKeychainTracing
); 
 225         asl_set(mAsl
, key_buffer
, value_buffer
); 
 226         asl_log(NULL
, mAsl
, ASL_LEVEL_NOTICE
, "%s is %lld", key_buffer
, value
); 
 233 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) 
 235 typedef void (*type_ADClientClearScalarKey
)(CFStringRef key
); 
 236 typedef void (*type_ADClientSetValueForScalarKey
)(CFStringRef key
, int64_t value
); 
 238 static type_ADClientClearScalarKey gADClientClearScalarKey 
= NULL
; 
 239 static type_ADClientSetValueForScalarKey gADClientSetValueForScalarKey 
= NULL
; 
 241 static dispatch_once_t gADFunctionPointersSet 
= 0; 
 242 static CFBundleRef gAggdBundleRef 
= NULL
; 
 243 static bool gFunctionPointersAreLoaded 
= false; 
 245 /* -------------------------------------------------------------------------- 
 246         Function:               InitializeADFunctionPointers 
 248         Description:    Linking to the Aggregate library causes a build cycle so 
 249                                         This function will dynamically load the needed function 
 251    -------------------------------------------------------------------------- */ 
 252 static bool InitializeADFunctionPointers() 
 254         if (gFunctionPointersAreLoaded
) 
 256                 return gFunctionPointersAreLoaded
; 
 259     dispatch_once(&gADFunctionPointersSet
, 
 261           CFStringRef path_to_aggd_framework 
= CFSTR("/System/Library/PrivateFrameworks/AggregateDictionary.framework"); 
 263           CFURLRef aggd_url 
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, path_to_aggd_framework
, kCFURLPOSIXPathStyle
, true); 
 265           if (NULL 
!= aggd_url
) 
 267               gAggdBundleRef 
= CFBundleCreate(kCFAllocatorDefault
, aggd_url
); 
 268               if (NULL 
!= gAggdBundleRef
) 
 270                   gADClientClearScalarKey 
= (type_ADClientClearScalarKey
) 
 271                     CFBundleGetFunctionPointerForName(gAggdBundleRef
, CFSTR("ADClientClearScalarKey")); 
 273                   gADClientSetValueForScalarKey 
= (type_ADClientSetValueForScalarKey
) 
 274                     CFBundleGetFunctionPointerForName(gAggdBundleRef
, CFSTR("ADClientSetValueForScalarKey")); 
 280     gFunctionPointersAreLoaded 
= ((NULL 
!= gADClientClearScalarKey
) && (NULL 
!= gADClientSetValueForScalarKey
)); 
 281     return gFunctionPointersAreLoaded
; 
 284 /* -------------------------------------------------------------------------- 
 285         Function:               Internal_ADClientClearScalarKey 
 287         Description:    This fucntion is a wrapper around calling the   
 288                                         ADClientClearScalarKey function.   
 290                                         NOTE: The key should be a simple key such as  
 291                                         "numberOfPeers".  This is because this function will  
 292                                         apptend the required prefix of "com.apple.cloudkeychain" 
 293    -------------------------------------------------------------------------- */ 
 294 static void Internal_ADClientClearScalarKey(CFStringRef key
) 
 296     if (InitializeADFunctionPointers()) 
 298                 CFStringRef real_key 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s.%@"), gTopLevelKeyForiCloudKeychainTracing
, key
); 
 299                 if (NULL 
== real_key
) 
 304         gADClientClearScalarKey(real_key
); 
 309 /* -------------------------------------------------------------------------- 
 310         Function:               Internal_ADClientSetValueForScalarKey 
 312         Description:    This fucntion is a wrapper around calling the   
 313                                         ADClientSetValueForScalarKey function. 
 315                                         NOTE: The key should be a simple key such as  
 316                                         "numberOfPeers".  This is because this function will  
 317                                         apptend the required prefix of "com.apple.cloudkeychain" 
 318    -------------------------------------------------------------------------- */ 
 319 static void Internal_ADClientSetValueForScalarKey(CFStringRef key
, int64_t value
) 
 321     if (InitializeADFunctionPointers()) 
 323                 CFStringRef real_key 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s.%@"), gTopLevelKeyForiCloudKeychainTracing
, key
); 
 324                 if (NULL 
== real_key
) 
 329         gADClientSetValueForScalarKey(real_key
, value
); 
 335 /* -------------------------------------------------------------------------- 
 336         Function:               iOS_SetCloudKeychainTraceValueForKey 
 338         Description:    This fucntion is a wrapper around calling either    
 339                                         ADClientSetValueForScalarKey  or ADClientClearScalarKey 
 340                                         depending on if the value is 0. 
 342                                         NOTE: The key should be a simple key such as  
 343                                         "numberOfPeers".  This is because this function will  
 344                                         apptend the required prefix of "com.apple.cloudkeychain" 
 345    -------------------------------------------------------------------------- */ 
 346 static bool iOS_SetCloudKeychainTraceValueForKey(CFStringRef key
, int64_t value
) 
 355         Internal_ADClientClearScalarKey(key
); 
 359         Internal_ADClientSetValueForScalarKey(key
, value
); 
 364 /* -------------------------------------------------------------------------- 
 365         Function:               iOS_AddKeyValuePairToKeychainLoggingTransaction 
 367         Description:    For iOS the is no "bunching"  This function will simply 
 368                                         call iOS_SetCloudKeychainTraceValueForKey to log the  
 370    -------------------------------------------------------------------------- */ 
 371 static bool iOS_AddKeyValuePairToKeychainLoggingTransaction(void* token
, CFStringRef key
, int64_t value
) 
 373 #pragma unused(token) 
 374         return iOS_SetCloudKeychainTraceValueForKey(key
, value
); 
 378 /* -------------------------------------------------------------------------- 
 379         Function:               SetCloudKeychainTraceValueForKey 
 381         Description:    SPI to log a single key value pair with the logging system 
 382    -------------------------------------------------------------------------- */ 
 383 bool SetCloudKeychainTraceValueForKey(CFStringRef key
, int64_t value
) 
 385 #if (TARGET_IPHONE_SIMULATOR) 
 389 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 
 390         return OSX_SetCloudKeychainTraceValueForKey(key
, value
); 
 393 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) 
 394         return iOS_SetCloudKeychainTraceValueForKey(key
, value
); 
 398 /* -------------------------------------------------------------------------- 
 399         Function:               BeginCloudKeychainLoggingTransaction 
 401         Description:    SPI to begin a logging transaction 
 402    -------------------------------------------------------------------------- */ 
 403 void* BeginCloudKeychainLoggingTransaction() 
 405 #if (TARGET_IPHONE_SIMULATOR) 
 409 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 
 410         return OSX_BeginCloudKeychainLoggingTransaction(); 
 413 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) 
 418 /* -------------------------------------------------------------------------- 
 419         Function:               AddKeyValuePairToKeychainLoggingTransaction 
 421         Description:    SPI to add a key value pair to an outstanding logging 
 423    -------------------------------------------------------------------------- */ 
 424 bool AddKeyValuePairToKeychainLoggingTransaction(void* token
, CFStringRef key
, int64_t value
) 
 426 #if (TARGET_IPHONE_SIMULATOR) 
 430 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 
 431         return OSX_AddKeyValuePairToKeychainLoggingTransaction(token
, key
, value
); 
 434 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) 
 435         return iOS_AddKeyValuePairToKeychainLoggingTransaction(token
, key
, value
); 
 439 /* -------------------------------------------------------------------------- 
 440         Function:               CloseCloudKeychainLoggingTransaction 
 442         Description:    SPI to complete a logging transaction and clean up the 
 444    -------------------------------------------------------------------------- */ 
 445 void CloseCloudKeychainLoggingTransaction(void* token
) 
 447 #if (TARGET_IPHONE_SIMULATOR) 
 451 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 
 452         OSX_CloseCloudKeychainLoggingTransaction(token
); 
 455 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)