X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=isapi_shib%2Fisapi_shib.cpp;h=1f01f44186083f87ba4677a0228e99cb6030aeac;hb=4f85e385a59229b06f2ae6eef7a58a1d403f8959;hp=6b66058515c6e418d1cead76c0f6dfd1ff23c1db;hpb=ad5ec3841b42da21f68c895059a992a4ebb9bc63;p=shibboleth%2Fsp.git diff --git a/isapi_shib/isapi_shib.cpp b/isapi_shib/isapi_shib.cpp index 6b66058..1f01f44 100644 --- a/isapi_shib/isapi_shib.cpp +++ b/isapi_shib/isapi_shib.cpp @@ -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); @@ -89,6 +88,11 @@ namespace { string m_scheme,m_port,m_sslport,m_name; set m_aliases; }; + + struct context_t { + char* m_user; + bool m_checked; + }; HINSTANCE g_hinstDLL; SPConfig* g_Config = NULL; @@ -96,6 +100,7 @@ namespace { bool g_bNormalizeRequest = true; string g_unsetHeaderValue; bool g_checkSpoofing = true; + bool g_catchAll = false; vector g_NoCerts; } @@ -151,12 +156,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 +165,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 docjanitor(dummydoc); @@ -193,7 +196,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 +204,21 @@ extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer) pair unsetValue=props->getString("unsetHeaderValue"); if (unsetValue.first) g_unsetHeaderValue = unsetValue.second; - pair 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 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(id.get(),site_t(impl))); - impl=XMLHelper::getNextSiblingElement(impl,Site); + g_Sites.insert(pair(id.get(),site_t(child))); + child=XMLHelper::getNextSiblingElement(child,Site); } } } @@ -350,20 +355,20 @@ class ShibTargetIsapiF : public AbstractSPRequest { PHTTP_FILTER_CONTEXT m_pfc; PHTTP_FILTER_PREPROC_HEADERS m_pn; - map m_headers; + multimap 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())) { @@ -388,6 +393,14 @@ public: m_hostname = var; if (site.m_name!=m_hostname && site.m_aliases.find(m_hostname)==site.m_aliases.end()) m_hostname=site.m_name; + + if (!pfc->pFilterContext) { + pfc->pFilterContext = pfc->AllocMem(pfc, sizeof(context_t), NULL); + if (static_cast(pfc->pFilterContext)) { + static_cast(pfc->pFilterContext)->m_user = NULL; + static_cast(pfc->pFilterContext)->m_checked = false; + } + } } ~ShibTargetIsapiF() { } @@ -400,9 +413,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); @@ -439,7 +449,7 @@ public: LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, msg.c_str()); } void clearHeader(const char* rawname, const char* cginame) { - if (g_checkSpoofing) { + if (g_checkSpoofing && m_pfc->pFilterContext && !static_cast(m_pfc->pFilterContext)->m_checked) { if (m_allhttp.empty()) GetServerVariable(m_pfc,"ALL_HTTP",m_allhttp,4096); if (strstr(m_allhttp, cginame)) @@ -463,6 +473,12 @@ public: } void setRemoteUser(const char* user) { setHeader("remote-user", user); + if (m_pfc->pFilterContext) { + if (!user || !*user) + static_cast(m_pfc->pFilterContext)->m_user = NULL; + else if (static_cast(m_pfc->pFilterContext)->m_user = (char*)m_pfc->AllocMem(m_pfc, sizeof(char) * (strlen(user) + 1), NULL)) + strcpy(static_cast(m_pfc->pFilterContext)->m_user, user); + } } string getRemoteUser() const { return getHeader("remote-user"); @@ -470,20 +486,21 @@ public: void setResponseHeader(const char* name, const char* value) { // Set for later. if (value) - m_headers[name] = value; + m_headers.insert(make_pair(name,value)); else m_headers.erase(name); } long sendResponse(istream& in, long status) { string hdr = string("Connection: close\r\n"); - for (map::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i) + for (multimap::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i) hdr += i->first + ": " + i->second + "\r\n"; 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]; @@ -501,7 +518,7 @@ public: "Content-Length: 40\r\n" "Expires: 01-Jan-1997 12:00:00 GMT\r\n" "Cache-Control: private,no-store,no-cache\r\n"; - for (map::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i) + for (multimap::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i) hdr += i->first + ": " + i->second + "\r\n"; hdr += "\r\n"; m_pfc->ServerSupportFunction(m_pfc, SF_REQ_SEND_RESPONSE_HEADER, "302 Please Wait", (DWORD)hdr.c_str(), 0); @@ -549,7 +566,7 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat if (notificationType==SF_NOTIFY_LOG) { if (pfc->pFilterContext) - ((PHTTP_FILTER_LOG)pvNotification)->pszClientUserName=static_cast(pfc->pFilterContext); + ((PHTTP_FILTER_LOG)pvNotification)->pszClientUserName=static_cast(pfc->pFilterContext)->m_user; return SF_STATUS_REQ_NEXT_NOTIFICATION; } @@ -573,6 +590,8 @@ extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificat // "false" because we don't override the Shib settings pair res = stf.getServiceProvider().doAuthentication(stf); + if (pfc->pFilterContext) + static_cast(pfc->pFilterContext)->m_checked = true; if (res.first) return res.second; // "false" because we don't override the Shib settings @@ -597,11 +616,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!"); } @@ -630,7 +650,7 @@ DWORD WriteClientError(LPEXTENSION_CONTROL_BLOCK lpECB, const char* msg) class ShibTargetIsapiE : public AbstractSPRequest { LPEXTENSION_CONTROL_BLOCK m_lpECB; - map m_headers; + multimap m_headers; mutable vector m_certs; mutable string m_body; mutable bool m_gotBody; @@ -639,7 +659,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 +713,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 +748,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; } @@ -773,7 +795,7 @@ public: void setResponseHeader(const char* name, const char* value) { // Set for later. if (value) - m_headers[name] = value; + m_headers.insert(make_pair(name,value)); else m_headers.erase(name); } @@ -806,14 +828,15 @@ public: } long sendResponse(istream& in, long status) { string hdr = string("Connection: close\r\n"); - for (map::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i) + for (multimap::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i) hdr += i->first + ": " + i->second + "\r\n"; 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]; @@ -830,7 +853,7 @@ public: "Content-Length: 40\r\n" "Expires: 01-Jan-1997 12:00:00 GMT\r\n" "Cache-Control: private,no-store,no-cache\r\n"; - for (map::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i) + for (multimap::const_iterator i=m_headers.begin(); i!=m_headers.end(); ++i) hdr += i->first + ": " + i->second + "\r\n"; hdr += "\r\n"; m_lpECB->ServerSupportFunction(m_lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, "302 Moved", 0, (LPDWORD)hdr.c_str()); @@ -892,7 +915,7 @@ extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) // Match site instance to host name, skip if no match. map::const_iterator map_i=g_Sites.find(static_cast(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 mappings in configuration)."); ShibTargetIsapiE ste(lpECB, map_i->second); pair res = ste.getServiceProvider().doHandler(ste); @@ -914,11 +937,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;