2  *  Copyright (c) 2003-2004,2008-2009 Apple Inc. All Rights Reserved. 
   4  *  @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  *  @APPLE_LICENSE_HEADER_END@ 
  23  *  AuthorizationRule.cpp 
  28 #include "AuthorizationRule.h" 
  29 #include <Security/AuthorizationTags.h> 
  30 #include <Security/AuthorizationTagsPriv.h> 
  31 #include <Security/AuthorizationDB.h> 
  32 #include <Security/AuthorizationPriv.h> 
  33 #include <security_utilities/logging.h> 
  34 #include <bsm/audit_uevents.h> 
  35 #include "ccaudit_extensions.h" 
  36 #include "authority.h" 
  39 #include "agentquery.h" 
  40 #include "AuthorizationMechEval.h" 
  46 #include <membership.h> 
  49 #include <membershipPriv.h> 
  52 using namespace CommonCriteria::Securityd
; 
  57 namespace Authorization 
{ 
  59 CFStringRef 
RuleImpl::kUserGroupID 
= CFSTR(kAuthorizationRuleParameterGroup
); 
  60 CFStringRef 
RuleImpl::kTimeoutID 
= CFSTR(kAuthorizationRuleParameterCredentialTimeout
); 
  61 CFStringRef 
RuleImpl::kSharedID 
= CFSTR(kAuthorizationRuleParameterCredentialShared
); 
  62 CFStringRef 
RuleImpl::kAllowRootID 
= CFSTR(kAuthorizationRuleParameterAllowRoot
); 
  63 CFStringRef 
RuleImpl::kMechanismsID 
= CFSTR(kAuthorizationRuleParameterMechanisms
); 
  64 CFStringRef 
RuleImpl::kSessionOwnerID 
= CFSTR(kAuthorizationRuleParameterCredentialSessionOwner
); 
  65 CFStringRef 
RuleImpl::kKofNID 
= CFSTR(kAuthorizationRuleParameterKofN
); 
  66 CFStringRef 
RuleImpl::kPromptID 
= CFSTR(kAuthorizationRuleParameterDefaultPrompt
); 
  67 CFStringRef 
RuleImpl::kButtonID 
= CFSTR(kAuthorizationRuleParameterDefaultButton
); 
  68 CFStringRef 
RuleImpl::kTriesID 
= CFSTR("tries"); // XXX/cs move to AuthorizationTagsPriv.h 
  69 CFStringRef 
RuleImpl::kExtractPasswordID 
= CFSTR(kAuthorizationRuleParameterExtractPassword
); 
  71 CFStringRef 
RuleImpl::kRuleClassID 
= CFSTR(kAuthorizationRuleClass
); 
  72 CFStringRef 
RuleImpl::kRuleAllowID 
= CFSTR(kAuthorizationRuleClassAllow
); 
  73 CFStringRef 
RuleImpl::kRuleDenyID 
= CFSTR(kAuthorizationRuleClassDeny
); 
  74 CFStringRef 
RuleImpl::kRuleUserID 
= CFSTR(kAuthorizationRuleClassUser
); 
  75 CFStringRef 
RuleImpl::kRuleDelegateID 
= CFSTR(kAuthorizationRightRule
); 
  76 CFStringRef 
RuleImpl::kRuleMechanismsID 
= CFSTR(kAuthorizationRuleClassMechanisms
); 
  77 CFStringRef 
RuleImpl::kRuleAuthenticateUserID 
= CFSTR(kAuthorizationRuleParameterAuthenticateUser
); 
  81 RuleImpl::Attribute::getString(CFDictionaryRef config
, CFStringRef key
, bool required 
= false, const char *defaultValue 
= "") 
  83         CFTypeRef value 
= CFDictionaryGetValue(config
, key
); 
  84         if (value 
&& (CFGetTypeID(value
) == CFStringGetTypeID())) 
  86                 CFStringRef stringValue 
= reinterpret_cast<CFStringRef
>(value
); 
  88                 const char *ptr 
= CFStringGetCStringPtr(stringValue
, kCFStringEncodingUTF8
); 
  91                         if (CFStringGetCString(stringValue
, buffer
, sizeof(buffer
), kCFStringEncodingUTF8
)) 
  95                                 Syslog::alert("Could not convert CFString to C string"); 
  96                                 MacOSError::throwMe(errAuthorizationInternal
); 
 104                         return string(defaultValue
); 
 107                         Syslog::alert("Failed to get rule string"); 
 108                         MacOSError::throwMe(errAuthorizationInternal
); 
 113 RuleImpl::Attribute::getDouble(CFDictionaryRef config
, CFStringRef key
, bool required 
= false, double defaultValue 
= 0.0) 
 115         double doubleValue 
= 0; 
 117         CFTypeRef value 
= CFDictionaryGetValue(config
, key
); 
 118         if (value 
&& (CFGetTypeID(value
) == CFNumberGetTypeID())) 
 120                 CFNumberGetValue(reinterpret_cast<CFNumberRef
>(value
), kCFNumberDoubleType
, &doubleValue
); 
 127                         Syslog::alert("Failed to get rule double value"); 
 128                         MacOSError::throwMe(errAuthorizationInternal
); 
 135 RuleImpl::Attribute::getBool(CFDictionaryRef config
, CFStringRef key
, bool required 
= false, bool defaultValue 
= false) 
 137         bool boolValue 
= false; 
 138         CFTypeRef value 
= CFDictionaryGetValue(config
, key
); 
 140         if (value 
&& (CFGetTypeID(value
) == CFBooleanGetTypeID())) 
 142                 boolValue 
= CFBooleanGetValue(reinterpret_cast<CFBooleanRef
>(value
)); 
 149                         Syslog::alert("Failed to get rule bool value"); 
 150                         MacOSError::throwMe(errAuthorizationInternal
); 
 157 RuleImpl::Attribute::getVector(CFDictionaryRef config
, CFStringRef key
, bool required 
= false) 
 159         vector
<string
> valueArray
; 
 161         CFTypeRef value 
= CFDictionaryGetValue(config
, key
); 
 162         if (value 
&& (CFGetTypeID(value
) == CFArrayGetTypeID())) 
 164                 CFArrayRef evalArray 
= reinterpret_cast<CFArrayRef
>(value
); 
 166         CFIndex numItems 
= CFArrayGetCount(evalArray
); 
 167                 for (CFIndex index
=0; index 
< numItems
; index
++) 
 169                         CFTypeRef arrayValue 
= CFArrayGetValueAtIndex(evalArray
, index
); 
 170                         if (arrayValue 
&& (CFGetTypeID(arrayValue
) == CFStringGetTypeID())) 
 172                                 CFStringRef stringValue 
= reinterpret_cast<CFStringRef
>(arrayValue
); 
 174                                 const char *ptr 
= CFStringGetCStringPtr(stringValue
, kCFStringEncodingUTF8
); 
 177                                         if (CFStringGetCString(stringValue
, buffer
, sizeof(buffer
), kCFStringEncodingUTF8
)) 
 181                                                 Syslog::alert("Failed to convert CFString to C string for item %u in array", index
); 
 182                                                 MacOSError::throwMe(errAuthorizationInternal
); 
 185                                 valueArray
.push_back(string(ptr
)); 
 192                         Syslog::alert("Value for key either not present or not a CFArray"); 
 193                         MacOSError::throwMe(errAuthorizationInternal
); 
 200 bool RuleImpl::Attribute::getLocalizedText(CFDictionaryRef config
, map
<string
,string
> &localizedPrompts
, CFStringRef dictKey
, const char *descriptionKey
) 
 202         CFIndex numberOfPrompts 
= 0; 
 203         CFDictionaryRef promptsDict
; 
 204         if (CFDictionaryContainsKey(config
, dictKey
)) 
 206                 promptsDict 
= reinterpret_cast<CFDictionaryRef
>(CFDictionaryGetValue(config
, dictKey
)); 
 207                 if (promptsDict 
&& (CFGetTypeID(promptsDict
) == CFDictionaryGetTypeID())) 
 208                         numberOfPrompts 
= CFDictionaryGetCount(promptsDict
); 
 210         if (numberOfPrompts 
== 0) 
 213         const void *keys
[numberOfPrompts
+1]; 
 214         const void *values
[numberOfPrompts
+1]; 
 215         CFDictionaryGetKeysAndValues(promptsDict
, &keys
[0], &values
[0]); 
 217         while (numberOfPrompts
-- > 0) 
 219                 CFStringRef keyRef 
= reinterpret_cast<CFStringRef
>(keys
[numberOfPrompts
]); 
 220                 CFStringRef valueRef 
= reinterpret_cast<CFStringRef
>(values
[numberOfPrompts
]); 
 221                 if (!keyRef 
|| (CFGetTypeID(keyRef
) != CFStringGetTypeID())) { 
 224                 if (!valueRef 
|| (CFGetTypeID(valueRef
) != CFStringGetTypeID())) { 
 227                 string key 
= cfString(keyRef
); 
 228                 string value 
= cfString(valueRef
); 
 229                 localizedPrompts
[descriptionKey 
+ key
] = value
; 
 237 RuleImpl::RuleImpl() : 
 238 mType(kUser
), mGroupName("admin"), mMaxCredentialAge(300.0), mShared(true), mAllowRoot(false), mSessionOwner(false), mTries(0), mAuthenticateUser(true), mExtractPassword(false) 
 240         // XXX/cs read default descriptions from somewhere 
 241         // @@@ Default rule is shared admin group with 5 minute timeout 
 244 // return rule built from rule definition; throw if invalid. 
 245 RuleImpl::RuleImpl(const string 
&inRightName
, CFDictionaryRef cfRight
, CFDictionaryRef cfRules
) : mRightName(inRightName
), mExtractPassword(false) 
 247         // @@@ make sure cfRight is non mutable and never used that way 
 249         if (CFGetTypeID(cfRight
) != CFDictionaryGetTypeID()) 
 251                 Syslog::alert("Invalid rights set"); 
 252                 MacOSError::throwMe(errAuthorizationInternal
); 
 257         string classTag 
= Attribute::getString(cfRight
, kRuleClassID
, false, ""); 
 259         if (classTag
.length()) 
 261                 if (classTag 
== kAuthorizationRuleClassAllow
) 
 263                         secdebug("authrule", "%s : rule allow", inRightName
.c_str()); 
 266                 else if (classTag 
== kAuthorizationRuleClassDeny
) 
 268                         secdebug("authrule", "%s : rule deny", inRightName
.c_str()); 
 271                 else if (classTag 
== kAuthorizationRuleClassUser
) 
 274                         mGroupName 
= Attribute::getString(cfRight
, kUserGroupID
); 
 275                         // grab other user-in-group attributes 
 276                         mMaxCredentialAge 
= Attribute::getDouble(cfRight
, kTimeoutID
, false, DBL_MAX
); 
 277                         mShared 
= Attribute::getBool(cfRight
, kSharedID
); 
 278                         mAllowRoot 
= Attribute::getBool(cfRight
, kAllowRootID
); 
 279                         mSessionOwner 
= Attribute::getBool(cfRight
, kSessionOwnerID
); 
 280                         // authorization tags can have eval now too 
 281                         mEvalDef 
= Attribute::getVector(cfRight
, kMechanismsID
); 
 282                         if (mEvalDef
.size() == 0 && cfRules 
/*only rights default see appserver-admin*/) 
 284                                 CFDictionaryRef cfRuleDef 
= reinterpret_cast<CFDictionaryRef
>(CFDictionaryGetValue(cfRules
, CFSTR("authenticate"))); 
 285                                 if (cfRuleDef 
&& CFGetTypeID(cfRuleDef
) == CFDictionaryGetTypeID()) 
 286                                         mEvalDef 
= Attribute::getVector(cfRuleDef
, kMechanismsID
); 
 288                         mTries 
= int(Attribute::getDouble(cfRight
, kTriesID
, false, double(kMaximumAuthorizationTries
))); 
 289                         mAuthenticateUser 
= Attribute::getBool(cfRight
, kRuleAuthenticateUserID
, false, true); 
 290                         mExtractPassword 
= Attribute::getBool(cfRight
, kExtractPasswordID
, false, false); 
 292                         secdebug("authrule", "%s : rule user in group \"%s\" timeout %g%s%s", 
 294                                 mGroupName
.c_str(), mMaxCredentialAge
, mShared 
? " shared" : "", 
 295                                 mAllowRoot 
? " allow-root" : ""); 
 298                 else if (classTag 
== kAuthorizationRuleClassMechanisms
) 
 300                         secdebug("authrule", "%s : rule evaluate mechanisms", inRightName
.c_str()); 
 301                         mType 
= kEvaluateMechanisms
; 
 302                         // mechanisms to evaluate 
 303                         mEvalDef 
= Attribute::getVector(cfRight
, kMechanismsID
, true); 
 304                         mTries 
= int(Attribute::getDouble(cfRight
, kTriesID
, false, 0.0)); // "forever" 
 305                         mShared 
= Attribute::getBool(cfRight
, kSharedID
, false, true); 
 306                         mExtractPassword 
= Attribute::getBool(cfRight
, kExtractPasswordID
, false, false); 
 308                 else if (classTag 
== kAuthorizationRightRule
) 
 310                         assert(cfRules
); // rules can't delegate to other rules 
 311                         secdebug("authrule", "%s : rule delegate rule", inRightName
.c_str()); 
 312                         mType 
= kRuleDelegation
; 
 315                         string ruleDefString 
= Attribute::getString(cfRight
, kRuleDelegateID
, false, ""); 
 316                         if (ruleDefString
.length()) 
 318                                 CFStringRef ruleDefRef 
= makeCFString(ruleDefString
); 
 319                                 CFDictionaryRef cfRuleDef 
= reinterpret_cast<CFDictionaryRef
>(CFDictionaryGetValue(cfRules
, ruleDefRef
)); 
 321                                         CFRelease(ruleDefRef
); 
 322                                 if (!cfRuleDef 
|| CFGetTypeID(cfRuleDef
) != CFDictionaryGetTypeID()) 
 324                                         Syslog::alert("'%s' does not name a built-in rule", ruleDefString
.c_str()); 
 325                                         MacOSError::throwMe(errAuthorizationInternal
); 
 327                                 mRuleDef
.push_back(Rule(ruleDefString
, cfRuleDef
, cfRules
)); 
 331                                 vector
<string
> ruleDef 
= Attribute::getVector(cfRight
, kRuleDelegateID
, true); 
 332                                 for (vector
<string
>::const_iterator it 
= ruleDef
.begin(); it 
!= ruleDef
.end(); it
++) 
 334                                         CFStringRef ruleNameRef 
= makeCFString(*it
); 
 335                                         CFDictionaryRef cfRuleDef 
= reinterpret_cast<CFDictionaryRef
>(CFDictionaryGetValue(cfRules
, ruleNameRef
)); 
 337                                                 CFRelease(ruleNameRef
); 
 338                                         if (!cfRuleDef 
|| (CFGetTypeID(cfRuleDef
) != CFDictionaryGetTypeID())) 
 340                                                 Syslog::alert("Invalid rule '%s'in rule set", it
->c_str()); 
 341                                                 MacOSError::throwMe(errAuthorizationInternal
); 
 343                                         mRuleDef
.push_back(Rule(*it
, cfRuleDef
, cfRules
)); 
 347                         mKofN 
= int(Attribute::getDouble(cfRight
, kKofNID
, false, 0.0)); 
 354                         secdebug("authrule", "%s : rule class '%s' unknown.", inRightName
.c_str(), classTag
.c_str()); 
 355                         Syslog::alert("%s : rule class '%s' unknown", inRightName
.c_str(), classTag
.c_str()); 
 356                         MacOSError::throwMe(errAuthorizationInternal
); 
 361                 // no class tag means, this is the abbreviated specification from the API 
 362                 // it _must_ have a definition for "rule" which will be used as a delegate 
 363                 // it may have a comment (not extracted here) 
 364                 // it may have a default prompt, or a whole dictionary of languages (not extracted here) 
 365                 mType 
= kRuleDelegation
; 
 366                 string ruleName 
= Attribute::getString(cfRight
, kRuleDelegateID
, true); 
 367                 secdebug("authrule", "%s : rule delegate rule (1): %s", inRightName
.c_str(), ruleName
.c_str()); 
 368                 CFStringRef ruleNameRef 
= makeCFString(ruleName
); 
 369                 CFDictionaryRef cfRuleDef 
= reinterpret_cast<CFDictionaryRef
>(CFDictionaryGetValue(cfRules
, ruleNameRef
)); 
 371                         CFRelease(ruleNameRef
); 
 372                 if (!cfRuleDef 
|| CFGetTypeID(cfRuleDef
) != CFDictionaryGetTypeID()) 
 374                         Syslog::alert("Rule '%s' for right '%s' does not exist or is not properly formed", ruleName
.c_str(), inRightName
.c_str()); 
 375                         MacOSError::throwMe(errAuthorizationInternal
); 
 377                 mRuleDef
.push_back(Rule(ruleName
, cfRuleDef
, cfRules
)); 
 380         Attribute::getLocalizedText(cfRight
, mLocalizedPrompts
, kPromptID
, kAuthorizationRuleParameterDescription
); 
 381         Attribute::getLocalizedText(cfRight
, mLocalizedButtons
, kButtonID
, kAuthorizationRuleParameterButton
); 
 391 RuleImpl::setAgentHints(const AuthItemRef 
&inRight
, const Rule 
&inTopLevelRule
, AuthItemSet 
&environmentToClient
, AuthorizationToken 
&auth
) const 
 393         string 
authorizeString(inRight
->name()); 
 394         environmentToClient
.erase(AuthItemRef(AGENT_HINT_AUTHORIZE_RIGHT
));  
 395         environmentToClient
.insert(AuthItemRef(AGENT_HINT_AUTHORIZE_RIGHT
, AuthValueOverlay(authorizeString
))); 
 397         pid_t creatorPid 
= auth
.creatorPid(); 
 398         environmentToClient
.erase(AuthItemRef(AGENT_HINT_CREATOR_PID
));  
 399         environmentToClient
.insert(AuthItemRef(AGENT_HINT_CREATOR_PID
, AuthValueOverlay(sizeof(pid_t
), &creatorPid
))); 
 401         audit_token_t creatorAuditToken 
= auth
.creatorAuditToken().auditToken(); 
 402         environmentToClient
.erase(AuthItemRef(AGENT_HINT_CREATOR_AUDIT_TOKEN
)); 
 403         environmentToClient
.insert(AuthItemRef(AGENT_HINT_CREATOR_AUDIT_TOKEN
, AuthValueOverlay(sizeof(audit_token_t
), &creatorAuditToken
))); 
 405         Process 
&thisProcess 
= Server::process(); 
 407         if (SecStaticCodeRef clientCode 
= auth
.creatorCode()) 
 408                 bundlePath 
= codePath(clientCode
); 
 409         AuthItemSet processHints 
= SecurityAgent::Client::clientHints( 
 410                 SecurityAgent::bundle
, bundlePath
, thisProcess
.pid(), thisProcess
.uid()); 
 411         environmentToClient
.erase(AuthItemRef(AGENT_HINT_CLIENT_TYPE
)); 
 412         environmentToClient
.erase(AuthItemRef(AGENT_HINT_CLIENT_PATH
)); 
 413         environmentToClient
.erase(AuthItemRef(AGENT_HINT_CLIENT_PID
)); 
 414         environmentToClient
.erase(AuthItemRef(AGENT_HINT_CLIENT_UID
)); 
 415         environmentToClient
.insert(processHints
.begin(), processHints
.end()); 
 417         map
<string
,string
> defaultPrompts 
= inTopLevelRule
->localizedPrompts(); 
 418         map
<string
,string
> defaultButtons 
= inTopLevelRule
->localizedButtons(); 
 420         if (defaultPrompts
.empty()) 
 421                 defaultPrompts 
= localizedPrompts(); 
 422         if (defaultButtons
.empty()) 
 423                 defaultButtons 
= localizedButtons(); 
 425         if (!defaultPrompts
.empty()) 
 427                 map
<string
,string
>::const_iterator it
; 
 428                 for (it 
= defaultPrompts
.begin(); it 
!= defaultPrompts
.end(); it
++) 
 430                         const string 
&key 
= it
->first
; 
 431                         const string 
&value 
= it
->second
; 
 432                         environmentToClient
.insert(AuthItemRef(key
.c_str(), AuthValueOverlay(value
))); 
 435         if (!defaultButtons
.empty()) 
 437                 map
<string
,string
>::const_iterator it
; 
 438                 for (it 
= defaultButtons
.begin(); it 
!= defaultButtons
.end(); it
++) 
 440                         const string 
&key 
= it
->first
; 
 441                         const string 
&value 
= it
->second
; 
 442                         environmentToClient
.insert(AuthItemRef(key
.c_str(), AuthValueOverlay(value
))); 
 446         // add rulename as a hint 
 447         string ruleName 
= name(); 
 448     environmentToClient
.erase(AuthItemRef(AGENT_HINT_AUTHORIZE_RULE
)); 
 449         environmentToClient
.insert(AuthItemRef(AGENT_HINT_AUTHORIZE_RULE
, AuthValueOverlay(ruleName
))); 
 452 // If a different evaluation for getting a credential is prescribed, 
 453 // we'll run that and validate the credentials from there. 
 454 // we fall back on a default configuration from the authenticate rule 
 456 RuleImpl::evaluateAuthentication(const AuthItemRef 
&inRight
, const Rule 
&inRule
,AuthItemSet 
&environmentToClient
, AuthorizationFlags flags
, CFAbsoluteTime now
, const CredentialSet 
*inCredentials
, CredentialSet 
&credentials
, AuthorizationToken 
&auth
, SecurityAgent::Reason 
&reason
, bool savePassword
) const 
 458         OSStatus status 
= errAuthorizationDenied
; 
 460         Credential hintCredential
; 
 461         if (errAuthorizationSuccess 
== evaluateSessionOwner(inRight
, inRule
, environmentToClient
, now
, auth
, hintCredential
, reason
)) { 
 462                 if (hintCredential
->username().length()) 
 463                         environmentToClient
.insert(AuthItemRef(AGENT_HINT_SUGGESTED_USER
, AuthValueOverlay(hintCredential
->username()))); 
 464                 if (hintCredential
->realname().length()) 
 465                         environmentToClient
.insert(AuthItemRef(AGENT_HINT_SUGGESTED_USER_LONG
, AuthValueOverlay(hintCredential
->realname()))); 
 468         if ((mType 
== kUser
) && (mGroupName
.length())) 
 469                 environmentToClient
.insert(AuthItemRef(AGENT_HINT_REQUIRE_USER_IN_GROUP
, AuthValueOverlay(mGroupName
))); 
 472         reason 
= SecurityAgent::noReason
; 
 474         Process 
&cltProc 
= Server::process(); 
 475         // Authorization preserves creator's UID in setuid processes 
 476     // (which is nice, but cltUid ends up being unused except by the debug 
 477     // message -- AgentMechanismEvaluator ignores it) 
 478         uid_t cltUid 
= (cltProc
.uid() != 0) ? cltProc
.uid() : auth
.creatorUid(); 
 479         secdebug("AuthEvalMech", "Mechanism invocation by process %d (UID %d)", cltProc
.pid(), cltUid
); 
 481     // For auditing within AuthorizationMechEval, pass the right name.   
 482     size_t rightNameSize 
= inRight
->name() ? strlen(inRight
->name()) : 0; 
 483     AuthorizationString rightName 
= inRight
->name() ? inRight
->name() : ""; 
 484     // @@@  AuthValueRef's ctor ought to take a const void * 
 485     AuthValueRef 
rightValue(rightNameSize
, const_cast<char *>(rightName
)); 
 486     AuthValueVector authValueVector
; 
 487     authValueVector
.push_back(rightValue
); 
 489     RightAuthenticationLogger 
rightAuthLogger(auth
.creatorAuditToken(), AUE_ssauthint
); 
 490     rightAuthLogger
.setRight(rightName
); 
 492         // Just succeed for a continuously active session owner. 
 493         if (auth
.session().originatorUid() == auth
.creatorUid() && auth
.session().attributes() & AU_SESSION_FLAG_HAS_AUTHENTICATED
) { 
 494                 secdebug("AuthEvalMech", "We are an active session owner."); 
 495                 aslmsg m 
= asl_new(ASL_TYPE_MSG
); 
 496                 asl_set(m
, "com.apple.message.domain", "com.apple.securityd.UserActivity"); 
 497                 asl_set(m
, "com.apple.message.signature", "userIsActive"); 
 498                 asl_set(m
, "com.apple.message.signature2", rightName
); 
 499                 asl_set(m
, "com.apple.message.result", "failure"); 
 500                 asl_log(NULL
, m
, ASL_LEVEL_NOTICE
, "We are an active session owner."); 
 502 //              Credential rightCredential(rightName, auth.creatorUid(), mShared); 
 503 //              credentials.erase(rightCredential); credentials.insert(rightCredential); 
 504 //              return errAuthorizationSuccess; 
 507                 secdebug("AuthEvalMech", "We are not an active session owner."); 
 508                 aslmsg m 
= asl_new(ASL_TYPE_MSG
); 
 509                 asl_set(m
, "com.apple.message.domain", "com.apple.securityd.UserActivity"); 
 510                 asl_set(m
, "com.apple.message.signature", "userIsNotActive"); 
 511                 asl_set(m
, "com.apple.message.signature2", rightName
); 
 512                 asl_set(m
, "com.apple.message.result", "success"); 
 513                 asl_log(NULL
, m
, ASL_LEVEL_NOTICE
, "We are not an active session owner."); 
 517         AgentMechanismEvaluator 
eval(cltUid
, auth
.session(), mEvalDef
); 
 519         for (tries 
= 0; tries 
< mTries
; tries
++) 
 521                 AuthItemRef 
retryHint(AGENT_HINT_RETRY_REASON
, AuthValueOverlay(sizeof(reason
), &reason
)); 
 522                 environmentToClient
.erase(retryHint
); environmentToClient
.insert(retryHint
); // replace 
 523                 AuthItemRef 
triesHint(AGENT_HINT_TRIES
, AuthValueOverlay(sizeof(tries
), &tries
)); 
 524                 environmentToClient
.erase(triesHint
); environmentToClient
.insert(triesHint
); // replace 
 526             status 
= eval
.run(authValueVector
, environmentToClient
, auth
); 
 528             if ((status 
== errAuthorizationSuccess
) || 
 529                 (status 
== errAuthorizationCanceled
)) // @@@ can only pass back sideband through context 
 531                 secdebug("AuthEvalMech", "storing new context for authorization"); 
 532                 auth
.setInfoSet(eval
.context(), savePassword
); 
 535             // successfully ran mechanisms to obtain credential 
 536             if (status 
== errAuthorizationSuccess
) 
 538                 // deny is the default 
 539                 status 
= errAuthorizationDenied
; 
 541                 CredentialSet newCredentials 
= makeCredentials(auth
); 
 542                 // clear context after extracting credentials 
 543                 auth
.scrubInfoSet(savePassword
); 
 545                 for (CredentialSet::const_iterator it 
= newCredentials
.begin(); it 
!= newCredentials
.end(); ++it
) 
 547                     const Credential
& newCredential 
= *it
; 
 549                     // @@@ we log the uid a process was running under when it created the authref, which is misleading in the case of loginwindow 
 550                     if (newCredential
->isValid()) { 
 551                         Syslog::info("UID %u authenticated as user %s (UID %u) for right '%s'", auth
.creatorUid(), newCredential
->username().c_str(), newCredential
->uid(), rightName
); 
 552                         rightAuthLogger
.logSuccess(auth
.creatorUid(), newCredential
->uid(), newCredential
->username().c_str()); 
 554                         // we can't be sure that the user actually exists so inhibit logging of uid 
 555                         Syslog::error("UID %u failed to authenticate as user '%s' for right '%s'", auth
.creatorUid(), newCredential
->username().c_str(), rightName
); 
 556                         rightAuthLogger
.logFailure(auth
.creatorUid(), newCredential
->username().c_str()); 
 559                     if (!newCredential
->isValid()) 
 561                         reason 
= SecurityAgent::invalidPassphrase
; 
 565                     // verify that this credential authorizes right 
 566                     status 
= evaluateUserCredentialForRight(auth
, inRight
, inRule
, environmentToClient
, now
, newCredential
, true, reason
); 
 568                     if (status 
== errAuthorizationSuccess
) 
 570                         if (auth
.operatesAsLeastPrivileged()) { 
 571                             Credential 
rightCredential(rightName
, newCredential
->uid(), mShared
); 
 572                             credentials
.erase(rightCredential
); credentials
.insert(rightCredential
); 
 574                                 credentials
.insert(Credential(rightName
, newCredential
->uid(), false)); 
 576                             // whack an equivalent credential, so it gets updated to a later achieved credential which must have been more stringent 
 577                             credentials
.erase(newCredential
); credentials
.insert(newCredential
); 
 578                            // just got a new credential - if it's shared also add a non-shared one that to stick in the authorizationref local cache 
 580                                credentials
.insert(Credential(newCredential
->uid(), newCredential
->username(), newCredential
->realname(), newCredential
->groupname(), false)); 
 583                         // use valid credential to set context info 
 584                         // XXX/cs keeping this for now, such that the uid is passed back 
 585                         auth
.setCredentialInfo(newCredential
, savePassword
); 
 586                         secdebug("SSevalMech", "added valid credential for user %s", newCredential
->username().c_str()); 
 587                                                 // set the sessionHasAuthenticated 
 588                                                 if (newCredential
->uid() == auth
.session().originatorUid()) { 
 589                                                         secdebug("AuthEvalMech", "We authenticated as the session owner.\n"); 
 590                                                         SessionAttributeBits flags 
= auth
.session().attributes(); 
 591                                                         flags 
|= AU_SESSION_FLAG_HAS_AUTHENTICATED
; 
 592                                                         auth
.session().setAttributes(flags
); 
 595                         status 
= errAuthorizationSuccess
; 
 600                         if (status 
== errAuthorizationSuccess
) 
 604                         if ((status 
== errAuthorizationCanceled
) || (status 
== errAuthorizationInternal
)) 
 606                                 auth
.scrubInfoSet(false); 
 609                         else // last mechanism is now authentication - fail 
 610                                 if (status 
== errAuthorizationDenied
) 
 611                                         reason 
= SecurityAgent::invalidPassphrase
; 
 614         // If we fell out of the loop because of too many tries, notify user 
 617                 reason 
= SecurityAgent::tooManyTries
; 
 618                 AuthItemRef 
retryHint (AGENT_HINT_RETRY_REASON
, AuthValueOverlay(sizeof(reason
), &reason
)); 
 619                 environmentToClient
.erase(retryHint
); environmentToClient
.insert(retryHint
); // replace 
 620                 AuthItemRef 
triesHint(AGENT_HINT_TRIES
, AuthValueOverlay(sizeof(tries
), &tries
)); 
 621                 environmentToClient
.erase(triesHint
); environmentToClient
.insert(triesHint
); // replace 
 622             eval
.run(AuthValueVector(), environmentToClient
, auth
); 
 623                 // XXX/cs is this still necessary? 
 624                 auth
.scrubInfoSet(false); 
 626         rightAuthLogger
.logFailure(NULL
, CommonCriteria::errTooManyTries
); 
 632 // create externally verified credentials on the basis of  
 633 // mechanism-provided information 
 635 RuleImpl::makeCredentials(const AuthorizationToken 
&auth
) const 
 637         // fetch context and construct a credential to be tested 
 638         const AuthItemSet 
&context 
= const_cast<AuthorizationToken 
&>(auth
).infoSet(); 
 639         CredentialSet newCredentials
; 
 642                 AuthItemSet::const_iterator found 
= find_if(context
.begin(), context
.end(), FindAuthItemByRightName(kAuthorizationEnvironmentUsername
) ); 
 643                 if (found 
== context
.end()) 
 645                 string username 
= (**found
).stringValue(); 
 646                 secdebug("AuthEvalMech", "found username"); 
 648                 const uid_t 
*uid 
= NULL
; 
 649                 found 
= find_if(context
.begin(), context
.end(), FindAuthItemByRightName("uid") ); 
 650                 if (found 
!= context
.end()) 
 652                         uid 
= static_cast<const uid_t 
*>((**found
).value().data
); 
 653                         secdebug("AuthEvalMech", "found uid"); 
 656                 if (username
.length() && uid
) 
 658                         // credential is valid because mechanism says so 
 659                         newCredentials
.insert(Credential(*uid
, username
, "", "", mShared
)); 
 663         return newCredentials
; 
 666 // evaluate whether a good credential of the current session owner would authorize a right 
 668 RuleImpl::evaluateSessionOwner(const AuthItemRef 
&inRight
, const Rule 
&inRule
, const AuthItemSet 
&environment
, const CFAbsoluteTime now
, const AuthorizationToken 
&auth
, Credential 
&credential
, SecurityAgent::Reason 
&reason
) const 
 670         // username hint is taken from the user who created the authorization, unless it's clearly ineligible 
 671         // @@@ we have no access to current requester uid here and the process uid is only taken when the authorization is created 
 672         // meaning that a process like loginwindow that drops privs later is screwed. 
 674         Credential sessionCredential
; 
 675         uid_t uid 
= auth
.session().originatorUid(); 
 676         Server::active().longTermActivity(); 
 677         struct passwd 
*pw 
= getpwuid(uid
); 
 679                 // avoid hinting a locked account 
 680                 if ( (pw
->pw_passwd 
== NULL
) || 
 681                         strcmp(pw
->pw_passwd
, "*") ) { 
 682                         // Check if username will authorize the request and set username to 
 683                         // be used as a hint to the user if so 
 684                         secdebug("AuthEvalMech", "preflight credential from current user, result follows:"); 
 685                         sessionCredential 
= Credential(pw
->pw_uid
, pw
->pw_name
, pw
->pw_gecos
, "", mShared
/*ignored*/); 
 689         OSStatus status 
= evaluateUserCredentialForRight(auth
, inRight
, inRule
, environment
, now
, sessionCredential
, true, reason
); 
 690         if (errAuthorizationSuccess 
== status
) 
 691                 credential 
= sessionCredential
; 
 698 RuleImpl::evaluateCredentialForRight(const AuthorizationToken 
&auth
, const AuthItemRef 
&inRight
, const Rule 
&inRule
, const AuthItemSet 
&environment
, CFAbsoluteTime now
, const Credential 
&credential
, bool ignoreShared
, SecurityAgent::Reason 
&reason
) const 
 700         if (auth
.operatesAsLeastPrivileged()) { 
 701                 if (credential
->isRight() && credential
->isValid() && (inRight
->name() == credential
->rightname())) 
 702                         return errAuthorizationSuccess
; 
 705             // @@@  no proper SA::Reason 
 706             reason 
= SecurityAgent::unknownReason
; 
 707                         return errAuthorizationDenied
; 
 710                 return evaluateUserCredentialForRight(auth
, inRight
, inRule
, environment
, now
, credential
, false, reason
); 
 713 // Return errAuthorizationSuccess if this rule allows access based on the specified credential, 
 714 // return errAuthorizationDenied otherwise. 
 716 RuleImpl::evaluateUserCredentialForRight(const AuthorizationToken 
&auth
, const AuthItemRef 
&inRight
, const Rule 
&inRule
, const AuthItemSet 
&environment
, CFAbsoluteTime now
, const Credential 
&credential
, bool ignoreShared
, SecurityAgent::Reason 
&reason
) const 
 718         assert(mType 
== kUser
); 
 720     // Ideally we'd set the AGENT_HINT_RETRY_REASON hint in this method, but 
 721     // evaluateAuthentication() overwrites it before  
 722     // AgentMechanismEvaluator::run().  That's what led to passing "reason" 
 723     // everywhere, from RuleImpl::evaluate() on down.   
 725         // Get the username from the credential 
 726         const char *user 
= credential
->username().c_str(); 
 728         // If the credential is not valid or its age is more than the allowed maximum age 
 729         // for a credential, deny. 
 730         if (!credential
->isValid()) 
 732         // @@@  it could be the username, not password, was invalid 
 733         reason 
= SecurityAgent::invalidPassphrase
; 
 734                 secdebug("autheval", "credential for user %s is invalid, denying right %s", user
, inRight
->name()); 
 735                 return errAuthorizationDenied
; 
 738         if (now 
- credential
->creationTime() > mMaxCredentialAge
) 
 740         // @@@  no proper SA::Reason 
 741         reason 
= SecurityAgent::unknownReason
; 
 742                 secdebug("autheval", "credential for user %s has expired, denying right %s", user
, inRight
->name()); 
 743                 return errAuthorizationDenied
; 
 746         if (!ignoreShared 
&& !mShared 
&& credential
->isShared()) 
 748         // @@@  no proper SA::Reason 
 749         reason 
= SecurityAgent::unknownReason
; 
 750                 secdebug("autheval", "shared credential for user %s cannot be used, denying right %s", user
, inRight
->name()); 
 751                 return errAuthorizationDenied
; 
 754         // A root (uid == 0) user can do anything 
 755         if (credential
->uid() == 0) 
 757                 secdebug("autheval", "user %s has uid 0, granting right %s", user
, inRight
->name()); 
 758                 return errAuthorizationSuccess
; 
 763                 Session 
&session 
= auth
.session(); 
 764                 uid_t console_user 
= session
.originatorUid(); 
 766                 if (credential
->uid() == console_user
) 
 768                         secdebug("autheval", "user %s is session-owner(uid: %d), granting right %s", user
, console_user
, inRight
->name()); 
 769                         return errAuthorizationSuccess
; 
 771                 // set "reason" in this case?  not that a proper SA::Reason exists 
 775                 // @@@  no proper SA::Reason 
 776                 reason 
= SecurityAgent::unknownReason
; 
 777                 secdebug("autheval", "session-owner check failed."); 
 780         if (mGroupName
.length()) 
 782                 const char *groupname 
= mGroupName
.c_str(); 
 783                 Server::active().longTermActivity(); 
 786                         return errAuthorizationDenied
; 
 790                         uuid_t group_uuid
, user_uuid
; 
 793             // @@@  it'd be nice to have SA::Reason codes for the failures 
 794             // associated with the pre-check-membership mbr_*() functions,  
 795             // but userNotInGroup will do 
 796                         if (mbr_group_name_to_uuid(groupname
, group_uuid
)) 
 799                         if (mbr_uid_to_uuid(credential
->uid(), user_uuid
)) 
 802                                 if (NULL 
== (pwd 
= getpwnam(user
))) 
 804                                 if (mbr_uid_to_uuid(pwd
->pw_uid
, user_uuid
)) 
 808                         if (mbr_check_membership(user_uuid
, group_uuid
, &is_member
)) 
 813                 credential
->setGroupname(mGroupName
); 
 814                                 secdebug("autheval", "user %s is a member of group %s, granting right %s", 
 815                                         user
, groupname
, inRight
->name()); 
 816                                 return errAuthorizationSuccess
; 
 822         reason 
= SecurityAgent::userNotInGroup
; 
 823                 secdebug("autheval", "user %s is not a member of group %s, denying right %s", 
 824                         user
, groupname
, inRight
->name()); 
 826     else if (mSessionOwner
) // rule asks only if user is the session owner 
 828         reason 
= SecurityAgent::unacceptableUser
; 
 831         return errAuthorizationDenied
; 
 837 RuleImpl::evaluateUser(const AuthItemRef 
&inRight
, const Rule 
&inRule
, AuthItemSet 
&environmentToClient
, AuthorizationFlags flags
, CFAbsoluteTime now
, const CredentialSet 
*inCredentials
, CredentialSet 
&credentials
, AuthorizationToken 
&auth
, SecurityAgent::Reason 
&reason
, bool savePassword
) const 
 839     // If we got here, this is a kUser type rule, let's start looking for a 
 840         // credential that is satisfactory 
 842         // Zeroth -- Here is an extra special saucy ugly hack to allow authorizations 
 843         // created by a proccess running as root to automatically get a right. 
 844         if (mAllowRoot 
&& auth
.creatorUid() == 0) 
 846         SECURITYD_AUTH_USER_ALLOWROOT(&auth
); 
 848                 secdebug("autheval", "creator of authorization has uid == 0 granting right %s", 
 850                 return errAuthorizationSuccess
; 
 853         // if we're not supposed to authenticate evaluate the session-owner against the group 
 854         if (!mAuthenticateUser
) 
 856                 Credential hintCredential
; 
 857                 OSStatus status 
= evaluateSessionOwner(inRight
, inRule
, environmentToClient
, now
, auth
, hintCredential
, reason
); 
 861             SECURITYD_AUTH_USER_ALLOWSESSIONOWNER(&auth
); 
 862                         return errAuthorizationSuccess
; 
 865                 return errAuthorizationDenied
; 
 868         // First -- go though the credentials we either already used or obtained during this authorize operation. 
 869         for (CredentialSet::const_iterator it 
= credentials
.begin(); it 
!= credentials
.end(); ++it
) 
 871                 // Passed-in user credentials are allowed for least-privileged mode 
 872                 if (auth
.operatesAsLeastPrivileged() && !(*it
)->isRight() && (*it
)->isValid())  
 874                         OSStatus status 
= evaluateUserCredentialForRight(auth
, inRight
, inRule
, environmentToClient
, now
, *it
, false, reason
); 
 875                         if (errAuthorizationSuccess 
== status
) { 
 876                                 Credential 
rightCredential(inRight
->name(), (*it
)->uid(), mShared
); 
 877                                 credentials
.erase(rightCredential
); credentials
.insert(rightCredential
); 
 879                                         credentials
.insert(Credential(inRight
->name(), (*it
)->uid(), false)); 
 884                 // if this is least privileged, this will function differently: match credential to requested right 
 885                 OSStatus status 
= evaluateCredentialForRight(auth
, inRight
, inRule
, environmentToClient
, now
, *it
, false, reason
); 
 887                 if (status 
!= errAuthorizationDenied
) { 
 888                         // add credential to authinfo 
 889                         auth
.setCredentialInfo(*it
, savePassword
); 
 895         // Second -- go though the credentials passed in to this authorize operation by the state management layer. 
 898                 for (CredentialSet::const_iterator it 
= inCredentials
->begin(); it 
!= inCredentials
->end(); ++it
) 
 900                         // if this is least privileged, this will function differently: match credential to requested right 
 901                         OSStatus status 
= evaluateCredentialForRight(auth
, inRight
, inRule
, environmentToClient
, now
, *it
, false, reason
); 
 903                         if (status 
== errAuthorizationSuccess
) 
 905                                 // Add the credential we used to the output set. 
 906                                 // whack an equivalent credential, so it gets updated to a later achieved credential which must have been more stringent 
 907                                 credentials
.erase(*it
); credentials
.insert(*it
); 
 908                                 // add credential to authinfo 
 909                                 auth
.setCredentialInfo(*it
, savePassword
); 
 913                         else if (status 
!= errAuthorizationDenied
) 
 918         // Finally -- We didn't find the credential in our passed in credential lists.  Obtain a new credential if our flags let us do so. 
 919         if (!(flags 
& kAuthorizationFlagExtendRights
)) 
 920                 return errAuthorizationDenied
; 
 922         // authorizations that timeout immediately cannot be preauthorized 
 923         if ((flags 
& kAuthorizationFlagPreAuthorize
) &&  
 924                 (mMaxCredentialAge 
== 0.0)) 
 926                 inRight
->setFlags(inRight
->flags() | kAuthorizationFlagCanNotPreAuthorize
); 
 927                 return errAuthorizationSuccess
; 
 930         if (!(flags 
& kAuthorizationFlagInteractionAllowed
)) 
 931                 return errAuthorizationInteractionNotAllowed
; 
 933         setAgentHints(inRight
, inRule
, environmentToClient
, auth
); 
 935         return evaluateAuthentication(inRight
, inRule
, environmentToClient
, flags
, now
, inCredentials
, credentials
, auth
, reason
, savePassword
); 
 939 RuleImpl::evaluateMechanismOnly(const AuthItemRef 
&inRight
, const Rule 
&inRule
, AuthItemSet 
&environmentToClient
, AuthorizationToken 
&auth
, CredentialSet 
&outCredentials
, bool savePassword
) const 
 944         Process 
&cltProc 
= Server::process(); 
 945         // Authorization preserves creator's UID in setuid processes 
 946         uid_t cltUid 
= (cltProc
.uid() != 0) ? cltProc
.uid() : auth
.creatorUid(); 
 947         secdebug("AuthEvalMech", "Mechanism invocation by process %d (UID %d)", cltProc
.pid(), cltUid
); 
 950                 AgentMechanismEvaluator 
eval(cltUid
, auth
.session(), mEvalDef
); 
 951         // For auditing within AuthorizationMechEval, pass the right name.   
 952         size_t rightNameSize 
= inRight
->name() ? strlen(inRight
->name()) : 0; 
 953         AuthorizationString rightName 
= inRight
->name() ? inRight
->name() : ""; 
 954         // @@@  AuthValueRef's ctor ought to take a const void * 
 955         AuthValueRef 
rightValue(rightNameSize
, const_cast<char *>(rightName
)); 
 956         AuthValueVector authValueVector
; 
 957         authValueVector
.push_back(rightValue
); 
 961                         setAgentHints(inRight
, inRule
, environmentToClient
, auth
); 
 962                         AuthItemRef 
triesHint(AGENT_HINT_TRIES
, AuthValueOverlay(sizeof(tries
), &tries
)); 
 963                         environmentToClient
.erase(triesHint
); environmentToClient
.insert(triesHint
); // replace 
 965             status 
= eval
.run(authValueVector
, environmentToClient
, auth
); 
 966                         if ((status 
== errAuthorizationSuccess
) || 
 967                                 (status 
== errAuthorizationCanceled
)) // @@@ can only pass back sideband through context 
 969                                 secdebug("AuthEvalMech", "storing new context for authorization"); 
 970                                 auth
.setInfoSet(eval
.context(), savePassword
); 
 971                                 if (status 
== errAuthorizationSuccess
) 
 973                     // (try to) attach the authorizing UID to the least-priv cred 
 974                                         if (auth
.operatesAsLeastPrivileged()) 
 976                         RightAuthenticationLogger 
logger(auth
.creatorAuditToken(), AUE_ssauthint
); 
 977                         logger
.setRight(rightName
); 
 979                         AuthItem 
*uidItem 
= eval
.context().find(AGENT_CONTEXT_UID
); 
 983                             memcpy(&authorizedUid
, uidItem
->value().data
, sizeof(authorizedUid
)); 
 984                             secdebug("AuthEvalMech", "generating least-privilege cred for '%s' authorized by UID %u", inRight
->name(), authorizedUid
); 
 985                             outCredentials
.insert(Credential(rightName
, authorizedUid
, mShared
)); 
 986                             logger
.logLeastPrivilege(authorizedUid
, true); 
 988                         else    // cltUid is better than nothing 
 990                             secdebug("AuthEvalMech", "generating least-privilege cred for '%s' with process- or auth-UID %u", inRight
->name(), cltUid
); 
 991                             outCredentials
.insert(Credential(rightName
, cltUid
, mShared
)); 
 992                             logger
.logLeastPrivilege(cltUid
, false); 
 996                                                 if (0 == strcmp(rightName
, "system.login.console") && NULL 
== eval
.context().find(AGENT_CONTEXT_AUTO_LOGIN
)) { 
 997                                                         secdebug("AuthEvalMech", "We logged in as the session owner.\n"); 
 998                                                         SessionAttributeBits flags 
= auth
.session().attributes(); 
 999                                                         flags 
|= AU_SESSION_FLAG_HAS_AUTHENTICATED
; 
1000                                                         auth
.session().setAttributes(flags
);                                                     
1002                                                 CredentialSet newCredentials 
= makeCredentials(auth
); 
1003                                                 outCredentials
.insert(newCredentials
.begin(), newCredentials
.end()); 
1010                 while ((status 
== errAuthorizationDenied
) // only if we have an expected failure we continue 
1011                                         && ((mTries 
== 0)                               // mTries == 0 means we try forever 
1012                                         || ((mTries 
> 0)                        // mTries > 0 means we try up to mTries times 
1013                                         && (tries 
< mTries
)))); 
1016         // HACK kill all hosts to free pages for low memory systems 
1017     // (XXX/gh  there should be a #define for this right) 
1018         if (name() == "system.login.done") 
1020         // one case where we don't want to mark the agents as "busy" 
1021                 QueryInvokeMechanism 
query(securityAgent
, auth
.session()); 
1022                 query
.terminateAgent(); 
1023                 QueryInvokeMechanism 
query2(privilegedAuthHost
, auth
.session()); 
1024                 query2
.terminateAgent(); 
1031 RuleImpl::evaluateRules(const AuthItemRef 
&inRight
, const Rule 
&inRule
, AuthItemSet 
&environmentToClient
, AuthorizationFlags flags
, CFAbsoluteTime now
, const CredentialSet 
*inCredentials
, CredentialSet 
&credentials
, AuthorizationToken 
&auth
, SecurityAgent::Reason 
&reason
, bool savePassword
) const 
1033         // line up the rules to try 
1034         if (!mRuleDef
.size()) 
1035                 return errAuthorizationSuccess
; 
1038         OSStatus status 
= errAuthorizationSuccess
; 
1039         vector
<Rule
>::const_iterator it
; 
1041         for (it 
= mRuleDef
.begin();it 
!= mRuleDef
.end(); it
++) 
1044                 if ((mType 
== kKofN
) && (count 
== mKofN
)) 
1045                         return errAuthorizationSuccess
; 
1047                 // get a rule and try it 
1048                 status 
= (*it
)->evaluate(inRight
, inRule
, environmentToClient
, flags
, now
, inCredentials
, credentials
, auth
, reason
, savePassword
); 
1050                 // if status is cancel/internal error abort 
1051                 if ((status 
== errAuthorizationCanceled
) || (status 
== errAuthorizationInternal
)) 
1054                 if (status 
!= errAuthorizationSuccess
) 
1056                         // continue if we're only looking for k of n 
1066         if ((mType 
== kKofN
) && (status 
== errAuthorizationSuccess
) && (count 
< mKofN
)) 
1067                 status 
= errAuthorizationDenied
; 
1069         return status
; // return the last failure 
1074 RuleImpl::evaluate(const AuthItemRef 
&inRight
, const Rule 
&inRule
, AuthItemSet 
&environmentToClient
, AuthorizationFlags flags
, CFAbsoluteTime now
, const CredentialSet 
*inCredentials
, CredentialSet 
&credentials
, AuthorizationToken 
&auth
, SecurityAgent::Reason 
&reason
, bool savePassword
) const 
1079         SECURITYD_AUTH_ALLOW(&auth
, (char *)name().c_str()); 
1080                 return errAuthorizationSuccess
; 
1082         SECURITYD_AUTH_DENY(&auth
, (char *)name().c_str()); 
1083                 return errAuthorizationDenied
; 
1085         SECURITYD_AUTH_USER(&auth
, (char *)name().c_str()); 
1086                 return evaluateUser(inRight
, inRule
, environmentToClient
, flags
, now
, inCredentials
, credentials
, auth
, reason
, savePassword
); 
1087         case kRuleDelegation
: 
1088         SECURITYD_AUTH_RULES(&auth
, (char *)name().c_str()); 
1089                 return evaluateRules(inRight
, inRule
, environmentToClient
, flags
, now
, inCredentials
, credentials
, auth
, reason
, savePassword
); 
1091         SECURITYD_AUTH_KOFN(&auth
, (char *)name().c_str()); 
1092                 return evaluateRules(inRight
, inRule
, environmentToClient
, flags
, now
, inCredentials
, credentials
, auth
, reason
, savePassword
); 
1093         case kEvaluateMechanisms
: 
1094         SECURITYD_AUTH_MECHRULE(&auth
, (char *)name().c_str()); 
1095             // if we had a SecurityAgent::Reason code for "mechanism denied," 
1096             // it would make sense to pass down "reason" 
1097                 return evaluateMechanismOnly(inRight
, inRule
, environmentToClient
, auth
, credentials
, savePassword
); 
1099                 Syslog::alert("Unrecognized rule type %d", mType
); 
1100                 MacOSError::throwMe(errAuthorizationInternal
); // invalid rule 
1104 Rule::Rule() : RefPointer
<RuleImpl
>(new RuleImpl()) {} 
1105 Rule::Rule(const string 
&inRightName
, CFDictionaryRef cfRight
, CFDictionaryRef cfRules
) : RefPointer
<RuleImpl
>(new RuleImpl(inRightName
, cfRight
, cfRules
)) {} 
1109 } // end namespace Authorization