--- /dev/null
+/*
+ * Copyright (c) 2003-2009 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * AuthorizationMechEval.cpp
+ * securityd
+ *
+ */
+#include "AuthorizationMechEval.h"
+#include <security_utilities/logging.h>
+#include <bsm/audit_uevents.h>
+#include "ccaudit_extensions.h"
+
+namespace Authorization {
+
+using namespace CommonCriteria::Securityd;
+
+AgentMechanismRef::AgentMechanismRef(const AuthHostType type, Session &session) :
+ RefPointer<QueryInvokeMechanism>(new QueryInvokeMechanism(type, session)) {}
+
+// we need the vector<string> of mechanisms
+AgentMechanismEvaluator::AgentMechanismEvaluator(uid_t uid, Session& session, const vector<string>& inMechanisms) :
+ mMechanisms(inMechanisms), mClientUid(uid), mSession(session)
+{
+ //set up environment
+}
+
+OSStatus
+AgentMechanismEvaluator::run(const AuthValueVector &inArguments, const AuthItemSet &inHints, const AuthorizationToken &auth)
+{
+ AuthMechLogger logger(auth.creatorAuditToken(), AUE_ssauthmech);
+ string rightName = "<unknown right>"; // for syslog
+
+ // as of 10.6, the first item in inArguments should be the name of the
+ // requested right, for auditing
+ try
+ {
+ AuthorizationValue val = inArguments.at(0)->value();
+ string tmpstr(static_cast<const char *>(val.data), val.length);
+ logger.setRight(tmpstr);
+ rightName.clear();
+ rightName = tmpstr;
+ }
+ catch (...) { }
+
+ const AuthItemSet &inContext = const_cast<AuthorizationToken &>(auth).infoSet();
+
+ // add process specifics to context?
+
+ vector<std::string>::const_iterator currentMechanism = mMechanisms.begin();
+
+ AuthorizationResult result = kAuthorizationResultAllow;
+
+ AuthItemSet hints = inHints;
+ AuthItemSet context = inContext;
+ // add saved-off sticky context values to context for evaluation
+ context.insert(mStickyContext.begin(), mStickyContext.end());
+
+ while ( (result == kAuthorizationResultAllow) &&
+ (currentMechanism != mMechanisms.end()) ) // iterate mechanisms
+ {
+ SECURITYD_AUTH_MECH(&auth, (char *)(*currentMechanism).c_str());
+
+ // set up the audit message
+ logger.setCurrentMechanism(*currentMechanism);
+
+ // do the real work
+ ClientMap::iterator iter = mClients.find(*currentMechanism);
+ if (iter == mClients.end())
+ {
+ string::size_type extPlugin = currentMechanism->find(':');
+ if (extPlugin != string::npos)
+ {
+ // no whitespace removal
+ string pluginIn(currentMechanism->substr(0, extPlugin));
+ string mechanismIn, authhostIn;
+
+ string::size_type extMechanism = currentMechanism->rfind(',');
+ AuthHostType hostType = securityAgent;
+
+ if (extMechanism != string::npos)
+ {
+ if (extMechanism < extPlugin)
+ {
+ string auditMsg = "badly formed mechanism name; ending rule evaluation";
+ Syslog::alert("Right '%s', mech '%s': %s", rightName.c_str(), (*currentMechanism).c_str(), auditMsg.c_str());
+ logger.logFailure(auditMsg);
+ return errAuthorizationInternal;
+ }
+
+ mechanismIn = currentMechanism->substr(extPlugin + 1, extMechanism - extPlugin - 1);
+ authhostIn = currentMechanism->substr(extMechanism + 1);
+ if (authhostIn == "privileged")
+ hostType = privilegedAuthHost;
+ }
+ else
+ mechanismIn = currentMechanism->substr(extPlugin + 1);
+
+ secdebug("AuthEvalMech", "external mechanism %s:%s", pluginIn.c_str(), mechanismIn.c_str());
+
+ AgentMechanismRef client(hostType, mSession);
+ client->initialize(pluginIn, mechanismIn, inArguments);
+ mClients.insert(ClientMap::value_type(*currentMechanism, client));
+ }
+ else if (*currentMechanism == "authinternal")
+ {
+ secdebug("AuthEvalMech", "performing authentication");
+ result = authinternal(context);
+
+ if (kAuthorizationResultAllow == result)
+ {
+ logger.logSuccess();
+ }
+ else // kAuthorizationResultDeny
+ {
+ logger.logFailure();
+ }
+ }
+ else if (*currentMechanism == "push_hints_to_context")
+ {
+ secdebug("AuthEvalMech", "evaluate push_hints_to_context");
+ logger.logSuccess();
+ // doesn't block evaluation, ever
+ result = kAuthorizationResultAllow;
+ context = hints;
+ }
+ else
+ {
+ string auditMsg = "unknown mechanism; ending rule evaluation";
+ Syslog::alert("Right '%s', mech '%s': %s", rightName.c_str(), (*currentMechanism).c_str(), auditMsg.c_str());
+ logger.logFailure(auditMsg);
+ return errAuthorizationInternal;
+ }
+ }
+
+ iter = mClients.find(*currentMechanism);
+ if (iter != mClients.end())
+ {
+ try
+ {
+ AgentMechanismRef &client = iter->second;
+ client->run(inArguments, hints, context, &result);
+
+ bool interrupted = false;
+ while (client->state() == client->current)
+ {
+ // check for interruption
+ vector<std::string>::const_iterator checkMechanism = mMechanisms.begin();
+ while (*checkMechanism != *currentMechanism) {
+ ClientMap::iterator iter2 = mClients.find(*checkMechanism);
+ if (iter2->second->state() == iter2->second->interrupting)
+ {
+ client->deactivate();
+ // nothing can happen until the client mechanism returns control to us
+ while (client->state() == client->deactivating)
+ client->receive();
+
+ string auditMsg = "evaluation interrupted by ";
+ auditMsg += (iter2->first).c_str();
+ auditMsg += "; restarting evaluation there";
+ secdebug("AuthEvalMech", "%s", auditMsg.c_str());
+ logger.logInterrupt(auditMsg);
+
+ interrupted = true;
+ hints = iter2->second->inHints();
+ context = iter2->second->inContext();
+ currentMechanism = checkMechanism;
+ break;
+ }
+ else
+ checkMechanism++;
+ }
+ if (client->state() == client->current)
+ client->receive();
+ }
+
+ if (interrupted)
+ {
+ // clear reason for restart from interrupt
+ uint32_t reason = SecurityAgent::worldChanged;
+ AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason));
+ hints.erase(retryHint); hints.insert(retryHint); // replace
+
+ result = kAuthorizationResultAllow;
+ continue;
+ }
+ else
+ secdebug("AuthEvalMech", "evaluate(%s) with result: %u.", (iter->first).c_str(), (uint32_t)result);
+ }
+ catch (...) {
+ string auditMsg = "exception during evaluation of ";
+ auditMsg += (iter->first).c_str();
+ secdebug("AuthEvalMech", "%s", auditMsg.c_str());
+ logger.logFailure(auditMsg);
+ result = kAuthorizationResultUndefined;
+ }
+ }
+
+ if (result == kAuthorizationResultAllow)
+ {
+ logger.logSuccess();
+ currentMechanism++;
+ }
+ }
+
+ if ((result == kAuthorizationResultUserCanceled) ||
+ (result == kAuthorizationResultAllow))
+ {
+ mHints = hints;
+ mContext.clear();
+ // only make non-sticky context values available externally
+ AuthItemSet::const_iterator end = context.end();
+ for (AuthItemSet::const_iterator it = context.begin(); it != end; ++it) {
+ const AuthItemRef &item = *it;
+ if (item->flags() != kAuthorizationContextFlagSticky)
+ mContext.insert(item);
+ }
+ if (result == kAuthorizationResultUserCanceled)
+ logger.logFailure(NULL, errAuthorizationCanceled);
+ }
+ else if (result == kAuthorizationResultDeny)
+ {
+ // save off sticky values in context
+ mStickyContext.clear();
+ AuthItemSet::const_iterator end = context.end();
+ for (AuthItemSet::const_iterator it = context.begin(); it != end; ++it) {
+ const AuthItemRef &item = *it;
+ if (item->flags() == kAuthorizationContextFlagSticky)
+ mStickyContext.insert(item);
+ }
+ logger.logFailure();
+ }
+
+ // convert AuthorizationResult to OSStatus
+ switch(result)
+ {
+ case kAuthorizationResultDeny:
+ return errAuthorizationDenied;
+ case kAuthorizationResultUserCanceled:
+ return errAuthorizationCanceled;
+ case kAuthorizationResultAllow:
+ return errAuthorizationSuccess;
+ case kAuthorizationResultUndefined:
+ return errAuthorizationInternal;
+ default:
+ {
+ Syslog::alert("Right '%s': unexpected error result (%u)", rightName.c_str(), result);
+ logger.logFailure("unexpected error result", result);
+ return errAuthorizationInternal;
+ }
+ }
+}
+
+AuthorizationResult AgentMechanismEvaluator::authinternal(AuthItemSet &context)
+{
+ secdebug("AuthEvalMech", "evaluate authinternal");
+ do {
+ AuthItemSet::iterator found = find_if(context.begin(), context.end(), FindAuthItemByRightName(kAuthorizationEnvironmentUsername) );
+ if (found == context.end())
+ break;
+ string username(static_cast<const char *>((*found)->value().data), (*found)->value().length);
+ secdebug("AuthEvalMech", "found username");
+ found = find_if(context.begin(), context.end(), FindAuthItemByRightName(kAuthorizationEnvironmentPassword) );
+ if (found == context.end())
+ break;
+ string password(static_cast<const char *>((*found)->value().data), (*found)->value().length);
+ secdebug("AuthEvalMech", "found password");
+
+ Credential newCredential(username, password, true); // create a new shared credential
+ if (newCredential->isValid())
+ return kAuthorizationResultAllow;
+
+ } while (0);
+
+ return kAuthorizationResultDeny;
+}
+
+/*
+AuthItemSet &
+AgentMechanismEvaluator::commonHints(const AuthorizationToken &auth)
+{
+
+}
+*/
+
+} /* namespace Authorization */