Porting changes from 1.2 branch
[shibboleth/sp.git] / shib / ShibConfig.cpp
index e47b615..4372d77 100644 (file)
 */
 
 #include <time.h>
-#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #define SHIB_INSTANTIATE
 
 #include "internal.h"
-#include <log4cpp/Category.hh>
+#include "shib-threads.h"
+
+#include <openssl/err.h>
 
 using namespace saml;
 using namespace shibboleth;
+using namespace log4cpp;
+using namespace std;
 
-SAML_EXCEPTION_FACTORY(UnsupportedProtocolException);
-SAML_EXCEPTION_FACTORY(OriginSiteMapperException);
+SAML_EXCEPTION_FACTORY(MetadataException);
+SAML_EXCEPTION_FACTORY(CredentialException);
+SAML_EXCEPTION_FACTORY(InvalidHandleException);
 
 namespace {
-    ShibInternalConfig g_config;
+    ShibConfig g_config;
+    vector<Mutex*> g_openssl_locks;
 }
 
-ShibConfig::~ShibConfig() {}
-
-bool ShibInternalConfig::init()
+extern "C" void openssl_locking_callback(int mode,int n,const char *file,int line)
 {
-    saml::NDC ndc("init");
-
-    REGISTER_EXCEPTION_FACTORY("edu.internet2.middleware.shibboleth.common",UnsupportedProtocolException);
-    REGISTER_EXCEPTION_FACTORY("edu.internet2.middleware.shibboleth.common",OriginSiteMapperException);
-
-    // Register extension schema.
-    saml::XML::registerSchema(XML::SHIB_NS,XML::SHIB_SCHEMA_ID);
-
-    m_lock=RWLock::create();
-    m_shutdown_wait = CondWait::create();
-    if (!m_lock || !m_shutdown_wait)
-    {
-        log4cpp::Category::getInstance(SHIB_LOGCAT".ShibConfig").fatal("init: failed to create mapper locks");
-        delete m_lock;
-        delete m_shutdown_wait;
-        return false;
-    }
+    if (mode & CRYPTO_LOCK)
+        g_openssl_locks[n]->lock();
+    else
+        g_openssl_locks[n]->unlock();
+}
 
-    try
-    {
-        m_mapper=new XMLOriginSiteMapper(mapperURL.c_str(),SAMLConfig::getConfig().ssl_calist.c_str(),mapperCert);
-    }
-    catch(SAMLException& e)
-    {
-        log4cpp::Category::getInstance(SHIB_LOGCAT".ShibConfig").fatal("init: failed to initialize origin site mapper: %s", e.what());
-        delete m_lock;
-        delete m_shutdown_wait;
-        return false;
-    }
+#ifndef WIN32
+extern "C" unsigned long openssl_thread_id(void)
+{
+    return (unsigned long)(pthread_self());
+}
+#endif
 
-    m_manager=xmlSecSimpleKeysMngrCreate();
-    const char* roots=m_mapper->getTrustedRoots();
-    if (roots && *roots && xmlSecSimpleKeysMngrLoadPemCert(m_manager,roots,true) < 0)
-    {
-        log4cpp::Category::getInstance(SHIB_LOGCAT".ShibConfig").fatal("init: failed to load CAs into simple key manager");
-        xmlSecSimpleKeysMngrDestroy(m_manager);
-        delete m_mapper;
-        delete m_lock;
-        delete m_shutdown_wait;
-        return false;
-    }
-    SAMLConfig::getConfig().xmlsig_ptr=m_manager;
-    if (mapperRefreshInterval)
-        m_refresh_thread = Thread::create(&refresh_fn, (void*)this);
+bool ShibConfig::init()
+{
+    REGISTER_EXCEPTION_FACTORY(MetadataException);
+    REGISTER_EXCEPTION_FACTORY(CredentialException);
+    REGISTER_EXCEPTION_FACTORY(InvalidHandleException);
+
+    // Set up OpenSSL locking.
+       for (int i=0; i<CRYPTO_num_locks(); i++)
+        g_openssl_locks.push_back(Mutex::create());
+       CRYPTO_set_locking_callback(openssl_locking_callback);
+#ifndef WIN32
+    CRYPTO_set_id_callback(openssl_thread_id);
+#endif
 
     return true;
 }
 
-void ShibInternalConfig::term()
+void ShibConfig::term()
 {
-    // Shut down the refresh thread and let it know...
-    if (m_refresh_thread)
-    {
-        m_shutdown = true;
-        m_shutdown_wait->signal();
-        m_refresh_thread->join(NULL);
-    }
-
-    delete m_mapper;
-    if (m_manager)
-        xmlSecSimpleKeysMngrDestroy(m_manager);
-    delete mapperCert;
-    delete m_lock;
-    delete m_shutdown_wait;
+    CRYPTO_set_locking_callback(NULL);
+    for (vector<Mutex*>::iterator i=g_openssl_locks.begin(); i!=g_openssl_locks.end(); i++)
+        delete (*i);
+    g_openssl_locks.clear();
 }
 
-IOriginSiteMapper* ShibInternalConfig::getMapper()
+void PlugManager::regFactory(const char* type, Factory* factory)
 {
-    m_lock->rdlock();
-    return m_mapper;
+    if (type && factory)
+        m_map[type]=factory;
 }
 
-void ShibInternalConfig::releaseMapper(IOriginSiteMapper* mapper)
+IPlugIn* PlugManager::newPlugin(const char* type, const DOMElement* source)
 {
-    m_lock->unlock();
+    FactoryMap::const_iterator i=m_map.find(type);
+    if (i==m_map.end())
+        throw saml::UnsupportedExtensionException(std::string("unable to build plugin of type '") + type + "'");
+    return i->second(source);
 }
 
-ShibConfig& ShibConfig::getConfig()
+void PlugManager::unregFactory(const char* type)
 {
-    return g_config;
+    if (type)
+        m_map.erase(type);
 }
 
-void* ShibInternalConfig::refresh_fn(void* config_p)
+ShibConfig& ShibConfig::getConfig()
 {
-  ShibInternalConfig* config = reinterpret_cast<ShibInternalConfig*>(config_p);
-
-  // First, let's block all signals
-  sigset_t sigmask;
-  sigfillset(&sigmask);
-  Thread::mask_signals(SIG_BLOCK, &sigmask, NULL);
-
-  // Now run the cleanup process.
-  config->refresh();
+    return g_config;
 }
 
-void ShibInternalConfig::refresh()
+void shibboleth::log_openssl()
 {
-    Mutex* mutex = Mutex::create();
-    saml::NDC ndc("cleanup");
-    log4cpp::Category& log=log4cpp::Category::getInstance(SHIB_LOGCAT".ShibConfig");
+    const char* file;
+    const char* data;
+    int flags,line;
 
-    mutex->lock();
-
-    log.debug("XMLMapper refresh thread started...");
-
-    while (!m_shutdown)
+    unsigned long code=ERR_get_error_line_data(&file,&line,&data,&flags);
+    while (code)
     {
-        struct timespec ts;
-        memset (&ts, 0, sizeof(ts));
-        ts.tv_sec = time(NULL) + mapperRefreshInterval;
-
-        m_shutdown_wait->timedwait(mutex, &ts);
-
-        if (m_shutdown)
-            break;
-
-        log.info("Refresh thread running...");
-
-        // To refresh the mapper, we basically build a new one in the background and if it works,
-        // we grab the write lock and replace the official pointer with the new one.
-        try
-        {
-            IOriginSiteMapper* new_mapper=new XMLOriginSiteMapper(mapperURL.c_str(),SAMLConfig::getConfig().ssl_calist.c_str(),mapperCert);
-            m_lock->wrlock();
-            delete m_mapper;
-            m_mapper=new_mapper;
-            m_lock->unlock();
-        }
-        catch(SAMLException& e)
-        {
-            log.error("failed to build a refreshed origin site mapper, sticking with what we have: %s", e.what());
-        }
-        catch(...)
-        {
-            log.error("caught an unknown exception, sticking with what we have");
-        }
+        Category& log=Category::getInstance("OpenSSL");
+        log.errorStream() << "error code: " << code << " in " << file << ", line " << line << CategoryStream::ENDLINE;
+        if (data && (flags & ERR_TXT_STRING))
+            log.errorStream() << "error data: " << data << CategoryStream::ENDLINE;
+        code=ERR_get_error_line_data(&file,&line,&data,&flags);
     }
-
-    mutex->unlock();
-    delete mutex;
-    Thread::exit(NULL);
 }