Removed RPCHandle code.
[shibboleth/sp.git] / mod_shire / mod_shire.cpp
1 /*
2  * mod_shire.cpp -- the SHIRE Apache Module
3  *
4  * Created by:  Derek Atkins <derek@ihtfp.com>
5  *
6  * $Id$
7  */
8
9 // SAML Runtime
10 #include <saml/saml.h>
11 #include <shib/shib.h>
12 #include <shib/shib-threads.h>
13 #include <shib-target/shib-target.h>
14
15 // Apache specific header files
16 #include "httpd.h"
17 #include "http_config.h"
18 #include "http_protocol.h"
19 #include "http_main.h"
20 #include "util_script.h"
21 #define CORE_PRIVATE
22 #include "http_core.h"
23 #include "http_log.h"
24
25 #include <fstream>
26 #include <sstream>
27 #include <stdexcept>
28
29 // For POST processing from Apache
30 #undef _XOPEN_SOURCE            // bombs on solaris
31 #include <libapreq/apache_request.h>
32
33 using namespace std;
34 using namespace saml;
35 using namespace shibboleth;
36 using namespace shibtarget;
37
38 extern "C" module MODULE_VAR_EXPORT shire_module;
39
40 namespace {
41     char* g_szSHIREURL = NULL;
42     char* g_szSHIREConfig = NULL;
43     ShibTargetConfig* g_Config = NULL;
44 }
45
46 // per-dir module configuration structure
47 struct shire_dir_config
48 {
49     int bBasicHijack;           // activate for AuthType Basic?
50     int bSSLOnly;               // only over SSL?
51     SHIREConfig config;         // SHIRE Configuration
52 };
53
54 // creates per-directory config structure
55 extern "C" void* create_shire_dir_config (pool* p, char* d)
56 {
57     shire_dir_config* dc=(shire_dir_config*)ap_pcalloc(p,sizeof(shire_dir_config));
58     dc->bBasicHijack = -1;
59     dc->bSSLOnly = -1;
60     dc->config.lifetime = -1;
61     dc->config.timeout = -1;
62     return dc;
63 }
64
65 // overrides server configuration in directories
66 extern "C" void* merge_shire_dir_config (pool* p, void* base, void* sub)
67 {
68     shire_dir_config* dc=(shire_dir_config*)ap_pcalloc(p,sizeof(shire_dir_config));
69     shire_dir_config* parent=(shire_dir_config*)base;
70     shire_dir_config* child=(shire_dir_config*)sub;
71
72     dc->bBasicHijack=((child->bBasicHijack==-1) ? parent->bBasicHijack : child->bBasicHijack);
73     dc->bSSLOnly=((child->bSSLOnly==-1) ? parent->bSSLOnly : child->bSSLOnly);
74     dc->config.lifetime=((child->config.lifetime==-1) ? parent->config.lifetime : child->config.lifetime);
75     dc->config.timeout=((child->config.timeout==-1) ? parent->config.timeout : child->config.timeout);
76     return dc;
77 }
78
79 // generic global slot handlers
80 extern "C" const char* ap_set_global_string_slot(cmd_parms* parms, void*, const char* arg)
81 {
82     *((char**)(parms->info))=ap_pstrdup(parms->pool,arg);
83     return NULL;
84 }
85
86 // some shortcuts for directory config slots
87 extern "C" const char* set_lifetime(cmd_parms* parms, shire_dir_config* dc, const char* arg)
88 {
89     dc->config.lifetime=atoi(arg);
90     return NULL;
91 }
92
93 extern "C" const char* set_timeout(cmd_parms* parms, shire_dir_config* dc, const char* arg)
94 {
95     dc->config.timeout=atoi(arg);
96     return NULL;
97 }
98
99 typedef const char* (*config_fn_t)(void);
100
101 // SHIRE Module commands
102
103 static command_rec shire_cmds[] = {
104   {"SHIREConfig", (config_fn_t)ap_set_global_string_slot, &g_szSHIREConfig,
105    RSRC_CONF, TAKE1, "Path to SHIRE ini file."},
106   {"SHIREURL", (config_fn_t)ap_set_global_string_slot, &g_szSHIREURL,
107    RSRC_CONF, TAKE1, "SHIRE POST processor URL."},
108
109   {"ShibBasicHijack", (config_fn_t)ap_set_flag_slot,
110    (void *) XtOffsetOf (shire_dir_config, bBasicHijack),
111    OR_AUTHCFG, FLAG, "Respond to AuthType Basic and convert to shib?"},
112   {"ShibSSLOnly", (config_fn_t)ap_set_flag_slot,
113    (void *) XtOffsetOf (shire_dir_config, bSSLOnly),
114    OR_AUTHCFG, FLAG, "Require SSL when accessing a secured directory?"},
115   {"ShibAuthLifetime", (config_fn_t)set_lifetime, NULL,
116    OR_AUTHCFG, TAKE1, "Lifetime of session in seconds."},
117   {"ShibAuthTimeout", (config_fn_t)set_timeout, NULL,
118    OR_AUTHCFG, TAKE1, "Timeout for session in seconds."},
119
120   {NULL}
121 };
122
123 /* 
124  * shire_child_init()
125  *  Things to do when the child process is initialized.
126  */
127 extern "C" void shire_child_init(server_rec* s, pool* p)
128 {
129     // Initialize runtime components.
130
131     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,
132                  "shire_child_init() starting");
133
134     if (g_Config) {
135       ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,s,
136                    "shire_child_init(): already initialized!");
137       exit (1);
138     }
139
140     try {
141       g_Config = &(ShibTargetConfig::init(SHIBTARGET_SHIRE, g_szSHIREConfig));
142     } catch (...) {
143       ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,
144                    "shire_child_init() failed to initialize SHIB Target");
145       exit (1);
146     }
147
148     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_init() done");
149 }
150
151
152 /*
153  * shire_child_exit()
154  *  Cleanup.
155  */
156 extern "C" void shire_child_exit(server_rec* s, pool* p)
157 {
158     g_Config->shutdown();
159     g_Config = NULL;
160     ap_log_error(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,s,"shire_child_exit() done");
161 }
162
163 inline char hexchar(unsigned short s)
164 {
165     return (s<=9) ? ('0' + s) : ('A' + s - 10);
166 }
167
168 static char* url_encode(request_rec* r, const char* s)
169 {
170     static char badchars[]="\"\\+<>#%{}|^~[]`;/?:@=&";
171     char* ret=(char*)ap_palloc(r->pool,sizeof(char)*3*strlen(s)+1);
172
173     unsigned long count=0;
174     for (; *s; s++)
175     {
176         if (strchr(badchars,*s)!=NULL || *s<=0x1F || *s>=0x7F)
177         {
178             ret[count++]='%';
179             ret[count++]=hexchar(*s >> 4);
180             ret[count++]=hexchar(*s & 0x0F);
181         }
182         else
183             ret[count++]=*s;
184     }
185     ret[count++]=*s;
186     return ret;
187 }
188
189 static const char* get_application_id(request_rec* r)
190 {
191     ApplicationMapper mapper;
192     return ap_pstrdup(r->pool,
193         mapper->getApplicationFromParsedURL(
194             ap_http_method(r), ap_get_server_name(r), ap_get_server_port(r), r->unparsed_uri
195             )
196        );
197 }
198
199 static const char* get_shire_location(request_rec* r, const char* target, const char* application_id)
200 {
201   string shire_location;
202   ShibINI& ini = g_Config->getINI();
203
204   if (!ini.get_tag (application_id, "shireURL", true, &shire_location)) {
205     ap_log_rerror(APLOG_MARK,APLOG_ERR,r,
206                   "shire_get_location() no shireURL configuration for %s", application_id);
207     return NULL;
208   }
209
210   const char* shire = shire_location.c_str();
211
212   if (*shire != '/')
213       return ap_pstrdup(r->pool,shire);
214
215   const char* colon=strchr(target,':');
216   const char* slash=strchr(colon+3,'/');
217   return ap_pstrcat(r->pool, ap_pstrndup(r->pool,target,slash-target), shire, NULL);
218 }
219
220 static int shire_error_page(request_rec* r, const char* filename, ShibMLP& mlp)
221 {
222   ifstream infile (filename);
223   if (!infile) {
224       ap_log_rerror(APLOG_MARK,APLOG_ERR,r,
225                     "shire_error_page() cannot open %s", filename);
226       return SERVER_ERROR;
227   }
228
229   string res = mlp.run(infile);
230   r->content_type = ap_psprintf(r->pool, "text/html");
231   ap_send_http_header(r);
232   ap_rprintf(r, res.c_str());
233   return DONE;
234 }
235
236 extern "C" int shire_check_user(request_rec* r)
237 {
238     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user: ENTER");
239     shire_dir_config* dc=(shire_dir_config*)ap_get_module_config(r->per_dir_config,&shire_module);
240
241     // This will always be normalized, because Apache uses ap_get_server_name in this API call.
242     const char* targeturl=ap_construct_url(r->pool,r->unparsed_uri,r);
243     
244     // Map request to application ID, which is the key for config lookup.
245     const char* application_id=get_application_id(r);
246     
247     // Get unescaped location of this application's assertion consumer service.
248     const char* unescaped_shire = get_shire_location(r, targeturl, application_id);
249     
250     if (strstr(targeturl,unescaped_shire)) {
251       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
252            "shire_check_user: REQUEST FOR SHIRE!  Maybe you did not configure the SHIRE Handler?");
253       return SERVER_ERROR;
254     }
255     else {
256       // Regular access to arbitrary resource...check AuthType
257       const char *auth_type=ap_auth_type (r);
258       if (!auth_type)
259         return DECLINED;
260
261       if (strcasecmp(auth_type,"shibboleth"))
262       {
263         if (!strcasecmp(auth_type,"basic") && dc->bBasicHijack==1)
264         {
265             core_dir_config* conf=
266                 (core_dir_config*)ap_get_module_config(r->per_dir_config,
267                     ap_find_linked_module("http_core.c"));
268             conf->ap_auth_type="shibboleth";
269         }
270         else
271             return DECLINED;
272       }
273
274       // set the connection authtype
275       if (r->connection)
276         r->connection->ap_auth_type = "shibboleth";
277
278       // SSL check.
279       if (dc->bSSLOnly==1 && strcmp(ap_http_method(r),"https"))
280       {
281         ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user() blocked non-SSL access");
282         return SERVER_ERROR;
283       }
284     }
285
286     ostringstream threadid;
287     threadid << "[" << getpid() << "] shire" << '\0';
288     saml::NDC ndc(threadid.str().c_str());
289
290     ShibINI& ini = g_Config->getINI();
291
292     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
293                     "shire_check_user() Shib check for %s", targeturl);
294
295     
296     string tag;
297     bool has_tag = ini.get_tag (application_id, "checkIPAddress", true, &tag);
298     dc->config.checkIPAddress = (has_tag ? ShibINI::boolean (tag) : false);
299
300     string shib_cookie;
301     if (!ini.get_tag(application_id, "cookieName", true, &shib_cookie)) {
302       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
303                     "shire_check_user: no cookieName configuration for %s", application_id);
304       return SERVER_ERROR;
305     }
306
307     string wayfLocation;
308     if (!ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) {
309       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
310                     "shire_check_user: no wayfURL configuration for %s", application_id);
311       return SERVER_ERROR;
312     }
313
314     string shireError;
315     if (!ini.get_tag(application_id, "shireError", true, &shireError)) {
316       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
317                     "shire_check_user: no shireError configuration for %s", application_id);
318       return SERVER_ERROR;
319     }
320     
321     SHIRE shire(dc->config, unescaped_shire);
322
323     // We're in charge, so check for cookie.
324     const char* session_id=NULL;
325     const char* cookies=ap_table_get(r->headers_in,"Cookie");
326
327     if (cookies)
328     {
329         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
330                         "shire_check_user() cookies found: %s",cookies);
331         if (session_id=strstr(cookies,shib_cookie.c_str()))
332         {
333             // Yep, we found a cookie -- pull it out (our session_id)
334             session_id+=strlen(shib_cookie.c_str()) + 1; /* Skip over the '=' */
335             char* cookiebuf = ap_pstrdup(r->pool,session_id);
336             char* cookieend = strchr(cookiebuf,';');
337             if (cookieend)
338                 *cookieend = '\0';    /* Ignore anyting after a ; */
339             session_id=cookiebuf;
340         }
341     }
342
343     if (!session_id || !*session_id)
344     {
345         // No acceptable cookie.  Redirect to WAYF.
346         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
347                       "shire_check_user() no cookie found -- redirecting to WAYF");
348         char timebuf[16];
349         sprintf(timebuf,"%u",time(NULL));
350         char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
351                               "?shire=",url_encode(r,unescaped_shire),
352                               "&target=",url_encode(r,targeturl),
353                   "&time=",timebuf,
354                   "&providerId=",application_id,NULL);
355         ap_table_setn(r->headers_out,"Location",wayf);
356         return REDIRECT;
357     }
358
359     // Make sure this session is still valid
360     RPCError* status = NULL;
361     ShibMLP markupProcessor;
362     has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
363     markupProcessor.insert("supportContact", has_tag ? tag : "");
364     has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
365     markupProcessor.insert("logoLocation", has_tag ? tag : "");
366     markupProcessor.insert("requestURL", targeturl);
367
368     try {
369         status = shire.sessionIsValid(session_id, r->connection->remote_ip,application_id);
370     }
371     catch (ShibTargetException &e) {
372         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): %s", e.what());
373         markupProcessor.insert ("errorType", "SHIRE Processing Error");
374         markupProcessor.insert ("errorText", e.what());
375         markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
376         return shire_error_page (r, shireError.c_str(), markupProcessor);
377     }
378     catch (...) {
379         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user(): caught unexpected error");
380         markupProcessor.insert ("errorType", "SHIRE Processing Error");
381         markupProcessor.insert ("errorText", "Unexpected Exception");
382         markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
383         return shire_error_page (r, shireError.c_str(), markupProcessor);
384     }
385
386     // Check the status
387     if (status->isError()) {
388         ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
389                       "shire_check_user() session invalid: %s",
390                       status->getText());
391
392         if (status->isRetryable()) {
393             // Oops, session is invalid.  Redirect to WAYF.
394             char timebuf[16];
395             sprintf(timebuf,"%u",time(NULL));
396             char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
397                                   "?shire=",url_encode(r,unescaped_shire),
398                                   "&target=",url_encode(r,targeturl),
399                       "&time=",timebuf,
400                       "&providerId=",application_id,NULL);
401             ap_table_setn(r->headers_out,"Location",wayf);
402
403             delete status;
404             return REDIRECT;
405         }
406         else {
407             // return the error page to the user
408             markupProcessor.insert (*status);
409             delete status;
410             return shire_error_page (r, shireError.c_str(), markupProcessor);
411         }
412     }
413     else {
414         delete status;
415         ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_check_user() success");
416         return OK;
417     }
418
419     ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_check_user() server error");
420     return SERVER_ERROR;
421 }
422
423 extern "C" int shire_post_handler (request_rec* r)
424 {
425   ostringstream threadid;
426   threadid << "[" << getpid() << "] shire" << '\0';
427   saml::NDC ndc(threadid.str().c_str());
428
429   ShibINI& ini = g_Config->getINI();
430   ShibMLP markupProcessor;
431
432   ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler() ENTER");
433
434   // This will always be normalized, because Apache uses ap_get_server_name in this API call.
435   const char* targeturl = ap_construct_url(r->pool,r->unparsed_uri,r);
436    
437   // Map request to application ID, which is the key for config lookup.
438   const char* application_id = get_application_id(r);
439     
440   // The SHIRE URL is the current request URL, by definition...
441   const char* unescaped_shire = targeturl;
442
443   string tag;
444   bool has_tag = ini.get_tag(application_id, "checkIPAddress", true, &tag);
445   SHIREConfig config;
446   config.checkIPAddress = (has_tag ? ShibINI::boolean(tag) : false);
447
448   string shib_cookie;
449   if (! ini.get_tag(application_id, "cookieName", true, &shib_cookie)) {
450     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
451                   "shire_check_user: no cookieName configuration for %s", application_id);
452     return SERVER_ERROR;
453   }
454
455   string wayfLocation;
456   if (! ini.get_tag(application_id, "wayfURL", true, &wayfLocation)) {
457     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
458                   "shire_check_user: no wayfURL configuration for %s", application_id);
459     return SERVER_ERROR;
460   }
461
462   string shireError;
463   if (! ini.get_tag(application_id, "shireError", true, &shireError)) {
464     ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
465                   "shire_check_user: no shireError configuration for %s", application_id);
466     return SERVER_ERROR;
467   }
468
469   has_tag = ini.get_tag(application_id, "supportContact", true, &tag);
470   markupProcessor.insert("supportContact", has_tag ? tag : "");
471   has_tag = ini.get_tag(application_id, "logoLocation", true, &tag);
472   markupProcessor.insert("logoLocation", has_tag ? tag : "");
473   markupProcessor.insert("requestURL", targeturl);
474   
475     SHIRE shire(config, unescaped_shire);
476
477   // Process SHIRE POST
478
479   ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
480                 "shire_post_handler() Beginning SHIRE POST processing");
481       
482   try {
483     string sslonly;
484     if (!ini.get_tag(application_id, "shireSSLOnly", true, &sslonly))
485       ap_log_rerror(APLOG_MARK,APLOG_CRIT|APLOG_NOERRNO,r,
486                     "shire_post_handler: no shireSSLOnly configuration");
487     
488     // Make sure this is SSL, if it should be
489     if (ShibINI::boolean(sslonly) && strcmp(ap_http_method(r),"https"))
490       throw ShibTargetException(SHIBRPC_OK, "blocked non-SSL access to SHIRE POST processor");
491
492     // Make sure this is a POST
493     if (strcasecmp (r->method, "POST"))
494       throw ShibTargetException(SHIBRPC_OK, "blocked non-POST to SHIRE POST processor");
495
496     // Sure sure this POST is an appropriate content type
497     const char *ct = ap_table_get (r->headers_in, "Content-type");
498     if (!ct || strcasecmp (ct, "application/x-www-form-urlencoded"))
499       throw ShibTargetException (SHIBRPC_OK,
500                                  ap_psprintf(r->pool,
501                              "blocked bad content-type to SHIRE POST processor: %s",
502                                              (ct ? ct : "")));
503         
504     // Make sure the "bytes sent" is a reasonable number
505     if (r->bytes_sent > 1024*1024) // 1MB?
506       throw ShibTargetException (SHIBRPC_OK,
507                                  "blocked too-large a post to SHIRE POST processor");
508
509     // Read the posted data
510     ApacheRequest *ap_req = ApacheRequest_new(r);
511     int err = ApacheRequest_parse(ap_req);
512     if (err != OK)
513       throw ShibTargetException (SHIBRPC_OK,
514                                  ap_psprintf(r->pool,
515                              "ApacheRequest_parse() failed with %d.", err));
516
517     
518     // Make sure the target parameter exists
519     const char *target = ApacheRequest_param(ap_req, "TARGET");
520     if (!target || *target == '\0')
521       // invalid post
522       throw ShibTargetException (SHIBRPC_OK,
523                                  "SHIRE POST failed to find TARGET");
524
525     // Make sure the SAML Response parameter exists
526     const char *post = ApacheRequest_param(ap_req, "SAMLResponse");
527     if (!post || *post == '\0')
528       // invalid post
529       throw ShibTargetException (SHIBRPC_OK,
530                                  "SHIRE POST failed to find SAMLResponse");
531
532     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
533                   "shire_post_handler() Processing POST for target: %s", target);
534
535     // process the post
536     string cookie;
537     RPCError* status = shire.sessionCreate(post, r->connection->remote_ip, application_id, cookie);
538
539     if (status->isError()) {
540       ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,
541                     "shire_post_handler() POST process failed (%d): %s",
542                     status->getCode(), status->getText());
543
544     if (status->isRetryable()) {
545           ap_log_rerror(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,r,
546                 "shire_post_handler() Retrying POST by redirecting to WAYF");
547         
548         char timebuf[16];
549         sprintf(timebuf,"%u",time(NULL));
550         char* wayf=ap_pstrcat(r->pool,wayfLocation.c_str(),
551                               "?shire=",url_encode(r,unescaped_shire),
552                               "&target=",url_encode(r,targeturl),
553                   "&time=",timebuf,
554                   "&providerId=",application_id,NULL);
555         ap_table_setn(r->headers_out,"Location",wayf);
556         delete status;
557         return REDIRECT;
558     }
559
560       // return this error to the user.
561       markupProcessor.insert (*status);
562       delete status;
563       return shire_error_page (r, shireError.c_str(), markupProcessor);
564     }
565     delete status;
566
567     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
568                   "shire_post_handler() POST process succeeded.  New cookie: %s",
569                   cookie.c_str());
570
571     // We've got a good session, set the cookie...
572     char * domain = NULL;
573     char * new_cookie = ap_psprintf(r->pool, "%s=%s; path=/%s%s",
574                                     shib_cookie.c_str(),
575                                     cookie.c_str(),
576                                     (domain ? "; domain=" : ""),
577                                     (domain ? domain : ""));
578     
579     ap_table_setn(r->err_headers_out, "Set-Cookie", new_cookie);
580     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
581                   "shire_post_handler() Set cookie: %s", new_cookie);
582                     
583     // ... and redirect to the target
584     char* redir=ap_pstrcat(r->pool,url_encode(r,target),NULL);
585     ap_table_setn(r->headers_out, "Location", target);
586     return REDIRECT;
587
588   } catch (ShibTargetException &e) {
589     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,
590                   "shire_post_handler(): %s", e.what());
591         
592     markupProcessor.insert ("errorType", "SHIRE Processing Error");
593     markupProcessor.insert ("errorText", e.what());
594     markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
595     return shire_error_page (r, shireError.c_str(), markupProcessor);
596   }
597   catch (...) {
598     ap_log_rerror(APLOG_MARK,APLOG_DEBUG|APLOG_NOERRNO,r,"shire_post_handler(): unexpected exception");
599   
600     markupProcessor.insert ("errorType", "SHIRE Processing Error");
601     markupProcessor.insert ("errorText", "Unexpected Exception");
602     markupProcessor.insert ("errorDesc", "An error occurred while processing your request.");
603     return shire_error_page (r, shireError.c_str(), markupProcessor);
604   }
605
606   ap_log_rerror(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO,r,"shire_post_handler() server error");
607   return SERVER_ERROR;
608 }
609
610 extern "C"{
611 handler_rec shire_handlers[] = {
612   { "shib-shire-post", shire_post_handler },
613   { NULL }
614 };
615
616 extern "C" void mod_shire_init (server_rec*r, pool* p)
617 {
618   ShibTargetConfig::preinit();
619 }
620
621 module MODULE_VAR_EXPORT shire_module = {
622     STANDARD_MODULE_STUFF,
623     mod_shire_init,             /* initializer */
624     create_shire_dir_config,    /* dir config creater */
625     merge_shire_dir_config,     /* dir merger --- default is to override */
626     NULL,                       /* server config */
627     NULL,                       /* merge server config */
628     shire_cmds,                 /* command table */
629     shire_handlers,             /* handlers */
630     NULL,                       /* filename translation */
631     shire_check_user,           /* check_user_id */
632     NULL,                       /* check auth */
633     NULL,                       /* check access */
634     NULL,                       /* type_checker */
635     NULL,                       /* fixups */
636     NULL,                       /* logger */
637     NULL,                       /* header parser */
638     shire_child_init,           /* child_init */
639     shire_child_exit,           /* child_exit */
640     NULL                        /* post read-request */
641 };
642 }