https://issues.shibboleth.net/jira/browse/SSPCPP-255
[shibboleth/cpp-sp.git] / fastcgi / shibresponder.cpp
index 86c374c..f1b7dcf 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- *  Copyright 2001-2007 Internet2\r
+ *  Copyright 2001-2009 Internet2\r
  * \r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
@@ -32,6 +32,7 @@
 #include <fcgio.h>\r
 \r
 using namespace shibtarget;\r
+using namespace saml;\r
 using namespace std;\r
 \r
 typedef enum {\r
@@ -40,6 +41,8 @@ typedef enum {
     SHIB_RETURN_DONE\r
 } shib_return_t;\r
 \r
+set<string> g_allowedSchemes;\r
+\r
 class ShibTargetFCGI : public ShibTarget\r
 {\r
     FCGX_Request* m_req;\r
@@ -47,6 +50,14 @@ class ShibTargetFCGI : public ShibTarget
     string m_cookie;\r
     map<string, string> m_headers;\r
 \r
+    void checkString(const string& s, const char* msg) {\r
+        string::const_iterator e = s.end();\r
+        for (string::const_iterator i=s.begin(); i!=e; ++i) {\r
+            if (iscntrl(*i))\r
+                throw runtime_error(msg);\r
+        }\r
+    }\r
+\r
 public:\r
     ShibTargetFCGI(FCGX_Request* req, char* post_data, const char* scheme=NULL, const char* hostname=NULL, int port=0)\r
         : m_req(req), m_body(post_data) {\r
@@ -146,9 +157,12 @@ public:
         const string& content_type="text/html",\r
         const saml::Iterator<header_t>& headers=EMPTY(header_t)) {\r
 \r
+        checkString(content_type, "Detected control character in a response header.");\r
         string hdr = string ("Connection: close\r\nContent-type: ") + content_type + "\r\n" + m_cookie;\r
         while (headers.hasNext()) {\r
             const header_t& h=headers.next();\r
+            checkString(h.first, "Detected control character in a response header.");\r
+            checkString(h.second, "Detected control character in a response header.");\r
             hdr += h.first + ": " + h.second + "\r\n";\r
         }\r
 \r
@@ -164,6 +178,9 @@ public:
     }\r
 \r
     virtual void* sendRedirect(const string& url) {\r
+        checkString(url, "Detected control character in an attempted redirect.");\r
+        if (g_allowedSchemes.find(url.substr(0, url.find(':'))) == g_allowedSchemes.end())\r
+            throw runtime_error("Invalid scheme in attempted redirect.");\r
         cout << "Status: 302 Please Wait" << "\r\n" << "Location: " << url << "\r\n" << m_cookie << "\r\n"\r
             << "<HTML><BODY>Redirecting...</BODY></HTML>";\r
         return (void*)SHIB_RETURN_DONE;\r
@@ -260,6 +277,29 @@ int main(void)
             cerr << "failed to load Shibboleth configuration" << endl;\r
             exit(1);\r
         }\r
+\r
+        IConfig* conf=g_Config->getINI();\r
+        Locker locker(conf);\r
+        const IPropertySet* props=conf->getPropertySet("Local");\r
+        if (props) {\r
+            pair<bool,const char*> str=props->getString("allowedSchemes");\r
+            if (str.first) {\r
+                string schemes=str.second;\r
+                unsigned int j=0;\r
+                for (unsigned int i=0;  i < schemes.length();  i++) {\r
+                    if (schemes.at(i)==' ') {\r
+                        g_allowedSchemes.insert(schemes.substr(j, i-j));\r
+                        j = i+1;\r
+                    }\r
+                }\r
+                g_allowedSchemes.insert(schemes.substr(j, schemes.length()-j));\r
+            }\r
+        }\r
+        if (g_allowedSchemes.empty()) {\r
+            g_allowedSchemes.insert("https");\r
+            g_allowedSchemes.insert("http");\r
+        }\r
+\r
     }\r
     catch (exception& e) {\r
         cerr << "exception while initializing Shibboleth configuration:" << e.what() << endl;\r