Merge commit '2.5.0' into moonshot-packaging-fixes
[shibboleth/sp.git] / shibsp / handler / impl / RemotedHandler.cpp
index 27b0b23..668ed9d 100644 (file)
@@ -33,6 +33,7 @@
 #include "handler/RemotedHandler.h"
 
 #include <algorithm>
+#include <boost/scoped_ptr.hpp>
 #include <xmltooling/unicode.h>
 #include <xercesc/util/Base64.hpp>
 
 # include <xsec/framework/XSECProvider.hpp>
 #endif
 
+#ifdef HAVE_GSSAPI_NAMINGEXTS
+# ifdef SHIBSP_HAVE_GSSMIT
+#  include <gssapi/gssapi_ext.h>
+# endif
+#endif
+
 using namespace shibsp;
 using namespace opensaml;
 using namespace xmltooling;
 using namespace xercesc;
+using namespace boost;
 using namespace std;
 
 #ifndef SHIBSP_LITE
@@ -59,27 +67,28 @@ namespace shibsp {
         public HTTPRequest
     {
         DDF& m_input;
-        mutable CGIParser* m_parser;
+        mutable scoped_ptr<CGIParser> m_parser;
         mutable vector<XSECCryptoX509*> m_certs;
 #ifdef SHIBSP_HAVE_GSSAPI
-        mutable gss_ctx_id_t m_gss;
+        mutable gss_ctx_id_t m_gssctx;
+        mutable gss_name_t m_gssname;
 #endif
     public:
         RemotedRequest(DDF& input) : m_input(input), m_parser(nullptr)
 #ifdef SHIBSP_HAVE_GSSAPI
-            , m_gss(GSS_C_NO_CONTEXT)
+            , m_gssctx(GSS_C_NO_CONTEXT), m_gssname(GSS_C_NO_NAME)
 #endif
         {
         }
 
         virtual ~RemotedRequest() {
             for_each(m_certs.begin(), m_certs.end(), xmltooling::cleanup<XSECCryptoX509>());
-            delete m_parser;
 #ifdef SHIBSP_HAVE_GSSAPI
-            if (m_gss != GSS_C_NO_CONTEXT) {
-                OM_uint32 minor;
-                gss_delete_sec_context(&minor, &m_gss, GSS_C_NO_BUFFER);
-            }
+            OM_uint32 minor;
+            if (m_gssctx != GSS_C_NO_CONTEXT)
+                gss_delete_sec_context(&minor, &m_gssctx, GSS_C_NO_BUFFER);
+            if (m_gssname != GSS_C_NO_NAME)
+                gss_release_name(&minor, &m_gssname);
 #endif
         }
 
@@ -124,6 +133,7 @@ namespace shibsp {
 #ifdef SHIBSP_HAVE_GSSAPI
         // GSSRequest
         gss_ctx_id_t getGSSContext() const;
+        gss_name_t getGSSName() const;
 #endif
 
         // HTTPRequest
@@ -164,19 +174,19 @@ namespace shibsp {
 const char* RemotedRequest::getParameter(const char* name) const
 {
     if (!m_parser)
-        m_parser=new CGIParser(*this);
+        m_parser.reset(new CGIParser(*this));
     
-    pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
+    pair<CGIParser::walker,CGIParser::walker> bounds = m_parser->getParameters(name);
     return (bounds.first==bounds.second) ? nullptr : bounds.first->second;
 }
 
 std::vector<const char*>::size_type RemotedRequest::getParameters(const char* name, std::vector<const char*>& values) const
 {
     if (!m_parser)
-        m_parser=new CGIParser(*this);
+        m_parser.reset(new CGIParser(*this));
 
-    pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
-    while (bounds.first!=bounds.second) {
+    pair<CGIParser::walker,CGIParser::walker> bounds = m_parser->getParameters(name);
+    while (bounds.first != bounds.second) {
         values.push_back(bounds.first->second);
         ++bounds.first;
     }
@@ -195,7 +205,8 @@ const std::vector<XSECCryptoX509*>& RemotedRequest::getClientCertificates() cons
                     x509->loadX509PEM(cert.string(), cert.strlen());
                 else
                     x509->loadX509Base64Bin(cert.string(), cert.strlen());
-                m_certs.push_back(x509.release());
+                m_certs.push_back(x509.get());
+                x509.release();
             }
             catch(XSECException& e) {
                 auto_ptr_char temp(e.getMsg());
@@ -213,19 +224,19 @@ const std::vector<XSECCryptoX509*>& RemotedRequest::getClientCertificates() cons
 #ifdef SHIBSP_HAVE_GSSAPI
 gss_ctx_id_t RemotedRequest::getGSSContext() const
 {
-    if (m_gss == GSS_C_NO_CONTEXT) {
+    if (m_gssctx == GSS_C_NO_CONTEXT) {
         const char* encoded = m_input["gss_context"].string();
         if (encoded) {
             xsecsize_t x;
-            XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(encoded), &x);
+            XMLByte* decoded = Base64::decode(reinterpret_cast<const XMLByte*>(encoded), &x);
             if (decoded) {
                 gss_buffer_desc importbuf;
                 importbuf.length = x;
                 importbuf.value = decoded;
                 OM_uint32 minor;
-                OM_uint32 major = gss_import_sec_context(&minor, &importbuf, &m_gss);
+                OM_uint32 major = gss_import_sec_context(&minor, &importbuf, &m_gssctx);
                 if (major != GSS_S_COMPLETE)
-                    m_gss = GSS_C_NO_CONTEXT;
+                    m_gssctx = GSS_C_NO_CONTEXT;
 #ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
                 XMLString::release(&decoded);
 #else
@@ -234,7 +245,45 @@ gss_ctx_id_t RemotedRequest::getGSSContext() const
             }
         }
     }
-    return m_gss;
+    return m_gssctx;
+}
+
+gss_name_t RemotedRequest::getGSSName() const
+{
+    if (m_gssname == GSS_C_NO_NAME) {
+        const char* encoded = m_input["gss_name"].string();
+        if (encoded) {
+            xsecsize_t x;
+            XMLByte* decoded = Base64::decode(reinterpret_cast<const XMLByte*>(encoded), &x);
+            gss_buffer_desc importbuf;
+            importbuf.length = x;
+            importbuf.value = decoded;
+            OM_uint32 major,minor;
+#ifdef HAVE_GSSAPI_COMPOSITE_NAME
+            major = gss_import_name(&minor, &importbuf, GSS_C_NT_EXPORT_NAME_COMPOSITE, &m_gssname);
+#else
+            major = gss_import_name(&minor, &importbuf, GSS_C_NT_EXPORT_NAME, &m_gssname);
+#endif
+            if (major != GSS_S_COMPLETE)
+                m_gssname = GSS_C_NO_NAME;
+#ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
+            XMLString::release(&decoded);
+#else
+            XMLString::release((char**)&decoded);
+#endif
+        }
+
+        if (m_gssname == GSS_C_NO_NAME) {
+            gss_ctx_id_t ctx = getGSSContext();
+             if (ctx != GSS_C_NO_CONTEXT) {
+                 OM_uint32 minor;
+                 OM_uint32 major = gss_inquire_context(&minor, ctx, &m_gssname, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+                 if (major != GSS_S_COMPLETE)
+                     m_gssname = GSS_C_NO_NAME;
+             }
+         }
+    }
+    return m_gssname;
 }
 #endif
 
@@ -243,8 +292,8 @@ long RemotedResponse::sendResponse(std::istream& in, long status)
     string msg;
     char buf[1024];
     while (in) {
-        in.read(buf,1024);
-        msg.append(buf,in.gcount());
+        in.read(buf, 1024);
+        msg.append(buf, in.gcount());
     }
     if (!m_output.isstruct())
         m_output.structure();
@@ -283,7 +332,7 @@ void RemotedHandler::setAddress(const char* address)
     if (!conf.isEnabled(SPConfig::InProcess)) {
         ListenerService* listener = conf.getServiceProvider()->getListenerService(false);
         if (listener)
-            listener->regListener(m_address.c_str(),this);
+            listener->regListener(m_address.c_str(), this);
         else
             Category::getInstance(SHIBSP_LOGCAT".Handler").info("no ListenerService available, handler remoting disabled");
     }
@@ -316,8 +365,8 @@ DDF RemotedHandler::wrap(const SPRequest& request, const vector<string>* headers
     in.addmember("hostname").unsafe_string(request.getHostname());
     in.addmember("port").integer(request.getPort());
     in.addmember("content_type").string(request.getContentType().c_str());
-    in.addmember("content_length").integer(request.getContentLength());
     in.addmember("body").string(request.getRequestBody());
+    in.addmember("content_length").integer(request.getContentLength());
     in.addmember("remote_user").string(request.getRemoteUser().c_str());
     in.addmember("client_addr").string(request.getRemoteAddr().c_str());
     in.addmember("method").string(request.getMethod());
@@ -329,7 +378,7 @@ DDF RemotedHandler::wrap(const SPRequest& request, const vector<string>* headers
         string hdr;
         DDF hin = in.addmember("headers").structure();
         if (headers) {
-            for (vector<string>::const_iterator h = headers->begin(); h!=headers->end(); ++h) {
+            for (vector<string>::const_iterator h = headers->begin(); h != headers->end(); ++h) {
                 hdr = request.getHeader(h->c_str());
                 if (!hdr.empty())
                     hin.addmember(h->c_str()).unsafe_string(hdr.c_str());
@@ -370,13 +419,12 @@ DDF RemotedHandler::wrap(const SPRequest& request, const vector<string>* headers
         gss_ctx_id_t ctx = gss->getGSSContext();
         if (ctx != GSS_C_NO_CONTEXT) {
             OM_uint32 minor;
-            gss_buffer_desc contextbuf;
-            contextbuf.length = 0;
-            contextbuf.value = nullptr;
+            gss_buffer_desc contextbuf = GSS_C_EMPTY_BUFFER;
             OM_uint32 major = gss_export_sec_context(&minor, &ctx, &contextbuf);
             if (major == GSS_S_COMPLETE) {
-                xsecsize_t len=0;
-                XMLByte* out=Base64::encode(reinterpret_cast<const XMLByte*>(contextbuf.value), contextbuf.length, &len);
+                xsecsize_t len = 0;
+                XMLByte* out = Base64::encode(reinterpret_cast<const XMLByte*>(contextbuf.value), contextbuf.length, &len);
+                gss_release_buffer(&minor, &contextbuf);
                 if (out) {
                     string ctx;
                     ctx.append(reinterpret_cast<char*>(out), len);
@@ -395,6 +443,37 @@ DDF RemotedHandler::wrap(const SPRequest& request, const vector<string>* headers
                 request.log(SPRequest::SPError, "error while exporting GSS context");
             }
         }
+#ifdef HAVE_GSSAPI_NAMINGEXTS
+        else {
+            gss_name_t name = gss->getGSSName();
+            if (name != GSS_C_NO_NAME) {
+                OM_uint32 minor;
+                gss_buffer_desc namebuf = GSS_C_EMPTY_BUFFER;
+                OM_uint32 major = gss_export_name_composite(&minor, name, &namebuf);
+                if (major == GSS_S_COMPLETE) {
+                    xsecsize_t len = 0;
+                    XMLByte* out = Base64::encode(reinterpret_cast<const XMLByte*>(namebuf.value), namebuf.length, &len);
+                    gss_release_buffer(&minor, &namebuf);
+                    if (out) {
+                        string nm;
+                        nm.append(reinterpret_cast<char*>(out), len);
+#ifdef SHIBSP_XERCESC_HAS_XMLBYTE_RELEASE
+                        XMLString::release(&out);
+#else
+                        XMLString::release((char**)&out);
+#endif
+                        in.addmember("gss_name").string(nm.c_str());
+                    }
+                    else {
+                        request.log(SPRequest::SPError, "error while base64-encoding GSS name");
+                    }
+                }
+                else {
+                    request.log(SPRequest::SPError, "error while exporting GSS name");
+                }
+            }
+        }
+#endif
     }
 #endif
 
@@ -424,7 +503,7 @@ pair<bool,long> RemotedHandler::unwrap(SPRequest& request, DDF& out) const
         istringstream s(h["data"].string());
         return make_pair(true, request.sendResponse(s, h["status"].integer()));
     }
-    return make_pair(false,0L);
+    return make_pair(false, 0L);
 }
 
 HTTPRequest* RemotedHandler::getRequest(DDF& in) const