+
+#if SEC_OS_OSX
+/*
+ * Determine if the given task meets a specified requirement.
+ */
+OSStatus
+SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement)
+{
+ OSStatus status;
+ SecCodeRef code = NULL;
+ SecRequirementRef req = NULL;
+
+ CFMutableDictionaryRef codeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFDataRef auditData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)&task->token, sizeof(audit_token_t));
+ CFDictionarySetValue(codeDict, kSecGuestAttributeAudit, auditData);
+ status = SecCodeCopyGuestWithAttributes(NULL, codeDict, kSecCSDefaultFlags, &code);
+ CFReleaseNull(codeDict);
+ CFReleaseNull(auditData);
+
+ if (!status) {
+ status = SecRequirementCreateWithString(requirement,
+ kSecCSDefaultFlags, &req);
+ }
+ if (!status) {
+ status = SecCodeCheckValidity(code, kSecCSDefaultFlags, req);
+ }
+
+ CFReleaseNull(req);
+ CFReleaseNull(code);
+
+ return status;
+}
+#endif /* SEC_OS_OSX */
+
+Boolean SecTaskEntitlementsValidated(SecTaskRef task) {
+ // TODO: Cache the result
+ uint32_t csflags = 0;
+ const uint32_t mask = CS_VALID | CS_KILL | CS_ENTITLEMENTS_VALIDATED;
+ const uint32_t debug_mask = CS_DEBUGGED | CS_ENTITLEMENTS_VALIDATED;
+ int rc = csops_task(task, CS_OPS_STATUS, &csflags, sizeof(csflags));
+ // Allow debugged processes that were valid to continue being treated as valid
+ // We need this all the time (not just on internal) because third parties may need to debug their entitled process in xcode
+ return (rc != -1) && ((mask & csflags) == mask || (debug_mask & csflags) == debug_mask);
+}
+