]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/src/iCloudKeychainTrace.c
Security-58286.51.6.tar.gz
[apple/security.git] / OSX / utilities / src / iCloudKeychainTrace.c
1 /*
2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include "iCloudKeychainTrace.h"
26 #include <TargetConditionals.h>
27 #include <inttypes.h>
28 #include "SecCFWrappers.h"
29 #include <sys/time.h>
30 #include <CoreFoundation/CoreFoundation.h>
31
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");
38
39 #if !TARGET_IPHONE_SIMULATOR
40 #if TARGET_OS_IPHONE
41 static const char* gTopLevelKeyForiCloudKeychainTracing = "com.apple.icdp";
42 #else
43 static const char* gTopLevelKeyForiCloudKeychainTracing = "com.apple.icdp.KeychainStats";
44 #endif
45 #endif
46
47 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
48 #include <msgtracer_client.h>
49
50 struct msgtracer_instance {
51 msgtracer_msg_t message;
52 msgtracer_domain_t domain;
53 };
54
55 static const char* gMessageTracerSetPrefix = "com.apple.message.";
56
57 /* --------------------------------------------------------------------------
58 Function: OSX_BeginCloudKeychainLoggingTransaction
59
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.
65
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()
70 {
71
72 struct msgtracer_instance *instance = calloc(1, sizeof *instance);
73 if (!instance) {
74 return NULL;
75 }
76
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;
82 }
83 msgtracer_domain_free(instance->domain);
84 }
85 free(instance);
86 return NULL;
87 }
88
89 /* --------------------------------------------------------------------------
90 Function: OSX_AddKeyValuePairToKeychainLoggingTransaction
91
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.
95
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)
101 {
102 if (NULL == token || NULL == key)
103 {
104 return false;
105 }
106
107 struct msgtracer_instance *instance = (struct msgtracer_instance *)token;
108 msgtracer_msg_t msg = instance->message;
109
110 // Fix up the key
111 CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%@"), gMessageTracerSetPrefix, key);
112 if (NULL == real_key)
113 {
114 return false;
115 }
116
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))
122 {
123 CFRelease(real_key);
124 return false;
125 }
126 CFRelease(real_key);
127
128 CFStringRef value_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lld"), value);
129 if (NULL == value_str)
130 {
131 return false;
132 }
133
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))
139 {
140 CFRelease(value_str);
141 return false;
142 }
143 CFRelease(value_str);
144
145 msgtracer_set(msg, key_buffer, value_buffer);
146 return true;
147 }
148
149 /* --------------------------------------------------------------------------
150 Function: OSX_CloseCloudKeychainLoggingTransaction
151
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)
158 {
159 if (NULL != token)
160 {
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);
165 free(instance);
166 }
167 }
168
169 /* --------------------------------------------------------------------------
170 Function: OSX_SetCloudKeychainTraceValueForKey
171
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)
179 {
180 bool result = false;
181
182 if (NULL == key)
183 {
184 return result;
185 }
186
187 msgtracer_msg_t message = NULL;
188 msgtracer_domain_t domain = msgtracer_domain_new(gTopLevelKeyForiCloudKeychainTracing);
189
190 if (NULL == domain) {
191 return result;
192 }
193
194 message = msgtracer_msg_new(domain);
195 if (NULL == message) {
196 msgtracer_domain_free(domain);
197 return result;
198 }
199
200 // Fix up the key
201 CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%@"), gMessageTracerSetPrefix, key);
202 if (NULL == real_key)
203 {
204 return false;
205 }
206
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))
212 {
213 CFRelease(real_key);
214 return false;
215 }
216 CFRelease(real_key);
217
218
219 CFStringRef value_str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lld"), value);
220 if (NULL == value_str)
221 {
222 msgtracer_msg_free(message);
223 return result;
224 }
225
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))
231 {
232 msgtracer_msg_free(message);
233 CFRelease(value_str);
234 return result;
235 }
236 CFRelease(value_str);
237
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);
242 return true;
243
244 }
245 #endif
246
247 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
248
249 typedef void (*type_ADClientClearScalarKey)(CFStringRef key);
250 typedef void (*type_ADClientSetValueForScalarKey)(CFStringRef key, int64_t value);
251
252 static type_ADClientClearScalarKey gADClientClearScalarKey = NULL;
253 static type_ADClientSetValueForScalarKey gADClientSetValueForScalarKey = NULL;
254
255 static dispatch_once_t gADFunctionPointersSet = 0;
256 static CFBundleRef gAggdBundleRef = NULL;
257 static bool gFunctionPointersAreLoaded = false;
258
259 /* --------------------------------------------------------------------------
260 Function: InitializeADFunctionPointers
261
262 Description: Linking to the Aggregate library causes a build cycle so
263 This function will dynamically load the needed function
264 pointers.
265 -------------------------------------------------------------------------- */
266 static bool InitializeADFunctionPointers()
267 {
268 if (gFunctionPointersAreLoaded)
269 {
270 return gFunctionPointersAreLoaded;
271 }
272
273 dispatch_once(&gADFunctionPointersSet,
274 ^{
275 CFStringRef path_to_aggd_framework = CFSTR("/System/Library/PrivateFrameworks/AggregateDictionary.framework");
276
277 CFURLRef aggd_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_to_aggd_framework, kCFURLPOSIXPathStyle, true);
278
279 if (NULL != aggd_url)
280 {
281 gAggdBundleRef = CFBundleCreate(kCFAllocatorDefault, aggd_url);
282 if (NULL != gAggdBundleRef)
283 {
284 gADClientClearScalarKey = (type_ADClientClearScalarKey)
285 CFBundleGetFunctionPointerForName(gAggdBundleRef, CFSTR("ADClientClearScalarKey"));
286
287 gADClientSetValueForScalarKey = (type_ADClientSetValueForScalarKey)
288 CFBundleGetFunctionPointerForName(gAggdBundleRef, CFSTR("ADClientSetValueForScalarKey"));
289 }
290 CFRelease(aggd_url);
291 }
292 });
293
294 gFunctionPointersAreLoaded = ((NULL != gADClientClearScalarKey) && (NULL != gADClientSetValueForScalarKey));
295 return gFunctionPointersAreLoaded;
296 }
297
298 /* --------------------------------------------------------------------------
299 Function: Internal_ADClientClearScalarKey
300
301 Description: This fucntion is a wrapper around calling the
302 ADClientClearScalarKey function.
303
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)
309 {
310 if (InitializeADFunctionPointers())
311 {
312 CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%@"), gTopLevelKeyForiCloudKeychainTracing, key);
313 if (NULL == real_key)
314 {
315 return;
316 }
317
318 gADClientClearScalarKey(real_key);
319 CFRelease(real_key);
320 }
321 }
322
323 /* --------------------------------------------------------------------------
324 Function: Internal_ADClientSetValueForScalarKey
325
326 Description: This fucntion is a wrapper around calling the
327 ADClientSetValueForScalarKey function.
328
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)
334 {
335 if (InitializeADFunctionPointers())
336 {
337 CFStringRef real_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%@"), gTopLevelKeyForiCloudKeychainTracing, key);
338 if (NULL == real_key)
339 {
340 return;
341 }
342
343 gADClientSetValueForScalarKey(real_key, value);
344 CFRelease(real_key);
345 }
346 }
347
348
349 /* --------------------------------------------------------------------------
350 Function: iOS_SetCloudKeychainTraceValueForKey
351
352 Description: This fucntion is a wrapper around calling either
353 ADClientSetValueForScalarKey or ADClientClearScalarKey
354 depending on if the value is 0.
355
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)
361 {
362 if (NULL == key)
363 {
364 return false;
365 }
366
367 if (0LL == value)
368 {
369 Internal_ADClientClearScalarKey(key);
370 }
371 else
372 {
373 Internal_ADClientSetValueForScalarKey(key, value);
374 }
375 return true;
376 }
377
378 /* --------------------------------------------------------------------------
379 Function: iOS_AddKeyValuePairToKeychainLoggingTransaction
380
381 Description: For iOS the is no "bunching" This function will simply
382 call iOS_SetCloudKeychainTraceValueForKey to log the
383 key value pair
384 -------------------------------------------------------------------------- */
385 static bool iOS_AddKeyValuePairToKeychainLoggingTransaction(void* token, CFStringRef key, int64_t value)
386 {
387 #pragma unused(token)
388 return iOS_SetCloudKeychainTraceValueForKey(key, value);
389 }
390 #endif
391
392 /* --------------------------------------------------------------------------
393 Function: SetCloudKeychainTraceValueForKey
394
395 Description: SPI to log a single key value pair with the logging system
396 -------------------------------------------------------------------------- */
397 bool SetCloudKeychainTraceValueForKey(CFStringRef key, int64_t value)
398 {
399 #if (TARGET_IPHONE_SIMULATOR)
400 return false;
401 #endif
402
403 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
404 return OSX_SetCloudKeychainTraceValueForKey(key, value);
405 #endif
406
407 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
408 return iOS_SetCloudKeychainTraceValueForKey(key, value);
409 #endif
410 }
411
412 /* --------------------------------------------------------------------------
413 Function: BeginCloudKeychainLoggingTransaction
414
415 Description: SPI to begin a logging transaction
416 -------------------------------------------------------------------------- */
417 void* BeginCloudKeychainLoggingTransaction()
418 {
419 #if (TARGET_IPHONE_SIMULATOR)
420 return (void *)-1;
421 #endif
422
423 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
424 return OSX_BeginCloudKeychainLoggingTransaction();
425 #endif
426
427 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
428 return NULL;
429 #endif
430 }
431
432 /* --------------------------------------------------------------------------
433 Function: AddKeyValuePairToKeychainLoggingTransaction
434
435 Description: SPI to add a key value pair to an outstanding logging
436 tansaction
437 -------------------------------------------------------------------------- */
438 bool AddKeyValuePairToKeychainLoggingTransaction(void* token, CFStringRef key, int64_t value)
439 {
440 #if (TARGET_IPHONE_SIMULATOR)
441 return false;
442 #endif
443
444 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
445 return OSX_AddKeyValuePairToKeychainLoggingTransaction(token, key, value);
446 #endif
447
448 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
449 return iOS_AddKeyValuePairToKeychainLoggingTransaction(token, key, value);
450 #endif
451 }
452
453 /* --------------------------------------------------------------------------
454 Function: CloseCloudKeychainLoggingTransaction
455
456 Description: SPI to complete a logging transaction and clean up the
457 context
458 -------------------------------------------------------------------------- */
459 void CloseCloudKeychainLoggingTransaction(void* token)
460 {
461 #if (TARGET_IPHONE_SIMULATOR)
462 ; // nothing
463 #endif
464
465 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
466 OSX_CloseCloudKeychainLoggingTransaction(token);
467 #endif
468
469 #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR)
470 ; // nothing
471 #endif
472 }
473