X-Git-Url: https://git.saurik.com/apple/securityd.git/blobdiff_plain/ed7595be5e083c75d54eca237d14322e52887b0d..f7aa9f666a1c7ab343b4ce8f1677ea253c4e126e:/src/clientid.cpp?ds=inline diff --git a/src/clientid.cpp b/src/clientid.cpp new file mode 100644 index 0000000..b04b7c6 --- /dev/null +++ b/src/clientid.cpp @@ -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 _(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 attributes = (guestRef == kSecNoGuest) + ? NULL + : makeCFDictionary(1, kSecGuestAttributeCanonical, CFTempNumber(guestRef).get()); + Server::active().longTermActivity(); + CFRef 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 _(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 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 path; + MacOSError::check(SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref())); + return cfString(path); +} + + +// +// Debug dump support +// +#if defined(DEBUGDUMP) + +static void dumpCode(SecCodeRef code) +{ + CFRef 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