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