]> git.saurik.com Git - apple/security.git/blob - SecurityServer/Authorization/AuthorizationEngine.cpp
Security-163.tar.gz
[apple/security.git] / SecurityServer / Authorization / AuthorizationEngine.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 * AuthorizationEngine.cpp
21 * Authorization
22 *
23 * Created by Michael Brouwer on Thu Oct 12 2000.
24 * Copyright (c) 2000 Apple Computer Inc. All rights reserved.
25 *
26 */
27 #include "AuthorizationEngine.h"
28 #include <Security/AuthorizationWalkers.h>
29 #include "AuthorizationPriv.h"
30 #include "AuthorizationDB.h"
31
32
33 #include "authority.h"
34
35 #include <Security/AuthorizationTags.h>
36 #include <Security/logging.h>
37 #include <Security/cfutilities.h>
38 #include <Security/debugging.h>
39 #include "session.h"
40 #include "server.h"
41
42 #include <CoreFoundation/CFData.h>
43 #include <CoreFoundation/CFNumber.h>
44 #include <CoreFoundation/CFPropertyList.h>
45
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <float.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 CSSM_RETURN Error::cssmError() 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 CodeSigning::OSXCode *processCode = Server::connection().process.clientCode();
151 string processName = processCode ? processCode->canonicalPath() : "unknown";
152 CodeSigning::OSXCode *authCreatorCode = auth.creatorCode();
153 string authCreatorName = authCreatorCode ? authCreatorCode->canonicalPath() : "unknown";
154
155 if (result == errAuthorizationSuccess)
156 Syslog::info("Succeeded authorizing right %s by process %s for authorization created by %s.", (*it)->name(), processName.c_str(), authCreatorName.c_str());
157 else if (result == errAuthorizationDenied)
158 Syslog::notice("Failed to authorize right %s by process %s for authorization created by %s.", (*it)->name(), processName.c_str(), authCreatorName.c_str());
159 }
160
161 if (result == errAuthorizationSuccess)
162 outRights.insert(*it);
163 else if (result == errAuthorizationDenied || result == errAuthorizationInteractionNotAllowed)
164 {
165 // add creator pid to authorization token
166 if (!(flags & kAuthorizationFlagPartialRights))
167 {
168 status = result;
169 break;
170 }
171 }
172 else if (result == errAuthorizationCanceled)
173 {
174 status = result;
175 break;
176 }
177 else
178 {
179 Syslog::error("Engine::authorize: Rule::evaluate returned %ld returning errAuthorizationInternal", result);
180 status = errAuthorizationInternal;
181 break;
182 }
183 }
184
185 if (outCredentials)
186 outCredentials->swap(credentials);
187
188 return status;
189 }
190
191 OSStatus
192 Engine::verifyModification(string inRightName, bool remove,
193 const CredentialSet *inCredentials, CredentialSet *outCredentials, AuthorizationToken &auth)
194 {
195 // Validate right
196
197 // meta rights are constructed as follows:
198 // we don't allow setting of wildcard rights, so you can only be more specific
199 // note that you should never restrict things with a wildcard right without disallowing
200 // changes to the entire domain. ie.
201 // system.privilege. -> never
202 // config.add.system.privilege. -> never
203 // config.modify.system.privilege. -> never
204 // config.delete.system.privilege. -> never
205 // For now we don't allow any configuration of configuration rules
206 // config.config. -> never
207
208 string rightnameToCheck;
209
210 // @@@ verify right name is is not NULL or zero length
211 if (inRightName.length() == 0)
212 return errAuthorizationDenied;
213
214 // @@@ make sure it isn't a wildcard right by checking trailing "."
215 if ( *(inRightName.rbegin()) == '.')
216 return errAuthorizationDenied;
217
218 // @@@ make sure it isn't a configure right by checking it doesn't start with config.
219 if (inRightName.find(kConfigRight, 0) != string::npos)
220 {
221 // special handling of meta right change:
222 // config.add. config.modify. config.remove. config.{}.
223 // check for config.<right> (which always starts with config.config.)
224 rightnameToCheck = string(kConfigRight) + inRightName;
225 }
226 else
227 {
228 // regular check of rights
229 bool existingRule = mAuthdb.existRule(inRightName);
230 if (!remove)
231 {
232 if (existingRule)
233 rightnameToCheck = string(kAuthorizationConfigRightModify) + inRightName;
234 else
235 rightnameToCheck = string(kAuthorizationConfigRightAdd) + inRightName;
236 }
237 else
238 {
239 if (existingRule)
240 rightnameToCheck = string(kAuthorizationConfigRightRemove) + inRightName;
241 else
242 {
243 secdebug("engine", "rule %s doesn't exist.", inRightName.c_str());
244 return errAuthorizationSuccess; // doesn't exist, done
245 }
246 }
247 }
248
249
250 AuthItemSet rights, environment, outRights;
251 rights.insert(AuthItemRef(rightnameToCheck.c_str()));
252 secdebug("engine", "authorizing %s for db modification.", rightnameToCheck.c_str());
253 return authorize(rights, environment, kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights, inCredentials, outCredentials, outRights, auth);
254 }
255
256 OSStatus
257 Engine::getRule(string &inRightName, CFDictionaryRef *outRuleDefinition)
258 {
259 // Get current time of day.
260 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
261
262 // Update rules from database if needed
263 mAuthdb.sync(now);
264
265 CFDictionaryRef definition = mAuthdb.getRuleDefinition(inRightName);
266 if (definition)
267 {
268 if (outRuleDefinition)
269 *outRuleDefinition = definition;
270 else
271 CFRelease(definition);
272
273 return errAuthorizationSuccess;
274 }
275
276 return errAuthorizationDenied;
277 }
278
279 OSStatus
280 Engine::setRule(const char *inRightName, CFDictionaryRef inRuleDefinition, const CredentialSet *inCredentials, CredentialSet *outCredentials, AuthorizationToken &auth)
281 {
282 // Get current time of day.
283 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
284
285 // Update rules from database if needed
286 mAuthdb.sync(now);
287
288 // Validate rule by constructing it from the passed dictionary
289 if (!mAuthdb.validateRule(inRightName, inRuleDefinition))
290 return errAuthorizationDenied; // @@@ separate error for this?
291
292 OSStatus result = verifyModification(inRightName, false /*setting, not removing*/, inCredentials, outCredentials, auth);
293 if (result != errAuthorizationSuccess)
294 return result;
295
296 // set the rule for the right and save the database
297 mAuthdb.setRule(inRightName, inRuleDefinition);
298
299 return errAuthorizationSuccess;
300 }
301
302 OSStatus
303 Engine::removeRule(const char *inRightName, const CredentialSet *inCredentials, CredentialSet *outCredentials, AuthorizationToken &auth)
304 {
305 // Get current time of day.
306 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
307
308 // Update rules from database if needed
309 mAuthdb.sync(now);
310
311 OSStatus result = verifyModification(inRightName, true /*removing*/, inCredentials, outCredentials, auth);
312 if (result != errAuthorizationSuccess)
313 return result;
314
315 // set the rule for the right and save the database
316 mAuthdb.removeRule(inRightName);
317
318 return errAuthorizationSuccess;
319 }
320
321 } // end namespace Authorization