1/* 2 * Copyright (c) 2003-2010,2012 Apple 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 * AuthorizationRule.cpp 24 * Security 25 * 26 */ 27 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" 37#include "server.h" 38#include "process.h" 39#include "agentquery.h" 40#include "AuthorizationMechEval.h" 41 42#include <asl.h> 43#include <pwd.h> 44#include <grp.h> 45#include <unistd.h> 46#include <membership.h> 47 48extern "C" { 49#include <membershipPriv.h> 50} 51 52using namespace CommonCriteria::Securityd; 53 54// 55// Rule class 56// 57namespace Authorization { 58 59CFStringRef RuleImpl::kUserGroupID = CFSTR(kAuthorizationRuleParameterGroup); 60CFStringRef RuleImpl::kTimeoutID = CFSTR(kAuthorizationRuleParameterCredentialTimeout); 61CFStringRef RuleImpl::kSharedID = CFSTR(kAuthorizationRuleParameterCredentialShared); 62CFStringRef RuleImpl::kAllowRootID = CFSTR(kAuthorizationRuleParameterAllowRoot); 63CFStringRef RuleImpl::kMechanismsID = CFSTR(kAuthorizationRuleParameterMechanisms); 64CFStringRef RuleImpl::kSessionOwnerID = CFSTR(kAuthorizationRuleParameterCredentialSessionOwner); 65CFStringRef RuleImpl::kKofNID = CFSTR(kAuthorizationRuleParameterKofN); 66CFStringRef RuleImpl::kPromptID = CFSTR(kAuthorizationRuleParameterDefaultPrompt); 67CFStringRef RuleImpl::kButtonID = CFSTR(kAuthorizationRuleParameterDefaultButton); 68CFStringRef RuleImpl::kTriesID = CFSTR("tries"); // XXX/cs move to AuthorizationTagsPriv.h 69CFStringRef RuleImpl::kExtractPasswordID = CFSTR(kAuthorizationRuleParameterExtractPassword); 70 71CFStringRef RuleImpl::kRuleClassID = CFSTR(kAuthorizationRuleClass); 72CFStringRef RuleImpl::kRuleAllowID = CFSTR(kAuthorizationRuleClassAllow); 73CFStringRef RuleImpl::kRuleDenyID = CFSTR(kAuthorizationRuleClassDeny); 74CFStringRef RuleImpl::kRuleUserID = CFSTR(kAuthorizationRuleClassUser); 75CFStringRef RuleImpl::kRuleDelegateID = CFSTR(kAuthorizationRightRule); 76CFStringRef RuleImpl::kRuleMechanismsID = CFSTR(kAuthorizationRuleClassMechanisms); 77CFStringRef RuleImpl::kRuleAuthenticateUserID = CFSTR(kAuthorizationRuleParameterAuthenticateUser); 78 79 80string 81RuleImpl::Attribute::getString(CFDictionaryRef config, CFStringRef key, bool required = false, const char *defaultValue = "") 82{ 83 CFTypeRef value = CFDictionaryGetValue(config, key); 84 if (value && (CFGetTypeID(value) == CFStringGetTypeID())) 85 { 86 CFStringRef stringValue = reinterpret_cast<CFStringRef>(value); 87 char buffer[512]; 88 const char *ptr = CFStringGetCStringPtr(stringValue, kCFStringEncodingUTF8); 89 if (ptr == NULL) 90 { 91 if (CFStringGetCString(stringValue, buffer, sizeof(buffer), kCFStringEncodingUTF8)) 92 ptr = buffer; 93 else 94 { 95 Syslog::alert("Could not convert CFString to C string"); 96 MacOSError::throwMe(errAuthorizationInternal); 97 } 98 } 99 100 return string(ptr); 101 } 102 else 103 if (!required) 104 return string(defaultValue); 105 else 106 { 107 Syslog::alert("Failed to get rule string"); 108 MacOSError::throwMe(errAuthorizationInternal); 109 } 110} 111 112double 113RuleImpl::Attribute::getDouble(CFDictionaryRef config, CFStringRef key, bool required = false, double defaultValue = 0.0) 114{ 115 double doubleValue = 0; 116 117 CFTypeRef value = CFDictionaryGetValue(config, key); 118 if (value && (CFGetTypeID(value) == CFNumberGetTypeID())) 119 { 120 CFNumberGetValue(reinterpret_cast<CFNumberRef>(value), kCFNumberDoubleType, &doubleValue); 121 } 122 else 123 if (!required) 124 return defaultValue; 125 else 126 { 127 Syslog::alert("Failed to get rule double value"); 128 MacOSError::throwMe(errAuthorizationInternal); 129 } 130 131 return doubleValue; 132} 133 134bool 135RuleImpl::Attribute::getBool(CFDictionaryRef config, CFStringRef key, bool required = false, bool defaultValue = false) 136{ 137 bool boolValue = false; 138 CFTypeRef value = CFDictionaryGetValue(config, key); 139 140 if (value && (CFGetTypeID(value) == CFBooleanGetTypeID())) 141 { 142 boolValue = CFBooleanGetValue(reinterpret_cast<CFBooleanRef>(value)); 143 } 144 else 145 if (!required) 146 return defaultValue; 147 else 148 { 149 Syslog::alert("Failed to get rule bool value"); 150 MacOSError::throwMe(errAuthorizationInternal); 151 } 152 153 return boolValue; 154} 155 156vector<string> 157RuleImpl::Attribute::getVector(CFDictionaryRef config, CFStringRef key, bool required = false) 158{ 159 vector<string> valueArray; 160 161 CFTypeRef value = CFDictionaryGetValue(config, key); 162 if (value && (CFGetTypeID(value) == CFArrayGetTypeID())) 163 { 164 CFArrayRef evalArray = reinterpret_cast<CFArrayRef>(value); 165 166 CFIndex numItems = CFArrayGetCount(evalArray); 167 for (CFIndex index=0; index < numItems; index++) 168 { 169 CFTypeRef arrayValue = CFArrayGetValueAtIndex(evalArray, index); 170 if (arrayValue && (CFGetTypeID(arrayValue) == CFStringGetTypeID())) 171 { 172 CFStringRef stringValue = reinterpret_cast<CFStringRef>(arrayValue); 173 char buffer[512]; 174 const char *ptr = CFStringGetCStringPtr(stringValue, kCFStringEncodingUTF8); 175 if (ptr == NULL) 176 { 177 if (CFStringGetCString(stringValue, buffer, sizeof(buffer), kCFStringEncodingUTF8)) 178 ptr = buffer; 179 else 180 { 181 Syslog::alert("Failed to convert CFString to C string for item %u in array", index); 182 MacOSError::throwMe(errAuthorizationInternal); 183 } 184 } 185 valueArray.push_back(string(ptr)); 186 } 187 } 188 } 189 else 190 if (required) 191 { 192 Syslog::alert("Value for key either not present or not a CFArray"); 193 MacOSError::throwMe(errAuthorizationInternal); 194 } 195 196 return valueArray; 197} 198 199 200bool RuleImpl::Attribute::getLocalizedText(CFDictionaryRef config, map<string,string> &localizedPrompts, CFStringRef dictKey, const char *descriptionKey) 201{ 202 CFIndex numberOfPrompts = 0; 203 CFDictionaryRef promptsDict; 204 if (CFDictionaryContainsKey(config, dictKey)) 205 { 206 promptsDict = reinterpret_cast<CFDictionaryRef>(CFDictionaryGetValue(config, dictKey)); 207 if (promptsDict && (CFGetTypeID(promptsDict) == CFDictionaryGetTypeID())) 208 numberOfPrompts = CFDictionaryGetCount(promptsDict); 209 } 210 if (numberOfPrompts == 0) 211 return false; 212 213 const void *keys[numberOfPrompts+1]; 214 const void *values[numberOfPrompts+1]; 215 CFDictionaryGetKeysAndValues(promptsDict, &keys[0], &values[0]); 216 217 while (numberOfPrompts-- > 0) 218 { 219 CFStringRef keyRef = reinterpret_cast<CFStringRef>(keys[numberOfPrompts]); 220 CFStringRef valueRef = reinterpret_cast<CFStringRef>(values[numberOfPrompts]); 221 if (!keyRef || (CFGetTypeID(keyRef) != CFStringGetTypeID())) { 222 continue; 223 } 224 if (!valueRef || (CFGetTypeID(valueRef) != CFStringGetTypeID())) { 225 continue; 226 } 227 string key = cfString(keyRef); 228 string value = cfString(valueRef); 229 localizedPrompts[descriptionKey + key] = value; 230 } 231 232 return true; 233} 234 235 236// default rule 237RuleImpl::RuleImpl() : 238mType(kUser), mGroupName("admin"), mMaxCredentialAge(300.0), mShared(true), mAllowRoot(false), mSessionOwner(false), mTries(0), mAuthenticateUser(true), mExtractPassword(false) 239{ 240 // XXX/cs read default descriptions from somewhere 241 // @@@ Default rule is shared admin group with 5 minute timeout 242} 243 244// return rule built from rule definition; throw if invalid. 245RuleImpl::RuleImpl(const string &inRightName, CFDictionaryRef cfRight, CFDictionaryRef cfRules) : mRightName(inRightName), mExtractPassword(false) 246{ 247 // @@@ make sure cfRight is non mutable and never used that way 248 249 if (CFGetTypeID(cfRight) != CFDictionaryGetTypeID()) 250 { 251 Syslog::alert("Invalid rights set"); 252 MacOSError::throwMe(errAuthorizationInternal); 253 } 254 255 mTries = 0; 256 257 string classTag = Attribute::getString(cfRight, kRuleClassID, false, ""); 258 259 if (classTag.length()) 260 { 261 if (classTag == kAuthorizationRuleClassAllow) 262 { 263 secdebug("authrule", "%s : rule allow", inRightName.c_str()); 264 mType = kAllow; 265 } 266 else if (classTag == kAuthorizationRuleClassDeny) 267 { 268 secdebug("authrule", "%s : rule deny", inRightName.c_str()); 269 mType = kDeny; 270 } 271 else if (classTag == kAuthorizationRuleClassUser) 272 { 273 mType = kUser; 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*/) 283 { 284 CFDictionaryRef cfRuleDef = reinterpret_cast<CFDictionaryRef>(CFDictionaryGetValue(cfRules, CFSTR("authenticate"))); 285 if (cfRuleDef && CFGetTypeID(cfRuleDef) == CFDictionaryGetTypeID()) 286 mEvalDef = Attribute::getVector(cfRuleDef, kMechanismsID); 287 } 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); 291 292 secdebug("authrule", "%s : rule user in group \"%s\" timeout %g%s%s", 293 inRightName.c_str(), 294 mGroupName.c_str(), mMaxCredentialAge, mShared ? " shared" : "", 295 mAllowRoot ? " allow-root" : ""); 296 297 } 298 else if (classTag == kAuthorizationRuleClassMechanisms) 299 { 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); 307 } 308 else if (classTag == kAuthorizationRightRule) 309 { 310 assert(cfRules); // rules can't delegate to other rules 311 secdebug("authrule", "%s : rule delegate rule", inRightName.c_str()); 312 mType = kRuleDelegation; 313 314 // string or 315 string ruleDefString = Attribute::getString(cfRight, kRuleDelegateID, false, ""); 316 if (ruleDefString.length()) 317 { 318 CFStringRef ruleDefRef = makeCFString(ruleDefString); 319 CFDictionaryRef cfRuleDef = reinterpret_cast<CFDictionaryRef>(CFDictionaryGetValue(cfRules, ruleDefRef)); 320 if (ruleDefRef) 321 CFRelease(ruleDefRef); 322 if (!cfRuleDef || CFGetTypeID(cfRuleDef) != CFDictionaryGetTypeID()) 323 { 324 Syslog::alert("'%s' does not name a built-in rule", ruleDefString.c_str()); 325 MacOSError::throwMe(errAuthorizationInternal); 326 } 327 mRuleDef.push_back(Rule(ruleDefString, cfRuleDef, cfRules)); 328 } 329 else // array 330 { 331 vector<string> ruleDef = Attribute::getVector(cfRight, kRuleDelegateID, true); 332 for (vector<string>::const_iterator it = ruleDef.begin(); it != ruleDef.end(); it++) 333 { 334 CFStringRef ruleNameRef = makeCFString(*it); 335 CFDictionaryRef cfRuleDef = reinterpret_cast<CFDictionaryRef>(CFDictionaryGetValue(cfRules, ruleNameRef)); 336 if (ruleNameRef) 337 CFRelease(ruleNameRef); 338 if (!cfRuleDef || (CFGetTypeID(cfRuleDef) != CFDictionaryGetTypeID())) 339 { 340 Syslog::alert("Invalid rule '%s'in rule set", it->c_str()); 341 MacOSError::throwMe(errAuthorizationInternal); 342 } 343 mRuleDef.push_back(Rule(*it, cfRuleDef, cfRules)); 344 } 345 } 346 347 mKofN = int(Attribute::getDouble(cfRight, kKofNID, false, 0.0)); 348 if (mKofN) 349 mType = kKofN; 350 351 } 352 else 353 { 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); 357 } 358 } 359 else 360 { 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)); 370 if (ruleNameRef) 371 CFRelease(ruleNameRef); 372 if (!cfRuleDef || CFGetTypeID(cfRuleDef) != CFDictionaryGetTypeID()) 373 { 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); 376 } 377 mRuleDef.push_back(Rule(ruleName, cfRuleDef, cfRules)); 378 } 379 380 Attribute::getLocalizedText(cfRight, mLocalizedPrompts, kPromptID, kAuthorizationRuleParameterDescription); 381 Attribute::getLocalizedText(cfRight, mLocalizedButtons, kButtonID, kAuthorizationRuleParameterButton); 382} 383 384/* 385RuleImpl::~Rule() 386{ 387} 388*/ 389 390void 391RuleImpl::setAgentHints(const AuthItemRef &inRight, const Rule &inTopLevelRule, AuthItemSet &environmentToClient, AuthorizationToken &auth) const 392{ 393 string authorizeString(inRight->name()); 394 environmentToClient.erase(AuthItemRef(AGENT_HINT_AUTHORIZE_RIGHT)); 395 environmentToClient.insert(AuthItemRef(AGENT_HINT_AUTHORIZE_RIGHT, AuthValueOverlay(authorizeString))); 396 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))); 400 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))); 404 405 Process &thisProcess = Server::process(); 406 string bundlePath; 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()); 416 417 map<string,string> defaultPrompts = inTopLevelRule->localizedPrompts(); 418 map<string,string> defaultButtons = inTopLevelRule->localizedButtons(); 419 420 if (defaultPrompts.empty()) 421 defaultPrompts = localizedPrompts(); 422 if (defaultButtons.empty()) 423 defaultButtons = localizedButtons(); 424 425 if (!defaultPrompts.empty()) 426 { 427 map<string,string>::const_iterator it; 428 for (it = defaultPrompts.begin(); it != defaultPrompts.end(); it++) 429 { 430 const string &key = it->first; 431 const string &value = it->second; 432 environmentToClient.insert(AuthItemRef(key.c_str(), AuthValueOverlay(value))); 433 } 434 } 435 if (!defaultButtons.empty()) 436 { 437 map<string,string>::const_iterator it; 438 for (it = defaultButtons.begin(); it != defaultButtons.end(); it++) 439 { 440 const string &key = it->first; 441 const string &value = it->second; 442 environmentToClient.insert(AuthItemRef(key.c_str(), AuthValueOverlay(value))); 443 } 444 } 445 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))); 450} 451 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 455OSStatus 456RuleImpl::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 457{ 458 OSStatus status = errAuthorizationDenied; 459 460 Credential hintCredential; 461 if (errAuthorizationSuccess == evaluateSessionOwner(inRight, inRule, environmentToClient, now, auth, hintCredential, reason)) { 462 if (hintCredential->name().length()) 463 environmentToClient.insert(AuthItemRef(AGENT_HINT_SUGGESTED_USER, AuthValueOverlay(hintCredential->name()))); 464 if (hintCredential->realname().length()) 465 environmentToClient.insert(AuthItemRef(AGENT_HINT_SUGGESTED_USER_LONG, AuthValueOverlay(hintCredential->realname()))); 466 } 467 468 if ((mType == kUser) && (mGroupName.length())) 469 environmentToClient.insert(AuthItemRef(AGENT_HINT_REQUIRE_USER_IN_GROUP, AuthValueOverlay(mGroupName))); 470 471 uint32 tries; 472 reason = SecurityAgent::noReason; 473 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); 480 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); 488 489 RightAuthenticationLogger rightAuthLogger(auth.creatorAuditToken(), AUE_ssauthint); 490 rightAuthLogger.setRight(rightName); 491 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."); 501 asl_free(m); 502// Credential rightCredential(rightName, auth.creatorUid(), mShared); 503// credentials.erase(rightCredential); credentials.insert(rightCredential); 504// return errAuthorizationSuccess; 505 } 506 else { 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."); 514 asl_free(m); 515 } 516 517 AgentMechanismEvaluator eval(cltUid, auth.session(), mEvalDef); 518 519 for (tries = 0; tries < mTries; tries++) 520 { 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 525 526 status = eval.run(authValueVector, environmentToClient, auth); 527 528 if ((status == errAuthorizationSuccess) || 529 (status == errAuthorizationCanceled)) // @@@ can only pass back sideband through context 530 { 531 secdebug("AuthEvalMech", "storing new context for authorization"); 532 auth.setInfoSet(eval.context(), savePassword); 533 } 534 535 // successfully ran mechanisms to obtain credential 536 if (status == errAuthorizationSuccess) 537 { 538 // deny is the default 539 status = errAuthorizationDenied; 540 541 CredentialSet newCredentials = makeCredentials(auth); 542 // clear context after extracting credentials 543 auth.scrubInfoSet(savePassword); 544 545 for (CredentialSet::const_iterator it = newCredentials.begin(); it != newCredentials.end(); ++it) 546 { 547 const Credential& newCredential = *it; 548 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->name().c_str(), newCredential->uid(), rightName); 552 rightAuthLogger.logSuccess(auth.creatorUid(), newCredential->uid(), newCredential->name().c_str()); 553 } else { 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->name().c_str(), rightName); 556 rightAuthLogger.logFailure(auth.creatorUid(), newCredential->name().c_str()); 557 } 558 559 if (!newCredential->isValid()) 560 { 561 reason = SecurityAgent::invalidPassphrase; 562 continue; 563 } 564 565 // verify that this credential authorizes right 566 status = evaluateUserCredentialForRight(auth, inRight, inRule, environmentToClient, now, newCredential, true, reason); 567 568 if (status == errAuthorizationSuccess) 569 { 570 if (auth.operatesAsLeastPrivileged()) { 571 Credential rightCredential(rightName, mShared); 572 credentials.erase(rightCredential); credentials.insert(rightCredential); 573 if (mShared) 574 credentials.insert(Credential(rightName, false)); 575 } 576 577 // whack an equivalent credential, so it gets updated to a later achieved credential which must have been more stringent 578 credentials.erase(newCredential); credentials.insert(newCredential); 579 // just got a new credential - if it's shared also add a non-shared one that to stick in the authorizationref local cache 580 if (mShared) 581 credentials.insert(Credential(newCredential->uid(), newCredential->name(), newCredential->realname(), false)); 582 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->name().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); 593 } 594 595 status = errAuthorizationSuccess; 596 break; 597 } 598 } 599 600 if (status == errAuthorizationSuccess) 601 break; 602 } 603 else 604 if ((status == errAuthorizationCanceled) || (status == errAuthorizationInternal)) 605 { 606 auth.scrubInfoSet(false); 607 break; 608 } 609 else // last mechanism is now authentication - fail 610 if (status == errAuthorizationDenied) 611 reason = SecurityAgent::invalidPassphrase; 612 } 613 614 // If we fell out of the loop because of too many tries, notify user 615 if (tries == mTries) 616 { 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); 625 626 rightAuthLogger.logFailure(NULL, CommonCriteria::errTooManyTries); 627 } 628 629 return status; 630} 631 632// create externally verified credentials on the basis of 633// mechanism-provided information 634CredentialSet 635RuleImpl::makeCredentials(const AuthorizationToken &auth) const 636{ 637 // fetch context and construct a credential to be tested 638 const AuthItemSet &context = const_cast<AuthorizationToken &>(auth).infoSet(); 639 CredentialSet newCredentials; 640 641 do { 642 AuthItemSet::const_iterator found = find_if(context.begin(), context.end(), FindAuthItemByRightName(kAuthorizationEnvironmentUsername) ); 643 if (found == context.end()) 644 break; 645 string username = (**found).stringValue(); 646 secdebug("AuthEvalMech", "found username"); 647 648 const uid_t *uid = NULL; 649 found = find_if(context.begin(), context.end(), FindAuthItemByRightName("uid") ); 650 if (found != context.end()) 651 { 652 uid = static_cast<const uid_t *>((**found).value().data); 653 secdebug("AuthEvalMech", "found uid"); 654 } 655 656 if (username.length() && uid) 657 { 658 // credential is valid because mechanism says so 659 newCredentials.insert(Credential(*uid, username, "", mShared)); 660 } 661 } while(0); 662 663 return newCredentials; 664} 665 666// evaluate whether a good credential of the current session owner would authorize a right 667OSStatus 668RuleImpl::evaluateSessionOwner(const AuthItemRef &inRight, const Rule &inRule, const AuthItemSet &environment, const CFAbsoluteTime now, const AuthorizationToken &auth, Credential &credential, SecurityAgent::Reason &reason) const 669{ 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. 673 674 Credential sessionCredential; 675 uid_t uid = auth.session().originatorUid(); 676 Server::active().longTermActivity(); 677 struct passwd *pw = getpwuid(uid); 678 if (pw != NULL) { 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*/); 686 } //fi 687 endpwent(); 688 } 689 OSStatus status = evaluateUserCredentialForRight(auth, inRight, inRule, environment, now, sessionCredential, true, reason); 690 if (errAuthorizationSuccess == status) 691 credential = sessionCredential; 692 693 return status; 694} 695 696 697OSStatus 698RuleImpl::evaluateCredentialForRight(const AuthorizationToken &auth, const AuthItemRef &inRight, const Rule &inRule, const AuthItemSet &environment, CFAbsoluteTime now, const Credential &credential, bool ignoreShared, SecurityAgent::Reason &reason) const 699{ 700 if (auth.operatesAsLeastPrivileged()) { 701 if (credential->isRight() && credential->isValid() && (inRight->name() == credential->name())) 702 { 703 if (!ignoreShared && !mShared && credential->isShared()) 704 { 705 // @@@ no proper SA::Reason 706 reason = SecurityAgent::unknownReason; 707 secdebug("autheval", "shared credential cannot be used, denying right %s", inRight->name()); 708 return errAuthorizationDenied; 709 } else { 710 return errAuthorizationSuccess; 711 } 712 } else { 713 // @@@ no proper SA::Reason 714 reason = SecurityAgent::unknownReason; 715 return errAuthorizationDenied; 716 } 717 } else 718 return evaluateUserCredentialForRight(auth, inRight, inRule, environment, now, credential, false, reason); 719} 720 721// Return errAuthorizationSuccess if this rule allows access based on the specified credential, 722// return errAuthorizationDenied otherwise. 723OSStatus 724RuleImpl::evaluateUserCredentialForRight(const AuthorizationToken &auth, const AuthItemRef &inRight, const Rule &inRule, const AuthItemSet &environment, CFAbsoluteTime now, const Credential &credential, bool ignoreShared, SecurityAgent::Reason &reason) const 725{ 726 assert(mType == kUser); 727 728 // Ideally we'd set the AGENT_HINT_RETRY_REASON hint in this method, but 729 // evaluateAuthentication() overwrites it before 730 // AgentMechanismEvaluator::run(). That's what led to passing "reason" 731 // everywhere, from RuleImpl::evaluate() on down. 732 733 // Get the username from the credential 734 const char *user = credential->name().c_str(); 735 736 // If the credential is not valid or its age is more than the allowed maximum age 737 // for a credential, deny. 738 if (!credential->isValid()) 739 { 740 // @@@ it could be the username, not password, was invalid 741 reason = SecurityAgent::invalidPassphrase; 742 secdebug("autheval", "credential for user %s is invalid, denying right %s", user, inRight->name()); 743 return errAuthorizationDenied; 744 } 745 746 if (now - credential->creationTime() > mMaxCredentialAge) 747 { 748 // @@@ no proper SA::Reason 749 reason = SecurityAgent::unknownReason; 750 secdebug("autheval", "credential for user %s has expired, denying right %s", user, inRight->name()); 751 return errAuthorizationDenied; 752 } 753 754 if (!ignoreShared && !mShared && credential->isShared()) 755 { 756 // @@@ no proper SA::Reason 757 reason = SecurityAgent::unknownReason; 758 secdebug("autheval", "shared credential for user %s cannot be used, denying right %s", user, inRight->name()); 759 return errAuthorizationDenied; 760 } 761 762 // A root (uid == 0) user can do anything 763 if (credential->uid() == 0) 764 { 765 secdebug("autheval", "user %s has uid 0, granting right %s", user, inRight->name()); 766 return errAuthorizationSuccess; 767 } 768 769 if (mSessionOwner) 770 { 771 Session &session = auth.session(); 772 uid_t console_user = session.originatorUid(); 773 774 if (credential->uid() == console_user) 775 { 776 secdebug("autheval", "user %s is session-owner(uid: %d), granting right %s", user, console_user, inRight->name()); 777 return errAuthorizationSuccess; 778 } 779 // set "reason" in this case? not that a proper SA::Reason exists 780 } 781 else 782 { 783 // @@@ no proper SA::Reason 784 reason = SecurityAgent::unknownReason; 785 secdebug("autheval", "session-owner check failed."); 786 } 787 788 if (mGroupName.length()) 789 { 790 const char *groupname = mGroupName.c_str(); 791 Server::active().longTermActivity(); 792 793 if (!groupname) 794 return errAuthorizationDenied; 795 796 do 797 { 798 uuid_t group_uuid, user_uuid; 799 int is_member; 800 801 // @@@ it'd be nice to have SA::Reason codes for the failures 802 // associated with the pre-check-membership mbr_*() functions, 803 // but userNotInGroup will do 804 if (mbr_group_name_to_uuid(groupname, group_uuid)) 805 break; 806 807 if (mbr_uid_to_uuid(credential->uid(), user_uuid)) 808 { 809 struct passwd *pwd; 810 if (NULL == (pwd = getpwnam(user))) 811 break; 812 if (mbr_uid_to_uuid(pwd->pw_uid, user_uuid)) 813 break; 814 } 815 816 if (mbr_check_membership(user_uuid, group_uuid, &is_member)) 817 break; 818 819 if (is_member) 820 { 821 secdebug("autheval", "user %s is a member of group %s, granting right %s", 822 user, groupname, inRight->name()); 823 return errAuthorizationSuccess; 824 } 825 826 } 827 while (0); 828 829 reason = SecurityAgent::userNotInGroup; 830 secdebug("autheval", "user %s is not a member of group %s, denying right %s", 831 user, groupname, inRight->name()); 832 } 833 else if (mSessionOwner) // rule asks only if user is the session owner 834 { 835 reason = SecurityAgent::unacceptableUser; 836 } 837 838 return errAuthorizationDenied; 839} 840 841 842 843OSStatus 844RuleImpl::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 845{ 846 // If we got here, this is a kUser type rule, let's start looking for a 847 // credential that is satisfactory 848 849 // Zeroth -- Here is an extra special saucy ugly hack to allow authorizations 850 // created by a proccess running as root to automatically get a right. 851 if (mAllowRoot && auth.creatorUid() == 0) 852 { 853 SECURITYD_AUTH_USER_ALLOWROOT(&auth); 854 855 secdebug("autheval", "creator of authorization has uid == 0 granting right %s", 856 inRight->name()); 857 return errAuthorizationSuccess; 858 } 859 860 // if we're not supposed to authenticate evaluate the session-owner against the group 861 if (!mAuthenticateUser) 862 { 863 Credential hintCredential; 864 OSStatus status = evaluateSessionOwner(inRight, inRule, environmentToClient, now, auth, hintCredential, reason); 865 866 if (!status) 867 { 868 SECURITYD_AUTH_USER_ALLOWSESSIONOWNER(&auth); 869 return errAuthorizationSuccess; 870 } 871 872 return errAuthorizationDenied; 873 } 874 875 // First -- go though the credentials we either already used or obtained during this authorize operation. 876 for (CredentialSet::const_iterator it = credentials.begin(); it != credentials.end(); ++it) 877 { 878 // Passed-in user credentials are allowed for least-privileged mode 879 if (auth.operatesAsLeastPrivileged() && !(*it)->isRight() && (*it)->isValid()) 880 { 881 OSStatus status = evaluateUserCredentialForRight(auth, inRight, inRule, environmentToClient, now, *it, false, reason); 882 if (errAuthorizationSuccess == status) { 883 Credential rightCredential(inRight->name(), mShared); 884 credentials.erase(rightCredential); credentials.insert(rightCredential); 885 if (mShared) 886 credentials.insert(Credential(inRight->name(), false)); 887 return status; 888 } 889 } 890 891 // if this is least privileged, this will function differently: match credential to requested right 892 OSStatus status = evaluateCredentialForRight(auth, inRight, inRule, environmentToClient, now, *it, false, reason); 893 894 if (status != errAuthorizationDenied) { 895 // add credential to authinfo 896 auth.setCredentialInfo(*it, savePassword); 897 return status; 898 } 899 900 } 901 902 // Second -- go though the credentials passed in to this authorize operation by the state management layer. 903 if (inCredentials) 904 { 905 for (CredentialSet::const_iterator it = inCredentials->begin(); it != inCredentials->end(); ++it) 906 { 907 // if this is least privileged, this will function differently: match credential to requested right 908 OSStatus status = evaluateCredentialForRight(auth, inRight, inRule, environmentToClient, now, *it, false, reason); 909 910 if (status == errAuthorizationSuccess) 911 { 912 // Add the credential we used to the output set. 913 // whack an equivalent credential, so it gets updated to a later achieved credential which must have been more stringent 914 credentials.erase(*it); credentials.insert(*it); 915 // add credential to authinfo 916 auth.setCredentialInfo(*it, savePassword); 917 918 return status; 919 } 920 else if (status != errAuthorizationDenied) 921 return status; 922 } 923 } 924 925 // Finally -- We didn't find the credential in our passed in credential lists. Obtain a new credential if our flags let us do so. 926 if (!(flags & kAuthorizationFlagExtendRights)) 927 return errAuthorizationDenied; 928 929 // authorizations that timeout immediately cannot be preauthorized 930 if ((flags & kAuthorizationFlagPreAuthorize) && 931 (mMaxCredentialAge == 0.0)) 932 { 933 inRight->setFlags(inRight->flags() | kAuthorizationFlagCanNotPreAuthorize); 934 return errAuthorizationSuccess; 935 } 936 937 if (!(flags & kAuthorizationFlagInteractionAllowed)) 938 return errAuthorizationInteractionNotAllowed; 939 940 setAgentHints(inRight, inRule, environmentToClient, auth); 941 942 return evaluateAuthentication(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth, reason, savePassword); 943} 944 945OSStatus 946RuleImpl::evaluateMechanismOnly(const AuthItemRef &inRight, const Rule &inRule, AuthItemSet &environmentToClient, AuthorizationToken &auth, CredentialSet &outCredentials, bool savePassword) const 947{ 948 uint32 tries = 0; 949 OSStatus status; 950 951 Process &cltProc = Server::process(); 952 // Authorization preserves creator's UID in setuid processes 953 uid_t cltUid = (cltProc.uid() != 0) ? cltProc.uid() : auth.creatorUid(); 954 secdebug("AuthEvalMech", "Mechanism invocation by process %d (UID %d)", cltProc.pid(), cltUid); 955 956 { 957 AgentMechanismEvaluator eval(cltUid, auth.session(), mEvalDef); 958 // For auditing within AuthorizationMechEval, pass the right name. 959 size_t rightNameSize = inRight->name() ? strlen(inRight->name()) : 0; 960 AuthorizationString rightName = inRight->name() ? inRight->name() : ""; 961 // @@@ AuthValueRef's ctor ought to take a const void * 962 AuthValueRef rightValue(rightNameSize, const_cast<char *>(rightName)); 963 AuthValueVector authValueVector; 964 authValueVector.push_back(rightValue); 965 966 do 967 { 968 setAgentHints(inRight, inRule, environmentToClient, auth); 969 AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(tries), &tries)); 970 environmentToClient.erase(triesHint); environmentToClient.insert(triesHint); // replace 971 972 status = eval.run(authValueVector, environmentToClient, auth); 973 if ((status == errAuthorizationSuccess) || 974 (status == errAuthorizationCanceled)) // @@@ can only pass back sideband through context 975 { 976 secdebug("AuthEvalMech", "storing new context for authorization"); 977 auth.setInfoSet(eval.context(), savePassword); 978 if (status == errAuthorizationSuccess) 979 { 980 // (try to) attach the authorizing UID to the least-priv cred 981 if (auth.operatesAsLeastPrivileged()) 982 { 983 outCredentials.insert(Credential(rightName, mShared)); 984 if (mShared) 985 outCredentials.insert(Credential(rightName, false)); 986 987 RightAuthenticationLogger logger(auth.creatorAuditToken(), AUE_ssauthint); 988 logger.setRight(rightName); 989 990 AuthItem *uidItem = eval.context().find(AGENT_CONTEXT_UID); 991 if (uidItem) 992 { 993 uid_t authorizedUid; 994 memcpy(&authorizedUid, uidItem->value().data, sizeof(authorizedUid)); 995 secdebug("AuthEvalMech", "generating least-privilege cred for '%s' authorized by UID %u", inRight->name(), authorizedUid); 996 logger.logLeastPrivilege(authorizedUid, true); 997 } 998 else // cltUid is better than nothing 999 { 1000 secdebug("AuthEvalMech", "generating least-privilege cred for '%s' with process- or auth-UID %u", inRight->name(), cltUid); 1001 logger.logLeastPrivilege(cltUid, false); 1002 } 1003 } 1004 1005 if (0 == strcmp(rightName, "system.login.console") && NULL == eval.context().find(AGENT_CONTEXT_AUTO_LOGIN)) { 1006 secdebug("AuthEvalMech", "We logged in as the session owner.\n"); 1007 SessionAttributeBits flags = auth.session().attributes(); 1008 flags |= AU_SESSION_FLAG_HAS_AUTHENTICATED; 1009 auth.session().setAttributes(flags); 1010 } 1011 CredentialSet newCredentials = makeCredentials(auth); 1012 outCredentials.insert(newCredentials.begin(), newCredentials.end()); 1013 } 1014 } 1015 1016 tries++; 1017 } 1018 while ((status == errAuthorizationDenied) // only if we have an expected failure we continue 1019 && ((mTries == 0) // mTries == 0 means we try forever 1020 || ((mTries > 0) // mTries > 0 means we try up to mTries times 1021 && (tries < mTries)))); 1022 } 1023 1024 // HACK kill all hosts to free pages for low memory systems 1025 // (XXX/gh there should be a #define for this right) 1026 if (name() == "system.login.done") 1027 { 1028 // one case where we don't want to mark the agents as "busy" 1029 QueryInvokeMechanism query(securityAgent, auth.session()); 1030 query.terminateAgent(); 1031 QueryInvokeMechanism query2(privilegedAuthHost, auth.session()); 1032 query2.terminateAgent(); 1033 } 1034 1035 return status; 1036} 1037 1038OSStatus 1039RuleImpl::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 1040{ 1041 // line up the rules to try 1042 if (!mRuleDef.size()) 1043 return errAuthorizationSuccess; 1044 1045 uint32_t count = 0; 1046 OSStatus status = errAuthorizationSuccess; 1047 vector<Rule>::const_iterator it; 1048 1049 for (it = mRuleDef.begin();it != mRuleDef.end(); it++) 1050 { 1051 // are we at k yet? 1052 if ((mType == kKofN) && (count == mKofN)) 1053 return errAuthorizationSuccess; 1054 1055 // get a rule and try it 1056 status = (*it)->evaluate(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth, reason, savePassword); 1057 1058 // if status is cancel/internal error abort 1059 if ((status == errAuthorizationCanceled) || (status == errAuthorizationInternal)) 1060 return status; 1061 1062 if (status != errAuthorizationSuccess) 1063 { 1064 // continue if we're only looking for k of n 1065 if (mType == kKofN) 1066 continue; 1067 1068 break; 1069 } 1070 else 1071 count++; 1072 } 1073 1074 if ((mType == kKofN) && (status == errAuthorizationSuccess) && (count < mKofN)) 1075 status = errAuthorizationDenied; 1076 1077 return status; // return the last failure 1078} 1079 1080 1081OSStatus 1082RuleImpl::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 1083{ 1084 switch (mType) 1085 { 1086 case kAllow: 1087 SECURITYD_AUTH_ALLOW(&auth, (char *)name().c_str()); 1088 return errAuthorizationSuccess; 1089 case kDeny: 1090 SECURITYD_AUTH_DENY(&auth, (char *)name().c_str()); 1091 return errAuthorizationDenied; 1092 case kUser: 1093 SECURITYD_AUTH_USER(&auth, (char *)name().c_str()); 1094 return evaluateUser(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth, reason, savePassword); 1095 case kRuleDelegation: 1096 SECURITYD_AUTH_RULES(&auth, (char *)name().c_str()); 1097 return evaluateRules(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth, reason, savePassword); 1098 case kKofN: 1099 SECURITYD_AUTH_KOFN(&auth, (char *)name().c_str()); 1100 return evaluateRules(inRight, inRule, environmentToClient, flags, now, inCredentials, credentials, auth, reason, savePassword); 1101 case kEvaluateMechanisms: 1102 SECURITYD_AUTH_MECHRULE(&auth, (char *)name().c_str()); 1103 // if we had a SecurityAgent::Reason code for "mechanism denied," 1104 // it would make sense to pass down "reason" 1105 return evaluateMechanismOnly(inRight, inRule, environmentToClient, auth, credentials, savePassword); 1106 default: 1107 Syslog::alert("Unrecognized rule type %d", mType); 1108 MacOSError::throwMe(errAuthorizationInternal); // invalid rule 1109 } 1110} 1111 1112Rule::Rule() : RefPointer<RuleImpl>(new RuleImpl()) {} 1113Rule::Rule(const string &inRightName, CFDictionaryRef cfRight, CFDictionaryRef cfRules) : RefPointer<RuleImpl>(new RuleImpl(inRightName, cfRight, cfRules)) {} 1114 1115 1116 1117} // end namespace Authorization 1118