]> git.saurik.com Git - apple/securityd.git/commitdiff
securityd-33639.tar.gz v33639
authorApple <opensource@apple.com>
Fri, 4 Apr 2008 22:36:39 +0000 (22:36 +0000)
committerApple <opensource@apple.com>
Fri, 4 Apr 2008 22:36:39 +0000 (22:36 +0000)
securityd.xcodeproj/project.pbxproj
src/main.cpp
src/pcscmonitor.cpp
src/pcscmonitor.h
src/reader.cpp
src/reader.h
src/server.cpp
src/token.cpp
src/token.h

index 1466aa34b3b615d492e4f22819888e33c5016d71..c7a7e71d00efc9af484351385c8712355e31c72a 100644 (file)
                                BUILD_VARIANTS = debug;
                                COPY_PHASE_STRIP = NO;
                                CSSM_HEADERS = "$(BUILT_PRODUCTS_DIR)/Security.framework/Headers:$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/Headers";
-                               CURRENT_PROJECT_VERSION = 33082;
+                               CURRENT_PROJECT_VERSION = 33639;
                                FRAMEWORK_SEARCH_PATHS = (
                                        /usr/local/SecurityPieces/Frameworks,
                                        /usr/local/SecurityPieces/Components/securityd,
                                        debug,
                                );
                                CSSM_HEADERS = "$(BUILT_PRODUCTS_DIR)/Security.framework/Headers:$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/Headers";
-                               CURRENT_PROJECT_VERSION = 33082;
+                               CURRENT_PROJECT_VERSION = 33639;
                                DEAD_CODE_STRIPPING = YES;
                                EXPORTED_SYMBOLS_FILE = "$(SRCROOT)/src/securityd.exp";
                                FRAMEWORK_SEARCH_PATHS = (
                        buildSettings = {
                                BUILD_VARIANTS = normal;
                                COPY_PHASE_STRIP = NO;
-                               CURRENT_PROJECT_VERSION = 33082;
+                               CURRENT_PROJECT_VERSION = 33639;
                                EXPORTED_SYMBOLS_FILE = "$(SRCROOT)/src/securityd.exp";
                                FRAMEWORK_SEARCH_PATHS = (
                                        /usr/local/SecurityPieces/Frameworks,
                                        normal,
                                        debug,
                                );
-                               CURRENT_PROJECT_VERSION = 33082;
+                               CURRENT_PROJECT_VERSION = 33639;
                                EXPORTED_SYMBOLS_FILE = "$(SRCROOT)/src/securityd.exp";
                                FRAMEWORK_SEARCH_PATHS = (
                                        /usr/local/SecurityPieces/Frameworks,
index 683a907b41dd5ecbf62a706078144e303482dc6a..159e4abad64d4cdbca2c45801d25693212b8330b 100644 (file)
@@ -76,6 +76,7 @@ static PCSCMonitor::ServiceLevel scOptions(const char *optionString);
 
 
 static Port gMainServerPort;
+PCSCMonitor *gPCSC;
 
 
 //
@@ -237,8 +238,10 @@ int main(int argc, char *argv[])
         secdebug("SS", "Cannot handle SIGPIPE: errno=%d", errno);
 #if !defined(NDEBUG)
     if (signal(SIGUSR1, handleSignals) == SIG_ERR)
-        secdebug("SS", "Cannot handle SIGHUP: errno=%d", errno);
+        secdebug("SS", "Cannot handle SIGUSR1: errno=%d", errno);
 #endif //NDEBUG
+    if (signal(SIGUSR2, handleSignals) == SIG_ERR)
+        secdebug("SS", "Cannot handle SIGUSR2: errno=%d", errno);
 
        // create an Authorization engine
        Authority authority(authorizationConfig);
@@ -287,7 +290,7 @@ int main(int argc, char *argv[])
 #endif //NDEBUG
 
        // create a smartcard monitor to manage external token devices
-       new PCSCMonitor(server, tokenCacheDir, scOptions(smartCardOptions));
+       gPCSC = new PCSCMonitor(server, tokenCacheDir, scOptions(smartCardOptions));
     
     // create the RootSession object (if -d, give it graphics and tty attributes)
     RootSession rootSession(server,
index 238550711cc829623e24ba3f2e9ee5f1bcc23c28..d38efc96c79d6b8df3f6fa728f60f117cca4c7a5 100644 (file)
@@ -66,11 +66,11 @@ PCSCMonitor::PCSCMonitor(Server &server, const char* pathToCache, ServiceLevel l
        : Listener(kNotificationDomainPCSC, SecurityServer::kNotificationAllEvents),
          MachServer::Timer(true), // "heavy" timer task
          server(server),
-         cache (NULL),
-         cachePath (pathToCache),
          mServiceLevel(level),
          mTimerAction(&PCSCMonitor::initialSetup),
-         mGoingToSleep(false)
+         mGoingToSleep(false),
+         mCachePath(pathToCache),
+         mTokenCache(NULL)
 {
        // do all the smartcard-related work once the event loop has started
        server.setTimer(this, Time::now());             // ASAP
@@ -132,48 +132,60 @@ void PCSCMonitor::pollReaders()
                        // accounted for this reader
                        current.erase(reader);
                } else {
-                       RefPointer<Reader> newReader = new Reader(getTokenCache (), state);
+                       RefPointer<Reader> newReader = new Reader(tokenCache(), state);
                        mReaders.insert(make_pair(state.name(), newReader));
                        Syslog::notice("Token reader %s inserted into system", state.name());
                        newReader->update(state);               // initial state setup
                }
        }
        
-       // now deal with vanished readers
+       // now deal with known readers that PCSC did not report
        for (ReaderSet::iterator it = current.begin(); it != current.end(); it++) {
-               secdebug("pcsc", "removing reader %s", (*it)->name().c_str());
-               Syslog::notice("Token reader %s removed from system", (*it)->name().c_str());
-               (*it)->kill();                                          // prepare to die
-               mReaders.erase((*it)->name());          // remove from reader map
+               switch ((*it)->type()) {
+               case Reader::pcsc:
+                       // previous PCSC reader - was removed from system
+                       secdebug("pcsc", "removing reader %s", (*it)->name().c_str());
+                       Syslog::notice("Token reader %s removed from system", (*it)->name().c_str());
+                       (*it)->kill();                                          // prepare to die
+                       mReaders.erase((*it)->name());          // remove from reader map
+                       break;
+               case Reader::software:
+                       // previous software reader - keep
+                       break;
+               }
        }
 }
 
+
 //
-// Poll PCSC for smartcard status.
-// We are enumerating all readers on each call.
+// Remove some types of readers
 //
-void PCSCMonitor::clearReaders()
+void PCSCMonitor::clearReaders(Reader::Type type)
 {
        if (!mReaders.empty()) {
-               // uh-oh. We had readers connected when pcscd suddenly left
-               secdebug("pcsc", "%ld readers were present when pcscd died", mReaders.size());
-               for (ReaderMap::const_iterator it = mReaders.begin(); it != mReaders.end(); it++) {
-                       Reader *reader = it->second;
-                       secdebug("pcsc", "removing reader %s", reader->name().c_str());
-                       reader->kill();                                         // prepare to die
+               secdebug("pcsc", "%ld readers present - clearing type %d", mReaders.size(), type);
+               for (ReaderMap::iterator it = mReaders.begin(); it != mReaders.end(); ) {
+                       ReaderMap::iterator cur = it++;
+                       Reader *reader = cur->second;
+                       if (reader->isType(type)) {
+                               secdebug("pcsc", "removing reader %s", reader->name().c_str());
+                               reader->kill();                                         // prepare to die
+                               mReaders.erase(cur);
+                       }
                }
-               mReaders.erase(mReaders.begin(), mReaders.end());
-               secdebug("pcsc", "orphaned readers cleared");
        }
 }
 
-TokenCache& PCSCMonitor::getTokenCache ()
+
+//
+// Poll PCSC for smartcard status.
+// We are enumerating all readers on each call.
+//
+TokenCache& PCSCMonitor::tokenCache()
 {
-       if (cache == NULL) {
-               cache = new TokenCache(cachePath.c_str ());
-       }
-       
-       return *cache;
+       if (mTokenCache == NULL)
+               mTokenCache = new TokenCache(mCachePath.c_str());
+       return *mTokenCache;
 }
 
 
@@ -233,10 +245,7 @@ void PCSCMonitor::notifyMe(Notification *message)
        StLock<Mutex> _(*this);
        assert(mServiceLevel == externalDaemon || Child::state() == alive);
        if (message->event == kNotificationPCSCInitialized)
-       {
-               clearReaders();
-//             mSession.close();
-       }
+               clearReaders(Reader::pcsc);
        pollReaders();
        scheduleTimer(mReaders.empty() && !mGoingToSleep);
 }
@@ -304,10 +313,12 @@ void PCSCMonitor::initialSetup()
        case forcedOn:
                secdebug("pcsc", "pcscd launch is forced on");
                launchPcscd();
+               startSoftTokens();
                break;
 
        case externalDaemon:
                secdebug("pcsc", "using external pcscd (if any); no launch operations");
+               startSoftTokens();
                break;
        
        default:
@@ -330,6 +341,10 @@ void PCSCMonitor::initialSetup()
                        IOKit::DeviceMatch customUsbSelector(::IOServiceMatching("IOUSBDevice"));
                        mIOKitNotifier.add(customUsbSelector, *this);   // ditto for custom USB devices
                }
+               
+               // find and start software tokens
+               startSoftTokens();
+
                break;
        }
        
@@ -459,6 +474,60 @@ void PCSCMonitor::dying()
        Server::active().longTermActivity();
        StLock<Mutex> _(*this);
        assert(Child::state() == dead);
-       clearReaders();
+       clearReaders(Reader::pcsc);
        //@@@ this is where we would attempt a restart, if we wanted to...
 }
+
+
+//
+// Software token support
+//
+void PCSCMonitor::startSoftTokens()
+{
+       // clear all software readers. This will kill the respective TokenDaemons
+       clearReaders(Reader::software);
+
+       // scan for new ones
+       CodeRepository<Bundle> candidates("Security/tokend", ".tokend", "TOKENDAEMONPATH", false);
+       candidates.update();
+       for (CodeRepository<Bundle>::iterator it = candidates.begin(); it != candidates.end(); ++it) {
+               if (CFTypeRef type = (*it)->infoPlistItem("TokendType"))
+                       if (CFEqual(type, CFSTR("software")))
+                               loadSoftToken(*it);
+       }
+}
+
+void PCSCMonitor::loadSoftToken(Bundle *tokendBundle)
+{
+       try {
+               string bundleName = tokendBundle->identifier();
+               
+               // prepare a virtual reader, removing any existing one (this would kill a previous tokend)
+               assert(mReaders.find(bundleName) == mReaders.end());    // not already present
+               RefPointer<Reader> reader = new Reader(tokenCache(), bundleName);
+
+               // now launch the tokend
+               RefPointer<TokenDaemon> tokend = new TokenDaemon(tokendBundle,
+                       reader->name(), reader->pcscState(), reader->cache);
+               
+               if (tokend->state() == ServerChild::dead) {     // ah well, this one's no good
+                       secdebug("pcsc", "softtoken %s tokend launch failed", bundleName.c_str());
+                       Syslog::notice("Software token %s failed to run", tokendBundle->canonicalPath().c_str());
+                       return;
+               }
+               
+               // probe the (single) tokend
+               if (!tokend->probe()) {         // non comprende...
+                       secdebug("pcsc", "softtoken %s probe failed", bundleName.c_str());
+                       Syslog::notice("Software token %s refused operation", tokendBundle->canonicalPath().c_str());
+                       return;
+               }
+               
+               // okay, this seems to work. Set it up
+               mReaders.insert(make_pair(reader->name(), reader));
+               reader->insertToken(tokend);
+               Syslog::notice("Software token %s activated", bundleName.c_str());
+       } catch (...) {
+               secdebug("pcsc", "exception loading softtoken %s - continuing", tokendBundle->identifier().c_str());
+       }
+}
index 6b023e14099ca852815725c0f769ec8ba330e465..36bf3ed2692654a802e5706f88d0d0c86d39aca1 100644 (file)
@@ -37,6 +37,7 @@
 #include <security_utilities/powerwatch.h>
 #include <security_utilities/pcsc++.h>
 #include <security_utilities/iodevices.h>
+#include <security_utilities/coderepository.h>
 #include <set>
 
 
@@ -65,12 +66,10 @@ public:
 
 protected:
        void pollReaders();
-       void clearReaders();
+       void clearReaders(Reader::Type type);
 
        Server &server;
-       TokenCache *cache;
-       std::string cachePath;
-       TokenCache& getTokenCache ();
+       TokenCache& tokenCache();
 
 protected:
        // Listener
@@ -95,6 +94,10 @@ protected:
        void scheduleTimer(bool enable);
        void initialSetup();
        void noDeviceTimeout();
+       
+public: //@@@@
+       void startSoftTokens();
+       void loadSoftToken(Bundle *tokendBundle);
 
        enum DeviceSupport {
                impossible,                             // certain this is not a smartcard
@@ -108,6 +111,9 @@ private:
        ServiceLevel mServiceLevel;     // level of service requested/determined
        void (PCSCMonitor::*mTimerAction)(); // what to do when our timer fires 
        bool mGoingToSleep;                     // between sleep and wakeup; special timer handling
+       
+       std::string mCachePath;         // path to cache directory
+       TokenCache *mTokenCache;        // cache object (lazy)
 
        PCSC::Session mSession;         // PCSC client session
        IOKit::MachPortNotificationPort mIOKitNotifier; // IOKit connection
index ac476b3345309fb2a4fcf0a82eeb88e5411b7151..32b45abd52c637d684d099665b4b06f2e69f8ee9 100644 (file)
 // This does not commence state tracking; call update to start up the reader.
 //
 Reader::Reader(TokenCache &tc, const PCSC::ReaderState &state)
-       : cache(tc), mToken(NULL)
+       : cache(tc), mType(pcsc), mToken(NULL)
 {
        mName = state.name();   // remember separate copy of name
        mPrintName = mName;             //@@@ how to make this readable? Use IOKit information?
-       secdebug("reader", "%p (%s) new reader", this, name().c_str());
+       secdebug("reader", "%p (%s) new PCSC reader", this, name().c_str());
+}
+
+Reader::Reader(TokenCache &tc, const string &identifier)
+       : cache(tc), mType(software), mToken(NULL)
+{
+       mName = identifier;
+       mPrintName = mName;
+       secdebug("reader", "%p (%s) new software reader", this, name().c_str());
 }
 
 Reader::~Reader()
@@ -46,6 +54,15 @@ Reader::~Reader()
 }
 
 
+//
+// Type qualification. None matches anything.
+//
+bool Reader::isType(Type reqType) const
+{
+       return reqType == this->type();
+}
+
+
 //
 // Killing a reader forcibly removes its Token, if any
 //
@@ -90,7 +107,7 @@ void Reader::update(const PCSC::ReaderState &state)
                        //@@@ or should we call some verify-still-the-same function of tokend?
                        //@@@ (I think pcsc will return an error if the card changed?)
                        if (!mToken)
-                               insertToken();
+                               insertToken(NULL);
                } else {
                        secdebug("reader", "%p (%s) unexpected state change (0x%lx to 0x%lx)",
                                this, name().c_str(), oldState, state.state());
@@ -101,10 +118,10 @@ void Reader::update(const PCSC::ReaderState &state)
 }
 
 
-void Reader::insertToken()
+void Reader::insertToken(TokenDaemon *tokend)
 {
        RefPointer<Token> token = new Token();
-       token->insert(*this);
+       token->insert(*this, tokend);
        mToken = token;
        addReference(*token);
        secdebug("reader", "%p (%s) inserted token %p",
index 84cb931f3444904b40d150e493bd02b157385aa7..8e3d0d9f3e160ba4bb4b111371fe0e46e7b95b1e 100644 (file)
 //
 class Reader : public PerGlobal {
 public:
-       Reader(TokenCache &cache, const PCSC::ReaderState &state);
+       Reader(TokenCache &cache, const PCSC::ReaderState &state);      // PCSC managed
+       Reader(TokenCache &cache, const std::string &name);                     // software
        ~Reader();
        
+       enum Type {
+               pcsc,                           // represents PCSC-managed reader
+               software                        // software (virtual) reader,
+       };
+       Type type() const { return mType; }
+       bool isType(Type type) const;
+       
        TokenCache &cache;
        
        void kill();
@@ -50,16 +58,17 @@ public:
        string name() const { return mName; }
        string printName() const { return mPrintName; }
        const PCSC::ReaderState &pcscState() const { return mState; }
-       
+
+       void insertToken(TokenDaemon *tokend);
        void update(const PCSC::ReaderState &state);
+       void removeToken();
        
        IFDUMP(void dumpNode());
        
 protected:
-       void insertToken();
-       void removeToken();
        
 private:
+       Type mType;
        string mName;                   // PCSC reader name
        string mPrintName;              // human readable name of reader
        PCSC::ReaderState mState; // name field not valid (use mName)
index f07241d870948cedc08c462da452128b2066058e..9f4fb6b2000c4ca2b539d6b9c46eb5b879d77cd9 100644 (file)
@@ -36,6 +36,7 @@
 #include "child.h"
 #include <mach/mach_error.h>
 #include <security_utilities/ccaudit.h>
+#include "pcscmonitor.h"
 
 #include "agentquery.h"
 
@@ -374,6 +375,14 @@ kern_return_t self_server_handleSignal(mach_port_t sport,
                        NodeCore::dumpAll();
                        break;
 #endif //DEBUGDUMP
+
+               case SIGUSR2:
+                       {
+                               extern PCSCMonitor *gPCSC;
+                               gPCSC->startSoftTokens();
+                               break;
+                       }
+
                default:
                        assert(false);
         }
index 9b3de21094b5041b37cec0fa09c48e3848382ec3..1f8f7c0186d85b68c6c954309642401f3be869df 100644 (file)
@@ -200,11 +200,21 @@ void Token::removeCommon(TokenDbCommon &dbc)
 // we're analyzing the token, determine its characteristics, and get ready to
 // use it.
 //
-void Token::insert(::Reader &slot)
+void Token::insert(::Reader &slot, RefPointer<TokenDaemon> tokend)
 {
        try {
                // this might take a while...
                Server::active().longTermActivity();
+               referent(slot);
+               mState = slot.pcscState();
+               
+               if (tokend == NULL) {
+                       // no pre-determined Tokend - search for one
+                       if (!(tokend = chooseTokend())) {
+                               secdebug("token", "%p no token daemons available - faulting this card", this);
+                               fault(false);   // throws
+                       }
+               }
 
                // take Token lock and hold throughout insertion
                StLock<Mutex> _(*this);
@@ -212,26 +222,18 @@ void Token::insert(::Reader &slot)
                Syslog::debug("token inserted into reader %s", slot.name().c_str());
                secdebug("token", "%p begin insertion into slot %p (reader %s)",
                        this, &slot, slot.name().c_str());
-               referent(slot);
-               mState = slot.pcscState();
-               
-               RefPointer<TokenDaemon> tokend = chooseTokend();
-               if (!tokend) {
-                       secdebug("token", "%p no token daemons available - faulting this card", this);
-                       fault(false);
-               }
                
                // tell the tokend object to relay faults to us
                tokend->faultRelay(this);
 
                // locate or establish cache directories
                if (tokend->hasTokenUid()) {
-                       secdebug("token", "%p CHOOSING %s (score=%d, uid=\"%s\")",
+                       secdebug("token", "%p using %s (score=%d, uid=\"%s\")",
                                this, tokend->bundlePath().c_str(), tokend->score(), tokend->tokenUid().c_str());
                        mCache = new TokenCache::Token(reader().cache,
                                tokend->bundleIdentifier() + ":" + tokend->tokenUid());
                } else {
-                       secdebug("token", "%p CHOOSING %s (score=%d, temporary)",
+                       secdebug("token", "%p using %s (score=%d, temporary)",
                                this, tokend->bundlePath().c_str(), tokend->score());
                        mCache = new TokenCache::Token(reader().cache);
                }
@@ -448,10 +450,15 @@ RefPointer<TokenDaemon> Token::chooseTokend()
        RefPointer<TokenDaemon> leader;
        for (CodeRepository<Bundle>::const_iterator it = candidates.begin();
                        it != candidates.end(); it++) {
+               RefPointer<Bundle> candidate = *it;
                try {
-                       // any pre-launch screening of candidate *it goes here
-                       
-                       RefPointer<TokenDaemon> tokend = new TokenDaemon(*it,
+                       // skip software token daemons - ineligible for automatic choosing
+                       if (CFTypeRef type = (*it)->infoPlistItem("TokendType"))
+                               if (CFEqual(type, CFSTR("software")))
+                                       continue;
+
+                       // okay, launch it and let it try
+                       RefPointer<TokenDaemon> tokend = new TokenDaemon(candidate,
                                reader().name(), reader().pcscState(), reader().cache);
                        
                        if (tokend->state() == ServerChild::dead)       // ah well, this one's no good
@@ -465,7 +472,7 @@ RefPointer<TokenDaemon> Token::chooseTokend()
                        if (!leader || tokend->score() > leader->score())
                                leader = tokend;                // a new front runner, he is...
                } catch (...) {
-                       secdebug("token", "exception setting up %s (moving on)", (*it)->canonicalPath().c_str());
+                       secdebug("token", "exception setting up %s (moving on)", candidate->canonicalPath().c_str());
                }
        }
        return leader;
index 3acd721624272fed20d33e920f856e621d1c77c1..cbf3acaa93ebbeae80bac9068acb33b70866d4cc 100644 (file)
@@ -59,7 +59,7 @@ public:
        std::string printName() const { return mPrintName; }
        TokenCache::Token &cache() const { return *mCache; }
        
-       void insert(::Reader &slot);
+       void insert(::Reader &slot, RefPointer<TokenDaemon> tokend);
        void remove();
        
        void notify(NotificationEvent event);