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