X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_codesigning/lib/SecAssessment.cpp diff --git a/libsecurity_codesigning/lib/SecAssessment.cpp b/libsecurity_codesigning/lib/SecAssessment.cpp deleted file mode 100644 index 68417ce6..00000000 --- a/libsecurity_codesigning/lib/SecAssessment.cpp +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (c) 2011 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@ - */ -#include "cs.h" -#include "SecAssessment.h" -#include "policydb.h" -#include "policyengine.h" -#include "xpcengine.h" -#include "csutilities.h" -#include -#include -#include -#include -#include -#include - -using namespace CodeSigning; - - -static void esp_do_check(const char *op, CFDictionaryRef dict) -{ - OSStatus result = __esp_check_ns(op, (void *)(CFDictionaryRef)dict); - if (result != noErr) - MacOSError::throwMe(result); -} - -// -// CF Objects -// -struct _SecAssessment : private CFRuntimeBase { -public: - _SecAssessment(CFURLRef p, AuthorityType typ, CFDictionaryRef c, CFDictionaryRef r) : path(p), context(c), type(typ), result(r) { } - - CFCopyRef path; - CFCopyRef context; - AuthorityType type; - CFRef result; - -public: - static _SecAssessment &ref(SecAssessmentRef r) - { return *(_SecAssessment *)r; } - - // CF Boiler-plate - void *operator new (size_t size) - { - return (void *)_CFRuntimeCreateInstance(NULL, SecAssessmentGetTypeID(), - sizeof(_SecAssessment) - sizeof(CFRuntimeBase), NULL); - } - - static void finalize(CFTypeRef obj) - { ((_SecAssessment *)obj)->~_SecAssessment(); } -}; - -typedef _SecAssessment SecAssessment; - - -static const CFRuntimeClass assessmentClass = { - 0, // version - "SecAssessment", // name - NULL, // init - NULL, // copy - SecAssessment::finalize, // finalize - NULL, // equal - NULL, // hash - NULL, // formatting - NULL // debug string -}; - - -static dispatch_once_t assessmentOnce; -CFTypeID assessmentType = _kCFRuntimeNotATypeID; - -CFTypeID SecAssessmentGetTypeID() -{ - dispatch_once(&assessmentOnce, ^void() { - if ((assessmentType = _CFRuntimeRegisterClass(&assessmentClass)) == _kCFRuntimeNotATypeID) - abort(); - }); - return assessmentType; -} - - -// -// Common dictionary constants -// -CFStringRef kSecAssessmentContextKeyOperation = CFSTR("operation"); -CFStringRef kSecAssessmentOperationTypeExecute = CFSTR("operation:execute"); -CFStringRef kSecAssessmentOperationTypeInstall = CFSTR("operation:install"); -CFStringRef kSecAssessmentOperationTypeOpenDocument = CFSTR("operation:lsopen"); - -CFStringRef kSecAssessmentContextQuarantineFlags = CFSTR("context:qtnflags"); - - -// -// Read-only in-process access to the policy database -// -class ReadPolicy : public PolicyDatabase { -public: - ReadPolicy() : PolicyDatabase(defaultDatabase) { } -}; -ModuleNexus gDatabase; - - -// -// An on-demand instance of the policy engine -// -ModuleNexus gEngine; - - -// -// Policy evaluation ("assessment") operations -// -CFStringRef kSecAssessmentAssessmentVerdict = CFSTR("assessment:verdict"); -CFStringRef kSecAssessmentAssessmentOriginator = CFSTR("assessment:originator"); -CFStringRef kSecAssessmentAssessmentAuthority = CFSTR("assessment:authority"); -CFStringRef kSecAssessmentAssessmentSource = CFSTR("assessment:authority:source"); -CFStringRef kSecAssessmentAssessmentAuthorityRow = CFSTR("assessment:authority:row"); -CFStringRef kSecAssessmentAssessmentAuthorityOverride = CFSTR("assessment:authority:override"); -CFStringRef kSecAssessmentAssessmentAuthorityOriginalVerdict = CFSTR("assessment:authority:verdict"); -CFStringRef kSecAssessmentAssessmentFromCache = CFSTR("assessment:authority:cached"); -CFStringRef kSecAssessmentAssessmentWeakSignature = CFSTR("assessment:authority:weak"); -CFStringRef kSecAssessmentAssessmentCodeSigningError = CFSTR("assessment:cserror"); - -CFStringRef kDisabledOverride = CFSTR("security disabled"); - -SecAssessmentRef SecAssessmentCreate(CFURLRef path, - SecAssessmentFlags flags, - CFDictionaryRef context, - CFErrorRef *errors) -{ - BEGIN_CSAPI - - if (flags & kSecAssessmentFlagAsynchronous) - MacOSError::throwMe(errSecCSUnimplemented); - - AuthorityType type = typeFor(context, kAuthorityExecute); - CFRef result = makeCFMutableDictionary(); - - SYSPOLICY_ASSESS_API(cfString(path).c_str(), int(type), flags); - - try { - if (__esp_enabled() && (flags & kSecAssessmentFlagDirect)) { - CFTemp dict("{path=%O, flags=%d, context=%O, override=%d}", path, flags, context, overrideAssessment()); - esp_do_check("cs-assessment-evaluate", dict); - } - - // check the object cache first unless caller denied that or we need extended processing - if (!(flags & (kSecAssessmentFlagRequestOrigin | kSecAssessmentFlagIgnoreCache))) { - if (gDatabase().checkCache(path, type, flags, result)) - return new SecAssessment(path, type, context, result.yield()); - } - - if (flags & kSecAssessmentFlagDirect) { - // ask the engine right here to do its thing - SYSPOLICY_ASSESS_LOCAL(); - gEngine().evaluate(path, type, flags, context, result); - } else { - // relay the question to our daemon for consideration - SYSPOLICY_ASSESS_REMOTE(); - xpcEngineAssess(path, flags, context, result); - } - } catch (CommonError &error) { - switch (error.osStatus()) { - case CSSMERR_TP_CERT_REVOKED: - throw; - default: - if (!overrideAssessment(flags)) - throw; // let it go as an error - break; - } - // record the error we would have returned - cfadd(result, "{%O=#F,'assessment:error'=%d}}", kSecAssessmentAssessmentVerdict, error.osStatus()); - } catch (...) { - // catch stray errors not conforming to the CommonError scheme - if (!overrideAssessment(flags)) - throw; // let it go as an error - cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict); - } - - if (__esp_enabled() && (flags & kSecAssessmentFlagDirect)) { - CFTemp dict("{path=%O, flags=%d, context=%O, override=%d, result=%O}", path, flags, context, overrideAssessment(), (CFDictionaryRef)result); - __esp_notify_ns("cs-assessment-evaluate", (void *)(CFDictionaryRef)dict); - } - - return new SecAssessment(path, type, context, result.yield()); - - END_CSAPI_ERRORS1(NULL) -} - - -static void traceResult(CFURLRef target, MessageTrace &trace, std::string &sanitized) -{ - static const char *interestingBundles[] = { - "UNBUNDLED", - "com.apple.", - "com.install4j.", - "com.MindVision.", - "com.yourcompany.", - - "com.adobe.flashplayer.installmanager", - "com.adobe.Installers.Setup", - "com.adobe.PDApp.setup", - "com.bittorrent.uTorrent", - "com.divx.divx6formacinstaller", - "com.getdropbox.dropbox", - "com.google.Chrome", - "com.Google.GoogleEarthPlugin.plugin", - "com.Google.GoogleEarthPlus", - "com.hp.Installer", - "com.macpaw.CleanMyMac", - "com.microsoft.SilverlightInstaller", - "com.paragon-software.filesystems.NTFS.pkg", - "com.RealNetworks.RealPlayer", - "com.skype.skype", - "it.alfanet.squared5.MPEGStreamclip", - "org.mozilla.firefox", - "org.videolan.vlc", - - NULL // sentinel - }; - - string identifier = "UNBUNDLED"; - string version = "UNKNOWN"; - if (CFRef bundle = CFBundleCreate(NULL, target)) { - if (CFStringRef ident = CFBundleGetIdentifier(bundle)) - identifier = cfString(ident); - if (CFStringRef vers = CFStringRef(CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString")))) - version = cfString(vers); - } - - CFRef url = CFURLCopyAbsoluteURL(target); - sanitized = cfString(url); - string::size_type rslash = sanitized.rfind('/'); - if (rslash != string::npos) - sanitized = sanitized.substr(rslash+1); - bool keepFilename = false; - for (const char **pfx = interestingBundles; *pfx; pfx++) { - size_t pfxlen = strlen(*pfx); - if (identifier.compare(0, pfxlen, *pfx, pfxlen) == 0) - if (pfxlen == identifier.size() || (*pfx)[pfxlen-1] == '.') { - keepFilename = true; - break; - } - } - if (!keepFilename) { - string::size_type dot = sanitized.rfind('.'); - if (dot != string::npos) - sanitized = sanitized.substr(dot); - else - sanitized = "(none)"; - } - - trace.add("signature2", "bundle:%s", identifier.c_str()); - trace.add("signature3", "%s", sanitized.c_str()); - trace.add("signature5", "%s", version.c_str()); -} - -static void traceAssessment(SecAssessment &assessment, AuthorityType type, CFDictionaryRef result) -{ - if (CFDictionaryGetValue(result, CFSTR("assessment:remote"))) - return; // just traced in syspolicyd - - string authority = "UNSPECIFIED"; - bool overridden = false; - bool old_overridden = false; - if (CFDictionaryRef authdict = CFDictionaryRef(CFDictionaryGetValue(result, kSecAssessmentAssessmentAuthority))) { - if (CFStringRef auth = CFStringRef(CFDictionaryGetValue(authdict, kSecAssessmentAssessmentSource))) - authority = cfString(auth); - else - authority = "no authority"; - if (CFTypeRef override = CFDictionaryGetValue(authdict, kSecAssessmentAssessmentAuthorityOverride)) - if (CFEqual(override, kDisabledOverride)) { - old_overridden = true; - if (CFDictionaryGetValue(authdict, kSecAssessmentAssessmentAuthorityOriginalVerdict) == kCFBooleanFalse) - overridden = true; - } - } - - MessageTrace trace("com.apple.security.assessment.outcome2", NULL); - std::string sanitized; - traceResult(assessment.path, trace, sanitized); - trace.add("signature4", "%d", type); - - if (CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict) == kCFBooleanFalse) { - trace.add("signature", "denied:%s", authority.c_str()); - trace.send("assessment denied for %s", sanitized.c_str()); - } else if (overridden) { // would have failed except for override - trace.add("signature", "defeated:%s", authority.c_str()); - trace.send("assessment denied for %s but overridden", sanitized.c_str()); - } else if (old_overridden) { // would have succeeded even without override - trace.add("signature", "override:%s", authority.c_str()); - trace.send("assessment granted for %s and overridden", sanitized.c_str()); - } else { - trace.add("signature", "granted:%s", authority.c_str()); - trace.send("assessment granted for %s by %s", sanitized.c_str(), authority.c_str()); - } -} - -static void traceUpdate(CFTypeRef target, CFDictionaryRef context, CFDictionaryRef result) -{ - // only trace add operations on URL targets - if (target == NULL || CFGetTypeID(target) != CFURLGetTypeID()) - return; - CFStringRef edit = CFStringRef(CFDictionaryGetValue(context, kSecAssessmentContextKeyUpdate)); - if (!CFEqual(edit, kSecAssessmentUpdateOperationAdd)) - return; - MessageTrace trace("com.apple.security.assessment.update", NULL); - std::string sanitized; - traceResult(CFURLRef(target), trace, sanitized); - trace.send("added rule for %s", sanitized.c_str()); -} - - -// -// At present, CopyResult simply retrieves the result already formed by Create. -// In the future, this will be more lazy. -// -CFDictionaryRef SecAssessmentCopyResult(SecAssessmentRef assessmentRef, - SecAssessmentFlags flags, - CFErrorRef *errors) -{ - BEGIN_CSAPI - - SecAssessment &assessment = SecAssessment::ref(assessmentRef); - CFCopyRef result = assessment.result; - if (overrideAssessment(flags)) { - // turn rejections into approvals, but note that we did that - CFTypeRef verdict = CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict); - if (verdict == kCFBooleanFalse) { - CFRef adulterated = makeCFMutableDictionary(result.get()); - CFDictionarySetValue(adulterated, kSecAssessmentAssessmentVerdict, kCFBooleanTrue); - if (CFDictionaryRef authority = CFDictionaryRef(CFDictionaryGetValue(adulterated, kSecAssessmentAssessmentAuthority))) { - CFRef authority2 = makeCFMutableDictionary(authority); - CFDictionarySetValue(authority2, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride); - CFDictionarySetValue(authority2, kSecAssessmentAssessmentAuthorityOriginalVerdict, verdict); - CFDictionarySetValue(adulterated, kSecAssessmentAssessmentAuthority, authority2); - } else { - cfadd(adulterated, "{%O={%O=%O}}", - kSecAssessmentAssessmentAuthority, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride); - } - result = adulterated.get(); - } - } - bool trace = CFDictionaryContainsKey(assessment.context, kSecAssessmentContextQuarantineFlags); - if (trace) - traceAssessment(assessment, assessment.type, result); - return result.yield(); - - END_CSAPI_ERRORS1(NULL) -} - - -// -// Policy editing operations. -// These all make permanent changes to the system-wide authority records. -// -CFStringRef kSecAssessmentContextKeyUpdate = CFSTR("update"); -CFStringRef kSecAssessmentUpdateOperationAdd = CFSTR("update:add"); -CFStringRef kSecAssessmentUpdateOperationRemove = CFSTR("update:remove"); -CFStringRef kSecAssessmentUpdateOperationEnable = CFSTR("update:enable"); -CFStringRef kSecAssessmentUpdateOperationDisable = CFSTR("update:disable"); -CFStringRef kSecAssessmentUpdateOperationFind = CFSTR("update:find"); - -CFStringRef kSecAssessmentUpdateKeyAuthorization = CFSTR("update:authorization"); -CFStringRef kSecAssessmentUpdateKeyPriority = CFSTR("update:priority"); -CFStringRef kSecAssessmentUpdateKeyLabel = CFSTR("update:label"); -CFStringRef kSecAssessmentUpdateKeyExpires = CFSTR("update:expires"); -CFStringRef kSecAssessmentUpdateKeyAllow = CFSTR("update:allow"); -CFStringRef kSecAssessmentUpdateKeyRemarks = CFSTR("update:remarks"); - -CFStringRef kSecAssessmentUpdateKeyRow = CFSTR("update:row"); -CFStringRef kSecAssessmentUpdateKeyCount = CFSTR("update:count"); -CFStringRef kSecAssessmentUpdateKeyFound = CFSTR("update:found"); - -CFStringRef kSecAssessmentRuleKeyID = CFSTR("rule:id"); -CFStringRef kSecAssessmentRuleKeyPriority = CFSTR("rule:priority"); -CFStringRef kSecAssessmentRuleKeyAllow = CFSTR("rule:allow"); -CFStringRef kSecAssessmentRuleKeyLabel = CFSTR("rule:label"); -CFStringRef kSecAssessmentRuleKeyRemarks = CFSTR("rule:remarks"); -CFStringRef kSecAssessmentRuleKeyRequirement = CFSTR("rule:requirement"); -CFStringRef kSecAssessmentRuleKeyType = CFSTR("rule:type"); -CFStringRef kSecAssessmentRuleKeyExpires = CFSTR("rule:expires"); -CFStringRef kSecAssessmentRuleKeyDisabled = CFSTR("rule:disabled"); -CFStringRef kSecAssessmentRuleKeyBookmark = CFSTR("rule:bookmark"); - - -Boolean SecAssessmentUpdate(CFTypeRef target, - SecAssessmentFlags flags, - CFDictionaryRef context, - CFErrorRef *errors) -{ - if (CFDictionaryRef outcome = SecAssessmentCopyUpdate(target, flags, context, errors)) { - CFRelease(outcome); - return true; - } else { - return false; - } -} - -CFDictionaryRef SecAssessmentCopyUpdate(CFTypeRef target, - SecAssessmentFlags flags, - CFDictionaryRef context, - CFErrorRef *errors) -{ - BEGIN_CSAPI - - CFDictionary ctx(context, errSecCSInvalidAttributeValues); - CFRef result; - - if (flags & kSecAssessmentFlagDirect) { - if (__esp_enabled()) { - CFTemp dict("{target=%O, flags=%d, context=%O}", target, flags, context); - OSStatus esp_result = __esp_check_ns("cs-assessment-update", (void *)(CFDictionaryRef)dict); - if (esp_result != noErr) - return NULL; - } - - // ask the engine right here to do its thing - result = gEngine().update(target, flags, ctx); - } else { - // relay the question to our daemon for consideration - result = xpcEngineUpdate(target, flags, ctx); - } - - if (__esp_enabled() && (flags & kSecAssessmentFlagDirect)) { - CFTemp dict("{target=%O, flags=%d, context=%O, outcome=%O}", target, flags, context, (CFDictionaryRef)result); - __esp_notify_ns("cs-assessment-update", (void *)(CFDictionaryRef)dict); - } - - traceUpdate(target, context, result); - return result.yield(); - - END_CSAPI_ERRORS1(false) -} - - -// -// The fcntl of System Policies. -// For those very special requests. -// -Boolean SecAssessmentControl(CFStringRef control, void *arguments, CFErrorRef *errors) -{ - BEGIN_CSAPI - - CFTemp dict("{control=%O}", control); - esp_do_check("cs-assessment-control", dict); - - if (CFEqual(control, CFSTR("ui-enable"))) { - setAssessment(true); - MessageTrace trace("com.apple.security.assessment.state", "enable"); - trace.send("enable assessment outcomes"); - return true; - } else if (CFEqual(control, CFSTR("ui-disable"))) { - setAssessment(false); - MessageTrace trace("com.apple.security.assessment.state", "disable"); - trace.send("disable assessment outcomes"); - return true; - } else if (CFEqual(control, CFSTR("ui-status"))) { - CFBooleanRef &result = *(CFBooleanRef*)(arguments); - if (overrideAssessment()) - result = kCFBooleanFalse; - else - result = kCFBooleanTrue; - return true; - } else if (CFEqual(control, CFSTR("ui-enable-devid"))) { - CFTemp ctx("{%O=%s}", kSecAssessmentUpdateKeyLabel, "Developer ID"); - if (CFDictionaryRef result = gEngine().enable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx)) - CFRelease(result); - MessageTrace trace("com.apple.security.assessment.state", "enable-devid"); - trace.send("enable Developer ID approval"); - return true; - } else if (CFEqual(control, CFSTR("ui-disable-devid"))) { - CFTemp ctx("{%O=%s}", kSecAssessmentUpdateKeyLabel, "Developer ID"); - if (CFDictionaryRef result = gEngine().disable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx)) - CFRelease(result); - MessageTrace trace("com.apple.security.assessment.state", "disable-devid"); - trace.send("disable Developer ID approval"); - return true; - } else if (CFEqual(control, CFSTR("ui-get-devid"))) { - CFBooleanRef &result = *(CFBooleanRef*)(arguments); - if (gEngine().value("SELECT disabled FROM authority WHERE label = 'Developer ID';", true)) - result = kCFBooleanFalse; - else - result = kCFBooleanTrue; - return true; - } else if (CFEqual(control, CFSTR("ui-record-reject"))) { - // send this through syspolicyd for update validation - xpcEngineRecord(CFDictionaryRef(arguments)); - return true; - } else if (CFEqual(control, CFSTR("ui-record-reject-local"))) { - // perform the local operation (requires root) - gEngine().recordFailure(CFDictionaryRef(arguments)); - return true; - } else if (CFEqual(control, CFSTR("ui-recall-reject"))) { - // no special privileges required for this, so read directly - CFDictionaryRef &result = *(CFDictionaryRef*)(arguments); - CFRef infoData = cfLoadFile(lastRejectFile); - if (infoData) - result = makeCFDictionaryFrom(infoData); - else - result = NULL; - return true; - } else - MacOSError::throwMe(errSecCSInvalidAttributeValues); - - END_CSAPI_ERRORS1(false) -}