2  * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  24 // clientid - track and manage identity of securityd clients 
  28 #include <Security/SecCodePriv.h> 
  32 // Constructing a ClientIdentification doesn't do much. 
  33 // We're waiting for setup(), which should be called by the child class's 
  36 ClientIdentification::ClientIdentification() 
  42 // Initialize the ClientIdentification. 
  43 // This creates a process-level code object for the client. 
  45 void ClientIdentification::setup(pid_t pid
) 
  47         StLock
<Mutex
> _(mLock
); 
  48         if (OSStatus rc 
= SecCodeCreateWithPID(pid
, kSecCSDefaultFlags
, 
  49                         &mClientProcess
.aref())) 
  50                 secdebug("clientid", "could not get code for process %d: OSStatus=%d", 
  52         mGuests
.erase(mGuests
.begin(), mGuests
.end()); 
  57 // Return a SecCodeRef for the client process itself, regardless of 
  58 // which guest within it is currently active. 
  59 // Think twice before using this. 
  61 SecCodeRef 
ClientIdentification::processCode() const 
  63         return mClientProcess
; 
  68 // Return a SecCodeRef for the currently active guest within the client 
  71 // We make a fair effort to cache client guest identities without over-growing 
  72 // the cache. Note that there's currently no protocol for being notified of 
  73 // a guest's death or disappearance (independent from the host process's death), 
  74 // so we couldn't track guests live even if we tried. 
  76 // Note that this consults Server::connection for the currently serviced 
  77 // Connection object, so this is not entirely a function of ClientIdentification state. 
  79 SecCodeRef 
ClientIdentification::currentGuest() const 
  81         if (GuestState 
*guest 
= current()) 
  84                 return mClientProcess
; 
  87 ClientIdentification::GuestState 
*ClientIdentification::current() const 
  89         // if we have no client identification, we can't find a current guest either 
  93         SecGuestRef guestRef 
= Server::connection().guestRef(); 
  95         // try to deliver an already-cached entry 
  97                 StLock
<Mutex
> _(mLock
); 
  98                 GuestMap::iterator it 
= mGuests
.find(guestRef
); 
  99                 if (it 
!= mGuests
.end()) 
 103         // okay, make a new one (this may take a while) 
 104         CFRef
<CFDictionaryRef
> attributes 
= (guestRef 
== kSecNoGuest
) 
 106                 : makeCFDictionary(1, kSecGuestAttributeCanonical
, CFTempNumber(guestRef
).get()); 
 107         Server::active().longTermActivity(); 
 108         CFRef
<SecCodeRef
> code
; 
 109         switch (OSStatus rc 
= SecCodeCopyGuestWithAttributes(processCode(), 
 110                 attributes
, kSecCSDefaultFlags
, &code
.aref())) { 
 113         case errSecCSUnsigned
:                  // not signed; clearly not a host 
 114         case errSecCSNotAHost
:                  // signed but not marked as a (potential) host 
 115                 code 
= mClientProcess
; 
 117         case errSecCSNoSuchCode
:                // potential host, but... 
 118                 if (guestRef 
== kSecNoGuest
) {  //  ... no guests (yet), so return the process 
 119                         code 
= mClientProcess
; 
 122                 // else fall through            //  ... the guest we expected to be there isn't 
 124                 MacOSError::throwMe(rc
); 
 126         StLock
<Mutex
> _(mLock
); 
 127         GuestState 
&slot 
= mGuests
[guestRef
]; 
 128         if (!slot
.code
) // if another thread didn't get here first... 
 135 // Support for the legacy hash identification mechanism. 
 136 // The legacy machinery deals exclusively in terms of processes. 
 137 // It knows nothing about guests and their identities. 
 139 string 
ClientIdentification::getPath() const 
 141         assert(mClientProcess
); 
 142         return codePath(currentGuest()); 
 145 const CssmData 
ClientIdentification::getHash() const 
 147         if (GuestState 
*guest 
= current()) { 
 148                 if (!guest
->gotHash
) { 
 149                         RefPointer
<OSXCode
> clientCode 
= new OSXCodeWrap(guest
->code
); 
 150                         OSXVerifier::makeLegacyHash(clientCode
, guest
->legacyHash
); 
 151                         guest
->gotHash 
= true; 
 153                 return CssmData::wrap(guest
->legacyHash
, SHA1::digestLength
); 
 160 // Bonus function: get the path out of a SecCodeRef 
 162 std::string 
codePath(SecStaticCodeRef code
) 
 164         CFRef
<CFURLRef
> path
; 
 165         MacOSError::check(SecCodeCopyPath(code
, kSecCSDefaultFlags
, &path
.aref())); 
 166         return cfString(path
); 
 171 // Debug dump support 
 173 #if defined(DEBUGDUMP) 
 175 static void dumpCode(SecCodeRef code
) 
 177         CFRef
<CFURLRef
> path
; 
 178         if (OSStatus rc 
= SecCodeCopyPath(code
, kSecCSDefaultFlags
, &path
.aref())) 
 179                 Debug::dump("unknown(rc=%d)", int32_t(rc
)); 
 181                 Debug::dump("%s", cfString(path
).c_str()); 
 184 void ClientIdentification::dump() 
 186         Debug::dump(" client="); 
 187         dumpCode(mClientProcess
); 
 188         for (GuestMap::const_iterator it 
= mGuests
.begin(); it 
!= mGuests
.end(); ++it
) { 
 189                 Debug::dump(" guest(0x%x)=", it
->first
); 
 190                 dumpCode(it
->second
.code
); 
 191                 if (it
->second
.gotHash
) 
 192                         Debug::dump(" [got hash]");