2 * Copyright (c) 2011 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include "policyengine.h"
26 #include <Security/CodeSigning.h>
27 #include <security_utilities/cfutilities.h>
28 #include <security_utilities/cfmunge.h>
31 namespace CodeSigning
{
34 using namespace SQLite
;
38 // The one and only PolicyDatabase object.
39 // It auto-adapts to readonly vs. writable use.
41 ModuleNexus
<PolicyDatabase
> PolicyDatabase
;
45 // Determine the database path
47 static const char *dbPath()
49 if (const char *s
= getenv("SYSPOLICYDATABASE"))
51 return defaultDatabase
;
56 // Open the database (creating it if necessary and possible).
57 // Note that this isn't creating the schema; we do that on first write.
59 PolicyDatabase::PolicyDatabase(const char *path
, int flags
)
60 : SQLite::Database(path
? path
: dbPath(), flags
)
64 PolicyDatabase::~PolicyDatabase()
69 // Quick-check the cache for a match.
70 // Return true on a cache hit, false on failure to confirm a hit for any reason.
72 bool PolicyDatabase::checkCache(CFURLRef path
, AuthorityType type
, CFMutableDictionaryRef result
)
74 // we currently don't use the cache for anything but execution rules
75 if (type
!= kAuthorityExecute
)
78 SecCSFlags validationFlags
= kSecCSDefaultFlags
;
79 if (overrideAssessment()) // we'll force the verdict to 'pass' at the end, so don't sweat validating code
80 validationFlags
= kSecCSBasicValidateOnly
;
82 CFRef
<SecStaticCodeRef
> code
;
83 MacOSError::check(SecStaticCodeCreateWithPath(path
, kSecCSDefaultFlags
, &code
.aref()));
84 if (SecStaticCodeCheckValidity(code
, validationFlags
, NULL
) != noErr
)
85 return false; // quick pass - any error is a cache miss
86 CFRef
<CFDictionaryRef
> info
;
87 MacOSError::check(SecCodeCopySigningInformation(code
, kSecCSDefaultFlags
, &info
.aref()));
88 CFDataRef cdHash
= CFDataRef(CFDictionaryGetValue(info
, kSecCodeInfoUnique
));
90 // check the cache table for a fast match
91 SQLite::Statement
cached(*this, "SELECT allow, expires, label, authority FROM object WHERE type = ?1 and hash = ?2;");
92 cached
.bind(1).integer(type
);
93 cached
.bind(2) = cdHash
;
94 if (cached
.nextRow()) {
95 bool allow
= int(cached
[0]);
96 const char *label
= cached
[2];
97 SQLite::int64 auth
= cached
[3];
99 if (SQLite3::int64 expires
= cached
[1])
100 valid
= time(NULL
) <= expires
;
102 SYSPOLICY_ASSESS_CACHE_HIT();
103 cfadd(result
, "{%O=%B}", kSecAssessmentAssessmentVerdict
, allow
);
104 PolicyEngine::addAuthority(result
, label
, auth
, kCFBooleanTrue
);
113 // Purge the object cache of all expired entries
115 void PolicyDatabase::purge(const char *table
)
117 SQLite::Statement
cleaner(*this,
118 "DELETE FROM ?1 WHERE expires < DATE_TIME('now');");
119 cleaner
.bind(1) = table
;
125 // Check the override-enable master flag
127 bool overrideAssessment()
129 if (::access(visibleSecurityFlagFile
, F_OK
) == 0) {
131 } else if (errno
== ENOENT
) {
134 UnixError::throwMe();
138 } // end namespace CodeSigning
139 } // end namespace Security