Next integration phase, metadata and trust conversion.
[shibboleth/cpp-sp.git] / odbc_ccache / odbc-ccache.cpp
index 44d62cc..1dc7b99 100644 (file)
 # define SHIBODBC_EXPORTS
 #endif
 
-#include <shib/shib-threads.h>
 #include <shib-target/shib-target.h>
+#include <shibsp/exceptions.h>
 #include <log4cpp/Category.hh>
+#include <xmltooling/util/NDC.h>
 
+#include <ctime>
 #include <algorithm>
 #include <sstream>
 
 #include <dmalloc.h>
 #endif
 
-using namespace std;
-using namespace saml;
-using namespace shibboleth;
+using namespace shibsp;
 using namespace shibtarget;
+using namespace opensaml::saml2md;
+using namespace saml;
+using namespace xmltooling;
 using namespace log4cpp;
+using namespace std;
 
 #define PLUGIN_VER_MAJOR 3
 #define PLUGIN_VER_MINOR 0
@@ -65,7 +69,7 @@ using namespace log4cpp;
 #define COLSIZE_APPLICATION_ID 256
 #define COLSIZE_ADDRESS 128
 #define COLSIZE_PROVIDER_ID 256
-#define LONGDATA_BUFLEN 2048
+#define LONGDATA_BUFLEN 32768
 
 /*
   CREATE TABLE state (
@@ -118,10 +122,9 @@ public:
 
     SQLHDBC getHDBC();
 
-    log4cpp::Category* log;
+    Category* log;
 
 protected:
-    //ThreadKey* m_mysql;
     const DOMElement* m_root; // can only use this during initialization
     string m_connstring;
 
@@ -139,7 +142,7 @@ const char* ODBCBase::p_connstring = NULL;
 ODBCBase::ODBCBase(const DOMElement* e) : m_root(e), m_bInitializedODBC(false)
 {
 #ifdef _DEBUG
-    saml::NDC ndc("ODBCBase");
+    xmltooling::NDC ndc("ODBCBase");
 #endif
     log = &(Category::getInstance("shibtarget.ODBC"));
 
@@ -168,7 +171,7 @@ ODBCBase::ODBCBase(const DOMElement* e) : m_root(e), m_bInitializedODBC(false)
         m_connstring=p_connstring;
     }
     else {
-        auto_ptr_char arg(e->getFirstChild()->getNodeValue());
+        xmltooling::auto_ptr_char arg(e->getFirstChild()->getNodeValue());
         m_connstring=arg.get();
         p_connstring=m_connstring.c_str();
     }
@@ -215,7 +218,7 @@ void ODBCBase::log_error(SQLHANDLE handle, SQLSMALLINT htype)
 SQLHDBC ODBCBase::getHDBC()
 {
 #ifdef _DEBUG
-    saml::NDC ndc("getMYSQL");
+    xmltooling::NDC ndc("getMYSQL");
 #endif
 
     // Get a handle.
@@ -274,13 +277,13 @@ public:
     // Delegate all the ISessionCache methods.
     string insert(
         const IApplication* application,
-        const IEntityDescriptor* source,
+        const RoleDescriptor* role,
         const char* client_addr,
         const SAMLSubject* subject,
         const char* authnContext,
         const SAMLResponse* tokens
         )
-    { return m_cache->insert(application,source,client_addr,subject,authnContext,tokens); }
+    { return m_cache->insert(application,role,client_addr,subject,authnContext,tokens); }
     ISessionCacheEntry* find(const char* key, const IApplication* application, const char* client_addr)
     { return m_cache->find(key,application,client_addr); }
     void remove(const char* key, const IApplication* application, const char* client_addr)
@@ -320,9 +323,9 @@ public:
 private:
     bool m_storeAttributes;
     ISessionCache* m_cache;
-    CondWait* shutdown_wait;
+    xmltooling::CondWait* shutdown_wait;
     bool shutdown;
-    Thread* cleanup_thread;
+    xmltooling::Thread* cleanup_thread;
 
     static void* cleanup_fcn(void*); // XXX Assumed an ODBCCCache
 };
@@ -330,7 +333,7 @@ private:
 ODBCCCache::ODBCCCache(const DOMElement* e) : ODBCBase(e), m_storeAttributes(false)
 {
 #ifdef _DEBUG
-    saml::NDC ndc("ODBCCCache");
+    xmltooling::NDC ndc("ODBCCCache");
 #endif
     log = &(Category::getInstance("shibtarget.SessionCache.ODBC"));
 
@@ -362,6 +365,18 @@ ODBCCCache::~ODBCCCache()
     delete m_cache;
 }
 
+void appendXML(ostream& os, const char* str)
+{
+    const char* pos=strchr(str,'\'');
+    while (pos) {
+        os.write(str,pos-str);
+        os << "''";
+        str=pos+1;
+        pos=strchr(str,'\'');
+    }
+    os << str;
+}
+
 HRESULT ODBCCCache::onCreate(
     const char* key,
     const IApplication* application,
@@ -372,7 +387,7 @@ HRESULT ODBCCCache::onCreate(
     )
 {
 #ifdef _DEBUG
-    saml::NDC ndc("onCreate");
+    xmltooling::NDC ndc("onCreate");
 #endif
 
     // Get XML data from entry. Default is not to return SAML objects.
@@ -396,8 +411,18 @@ HRESULT ODBCCCache::onCreate(
     ostringstream q;
     q << "INSERT state VALUES ('" << key << "','" << application->getId() << "'," << timebuf << "," << timebuf
         << ",'" << entry->getClientAddress() << "'," << majorVersion << "," << minorVersion << ",'" << entry->getProviderId()
-        << "',?,?,?)";
-
+        << "','";
+    appendXML(q,subject.first);
+    q << "','";
+    appendXML(q,context);
+    q << "',";
+    if (m_storeAttributes && tokens.first) {
+        q << "'";
+        appendXML(q,tokens.first);
+       q << "')";
+    }
+    else
+        q << "null)";
     if (log->isDebugEnabled())
         log->debug("SQL insert: %s", q.str().c_str());
 
@@ -406,42 +431,9 @@ HRESULT ODBCCCache::onCreate(
     ODBCConn conn(getHDBC());
     SQLAllocHandle(SQL_HANDLE_STMT,conn,&hstmt);
 
-    // Bind text parameters to statement.
-    SQLINTEGER cbSubject=SQL_LEN_DATA_AT_EXEC(0),cbContext=SQL_LEN_DATA_AT_EXEC(0),cbTokens;
-    if (!m_storeAttributes || !tokens.first)
-        cbTokens=SQL_NULL_DATA;
-    else
-        cbTokens=SQL_LEN_DATA_AT_EXEC(0);
-    SQLRETURN sr=SQLBindParameter(hstmt,1,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_LONGVARCHAR,LONGDATA_BUFLEN,0,(SQLPOINTER)subject.first,0,&cbSubject);
-    if (!SQL_SUCCEEDED(sr))
-        log_error(hstmt, SQL_HANDLE_STMT);
-    sr=SQLBindParameter(hstmt,2,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_LONGVARCHAR,LONGDATA_BUFLEN,0,(SQLPOINTER)context,0,&cbContext);
-    if (!SQL_SUCCEEDED(sr))
-        log_error(hstmt, SQL_HANDLE_STMT);
-    sr=SQLBindParameter(hstmt,3,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_LONGVARCHAR,LONGDATA_BUFLEN,0,(SQLPOINTER)tokens.first,0,&cbTokens);
-    if (!SQL_SUCCEEDED(sr))
-        log_error(hstmt, SQL_HANDLE_STMT);
-
     // Execute statement.
-    sr=SQLExecDirect(hstmt, (SQLCHAR*)q.str().c_str(), SQL_NTS);
-    if (sr==SQL_NEED_DATA) {
-        // Loop to send text data into driver.
-        // pData is set each round by the driver to the pointers we bound above.
-        char* pData;
-        sr=SQLParamData(hstmt,(SQLPOINTER*)&pData);
-        while (sr==SQL_NEED_DATA) {
-            size_t len=strlen(pData);
-            while (len>0) {
-                size_t amt = std::min<size_t>(LONGDATA_BUFLEN,len);
-                SQLPutData(hstmt, pData, amt);
-                pData += amt;
-                len = len - amt;
-            }
-            sr=SQLParamData(hstmt,(SQLPOINTER*)&pData);
-       }
-    }
-
     HRESULT hr=NOERROR;
+    SQLRETURN sr=SQLExecDirect(hstmt, (SQLCHAR*)q.str().c_str(), SQL_NTS);
     if (!SQL_SUCCEEDED(sr)) {
         log->error("failed to insert record into database");
         log_error(hstmt, SQL_HANDLE_STMT);
@@ -467,7 +459,7 @@ HRESULT ODBCCCache::onRead(
     )
 {
 #ifdef _DEBUG
-    saml::NDC ndc("onRead");
+    xmltooling::NDC ndc("onRead");
 #endif
 
     log->debug("searching database...");
@@ -566,7 +558,7 @@ HRESULT ODBCCCache::onRead(
 HRESULT ODBCCCache::onRead(const char* key, time_t& accessed)
 {
 #ifdef _DEBUG
-    saml::NDC ndc("onRead");
+    xmltooling::NDC ndc("onRead");
 #endif
 
     log->debug("reading last access time from database");
@@ -615,7 +607,7 @@ HRESULT ODBCCCache::onRead(const char* key, time_t& accessed)
 HRESULT ODBCCCache::onRead(const char* key, string& tokens)
 {
 #ifdef _DEBUG
-    saml::NDC ndc("onRead");
+    xmltooling::NDC ndc("onRead");
 #endif
 
     if (!m_storeAttributes)
@@ -662,12 +654,10 @@ HRESULT ODBCCCache::onRead(const char* key, string& tokens)
 HRESULT ODBCCCache::onUpdate(const char* key, const char* tokens, time_t lastAccess)
 {
 #ifdef _DEBUG
-    saml::NDC ndc("onUpdate");
+    xmltooling::NDC ndc("onUpdate");
 #endif
 
-    SQLRETURN sr;
-    SQLHSTMT hstmt;
-    ODBCConn conn(getHDBC());
+    ostringstream q;
 
     if (lastAccess>0) {
 #ifndef HAVE_GMTIME_R
@@ -679,48 +669,31 @@ HRESULT ODBCCCache::onUpdate(const char* key, const char* tokens, time_t lastAcc
         char timebuf[32];
         strftime(timebuf,32,"{ts '%Y-%m-%d %H:%M:%S'}",ptime);
 
-        ostringstream q;
         q << "UPDATE state SET atime=" << timebuf << " WHERE cookie='" << key << "'";
-
-        SQLAllocHandle(SQL_HANDLE_STMT,conn,&hstmt);
-        sr=SQLExecDirect(hstmt, (SQLCHAR*)q.str().c_str(), SQL_NTS);
     }
     else if (tokens) {
         if (!m_storeAttributes)
             return S_FALSE;
-        string q = string("UPDATE state SET tokens=? WHERE cookie='") + key + "'";
-
-        SQLAllocHandle(SQL_HANDLE_STMT,conn,&hstmt);
-
-        // Bind text parameters to statement.
-        SQLINTEGER cbTokens = tokens ? SQL_LEN_DATA_AT_EXEC(0) : SQL_NULL_DATA;
-        sr=SQLBindParameter(hstmt,1,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_LONGVARCHAR,LONGDATA_BUFLEN,0,(SQLPOINTER)tokens,0,&cbTokens);
-
-        // Execute statement.
-        sr=SQLExecDirect(hstmt, (SQLCHAR*)q.c_str(), SQL_NTS);
-        if (sr==SQL_NEED_DATA) {
-            // Loop to send text data into driver.
-            // pData is set each round by the driver to the pointers we bound above.
-            char* pData;
-            sr=SQLParamData(hstmt,(SQLPOINTER*)&pData);
-            while (sr==SQL_NEED_DATA) {
-                size_t len=strlen(pData);
-                while (len>0) {
-                    size_t amt=std::min<size_t>(LONGDATA_BUFLEN,len);
-                    SQLPutData(hstmt, pData, amt);
-                    pData += amt;
-                    len = len - amt;
-                }
-                sr=SQLParamData(hstmt,(SQLPOINTER*)&pData);
-           }
-        }
+        q << "UPDATE state SET tokens=";
+       if (*tokens) {
+           q << "'";
+           appendXML(q,tokens);
+           q << "' ";
+       }
+       else
+           q << "null ";
+       q << "WHERE cookie='" << key << "'";
     }
     else {
         log->warn("onUpdate called with nothing to do!");
         return S_FALSE;
     }
  
-    HRESULT hr;
+    HRESULT hr=NOERROR;
+    SQLHSTMT hstmt;
+    ODBCConn conn(getHDBC());
+    SQLAllocHandle(SQL_HANDLE_STMT,conn,&hstmt);
+    SQLRETURN sr=SQLExecDirect(hstmt, (SQLCHAR*)q.str().c_str(), SQL_NTS);
     if (sr==SQL_NO_DATA)
         hr=S_FALSE;
     else if (!SQL_SUCCEEDED(sr)) {
@@ -728,8 +701,6 @@ HRESULT ODBCCCache::onUpdate(const char* key, const char* tokens, time_t lastAcc
         log_error(hstmt, SQL_HANDLE_STMT);
         hr=E_FAIL;
     }
-    else
-        hr=NOERROR;
 
     SQLFreeHandle(SQL_HANDLE_STMT,hstmt);
     return hr;
@@ -738,7 +709,7 @@ HRESULT ODBCCCache::onUpdate(const char* key, const char* tokens, time_t lastAcc
 HRESULT ODBCCCache::onDelete(const char* key)
 {
 #ifdef _DEBUG
-    saml::NDC ndc("onDelete");
+    xmltooling::NDC ndc("onDelete");
 #endif
 
     SQLHSTMT hstmt;
@@ -747,7 +718,7 @@ HRESULT ODBCCCache::onDelete(const char* key)
     string q = string("DELETE FROM state WHERE cookie='") + key + "'";
     SQLRETURN sr=SQLExecDirect(hstmt, (SQLCHAR*)q.c_str(), SQL_NTS);
  
-    HRESULT hr;
+    HRESULT hr=NOERROR;
     if (sr==SQL_NO_DATA)
         hr=S_FALSE;
     else if (!SQL_SUCCEEDED(sr)) {
@@ -755,8 +726,6 @@ HRESULT ODBCCCache::onDelete(const char* key)
         log_error(hstmt, SQL_HANDLE_STMT);
         hr=E_FAIL;
     }
-    else
-        hr=NOERROR;
 
     SQLFreeHandle(SQL_HANDLE_STMT,hstmt);
     return hr;
@@ -765,10 +734,10 @@ HRESULT ODBCCCache::onDelete(const char* key)
 void ODBCCCache::cleanup()
 {
 #ifdef _DEBUG
-    saml::NDC ndc("cleanup");
+    xmltooling::NDC ndc("cleanup");
 #endif
 
-    Mutex* mutex = Mutex::create();
+    Mutex* mutex = xmltooling::Mutex::create();
 
     int rerun_timer = 0;
     int timeout_life = 0;
@@ -841,15 +810,17 @@ void ODBCCCache::cleanup()
 
     mutex->unlock();
     delete mutex;
-    Thread::exit(NULL);
+    xmltooling::Thread::exit(NULL);
 }
 
 void* ODBCCCache::cleanup_fcn(void* cache_p)
 {
   ODBCCCache* cache = (ODBCCCache*)cache_p;
 
+#ifndef WIN32
   // First, let's block all signals
   Thread::mask_all_signals();
+#endif
 
   // Now run the cleanup process.
   cache->cleanup();
@@ -863,7 +834,7 @@ public:
   ODBCReplayCache(const DOMElement* e);
   virtual ~ODBCReplayCache() {}
 
-  bool check(const XMLCh* str, time_t expires) {auto_ptr_XMLCh temp(str); return check(temp.get(),expires);}
+  bool check(const XMLCh* str, time_t expires) {xmltooling::auto_ptr_XMLCh temp(str); return check(temp.get(),expires);}
   bool check(const char* str, time_t expires);
 };