void
debugCallback(
	CFNotificationCenterRef center,
	void *observer,
	CFStringRef name,
	const void *object,
	CFDictionaryRef userInfo)
{
	int i = 0;
	
	printf("Debug callback: %s\n", CFStringToCString(name));
	if (!userInfo)
		return;
	
	CFIndex count = CFDictionaryGetCount(userInfo);
	const void *keys[count];
	const void *values[count];
	CFDictionaryGetKeysAndValues(userInfo, keys, values);
	for(i = 0; i < count; i++)
	{
		printf("For i=%d, key: %s\n", i,
					CFStringToCString((CFStringRef)keys[i]));
	}
}
static void
filter_exception(const void *key, const void *value, void *context)
{
	SecExceptionFilterContext *ctx = (SecExceptionFilterContext *)context;
	if (!ctx) { return; }

	SecTrustOptionFlags options = ctx->flags;
	CFMutableDictionaryRef filteredException = ctx->filteredException;
	CFStringRef keystr = (CFStringRef)key;

	if (ctx->oldException && CFDictionaryContainsKey(ctx->oldException, key)) {
		// Keep existing exception in filtered dictionary, regardless of options
		CFDictionaryAddValue(filteredException, key, CFDictionaryGetValue(ctx->oldException, key));
		return;
	}

	bool allowed = false;

	if (CFEqual(keystr, CFSTR("SHA1Digest"))) {
		allowed = true; // this key is informational and always permitted
	}
	else if (CFEqual(keystr, CFSTR("NotValidBefore"))) {
		allowed = ((options & kSecTrustOptionAllowExpired) != 0);
	}
	else if (CFEqual(keystr, CFSTR("ValidLeaf"))) {
		allowed = ((options & kSecTrustOptionAllowExpired) != 0);
	}
	else if (CFEqual(keystr, CFSTR("ValidIntermediates"))) {
		allowed = ((options & kSecTrustOptionAllowExpired) != 0);
	}
	else if (CFEqual(keystr, CFSTR("ValidRoot"))) {
        if (((options & kSecTrustOptionAllowExpired) != 0) ||
            ((options & kSecTrustOptionAllowExpiredRoot) != 0)) {
            allowed = true;
        }
	}
	else if (CFEqual(keystr, CFSTR("AnchorTrusted"))) {
		bool implicitAnchors = ((options & kSecTrustOptionImplicitAnchors) != 0);
		// Implicit anchors option only filters exceptions for self-signed certs
		if (implicitAnchors && ctx->trustRef &&
		    (ctx->certIX < SecTrustGetCertificateCount(ctx->trustRef))) {
			Boolean isSelfSigned = false;
			SecCertificateRef cert = SecTrustGetCertificateAtIndex(ctx->trustRef, ctx->certIX);
			if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) &&
			    isSelfSigned) {
				allowed = true;
			}
		}
	}
	else if (CFEqual(keystr, CFSTR("KeyUsage")) ||
	         CFEqual(keystr, CFSTR("ExtendedKeyUsage")) ||
	         CFEqual(keystr, CFSTR("BasicConstraints")) ||
	         CFEqual(keystr, CFSTR("NonEmptySubject")) ||
	         CFEqual(keystr, CFSTR("IdLinkage"))) {
		// Cannot override these exceptions
		allowed = false;
	}
	else {
		// Unhandled exceptions should not be overridden,
		// but we want to know which ones we're missing
		char *cstr = CFStringToCString(keystr);
		syslog(LOG_ERR, "Unfiltered exception: %s", (cstr) ? cstr : "<NULL>");
		if (cstr) { free(cstr); }
		allowed = false;
	}

	if (allowed) {
		CFDictionaryAddValue(filteredException, key, value);
	}
}
OSStatus SecAccessCreateWithTrustedApplications(CFStringRef trustedApplicationsPListPath, CFStringRef accessLabel, Boolean allowAny, SecAccessRef* returnedAccess)
{
	OSStatus err = errSecSuccess;
	SecAccessRef accessToReturn=nil;
	CFMutableArrayRef trustedApplications=nil;

	if (!allowAny) // use default access ("confirm access")
	{
		// make an exception list of applications you want to trust,
		// which are allowed to access the item without requiring user confirmation
		SecTrustedApplicationRef myself=NULL, someOther=NULL;
        CFArrayRef trustedAppListFromBundle=NULL;

        trustedApplications=CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks);
        err = SecTrustedApplicationCreateFromPath(NULL, &myself);
        if (!err)
            CFArrayAppendValue(trustedApplications,myself);

		CFURLRef url = CFURLCreateWithFileSystemPath(NULL, trustedApplicationsPListPath, kCFURLPOSIXPathStyle, 0);
		CFStringRef leafStr = NULL;
		leafStr = CFURLCopyLastPathComponent(url);

		CFURLRef bndlPathURL = NULL;
		bndlPathURL = CFURLCreateCopyDeletingLastPathComponent(NULL, url);
		CFStringRef bndlPath = NULL;
		bndlPath = CFURLCopyFileSystemPath(bndlPathURL, kCFURLPOSIXPathStyle);
        trustedAppListFromBundle=copyTrustedAppListFromBundle(bndlPath, leafStr);
		if ( leafStr )
			CFRelease(leafStr);
		if ( bndlPath )
			CFRelease(bndlPath);
		if ( url )
			CFRelease(url);
		if ( bndlPathURL )
			CFRelease(bndlPathURL);
        if (trustedAppListFromBundle)
        {
            CFIndex ix,top;
            char buffer[MAXPATHLEN];
            top = CFArrayGetCount(trustedAppListFromBundle);
            for (ix=0;ix<top;ix++)
            {
                CFStringRef filename = (CFStringRef)CFArrayGetValueAtIndex(trustedAppListFromBundle,ix);
                CFIndex stringLength = CFStringGetLength(filename);
                CFIndex usedBufLen;

                if (stringLength != CFStringGetBytes(filename,CFRangeMake(0,stringLength),kCFStringEncodingUTF8,0,
                    false,(UInt8 *)&buffer,MAXPATHLEN, &usedBufLen))
                    break;
                buffer[usedBufLen] = 0;
				//
				// Support specification of trusted applications by either
				// a full pathname or a code requirement string.
				//
				if (buffer[0]=='/')
				{
					err = SecTrustedApplicationCreateFromPath(buffer,&someOther);
				}
				else
				{
					char *buf = NULL;
					CFStringRef reqStr = filename;
					CFArrayRef descArray = CFStringCreateArrayBySeparatingStrings(NULL, reqStr, CFSTR("\""));
					if (descArray && (CFArrayGetCount(descArray) > 1))
					{
						CFStringRef descStr = (CFStringRef) CFArrayGetValueAtIndex(descArray, 1);
						if (descStr)
							buf = CFStringToCString(descStr);
					}
					SecRequirementRef reqRef = NULL;
					err = SecRequirementCreateWithString(reqStr, kSecCSDefaultFlags, &reqRef);
					if (!err)
						err = SecTrustedApplicationCreateFromRequirement((const char *)buf, reqRef, &someOther);
					if (buf)
						free(buf);
					CFReleaseSafe(reqRef);
					CFReleaseSafe(descArray);
				}
                if (!err)
                    CFArrayAppendValue(trustedApplications,someOther);

				if (someOther)
					CFReleaseNull(someOther);
            }
            CFRelease(trustedAppListFromBundle);
        }
	}

	err = SecAccessCreate((CFStringRef)accessLabel, (CFArrayRef)trustedApplications, &accessToReturn);
    if (!err)
	{
		if (allowAny) // change access to be wide-open for decryption ("always allow access")
		{
			// get the access control list for decryption operations
			CFArrayRef aclList=nil;
			err = SecAccessCopySelectedACLList(accessToReturn, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
			if (!err)
			{
				// get the first entry in the access control list
				SecACLRef aclRef=(SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
				CFArrayRef appList=nil;
				CFStringRef promptDescription=nil;
				CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
				err = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);

				// modify the default ACL to not require the passphrase, and have a nil application list
				promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
				err = SecACLSetSimpleContents(aclRef, NULL, promptDescription, &promptSelector);

				if (appList) CFRelease(appList);
				if (promptDescription) CFRelease(promptDescription);
			}
		}
	}
	*returnedAccess = accessToReturn;
	return err;
}