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))
48 #include <msgtracer_client.h>
50 struct msgtracer_instance
{
51 msgtracer_msg_t message
;
52 msgtracer_domain_t domain
;
55 static const char* gMessageTracerSetPrefix
= "com.apple.message.";
57 /* --------------------------------------------------------------------------
58 Function: OSX_BeginCloudKeychainLoggingTransaction
60 Description: For OSX the message tracer back end wants its logging
61 done in "bunches". This function allows for beginning
62 a 'transaction' of logging which will allow for putting
63 all of the transactions items into a single log making
64 the message tracer folks happy.
66 The work of this function is to ask msgtracer for a domain,
67 create a message and return the pair as a void *.
68 -------------------------------------------------------------------------- */
69 static void *OSX_BeginCloudKeychainLoggingTransaction()
72 struct msgtracer_instance
*instance
= calloc(1, sizeof *instance
);
77 instance
->domain
= msgtracer_domain_new(gTopLevelKeyForiCloudKeychainTracing
);
78 if (instance
->domain
) {
79 instance
->message
= msgtracer_msg_new(instance
->domain
);
80 if (instance
->message
) {
81 return (void *)instance
;
83 msgtracer_domain_free(instance
->domain
);
89 /* --------------------------------------------------------------------------
90 Function: OSX_AddKeyValuePairToKeychainLoggingTransaction
92 Description: Once a call to OSX_BeginCloudKeychainLoggingTransaction
93 is done, this call all allow for adding items to the
94 "bunch" of items being logged.
96 NOTE: The key should be a simple key such as
97 "numberOfPeers". This is because this function will
98 prepend the required prefix of "com.apple.message."
99 -------------------------------------------------------------------------- */
100 static bool OSX_AddKeyValuePairToKeychainLoggingTransaction(void *token
, CFStringRef key
, int64_t value
)
102 if (NULL
== token
|| NULL
== key
)
107 struct msgtracer_instance
*instance
= (struct msgtracer_instance
*)token
;
108 msgtracer_msg_t msg
= instance
->message
;
111 CFStringRef real_key
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%@"), gMessageTracerSetPrefix
, key
);
112 if (NULL
== real_key
)
117 CFIndex key_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key
), kCFStringEncodingUTF8
);
118 key_length
+= 1; // For null
119 char key_buffer
[key_length
];
120 memset(key_buffer
, 0, key_length
);
121 if (!CFStringGetCString(real_key
, key_buffer
, key_length
, kCFStringEncodingUTF8
))
128 CFStringRef value_str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%lld"), value
);
129 if (NULL
== value_str
)
134 CFIndex value_str_numBytes
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str
), kCFStringEncodingUTF8
);
135 value_str_numBytes
+= 1; // For null
136 char value_buffer
[value_str_numBytes
];
137 memset(value_buffer
, 0, value_str_numBytes
);
138 if (!CFStringGetCString(value_str
, value_buffer
, value_str_numBytes
, kCFStringEncodingUTF8
))
140 CFRelease(value_str
);
143 CFRelease(value_str
);
145 msgtracer_set(msg
, key_buffer
, value_buffer
);
149 /* --------------------------------------------------------------------------
150 Function: OSX_CloseCloudKeychainLoggingTransaction
152 Description: Once a call to OSX_BeginCloudKeychainLoggingTransaction
153 is done, and all of the items that are to be in the
154 "bunch" of items being logged, this function will do the
155 real logging and free the aslmsg context.
156 -------------------------------------------------------------------------- */
157 static void OSX_CloseCloudKeychainLoggingTransaction(void *token
)
161 struct msgtracer_instance
*instance
= (struct msgtracer_instance
*)token
;
162 msgtracer_log(instance
->message
, ASL_LEVEL_NOTICE
, "");
163 msgtracer_msg_free(instance
->message
);
164 msgtracer_domain_free(instance
->domain
);
169 /* --------------------------------------------------------------------------
170 Function: OSX_SetCloudKeychainTraceValueForKey
172 Description: If "bunching" of items either cannot be done or is not
173 desired, then this 'single shot' function shold be used.
174 It will create the aslmsg context, register the domain
175 fix up the key and log the key value pair and then
176 do the real logging and free the aslmsg context.
177 -------------------------------------------------------------------------- */
178 static bool OSX_SetCloudKeychainTraceValueForKey(CFStringRef key
, int64_t value
)
187 msgtracer_msg_t message
= NULL
;
188 msgtracer_domain_t domain
= msgtracer_domain_new(gTopLevelKeyForiCloudKeychainTracing
);
190 if (NULL
== domain
) {
194 message
= msgtracer_msg_new(domain
);
195 if (NULL
== message
) {
196 msgtracer_domain_free(domain
);
201 CFStringRef real_key
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s%@"), gMessageTracerSetPrefix
, key
);
202 if (NULL
== real_key
)
207 CFIndex key_length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(real_key
), kCFStringEncodingUTF8
);
208 key_length
+= 1; // For null
209 char key_buffer
[key_length
];
210 memset(key_buffer
, 0,key_length
);
211 if (!CFStringGetCString(real_key
, key_buffer
, key_length
, kCFStringEncodingUTF8
))
219 CFStringRef value_str
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%lld"), value
);
220 if (NULL
== value_str
)
222 msgtracer_msg_free(message
);
226 CFIndex value_str_numBytes
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value_str
), kCFStringEncodingUTF8
);
227 value_str_numBytes
+= 1; // For null
228 char value_buffer
[value_str_numBytes
];
229 memset(value_buffer
, 0, value_str_numBytes
);
230 if (!CFStringGetCString(value_str
, value_buffer
, value_str_numBytes
, kCFStringEncodingUTF8
))
232 msgtracer_msg_free(message
);
233 CFRelease(value_str
);
236 CFRelease(value_str
);
238 msgtracer_set(message
, key_buffer
, value_buffer
);
239 msgtracer_log(message
, ASL_LEVEL_NOTICE
, "%s is %lld", key_buffer
, value
);
240 msgtracer_msg_free(message
);
241 msgtracer_domain_free(domain
);
247 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
249 typedef void (*type_ADClientClearScalarKey
)(CFStringRef key
);
250 typedef void (*type_ADClientSetValueForScalarKey
)(CFStringRef key
, int64_t value
);
252 static type_ADClientClearScalarKey gADClientClearScalarKey
= NULL
;
253 static type_ADClientSetValueForScalarKey gADClientSetValueForScalarKey
= NULL
;
255 static dispatch_once_t gADFunctionPointersSet
= 0;
256 static CFBundleRef gAggdBundleRef
= NULL
;
257 static bool gFunctionPointersAreLoaded
= false;
259 /* --------------------------------------------------------------------------
260 Function: InitializeADFunctionPointers
262 Description: Linking to the Aggregate library causes a build cycle so
263 This function will dynamically load the needed function
265 -------------------------------------------------------------------------- */
266 static bool InitializeADFunctionPointers()
268 if (gFunctionPointersAreLoaded
)
270 return gFunctionPointersAreLoaded
;
273 dispatch_once(&gADFunctionPointersSet
,
275 CFStringRef path_to_aggd_framework
= CFSTR("/System/Library/PrivateFrameworks/AggregateDictionary.framework");
277 CFURLRef aggd_url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, path_to_aggd_framework
, kCFURLPOSIXPathStyle
, true);
279 if (NULL
!= aggd_url
)
281 gAggdBundleRef
= CFBundleCreate(kCFAllocatorDefault
, aggd_url
);
282 if (NULL
!= gAggdBundleRef
)
284 gADClientClearScalarKey
= (type_ADClientClearScalarKey
)
285 CFBundleGetFunctionPointerForName(gAggdBundleRef
, CFSTR("ADClientClearScalarKey"));
287 gADClientSetValueForScalarKey
= (type_ADClientSetValueForScalarKey
)
288 CFBundleGetFunctionPointerForName(gAggdBundleRef
, CFSTR("ADClientSetValueForScalarKey"));
294 gFunctionPointersAreLoaded
= ((NULL
!= gADClientClearScalarKey
) && (NULL
!= gADClientSetValueForScalarKey
));
295 return gFunctionPointersAreLoaded
;
298 /* --------------------------------------------------------------------------
299 Function: Internal_ADClientClearScalarKey
301 Description: This fucntion is a wrapper around calling the
302 ADClientClearScalarKey function.
304 NOTE: The key should be a simple key such as
305 "numberOfPeers". This is because this function will
306 apptend the required prefix of "com.apple.cloudkeychain"
307 -------------------------------------------------------------------------- */
308 static void Internal_ADClientClearScalarKey(CFStringRef key
)
310 if (InitializeADFunctionPointers())
312 CFStringRef real_key
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s.%@"), gTopLevelKeyForiCloudKeychainTracing
, key
);
313 if (NULL
== real_key
)
318 gADClientClearScalarKey(real_key
);
323 /* --------------------------------------------------------------------------
324 Function: Internal_ADClientSetValueForScalarKey
326 Description: This fucntion is a wrapper around calling the
327 ADClientSetValueForScalarKey function.
329 NOTE: The key should be a simple key such as
330 "numberOfPeers". This is because this function will
331 apptend the required prefix of "com.apple.cloudkeychain"
332 -------------------------------------------------------------------------- */
333 static void Internal_ADClientSetValueForScalarKey(CFStringRef key
, int64_t value
)
335 if (InitializeADFunctionPointers())
337 CFStringRef real_key
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s.%@"), gTopLevelKeyForiCloudKeychainTracing
, key
);
338 if (NULL
== real_key
)
343 gADClientSetValueForScalarKey(real_key
, value
);
349 /* --------------------------------------------------------------------------
350 Function: iOS_SetCloudKeychainTraceValueForKey
352 Description: This fucntion is a wrapper around calling either
353 ADClientSetValueForScalarKey or ADClientClearScalarKey
354 depending on if the value is 0.
356 NOTE: The key should be a simple key such as
357 "numberOfPeers". This is because this function will
358 apptend the required prefix of "com.apple.cloudkeychain"
359 -------------------------------------------------------------------------- */
360 static bool iOS_SetCloudKeychainTraceValueForKey(CFStringRef key
, int64_t value
)
369 Internal_ADClientClearScalarKey(key
);
373 Internal_ADClientSetValueForScalarKey(key
, value
);
378 /* --------------------------------------------------------------------------
379 Function: iOS_AddKeyValuePairToKeychainLoggingTransaction
381 Description: For iOS the is no "bunching" This function will simply
382 call iOS_SetCloudKeychainTraceValueForKey to log the
384 -------------------------------------------------------------------------- */
385 static bool iOS_AddKeyValuePairToKeychainLoggingTransaction(void* token
, CFStringRef key
, int64_t value
)
387 #pragma unused(token)
388 return iOS_SetCloudKeychainTraceValueForKey(key
, value
);
392 /* --------------------------------------------------------------------------
393 Function: SetCloudKeychainTraceValueForKey
395 Description: SPI to log a single key value pair with the logging system
396 -------------------------------------------------------------------------- */
397 bool SetCloudKeychainTraceValueForKey(CFStringRef key
, int64_t value
)
399 #if (TARGET_IPHONE_SIMULATOR)
403 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
404 return OSX_SetCloudKeychainTraceValueForKey(key
, value
);
407 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
408 return iOS_SetCloudKeychainTraceValueForKey(key
, value
);
412 /* --------------------------------------------------------------------------
413 Function: BeginCloudKeychainLoggingTransaction
415 Description: SPI to begin a logging transaction
416 -------------------------------------------------------------------------- */
417 void* BeginCloudKeychainLoggingTransaction()
419 #if (TARGET_IPHONE_SIMULATOR)
423 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
424 return OSX_BeginCloudKeychainLoggingTransaction();
427 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
432 /* --------------------------------------------------------------------------
433 Function: AddKeyValuePairToKeychainLoggingTransaction
435 Description: SPI to add a key value pair to an outstanding logging
437 -------------------------------------------------------------------------- */
438 bool AddKeyValuePairToKeychainLoggingTransaction(void* token
, CFStringRef key
, int64_t value
)
440 #if (TARGET_IPHONE_SIMULATOR)
444 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
445 return OSX_AddKeyValuePairToKeychainLoggingTransaction(token
, key
, value
);
448 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
449 return iOS_AddKeyValuePairToKeychainLoggingTransaction(token
, key
, value
);
453 /* --------------------------------------------------------------------------
454 Function: CloseCloudKeychainLoggingTransaction
456 Description: SPI to complete a logging transaction and clean up the
458 -------------------------------------------------------------------------- */
459 void CloseCloudKeychainLoggingTransaction(void* token
)
461 #if (TARGET_IPHONE_SIMULATOR)
465 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
466 OSX_CloseCloudKeychainLoggingTransaction(token
);
469 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)