Improve error msg.
[shibboleth/sp.git] / isapi_shib / isapi_shib.cpp
index 4465e4f..7ca3057 100644 (file)
@@ -54,13 +54,12 @@ using namespace std;
 // globals
 namespace {
     static const XMLCh path[] =             UNICODE_LITERAL_4(p,a,t,h);
-    static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);
+    static const XMLCh validate[] =         UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);
     static const XMLCh name[] =             UNICODE_LITERAL_4(n,a,m,e);
     static const XMLCh port[] =             UNICODE_LITERAL_4(p,o,r,t);
     static const XMLCh sslport[] =          UNICODE_LITERAL_7(s,s,l,p,o,r,t);
     static const XMLCh scheme[] =           UNICODE_LITERAL_6(s,c,h,e,m,e);
     static const XMLCh id[] =               UNICODE_LITERAL_2(i,d);
-    static const XMLCh Implementation[] =   UNICODE_LITERAL_14(I,m,p,l,e,m,e,n,t,a,t,i,o,n);
     static const XMLCh ISAPI[] =            UNICODE_LITERAL_5(I,S,A,P,I);
     static const XMLCh Alias[] =            UNICODE_LITERAL_5(A,l,i,a,s);
     static const XMLCh normalizeRequest[] = UNICODE_LITERAL_16(n,o,r,m,a,l,i,z,e,R,e,q,u,e,s,t);
@@ -96,6 +95,7 @@ namespace {
     bool g_bNormalizeRequest = true;
     string g_unsetHeaderValue;
     bool g_checkSpoofing = true;
+    bool g_catchAll = false;
     vector<string> g_NoCerts;
 }
 
@@ -151,12 +151,6 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
         return TRUE;
     }
 
-    LPCSTR schemadir=getenv("SHIBSP_SCHEMAS");
-    if (!schemadir)
-        schemadir=SHIBSP_SCHEMAS;
-    LPCSTR config=getenv("SHIBSP_CONFIG");
-    if (!config)
-        config=SHIBSP_CONFIG;
     g_Config=&SPConfig::getConfig();
     g_Config->setFeatures(
         SPConfig::Listener |
@@ -166,13 +160,17 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
         SPConfig::Logging |
         SPConfig::Handlers
         );
-    if (!g_Config->init(schemadir)) {
+    if (!g_Config->init()) {
         g_Config=NULL;
         LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL,
                 "Filter startup failed during library initialization, check native log for help.");
         return FALSE;
     }
 
+    LPCSTR config=getenv("SHIBSP_CONFIG");
+    if (!config)
+        config=SHIBSP_CONFIG;
+
     try {
         DOMDocument* dummydoc=XMLToolingConfig::getConfig().getParser().newDocument();
         XercesJanitor<DOMDocument> docjanitor(dummydoc);
@@ -193,7 +191,7 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
         return FALSE;
     }
     
-    // Access the implementation-specifics for site mappings.
+    // Access implementation-specifics and site mappings.
     ServiceProvider* sp=g_Config->getServiceProvider();
     Locker locker(sp);
     const PropertySet* props=sp->getPropertySet("InProcess");
@@ -201,19 +199,21 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
         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);
-            g_bNormalizeRequest=(!flag || !*flag || *flag==chDigit_1 || *flag==chLatin_t);
-            impl=XMLHelper::getFirstChildElement(impl,Site);
-            while (impl) {
-                auto_ptr_char id(impl->getAttributeNS(NULL,id));
+        pair<bool,bool> flag=props->getBool("checkSpoofing");
+        g_checkSpoofing = !flag.first || flag.second;
+        flag=props->getBool("catchAll");
+        g_catchAll = flag.first && flag.second;
+
+        props = props->getPropertySet("ISAPI");
+        if (props) {
+            flag = props->getBool("normalizeRequest");
+            g_bNormalizeRequest = !flag.first || flag.second;
+            const DOMElement* child = XMLHelper::getFirstChildElement(props->getElement(),Site);
+            while (child) {
+                auto_ptr_char id(child->getAttributeNS(NULL,id));
                 if (id.get())
-                    g_Sites.insert(pair<string,site_t>(id.get(),site_t(impl)));
-                impl=XMLHelper::getNextSiblingElement(impl,Site);
+                    g_Sites.insert(pair<string,site_t>(id.get(),site_t(child)));
+                child=XMLHelper::getNextSiblingElement(child,Site);
             }
         }
     }
@@ -352,18 +352,18 @@ class ShibTargetIsapiF : public AbstractSPRequest
   PHTTP_FILTER_PREPROC_HEADERS m_pn;
   multimap<string,string> m_headers;
   int m_port;
-  string m_scheme,m_hostname,m_uri;
+  string m_scheme,m_hostname;
   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), m_allhttp(4096) {
+      : AbstractSPRequest(SHIBSP_LOGCAT".ISAPI"), m_pfc(pfc), m_pn(pn), m_allhttp(4096) {
 
     // URL path always come from IIS.
     dynabuf var(256);
     GetHeader(pn,pfc,"url",var,256,false);
-    m_uri = var;
+    setRequestURI(var);
 
     // Port may come from IIS or from site def.
     if (!g_bNormalizeRequest || (pfc->fIsSecurePort && site.m_sslport.empty()) || (!pfc->fIsSecurePort && site.m_port.empty())) {
@@ -400,9 +400,6 @@ public:
   int getPort() const {
     return m_port;
   }
-  const char* getRequestURI() const {
-    return m_uri.c_str();
-  }
   const char* getMethod() const {
     if (m_method.empty()) {
         dynabuf var(5);
@@ -481,9 +478,10 @@ public:
     hdr += "\r\n";
     const char* codestr="200 OK";
     switch (status) {
-        case XMLTOOLING_HTTP_STATUS_FORBIDDEN:codestr="403 Forbidden"; break;
-        case XMLTOOLING_HTTP_STATUS_NOTFOUND: codestr="404 Not Found"; break;
-        case XMLTOOLING_HTTP_STATUS_ERROR:    codestr="500 Server Error"; break;
+        case XMLTOOLING_HTTP_STATUS_UNAUTHORIZED:   codestr="401 Authorization Required"; break;
+        case XMLTOOLING_HTTP_STATUS_FORBIDDEN:      codestr="403 Forbidden"; break;
+        case XMLTOOLING_HTTP_STATUS_NOTFOUND:       codestr="404 Not Found"; break;
+        case XMLTOOLING_HTTP_STATUS_ERROR:          codestr="500 Server Error"; break;
     }
     m_pfc->ServerSupportFunction(m_pfc, SF_REQ_SEND_RESPONSE_HEADER, (void*)codestr, (DWORD)hdr.c_str(), 0);
     char buf[1024];
@@ -597,11 +595,12 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat
         LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, e.what());
         return WriteClientError(pfc,"Shibboleth Filter caught an exception, check Event Log for details.");
     }
-#ifndef _DEBUG
     catch(...) {
-        return WriteClientError(pfc,"Shibboleth Filter caught an unknown exception.");
+        LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "Shibboleth Filter threw an unknown exception.");
+        if (g_catchAll)
+            return WriteClientError(pfc,"Shibboleth Filter threw an unknown exception.");
+        throw;
     }
-#endif
 
     return WriteClientError(pfc,"Shibboleth Filter reached unreachable code, save my walrus!");
 }
@@ -639,7 +638,8 @@ class ShibTargetIsapiE : public AbstractSPRequest
   mutable string m_remote_addr,m_remote_user;
   
 public:
-  ShibTargetIsapiE(LPEXTENSION_CONTROL_BLOCK lpECB, const site_t& site) : m_lpECB(lpECB), m_gotBody(false) {
+  ShibTargetIsapiE(LPEXTENSION_CONTROL_BLOCK lpECB, const site_t& site)
+      : AbstractSPRequest(SHIBSP_LOGCAT".ISAPI"), m_lpECB(lpECB), m_gotBody(false) {
     dynabuf ssl(5);
     GetServerVariable(lpECB,"HTTPS",ssl,5);
     bool SSL=(ssl=="on" || ssl=="ON");
@@ -692,25 +692,29 @@ public:
      *      PathInfo:   /SAML/POST
      */
     
+    string uri;
+
     // Clearly we're only in bad mode if path info exists at all.
     if (lpECB->lpszPathInfo && *(lpECB->lpszPathInfo)) {
         if (strstr(lpECB->lpszPathInfo,url))
             // Pretty good chance we're in bad mode, unless the PathInfo repeats the path itself.
-            m_uri = lpECB->lpszPathInfo;
+            uri = lpECB->lpszPathInfo;
         else {
-            m_uri = url;
-            m_uri += lpECB->lpszPathInfo;
+            uri = url;
+            uri += lpECB->lpszPathInfo;
         }
     }
     else {
-        m_uri = url;
+        uri = url;
     }
     
     // For consistency with Apache, let's add the query string.
     if (lpECB->lpszQueryString && *(lpECB->lpszQueryString)) {
-        m_uri += '?';
-        m_uri += lpECB->lpszQueryString;
+        uri += '?';
+        uri += lpECB->lpszQueryString;
     }
+
+    setRequestURI(uri.c_str());
   }
   ~ShibTargetIsapiE() { }
 
@@ -723,9 +727,6 @@ public:
   int getPort() const {
     return m_port;
   }
-  const char* getRequestURI() const {
-    return m_uri.c_str();
-  }
   const char* getMethod() const {
     return m_lpECB->lpszMethod;
   }
@@ -811,9 +812,10 @@ public:
     hdr += "\r\n";
     const char* codestr="200 OK";
     switch (status) {
-        case XMLTOOLING_HTTP_STATUS_FORBIDDEN:codestr="403 Forbidden"; break;
-        case XMLTOOLING_HTTP_STATUS_NOTFOUND: codestr="404 Not Found"; break;
-        case XMLTOOLING_HTTP_STATUS_ERROR:    codestr="500 Server Error"; break;
+        case XMLTOOLING_HTTP_STATUS_UNAUTHORIZED:   codestr="401 Authorization Required"; break;
+        case XMLTOOLING_HTTP_STATUS_FORBIDDEN:      codestr="403 Forbidden"; break;
+        case XMLTOOLING_HTTP_STATUS_NOTFOUND:       codestr="404 Not Found"; break;
+        case XMLTOOLING_HTTP_STATUS_ERROR:          codestr="500 Server Error"; break;
     }
     m_lpECB->ServerSupportFunction(m_lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, (void*)codestr, 0, (LPDWORD)hdr.c_str());
     char buf[1024];
@@ -892,7 +894,7 @@ extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
         // Match site instance to host name, skip if no match.
         map<string,site_t>::const_iterator map_i=g_Sites.find(static_cast<char*>(buf));
         if (map_i==g_Sites.end())
-            return WriteClientError(lpECB, "Shibboleth Extension not configured for this web site.");
+            return WriteClientError(lpECB, "Shibboleth Extension not configured for web site (check <ISAPI> mappings in configuration).");
 
         ShibTargetIsapiE ste(lpECB, map_i->second);
         pair<bool,long> res = ste.getServiceProvider().doHandler(ste);
@@ -914,11 +916,12 @@ extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
         LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, e.what());
         return WriteClientError(lpECB,"Shibboleth Extension caught an exception, check Event Log for details.");
     }
-#ifndef _DEBUG
     catch(...) {
-        return WriteClientError(lpECB,"Shibboleth Extension caught an unknown exception.");
+        LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "Shibboleth Extension threw an unknown exception.");
+        if (g_catchAll)
+            return WriteClientError(lpECB,"Shibboleth Extension threw an unknown exception.");
+        throw;
     }
-#endif
 
     // If we get here we've got an error.
     return HSE_STATUS_ERROR;