X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/securityd/src/AuthorizationMechEval.cpp diff --git a/securityd/src/AuthorizationMechEval.cpp b/securityd/src/AuthorizationMechEval.cpp new file mode 100644 index 00000000..971df40b --- /dev/null +++ b/securityd/src/AuthorizationMechEval.cpp @@ -0,0 +1,304 @@ +/* + * 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 +#include +#include "ccaudit_extensions.h" + +namespace Authorization { + +using namespace CommonCriteria::Securityd; + +AgentMechanismRef::AgentMechanismRef(const AuthHostType type, Session &session) : + RefPointer(new QueryInvokeMechanism(type, session)) {} + +// we need the vector of mechanisms +AgentMechanismEvaluator::AgentMechanismEvaluator(uid_t uid, Session& session, const vector& 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 = ""; // 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(val.data), val.length); + logger.setRight(tmpstr); + rightName.clear(); + rightName = tmpstr; + } + catch (...) { } + + const AuthItemSet &inContext = const_cast(auth).infoSet(); + + // add process specifics to context? + + vector::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::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((*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((*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 */