]> git.saurik.com Git - apple/securityd.git/blobdiff - src/clientid.cpp
securityd-32661.tar.gz
[apple/securityd.git] / src / clientid.cpp
diff --git a/src/clientid.cpp b/src/clientid.cpp
new file mode 100644 (file)
index 0000000..b04b7c6
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2007 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@
+ */
+//
+// clientid - track and manage identity of securityd clients
+//
+#include "clientid.h"
+#include "server.h"
+#include "osxcodewrap.h"
+
+
+//
+// Constructing a ClientIdentification doesn't do much.
+// We're waiting for setup(), which should be called by the child class's
+// constructor.
+//
+ClientIdentification::ClientIdentification()
+{
+}
+
+
+//
+// Initialize the ClientIdentification.
+// This creates a process-level code object for the client.
+//
+void ClientIdentification::setup(pid_t pid)
+{
+       if (IFDEBUG(OSStatus rc =)SecCodeCreateWithPID(pid, kSecCSDefaultFlags,
+                       &mClientProcess.aref()))
+               secdebug("clientid", "could not get code for process %d: OSStatus=%ld",
+                       pid, rc);
+}
+
+
+//
+// Return a SecCodeRef for the client process itself, regardless of
+// which guest within it is currently active.
+// Think twice before using this.
+//
+SecCodeRef ClientIdentification::processCode() const
+{
+       return mClientProcess;
+}
+
+
+//
+// Return a SecCodeRef for the currently active guest within the client
+// process.
+//
+// We make a fair effort to cache client guest identities without over-growing
+// the cache. Note that there's currently no protocol for being notified of
+// a guest's death or disappearance (independent from the host process's death),
+// so we couldn't track guests live even if we tried.
+//
+// Note that this consults Server::connection for the currently serviced
+// Connection object, so this is not entirely a function of ClientIdentification state.
+//
+SecCodeRef ClientIdentification::currentGuest() const
+{
+       if (GuestState *guest = current())
+               return guest->code;
+       else
+               return mClientProcess;
+}
+
+ClientIdentification::GuestState *ClientIdentification::current() const
+{
+       // if we have no client identification, we can't find a current guest either
+       if (!processCode())
+               return NULL;
+
+       SecGuestRef guestRef = Server::connection().guestRef();
+       
+       // try to deliver an already-cached entry
+       {
+               StLock<Mutex> _(mLock);
+               GuestMap::iterator it = mGuests.find(guestRef);
+               if (it != mGuests.end())
+                       return &it->second;
+       }
+
+       // okay, make a new one (this may take a while)
+       CFRef<CFDictionaryRef> attributes = (guestRef == kSecNoGuest)
+               ? NULL
+               : makeCFDictionary(1, kSecGuestAttributeCanonical, CFTempNumber(guestRef).get());
+       Server::active().longTermActivity();
+       CFRef<SecCodeRef> code;
+       switch (OSStatus rc = SecCodeCopyGuestWithAttributes(processCode(),
+               attributes, kSecCSDefaultFlags, &code.aref())) {
+       case noErr:
+               break;
+       case errSecCSUnsigned:                  // not signed; clearly not a host
+       case errSecCSNotAHost:                  // signed but not marked as a (potential) host
+               code = mClientProcess;
+               break;
+       case errSecCSNoSuchCode:                // potential host, but...
+               if (guestRef == kSecNoGuest) {  //  ... no guests (yet), so return the process
+                       code = mClientProcess;
+                       break;
+               }
+               // else fall through            //  ... the guest we expected to be there isn't
+       default:
+               MacOSError::throwMe(rc);
+       }
+       StLock<Mutex> _(mLock);
+       GuestState &slot = mGuests[guestRef];
+       if (!slot.code) // if another thread didn't get here first...
+               slot.code = code;
+       return &slot;
+}
+
+
+//
+// Support for the legacy hash identification mechanism.
+// The legacy machinery deals exclusively in terms of processes.
+// It knows nothing about guests and their identities.
+//
+string ClientIdentification::getPath() const
+{
+       assert(mClientProcess);
+       return codePath(currentGuest());
+}
+
+const CssmData ClientIdentification::getHash() const
+{
+       if (GuestState *guest = current()) {
+               if (!guest->gotHash) {
+                       RefPointer<OSXCode> clientCode = new OSXCodeWrap(guest->code);
+                       OSXVerifier::makeLegacyHash(clientCode, guest->legacyHash);
+                       guest->gotHash = true;
+               }
+               return CssmData::wrap(guest->legacyHash, SHA1::digestLength);
+       } else
+               return CssmData();
+}
+
+
+//
+// Bonus function: get the path out of a SecCodeRef
+//
+std::string codePath(SecStaticCodeRef code)
+{
+       CFRef<CFURLRef> path;
+       MacOSError::check(SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref()));
+       return cfString(path);
+}
+
+
+//
+// Debug dump support
+//
+#if defined(DEBUGDUMP)
+
+static void dumpCode(SecCodeRef code)
+{
+       CFRef<CFURLRef> path;
+       if (OSStatus rc = SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref()))
+               Debug::dump("unknown(rc=%ld)", rc);
+       else
+               Debug::dump("%s", cfString(path).c_str());
+}
+
+void ClientIdentification::dump()
+{
+       Debug::dump(" client=");
+       dumpCode(mClientProcess);
+       for (GuestMap::const_iterator it = mGuests.begin(); it != mGuests.end(); ++it) {
+               Debug::dump(" guest(0x%x)=", it->first);
+               dumpCode(it->second.code);
+               if (it->second.gotHash)
+                       Debug::dump(" [got hash]");
+       }
+}
+
+#endif //DEBUGDUMP