2  * Copyright (c) 2004-2006 Apple Computer, 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@ 
  26 // tokend - internal tracker for a tokend smartcard driver process 
  29 #include <security_utilities/logging.h> 
  33 // Construct a TokenDaemon. 
  34 // This will (try to) execute the actual tokend at 'path'; it will not communicate 
  35 // with it beyond the standard securityd checkin mechanism. 
  36 // The constructor will return if the tokend is either checked in and ready, or 
  37 // it has died (or been unable to start at all). It's then our owner's responsibility 
  38 // to manage us from there, including deleting us eventually. 
  40 TokenDaemon::TokenDaemon(RefPointer
<Bundle
> code
, 
  41                 const string 
&reader
, const PCSC::ReaderState 
&readerState
, TokenCache 
&cache
) 
  42         : Tokend::ClientSession(Allocator::standard(), Allocator::standard()), 
  43           mMe(code
), mReaderName(reader
), mState(readerState
), 
  44           mFaultRelay(NULL
), mFaulted(false), mProbed(false), 
  45           mUid(cache
.tokendUid()), mGid(cache
.tokendGid()) 
  48         switch (ServerChild::state()) { 
  50                 Tokend::ClientSession::servicePort(ServerChild::servicePort()); 
  51                 secinfo("tokend", "%p (pid %d) %s has launched", this, pid(), bundlePath().c_str()); 
  54                 // tokend died or quit before becoming ready 
  55                 secinfo("tokend", "%p (pid %d) %s failed on startup", this, pid(), bundlePath().c_str()); 
  64 // The destructor for TokenDaemon *may* be called with tokend still alive. 
  65 // We rely on ServerChild's destructor to kill it for us. 
  66 // If we wanted to do something especally nice just for tokend (such as sending 
  67 // a "go die" message), we'd do it here. 
  69 TokenDaemon::~TokenDaemon() 
  71         secinfo("tokend", "%p (pid %d) %s is being destroyed", this, pid(), bundlePath().c_str()); 
  76 // Calculate a tokenUid as a concatenation of tokend identifier and uid 
  78 std::string 
TokenDaemon::tokenUid() const 
  80         assert(hasTokenUid()); 
  86 // Access to custom Info.plist fields 
  88 uint32 
TokenDaemon::maxScore() const 
  90         return cfNumber(CFNumberRef(mMe
->infoPlistItem("TokendBestScore")), INT_MAX
); 
  95 // Our childAction is to launch tokend after preparing its environment 
  97 void TokenDaemon::childAction() 
 100         // permanently relinquish high privilege 
 102         UnixError::check(::setgid(mGid
)); 
 103         UnixError::check(::setuid(mUid
)); 
 105         // best effort, okay if not 
 109         secinfo("tokend", "uid=%d gid=%d", getuid(), getgid()); 
 112         char protocol
[20]; snprintf(protocol
, sizeof(protocol
), "%d", TDPROTOVERSION
); 
 113         secinfo("tokend", "executing %s(\"%s\",%s)", 
 114                 mMe
->executablePath().c_str(), mReaderName
.c_str(), protocol
); 
 115         execl(mMe
->executablePath().c_str(), 
 116                 mMe
->executablePath().c_str(), 
 117                 protocol
,                                                                       // #1: protocol version 
 118                 mReaderName
.c_str(),                                            // #2: reader name 
 119                 CssmData::wrap(mState
).toHex().c_str(),         // #3: PCSC reader state (hex) 
 125 // This will be called (by the UnixChild layer) when UNIX tells us that our tokend 
 126 // has died. That means it's quite dead (a Zombie) already. 
 128 void TokenDaemon::dying() 
 130         ServerChild::dying();                                   // honor prior engagement 
 131         fault(true, "token daemon has died");   // flag asynchronous fault 
 139 void TokenDaemon::fault(bool async
, const char *reason
) 
 142                 secinfo("tokend", "%p declaring %s FAULT condition: %s", 
 143                         this, async 
? "ASYNCHRONOUS" : "SYNCHRONOUS", reason
); 
 144                 Syslog::notice("card in reader %s has faulted (%s)", 
 145                         mReaderName
.c_str(), reason
); 
 148                         mFaultRelay
->relayFault(async
); 
 151                 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_FAILED
); 
 156 // A fault signalled from the ClientSession layer is just a (synchronous) fault 
 157 // of TokenDaemon itself. 
 159 void TokenDaemon::fault() 
 161         this->fault(false, "tokend service failed"); 
 166 // Overridden Tokend::ClientSession methods (to siphon off some return data). 
 167 // Note that this does NOT include the Access magic; you still have to use 
 168 // TokenDaemon::Access to mediate the call. 
 170 bool TokenDaemon::probe() 
 172         secinfo("tokend", "%p probing", this); 
 173         ClientSession::probe(mScore
, mTokenUid
); 
 174         secinfo("tokend", "%p probed score=%d tokenUid=\"%s\"", this, mScore
, mTokenUid
.c_str()); 
 183 FaultRelay::~FaultRelay() 
 188 // Debug dump support 
 190 #if defined(DEBUGDUMP) 
 192 void TokenDaemon::dumpNode() 
 194         PerGlobal::dumpNode(); 
 196                 Debug::dump(" FAULT"); 
 197         Debug::dump(" service=%d/%d", 
 198                 ClientSession::servicePort().port(), ServerChild::servicePort().port());