]> git.saurik.com Git - apple/securityd.git/blob - src/AuthorizationEngine.cpp
securityd-36489.tar.gz
[apple/securityd.git] / src / AuthorizationEngine.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, 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
24 #include "AuthorizationEngine.h"
25 #include <security_cdsa_utilities/AuthorizationWalkers.h>
26 #include <Security/AuthorizationPriv.h>
27 #include <Security/AuthorizationDB.h>
28
29
30 #include "authority.h"
31
32 #include <Security/AuthorizationTags.h>
33 #include <Security/AuthorizationTagsPriv.h>
34 #include <security_utilities/logging.h>
35 #include <security_utilities/cfutilities.h>
36 #include <security_utilities/debugging.h>
37 //#include "session.h"
38 #include "server.h"
39
40 #include <CoreFoundation/CFData.h>
41 #include <CoreFoundation/CFNumber.h>
42 #include <CoreFoundation/CFPropertyList.h>
43
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <float.h>
47
48 #include <bsm/audit_uevents.h>
49
50 namespace Authorization {
51
52
53 //
54 // Errors to be thrown
55 //
56 Error::Error(int err) : error(err)
57 {
58 }
59
60 const char *Error::what() const throw()
61 { return "Authorization error"; }
62
63 int Error::unixError() const throw()
64 { return error; } // @@@ eventually...
65
66 OSStatus Error::osStatus() const throw()
67 { return error; }
68
69 void Error::throwMe(int err) { throw Error(err); }
70
71 //
72 // Engine class
73 //
74 Engine::Engine(const char *configFile) : mAuthdb(configFile)
75 {
76 }
77
78 Engine::~Engine()
79 {
80 }
81
82
83 /*!
84 @function AuthorizationEngine::authorize
85
86 @@@.
87
88 @param inRights (input) List of rights being requested for authorization.
89 @param environment (optional/input) Environment containing information to be used during evaluation.
90 @param flags (input) Optional flags @@@ see AuthorizationCreate for a description.
91 @param inCredentials (input) Credentials already held by the caller.
92 @param outCredentials (output/optional) Credentials obtained, used or refreshed during this call to authorize the requested rights.
93 @param outRights (output/optional) Subset of inRights which were actually authorized.
94
95 @results Returns errAuthorizationSuccess if all rights requested are authorized, or if the kAuthorizationFlagPartialRights flag was specified. Might return other status values like errAuthorizationDenied, errAuthorizationCanceled or errAuthorizationInteractionNotAllowed
96 */
97 OSStatus
98 Engine::authorize(const AuthItemSet &inRights, const AuthItemSet &environment,
99 AuthorizationFlags flags, const CredentialSet *inCredentials, CredentialSet *outCredentials,
100 AuthItemSet &outRights, AuthorizationToken &auth)
101 {
102 CredentialSet credentials;
103 OSStatus status = errAuthorizationSuccess;
104
105 // Get current time of day.
106 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
107
108 // Update rules from database if needed
109 mAuthdb.sync(now);
110
111 // Check if a credential was passed into the environment and we were asked to extend the rights
112 if (flags & kAuthorizationFlagExtendRights)
113 {
114 string username, password;
115 bool shared = false;
116 for (AuthItemSet::iterator item = environment.begin(); item != environment.end(); item ++)
117 {
118 if (!strcmp((*item)->name(), kAuthorizationEnvironmentUsername))
119 username = (*item)->stringValue();
120 else if (!strcmp((*item)->name(), kAuthorizationEnvironmentPassword))
121 password = (*item)->stringValue();
122 else if (!strcmp((*item)->name(), kAuthorizationEnvironmentShared))
123 shared = true;
124 }
125
126 if (username.length())
127 {
128 // Let's create a credential from the passed in username and password.
129 Credential newCredential(username, password, shared);
130 // If it's valid insert it into the credentials list. Normally this is
131 // only done if it actually authorizes a requested right, but for this
132 // special case (environment) we do it even when no rights are being requested.
133 if (newCredential->isValid())
134 credentials.insert(newCredential);
135 }
136 }
137
138 // generate hints for every authorization
139 AuthItemSet environmentToClient = environment;
140
141 AuthItemSet::const_iterator end = inRights.end();
142 for (AuthItemSet::const_iterator it = inRights.begin(); it != end; ++it)
143 {
144 // Get the rule for each right we are trying to obtain.
145 const Rule &toplevelRule = mAuthdb.getRule(*it);
146 OSStatus result = toplevelRule->evaluate(*it, toplevelRule, environmentToClient, flags, now, inCredentials, credentials, auth);
147 secdebug("autheval", "evaluate rule %s for right %s returned %ld.", toplevelRule->name().c_str(), (*it)->name(), result);
148
149 {
150 string processName = "unknown";
151 if (SecCodeRef code = Server::process().currentGuest()) {
152 CFRef<CFURLRef> path;
153 if (!SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref()))
154 processName = cfString(path);
155 }
156 string authCreatorName = "unknown";
157 if (SecStaticCodeRef code = auth.creatorCode()) {
158 CFRef<CFURLRef> path;
159 if (!SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref()))
160 authCreatorName = cfString(path);
161 }
162
163 if (result == errAuthorizationSuccess) {
164 Syslog::info("Succeeded authorizing right %s by client %s for authorization created by %s.", (*it)->name(), processName.c_str(), authCreatorName.c_str());
165 CommonCriteria::AuditRecord auditrec(auth.creatorAuditToken());
166 auditrec.submit(AUE_ssauthorize, CommonCriteria::errNone, (*it)->name());
167 } else if (result == errAuthorizationDenied) {
168 Syslog::notice("Failed to authorize right %s by client %s for authorization created by %s.", (*it)->name(), processName.c_str(), authCreatorName.c_str());
169 }
170 }
171
172 if (result == errAuthorizationSuccess)
173 outRights.insert(*it);
174 else if (result == errAuthorizationDenied || result == errAuthorizationInteractionNotAllowed)
175 {
176 // add creator pid to authorization token
177 if (!(flags & kAuthorizationFlagPartialRights))
178 {
179 status = result;
180 break;
181 }
182 }
183 else if (result == errAuthorizationCanceled)
184 {
185 status = result;
186 break;
187 }
188 else
189 {
190 Syslog::error("Engine::authorize: Rule::evaluate returned %ld returning errAuthorizationInternal", result);
191 status = errAuthorizationInternal;
192 break;
193 }
194 }
195
196 if (outCredentials)
197 outCredentials->swap(credentials);
198
199 return status;
200 }
201
202 OSStatus
203 Engine::verifyModification(string inRightName, bool remove,
204 const CredentialSet *inCredentials, CredentialSet *outCredentials, AuthorizationToken &auth)
205 {
206 // Validate right
207
208 // meta rights are constructed as follows:
209 // we don't allow setting of wildcard rights, so you can only be more specific
210 // note that you should never restrict things with a wildcard right without disallowing
211 // changes to the entire domain. ie.
212 // system.privilege. -> never
213 // config.add.system.privilege. -> never
214 // config.modify.system.privilege. -> never
215 // config.delete.system.privilege. -> never
216 // For now we don't allow any configuration of configuration rules
217 // config.config. -> never
218
219 string rightnameToCheck;
220
221 // @@@ verify right name is is not NULL or zero length
222 if (inRightName.length() == 0)
223 return errAuthorizationDenied;
224
225 // @@@ make sure it isn't a wildcard right by checking trailing "."
226 if ( *(inRightName.rbegin()) == '.')
227 return errAuthorizationDenied;
228
229 // @@@ make sure it isn't a configure right by checking it doesn't start with config.
230 if (inRightName.find(kConfigRight, 0) != string::npos)
231 {
232 // special handling of meta right change:
233 // config.add. config.modify. config.remove. config.{}.
234 // check for config.<right> (which always starts with config.config.)
235 rightnameToCheck = string(kConfigRight) + inRightName;
236 }
237 else
238 {
239 // regular check of rights
240 bool existingRule = mAuthdb.existRule(inRightName);
241 if (!remove)
242 {
243 if (existingRule)
244 rightnameToCheck = string(kAuthorizationConfigRightModify) + inRightName;
245 else
246 rightnameToCheck = string(kAuthorizationConfigRightAdd) + inRightName;
247 }
248 else
249 {
250 if (existingRule)
251 rightnameToCheck = string(kAuthorizationConfigRightRemove) + inRightName;
252 else
253 {
254 secdebug("engine", "rule %s doesn't exist.", inRightName.c_str());
255 return errAuthorizationSuccess; // doesn't exist, done
256 }
257 }
258 }
259
260
261 AuthItemSet rights, environment, outRights;
262 rights.insert(AuthItemRef(rightnameToCheck.c_str()));
263 secdebug("engine", "authorizing %s for db modification.", rightnameToCheck.c_str());
264 return authorize(rights, environment, kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights, inCredentials, outCredentials, outRights, auth);
265 }
266
267 OSStatus
268 Engine::getRule(string &inRightName, CFDictionaryRef *outRuleDefinition)
269 {
270 // Get current time of day.
271 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
272
273 // Update rules from database if needed
274 mAuthdb.sync(now);
275
276 CFDictionaryRef definition = mAuthdb.getRuleDefinition(inRightName);
277 if (definition)
278 {
279 if (outRuleDefinition)
280 *outRuleDefinition = definition;
281 else
282 CFRelease(definition);
283
284 return errAuthorizationSuccess;
285 }
286
287 return errAuthorizationDenied;
288 }
289
290 OSStatus
291 Engine::setRule(const char *inRightName, CFDictionaryRef inRuleDefinition, const CredentialSet *inCredentials, CredentialSet *outCredentials, AuthorizationToken &auth)
292 {
293 // Validate rule by constructing it from the passed dictionary
294 if (!mAuthdb.validateRule(inRightName, inRuleDefinition))
295 return errAuthorizationDenied; // @@@ separate error for this?
296
297 OSStatus result = verifyModification(inRightName, false /*setting, not removing*/, inCredentials, outCredentials, auth);
298 if (result != errAuthorizationSuccess)
299 return result;
300
301 // set the rule for the right and save the database
302 mAuthdb.setRule(inRightName, inRuleDefinition);
303
304 return errAuthorizationSuccess;
305 }
306
307 OSStatus
308 Engine::removeRule(const char *inRightName, const CredentialSet *inCredentials, CredentialSet *outCredentials, AuthorizationToken &auth)
309 {
310 // Get current time of day.
311 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
312
313 // Update rules from database if needed
314 mAuthdb.sync(now);
315
316 OSStatus result = verifyModification(inRightName, true /*removing*/, inCredentials, outCredentials, auth);
317 if (result != errAuthorizationSuccess)
318 return result;
319
320 // set the rule for the right and save the database
321 mAuthdb.removeRule(inRightName);
322
323 return errAuthorizationSuccess;
324 }
325
326 } // end namespace Authorization