]> git.saurik.com Git - apple/security.git/blobdiff - OSX/include/security_codesigning/evaluationmanager.cpp
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / include / security_codesigning / evaluationmanager.cpp
diff --git a/OSX/include/security_codesigning/evaluationmanager.cpp b/OSX/include/security_codesigning/evaluationmanager.cpp
deleted file mode 100644 (file)
index d64d6e1..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright (c) 2011-2014 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@
- */
-
-#include "evaluationmanager.h"
-#include "policyengine.h"
-#include <security_utilities/cfmunge.h>
-#include <xpc/xpc.h>
-#include <exception>
-#include <vector>
-
-
-
-
-namespace Security {
-namespace CodeSigning {
-
-
-
-
-#pragma mark - EvaluationTask
-
-
-//
-// An evaluation task object manages the assessment - either directly, or in the
-// form of waiting for another evaluation task to finish an assessment on the
-// same target.
-//
-class EvaluationTask
-{
-public:
-    CFURLRef path()      const { return mPath.get(); }
-    AuthorityType type() const { return mType; }
-    bool isSharable()    const { return mSharable; }
-    void setUnsharable()       { mSharable = false; }
-
-private:
-    EvaluationTask(PolicyEngine *engine, CFURLRef path, AuthorityType type);
-    virtual ~EvaluationTask();
-    void performEvaluation(SecAssessmentFlags flags, CFDictionaryRef context);
-    void waitForCompletion(SecAssessmentFlags flags, CFMutableDictionaryRef result);
-
-    PolicyEngine                      *mPolicyEngine;
-    AuthorityType                      mType;
-    dispatch_queue_t                   mWorkQueue;
-    dispatch_queue_t                   mFeedbackQueue;
-    dispatch_semaphore_t               mAssessmentLock;
-    __block dispatch_once_t            mAssessmentKicked;
-    int32_t                            mReferenceCount;
-    int32_t                            mEvalCount;
-// This whole thing is a pre-existing crutch and must be fixed soon.
-#define UNOFFICIAL_MAX_XPC_ID_LENGTH 127
-    char                               mXpcActivityName[UNOFFICIAL_MAX_XPC_ID_LENGTH];
-    bool                               mSharable;
-
-    CFCopyRef<CFURLRef>                mPath;
-    CFCopyRef<CFMutableDictionaryRef>  mResult;
-    std::vector<SecAssessmentFeedback> mFeedback;
-
-    std::exception_ptr                 mExceptionToRethrow;
-
-    friend class EvaluationManager;
-};
-
-
-EvaluationTask::EvaluationTask(PolicyEngine *engine, CFURLRef path, AuthorityType type) :
-    mPolicyEngine(engine), mType(type), mAssessmentLock(dispatch_semaphore_create(0)),
-    mAssessmentKicked(0), mReferenceCount(0), mEvalCount(0), mSharable(true),
-    mExceptionToRethrow(0)
-{
-    mXpcActivityName[0] = 0;
-
-    mWorkQueue = dispatch_queue_create("EvaluationTask", 0);
-    mFeedbackQueue = dispatch_queue_create("EvaluationTaskFeedback", 0);
-
-    mPath = path;
-    mResult.take(makeCFMutableDictionary());
-}
-
-
-EvaluationTask::~EvaluationTask()
-{
-    dispatch_release(mFeedbackQueue);
-    dispatch_release(mWorkQueue);
-    dispatch_release(mAssessmentLock);
-}
-
-
-void EvaluationTask::performEvaluation(SecAssessmentFlags flags, CFDictionaryRef context)
-{
-    bool performTheEvaluation = false;
-    bool lowPriority = flags & kSecAssessmentFlagLowPriority;
-
-    // each evaluation task performs at most a single evaluation
-    if (OSAtomicIncrement32Barrier(&mEvalCount) == 1)
-        performTheEvaluation = true;
-
-    // define a block to run when the assessment has feedback available
-    SecAssessmentFeedback relayFeedback = ^Boolean(CFStringRef type, CFDictionaryRef information) {
-
-        __block Boolean proceed = true;
-        dispatch_sync(mFeedbackQueue, ^{
-            if (mFeedback.size() > 0) {
-                proceed = false; // we need at least one interested party to proceed
-                // forward the feedback to all registered listeners
-                for (int i = 0; i < mFeedback.size(); ++i) {
-                    proceed |= mFeedback[i](type, information);
-                }
-            }
-        });
-        if (!proceed)
-            this->setUnsharable(); // don't share an expiring evaluation task
-        return proceed;
-    };
-
-
-    // if the calling context has a feedback block, register it to listen to
-    // our feedback relay
-    dispatch_sync(mFeedbackQueue, ^{
-        SecAssessmentFeedback feedback = (SecAssessmentFeedback)CFDictionaryGetValue(context, kSecAssessmentContextKeyFeedback);
-        if (feedback && CFGetTypeID(feedback) == CFGetTypeID(relayFeedback))
-            mFeedback.push_back(feedback);
-    });
-
-    // if we haven't already started the evaluation (we're the first interested
-    // party), do it now
-    if (performTheEvaluation) {
-        dispatch_semaphore_t startLock = dispatch_semaphore_create(0);
-
-        // create the assessment block
-        dispatch_async(mWorkQueue, dispatch_block_create_with_qos_class(DISPATCH_BLOCK_ENFORCE_QOS_CLASS, QOS_CLASS_UTILITY, 0, ^{
-            // signal that the assessment is ready to start
-            dispatch_semaphore_signal(startLock);
-
-            // wait until we're permitted to start the assessment. if we're in low
-            // priority mode, this will not happen until we're on AC power. if not
-            // in low priority mode, we're either already free to perform the
-            // assessment or we will be quite soon
-            dispatch_semaphore_wait(mAssessmentLock, DISPATCH_TIME_FOREVER);
-
-            // Unregister a possibly still scheduled activity, as it lost its point.
-            if (strlen(mXpcActivityName)) {
-                xpc_activity_unregister(mXpcActivityName);
-            }
-
-            // copy the original context into our own mutable dictionary and replace
-            // (or assign) the feedback entry within it to our multi-receiver
-            // feedback relay block
-            CFRef<CFMutableDictionaryRef> contextOverride = makeCFMutableDictionary(context);
-            CFDictionaryRemoveValue(contextOverride.get(), kSecAssessmentContextKeyFeedback);
-            CFDictionaryAddValue(contextOverride.get(), kSecAssessmentContextKeyFeedback, relayFeedback);
-
-            try {
-                // perform the evaluation
-                switch (mType) {
-                    case kAuthorityExecute:
-                        mPolicyEngine->evaluateCode(mPath.get(), kAuthorityExecute, flags, contextOverride.get(), mResult.get(), true);
-                        break;
-                    case kAuthorityInstall:
-                        mPolicyEngine->evaluateInstall(mPath.get(), flags, contextOverride.get(), mResult.get());
-                        break;
-                    case kAuthorityOpenDoc:
-                        mPolicyEngine->evaluateDocOpen(mPath.get(), flags, contextOverride.get(), mResult.get());
-                        break;
-                    default:
-                        MacOSError::throwMe(errSecCSInvalidAttributeValues);
-                        break;
-                }
-            } catch(...) {
-                mExceptionToRethrow = std::current_exception();
-            }
-
-        }));
-
-        // wait for the assessment to start
-        dispatch_semaphore_wait(startLock, DISPATCH_TIME_FOREVER);
-        dispatch_release(startLock);
-
-        if (lowPriority) {
-            // This whole thing is a crutch and should be handled differently.
-            // Maybe by having just one activity that just kicks off all remaining
-            // background assessments, CTS determines that it's a good time.
-
-            // reduce the bundle path name to just the app component and generate an
-            // xpc_activity identifier from it. this identifier should be smaller than
-            // 128 characters due to rdar://problem/20094806
-            string path = cfString(mPath);
-            size_t bundleNamePosition = path.rfind('/');
-            const char *bundleName = "/default";
-            if (bundleNamePosition != string::npos)
-                bundleName = path.c_str() + bundleNamePosition;
-            snprintf(mXpcActivityName, UNOFFICIAL_MAX_XPC_ID_LENGTH, "com.apple.security.assess%s", bundleName);
-
-            // schedule the assessment to be permitted to run (beyond start) -- this
-            // will either happen once we're no longer on battery power, or
-            // immediately, based on the flag value of kSecAssessmentFlagLowPriority
-            xpc_object_t criteria = xpc_dictionary_create(NULL, NULL, 0);
-            xpc_dictionary_set_bool(criteria, XPC_ACTIVITY_REPEATING, false);
-            xpc_dictionary_set_int64(criteria, XPC_ACTIVITY_DELAY, 0);
-            xpc_dictionary_set_int64(criteria, XPC_ACTIVITY_GRACE_PERIOD, 0);
-
-            xpc_dictionary_set_string(criteria, XPC_ACTIVITY_PRIORITY, XPC_ACTIVITY_PRIORITY_MAINTENANCE);
-            xpc_dictionary_set_bool(criteria, XPC_ACTIVITY_ALLOW_BATTERY, false);
-
-            xpc_activity_register(mXpcActivityName, criteria, ^(xpc_activity_t activity) {
-                dispatch_once(&mAssessmentKicked, ^{
-                    dispatch_semaphore_signal(mAssessmentLock);
-                });
-            });
-            xpc_release(criteria);
-        }
-    }
-
-    // If this is a foreground assessment to begin with, or if an assessment
-    // with an existing task has been requested in the foreground, kick it
-    // immediately.
-    if (!lowPriority) {
-        dispatch_once(&mAssessmentKicked, ^{
-            dispatch_semaphore_signal(mAssessmentLock);
-        });
-    }
-}
-
-
-
-void EvaluationTask::waitForCompletion(SecAssessmentFlags flags, CFMutableDictionaryRef result)
-{
-    // if the caller didn't request low priority we will elevate the dispatch
-    // queue priority via our wait block
-    dispatch_qos_class_t qos_class = QOS_CLASS_USER_INITIATED;
-    if (flags & kSecAssessmentFlagLowPriority)
-        qos_class = QOS_CLASS_UTILITY;
-
-    // wait for the assessment to complete; our wait block will queue up behind
-    // the assessment and the copy its results
-    dispatch_sync(mWorkQueue, dispatch_block_create_with_qos_class  (DISPATCH_BLOCK_ENFORCE_QOS_CLASS, qos_class, 0, ^{
-        // copy the class result back to the caller
-        cfDictionaryApplyBlock(mResult.get(), ^(const void *key, const void *value){
-            CFDictionaryAddValue(result, key, value);
-        });
-    }));
-
-    if (mExceptionToRethrow) std::rethrow_exception(mExceptionToRethrow);
-}
-
-
-
-#pragma mark -
-
-
-static Boolean evaluationTasksAreEqual(const EvaluationTask *task1, const EvaluationTask *task2)
-{
-    if (!task1->isSharable() || !task2->isSharable()) return false;
-    if ((task1->type() != task2->type()) ||
-        (cfString(task1->path()) != cfString(task2->path())))
-        return false;
-
-    return true;
-}
-
-
-
-
-#pragma mark - EvaluationManager
-
-
-EvaluationManager *EvaluationManager::globalManager()
-{
-    static EvaluationManager *singleton;
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        singleton = new EvaluationManager();
-    });
-    return singleton;
-}
-
-
-EvaluationManager::EvaluationManager()
-{
-    static CFDictionaryValueCallBacks evalTaskValueCallbacks = kCFTypeDictionaryValueCallBacks;
-    evalTaskValueCallbacks.equal = (CFDictionaryEqualCallBack)evaluationTasksAreEqual;
-    evalTaskValueCallbacks.retain = NULL;
-    evalTaskValueCallbacks.release = NULL;
-    mCurrentEvaluations.take(
-        CFDictionaryCreateMutable(NULL,
-                              0,
-                              &kCFTypeDictionaryKeyCallBacks,
-                              &evalTaskValueCallbacks));
-
-    mListLockQueue = dispatch_queue_create("EvaluationManagerSyncronization", 0);
-}
-
-
-EvaluationManager::~EvaluationManager()
-{
-    dispatch_release(mListLockQueue);
-}
-
-
-EvaluationTask *EvaluationManager::evaluationTask(PolicyEngine *engine, CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result)
-{
-    __block EvaluationTask *evalTask = NULL;
-
-    dispatch_sync(mListLockQueue, ^{
-        // is path already being evaluated?
-        if (!(flags & kSecAssessmentFlagIgnoreActiveAssessments))
-            evalTask = (EvaluationTask *)CFDictionaryGetValue(mCurrentEvaluations.get(), path);
-        if (!evalTask) {
-            // create a new task for the evaluation
-            evalTask = new EvaluationTask(engine, path, type);
-            if (flags & kSecAssessmentFlagIgnoreActiveAssessments)
-                evalTask->setUnsharable();
-            CFDictionaryAddValue(mCurrentEvaluations.get(), path, evalTask);
-        }
-        evalTask->mReferenceCount++;
-    });
-
-    if (evalTask)
-        evalTask->performEvaluation(flags, context);
-
-    return evalTask;
-}
-
-
-void EvaluationManager::waitForCompletion(EvaluationTask *task, SecAssessmentFlags flags, CFMutableDictionaryRef result)
-{
-    task->waitForCompletion(flags, result);
-}
-
-
-void EvaluationManager::removeTask(EvaluationTask *task)
-{
-    dispatch_sync(mListLockQueue, ^{
-        // are we done with this evaluation task?
-        if (--task->mReferenceCount == 0) {
-            // yes -- remove it from our list and delete the object
-            CFDictionaryRemoveValue(mCurrentEvaluations.get(), task->path());
-            delete task;
-        }
-    });
-}
-
-
-
-} // end namespace CodeSigning
-} // end namespace Security
-