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