Updating versions, working on new installer.
[shibboleth/cpp-sp.git] / isapi_shib / isapi_shib.cpp
index 9bc2e45..a84d748 100644 (file)
@@ -34,6 +34,7 @@
 #include <xmltooling/util/NDC.h>
 #include <xmltooling/util/XMLConstants.h>
 #include <xmltooling/util/XMLHelper.h>
+#include <xercesc/util/Base64.hpp>
 #include <xercesc/util/XMLUniDefs.hpp>
 
 #include <set>
@@ -93,6 +94,9 @@ namespace {
     SPConfig* g_Config = NULL;
     map<string,site_t> g_Sites;
     bool g_bNormalizeRequest = true;
+    string g_unsetHeaderValue;
+    bool g_checkSpoofing = true;
+    vector<string> g_NoCerts;
 }
 
 BOOL LogEvent(
@@ -190,9 +194,15 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
     
     // Access the implementation-specifics for site mappings.
     ServiceProvider* sp=g_Config->getServiceProvider();
-    xmltooling::Locker locker(sp);
-    const PropertySet* props=sp->getPropertySet("Local");
+    Locker locker(sp);
+    const PropertySet* props=sp->getPropertySet("InProcess");
     if (props) {
+        pair<bool,const char*> unsetValue=props->getString("unsetHeaderValue");
+        if (unsetValue.first)
+            g_unsetHeaderValue = unsetValue.second;
+        pair<bool,bool> checkSpoofing=props->getBool("checkSpoofing");
+        if (checkSpoofing.first && !checkSpoofing.second)
+            g_checkSpoofing = false;
         const DOMElement* impl=XMLHelper::getFirstChildElement(props->getElement(),Implementation);
         if (impl && (impl=XMLHelper::getFirstChildElement(impl,ISAPI))) {
             const XMLCh* flag=impl->getAttributeNS(NULL,normalizeRequest);
@@ -340,16 +350,14 @@ class ShibTargetIsapiF : public AbstractSPRequest
   PHTTP_FILTER_CONTEXT m_pfc;
   PHTTP_FILTER_PREPROC_HEADERS m_pn;
   map<string,string> m_headers;
-  vector<string> m_certs;
   int m_port;
   string m_scheme,m_hostname,m_uri;
   mutable string m_remote_addr,m_content_type,m_method;
+  dynabuf m_allhttp;
 
 public:
-  ShibTargetIsapiF(PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, const site_t& site) {
-
-    m_pfc = pfc;
-    m_pn = pn;
+  ShibTargetIsapiF(PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pn, const site_t& site)
+      : m_pfc(pfc), m_pn(pn), m_allhttp(4096) {
 
     // URL path always come from IIS.
     dynabuf var(256);
@@ -429,10 +437,16 @@ public:
     if (level >= SPError)
         LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg.c_str());
   }
-  void clearHeader(const char* name) {
-    string hdr(!strcmp(name,"REMOTE_USER") ? "remote-user" : name);
+  void clearHeader(const char* rawname, const char* cginame) {
+    if (g_checkSpoofing) {
+        if (m_allhttp.empty())
+               GetServerVariable(m_pfc,"ALL_HTTP",m_allhttp,4096);
+        if (strstr(m_allhttp, cginame))
+            throw opensaml::SecurityPolicyException("Attempt to spoof header ($1) was detected.", params(1, rawname));
+    }
+    string hdr(!strcmp(rawname,"REMOTE_USER") ? "remote-user" : rawname);
     hdr += ':';
-    m_pn->SetHeader(m_pfc, const_cast<char*>(hdr.c_str()), "");
+    m_pn->SetHeader(m_pfc, const_cast<char*>(hdr.c_str()), const_cast<char*>(g_unsetHeaderValue.c_str()));
   }
   void setHeader(const char* name, const char* value) {
     string hdr(name);
@@ -442,8 +456,8 @@ public:
   string getHeader(const char* name) const {
     string hdr(name);
     hdr += ':';
-    dynabuf buf(1024);
-    GetHeader(m_pn, m_pfc, const_cast<char*>(hdr.c_str()), buf, 1024, false);
+    dynabuf buf(256);
+    GetHeader(m_pn, m_pfc, const_cast<char*>(hdr.c_str()), buf, 256, false);
     return string(buf);
   }
   void setRemoteUser(const char* user) {
@@ -503,7 +517,7 @@ public:
   }
 
   const vector<string>& getClientCertificates() const {
-      return m_certs;
+      return g_NoCerts;
   }
   
   // The filter never processes the POST, so stub these methods.
@@ -616,12 +630,12 @@ class ShibTargetIsapiE : public AbstractSPRequest
 {
   LPEXTENSION_CONTROL_BLOCK m_lpECB;
   map<string,string> m_headers;
-  vector<string> m_certs;
+  mutable vector<string> m_certs;
   mutable string m_body;
   mutable bool m_gotBody;
   int m_port;
   string m_scheme,m_hostname,m_uri;
-  mutable string m_remote_addr;
+  mutable string m_remote_addr,m_remote_user;
   
 public:
   ShibTargetIsapiE(LPEXTENSION_CONTROL_BLOCK lpECB, const site_t& site) : m_lpECB(lpECB), m_gotBody(false) {
@@ -717,6 +731,15 @@ public:
   long getContentLength() const {
       return m_lpECB->cbTotalBytes;
   }
+  string getRemoteUser() const {
+    if (m_remote_user.empty()) {
+        dynabuf var(16);
+        GetServerVariable(m_lpECB, "REMOTE_USER", var, 32, false);
+        if (!var.empty())
+            m_remote_user = var;
+    }
+    return m_remote_user;
+  }
   string getRemoteAddr() const {
     if (m_remote_addr.empty()) {
         dynabuf var(16);
@@ -726,7 +749,7 @@ public:
     }
     return m_remote_addr;
   }
-  void log(SPLogLevel level, const string& msg) {
+  void log(SPLogLevel level, const string& msg) const {
       AbstractSPRequest::log(level,msg);
       if (level >= SPError)
           LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg.c_str());
@@ -826,14 +849,29 @@ public:
   }
 
   const vector<string>& getClientCertificates() const {
+      if (m_certs.empty()) {
+        char CertificateBuf[8192];
+        CERT_CONTEXT_EX ccex;
+        ccex.cbAllocated = sizeof(CertificateBuf);
+        ccex.CertContext.pbCertEncoded = (BYTE*)CertificateBuf;
+        DWORD dwSize = sizeof(ccex);
+
+        if (m_lpECB->ServerSupportFunction(m_lpECB->ConnID, HSE_REQ_GET_CERT_INFO_EX, (LPVOID)&ccex, (LPDWORD)dwSize, NULL)) {
+            if (ccex.CertContext.cbCertEncoded) {
+                unsigned int outlen;
+                XMLByte* serialized = Base64::encode(reinterpret_cast<XMLByte*>(CertificateBuf), ccex.CertContext.cbCertEncoded, &outlen);
+                m_certs.push_back(reinterpret_cast<char*>(serialized));
+                XMLString::release(&serialized);
+            }
+        }
+      }
       return m_certs;
   }
 
   // Not used in the extension.
-  virtual void clearHeader(const char* name) { throw runtime_error("clearHeader not implemented"); }
-  virtual void setHeader(const char* name, const char* value) { throw runtime_error("setHeader not implemented"); }
-  virtual void setRemoteUser(const char* user) { throw runtime_error("setRemoteUser not implemented"); }
-  virtual string getRemoteUser() const { throw runtime_error("getRemoteUser not implemented"); }
+  void clearHeader(const char* rawname, const char* cginame) { throw runtime_error("clearHeader not implemented"); }
+  void setHeader(const char* name, const char* value) { throw runtime_error("setHeader not implemented"); }
+  void setRemoteUser(const char* user) { throw runtime_error("setRemoteUser not implemented"); }
 };
 
 extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)