Convert more strings to references.
[shibboleth/sp.git] / apache / mod_apache.cpp
index 2a24874..d98a066 100644 (file)
@@ -47,7 +47,9 @@ using namespace shibboleth;
 using namespace shibtarget;
 
 extern "C" module MODULE_VAR_EXPORT mod_shib;
+#if 0
 int shib_handler(request_rec* r, const IApplication* application, SHIRE& shire);
+#endif
 
 namespace {
     char* g_szSHIBConfig = NULL;
@@ -56,6 +58,10 @@ namespace {
     static const char* g_UserDataKey = "_shib_check_user_";
 }
 
+/********************************************************************************/
+// Basic Apache Configuration code.
+//
+
 // per-server module configuration structure
 struct shib_server_config
 {
@@ -148,32 +154,374 @@ extern "C" const char* shib_set_server_string_slot(cmd_parms* parms, void*, cons
     return NULL;
 }
 
-typedef const char* (*config_fn_t)(void);
+extern "C" const char* shib_ap_set_file_slot(cmd_parms* parms,
+#ifdef SHIB_APACHE_13
+                                            char* arg1, char* arg2
+#else
+                                            void* arg1, const char* arg2
+#endif
+                                            )
+{
+  ap_set_file_slot(parms, arg1, arg2);
+  return DECLINE_CMD;
+}
 
-static int shib_error_page(request_rec* r, const IApplication* app, const char* page, ShibMLP& mlp)
+/********************************************************************************/
+// Some other useful helper function(s)
+
+static SH_AP_TABLE* groups_for_user(request_rec* r, const char* user, char* grpfile)
 {
-    const IPropertySet* props=app->getPropertySet("Errors");
-    if (props) {
-        pair<bool,const char*> p=props->getString(page);
-        if (p.first) {
-            ifstream infile(p.second);
-            if (!infile.fail()) {
-                const char* res = mlp.run(infile,props);
-                if (res) {
-                    r->content_type = ap_psprintf(r->pool, "text/html");
-                    ap_send_http_header(r);
-                    ap_rprintf(r, res);
-                    return DONE;
-                }
+    SH_AP_CONFIGFILE* f;
+    SH_AP_TABLE* grps=ap_make_table(r->pool,15);
+    char l[MAX_STRING_LEN];
+    const char *group_name, *ll, *w;
+
+#ifdef SHIB_APACHE_13
+    if (!(f=ap_pcfg_openfile(r->pool,grpfile))) {
+#else
+    if (ap_pcfg_openfile(&f,r->pool,grpfile) != APR_SUCCESS) {
+#endif
+        ap_log_rerror(APLOG_MARK,APLOG_DEBUG,SH_AP_R(r),"groups_for_user() could not open group file: %s\n",grpfile);
+        return NULL;
+    }
+
+    SH_AP_POOL* sp;
+#ifdef SHIB_APACHE_13
+    sp=ap_make_sub_pool(r->pool);
+#else
+    if (apr_pool_create(&sp,r->pool) != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,
+            "groups_for_user() could not create a subpool");
+        return NULL;
+    }
+#endif
+
+    while (!(ap_cfg_getline(l,MAX_STRING_LEN,f))) {
+        if ((*l=='#') || (!*l))
+            continue;
+        ll = l;
+        ap_clear_pool(sp);
+
+        group_name=ap_getword(sp,&ll,':');
+
+        while (*ll) {
+            w=ap_getword_conf(sp,&ll);
+            if (!strcmp(w,user)) {
+                ap_table_setn(grps,ap_pstrdup(r->pool,group_name),"in");
+                break;
             }
         }
     }
+    ap_cfg_closefile(f);
+    ap_destroy_pool(sp);
+    return grps;
+}
 
-    ap_log_rerror(APLOG_MARK,APLOG_ERR,SH_AP_R(r),
-        "shib_error_page() could not process shire error template for application %s",app->getId());
+/********************************************************************************/
+// Apache ShibTarget subclass(es) here.
+
+class HTGroupTableApache : public HTGroupTable
+{
+public:
+  HTGroupTableApache(request_rec* r, const char *user, char *grpfile) {
+    groups = groups_for_user(r, user, grpfile);
+    if (!groups)
+      throw ResourceAccessException("Unable to access group file ($1) for user ($2)",params(2,grpfile,user));
+  }
+  ~HTGroupTableApache() {}
+  bool lookup(const char *entry) { return (ap_table_get(groups, entry)!=NULL); }
+  SH_AP_TABLE* groups;
+};
+
+class ShibTargetApache : public ShibTarget
+{
+public:
+  ShibTargetApache(request_rec* req) {
+    m_sc = (shib_server_config*)
+      ap_get_module_config(req->server->module_config, &mod_shib);
+
+    m_dc = (shib_dir_config*)ap_get_module_config(req->per_dir_config, &mod_shib);
+
+    init(
+        g_Config,
+        m_sc->szScheme ? m_sc->szScheme : ap_http_method(req),
+           ap_get_server_name(req),
+        (int)ap_get_server_port(req),
+           req->unparsed_uri,
+        ap_table_get(req->headers_in, "Content-type"),
+           req->connection->remote_ip,
+        req->method
+        );
+
+    m_req = req;
+  }
+  ~ShibTargetApache() { }
+
+  virtual void log(ShibLogLevel level, const string &msg) {
+    ap_log_rerror(APLOG_MARK,
+                 (level == LogLevelDebug ? APLOG_DEBUG :
+                  (level == LogLevelInfo ? APLOG_INFO :
+                   (level == LogLevelWarn ? APLOG_WARNING :
+                    APLOG_ERR)))|APLOG_NOERRNO, SH_AP_R(m_req),
+                 msg.c_str());
+  }
+  virtual string getCookies(void) {
+    const char *c = ap_table_get(m_req->headers_in, "Cookie");
+    return string(c ? c : "");
+  }
+  virtual void setCookie(const string &name, const string &value) {
+    char* val = ap_psprintf(m_req->pool, "%s=%s", name.c_str(), value.c_str());
+    ap_table_setn(m_req->err_headers_out, "Set-Cookie", val);
+  }
+  virtual string getArgs(void) { return string(m_req->args ? m_req->args : ""); }
+  virtual string getPostData(void) {
+    // Read the posted data
+    if (ap_setup_client_block(m_req, REQUEST_CHUNKED_ERROR))
+        throw FatalProfileException("Apache function (setup_client_block) failed while reading profile submission.");
+    if (!ap_should_client_block(m_req))
+        throw FatalProfileException("Apache function (should_client_block) failed while reading profile submission.");
+    if (m_req->remaining > 1024*1024)
+        throw FatalProfileException("Blocked too-large a submission to profile endpoint.");
+    string cgistr;
+    char buff[HUGE_STRING_LEN];
+    ap_hard_timeout("[mod_shib] getPostData", m_req);
+    memset(buff, 0, sizeof(buff));
+    while (ap_get_client_block(m_req, buff, sizeof(buff)-1) > 0) {
+      ap_reset_timeout(m_req);
+      cgistr += buff;
+      memset(buff, 0, sizeof(buff));
+    }
+    ap_kill_timeout(m_req);
+
+    return cgistr;
+  }
+  virtual void clearHeader(const string &name) {
+    ap_table_unset(m_req->headers_in, name.c_str());
+  }
+  virtual void setHeader(const string &name, const string &value) {
+    ap_table_set(m_req->headers_in, name.c_str(), value.c_str());
+  }
+  virtual string getHeader(const string &name) {
+    const char *hdr = ap_table_get(m_req->headers_in, name.c_str());
+    return string(hdr ? hdr : "");
+  }
+  virtual void setRemoteUser(const string &user) {
+    SH_AP_USER(m_req) = ap_pstrdup(m_req->pool, user.c_str());
+  }
+  virtual string getRemoteUser(void) {
+    return string(SH_AP_USER(m_req) ? SH_AP_USER(m_req) : "");
+  }
+  // override so we can look at the actual auth type and maybe override it.
+  virtual string getAuthType(void) {
+    const char *auth_type=ap_auth_type(m_req);
+    if (!auth_type)
+        return string("");
+    if (strcasecmp(auth_type, "shibboleth")) {
+      if (!strcasecmp(auth_type, "basic") && m_dc->bBasicHijack == 1) {
+       core_dir_config* conf= (core_dir_config*)
+         ap_get_module_config(m_req->per_dir_config,
+                              ap_find_linked_module("http_core.c"));
+       auth_type = conf->ap_auth_type = "shibboleth";
+      }
+    }
+    return string(auth_type);
+  }
+  // Override this function because we want to add the Apache Directory override
+  virtual pair<bool,bool> getRequireSession(IRequestMapper::Settings &settings) {
+    pair<bool,bool> requireSession = settings.first->getBool("requireSession");
+    if (!requireSession.first || !requireSession.second)
+      if (m_dc->bRequireSession == 1)
+       requireSession.second=true;
+
+    return requireSession;
+  }
+
+  virtual HTAccessInfo* getAccessInfo(void) { 
+    int m = m_req->method_number;
+    const array_header* reqs_arr = ap_requires(m_req);
+    if (!reqs_arr)
+      return NULL;
+
+    require_line* reqs = (require_line*) reqs_arr->elts;
+
+    ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req),
+                 "REQUIRE nelts: %d", reqs_arr->nelts);
+    ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req),
+                 "REQUIRE all: %d", m_dc->bRequireAll);
+
+    HTAccessInfo* ht = new HTAccessInfo();
+    ht->requireAll = (m_dc->bRequireAll == 1);
+    ht->elements.reserve(reqs_arr->nelts);
+    for (int x = 0; x < reqs_arr->nelts; x++) {
+      HTAccessInfo::RequireLine* rline = new HTAccessInfo::RequireLine();
+      rline->use_line = (reqs[x].method_mask & (1 << m));
+      rline->tokens.reserve(6);        // No reason to reserve specifically 6 tokens
+      const char* t = reqs[x].requirement;
+      const char* w = ap_getword_white(m_req->pool, &t);
+      rline->tokens.push_back(w);
+      while (*t) {
+       w = ap_getword_conf(m_req->pool, &t);
+       rline->tokens.push_back(w);
+      }
+      ht->elements.push_back(rline);
+    }
+    return ht;
+  }
+  virtual HTGroupTable* getGroupTable(string &user) {
+    if (m_dc->szAuthGrpFile && !user.empty()) {
+      ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(m_req),
+                   "getGroupTable() using groups file: %s\n",
+                   m_dc->szAuthGrpFile);
+      try {
+       HTGroupTableApache *gt = new HTGroupTableApache(m_req, user.c_str(),
+                                                       m_dc->szAuthGrpFile);
+       return gt;
+      } catch (...) { }
+    }
+    return NULL;
+  }
+
+  virtual void* sendPage(
+    const string& msg,
+    const string& content_type,
+       const saml::Iterator<header_t>& headers=EMPTY(header_t),
+    int code=200
+    ) {
+    m_req->content_type = ap_psprintf(m_req->pool, content_type.c_str());
+    while (headers.hasNext()) {
+        const header_t& h=headers.next();
+        ap_table_setn(m_req->headers_out, h.first.c_str(), h.second.c_str());
+    }
+    ap_send_http_header(m_req);
+    ap_rprintf(m_req, msg.c_str());
+    return (void*)DONE;
+  }
+  virtual void* sendRedirect(const string& url) {
+    ap_table_set(m_req->headers_out, "Location", url.c_str());
+    return (void*)REDIRECT;
+  }
+  virtual void* returnDecline(void) { return (void*)DECLINED; }
+  virtual void* returnOK(void) { return (void*)OK; }
+
+  request_rec* m_req;
+  shib_dir_config* m_dc;
+  shib_server_config* m_sc;
+};
+
+/********************************************************************************/
+// Apache handlers
+
+extern "C" int shib_check_user(request_rec* r)
+{
+  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),
+               "shib_check_user(%d): ENTER\n", (int)getpid());
+
+  ostringstream threadid;
+  threadid << "[" << getpid() << "] shib_check_user" << '\0';
+  saml::NDC ndc(threadid.str().c_str());
+
+#ifndef _DEBUG
+  try {
+#endif
+    ShibTargetApache sta(r);
+
+    // Check user authentication, the set the post handler bypass
+    pair<bool,void*> res = sta.doCheckAuthN((sta.m_dc->bRequireSession == 1), true);
+    apr_pool_userdata_setn((const void*)42,g_UserDataKey,NULL,r->pool);
+    if (res.first) return (int)res.second;
+
+    // user auth was okay -- export the assertions now
+    res = sta.doExportAssertions((sta.m_dc->bExportAssertion == 1));
+    if (res.first) return (int)res.second;
+
+    // export happened successfully..  this user is ok.
+    return OK;
+
+#ifndef _DEBUG
+  } catch (...) {
+    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r),
+                 "shib_check_user threw an uncaught exception!");
     return SERVER_ERROR;
+  }
+#endif
 }
 
+extern "C" int shib_post_handler(request_rec* r)
+{
+  ostringstream threadid;
+  threadid << "[" << getpid() << "] shib_post_handler" << '\0';
+  saml::NDC ndc(threadid.str().c_str());
+
+#ifndef SHIB_APACHE_13
+  // With 2.x, this handler always runs, though last.
+  // We check if shib_check_user ran, because it will detect a SHIRE request
+  // and dispatch it directly.
+  void* data;
+  apr_pool_userdata_get(&data,g_UserDataKey,r->pool);
+  if (data==(const void*)42) {
+    ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_post_handler skipped since check_user ran");
+    return DECLINED;
+  }
+#endif
+
+  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),
+               "shib_post_handler(%d): ENTER", (int)getpid());
+
+#ifndef _DEBUG
+  try {
+#endif
+    ShibTargetApache sta(r);
+
+    pair<bool,void*> res = sta.doHandleProfile();
+    if (res.first) return (int)res.second;
+
+    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r),
+                 "doHandleProfile() did not do anything.");
+    return SERVER_ERROR;
+
+#ifndef _DEBUG
+  } catch (...) {
+    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r),
+                 "shib_post_handler threw an uncaught exception!");
+    return SERVER_ERROR;
+  }
+#endif
+}
+
+/*
+ * shib_auth_checker() -- a simple resource manager to
+ * process the .htaccess settings
+ */
+extern "C" int shib_auth_checker(request_rec* r)
+{
+  ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),
+               "shib_auth_checker(%d): ENTER", (int)getpid());
+
+  ostringstream threadid;
+  threadid << "[" << getpid() << "] shib_auth_checker" << '\0';
+  saml::NDC ndc(threadid.str().c_str());
+
+#ifndef _DEBUG
+  try {
+#endif
+    ShibTargetApache sta(r);
+
+    pair<bool,void*> res = sta.doCheckAuthZ();
+    if (res.first) return (int)res.second;
+
+    // We're all okay.
+    return OK;
+
+#ifndef _DEBUG
+  } catch (...) {
+    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, SH_AP_R(r),
+                 "shib_auth_checker threw an uncaught exception!");
+    return SERVER_ERROR;
+  }
+#endif
+}
+
+#if 0
 static char* shib_get_targeturl(request_rec* r, const char* scheme=NULL)
 {
     // On 1.3, this is always canonical, but on 2.0, UseCanonicalName comes into play.
@@ -221,8 +569,15 @@ extern "C" int shib_check_user(request_rec* r)
     // Declare SHIRE object for this request.
     SHIRE shire(application);
     
+    const char* shireURL=shire.getShireURL(targeturl);
+    if (!shireURL) {
+        ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,SH_AP_R(r),
+           "shib_check_user: unable to map request to proper shireURL setting, check configuration");
+        return SERVER_ERROR;
+    }
+    
     // Get location of this application's assertion consumer service and see if this is it.
-    if (strstr(targeturl,shire.getShireURL(targeturl))) {
+    if (strstr(targeturl,shireURL)) {
         return shib_handler(r,application,shire);
     }
 
@@ -564,8 +919,15 @@ int shib_handler(request_rec* r, const IApplication* application, SHIRE& shire)
 
     const char* targeturl=shib_get_targeturl(r,sc->szScheme);
 
+    const char* shireURL=shire.getShireURL(targeturl);
+    if (!shireURL) {
+        ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,SH_AP_R(r),
+           "shib_post_handler: unable to map request to proper shireURL setting, check configuration");
+        return SERVER_ERROR;
+    }
+
     // Make sure we only process the SHIRE requests.
-    if (!strstr(targeturl,shire.getShireURL(targeturl)))
+    if (!strstr(targeturl,shireURL))
         return DECLINED;
 
     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),"shib_handler() running");
@@ -623,6 +985,7 @@ int shib_handler(request_rec* r, const IApplication* application, SHIRE& shire)
         ap_hard_timeout("[mod_shib] CGI Parser", r);
         memset(buff, 0, sizeof(buff));
         while (ap_get_client_block(r, buff, sizeof(buff)-1) > 0) {
+            ap_reset_timeout(r);
             cgistr += buff;
             memset(buff, 0, sizeof(buff));
         }
@@ -698,52 +1061,28 @@ int shib_handler(request_rec* r, const IApplication* application, SHIRE& shire)
     return SERVER_ERROR;
 }
 
-static SH_AP_TABLE* groups_for_user(request_rec* r, const char* user, char* grpfile)
+static int shib_error_page(request_rec* r, const IApplication* app, const char* page, ShibMLP& mlp)
 {
-    SH_AP_CONFIGFILE* f;
-    SH_AP_TABLE* grps=ap_make_table(r->pool,15);
-    char l[MAX_STRING_LEN];
-    const char *group_name, *ll, *w;
-
-#ifdef SHIB_APACHE_13
-    if (!(f=ap_pcfg_openfile(r->pool,grpfile))) {
-#else
-    if (ap_pcfg_openfile(&f,r->pool,grpfile) != APR_SUCCESS) {
-#endif
-        ap_log_rerror(APLOG_MARK,APLOG_DEBUG,SH_AP_R(r),"groups_for_user() could not open group file: %s\n",grpfile);
-        return NULL;
-    }
-
-    SH_AP_POOL* sp;
-#ifdef SHIB_APACHE_13
-    sp=ap_make_sub_pool(r->pool);
-#else
-    if (apr_pool_create(&sp,r->pool) != APR_SUCCESS) {
-        ap_log_rerror(APLOG_MARK,APLOG_ERR,0,r,
-            "groups_for_user() could not create a subpool");
-        return NULL;
-    }
-#endif
-
-    while (!(ap_cfg_getline(l,MAX_STRING_LEN,f))) {
-        if ((*l=='#') || (!*l))
-            continue;
-        ll = l;
-        ap_clear_pool(sp);
-
-        group_name=ap_getword(sp,&ll,':');
-
-        while (*ll) {
-            w=ap_getword_conf(sp,&ll);
-            if (!strcmp(w,user)) {
-                ap_table_setn(grps,ap_pstrdup(r->pool,group_name),"in");
-                break;
+    const IPropertySet* props=app->getPropertySet("Errors");
+    if (props) {
+        pair<bool,const char*> p=props->getString(page);
+        if (p.first) {
+            ifstream infile(p.second);
+            if (!infile.fail()) {
+                const char* res = mlp.run(infile,props);
+                if (res) {
+                    r->content_type = ap_psprintf(r->pool, "text/html");
+                    ap_send_http_header(r);
+                    ap_rprintf(r, res);
+                    return DONE;
+                }
             }
         }
     }
-    ap_cfg_closefile(f);
-    ap_destroy_pool(sp);
-    return grps;
+
+    ap_log_rerror(APLOG_MARK,APLOG_ERR,SH_AP_R(r),
+        "shib_error_page() could not process shire error template for application %s",app->getId());
+    return SERVER_ERROR;
 }
 
 /*
@@ -920,7 +1259,7 @@ extern "C" int shib_auth_checker(request_rec* r)
                                     SHIB_AP_CHECK_IS_OK;
                                 }
                             }
-                            else if (val==w) {
+                            else if ((wrapper->getCaseSensitive() && val==w) || (!wrapper->getCaseSensitive() && !strcasecmp(val.c_str(),w))) {
                                 ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),
                                                 "shib_auth_checker() expecting %s, got %s: authorization granted", w, val.c_str());
                                 SHIB_AP_CHECK_IS_OK;
@@ -941,7 +1280,7 @@ extern "C" int shib_auth_checker(request_rec* r)
                             SHIB_AP_CHECK_IS_OK;
                         }
                     }
-                    else if (val==w) {
+                    else if ((wrapper->getCaseSensitive() && val==w) || (!wrapper->getCaseSensitive() && !strcasecmp(val.c_str(),w))) {
                         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(r),
                                         "shib_auth_checker() expecting %s, got %s: authorization granted", w, val.c_str());
                         SHIB_AP_CHECK_IS_OK;
@@ -986,32 +1325,25 @@ extern "C" int shib_auth_checker(request_rec* r)
     markupProcessor.insert("requestURL", ap_construct_url(r->pool,r->unparsed_uri,r));
     return shib_error_page(r, application, "access", markupProcessor);
 }
+#endif /* 0 */
 
+#ifndef SHIB_APACHE_13
 /*
  * shib_exit()
- *  Cleanup the (per-process) pool info.
+ *  Empty cleanup hook, Apache 2.x doesn't check NULL very well...
  */
-#ifdef SHIB_APACHE_13
-extern "C" void shib_exit(server_rec* s, SH_AP_POOL* p)
-{
-#else
 extern "C" apr_status_t shib_exit(void* data)
 {
-    server_rec* s = NULL;
-#endif
-
-    ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_exit(%d) dealing with g_Config..", (int)getpid());
-
-    g_Config->shutdown();
-    g_Config = NULL;
-
-    ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_exit() done\n");
-#ifndef SHIB_APACHE_13
+    ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,0,NULL,"shib_exit() done\n");
     return OK;
-#endif
 }
+#endif
 
 
+/*
+ * shib_child_exit()
+ *  Cleanup the (per-process) pool info.
+ */
 #ifdef SHIB_APACHE_13
 extern "C" void shib_child_exit(server_rec* s, SH_AP_POOL* p)
 {
@@ -1021,8 +1353,10 @@ extern "C" apr_status_t shib_child_exit(void* data)
   server_rec* s = NULL;
 #endif
 
-  ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_exit(%d)",
-              (int)getpid());
+    ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_exit(%d) dealing with g_Config..", (int)getpid());
+    g_Config->shutdown();
+    g_Config = NULL;
+    ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_exit() done\n");
 
 #ifndef SHIB_APACHE_13
     return OK;
@@ -1037,8 +1371,7 @@ extern "C" apr_status_t shib_child_exit(void* data)
 #ifdef SHIB_APACHE_13
 extern "C" void shib_child_init(server_rec* s, SH_AP_POOL* p)
 #else
-extern "C" int shib_post_config(apr_pool_t* pconf, apr_pool_t* plog,
-                               apr_pool_t* ptemp, server_rec* s)
+extern "C" void shib_child_init(apr_pool_t* p, server_rec* s)
 #endif
 {
     // Initialize runtime components.
@@ -1047,11 +1380,7 @@ extern "C" int shib_post_config(apr_pool_t* pconf, apr_pool_t* plog,
 
     if (g_Config) {
         ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() already initialized!");
-#ifdef SHIB_APACHE_13
         exit(1);
-#else
-       return OK;
-#endif
     }
 
     try {
@@ -1061,7 +1390,7 @@ extern "C" int shib_post_config(apr_pool_t* pconf, apr_pool_t* plog,
             ShibTargetConfig::Metadata |
             ShibTargetConfig::AAP |
             ShibTargetConfig::RequestMapper |
-            ShibTargetConfig::SHIREExtensions |
+            ShibTargetConfig::LocalExtensions |
             ShibTargetConfig::Logging
             );
         if (!g_Config->init(g_szSchemaDir,g_szSHIBConfig)) {
@@ -1075,15 +1404,13 @@ extern "C" int shib_post_config(apr_pool_t* pconf, apr_pool_t* plog,
     }
 
     // Set the cleanup handler
-    apr_pool_cleanup_register(pconf, NULL, &shib_exit, &shib_child_exit);
+    apr_pool_cleanup_register(p, NULL, &shib_exit, &shib_child_exit);
 
     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,SH_AP_R(s),"shib_child_init() done");
-
-#ifndef SHIB_APACHE_13
-    return OK;
-#endif
 }
 
+typedef const char* (*config_fn_t)(void);
+
 #ifdef SHIB_APACHE_13
 
 // SHIB Module commands
@@ -1109,7 +1436,7 @@ static command_rec shire_cmds[] = {
   {"ShibExportAssertion", (config_fn_t)ap_set_flag_slot,
    (void *) XtOffsetOf (shib_dir_config, bExportAssertion),
    OR_AUTHCFG, FLAG, "Export SAML assertion to Shibboleth-defined header?"},
-  {"AuthGroupFile", (config_fn_t)ap_set_file_slot,
+  {"AuthGroupFile", (config_fn_t)shib_ap_set_file_slot,
    (void *) XtOffsetOf (shib_dir_config, szAuthGrpFile),
    OR_AUTHCFG, TAKE1, "text file containing group names and member user IDs"},
   {"ShibRequireAll", (config_fn_t)ap_set_flag_slot,
@@ -1143,7 +1470,7 @@ module MODULE_VAR_EXPORT mod_shib = {
     NULL,                      /* logger */
     NULL,                      /* header parser */
     shib_child_init,           /* child_init */
-    shib_exit,                 /* child_exit */
+    shib_child_exit,           /* child_exit */
     NULL                       /* post read-request */
 };
 
@@ -1151,7 +1478,7 @@ module MODULE_VAR_EXPORT mod_shib = {
 
 extern "C" void shib_register_hooks (apr_pool_t *p)
 {
-  ap_hook_post_config(shib_post_config, NULL, NULL, APR_HOOK_MIDDLE);
+  ap_hook_child_init(shib_child_init, NULL, NULL, APR_HOOK_MIDDLE);
   ap_hook_check_user_id(shib_check_user, NULL, NULL, APR_HOOK_MIDDLE);
   ap_hook_auth_checker(shib_auth_checker, NULL, NULL, APR_HOOK_FIRST);
   ap_hook_handler(shib_post_handler, NULL, NULL, APR_HOOK_LAST);
@@ -1182,7 +1509,7 @@ static command_rec shib_cmds[] = {
   AP_INIT_FLAG("ShibExportAssertion", (config_fn_t)ap_set_flag_slot,
          (void *) offsetof (shib_dir_config, bExportAssertion),
         OR_AUTHCFG, "Export SAML assertion to Shibboleth-defined header?"),
-  AP_INIT_TAKE1("AuthGroupFile", (config_fn_t)ap_set_file_slot,
+  AP_INIT_TAKE1("AuthGroupFile", (config_fn_t)shib_ap_set_file_slot,
                (void *) offsetof (shib_dir_config, szAuthGrpFile),
                OR_AUTHCFG, "text file containing group names and member user IDs"),
   AP_INIT_FLAG("ShibRequireAll", (config_fn_t)ap_set_flag_slot,