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