Start to clean up Unix build.
[shibboleth/cpp-sp.git] / apache / mod_apache.cpp
index df67456..4b2b9c8 100644 (file)
@@ -22,6 +22,8 @@
  * $Id$
  */
 
+#define SHIBSP_LITE
+
 #ifdef SOLARIS2
 #undef _XOPEN_SOURCE    // causes gethostname conflict in unistd.h
 #endif
@@ -44,6 +46,7 @@
 #include <xmltooling/XMLToolingConfig.h>
 #include <xmltooling/util/NDC.h>
 #include <xmltooling/util/Threads.h>
+#include <xmltooling/util/XMLConstants.h>
 #include <xmltooling/util/XMLHelper.h>
 
 #ifdef WIN32
@@ -77,6 +80,8 @@
 using namespace shibsp;
 using namespace xmltooling;
 using namespace std;
+using xercesc::RegularExpression;
+using xercesc::XMLException;
 
 extern "C" module MODULE_VAR_EXPORT mod_shib;
 
@@ -266,7 +271,7 @@ class ShibTargetApache : public AbstractSPRequest
 {
   mutable string m_body;
   mutable bool m_gotBody;
-  vector<XSECCryptoX509*> m_certs;
+  vector<string> m_certs;
 
 public:
   request_rec* m_req;
@@ -324,13 +329,15 @@ public:
     if (m_gotBody || m_req->method_number==M_GET)
         return m_body.c_str();
     // Read the posted data
-    if (ap_setup_client_block(m_req, REQUEST_CHUNKED_DECHUNK)) {
+    if (ap_setup_client_block(m_req, REQUEST_CHUNKED_DECHUNK) != OK) {
         m_gotBody=true;
         log(SPError, "Apache function (setup_client_block) failed while reading request body.");
+        return m_body.c_str();
     }
     if (!ap_should_client_block(m_req)) {
         m_gotBody=true;
         log(SPError, "Apache function (should_client_block) failed while reading request body.");
+        return m_body.c_str();
     }
     if (m_req->remaining > 1024*1024)
         throw opensaml::SecurityPolicyException("Blocked request body larger than 1M size limit.");
@@ -413,13 +420,13 @@ public:
         in.read(buf,1024);
         ap_rwrite(buf,in.gcount(),m_req);
     }
-    return ((status==SAML_HTTP_STATUS_OK) ? DONE : status);
+    return ((status==XMLTOOLING_HTTP_STATUS_OK) ? DONE : status);
   }
   long sendRedirect(const char* url) {
     ap_table_set(m_req->headers_out, "Location", url);
     return REDIRECT;
   }
-  const vector<XSECCryptoX509*>& getClientCertificates() const {
+  const vector<string>& getClientCertificates() const {
       return m_certs;
   }
   long returnDecline(void) { return DECLINED; }
@@ -559,9 +566,11 @@ public:
     Lockable* lock() {return this;}
     void unlock() {}
     bool authorized(const SPRequest& request, const Session* session) const;
+private:
+    bool checkAttribute(const SPRequest& request, const Attribute* attr, const char* toMatch, RegularExpression* re) const;
 };
 
-AccessControl* htAccessFactory(const DOMElement* const & e)
+AccessControl* htAccessFactory(const xercesc::DOMElement* const & e)
 {
     return new htAccessControl();
 }
@@ -569,19 +578,20 @@ AccessControl* htAccessFactory(const DOMElement* const & e)
 class ApacheRequestMapper : public virtual RequestMapper, public virtual PropertySet
 {
 public:
-    ApacheRequestMapper(const DOMElement* e);
+    ApacheRequestMapper(const xercesc::DOMElement* e);
     ~ApacheRequestMapper() { delete m_mapper; delete m_htaccess; delete m_staKey; delete m_propsKey; }
     Lockable* lock() { return m_mapper->lock(); }
     void unlock() { m_staKey->setData(NULL); m_propsKey->setData(NULL); m_mapper->unlock(); }
     Settings getSettings(const SPRequest& request) const;
     
+    void setParent(const PropertySet*) {}
     pair<bool,bool> getBool(const char* name, const char* ns=NULL) const;
     pair<bool,const char*> getString(const char* name, const char* ns=NULL) const;
     pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const;
     pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const;
     pair<bool,int> getInt(const char* name, const char* ns=NULL) const;
-    const PropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const;
-    const DOMElement* getElement() const;
+    const PropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:2.0:native:sp:config") const;
+    const xercesc::DOMElement* getElement() const;
 
 private:
     RequestMapper* m_mapper;
@@ -590,12 +600,12 @@ private:
     AccessControl* m_htaccess;
 };
 
-RequestMapper* ApacheRequestMapFactory(const DOMElement* const & e)
+RequestMapper* ApacheRequestMapFactory(const xercesc::DOMElement* const & e)
 {
     return new ApacheRequestMapper(e);
 }
 
-ApacheRequestMapper::ApacheRequestMapper(const DOMElement* e) : m_mapper(NULL), m_staKey(NULL), m_propsKey(NULL), m_htaccess(NULL)
+ApacheRequestMapper::ApacheRequestMapper(const xercesc::DOMElement* e) : m_mapper(NULL), m_staKey(NULL), m_propsKey(NULL), m_htaccess(NULL)
 {
     m_mapper=SPConfig::getConfig().RequestMapperManager.newPlugin(XML_REQUEST_MAPPER,e);
     m_htaccess=new htAccessControl();
@@ -686,7 +696,7 @@ const PropertySet* ApacheRequestMapper::getPropertySet(const char* name, const c
     return s ? s->getPropertySet(name,ns) : NULL;
 }
 
-const DOMElement* ApacheRequestMapper::getElement() const
+const xercesc::DOMElement* ApacheRequestMapper::getElement() const
 {
     const PropertySet* s=reinterpret_cast<const PropertySet*>(m_propsKey->getData());
     return s ? s->getElement() : NULL;
@@ -740,6 +750,35 @@ static SH_AP_TABLE* groups_for_user(request_rec* r, const char* user, char* grpf
     return grps;
 }
 
+bool htAccessControl::checkAttribute(const SPRequest& request, const Attribute* attr, const char* toMatch, RegularExpression* re) const
+{
+    bool caseSensitive = attr->isCaseSensitive();
+    const vector<string>& vals = attr->getSerializedValues();
+    for (vector<string>::const_iterator v=vals.begin(); v!=vals.end(); ++v) {
+        if (re) {
+            auto_ptr<XMLCh> trans(fromUTF8(v->c_str()));
+            if (re->matches(trans.get())) {
+                request.log(SPRequest::SPDebug,
+                    string("htAccessControl plugin expecting regexp ") + toMatch + ", got " + *v + ": authorization granted"
+                    );
+                return true;
+            }
+        }
+        else if ((caseSensitive && *v == toMatch) || (!caseSensitive && !strcasecmp(v->c_str(), toMatch))) {
+            request.log(SPRequest::SPDebug,
+                string("htAccessControl plugin expecting ") + toMatch + ", got " + *v + ": authorization granted."
+                );
+            return true;
+        }
+        else {
+            request.log(SPRequest::SPDebug,
+                string("htAccessControl plugin expecting ") + toMatch + ", got " + *v + ": authorization not granted."
+                );
+        }
+    }
+    return false;
+}
+
 bool htAccessControl::authorized(const SPRequest& request, const Session* session) const
 {
     // Make sure the object is our type.
@@ -850,16 +889,15 @@ bool htAccessControl::authorized(const SPRequest& request, const Session* sessio
                 continue;
             }
             
-            // Find the attribute matching the require rule.
-            map<string,const Attribute*>::const_iterator attr = session->getAttributes().find(w);
-            if (attr == session->getAttributes().end()) {
+            // Find the attribute(s) matching the require rule.
+            pair<multimap<string,Attribute*>::const_iterator,multimap<string,Attribute*>::const_iterator> attrs =
+                session->getAttributes().equal_range(w);
+            if (attrs.first == attrs.second) {
                 request.log(SPRequest::SPWarn, string("htAccessControl rule requires attribute (") + w + "), not found in session");
                 continue;
             }
 
             bool regexp=false;
-            bool caseSensitive = attr->second->isCaseSensitive();
-            const vector<string>& vals = attr->second->getSerializedValues();
 
             while (!auth_OK[x] && *t) {
                 w=ap_getword_conf(sta->m_req->pool,&t);
@@ -873,31 +911,14 @@ bool htAccessControl::authorized(const SPRequest& request, const Session* sessio
                     if (regexp) {
                         delete re.release();
                         auto_ptr<XMLCh> trans(fromUTF8(w));
-                        auto_ptr<RegularExpression> temp(new RegularExpression(trans.get()));
+                        auto_ptr<xercesc::RegularExpression> temp(new xercesc::RegularExpression(trans.get()));
                         re=temp;
                     }
                     
-                    for (vector<string>::const_iterator v=vals.begin(); !auth_OK[x] && v!=vals.end(); ++v) {
-                        if (regexp) {
-                            auto_ptr<XMLCh> trans(fromUTF8(v->c_str()));
-                            if (re->matches(trans.get())) {
-                                request.log(SPRequest::SPDebug,
-                                    string("htAccessControl plugin expecting ") + w + ", got " + *v + ": authorization granted"
-                                    );
-                                SHIB_AP_CHECK_IS_OK;
-                            }
-                        }
-                        else if ((caseSensitive && *v == w) || (!caseSensitive && !strcasecmp(v->c_str(),w))) {
-                            request.log(SPRequest::SPDebug,
-                                string("htAccessControl plugin expecting ") + w + ", got " + *v + ": authorization granted."
-                                );
+                    for (; !auth_OK[x] && attrs.first!=attrs.second; ++attrs.first) {
+                        if (checkAttribute(request, attrs.first->second, w, regexp ? re.get() : NULL)) {
                             SHIB_AP_CHECK_IS_OK;
                         }
-                        else {
-                            request.log(SPRequest::SPDebug,
-                                string("htAccessControl plugin expecting ") + w + ", got " + *v + ": authorization not granted."
-                                );
-                        }
                     }
                 }
                 catch (XMLException& ex) {
@@ -1019,7 +1040,6 @@ extern "C" void shib_child_init(apr_pool_t* p, server_rec* s)
     g_Config->setFeatures(
         SPConfig::Listener |
         SPConfig::Caching |
-        SPConfig::Metadata |
         SPConfig::RequestMapping |
         SPConfig::InProcess |
         SPConfig::Logging
@@ -1032,9 +1052,9 @@ extern "C" void shib_child_init(apr_pool_t* p, server_rec* s)
     g_Config->RequestMapperManager.registerFactory(NATIVE_REQUEST_MAPPER,&ApacheRequestMapFactory);
     
     try {
-        DOMDocument* dummydoc=XMLToolingConfig::getConfig().getParser().newDocument();
-        XercesJanitor<DOMDocument> docjanitor(dummydoc);
-        DOMElement* dummy = dummydoc->createElementNS(NULL,path);
+        xercesc::DOMDocument* dummydoc=XMLToolingConfig::getConfig().getParser().newDocument();
+        XercesJanitor<xercesc::DOMDocument> docjanitor(dummydoc);
+        xercesc::DOMElement* dummy = dummydoc->createElementNS(NULL,path);
         auto_ptr_XMLCh src(g_szSHIBConfig);
         dummy->setAttributeNS(NULL,path,src.get());
         dummy->setAttributeNS(NULL,validate,xmlconstants::XML_ONE);
@@ -1075,6 +1095,12 @@ static void set_error_filter(request_rec *r)
    ap_add_output_filter("SHIB_HEADERS_ERR", NULL, r, r->connection);
 }
 
+static int _table_add(void *v, const char *key, const char *value)
+{
+    apr_table_addn((apr_table_t*)v, key, value);
+    return 1;
+}
+
 static apr_status_t do_output_filter(ap_filter_t *f, apr_bucket_brigade *in)
 {
     request_rec *r = f->r;
@@ -1082,7 +1108,9 @@ static apr_status_t do_output_filter(ap_filter_t *f, apr_bucket_brigade *in)
 
     if (rc) {
         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_out_filter: merging %d headers", apr_table_elts(rc->hdr_out)->nelts);
-        apr_table_overlap(r->headers_out, rc->hdr_out, APR_OVERLAP_TABLES_MERGE);
+        apr_table_do(_table_add,r->headers_out, rc->hdr_out,NULL);
+        // can't use overlap call because it will collapse Set-Cookie headers
+        //apr_table_overlap(r->headers_out, rc->hdr_out, APR_OVERLAP_TABLES_MERGE);
     }
 
     /* remove ourselves from the filter chain */
@@ -1099,7 +1127,9 @@ static apr_status_t do_error_filter(ap_filter_t *f, apr_bucket_brigade *in)
 
     if (rc) {
         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_err_filter: merging %d headers", apr_table_elts(rc->hdr_err)->nelts);
-        apr_table_overlap(r->err_headers_out, rc->hdr_err, APR_OVERLAP_TABLES_MERGE);
+        apr_table_do(_table_add,r->err_headers_out, rc->hdr_err,NULL);
+        // can't use overlap call because it will collapse Set-Cookie headers
+        //apr_table_overlap(r->err_headers_out, rc->hdr_err, APR_OVERLAP_TABLES_MERGE);
     }
 
     /* remove ourselves from the filter chain */