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