2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 * AuthorizationEngine.cpp
23 * Created by Michael Brouwer on Thu Oct 12 2000.
24 * Copyright (c) 2000 Apple Computer Inc. All rights reserved.
27 #include "AuthorizationEngine.h"
28 #include <Security/AuthorizationWalkers.h>
29 #include "AuthorizationPriv.h"
30 #include "AuthorizationDB.h"
33 #include "authority.h"
35 #include <Security/AuthorizationTags.h>
36 #include <Security/logging.h>
37 #include <Security/cfutilities.h>
38 #include <Security/debugging.h>
42 #include <CoreFoundation/CFData.h>
43 #include <CoreFoundation/CFNumber.h>
44 #include <CoreFoundation/CFPropertyList.h>
50 namespace Authorization
{
53 // Errors to be thrown
55 Error::Error(int err
) : error(err
)
59 const char *Error::what() const throw()
60 { return "Authorization error"; }
62 CSSM_RETURN
Error::cssmError() const throw()
63 { return error
; } // @@@ eventually...
65 OSStatus
Error::osStatus() const throw()
68 void Error::throwMe(int err
) { throw Error(err
); }
73 Engine::Engine(const char *configFile
) : mAuthdb(configFile
)
83 @function AuthorizationEngine::authorize
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.
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
97 Engine::authorize(const AuthItemSet
&inRights
, const AuthItemSet
&environment
,
98 AuthorizationFlags flags
, const CredentialSet
*inCredentials
, CredentialSet
*outCredentials
,
99 AuthItemSet
&outRights
, AuthorizationToken
&auth
)
101 CredentialSet credentials
;
102 OSStatus status
= errAuthorizationSuccess
;
104 // Get current time of day.
105 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
107 // Update rules from database if needed
110 // Check if a credential was passed into the environment and we were asked to extend the rights
111 if (flags
& kAuthorizationFlagExtendRights
)
113 string username
, password
;
115 for (AuthItemSet::iterator item
= environment
.begin(); item
!= environment
.end(); item
++)
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
))
125 if (username
.length())
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
);
137 // generate hints for every authorization
138 AuthItemSet environmentToClient
= environment
;
140 AuthItemSet::const_iterator end
= inRights
.end();
141 for (AuthItemSet::const_iterator it
= inRights
.begin(); it
!= end
; ++it
)
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
);
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";
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());
160 if (result
== errAuthorizationSuccess
)
161 outRights
.insert(*it
);
162 else if (result
== errAuthorizationDenied
|| result
== errAuthorizationInteractionNotAllowed
)
164 // add creator pid to authorization token
165 if (!(flags
& kAuthorizationFlagPartialRights
))
171 else if (result
== errAuthorizationCanceled
)
178 Syslog::error("Engine::authorize: Rule::evaluate returned %ld returning errAuthorizationInternal", result
);
179 status
= errAuthorizationInternal
;
185 outCredentials
->swap(credentials
);
191 Engine::verifyModification(string inRightName
, bool remove
,
192 const CredentialSet
*inCredentials
, CredentialSet
*outCredentials
, AuthorizationToken
&auth
)
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
207 string rightnameToCheck
;
209 // @@@ verify right name is is not NULL or zero length
210 if (inRightName
.length() == 0)
211 return errAuthorizationDenied
;
213 // @@@ make sure it isn't a wildcard right by checking trailing "."
214 if ( *(inRightName
.rbegin()) == '.')
215 return errAuthorizationDenied
;
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
)
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
;
227 // regular check of rights
228 bool existingRule
= mAuthdb
.existRule(inRightName
);
232 rightnameToCheck
= string(kAuthorizationConfigRightModify
) + inRightName
;
234 rightnameToCheck
= string(kAuthorizationConfigRightAdd
) + inRightName
;
239 rightnameToCheck
= string(kAuthorizationConfigRightRemove
) + inRightName
;
242 secdebug("engine", "rule %s doesn't exist.", inRightName
.c_str());
243 return errAuthorizationSuccess
; // doesn't exist, done
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
);
256 Engine::getRule(string
&inRightName
, CFDictionaryRef
*outRuleDefinition
)
258 // Get current time of day.
259 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
261 // Update rules from database if needed
264 CFDictionaryRef definition
= mAuthdb
.getRuleDefinition(inRightName
);
267 if (outRuleDefinition
)
268 *outRuleDefinition
= definition
;
270 CFRelease(definition
);
272 return errAuthorizationSuccess
;
275 return errAuthorizationDenied
;
279 Engine::setRule(const char *inRightName
, CFDictionaryRef inRuleDefinition
, const CredentialSet
*inCredentials
, CredentialSet
*outCredentials
, AuthorizationToken
&auth
)
281 // Get current time of day.
282 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
284 // Update rules from database if needed
287 // Validate rule by constructing it from the passed dictionary
288 if (!mAuthdb
.validateRule(inRightName
, inRuleDefinition
))
289 return errAuthorizationDenied
; // @@@ separate error for this?
291 OSStatus result
= verifyModification(inRightName
, false /*setting, not removing*/, inCredentials
, outCredentials
, auth
);
292 if (result
!= errAuthorizationSuccess
)
295 // set the rule for the right and save the database
296 mAuthdb
.setRule(inRightName
, inRuleDefinition
);
298 return errAuthorizationSuccess
;
302 Engine::removeRule(const char *inRightName
, const CredentialSet
*inCredentials
, CredentialSet
*outCredentials
, AuthorizationToken
&auth
)
304 // Get current time of day.
305 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
307 // Update rules from database if needed
310 OSStatus result
= verifyModification(inRightName
, true /*removing*/, inCredentials
, outCredentials
, auth
);
311 if (result
!= errAuthorizationSuccess
)
314 // set the rule for the right and save the database
315 mAuthdb
.removeRule(inRightName
);
317 return errAuthorizationSuccess
;
320 } // end namespace Authorization