+++ /dev/null
-/*
- * Copyright (c) 2006-2010,2012-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@
- */
-
-
-/*
- * debugging.c - non-trivial debug support
- */
-#include "utilities/debugging.h"
-#include "utilities/debugging_test.h"
-#include "utilities/SecCFWrappers.h"
-#include <CoreFoundation/CFSet.h>
-#include <CoreFoundation/CFString.h>
-#include <CoreFoundation/CFPreferences.h>
-
-#include <dispatch/dispatch.h>
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <pthread.h>
-#include <asl.h>
-
-
-const CFStringRef kStringNegate = CFSTR("-");
-const CFStringRef kStringAll = CFSTR("all");
-
-const CFStringRef kAPIScope = CFSTR("api");
-
-static CFMutableArrayRef sLogSettings = NULL; /* Either sets or dictionaries of level => set. */
-
-static dispatch_queue_t GetDispatchControlQueue(void) {
- static dispatch_queue_t sLoggingScopeControlQueue;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- sLoggingScopeControlQueue = dispatch_queue_create("security scope control", DISPATCH_QUEUE_CONCURRENT);
- });
- return sLoggingScopeControlQueue;
-}
-
-static void with_scopes_read(dispatch_block_t action) {
- dispatch_sync(GetDispatchControlQueue(), action);
-}
-
-static void with_scopes_write(dispatch_block_t action) {
- dispatch_barrier_sync(GetDispatchControlQueue(), action);
-}
-
-bool IsScopeActive(int level, CFStringRef scope)
-{
- if (scope == NULL)
- return true;
-
- CFNumberRef level_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &level);
-
- __block bool isActive = false;
- with_scopes_read(^{
- if (sLogSettings) {
- CFArrayForEach(sLogSettings, ^(const void *value) {
- CFSetRef setToCheck = NULL;
-
- if (isSet(value)) {
- setToCheck = (CFSetRef) value;
- } else if (isDictionary(value)) {
- CFDictionaryRef levels = (CFDictionaryRef) value;
-
- setToCheck = CFDictionaryGetValue(levels, level_number);
-
- if (!isSet(setToCheck))
- setToCheck = NULL;
- }
-
- if (setToCheck != NULL && !isActive) {
- bool negated = CFSetContainsValue(setToCheck, kStringNegate);
- bool inSet = CFSetContainsValue(setToCheck, scope);
-
- isActive = negated ^ inSet;
- }
- });
- }
- });
-
- CFReleaseNull(level_number);
-
- return isActive;
-}
-
-bool IsScopeActiveC(int level, const char *scope)
-{
- CFStringRef scopeString = CFStringCreateWithBytes(kCFAllocatorDefault, (const uint8_t*)scope, strlen(scope), kCFStringEncodingUTF8, false);
- bool isActive = IsScopeActive(level, scopeString);
- CFReleaseNull(scopeString);
-
- return isActive;
-}
-
-
-
-static CFStringRef copyScopeName(const char *scope, CFIndex scopeLen) {
- return CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)scope,
- scopeLen, kCFStringEncodingUTF8, false);
-}
-
-static CFMutableSetRef CopyScopesFromScopeList(CFStringRef scopes) {
- CFMutableSetRef resultSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
-
- CFStringRef allocated_scope_list = NULL;
- CFStringRef clean_scope_list = scopes;
- bool add_negate = false;
-
- if (CFStringHasPrefix(scopes, kStringNegate)) {
- allocated_scope_list = CFStringCreateWithSubstring(kCFAllocatorDefault, scopes, CFRangeMake(CFStringGetLength(kStringNegate), CFStringGetLength(scopes) - 1));
- clean_scope_list = allocated_scope_list;
- add_negate = true;
- }
-
- CFArrayRef commaArray = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, clean_scope_list, CFSTR(","));
-
- if (commaArray) {
- CFArrayForEach(commaArray, ^(const void *value) {
- if (isString(value)) {
- CFMutableStringRef copy = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, (CFStringRef) value);
- CFStringTrimWhitespace(copy);
- CFSetSetValue(resultSet, copy);
- CFReleaseNull(copy);
- }
- });
- }
-
- CFSetRemoveValue(resultSet, CFSTR("none"));
- CFSetRemoveValue(resultSet, CFSTR(""));
-
- if (CFSetContainsValue(resultSet, CFSTR("all"))) {
- CFSetRemoveAllValues(resultSet);
- add_negate = !add_negate;
- }
-
- if (add_negate)
- CFSetSetValue(resultSet, kStringNegate);
-
- CFReleaseNull(commaArray);
- CFReleaseNull(allocated_scope_list);
-
- return resultSet;
-}
-
-static CFMutableArrayRef CFArrayCreateMutableForCFTypesFilledWithCFNull(CFAllocatorRef allocator, CFIndex capacity) {
- CFMutableArrayRef result = CFArrayCreateMutableForCFTypesWithCapacity(kCFAllocatorDefault, kScopeIDMax);
-
- for(int count = 0; count <= capacity; ++count)
- CFArrayAppendValue(result, kCFNull);
-
- return result;
-}
-
-static bool CFArrayIsAll(CFArrayRef array, const void *value)
-{
- return CFArrayGetCountOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), value) == CFArrayGetCount(array);
-}
-
-static void SetNthScopeSet(int nth, CFTypeRef collection)
-{
- with_scopes_write(^{
- if (sLogSettings == NULL) {
- sLogSettings = CFArrayCreateMutableForCFTypesFilledWithCFNull(kCFAllocatorDefault, kScopeIDMax);
- }
-
- CFArraySetValueAtIndex(sLogSettings, nth, collection);
-
- if (CFArrayIsAll(sLogSettings, kCFNull)) {
- CFReleaseNull(sLogSettings);
- }
- });
-}
-
-static int string_to_log_level(CFStringRef string) {
- if (CFEqual(string, CFSTR(ASL_STRING_EMERG)))
- return ASL_LEVEL_EMERG;
- else if (CFEqual(string, CFSTR(ASL_STRING_ALERT)))
- return ASL_LEVEL_ALERT;
- else if (CFEqual(string, CFSTR(ASL_STRING_CRIT)))
- return ASL_LEVEL_CRIT;
- else if (CFEqual(string, CFSTR(ASL_STRING_ERR)))
- return ASL_LEVEL_ERR;
- else if (CFEqual(string, CFSTR(ASL_STRING_WARNING)))
- return ASL_LEVEL_WARNING;
- else if (CFEqual(string, CFSTR(ASL_STRING_NOTICE)))
- return ASL_LEVEL_NOTICE;
- else if (CFEqual(string, CFSTR(ASL_STRING_INFO)))
- return ASL_LEVEL_INFO;
- else if (CFEqual(string, CFSTR(ASL_STRING_DEBUG)))
- return ASL_LEVEL_DEBUG;
- else
- return -1;
-}
-
-static void CFSetAppendValues(CFSetRef set, CFMutableArrayRef appendTo)
-{
- CFSetForEach(set, ^(const void *value) {
- CFArrayAppendValue(appendTo, value);
- });
-}
-
-static CFMutableArrayRef CFSetOfCFObjectsCopyValues(CFSetRef setOfCFs)
-{
- CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-
- CFSetForEach(setOfCFs, ^(const void *value) {
- CFArrayAppendValue(result, value);
- });
-
- return result;
-}
-
-CFPropertyListRef CopyCurrentScopePlist(void)
-{
- CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
- with_scopes_read(^{
- CFArrayForEach(sLogSettings, ^(const void *value) {
- if (isSet(value)) {
- CFArrayRef values = CFSetOfCFObjectsCopyValues((CFSetRef) value);
- CFArrayAppendValue(result, values);
- CFReleaseNull(values);
- } else if (isDictionary(value)) {
- CFMutableDictionaryRef levels = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-
- CFDictionaryForEach((CFDictionaryRef) value, ^(const void *key, const void *value) {
- if (isSet(value)) {
- CFArrayRef values = CFSetOfCFObjectsCopyValues((CFSetRef) value);
- CFDictionaryAddValue(levels, key, values);
- CFReleaseNull(values);
- }
- });
-
- CFArrayAppendValue(result, levels);
- } else {
- CFArrayAppendValue(result, kCFNull);
- }
- });
- });
- return result;
-}
-
-void ApplyScopeDictionaryForID(CFDictionaryRef scopeDictionary, SecDebugScopeID whichID)
-{
- CFMutableDictionaryRef dictionary_for_id = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-
- CFDictionaryForEach(scopeDictionary, ^(const void *key, const void *value) {
- CFSetRef scope_set = NULL;
- CFNumberRef key_number = NULL;
- if (isString(key)) {
- int level = string_to_log_level((CFStringRef) key);
-
- if (level >= 0)
- key_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &level);
- } else if (isNumber(key)) {
- key_number = CFRetainSafe(key);
- }
-
- if (isString(value)) {
- scope_set = CopyScopesFromScopeList(value);
- }
-
- if (key_number && scope_set)
- CFDictionaryAddValue(dictionary_for_id, key_number, scope_set);
-
- CFReleaseNull(key_number);
- CFReleaseNull(scope_set);
- });
-
- if (CFDictionaryGetCount(dictionary_for_id) > 0) {
- SetNthScopeSet(whichID, dictionary_for_id);
- }
-
- CFReleaseNull(dictionary_for_id);
-}
-
-void ApplyScopeListForID(CFStringRef scopeList, SecDebugScopeID whichID)
-{
- CFMutableSetRef scopesToUse = CopyScopesFromScopeList(scopeList);
-
- SetNthScopeSet(whichID, scopesToUse);
-
- CFReleaseNull(scopesToUse);
-}
-
-void ApplyScopeListForIDC(const char *scopeList, SecDebugScopeID whichID) {
- CFStringRef scope_string = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, scopeList, kCFStringEncodingUTF8, kCFAllocatorNull);
-
- ApplyScopeListForID(scope_string, whichID);
-
- CFReleaseNull(scope_string);
-}
-
-#pragma mark - Log Handlers to catch log information
-
-static CFMutableArrayRef sSecurityLogHandlers;
-
-#if TARGET_OS_IPHONE
-
-/*
- * Instead of using CFPropertyListReadFromFile we use a
- * CFPropertyListCreateWithStream directly
- * here. CFPropertyListReadFromFile() uses
- * CFURLCopyResourcePropertyForKey() andCF pulls in CoreServices for
- * CFURLCopyResourcePropertyForKey() and that doesn't work in install
- * enviroment.
- */
-
-static CFPropertyListRef
-CopyPlistFromFile(CFURLRef url)
-{
- CFDictionaryRef d = NULL;
- CFReadStreamRef s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
- if (s && CFReadStreamOpen(s)) {
- d = (CFDictionaryRef)CFPropertyListCreateWithStream(kCFAllocatorDefault, s, 0, kCFPropertyListImmutable, NULL, NULL);
- }
- CFReleaseSafe(s);
-
- return d;
-}
-#endif
-
-static void ApplyScopeByTypeForID(CFPropertyListRef scopes, SecDebugScopeID whichID) {
- if (isDictionary(scopes)) {
- ApplyScopeDictionaryForID(scopes, whichID);
- } else if (isString(scopes)) {
- ApplyScopeListForID(scopes, whichID);
- }
-}
-
-static void setup_config_settings() {
-#if TARGET_OS_IPHONE
- CFURLRef prefURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/Library/Managed Preferences/mobile/.GlobalPreferences.plist"), kCFURLPOSIXPathStyle, false);
- if(prefURL) {
- CFPropertyListRef plist = CopyPlistFromFile(prefURL);
- if (plist) {
- ApplyScopeByTypeForID(CFDictionaryGetValue(plist, CFSTR("SecLogging")), kScopeIDConfig);
- }
- CFReleaseSafe(plist);
- }
- CFReleaseSafe(prefURL);
-#endif
-}
-
-static void setup_defaults_settings() {
- CFPropertyListRef scopes_value = CFPreferencesCopyValue(CFSTR("Logging"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
-
- ApplyScopeByTypeForID(scopes_value, kScopeIDDefaults);
-
- CFReleaseSafe(scopes_value);
-}
-
-static void setup_environment_scopes() {
- const char *cur_scope = getenv("DEBUGSCOPE");
- if (cur_scope == NULL)
- cur_scope = "";
-
- ApplyScopeListForIDC(cur_scope, kScopeIDEnvironment);
-}
-
-void __security_debug_init(void) {
- static dispatch_once_t sdOnceToken;
-
- dispatch_once(&sdOnceToken, ^{
- setup_environment_scopes();
- setup_config_settings();
- setup_defaults_settings();
- });
-}
-
-
-// MARK: Log handler recording (e.g. grabbing security logging and sending it to test results).
-static void clean_aslclient(void *client)
-{
- asl_close(client);
-}
-
-static aslclient get_aslclient()
-{
- static dispatch_once_t once;
- static pthread_key_t asl_client_key;
- dispatch_once(&once, ^{
- pthread_key_create(&asl_client_key, clean_aslclient);
- });
- aslclient client = pthread_getspecific(asl_client_key);
- if (!client) {
- client = asl_open(NULL, "SecLogging", 0);
- asl_set_filter(client, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
- pthread_setspecific(asl_client_key, client);
- }
-
- return client;
-}
-
-static CFMutableArrayRef get_log_handlers()
-{
- static dispatch_once_t handlers_once;
-
- dispatch_once(&handlers_once, ^{
- sSecurityLogHandlers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-
- CFArrayAppendValue(sSecurityLogHandlers, ^(int level, CFStringRef scope, const char *function,
- const char *file, int line, CFStringRef message){
- CFStringRef logStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %s %@\n"), scope ? scope : CFSTR(""), function, message);
- CFStringPerformWithCString(logStr, ^(const char *logMsg) {
- aslmsg msg = asl_new(ASL_TYPE_MSG);
- if (scope) {
- CFStringPerformWithCString(scope, ^(const char *scopeStr) {
- asl_set(msg, ASL_KEY_FACILITY, scopeStr);
- });
- }
- asl_log(get_aslclient(), msg, level, "%s", logMsg);
- asl_free(msg);
- });
- CFReleaseSafe(logStr);
- });
- });
-
- return sSecurityLogHandlers;
-}
-
-static void log_api_trace_v(const char *api, const char *caller_info, CFStringRef format, va_list args)
-{
- aslmsg msg = asl_new(ASL_TYPE_MSG);
- asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_DEBUG);
- CFStringPerformWithCString(kAPIScope, ^(const char *scopeStr) {
- asl_set(msg, ASL_KEY_FACILITY, scopeStr);
- });
- asl_set(msg, "SecAPITrace", api);
- asl_set(msg, caller_info ? "ENTER" : "RETURN", "");
-
- if (format) {
- CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args);
- CFStringPerformWithCString(message, ^(const char *utf8Str) {
- asl_set(msg, ASL_KEY_MSG, utf8Str);
- });
- CFReleaseSafe(message);
- }
-
- if (caller_info) {
- asl_set(msg, "CALLER", caller_info);
- }
-
- asl_send(get_aslclient(), msg);
- asl_free(msg);
-}
-
-void __security_trace_enter_api(const char *api, CFStringRef format, ...)
-{
- if (!IsScopeActive(ASL_LEVEL_DEBUG, kAPIScope))
- return;
-
- va_list args;
- va_start(args, format);
-
- {
- char stack_info[80];
-
- snprintf(stack_info, sizeof(stack_info), "C%p F%p", __builtin_return_address(1), __builtin_frame_address(2));
-
- log_api_trace_v(api, stack_info, format, args);
- }
-
- va_end(args);
-}
-
-void __security_trace_return_api(const char *api, CFStringRef format, ...)
-{
- if (!IsScopeActive(ASL_LEVEL_DEBUG, kAPIScope))
- return;
-
- va_list args;
- va_start(args, format);
-
- log_api_trace_v(api, NULL, format, args);
-
- va_end(args);
-}
-
-
-void add_security_log_handler(security_log_handler handler)
-{
- CFArrayAppendValue(get_log_handlers(), handler);
-}
-
-void remove_security_log_handler(security_log_handler handler)
-{
- CFArrayRemoveAllValue(get_log_handlers(), handler);
-}
-
-static void __security_post_msg(int level, CFStringRef scope, const char *function,
- const char *file, int line, CFStringRef message)
-{
- CFArrayForEach(get_log_handlers(), ^(const void *value) {
- security_log_handler handler = (security_log_handler) value;
-
- handler(level, scope, function, file, line, message);
- });
-}
-
-static void __security_log_msg_v(int level, CFStringRef scope, const char *function,
- const char *file, int line, CFStringRef format, va_list args)
-{
- __security_debug_init();
-
- if (!IsScopeActive(level, scope))
- return;
-
- CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args);
- __security_post_msg(level, scope, function, file, line, message);
- CFRelease(message);
-
-}
-
-void __security_debug(CFStringRef scope, const char *function,
- const char *file, int line, CFStringRef format, ...)
-{
- va_list args;
- va_start(args, format);
-
- __security_log_msg_v(ASL_LEVEL_DEBUG, scope, function, file, line, format, args);
-
- va_end(args);
-}
-
-void __security_log(int level, CFStringRef scope, const char *function,
- const char *file, int line, CFStringRef format, ...)
-{
- va_list args;
- va_start(args, format);
-
- __security_log_msg_v(level, scope, function, file, line, format, args);
-
- va_end(args);
-}