https://issues.shibboleth.net/jira/browse/CPPXT-47
[shibboleth/cpp-xmltooling.git] / xmltooling / soap / impl / CURLSOAPTransport.cpp
index 41828dc..af06fbb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2001-2007 Internet2
+ *  Copyright 2001-2009 Internet2
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -155,18 +155,33 @@ namespace xmltooling {
             if (opt < CURLOPTTYPE_OBJECTPOINT)
                 return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
 #ifdef CURLOPTTYPE_OFF_T
-            else if (opt < CURLOPTTYPE_OFF_T)
-                return (curl_easy_setopt(m_handle, opt, value) == CURLE_OK);
+            else if (opt < CURLOPTTYPE_OFF_T) {
+                if (value)
+                    m_saved_options.push_back(value);
+                return (curl_easy_setopt(m_handle, opt, value ? m_saved_options.back().c_str() : NULL) == CURLE_OK);
+            }
+# ifdef HAVE_CURL_OFF_T
             else if (sizeof(curl_off_t) == sizeof(long))
                 return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
+# else
+            else if (sizeof(off_t) == sizeof(long))
+                return (curl_easy_setopt(m_handle, opt, strtol(value, NULL, 10)) == CURLE_OK);
+# endif
             return false;
 #else
-            else
-                return (curl_easy_setopt(m_handle, opt, value) == CURLE_OK);
+            else {
+                if (value)
+                    m_saved_options.push_back(value);
+                return (curl_easy_setopt(m_handle, opt, value ? m_saved_options.back().c_str() : NULL) == CURLE_OK);
+            }
 #endif
         }
 
-        void send(istream& in);
+        void send(istream& in) {
+            send(&in);
+        }
+
+        void send(istream* in=NULL);
 
         istream& receive() {
             return m_stream;
@@ -204,6 +219,7 @@ namespace xmltooling {
         stringstream m_stream;
         struct curl_slist* m_headers;
         map<string,vector<string> > m_response_headers;
+        vector<string> m_saved_options;
 #ifndef XMLTOOLING_NO_XMLSEC
         const OpenSSLCredential* m_cred;
         const OpenSSLTrustEngine* m_trustEngine;
@@ -255,6 +271,14 @@ void xmltooling::termSOAPTransports()
     g_CURLPool = NULL;
 }
 
+OpenSSLSOAPTransport::OpenSSLSOAPTransport()
+{
+}
+
+OpenSSLSOAPTransport::~OpenSSLSOAPTransport()
+{
+}
+
 CURLPool::~CURLPool()
 {
     for (poolmap_t::iterator i=m_bindingMap.begin(); i!=m_bindingMap.end(); i++) {
@@ -304,10 +328,10 @@ CURL* CURLPool::get(const SOAPTransport::Address& addr)
     curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1);
     curl_easy_setopt(handle,CURLOPT_NOSIGNAL,1);
     curl_easy_setopt(handle,CURLOPT_FAILONERROR,1);
-    curl_easy_setopt(handle,CURLOPT_SSLVERSION,CURL_SSLVERSION_SSLv3);
     curl_easy_setopt(handle,CURLOPT_SSL_CIPHER_LIST,"ALL:!aNULL:!LOW:!EXPORT:!SSLv2");
     // Verification of the peer is via TrustEngine only.
     curl_easy_setopt(handle,CURLOPT_SSL_VERIFYPEER,0);
+    curl_easy_setopt(handle,CURLOPT_CAINFO,NULL);
     curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,&curl_header_hook);
     curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,&curl_write_hook);
     curl_easy_setopt(handle,CURLOPT_DEBUGFUNCTION,&curl_debug_hook);
@@ -404,7 +428,7 @@ string CURLSOAPTransport::getContentType() const
     return content_type ? content_type : "";
 }
 
-void CURLSOAPTransport::send(istream& in)
+void CURLSOAPTransport::send(istream* in)
 {
 #ifdef _DEBUG
     xmltooling::NDC ndc("send");
@@ -428,13 +452,13 @@ void CURLSOAPTransport::send(istream& in)
         curl_easy_setopt(m_handle,CURLOPT_POST,1);
         m_headers=curl_slist_append(m_headers,"Transfer-Encoding: chunked");
         curl_easy_setopt(m_handle,CURLOPT_READFUNCTION,&curl_read_hook);
-        curl_easy_setopt(m_handle,CURLOPT_READDATA,&in);
+        curl_easy_setopt(m_handle,CURLOPT_READDATA,in);
     }
     else if (in) {
         char buf[1024];
-        while (in) {
-            in.read(buf,1024);
-            msg.append(buf,in.gcount());
+        while (*in) {
+            in->read(buf,1024);
+            msg.append(buf,in->gcount());
         }
         curl_easy_setopt(m_handle,CURLOPT_POST,1);
         curl_easy_setopt(m_handle,CURLOPT_READFUNCTION,NULL);
@@ -513,10 +537,10 @@ size_t xmltooling::curl_header_hook(void* ptr, size_t size, size_t nmemb, void*
 // callback to send data to server
 size_t xmltooling::curl_read_hook(void* ptr, size_t size, size_t nmemb, void* stream)
 {
-    // *stream is actually an istream object
-    istream& buf=*(reinterpret_cast<istream*>(stream));
-    buf.read(reinterpret_cast<char*>(ptr),size*nmemb);
-    return buf.gcount();
+    // stream is actually an istream pointer
+    istream* buf=reinterpret_cast<istream*>(stream);
+    buf->read(reinterpret_cast<char*>(ptr),size*nmemb);
+    return buf->gcount();
 }
 
 // callback to buffer data from server
@@ -589,6 +613,15 @@ CURLcode xmltooling::xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* us
 {
     CURLSOAPTransport* conf = reinterpret_cast<CURLSOAPTransport*>(userptr);
 
+    // Manually disable SSLv2 so we're not dependent on libcurl to do it.
+    // Also disable the ticket option where implemented, since this breaks a variety
+    // of servers. Newer libcurl also does this for us.
+#ifdef SSL_OP_NO_TICKET
+    SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET);
+#else
+    SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
+#endif
+
 #ifndef XMLTOOLING_NO_XMLSEC
     if (conf->m_cred)
         conf->m_cred->attach(ssl_ctx);