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