]> git.saurik.com Git - apple/securityd.git/blobdiff - src/csproxy.cpp
securityd-55199.3.tar.gz
[apple/securityd.git] / src / csproxy.cpp
index 6511b439c361293d9d85025904b3516d8b11ce9a..11af7cc2c82cbccfc236a12f1ff4f32554a92b56 100644 (file)
 //
 #include "csproxy.h"
 #include "server.h"
+#include <Security/SecStaticCode.h>
 #include <securityd_client/cshosting.h>
+#include <security_utilities/cfmunge.h>
 
 
 //
 // Construct a CodeSigningHost
 //
 CodeSigningHost::CodeSigningHost()
-       : mHostingState(noHosting)
+       : mLock(Mutex::recursive), mHostingState(noHosting)
 {
 }
 
@@ -54,12 +56,14 @@ CodeSigningHost::~CodeSigningHost()
 //
 void CodeSigningHost::reset()
 {
+       StLock<Mutex> _(mLock);
        switch (mHostingState) {
        case noHosting:
                break;  // nothing to do
        case dynamicHosting:
                mHostingPort.destroy();
                mHostingPort = MACH_PORT_NULL;
+               SECURITYD_HOST_UNREGISTER(DTSELF);
                break;
        case proxyHosting:
                Server::active().remove(*this); // unhook service handler
@@ -67,6 +71,7 @@ void CodeSigningHost::reset()
                mHostingState = noHosting;
                mHostingPort = MACH_PORT_NULL;
                mGuests.erase(mGuests.begin(), mGuests.end());
+               SECURITYD_HOST_UNREGISTER(DTSELF);
                break;
        }
 }
@@ -84,7 +89,6 @@ CodeSigningHost::Guest *CodeSigningHost::findHost(SecGuestRef hostRef)
        for (;;) {
                if (Guest *guest = findGuest(host))
                        if (guest->dedicated) {
-                               secdebug("hosting", "%p selecting dedicated guest %p of %p", this, guest, host);
                                host = guest;
                                continue;
                        }
@@ -95,7 +99,7 @@ CodeSigningHost::Guest *CodeSigningHost::findHost(SecGuestRef hostRef)
 
 //
 // Look up guest by guestRef.
-// Throws if they we don't have a guest by that ref.
+// Throws if we don't have a guest by that ref.
 //
 CodeSigningHost::Guest *CodeSigningHost::findGuest(SecGuestRef guestRef, bool hostOk /* = false */)
 {
@@ -127,12 +131,10 @@ CodeSigningHost::Guest *CodeSigningHost::findGuest(Guest *host, const CssmData &
        if (CFNumberRef canonical = attrs.get<CFNumberRef>(kSecGuestAttributeCanonical)) {
                // direct lookup by SecGuestRef (canonical guest handle)
                SecGuestRef guestRef = cfNumber<SecGuestRef>(canonical);
-               secdebug("hosting", "host %p looking for guest handle 0x%x", host, guestRef);
                if (Guest *guest = findGuest(guestRef, true))   // found guest handle
-                       if (guest->isGuestOf(host, loose)) {
-                               secdebug("hosting", "found guest %p, continuing search", guest);
+                       if (guest->isGuestOf(host, loose))
                                host = guest;           // new starting point
-                       else
+                       else
                                MacOSError::throwMe(errSecCSNoSuchCode); // not a guest of given host
                else
                        MacOSError::throwMe(errSecCSNoSuchCode); // not there at all
@@ -143,7 +145,6 @@ CodeSigningHost::Guest *CodeSigningHost::findGuest(Guest *host, const CssmData &
        CFTypeRef keys[count], values[count];
        CFDictionaryGetKeysAndValues(attrs, keys, values);
        for (;;) {
-               secdebug("hosting", "searching host %p by attributes", host);
                Guest *match = NULL;    // previous match found
                for (GuestMap::const_iterator it = mGuests.begin(); it != mGuests.end(); ++it)
                        if (it->second->isGuestOf(host, strict))
@@ -152,13 +153,10 @@ CodeSigningHost::Guest *CodeSigningHost::findGuest(Guest *host, const CssmData &
                                                MacOSError::throwMe(errSecCSMultipleGuests);    // ambiguous
                                        else
                                                match = it->second;
-               if (!match) {           // nothing found
-                       secdebug("hosting", "nothing found, returning %p", host);
+               if (!match)             // nothing found
                        return host;
-               } else {
-                       secdebug("hosting", "found guest %p, continuing", match);
+               else
                        host = match;   // and repeat
-               }
        }
 }
 
@@ -184,12 +182,12 @@ CodeSigningHost::Guest *CodeSigningHost::findGuest(Guest *host)
 //
 void CodeSigningHost::registerCodeSigning(mach_port_t hostingPort, SecCSFlags flags)
 {
+       StLock<Mutex> _(mLock);
        switch (mHostingState) {
        case noHosting:
-               secdebug("hosting", "%p registering for dynamic hosting on port %d",
-                       this, hostingPort);
                mHostingPort = hostingPort;
                mHostingState = dynamicHosting;
+               SECURITYD_HOST_REGISTER(DTSELF, mHostingPort);
                break;
        default:
                MacOSError::throwMe(errSecCSHostProtocolContradiction);
@@ -203,35 +201,37 @@ void CodeSigningHost::registerCodeSigning(mach_port_t hostingPort, SecCSFlags fl
 // 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 &attributes, SecCSFlags flags)
+               uint32_t status, const char *path,
+               const CssmData &cdhash, const CssmData &attributes, SecCSFlags flags)
 {
-       secdebug("hosting", "%p create guest from host %d", this, hostRef);
-       
+       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:
+       case noHosting:                                                                         // first hosting call, this host
                // set up proxy hosting
-               mHostingPort.allocate();
-               MachServer::Handler::port(mHostingPort);
-               MachServer::active().add(*this);
-               mHostingState = proxyHosting;
-               secdebug("hosting", "%p created hosting port %d for proxy hosting", this, mHostingPort.port());
+               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
+               SECURITYD_HOST_PROXY(DTSELF, mHostingPort);
                break;
-       case proxyHosting:
-               break;          // all set
-       case dynamicHosting:
+       case proxyHosting:                                                                      // already proxying
+               break;
+       case dynamicHosting:                                                            // in dynamic mode, can't switch
                MacOSError::throwMe(errSecCSHostProtocolContradiction);
        }
        
        RefPointer<Guest> host = findHost(hostRef);
-       RefPointer<Guest> knownGuest = findGuest(host);
-       if ((flags & kSecCSDedicatedHost) && knownGuest)
-               MacOSError::throwMe(errSecCSHostProtocolDedicationError);       // can't dedicate with other guests
-       else if (knownGuest && knownGuest->dedicated)
-               MacOSError::throwMe(errSecCSHostProtocolDedicationError);       // other guest is already dedicated
+       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;
@@ -241,27 +241,31 @@ SecGuestRef CodeSigningHost::createGuest(SecGuestRef hostRef,
        guest->status = status;
        guest->path = path;
        guest->setAttributes(attributes);
+       guest->setHash(cdhash, flags & kSecCSGenerateGuestHash);
        guest->dedicated = (flags & kSecCSDedicatedHost);
        mGuests[guest->guestRef()] = guest;
-       secdebug("hosting", "guest 0x%x created %sstatus=0x%x path=%s",
-               guest->guestRef(), guest->dedicated ? "dedicated " : "", guest->status, guest->path.c_str());
+       SECURITYD_GUEST_CREATE(DTSELF, hostRef, guest->guestRef(), guest->status, flags, guest->path.c_str());
+       if (SECURITYD_GUEST_CDHASH_ENABLED())
+               SECURITYD_GUEST_CDHASH(DTSELF, guest->guestRef(),
+                       (void*)CFDataGetBytePtr(guest->cdhash), CFDataGetLength(guest->cdhash));
        return guest->guestRef();
 }
 
 
 void CodeSigningHost::setGuestStatus(SecGuestRef guestRef, uint32_t status, const CssmData &attributes)
 {
-       secdebug("hosting", "%p set guest 0x%x", this, guestRef);
+       StLock<Mutex> _(mLock);
        if (mHostingState != proxyHosting)
                MacOSError::throwMe(errSecCSHostProtocolNotProxy);
        Guest *guest = findGuest(guestRef);
 
        // state modification machine
-       if ((status & ~guest->status) & CS_VALID)
+       if ((status & ~guest->status) & kSecCodeStatusValid)
                MacOSError::throwMe(errSecCSHostProtocolStateError); // can't set
-       if ((~status & guest->status) & (CS_HARD | CS_KILL))
+       if ((~status & guest->status) & (kSecCodeStatusHard | kSecCodeStatusKill))
                MacOSError::throwMe(errSecCSHostProtocolStateError); // can't clear
        guest->status = status;
+       SECURITYD_GUEST_CHANGE(DTSELF, guestRef, status);
 
        // replace attributes if requested
        if (attributes)
@@ -274,7 +278,7 @@ void CodeSigningHost::setGuestStatus(SecGuestRef guestRef, uint32_t status, cons
 //
 void CodeSigningHost::removeGuest(SecGuestRef hostRef, SecGuestRef guestRef)
 {
-       secdebug("hosting", "%p removes guest %d from host %d", this, guestRef, hostRef);
+       StLock<Mutex> _(mLock);
        if (mHostingState != proxyHosting) 
                MacOSError::throwMe(errSecCSHostProtocolNotProxy);
        RefPointer<Guest> host = findHost(hostRef);
@@ -284,8 +288,10 @@ void CodeSigningHost::removeGuest(SecGuestRef hostRef, SecGuestRef guestRef)
        if (!guest->isGuestOf(host, strict))
                MacOSError::throwMe(errSecCSHostProtocolUnrelated);
        for (GuestMap::iterator it = mGuests.begin(); it != mGuests.end(); ++it)
-               if (it->second->isGuestOf(guest, loose))
+               if (it->second->isGuestOf(guest, loose)) {
+                       SECURITYD_GUEST_DESTROY(DTSELF, it->first);
                        mGuests.erase(it);
+               }
 }
 
 
@@ -293,23 +299,45 @@ void CodeSigningHost::removeGuest(SecGuestRef hostRef, SecGuestRef guestRef)
 // The internal Guest object
 //
 CodeSigningHost::Guest::~Guest()
-{
-       secdebug("hosting", "guest %ld destroyed", handle());
-}
+{ }
 
 void CodeSigningHost::Guest::setAttributes(const CssmData &attrData)
 {
        CFRef<CFNumberRef> guest = makeCFNumber(guestRef());
        if (attrData) {
-               CFRef<CFDictionaryRef> inputDict = makeCFDictionaryFrom(attrData.data(), attrData.length());
-               CFRef<CFMutableDictionaryRef> dict = CFDictionaryCreateMutableCopy(NULL, 0, inputDict);
-               CFDictionaryAddValue(dict, kSecGuestAttributeCanonical, guest);
-               attributes.take(dict);
+               attributes.take(cfmake<CFDictionaryRef>("{+%O,%O=%O}",
+                       makeCFDictionaryFrom(attrData.data(), attrData.length()), kSecGuestAttributeCanonical, guest.get()));
        } else {
                attributes.take(makeCFDictionary(1, kSecGuestAttributeCanonical, guest.get()));
        }
 }
 
+CFDataRef CodeSigningHost::Guest::attrData() const
+{
+       if (!mAttrData)
+               mAttrData = makeCFData(this->attributes.get());
+       return mAttrData;
+}
+
+
+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
 {
@@ -355,12 +383,20 @@ bool CodeSigningHost::Guest::matches(CFIndex count, CFTypeRef keys[], CFTypeRef
 //
 // The MachServer dispatch handler for proxy hosting.
 //
+
+// give MIG handlers access to the object lock
+struct CodeSigningHost::Lock : private StLock<Mutex> {
+       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);
 }
@@ -416,10 +452,26 @@ kern_return_t cshosting_server_findGuest(CSH_ARGS, SecGuestRef hostRef,
 //
 // Retrieve the path to a guest specified by canonical reference.
 //
-kern_return_t cshosting_server_guestPath(CSH_ARGS, SecGuestRef guestRef, char *path)
+kern_return_t cshosting_server_identifyGuest(CSH_ARGS, SecGuestRef guestRef,
+       char *path, char *hash, uint32_t *hashLength, DATA_OUT(attributes))
 {
        BEGIN_IPC
-       strncpy(path, context()->findGuest(guestRef)->path.c_str(), MAXPATHLEN);
+       CodeSigningHost::Guest *guest = context()->findGuest(guestRef);
+       strncpy(path, guest->path.c_str(), MAXPATHLEN);
+
+       // canonical cdhash
+       if (guest->cdhash) {
+               *hashLength = 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
+       CFDataRef attrData = guest->attrData(); // (the guest will cache this until it dies)
+       *attributes = (void *)CFDataGetBytePtr(attrData);       // MIG botch (it doesn't need a writable pointer)
+       *attributesLength = CFDataGetLength(attrData);
+       
        END_IPC
 }
 
@@ -442,6 +494,7 @@ kern_return_t cshosting_server_guestStatus(CSH_ARGS, SecGuestRef guestRef, uint3
 
 void CodeSigningHost::dump() const
 {
+       StLock<Mutex> _(mLock);
        switch (mHostingState) {
        case noHosting:
                break;