]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/policydb.cpp
72018c3c91955d05d400910f43f85490e2abde76
[apple/libsecurity_codesigning.git] / lib / policydb.cpp
1 /*
2 * Copyright (c) 2011 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include "cs.h"
24 #include "policydb.h"
25 #include "policyengine.h"
26 #include <Security/CodeSigning.h>
27 #include <security_utilities/cfutilities.h>
28 #include <security_utilities/cfmunge.h>
29
30 namespace Security {
31 namespace CodeSigning {
32
33
34 using namespace SQLite;
35
36
37 //
38 // The one and only PolicyDatabase object.
39 // It auto-adapts to readonly vs. writable use.
40 //
41 ModuleNexus<PolicyDatabase> PolicyDatabase;
42
43
44 //
45 // Determine the database path
46 //
47 static const char *dbPath()
48 {
49 if (const char *s = getenv("SYSPOLICYDATABASE"))
50 return s;
51 return defaultDatabase;
52 }
53
54
55 //
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.
58 //
59 PolicyDatabase::PolicyDatabase(const char *path, int flags)
60 : SQLite::Database(path ? path : dbPath(), flags)
61 {
62 }
63
64 PolicyDatabase::~PolicyDatabase()
65 { /* virtual */ }
66
67
68 //
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.
71 //
72 bool PolicyDatabase::checkCache(CFURLRef path, AuthorityType type, CFMutableDictionaryRef result)
73 {
74 // we currently don't use the cache for anything but execution rules
75 if (type != kAuthorityExecute)
76 return false;
77
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;
81
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));
89
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];
98 bool valid = true;
99 if (SQLite3::int64 expires = cached[1])
100 valid = time(NULL) <= expires;
101 if (valid) {
102 SYSPOLICY_ASSESS_CACHE_HIT();
103 cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow);
104 PolicyEngine::addAuthority(result, label, auth, kCFBooleanTrue);
105 return true;
106 }
107 }
108 return false;
109 }
110
111
112 //
113 // Purge the object cache of all expired entries
114 //
115 void PolicyDatabase::purge(const char *table)
116 {
117 SQLite::Statement cleaner(*this,
118 "DELETE FROM ?1 WHERE expires < DATE_TIME('now');");
119 cleaner.bind(1) = table;
120 cleaner.execute();
121 }
122
123
124 //
125 // Check the override-enable master flag
126 //
127 bool overrideAssessment()
128 {
129 if (::access(visibleSecurityFlagFile, F_OK) == 0) {
130 return false;
131 } else if (errno == ENOENT) {
132 return true;
133 } else
134 UnixError::throwMe();
135 }
136
137
138 } // end namespace CodeSigning
139 } // end namespace Security