]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/src/debugging.c
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / utilities / src / debugging.c
1 /*
2 * Copyright (c) 2006-2010,2012-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 /*
26 * debugging.c - non-trivial debug support
27 */
28 #include "utilities/debugging.h"
29 #include "utilities/debugging_test.h"
30 #include "utilities/SecCFWrappers.h"
31 #include "utilities/SecFileLocations.h"
32 #include <CoreFoundation/CFSet.h>
33 #include <CoreFoundation/CFString.h>
34 #include <CoreFoundation/CFPreferences.h>
35
36 #include <dispatch/dispatch.h>
37
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <pthread.h>
43 #include <asl.h>
44 #include <os/trace.h>
45 #include <os/log_private.h>
46 #include <sqlite3.h>
47
48 const char *api_trace = "api_trace";
49
50
51 const CFStringRef kStringNegate = CFSTR("-");
52 const CFStringRef kStringAll = CFSTR("all");
53
54 const CFStringRef kAPIScope = CFSTR("api");
55
56 static CFMutableArrayRef sLogSettings = NULL; /* Either sets or dictionaries of level => set. */
57
58 static dispatch_queue_t GetDispatchControlQueue(void) {
59 static dispatch_queue_t sLoggingScopeControlQueue;
60 static dispatch_once_t onceToken;
61 dispatch_once(&onceToken, ^{
62 sLoggingScopeControlQueue = dispatch_queue_create("security scope control", DISPATCH_QUEUE_CONCURRENT);
63 });
64 return sLoggingScopeControlQueue;
65 }
66
67 static void with_scopes_read(dispatch_block_t action) {
68 dispatch_sync(GetDispatchControlQueue(), action);
69 }
70
71 static void with_scopes_write(dispatch_block_t action) {
72 dispatch_barrier_sync(GetDispatchControlQueue(), action);
73 }
74
75 bool IsScopeActive(int level, CFStringRef scope)
76 {
77 if (scope == NULL)
78 return true;
79
80 CFNumberRef level_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &level);
81
82 __block bool isActive = false;
83 with_scopes_read(^{
84 if (sLogSettings) {
85 CFArrayForEach(sLogSettings, ^(const void *value) {
86 CFSetRef setToCheck = NULL;
87
88 if (isSet(value)) {
89 setToCheck = (CFSetRef) value;
90 } else if (isDictionary(value)) {
91 CFDictionaryRef levels = (CFDictionaryRef) value;
92
93 setToCheck = CFDictionaryGetValue(levels, level_number);
94
95 if (!isSet(setToCheck))
96 setToCheck = NULL;
97 }
98
99 if (setToCheck != NULL && !isActive) {
100 bool negated = CFSetContainsValue(setToCheck, kStringNegate);
101 bool inSet = CFSetContainsValue(setToCheck, scope);
102
103 isActive = negated ^ inSet;
104 }
105 });
106 }
107 });
108
109 CFReleaseNull(level_number);
110
111 return isActive;
112 }
113
114 bool IsScopeActiveC(int level, const char *scope)
115 {
116 CFStringRef scopeString = CFStringCreateWithBytes(kCFAllocatorDefault, (const uint8_t*)scope, strlen(scope), kCFStringEncodingUTF8, false);
117 bool isActive = IsScopeActive(level, scopeString);
118 CFReleaseNull(scopeString);
119
120 return isActive;
121 }
122
123
124 static CFMutableSetRef CopyScopesFromScopeList(CFStringRef scopes) {
125 CFMutableSetRef resultSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
126
127 CFStringRef allocated_scope_list = NULL;
128 CFStringRef clean_scope_list = scopes;
129 bool add_negate = false;
130
131 if (CFStringHasPrefix(scopes, kStringNegate)) {
132 allocated_scope_list = CFStringCreateWithSubstring(kCFAllocatorDefault, scopes, CFRangeMake(CFStringGetLength(kStringNegate), CFStringGetLength(scopes) - 1));
133 clean_scope_list = allocated_scope_list;
134 add_negate = true;
135 }
136
137 CFArrayRef commaArray = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, clean_scope_list, CFSTR(","));
138
139 if (commaArray) {
140 CFArrayForEach(commaArray, ^(const void *value) {
141 if (isString(value)) {
142 CFMutableStringRef copy = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, (CFStringRef) value);
143 CFStringTrimWhitespace(copy);
144 CFSetSetValue(resultSet, copy);
145 CFReleaseNull(copy);
146 }
147 });
148 }
149
150 CFSetRemoveValue(resultSet, CFSTR("none"));
151 CFSetRemoveValue(resultSet, CFSTR(""));
152
153 if (CFSetContainsValue(resultSet, CFSTR("all"))) {
154 CFSetRemoveAllValues(resultSet);
155 add_negate = !add_negate;
156 }
157
158 if (add_negate)
159 CFSetSetValue(resultSet, kStringNegate);
160
161 CFReleaseNull(commaArray);
162 CFReleaseNull(allocated_scope_list);
163
164 return resultSet;
165 }
166
167 static CFMutableArrayRef CFArrayCreateMutableForCFTypesFilledWithCFNull(CFAllocatorRef allocator, CFIndex capacity) {
168 CFMutableArrayRef result = CFArrayCreateMutableForCFTypesWithCapacity(kCFAllocatorDefault, kScopeIDMax);
169
170 for(int count = 0; count <= capacity; ++count)
171 CFArrayAppendValue(result, kCFNull);
172
173 return result;
174 }
175
176 static bool CFArrayIsAll(CFArrayRef array, const void *value)
177 {
178 return CFArrayGetCountOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), value) == CFArrayGetCount(array);
179 }
180
181 static void SetNthScopeSet(int nth, CFTypeRef collection)
182 {
183 with_scopes_write(^{
184 if (sLogSettings == NULL) {
185 sLogSettings = CFArrayCreateMutableForCFTypesFilledWithCFNull(kCFAllocatorDefault, kScopeIDMax);
186 }
187
188 CFArraySetValueAtIndex(sLogSettings, nth, collection);
189
190 if (CFArrayIsAll(sLogSettings, kCFNull)) {
191 CFReleaseNull(sLogSettings);
192 }
193 });
194 }
195
196 static int string_to_log_level(CFStringRef string) {
197 if (CFEqual(string, CFSTR(ASL_STRING_EMERG)))
198 return SECLOG_LEVEL_EMERG;
199 else if (CFEqual(string, CFSTR(ASL_STRING_ALERT)))
200 return SECLOG_LEVEL_ALERT;
201 else if (CFEqual(string, CFSTR(ASL_STRING_CRIT)))
202 return SECLOG_LEVEL_CRIT;
203 else if (CFEqual(string, CFSTR(ASL_STRING_ERR)))
204 return SECLOG_LEVEL_ERR;
205 else if (CFEqual(string, CFSTR(ASL_STRING_WARNING)))
206 return SECLOG_LEVEL_WARNING;
207 else if (CFEqual(string, CFSTR(ASL_STRING_NOTICE)))
208 return SECLOG_LEVEL_NOTICE;
209 else if (CFEqual(string, CFSTR(ASL_STRING_INFO)))
210 return SECLOG_LEVEL_INFO;
211 else if (CFEqual(string, CFSTR(ASL_STRING_DEBUG)))
212 return SECLOG_LEVEL_DEBUG;
213 else
214 return -1;
215 }
216
217 static void CFSetAppendValues(CFSetRef set, CFMutableArrayRef appendTo)
218 {
219 CFSetForEach(set, ^(const void *value) {
220 CFArrayAppendValue(appendTo, value);
221 });
222 }
223
224 static CFMutableArrayRef CFSetOfCFObjectsCopyValues(CFSetRef setOfCFs)
225 {
226 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
227
228 CFSetForEach(setOfCFs, ^(const void *value) {
229 CFArrayAppendValue(result, value);
230 });
231
232 return result;
233 }
234
235 CFPropertyListRef CopyCurrentScopePlist(void)
236 {
237 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
238 with_scopes_read(^{
239 CFArrayForEach(sLogSettings, ^(const void *value) {
240 if (isSet(value)) {
241 CFArrayRef values = CFSetOfCFObjectsCopyValues((CFSetRef) value);
242 CFArrayAppendValue(result, values);
243 CFReleaseNull(values);
244 } else if (isDictionary(value)) {
245 CFMutableDictionaryRef levels = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
246
247 CFDictionaryForEach((CFDictionaryRef) value, ^(const void *key, const void *value) {
248 if (isSet(value)) {
249 CFArrayRef values = CFSetOfCFObjectsCopyValues((CFSetRef) value);
250 CFDictionaryAddValue(levels, key, values);
251 CFReleaseNull(values);
252 }
253 });
254
255 CFArrayAppendValue(result, levels);
256 } else {
257 CFArrayAppendValue(result, kCFNull);
258 }
259 });
260 });
261 return result;
262 }
263
264 void ApplyScopeDictionaryForID(CFDictionaryRef scopeDictionary, SecDebugScopeID whichID)
265 {
266 CFMutableDictionaryRef dictionary_for_id = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
267
268 CFDictionaryForEach(scopeDictionary, ^(const void *key, const void *value) {
269 CFSetRef scope_set = NULL;
270 CFNumberRef key_number = NULL;
271 if (isString(key)) {
272 int level = string_to_log_level((CFStringRef) key);
273
274 if (level >= 0)
275 key_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &level);
276 } else if (isNumber(key)) {
277 key_number = CFRetainSafe(key);
278 }
279
280 if (isString(value)) {
281 scope_set = CopyScopesFromScopeList(value);
282 }
283
284 if (key_number && scope_set)
285 CFDictionaryAddValue(dictionary_for_id, key_number, scope_set);
286
287 CFReleaseNull(key_number);
288 CFReleaseNull(scope_set);
289 });
290
291 if (CFDictionaryGetCount(dictionary_for_id) > 0) {
292 SetNthScopeSet(whichID, dictionary_for_id);
293 }
294
295 CFReleaseNull(dictionary_for_id);
296 }
297
298 void ApplyScopeListForID(CFStringRef scopeList, SecDebugScopeID whichID)
299 {
300 CFMutableSetRef scopesToUse = CopyScopesFromScopeList(scopeList);
301
302 SetNthScopeSet(whichID, scopesToUse);
303
304 CFReleaseNull(scopesToUse);
305 }
306
307 void ApplyScopeListForIDC(const char *scopeList, SecDebugScopeID whichID) {
308 CFStringRef scope_string = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, scopeList, kCFStringEncodingUTF8, kCFAllocatorNull);
309
310 ApplyScopeListForID(scope_string, whichID);
311
312 CFReleaseNull(scope_string);
313 }
314
315 #pragma mark - Log Handlers to catch log information
316
317
318 /*
319 * Instead of using CFPropertyListReadFromFile we use a
320 * CFPropertyListCreateWithStream directly
321 * here. CFPropertyListReadFromFile() uses
322 * CFURLCopyResourcePropertyForKey() andCF pulls in CoreServices for
323 * CFURLCopyResourcePropertyForKey() and that doesn't work in install
324 * environment.
325 */
326
327 static CFPropertyListRef
328 CopyPlistFromFile(CFURLRef url)
329 {
330 CFDictionaryRef d = NULL;
331 CFReadStreamRef s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
332 if (s && CFReadStreamOpen(s)) {
333 d = (CFDictionaryRef)CFPropertyListCreateWithStream(kCFAllocatorDefault, s, 0, kCFPropertyListImmutable, NULL, NULL);
334 }
335 CFReleaseSafe(s);
336
337 return d;
338 }
339
340 static void ApplyScopeByTypeForID(CFPropertyListRef scopes, SecDebugScopeID whichID) {
341 if (isDictionary(scopes)) {
342 ApplyScopeDictionaryForID(scopes, whichID);
343 } else if (isString(scopes)) {
344 ApplyScopeListForID(scopes, whichID);
345 }
346 }
347
348 static void setup_config_settings() {
349 CFStringRef logFileName;
350 #if TARGET_OS_IPHONE
351 logFileName = CFSTR(".GlobalPreferences.plist");
352 #else
353 logFileName = CFSTR("com.apple.security.logging.plist");
354 #endif
355 CFURLRef prefURL = SecCopyURLForFileInManagedPreferencesDirectory(logFileName);
356 if(prefURL) {
357 CFPropertyListRef plist = CopyPlistFromFile(prefURL);
358 if (plist) {
359 ApplyScopeByTypeForID(CFDictionaryGetValue(plist, CFSTR("SecLogging")), kScopeIDConfig);
360 }
361 CFReleaseSafe(plist);
362 }
363 CFReleaseSafe(prefURL);
364 }
365
366 static void setup_defaults_settings() {
367 CFPropertyListRef scopes_value = CFPreferencesCopyValue(CFSTR("Logging"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
368
369 ApplyScopeByTypeForID(scopes_value, kScopeIDDefaults);
370
371 CFReleaseSafe(scopes_value);
372 }
373
374 static void setup_circle_defaults_settings() {
375 CFPropertyListRef scopes_value = CFPreferencesCopyValue(CFSTR("Circle-Logging"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
376
377 ApplyScopeByTypeForID(scopes_value, kScopeIDDefaults);
378
379 CFReleaseSafe(scopes_value);
380 }
381
382 static void setup_environment_scopes() {
383 const char *cur_scope = getenv("DEBUGSCOPE");
384 if (cur_scope == NULL)
385 cur_scope = "";
386
387 ApplyScopeListForIDC(cur_scope, kScopeIDEnvironment);
388 }
389
390
391 void __security_debug_init(void) {
392 static dispatch_once_t sdOnceToken;
393
394 dispatch_once(&sdOnceToken, ^{
395 setup_environment_scopes();
396 setup_config_settings();
397 setup_defaults_settings();
398 setup_circle_defaults_settings();
399 });
400 }
401
402
403
404
405 static char *copyScopeStr(CFStringRef scope, char *alternative) {
406 char *scopeStr = NULL;
407 if(scope) {
408 scopeStr = CFStringToCString(scope);
409 } else {
410 scopeStr = strdup("noScope");
411 }
412 return scopeStr;
413 }
414
415 static os_log_t logObjForCFScope(CFStringRef scope) {
416 static dispatch_once_t onceToken = 0;
417 __block os_log_t retval = OS_LOG_DISABLED;
418 static dispatch_queue_t logObjectQueue = NULL;
419 static CFMutableDictionaryRef scopeMap = NULL;
420
421 if(scope == NULL) scope = CFSTR("logging");
422
423 dispatch_once(&onceToken, ^{
424 logObjectQueue = dispatch_queue_create("logObjectQueue", DISPATCH_QUEUE_SERIAL);
425 scopeMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, NULL);
426 });
427
428 dispatch_sync(logObjectQueue, ^{
429 retval = (os_log_t) CFDictionaryGetValue(scopeMap, scope);
430 if (retval) return;
431
432 CFStringPerformWithCString(scope, ^(const char *scopeStr) {
433 CFDictionaryAddValue(scopeMap, scope, os_log_create("com.apple.securityd", scopeStr));
434 });
435 retval = (os_log_t) CFDictionaryGetValue(scopeMap, scope);
436 });
437
438 return retval;
439 }
440
441 static bool loggingEnabled = true;
442
443 bool secLogEnabled(void) {
444 return loggingEnabled;
445 }
446 void secLogDisable(void) {
447 loggingEnabled = false;
448 }
449
450 void secLogEnable(void) {
451 loggingEnabled = true;
452 }
453
454
455 os_log_t logObjForScope(const char *scope) {
456 if (!loggingEnabled)
457 return OS_LOG_DISABLED;
458 CFStringRef cfscope = NULL;
459 if(scope) cfscope = CFStringCreateWithCString(kCFAllocatorDefault, scope, kCFStringEncodingASCII);
460 os_log_t retval = logObjForCFScope(cfscope);
461 CFReleaseNull(cfscope);
462 return retval;
463 }
464
465
466
467 CFStringRef SecLogAPICreate(bool apiIn, const char *api, CFStringRef format, ... ) {
468 CFMutableStringRef outStr = CFStringCreateMutable(kCFAllocatorDefault, 0);
469
470 char *direction = apiIn ? "ENTER" : "RETURN";
471 va_list args;
472 va_start(args, format);
473
474 CFStringAppend(outStr, CFSTR("SecAPITrace "));
475 CFStringAppendCString(outStr, api, kCFStringEncodingASCII);
476 CFStringAppendCString(outStr, direction, kCFStringEncodingASCII);
477
478 if (format) {
479 CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args);
480 CFStringAppend(outStr, message);
481 CFReleaseSafe(message);
482 }
483
484 if (apiIn) {
485 char caller_info[80];
486 snprintf(caller_info, sizeof(caller_info), "C%p F%p", __builtin_return_address(1), __builtin_frame_address(2));
487 CFStringAppend(outStr, CFSTR("CALLER "));
488 CFStringAppendCString(outStr, caller_info, kCFStringEncodingASCII);
489 }
490 va_end(args);
491
492 return outStr;
493 }
494
495 #if TARGET_OS_OSX
496 #ifdef NO_OS_LOG
497 // Functions for weak-linking os_log functions
498 #include <dlfcn.h>
499
500 #define weak_log_f(fname, newname, rettype, fallthrough) \
501 rettype newname(log_args) { \
502 static dispatch_once_t onceToken = 0; \
503 static rettype (*newname)(log_args) = NULL; \
504 \
505 dispatch_once(&onceToken, ^{ \
506 void* libtrace = dlopen("/usr/lib/system/libsystem_trace.dylib", RTLD_LAZY | RTLD_LOCAL); \
507 if (libtrace) { \
508 newname = (rettype(*)(log_args)) dlsym(libtrace, #fname); \
509 } \
510 }); \
511 \
512 if(newname) { \
513 return newname(log_argnames); \
514 } \
515 fallthrough;\
516 }
517
518 #define log_args void *dso, os_log_t log, os_log_type_t type, const char *format, uint8_t *buf, unsigned int size
519 #define log_argnames dso, log, type, format, buf, size
520 weak_log_f(_os_log_impl, weak_os_log_impl, void, return);
521 #undef log_args
522 #undef log_argnames
523
524 #define log_args const char *subsystem, const char *category
525 #define log_argnames subsystem, category
526 weak_log_f(os_log_create, weak_os_log_create, os_log_t, return NULL);
527 #undef log_args
528 #undef log_argnames
529
530 #define log_args os_log_t oslog, os_log_type_t type
531 #define log_argnames oslog, type
532 weak_log_f(os_log_type_enabled, weak_os_log_type_enabled, bool, return false);
533 #undef log_args
534 #undef log_argnames
535
536 #undef weak_log_f
537
538 #endif // NO_OS_LOG
539 #endif // TARGET_OS_OSX
540