/* * 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 */