]> git.saurik.com Git - apple/security.git/blobdiff - securityd/src/csproxy.cpp
Security-59306.11.20.tar.gz
[apple/security.git] / securityd / src / csproxy.cpp
diff --git a/securityd/src/csproxy.cpp b/securityd/src/csproxy.cpp
deleted file mode 100644 (file)
index 5ca68c6..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * Copyright (c) 2006-2010 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@
- */
-
-
-//
-// csproxy - Code Signing Hosting Proxy
-//
-#include <set>
-
-#include "csproxy.h"
-#include "server.h"
-#include <Security/SecStaticCode.h>
-#include <securityd_client/cshosting.h>
-#include <security_utilities/cfmunge.h>
-#include <security_utilities/casts.h>
-#include <utilities/SecCFRelease.h>
-
-//
-// Construct a CodeSigningHost
-//
-CodeSigningHost::CodeSigningHost()
-       : mLock(Mutex::recursive), mHostingState(noHosting)
-{
-}
-
-
-//
-// Cleanup code.
-//
-CodeSigningHost::~CodeSigningHost()
-{
-       reset();
-}
-
-
-//
-// Reset Code Signing Hosting state.
-// This turns hosting off and clears all children.
-//
-void CodeSigningHost::reset()
-{
-       StLock<Mutex> _(mLock);
-       switch (mHostingState) {
-       case noHosting:
-               break;  // nothing to do
-       case dynamicHosting:
-               mHostingPort.deallocate();
-        secnotice("SecServer", "%d host unregister", mHostingPort.port());
-               break;
-       case proxyHosting:
-               Server::active().remove(*this); // unhook service handler
-               mHostingPort.modRefs(MACH_PORT_RIGHT_RECEIVE, -1);
-               mHostingState = noHosting;
-               mHostingPort = MACH_PORT_NULL;
-               mGuests.erase(mGuests.begin(), mGuests.end());
-        secnotice("SecServer", "%d host unregister", mHostingPort.port());
-               break;
-       }
-}
-
-
-//
-// Given a host reference (possibly NULL for the process itself), locate
-// its most dedicated guest. This descends a contiguous chain of dedicated
-// guests until it find a host that either has no guests, or whose guests
-// are not dedicated.
-//
-CodeSigningHost::Guest *CodeSigningHost::findHost(SecGuestRef hostRef)
-{
-       Guest *host = findGuest(hostRef, true);
-       for (;;) {
-               if (Guest *guest = findGuest(host))
-                       if (guest->dedicated) {
-                               host = guest;
-                               continue;
-                       }
-               return host;
-       }
-}
-
-
-//
-// Look up guest by guestRef.
-// Throws if we don't have a guest by that ref.
-//
-CodeSigningHost::Guest *CodeSigningHost::findGuest(SecGuestRef guestRef, bool hostOk /* = false */)
-{
-       GuestMap::iterator it = mGuests.find(guestRef);
-    if (it == mGuests.end()) {
-        if (hostOk) {
-                       return NULL;
-        } else {
-                       MacOSError::throwMe(errSecCSNoSuchCode);
-        }
-    }
-       assert(it->first == it->second->guestRef());
-       return it->second;
-}
-
-
-//
-// Look up guest by attribute set.
-// Returns the host if the attributes can't be found (*loose* interpretation).
-// Throws if multiple guests are found (ambiguity).
-// Implicitly matches dedicated guests no matter what attributes are requested.
-//
-CodeSigningHost::Guest *CodeSigningHost::findGuest(Guest *host, const CssmData &attrData)
-{
-       CFRef<CFDictionaryRef> attrDict = attrData
-               ? makeCFDictionaryFrom(attrData.data(), attrData.length())
-               : makeCFDictionary(0);
-       CFDictionary attrs(attrDict, errSecCSInvalidAttributeValues);
-       
-       // if a guest handle was provided, start with that - it must be valid or we fail
-       if (CFNumberRef canonical = attrs.get<CFNumberRef>(kSecGuestAttributeCanonical)) {
-               // direct lookup by SecGuestRef (canonical guest handle)
-               SecGuestRef guestRef = cfNumber<SecGuestRef>(canonical);
-               if (Guest *guest = findGuest(guestRef, true))   // found guest handle
-                       if (guest->isGuestOf(host, loose))
-                               host = guest;           // new starting point
-                       else
-                               MacOSError::throwMe(errSecCSNoSuchCode); // not a guest of given host
-               else
-                       MacOSError::throwMe(errSecCSNoSuchCode); // not there at all
-       }
-       
-       // now take the rest of the attrs
-       CFIndex count = CFDictionaryGetCount(attrs);
-
-       CFTypeRef *keys   = (CFTypeRef*)malloc(count*sizeof(CFTypeRef));
-       CFTypeRef *values = (CFTypeRef*)malloc(count*sizeof(CFTypeRef));
-
-       if (keys == NULL || values == NULL) {
-               free(keys);
-               free(values);
-               MacOSError::throwMe(errSecMemoryError);
-       }
-
-       CFDictionaryGetKeysAndValues(attrs, keys, values);
-       for (;;) {
-               Guest *match = NULL;    // previous match found
-        for (GuestMap::const_iterator it = mGuests.begin(); it != mGuests.end(); ++it) {
-            if (it->second->isGuestOf(host, strict)) {
-                if (it->second->matches(count, keys, values)) {
-                    if (match) {
-                                               free(keys);
-                                               free(values);
-                                               MacOSError::throwMe(errSecCSMultipleGuests);    // ambiguous
-                    } else {
-                                               match = it->second;
-                    }
-                }
-            }
-        }
-               if (!match) { // nothing found
-                       free(keys);
-                       free(values);
-                       return host;
-               }
-               else {
-                       host = match;   // and repeat
-               }
-       }
-}
-
-
-//
-// Find any guest of a given host.
-// This will return a randomly chosen guest of this host if it has any,
-// or NULL if it has none (i.e. it is not a host).
-//
-CodeSigningHost::Guest *CodeSigningHost::findGuest(Guest *host)
-{
-       for (GuestMap::const_iterator it = mGuests.begin(); it != mGuests.end(); ++it)
-               if (it->second->isGuestOf(host, strict))
-                       return it->second;
-       return NULL;
-}
-
-
-//
-// Register a hosting API service port where the host will dynamically
-// answer hosting queries from interested parties. This switches the process
-// to dynamic hosting mode, and is incompatible with proxy hosting.
-//
-void CodeSigningHost::registerCodeSigning(mach_port_t hostingPort, SecCSFlags flags)
-{
-       StLock<Mutex> _(mLock);
-       switch (mHostingState) {
-       case noHosting:
-               mHostingPort = hostingPort;
-               mHostingState = dynamicHosting;
-        secnotice("SecServer", "%d host register: %d", mHostingPort.port(), mHostingPort.port());
-               break;
-       default:
-               MacOSError::throwMe(errSecCSHostProtocolContradiction);
-       }
-}
-
-
-//
-// Create a guest entry for the given host and prepare to answer for it
-// when dynamic hosting queries are received for it.
-// This engages proxy hosting mode, and is incompatible with dynamic hosting mode.
-//
-SecGuestRef CodeSigningHost::createGuest(SecGuestRef hostRef,
-               uint32_t status, const char *path,
-               const CssmData &cdhash, const CssmData &attributes, SecCSFlags flags)
-{
-       StLock<Mutex> _(mLock);
-       if (path[0] != '/')             // relative path (relative to what? :-)
-               MacOSError::throwMe(errSecCSHostProtocolRelativePath);
-       if (cdhash.length() > maxUcspHashLength)
-               MacOSError::throwMe(errSecCSHostProtocolInvalidHash);
-       
-       // set up for hosting proxy services if nothing's there yet
-       switch (mHostingState) {
-       case noHosting:                                                                         // first hosting call, this host
-               // set up proxy hosting
-               mHostingPort.allocate();                                                // allocate service port
-               MachServer::Handler::port(mHostingPort);                // put into Handler
-               MachServer::active().add(*this);                                // start listening
-               mHostingState = proxyHosting;                                   // now proxying for this host
-        secnotice("SecServer", "%d host proxy: %d", mHostingPort.port(), mHostingPort.port());
-               break;
-       case proxyHosting:                                                                      // already proxying
-               break;
-       case dynamicHosting:                                                            // in dynamic mode, can't switch
-               MacOSError::throwMe(errSecCSHostProtocolContradiction);
-       }
-       
-       RefPointer<Guest> host = findHost(hostRef);
-    if (RefPointer<Guest> knownGuest = findGuest(host)) {      // got a guest already
-        if (flags & kSecCSDedicatedHost) {
-                       MacOSError::throwMe(errSecCSHostProtocolDedicationError);       // can't dedicate with other guests
-        } else if (knownGuest->dedicated) {
-                       MacOSError::throwMe(errSecCSHostProtocolDedicationError);       // other guest is already dedicated
-        }
-    }
-
-       // create the new guest
-       RefPointer<Guest> guest = new Guest;
-       if (host)
-               guest->guestPath = host->guestPath;
-       guest->guestPath.push_back(int_cast<CSSM_HANDLE,SecGuestRef>(guest->handle()));
-       guest->status = status;
-       guest->path = path;
-       guest->setAttributes(attributes);
-       guest->setHash(cdhash, flags & kSecCSGenerateGuestHash);
-       guest->dedicated = (flags & kSecCSDedicatedHost);
-       mGuests[guest->guestRef()] = guest;
-    secnotice("SecServer", "%d guest create %d %d status:%d %d %s", mHostingPort.port(), hostRef, guest->guestRef(), guest->status, flags, guest->path.c_str());
-       return guest->guestRef();
-}
-
-
-void CodeSigningHost::setGuestStatus(SecGuestRef guestRef, uint32_t status, const CssmData &attributes)
-{
-       StLock<Mutex> _(mLock);
-       if (mHostingState != proxyHosting)
-               MacOSError::throwMe(errSecCSHostProtocolNotProxy);
-       Guest *guest = findGuest(guestRef);
-
-       // state modification machine
-       if ((status & ~guest->status) & kSecCodeStatusValid)
-               MacOSError::throwMe(errSecCSHostProtocolStateError); // can't set
-       if ((~status & guest->status) & (kSecCodeStatusHard | kSecCodeStatusKill))
-               MacOSError::throwMe(errSecCSHostProtocolStateError); // can't clear
-       guest->status = status;
-    secnotice("SecServer", "%d guest change %d %d", mHostingPort.port(), guestRef, status);
-
-       // replace attributes if requested
-       if (attributes)
-               guest->setAttributes(attributes);
-}
-
-
-//
-// Remove a guest previously introduced via createGuest().
-//
-void CodeSigningHost::removeGuest(SecGuestRef hostRef, SecGuestRef guestRef)
-{
-       StLock<Mutex> _(mLock);
-       if (mHostingState != proxyHosting) 
-               MacOSError::throwMe(errSecCSHostProtocolNotProxy);
-       RefPointer<Guest> host = findHost(hostRef);
-       RefPointer<Guest> guest = findGuest(guestRef);
-       if (guest->dedicated)   // can't remove a dedicated guest
-               MacOSError::throwMe(errSecCSHostProtocolDedicationError);
-       if (!guest->isGuestOf(host, strict))
-               MacOSError::throwMe(errSecCSHostProtocolUnrelated);
-
-    set<SecGuestRef> matchingGuests;
-
-    for (auto &it : mGuests) {
-               if (it.second->isGuestOf(guest, loose)) {
-            matchingGuests.insert(it.first);
-               }
-    }
-
-    for (auto &it : matchingGuests) {
-        secnotice("SecServer", "%d guest destroy %d", mHostingPort.port(), it);
-        mGuests.erase(it);
-    }
-}
-
-
-//
-// The internal Guest object
-//
-CodeSigningHost::Guest::Guest() : mAttrData(NULL), mAttrDataLength(0)
-{
-}
-
-CodeSigningHost::Guest::~Guest()
-{
-    if (mAttrData != NULL) {
-        vm_size_t rounded_size = mach_vm_round_page(mAttrDataLength);
-        vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(mAttrData), rounded_size);
-    }
-}
-
-void CodeSigningHost::Guest::setAttributes(const CssmData &attrData)
-{
-       CFRef<CFNumberRef> guest = makeCFNumber(guestRef());
-       if (attrData) {
-        CFDictionaryRef attrs = makeCFDictionaryFrom(attrData.data(), attrData.length());
-               attributes.take(cfmake<CFDictionaryRef>("{+%O,%O=%O}",
-                       attrs, kSecGuestAttributeCanonical, guest.get()));
-        CFReleaseNull(attrs);
-       } else {
-               attributes.take(makeCFDictionary(1, kSecGuestAttributeCanonical, guest.get()));
-       }
-}
-
-void CodeSigningHost::Guest::createAttrData() const {
-    if (!mAttrData) {
-        CFRef<CFDataRef> data = makeCFData(this->attributes.get());
-        
-        /* cshosting_server_identifyGuest() will point to the attrData in a MIG
-         * OOL buffer. To prevent leaking surrounding memory, the attr data gets its
-         * own (zeroed) pages. */
-        vm_address_t addr = 0;
-        vm_size_t rounded_size = mach_vm_round_page(CFDataGetLength(data.get()));
-        kern_return_t ret = vm_allocate(mach_task_self(), &addr, rounded_size, VM_FLAGS_ANYWHERE);
-        
-        if (ret == KERN_SUCCESS) {
-            mAttrData = reinterpret_cast<uint8_t *>(addr);
-            mAttrDataLength = CFDataGetLength(data.get());
-            memcpy(mAttrData, CFDataGetBytePtr(data.get()), mAttrDataLength);
-            // pages returned by vm_allocate are zeroed, no need to fill out padding.
-        } else {
-            secerror("csproxy attrData vm_allocate failed: %d", ret);
-        }
-    }
-}
-
-void CodeSigningHost::Guest::setHash(const CssmData &given, bool generate)
-{
-       if (given.length())             // explicitly given
-               this->cdhash.take(makeCFData(given));
-       else if (CFTypeRef hash = CFDictionaryGetValue(this->attributes, kSecGuestAttributeHash))
-               if (CFGetTypeID(hash) == CFDataGetTypeID())
-                       this->cdhash = CFDataRef(hash);
-               else
-                       MacOSError::throwMe(errSecCSHostProtocolInvalidHash);
-       else if (generate) {            // generate from path (well, try)
-               CFRef<SecStaticCodeRef> code;
-               MacOSError::check(SecStaticCodeCreateWithPath(CFTempURL(this->path), kSecCSDefaultFlags, &code.aref()));
-               CFRef<CFDictionaryRef> info;
-               MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref()));
-               this->cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique));
-       }
-}
-
-
-bool CodeSigningHost::Guest::isGuestOf(Guest *host, GuestCheck check) const
-{
-       vector<SecGuestRef> hostPath;
-       if (host)
-               hostPath = host->guestPath;
-       if (hostPath.size() <= guestPath.size()
-                       && !memcmp(&hostPath[0], &guestPath[0], sizeof(SecGuestRef) * hostPath.size()))
-               // hostPath is a prefix of guestPath
-               switch (check) {
-               case loose:
-                       return true;
-               case strict:
-                       return guestPath.size() == hostPath.size() + 1; // immediate guest
-               }
-       return false;
-}
-
-
-//
-// Check to see if a given guest matches the (possibly empty) attribute set provided
-// (in broken-open form, for efficiency). A dedicated guest will match all attribute
-// specifications, even empty ones. A non-dedicated guest matches if at least one
-// attribute value requested matches exactly (in the sense of CFEqual) that given
-// by the host for this guest.
-// 
-bool CodeSigningHost::Guest::matches(CFIndex count, CFTypeRef keys[], CFTypeRef values[]) const
-{
-       if (dedicated)
-               return true;
-       for (CFIndex n = 0; n < count; n++) {
-               CFStringRef key = CFStringRef(keys[n]);
-               if (CFEqual(key, kSecGuestAttributeCanonical))  // ignore canonical attribute (handled earlier)
-                       continue;
-               if (CFTypeRef value = CFDictionaryGetValue(attributes, key))
-                       if (CFEqual(value, values[n]))
-                               return true;
-       }
-       return false;
-}
-
-
-//
-// The MachServer dispatch handler for proxy hosting.
-//
-
-// give MIG handlers access to the object lock
-class CodeSigningHost::Lock : private StLock<Mutex> {
-public:
-       Lock(CodeSigningHost *host) : StLock<Mutex>(host->mLock) { }
-};
-
-
-boolean_t cshosting_server(mach_msg_header_t *, mach_msg_header_t *);
-
-static ThreadNexus<CodeSigningHost *> context;
-
-boolean_t CodeSigningHost::handle(mach_msg_header_t *in, mach_msg_header_t *out)
-{
-       CodeSigningHost::Lock _(this);
-       context() = this;
-       return cshosting_server(in, out);
-}
-
-
-//
-// Proxy implementation of Code Signing Hosting protocol
-//
-#define CSH_ARGS       mach_port_t servicePort, mach_port_t replyPort, OSStatus *rcode
-       
-#define BEGIN_IPC      try {
-#define END_IPC                *rcode = noErr; } \
-       catch (const CommonError &err) { *rcode = err.osStatus(); } \
-       catch (...) { *rcode = errSecCSInternalError; } \
-       return KERN_SUCCESS;
-
-#define DATA_IN(base)  void *base, mach_msg_type_number_t base##Length
-#define DATA_OUT(base) void **base, mach_msg_type_number_t *base##Length
-#define DATA(base)             CssmData(base, base##Length)
-
-
-//
-// Find a guest by arbitrary attribute set.
-//
-// This returns an array of canonical guest references describing the path
-// from the host given to the guest found. If the host itself is returned
-// as a guest, this will be an empty array (zero length).
-//
-// The subhost return argument may in the future return the hosting port for
-// a guest who dynamically manages its hosting (thus breaking out of proxy mode),
-// but this is not yet implemented.
-//
-kern_return_t cshosting_server_findGuest(CSH_ARGS, SecGuestRef hostRef,
-       DATA_IN(attributes),
-       GuestChain *foundGuest, mach_msg_type_number_t *depth, mach_port_t *subhost)
-{
-       BEGIN_IPC
-               
-       *subhost = MACH_PORT_NULL;      // preset no sub-hosting port returned
-       
-       Process::Guest *host = context()->findGuest(hostRef, true);
-       if (Process::Guest *guest = context()->findGuest(host, DATA(attributes))) {
-               *foundGuest = &guest->guestPath[0];
-               *depth = int_cast<size_t, mach_msg_type_number_t>(guest->guestPath.size());
-       } else {
-               *foundGuest = NULL;
-               *depth = 0;
-       }
-       END_IPC
-}
-
-
-//
-// Retrieve the path to a guest specified by canonical reference.
-//
-kern_return_t cshosting_server_identifyGuest(CSH_ARGS, SecGuestRef guestRef,
-       char *path, char *hash, uint32_t *hashLength, DATA_OUT(attributes))
-{
-       BEGIN_IPC
-       CodeSigningHost::Guest *guest = context()->findGuest(guestRef);
-       strncpy(path, guest->path.c_str(), MAXPATHLEN);
-
-       // canonical cdhash
-       if (guest->cdhash) {
-               *hashLength = int_cast<size_t, uint32_t>(CFDataGetLength(guest->cdhash));
-               assert(*hashLength <= maxUcspHashLength);
-               memcpy(hash, CFDataGetBytePtr(guest->cdhash), *hashLength);
-       } else
-               *hashLength = 0;        // unavailable
-
-       // visible attributes. This proxy returns all attributes set by the host
-    *attributes = (void*)guest->attrData(); // MIG botch (it doesn't need a writable pointer)
-    *attributesLength = int_cast<CFIndex, mach_msg_type_number_t>(guest->attrDataLength());
-       
-       END_IPC
-}
-
-
-//
-// Retrieve the status word for a guest specified by canonical reference.
-//
-kern_return_t cshosting_server_guestStatus(CSH_ARGS, SecGuestRef guestRef, uint32_t *status)
-{
-       BEGIN_IPC
-       *status = context()->findGuest(guestRef)->status;
-       END_IPC
-}
-
-
-//
-// Debug support
-//
-#if defined(DEBUGDUMP)
-
-void CodeSigningHost::dump() const
-{
-       StLock<Mutex> _(mLock);
-       switch (mHostingState) {
-       case noHosting:
-               break;
-       case dynamicHosting:
-               Debug::dump(" dynamic host port=%d", mHostingPort.port());
-               break;
-       case proxyHosting:
-               Debug::dump(" proxy-host port=%d", mHostingPort.port());
-               if (!mGuests.empty()) {
-                       Debug::dump(" %d guests={", int(mGuests.size()));
-                       for (GuestMap::const_iterator it = mGuests.begin(); it != mGuests.end(); ++it) {
-                               if (it != mGuests.begin())
-                                       Debug::dump(", ");
-                               it->second->dump();
-                       }
-                       Debug::dump("}");
-               }
-               break;
-       }
-}
-
-void CodeSigningHost::Guest::dump() const
-{
-       Debug::dump("%s[", path.c_str());
-       for (vector<SecGuestRef>::const_iterator it = guestPath.begin(); it != guestPath.end(); ++it) {
-               if (it != guestPath.begin())
-                       Debug::dump("/");
-               Debug::dump("0x%x", *it);
-       }
-       Debug::dump("; status=0x%x attrs=%s]",
-               status, cfStringRelease(CFCopyDescription(attributes)).c_str());
-}
-
-#endif //DEBUGDUMP