#include "cs.h"
#include "policydb.h"
#include "policyengine.h"
#include <Security/CodeSigning.h>
#include <security_utilities/cfutilities.h>
#include <security_utilities/cfmunge.h>
namespace Security {
namespace CodeSigning {
using namespace SQLite;
ModuleNexus<PolicyDatabase> PolicyDatabase;
static const char *dbPath()
{
if (const char *s = getenv("SYSPOLICYDATABASE"))
return s;
return defaultDatabase;
}
PolicyDatabase::PolicyDatabase(const char *path, int flags)
: SQLite::Database(path ? path : dbPath(), flags)
{
}
PolicyDatabase::~PolicyDatabase()
{ }
bool PolicyDatabase::checkCache(CFURLRef path, AuthorityType type, CFMutableDictionaryRef result)
{
if (type != kAuthorityExecute)
return false;
SecCSFlags validationFlags = kSecCSDefaultFlags;
if (overrideAssessment()) validationFlags = kSecCSBasicValidateOnly;
CFRef<SecStaticCodeRef> code;
MacOSError::check(SecStaticCodeCreateWithPath(path, kSecCSDefaultFlags, &code.aref()));
if (SecStaticCodeCheckValidity(code, validationFlags, NULL) != noErr)
return false; CFRef<CFDictionaryRef> info;
MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref()));
CFDataRef cdHash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique));
SQLite::Statement cached(*this, "SELECT allow, expires, label, authority FROM object WHERE type = ?1 and hash = ?2;");
cached.bind(1).integer(type);
cached.bind(2) = cdHash;
if (cached.nextRow()) {
bool allow = int(cached[0]);
const char *label = cached[2];
SQLite::int64 auth = cached[3];
bool valid = true;
if (SQLite3::int64 expires = cached[1])
valid = time(NULL) <= expires;
if (valid) {
SYSPOLICY_ASSESS_CACHE_HIT();
cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow);
PolicyEngine::addAuthority(result, label, auth, kCFBooleanTrue);
return true;
}
}
return false;
}
void PolicyDatabase::purge(const char *table)
{
SQLite::Statement cleaner(*this,
"DELETE FROM ?1 WHERE expires < DATE_TIME('now');");
cleaner.bind(1) = table;
cleaner.execute();
}
bool overrideAssessment()
{
if (::access(visibleSecurityFlagFile, F_OK) == 0) {
return false;
} else if (errno == ENOENT) {
return true;
} else
UnixError::throwMe();
}
} }