]> git.saurik.com Git - apple/security.git/blobdiff - securityd/src/AuthorizationMechEval.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / securityd / src / AuthorizationMechEval.cpp
diff --git a/securityd/src/AuthorizationMechEval.cpp b/securityd/src/AuthorizationMechEval.cpp
new file mode 100644 (file)
index 0000000..971df40
--- /dev/null
@@ -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 <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 */