typo
[hcoop/debian/libapache-mod-waklog.git] / mod_waklog.c
CommitLineData
87822447 1#define _LARGEFILE64_SOURCE
ff47641b 2#define _GNU_SOURCE
87822447 3
bed98ff9 4#include "httpd.h"
5#include "http_config.h"
bed98ff9 6#include "http_log.h"
7193eb01 7#include "http_protocol.h"
8#include "http_request.h"
9#include "http_core.h"
87822447 10
ff47641b 11#ifdef sun
12#include <synch.h>
13#elif linux
14#define use_pthreads
15#include <features.h>
16#include <sys/types.h>
17#include <sys/mman.h>
18#include <pthread.h>
19#else
20#error "make sure you include the right stuff here"
21#endif
22
23#ifndef MAXNAMELEN
24#define MAXNAMELEN 1024
25#endif
26
891fb458 27#ifdef STANDARD20_MODULE_STUFF
c9d59a9c 28#define APACHE2
29#endif
30
31/********************* APACHE1 ******************************************************************************/
32#ifndef APACHE2
ebb1f61c 33#include "ap_config.h"
34#if defined(sun)
35#include <sys/ioccom.h>
36#endif /* sun */
37#include <http_conf_globals.h>
38#define MK_POOL pool
39#define MK_TABLE_GET ap_table_get
40#define MK_TABLE_SET ap_table_set
41#define command(name, func, var, type, usage) \
42 { name, func, \
43 NULL , \
44 RSRC_CONF | ACCESS_CONF , type, usage }
21a7788b 45module waklog_module;
ebb1f61c 46
47/********************* APACHE2 ******************************************************************************/
48#else
87822447 49#include <apr_strings.h>
50#include <apr_base64.h>
ebb1f61c 51#define ap_pcalloc apr_pcalloc
52#define ap_pdupstr apr_pdupstr
53#define ap_pstrdup apr_pstrdup
87822447 54#define MK_POOL apr_pool_t
55#define MK_TABLE_GET apr_table_get
d06251b1 56#define MK_TABLE_SET apr_table_set
87822447 57#include "unixd.h"
58extern unixd_config_rec unixd_config;
59#define ap_user_id unixd_config.user_id
60#define ap_group_id unixd_config.group_id
61#define ap_user_name unixd_config.user_name
62#define command(name, func, var, type, usage) \
63 AP_INIT_ ## type (name, (void*) func, \
ebb1f61c 64 NULL, \
65 RSRC_CONF | ACCESS_CONF, usage)
21a7788b 66module AP_MODULE_DECLARE_DATA waklog_module;
67typedef struct { int dummy; } child_info;
87822447 68const char *userdata_key = "waklog_init";
21a7788b 69
c9d59a9c 70#endif /* APACHE2 */
ebb1f61c 71/**************************************************************************************************/
877d453f 72
73#include <krb5.h>
877d453f 74#include <stropts.h>
75#include <afs/venus.h>
76#include <afs/auth.h>
77#include <afs/dirpath.h>
78#include <afs/ptuser.h>
79#include <rx/rxkad.h>
80
81#define TKT_LIFE ( 12 * 60 * 60 )
42d78dfb 82#define SLEEP_TIME ( TKT_LIFE - 5*60 )
877d453f 83
84#define WAKLOG_ON 1
85#define WAKLOG_OFF 2
86#define WAKLOG_UNSET 0
87
88#ifdef WAKLOG_DEBUG
89#undef APLOG_DEBUG
90#define APLOG_DEBUG APLOG_ERR
91#endif
92
877d453f 93/* this is used to turn off pag generation for the backround worker child during startup */
94int pag_for_children = 1;
95
96typedef struct
97{
98 int forked;
99 int configured;
100 int protect;
101 int usertokens;
c8563f50 102 int cell_in_principal;
21a7788b 103 int disable_token_cache;
877d453f 104 char *keytab;
105 char *principal;
106 char *default_principal;
107 char *default_keytab;
108 char *afs_cell;
109 char *path;
110 MK_POOL *p;
111}
112waklog_config;
113
114typedef struct
115{
116 struct ktc_token token;
117 char clientprincipal[MAXNAMELEN];
118 krb5_context kcontext;
119 krb5_ccache ccache;
120 struct ktc_principal server;
121 struct ktc_principal client;
122 int pr_init;
123} waklog_child_config;
124
125waklog_child_config child;
126
127struct tokencache_ent {
128 char clientprincipal[MAXNAMELEN];
129 struct ktc_token token;
130 struct ktc_principal client;
131 struct ktc_principal server;
132 time_t lastused;
133 int persist;
134};
135
136#define SHARED_TABLE_SIZE 512
137
138struct sharedspace_s {
139 int renewcount;
140 struct tokencache_ent sharedtokens[SHARED_TABLE_SIZE];
141};
142
143struct sharedspace_s *sharedspace = NULL;
144
145struct renew_ent {
146 char *keytab;
147 char *principal;
148 int lastrenewed;
149};
150
151#ifdef use_pthreads
152pthread_rwlock_t *sharedlock = NULL;
153#else
154rwlock_t *sharedlock = NULL;
155#endif
156
157struct renew_ent renewtable[SHARED_TABLE_SIZE];
158
159int renewcount = 0;
160
ebb1f61c 161
87822447 162
c69d952f 163#define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
87822447 164
4e1ae1cd 165#include <krb5.h>
bed98ff9 166
7193eb01 167#if defined(sun)
bed98ff9 168#include <sys/ioccom.h>
7193eb01 169#endif /* sun */
bed98ff9 170#include <stropts.h>
bed98ff9 171#include <afs/venus.h>
7193eb01 172#include <afs/auth.h>
d06251b1 173#include <afs/dirpath.h>
174#include <afs/ptuser.h>
7193eb01 175#include <rx/rxkad.h>
176
58bbdc54 177
87822447 178static void
3f4fda20 179log_error (const char *file, int line, int level, int status,
42d78dfb 180 const server_rec * s, const char *fmt, ...)
4d47a8d9 181{
3f4fda20 182 char errstr[4096];
183 va_list ap;
4d47a8d9 184
3f4fda20 185 va_start (ap, fmt);
186 vsnprintf (errstr, 1024, fmt, ap);
187 va_end (ap);
4d47a8d9 188
c9d59a9c 189#ifdef APACHE2
3f4fda20 190 ap_log_error (file, line, level | APLOG_NOERRNO, status, s, "(%d) %s", getpid(), errstr);
87822447 191#else
3f4fda20 192 ap_log_error (file, line, level | APLOG_NOERRNO, s, "(%d) %s", getpid(), errstr);
87822447 193#endif
4d47a8d9 194
87822447 195}
4d47a8d9 196
3f4fda20 197waklog_config *retrieve_config(request_rec *r) {
198
199 request_rec *my;
200 waklog_config *cfg;
201
202 if ( r && r->main ) {
203 my = r->main;
204 } else if (r) {
205 my = r;
206 } else {
207 return NULL;
208 }
209
210 if ( my && ( cfg = (waklog_config *) ap_get_module_config(my->per_dir_config, &waklog_module ) ) ) {
211 return cfg;
212 } else {
213 getModConfig (cfg, r->server);
214 }
215
216 return cfg;
217
218}
313dde40 219
3f4fda20 220/* set_auth -- sets the tokens of the current process to this user.
221 if "self" is set, it divines the user from the current requests' environment.
222 otherwise, it's gettng it from principal/keytab */
223
224int
225set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keytab, int storeonly ) {
226
227 int i;
228 int usecached = 0;
229 krb5_error_code kerror = 0;
230 krb5_principal kprinc = NULL;
231 krb5_get_init_creds_opt kopts;
232 krb5_creds v5creds;
233 krb5_creds increds;
234 struct ktc_principal server = { "afs", "", "" };
235 struct ktc_principal client;
236 struct ktc_token token;
237 krb5_creds *v5credsp = NULL;
238 krb5_keytab krb5kt = NULL;
239 char buf[MAXNAMELEN];
240 waklog_config *cfg;
241 int rc = 0;
242 int buflen = 0;
243 time_t oldest_time = 0;
244 int oldest;
245 int stored = -1;
246 time_t mytime;
247 int indentical;
c8563f50 248 int cell_in_principal;
249 int attempt;
3f4fda20 250
251 char k5user[MAXNAMELEN];
252 char *k5secret;
253
254 memset((char *) &increds, 0, sizeof(increds));
255
256 /* init some stuff if it ain't already */
257
258 if ( ! child.kcontext ) {
259 kerror = krb5_init_context(&child.kcontext);
260 }
261
262 if ( ( ! child.ccache ) && ( kerror = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) ) {
263 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", kerror );
264 }
265
266
267 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth: %d, %s, %s, %d", self, principal ? principal : "NULL",
268 keytab ? keytab : "NULL", storeonly);
269
270 /* pull the server config record that we care about... */
271
272 if ( r ) {
273 cfg = retrieve_config(r);
274 } else {
275 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 276 "mod_waklog: set_auth using no config" );
3f4fda20 277 getModConfig (cfg, s);
278 }
279
280 if ( ! cfg ) {
281 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: cfg is %d", cfg );
282 }
283
c9d59a9c 284#ifdef APACHE2
3f4fda20 285 if ( self ) {
286 /* pull out our principal name and stuff from the environment -- webauth better have sent
287 through. This here is also where you'd suck stuff out of KRB5CCNAME if we were
288 using something like Cosign */
289
290 if ( ! ( r && r->connection && r->user )) {
291 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: self authentication selected, but no data available");
292 return -1;
293 }
294
295 strncpy(k5user, r->user, sizeof(k5user));
296
297 /* the other thing we need is someone's password */
298 if ( ! ( k5secret = (char *) MK_TABLE_GET( r->notes, "ATTR_PASSWORD" ) ) ) {
299 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cant do self auth without a secret");
300 return -1;
301 }
302
303 /* we'll pick this up later after we've checked the cache and current state */
304
305 } else
306#endif
307 if ( principal ) {
308 strncpy( k5user, principal, sizeof(k5user));
309 }
310
311 mytime = time(0);
312
313 /* see if we should just go ahead and ignore this call, since we already should be set to these
314 credentials */
313dde40 315
3f4fda20 316 if ( ! storeonly ) {
313dde40 317
3f4fda20 318#ifdef use_pthreads
319 pthread_rwlock_rdlock( sharedlock );
320#else
321 rw_rdlock( sharedlock );
322#endif
313dde40 323
3f4fda20 324 for ( i = 0; i < SHARED_TABLE_SIZE; ++i ) {
325
326 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
327
328 if ( ( !strcmp( k5user,
329 sharedspace->sharedtokens[i].clientprincipal ) ) &&
330 ( sharedspace->sharedtokens[i].token.endTime > mytime ) ) {
331
332 if ( ! memcmp(&child.token, &sharedspace->sharedtokens[i].token, sizeof(child.token) ) ) {
333 indentical = 1;
334 } else {
335 indentical = 0;
336 }
337
338 /* copy the token out of the cache and into the child object */
339
340 strcpy(child.clientprincipal, sharedspace->sharedtokens[i].clientprincipal );
341 memcpy(&child.token, &sharedspace->sharedtokens[i].token, sizeof(child.token));
342 memcpy(&child.server, &sharedspace->sharedtokens[i].server, sizeof(child.server));
343 memcpy(&child.client, &sharedspace->sharedtokens[i].client, sizeof(child.client));
344
345 /* set our last used time thing */
346 sharedspace->sharedtokens[i].lastused = mytime;
347
348 usecached = 1;
349
350 break;
351
352 }
353
354 }
355
356 /* release the lock on the token cache */
357#ifdef use_pthreads
358 pthread_rwlock_unlock( sharedlock );
359#else
360 rw_unlock( sharedlock );
361#endif
313dde40 362
3f4fda20 363 if ( usecached ) {
364 /* release the lock on the token cache */
365 log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
366 "mod_waklog: set_auth using shared token %d for %s", i, k5user );
367
368 }
369
370 /* if this is something that was in the cache, and it's the same as the token we already have stored,
371 and we weren't calling this just to renew it... */
372
373 if ( usecached && indentical ) {
374 log_error (APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: token is identical for %s", k5user );
375 return 0;
376 }
377
378 }
379
380 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
381
382 if (( ! usecached ) && ( k5user )) {
313dde40 383
3f4fda20 384 /* clear out the creds structure */
385 memset((void *) &v5creds, 0, sizeof(v5creds));
386
387 /* create a principal out of our k5user string */
388
389 if ( kerror = krb5_parse_name (child.kcontext, k5user, &kprinc ) ) {
390 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror) );
391 goto cleanup;
392 }
393
394 /* create the credentials options */
395
396 krb5_get_init_creds_opt_init ( &kopts );
397 krb5_get_init_creds_opt_set_tkt_life ( &kopts, TKT_LIFE );
398 krb5_get_init_creds_opt_set_renew_life ( &kopts, 0 );
399 krb5_get_init_creds_opt_set_forwardable ( &kopts, 0 );
400 krb5_get_init_creds_opt_set_proxiable ( &kopts, 0 );
401
402 if ( keytab ) {
403
404 /* if we've been passed a keytab, we're going to be getting our credentials from it */
405
406 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: using keytab %s", keytab);
407
408 if ( kerror = krb5_kt_resolve(child.kcontext, keytab, &krb5kt ) ) {
409 log_error( APLOG_MARK, APLOG_ERR, 0, s,
410 "mod_waklog: krb5_kt_resolve %s", error_message(kerror) );
411 goto cleanup;
412 }
413
414 if ((kerror = krb5_get_init_creds_keytab (child.kcontext, &v5creds,
415 kprinc, krb5kt, 0, NULL, &kopts ) ) ) {
416 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_init_creds_keytab %s",
417 error_message(kerror) );
418 goto cleanup;
419 }
420
421 } else if ( self ) {
422
423 /* if 'self' is set, we're going to use the credentials provided in the credential information */
424 /* if you're using CoSign, you'd actually just set the ccache to the KRB5CCNAME credentials */
425 /* and skip ahead... Our WebSSO is lame, but has a way for us to snarf the password out of */
426 /* the encrypted token for proxy-authentication stuff. We only hand out keys that allow this */
427 /* functionality to VERY special people. */
428
429 if ((kerror = krb5_get_init_creds_password ( child.kcontext, &v5creds,
430 kprinc, k5secret, NULL, NULL, 0, NULL, &kopts ) ) ) {
431 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_init_creds_password %s",
432 error_message(kerror) );
433 /* nuke the password so it doesn't end up in core files */
434 memset(k5secret, 0, sizeof(k5secret));
435 goto cleanup;
436 }
437
438 memset(k5secret, 0, sizeof(k5secret));
439
440 } else {
441
442 /* degenerate case -- we don't have enough information to do anything */
443
444 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: no keytab, no self?");
445 kerror = -1;
446 goto cleanup;
447
448 }
449
450 /* initialize the credentials cache and store the stuff we just got */
451
452 if ( kerror = krb5_cc_initialize (child.kcontext, child.ccache, kprinc)) {
453 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: init credentials cache %s",
454 error_message(kerror));
455 goto cleanup;
456 }
457
458 if ( kerror = krb5_cc_store_cred(child.kcontext, child.ccache, &v5creds) ) {
459 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot store credentials %s",
460 error_message(kerror));
461 goto cleanup;
462 }
463
464 krb5_free_cred_contents(child.kcontext, &v5creds);
465
466 if ( kerror ) {
467 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: store cred %s", error_message(kerror));
468 goto cleanup;
469 }
470
471 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: kinit ok for %s", k5user );
472
473 /* now, to the 'aklog' portion of our program. */
474
475 strncpy( buf, "afs", sizeof(buf) - 1 );
313dde40 476
c8563f50 477 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
478 for(attempt = 0; attempt <= 1; attempt++) {
479 cell_in_principal = (cfg->cell_in_principal + attempt) % 2;
480
481 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: cell_in_principal=%d", cell_in_principal );
482 if (cell_in_principal) {
483 strncat(buf, "/", sizeof(buf) - strlen(buf) - 1);
484 strncat(buf, cfg->afs_cell, sizeof(buf) - strlen(buf) - 1);
485 }
486
487 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: using AFS principal: %s", buf);
488
489 if ((kerror = krb5_parse_name (child.kcontext, buf, &increds.server))) {
490 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_parse name %s", error_message(kerror));
491 goto cleanup;
492 }
493
494 if ((kerror = krb5_cc_get_principal(child.kcontext, child.ccache, &increds.client))) {
495 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_cc_get_princ %s", error_message(kerror));
496 goto cleanup;
497 }
498
499 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: retrieved data from ccache for %s", k5user);
500
501 increds.times.endtime = 0;
502
503 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
504
505 if (kerror = krb5_get_credentials (child.kcontext, 0, child.ccache, &increds, &v5credsp )) {
506 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
507 if (attempt>=1) {
508 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_credentials: %s",
509 error_message(kerror));
510 goto cleanup;
511 } else {
512 continue;
513 }
514 }
515 cfg->cell_in_principal = cell_in_principal;
516 break;
3f4fda20 517 }
c8563f50 518
3f4fda20 519 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: get_credentials passed for %s", k5user);
520
521 if ( v5credsp->ticket.length >= MAXKTCTICKETLEN ) {
522 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: ticket size (%d) too big to fake",
523 v5credsp->ticket.length);
524 goto cleanup;
525 }
313dde40 526
3f4fda20 527 memset(&token, 0, sizeof(struct ktc_token));
528
529 token.startTime = v5credsp->times.starttime ? v5credsp->times.starttime : v5credsp->times.authtime;
530 token.endTime = v5credsp->times.endtime;
531
532 memmove( &token.sessionKey, v5credsp->keyblock.contents, v5credsp->keyblock.length);
533 token.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
534 token.ticketLen = v5credsp->ticket.length;
535 memmove( token.ticket, v5credsp->ticket.data, token.ticketLen);
536
537 /* build the name */
538
539 memmove( buf, v5credsp->client->data[0].data, min(v5credsp->client->data[0].length,
540 MAXKTCNAMELEN -1 ));
541 buf[v5credsp->client->data[0].length] = '\0';
542 if ( v5credsp->client->length > 1 ) {
543 strncat(buf, ".", sizeof(buf) - strlen(buf) - 1);
544 buflen = strlen(buf);
545 memmove(buf + buflen, v5credsp->client->data[1].data,
546 min(v5credsp->client->data[1].length,
547 MAXKTCNAMELEN - strlen(buf) - 1));
548 buf[buflen + v5credsp->client->data[1].length] = '\0';
549 }
550
551 /* assemble the client */
552 strncpy(client.name, buf, sizeof(client.name) - 1 );
553 strncpy(client.instance, "", sizeof(client.instance) - 1 );
554 memmove(buf, v5credsp->client->realm.data, min(v5credsp->client->realm.length,
555 MAXKTCNAMELEN - 1));
556 buf[v5credsp->client->realm.length] = '\0';
557 strncpy(client.cell, buf, sizeof(client.cell));
558
559 /* assemble the server's cell */
891fb458 560 strncpy(server.cell, cfg->afs_cell, sizeof(server.cell) - 1);
3f4fda20 561
562 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: preparing to init PTS connection for %s", server.cell);
563
564 /* fill out the AFS ID in the client name */
565 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
566 * strange things seem to happen. */
567
568 {
569 afs_int32 viceId = 0;
570
571 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: making PTS call to look up %s", client.name);
572
573 if ( ( rc = pr_SNameToId( client.name, &viceId ) ) == 0 ) {
574 snprintf( client.name, sizeof(client.name), "AFS ID %d", viceId );
575 } else {
576 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: PTS call returned error %d ", rc);
577 }
578
579 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: PTS call returned %s ", client.name);
580
581 }
582
583 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: server: name %s, instance %s, cell %s",
584 server.name, server.instance, server.cell );
585
586 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: client: name %s, instance %s, cell %s",
587 client.name, client.instance, client.cell );
588
589 /* copy the resulting stuff into the child structure */
590
591 strncpy(child.clientprincipal, k5user, sizeof(child.clientprincipal));
592 memcpy(&child.token, &token, sizeof(child.token));
593 memcpy(&child.server, &server, sizeof(child.server));
594 memcpy(&child.client, &client, sizeof(child.client));
595
596 /* stuff the resulting token-related stuff into our shared token cache */
597 /* note, that anything that was set from a keytab is "persistant", and is immune
598 * from LRU-aging. This is because nothing but the process that's running as root
599 * can update these, and it's running every hour or so and renewing these tokens.
600 * and we don't want them aged out.
601 */
602
603 mytime = oldest_time = time(0);
604
605 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: waiting for shared space for %s ", k5user);
4e1ae1cd 606
3f4fda20 607#ifdef use_pthreads
608 pthread_rwlock_wrlock(sharedlock);
609#else
610 rw_wrlock(sharedlock);
611#endif
4e1ae1cd 612
3f4fda20 613 for( i = ( SHARED_TABLE_SIZE - 1 ); i >= 0; i-- ) {
614 if ( ( sharedspace->sharedtokens[i].lastused <= oldest_time) &&
615 ( sharedspace->sharedtokens[i].persist == 0 ) ) {
616 oldest = i;
617 oldest_time = sharedspace->sharedtokens[i].lastused;
618 }
619 if ( ! strcmp ( sharedspace->sharedtokens[i].clientprincipal,
620 child.clientprincipal ) ) {
621 memcpy(&sharedspace->sharedtokens[i].token, &child.token, sizeof(child.token) );
622 memcpy(&sharedspace->sharedtokens[i].client, &child.client, sizeof(child.client) );
623 memcpy(&sharedspace->sharedtokens[i].server, &child.server, sizeof(child.server) );
624 sharedspace->sharedtokens[i].lastused = mytime;
625 sharedspace->sharedtokens[i].persist = keytab ? 1 : 0;
626 stored = i;
627 break;
628 }
629 }
630
631 if ( stored == -1 ) {
632 memcpy(&sharedspace->sharedtokens[oldest].token, &child.token, sizeof(child.token) );
633 memcpy(&sharedspace->sharedtokens[oldest].client, &child.client, sizeof(child.client) );
634 memcpy(&sharedspace->sharedtokens[oldest].server, &child.server, sizeof(child.server) );
635 strcpy(sharedspace->sharedtokens[oldest].clientprincipal, child.clientprincipal );
636 sharedspace->sharedtokens[oldest].lastused = mytime;
637 sharedspace->sharedtokens[oldest].persist = keytab ? 1 : 0;
638 stored = oldest;
639 }
3ed1e28a 640
3f4fda20 641#ifdef use_pthreads
642 pthread_rwlock_unlock(sharedlock);
643#else
644 rw_unlock(sharedlock);
645#endif
646
647 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: token stored in slot %d for %s", stored,
648 child.clientprincipal );
649
650 } else if ( ! usecached ) {
651 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth divergent case");
652 }
653
654 if ( storeonly ) {
655 goto cleanup;
656 }
657
658 usecachedtoken:
659
660 /* don't ask. Something about AIX. We're leaving it here.*/
661 /* write(2, "", 0); */
662
663 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
664
665 if ((rc = ktc_SetToken(&child.server, &child.token, &child.client, 0))) {
666 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: settoken returned %s for %s -- trying again",
667 error_message(rc), k5user);
668 if ((rc = ktc_SetToken(&child.server, &child.token, &child.client, 0))) {
669 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: settoken2 returned %s for %s",
670 error_message(rc), k5user);
671 goto cleanup;
672 }
673 }
674
675 cleanup:
676 if ( v5credsp )
677 krb5_free_cred_contents(child.kcontext, v5credsp);
678 if ( increds.client )
679 krb5_free_principal (child.kcontext, increds.client);
680 if ( increds.server )
681 krb5_free_principal (child.kcontext, increds.server);
682 if ( krb5kt )
683 (void) krb5_kt_close(child.kcontext, krb5kt);
684 if ( kprinc )
685 krb5_free_principal (child.kcontext, kprinc);
686
687 if ( rc ) {
688 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with %d", rc );
689 } else if ( kerror ) {
690 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror, error_message(kerror));
691 } else {
692 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth ending ok");
693 }
694
695 return kerror ? (int) kerror : (int) rc;
696
4e1ae1cd 697}
698
699
7193eb01 700
3f4fda20 701static void *
702waklog_create_server_config (MK_POOL * p, server_rec * s)
703{
704 waklog_config *cfg;
705
706 cfg = (waklog_config *) ap_pcalloc (p, sizeof (waklog_config));
707 cfg->p = p;
708 memset(cfg, 0, sizeof(waklog_config));
709 cfg->path = "(server)";
710 cfg->protect = WAKLOG_UNSET;
711 cfg->usertokens = WAKLOG_UNSET;
21a7788b 712 cfg->disable_token_cache = WAKLOG_UNSET;
3f4fda20 713 cfg->keytab = WAKLOG_UNSET;
714 cfg->principal = WAKLOG_UNSET;
715 cfg->default_principal = WAKLOG_UNSET;
716 cfg->default_keytab = WAKLOG_UNSET;
717 cfg->afs_cell = WAKLOG_UNSET;
718 cfg->forked = 0;
719 cfg->configured = 0;
720
721 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 722 "mod_waklog: server config created.");
3f4fda20 723
724 return (cfg);
725}
7193eb01 726
3f4fda20 727/* initialize with host-config information */
58bbdc54 728
3f4fda20 729static void *
730waklog_create_dir_config (MK_POOL * p, char *dir)
731{
732 waklog_config *cfg;
733
734 cfg = (waklog_config *) ap_pcalloc (p, sizeof (waklog_config));
735 memset(cfg, 0, sizeof(waklog_config));
736 cfg->p = p;
737 cfg->path = ap_pstrdup(p, dir );
738 cfg->protect = WAKLOG_UNSET;
739 cfg->usertokens = WAKLOG_UNSET;
21a7788b 740 cfg->disable_token_cache = WAKLOG_UNSET;
3f4fda20 741 cfg->keytab = WAKLOG_UNSET;
742 cfg->principal = WAKLOG_UNSET;
743 cfg->default_principal = WAKLOG_UNSET;
744 cfg->default_keytab = WAKLOG_UNSET;
745 cfg->afs_cell = WAKLOG_UNSET;
746 cfg->forked = 0;
747 cfg->configured = 0;
748
749 return (cfg);
58bbdc54 750}
751
3f4fda20 752static void *waklog_merge_dir_config(MK_POOL *p, void *parent_conf, void *newloc_conf) {
58bbdc54 753
3f4fda20 754 waklog_config *merged = ( waklog_config * ) ap_pcalloc(p, sizeof(waklog_config ) );
755 waklog_config *parent = ( waklog_config * ) parent_conf;
756 waklog_config *child = ( waklog_config * ) newloc_conf;
757
758 merged->protect = child->protect != WAKLOG_UNSET ? child->protect : parent->protect;
759
760 merged->path = child->path != WAKLOG_UNSET ? child->path : parent->path;
761
762 merged->usertokens = child->usertokens != WAKLOG_UNSET ? child->usertokens : parent->usertokens;
21a7788b 763
764 merged->disable_token_cache = child->disable_token_cache != WAKLOG_UNSET ? child->disable_token_cache : parent->disable_token_cache;
3f4fda20 765
766 merged->principal = child->principal != WAKLOG_UNSET ? child->principal : parent->principal;
767
768 merged->keytab = child->keytab != WAKLOG_UNSET ? child->keytab : parent->keytab;
769
770 merged->default_keytab = child->default_keytab != WAKLOG_UNSET ? child->default_keytab : parent->default_keytab;
771
772 merged->default_principal = child->default_principal != WAKLOG_UNSET ? child->default_principal : parent->default_principal;
773
774 merged->afs_cell = child->afs_cell != WAKLOG_UNSET ? child->afs_cell : parent->afs_cell;
775
776 return (void *) merged;
777
778}
58bbdc54 779
3f4fda20 780static void *waklog_merge_server_config(MK_POOL *p, void *parent_conf, void *newloc_conf) {
58bbdc54 781
3f4fda20 782 waklog_config *merged = ( waklog_config * ) ap_pcalloc(p, sizeof(waklog_config ) );
783 waklog_config *pconf = ( waklog_config * ) parent_conf;
784 waklog_config *nconf = ( waklog_config * ) newloc_conf;
785
786 merged->protect = nconf->protect == WAKLOG_UNSET ? pconf->protect : nconf->protect;
58bbdc54 787
3f4fda20 788 merged->usertokens = nconf->usertokens == WAKLOG_UNSET ? pconf->usertokens : nconf->usertokens;
58bbdc54 789
bce7d4d9 790 merged->disable_token_cache = nconf->disable_token_cache == WAKLOG_UNSET ? pconf->disable_token_cache : nconf->disable_token_cache;
21a7788b 791
3f4fda20 792 merged->keytab = nconf->keytab == WAKLOG_UNSET ? ap_pstrdup(p, pconf->keytab) :
793 ( nconf->keytab == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->keytab) );
794
795 merged->principal = nconf->principal == WAKLOG_UNSET ? ap_pstrdup(p, pconf->principal) :
796 ( nconf->principal == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->principal) );
797
798 merged->afs_cell = nconf->afs_cell == WAKLOG_UNSET ? ap_pstrdup(p, pconf->afs_cell) :
799 ( nconf->afs_cell == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->afs_cell) );
800
801 merged->default_keytab = nconf->default_keytab == WAKLOG_UNSET ? ap_pstrdup(p, pconf->default_keytab) :
802 ( nconf->default_keytab == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->default_keytab) );
58bbdc54 803
3f4fda20 804 merged->default_principal = nconf->default_principal == WAKLOG_UNSET ? ap_pstrdup(p, pconf->default_principal) :
805 ( nconf->default_principal == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->default_principal) );
806
807
808 return (void *) merged;
809
810}
811
812static const char *
21a7788b 813set_waklog_enabled (cmd_parms * params, void *mconfig, int flag)
58bbdc54 814{
3f4fda20 815 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
816 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
817
818 cfg->protect = flag;
819 cfg->configured = 1;
820 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
21a7788b 821 "mod_waklog: waklog_enabled set on %s", cfg->path ? cfg->path : "NULL");
3f4fda20 822 return (NULL);
823}
58bbdc54 824
7193eb01 825
3f4fda20 826/* this adds a principal/keytab pair to get their tokens renewed by the
827 child process every few centons. */
7193eb01 828
3f4fda20 829void add_to_renewtable(MK_POOL *p, char *keytab, char *principal) {
87822447 830
3f4fda20 831 int i;
832
833 if ( renewcount >= SHARED_TABLE_SIZE ) {
834 log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
835 decrease your tokens.");
b74fad73 836 return;
3f4fda20 837 }
838
839 /* check to see if it's already there */
840
841 for ( i = 0; i < renewcount; i++ ) {
842 if ( ! strcmp(renewtable[i].principal, principal ) ) {
843 return;
844 }
845 }
846
847 renewtable[renewcount].keytab = ap_pstrdup(p, keytab);
848 renewtable[renewcount].principal = ap_pstrdup(p, principal);
849 renewtable[renewcount].lastrenewed = 0;
850 ++renewcount;
851
b74fad73 852}
853
3f4fda20 854static const char *
21a7788b 855set_waklog_location_principal (cmd_parms *params, void *mconfig, char *principal, char *keytab)
3f4fda20 856{
857 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
858 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
859
860 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
42d78dfb 861 "mod_waklog: configuring principal: %s, keytab: %s", principal, keytab);
862
863 cfg->principal = ap_pstrdup(params->pool, principal);
3f4fda20 864 cfg->keytab = ap_pstrdup (params->pool, keytab);
865
866 add_to_renewtable(params->pool, keytab, principal);
867
868 cfg->configured = 1;
869
870 return (NULL);
871}
b74fad73 872
3f4fda20 873static const char *
21a7788b 874set_waklog_afs_cell (cmd_parms * params, void *mconfig, char *file)
313dde40 875{
891fb458 876 waklog_config *waklog_mconfig = ( waklog_config * ) mconfig;
877 waklog_config *waklog_srvconfig =
3f4fda20 878 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
879
891fb458 880 log_error (APLOG_MARK, APLOG_INFO, 0, params->server,
42d78dfb 881 "mod_waklog: will use afs_cell: %s", file);
313dde40 882
c8563f50 883 waklog_srvconfig->cell_in_principal = 0;
891fb458 884 waklog_srvconfig->afs_cell = ap_pstrdup (params->pool, file);
885 waklog_srvconfig->configured = 1;
886
887 if (waklog_mconfig != NULL) {
c8563f50 888 waklog_mconfig->cell_in_principal = waklog_srvconfig->cell_in_principal;
891fb458 889 waklog_mconfig->afs_cell = ap_pstrdup (params->pool, file);
890 waklog_mconfig->configured = 1;
891 }
3f4fda20 892 return (NULL);
893}
58bbdc54 894
3f4fda20 895static const char *
896set_waklog_default_principal (cmd_parms * params, void *mconfig, char *principal, char *keytab)
897{
898 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
899 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
58bbdc54 900
3f4fda20 901 waklog_config *srvcfg = ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
4e1ae1cd 902
3f4fda20 903 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
42d78dfb 904 "mod_waklog: set default princ/keytab: %s, %s for %s", principal, keytab, cfg->path ? cfg->path : "NULL");
313dde40 905
3f4fda20 906 cfg->default_principal = ap_pstrdup (params->pool, principal);
907 cfg->default_keytab = ap_pstrdup(params->pool, keytab );
908
909 /* this also gets set at the server level */
910 if ( mconfig && ( ! cfg->path ) ) {
911 srvcfg->default_principal = ap_pstrdup (params->pool, principal);
912 srvcfg->default_keytab = ap_pstrdup(params->pool, keytab );
913 } else {
914 log_error(APLOG_MARK, APLOG_ERR, 0, params->server, "only able to set default principal on a global level!");
915 return "Unable to set DefaultPrincipal outside of top level config!";
916 }
917
918 add_to_renewtable( params->pool, keytab, principal );
919
920 cfg->configured = 1;
921
922 return (NULL);
923}
313dde40 924
3f4fda20 925static const char *
926set_waklog_use_usertokens (cmd_parms * params, void *mconfig, int flag)
bed98ff9 927{
3f4fda20 928 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
929 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
bed98ff9 930
3f4fda20 931 cfg->usertokens = flag;
bed98ff9 932
3f4fda20 933 cfg->configured = 1;
bed98ff9 934
3f4fda20 935 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
42d78dfb 936 "mod_waklog: waklog_use_user_tokens set");
3f4fda20 937 return (NULL);
bed98ff9 938}
939
940
21a7788b 941static const char *
942set_waklog_disable_token_cache (cmd_parms * params, void *mconfig, int flag)
943{
944 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
945 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
946
947 cfg->disable_token_cache = flag;
948
949 cfg->configured = 1;
950
951 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
952 "mod_waklog: waklog_disable_token_cache set");
953 return (NULL);
954}
955
956
c9d59a9c 957#ifndef APACHE2
3f4fda20 958static void waklog_child_exit( server_rec *s, MK_POOL *p ) {
959#else
960apr_status_t waklog_child_exit( void *sr ) {
4e1ae1cd 961
3f4fda20 962 server_rec *s = (server_rec *) sr;
963#endif
964
965 if ( child.ccache ) {
966 krb5_cc_close(child.kcontext, child.ccache);
967 }
968
969 if ( child.kcontext ) {
970 krb5_free_context(child.kcontext);
971 }
972
973 /* forget our tokens */
974
975 ktc_ForgetAllTokens ();
976
977 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 978 "mod_waklog: waklog_child_exit complete");
4e1ae1cd 979
c9d59a9c 980#ifdef APACHE2
3f4fda20 981 return APR_SUCCESS;
982#endif
983
984}
4e1ae1cd 985
3f4fda20 986static void
c9d59a9c 987#ifdef APACHE2
3f4fda20 988waklog_child_init (MK_POOL * p, server_rec * s)
989#else
990waklog_child_init (server_rec * s, MK_POOL * p)
991#endif
992{
b52ccbb1 993
3f4fda20 994 krb5_error_code code;
995 waklog_config *cfg;
996
997 char *cell;
998
3f4fda20 999 log_error (APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init called for pid %d", getpid());
1000
1001 if ( !sharedspace ) {
1002 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: child_init called without shared space? %d", getpid());
1003 return;
1004 }
1005
1006 log_error (APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init called for pid %d", getpid());
7193eb01 1007
3f4fda20 1008 memset (&child, 0, sizeof(child));
1009
1010 if ( code = krb5_init_context(&child.kcontext) ) {
1011 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't init kerberos context %d", code );
1012 }
1013
1014 if ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) {
1015 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", code );
1016 }
1017
1018 if ( pag_for_children ) {
1019 setpag ();
1020 }
7193eb01 1021
3f4fda20 1022 getModConfig (cfg, s);
7193eb01 1023
3f4fda20 1024 if ( cfg->default_principal != WAKLOG_UNSET ) {
1025 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init setting default user %s, %s", cfg->default_principal, cfg->default_keytab);
1026 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1027 }
7193eb01 1028
891fb458 1029 cell = strdup(cfg->afs_cell);
3f4fda20 1030 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR, cell );
7193eb01 1031
c9d59a9c 1032#ifdef APACHE2
3f4fda20 1033 apr_pool_cleanup_register(p, s, waklog_child_exit, apr_pool_cleanup_null);
1034#endif
7193eb01 1035
3f4fda20 1036 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 1037 "mod_waklog: child_init returned");
7193eb01 1038
3f4fda20 1039 return;
1040}
b52ccbb1 1041
3f4fda20 1042command_rec waklog_cmds[] = {
1043
21a7788b 1044 command ("WaklogAFSCell", set_waklog_afs_cell, 0, TAKE1,
1045 "Use the supplied AFS cell (required)"),
7193eb01 1046
21a7788b 1047 command ("WaklogEnabled", set_waklog_enabled, 0, FLAG,
1048 "enable waklog on a server, location, or directory basis"),
7193eb01 1049
21a7788b 1050 command ("WaklogDefaultPrincipal", set_waklog_default_principal, 0, TAKE2,
1051 "Set the default principal that the server runs as"),
7193eb01 1052
21a7788b 1053 command ("WaklogLocationPrincipal", set_waklog_location_principal, 0, TAKE2,
1054 "Set the principal on a <Location>-specific basis"),
7193eb01 1055
21a7788b 1056 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache, 0, FLAG,
1057 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1058
1059 command ("WaklogUseUserTokens", set_waklog_use_usertokens, 0, FLAG,
1060 "Use the requesting user tokens (from webauth)"),
1061
3f4fda20 1062 {NULL}
1063};
7193eb01 1064
7193eb01 1065
3f4fda20 1066/* not currently using this */
7193eb01 1067
3f4fda20 1068static int
1069token_cleanup (void *data)
1070{
1071 request_rec *r = (request_rec *) data;
e2df6441 1072
3f4fda20 1073 if (child.token.ticketLen)
1074 {
1075 memset (&child.token, 0, sizeof (struct ktc_token));
e21f34f0 1076
3f4fda20 1077 ktc_ForgetAllTokens ();
7193eb01 1078
3f4fda20 1079 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1080 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1081 getpid ());
3f4fda20 1082 }
1083 return 0;
7193eb01 1084}
1085
3f4fda20 1086static int
1087waklog_child_routine (void *data, child_info * pinfo)
7193eb01 1088{
3f4fda20 1089 int i;
1090 server_rec *s = (server_rec *) data;
1091 krb5_error_code code;
1092 char *cell;
1093 time_t sleep_time = ( TKT_LIFE / 2 ) ;
1094 time_t when;
1095 time_t left;
1096 waklog_config *cfg;
1097
1098 getModConfig( cfg, s );
1099
1100 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1101
1102 memset (&child, 0, sizeof(child));
1103
1104 if ( code = krb5_init_context(&child.kcontext) ) {
1105 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't init kerberos context %d", code );
1106 }
1107
1108 if ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) {
1109 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", code );
1110 }
1111
1112 /* need to do this so we can make PTS calls */
891fb458 1113 cell = strdup(cfg->afs_cell); /* stupid */
3f4fda20 1114 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR, cell );
1115
1116 while(1) {
1117
1118 for ( i = 0; i < renewcount; ++i ) {
1119 renewtable[i].lastrenewed = time(0);
1120 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable[i].principal,
1121 renewtable[i].keytab);
1122
1123 set_auth( s, NULL, 0, renewtable[i].principal, renewtable[i].keytab, 1 );
1124
1125 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1126 things that it needs to read */
1127
1128 if ( cfg && cfg->default_principal && ( ! strcmp(cfg->default_principal, renewtable[i].principal ) ) ) {
1129 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: renewing/setting default tokens" );
1130 set_auth( s, NULL, 0, renewtable[i].principal, renewtable[i].keytab, 0 );
1131 }
1132
4e1ae1cd 1133 }
1134
3f4fda20 1135 sharedspace->renewcount++;
1136
1137 left = sleep_time;
1138
1139 while( left > 5 ) {
1140 when = time(0);
1141
1142 sleep(left);
1143
1144 left -= ( time(0) - when );
4e1ae1cd 1145 }
3f4fda20 1146
1147 }
4e1ae1cd 1148
3f4fda20 1149 pr_End();
403921ef 1150
3f4fda20 1151}
4e1ae1cd 1152
c9d59a9c 1153#ifdef APACHE2
3f4fda20 1154static int
1155waklog_init_handler (apr_pool_t * p, apr_pool_t * plog,
42d78dfb 1156 apr_pool_t * ptemp, server_rec * s)
3f4fda20 1157{
1158 int rv;
1159 extern char *version;
1160 apr_proc_t *proc;
1161 waklog_config *cfg;
1162 void *data;
1163 int fd = -1;
1164 int use_existing = 1;
1165 int oldrenewcount;
1166 char cache_file[MAXNAMELEN];
1167#ifdef use_pthreads
1168 pthread_rwlockattr_t rwlock_attr;
1169#endif
4e1ae1cd 1170
1171
3f4fda20 1172 getModConfig (cfg, s);
4e1ae1cd 1173
3f4fda20 1174 /* initialize_module() will be called twice, and if it's a DSO
1175 * then all static data from the first call will be lost. Only
1176 * set up our static data on the second call.
1177 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1178 apr_pool_userdata_get (&data, userdata_key, s->process->pool);
7193eb01 1179
891fb458 1180
1181 if (cfg->afs_cell==NULL) {
1182 log_error (APLOG_MARK, APLOG_ERR, 0, s,
21a7788b 1183 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
891fb458 1184 /** clobber apache */
1185 exit(-1);
1186 }
1187
3f4fda20 1188 if (!data)
1189 {
1190 apr_pool_userdata_set ((const void *) 1, userdata_key,
42d78dfb 1191 apr_pool_cleanup_null, s->process->pool);
4e1ae1cd 1192 }
3f4fda20 1193 else
1194 {
1195 log_error (APLOG_MARK, APLOG_INFO, 0, s,
891fb458 1196 "mod_waklog: version %s initialized for cell %s", version, cfg->afs_cell);
3f4fda20 1197
1198 if ( sharedspace ) {
1199 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: shared memory already allocated." );
1200 } else {
1201
1202 snprintf( cache_file, MAXNAMELEN, "/tmp/waklog_cache.%d", getpid() );
1203
1204 if ( ( fd = open( cache_file, O_RDWR, 0600 ) ) == -1 ) {
1205
1206 if ( errno == ENOENT ) {
1207
1208 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: creating shared token cache file %s", cache_file );
1209 use_existing = 0;
1210 if ( ( fd = open( cache_file, O_RDWR|O_CREAT|O_TRUNC, 0600 ) ) == -1 ) {
1211 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file, errno );
1212 exit(errno);
1213 }
1214 } else {
1215 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file, errno );
1216 }
1217 }
1218
1219 if ( use_existing == 0 ) {
1220 struct sharedspace_s bob;
1221 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: sizing our cache file %d to %d", fd, sizeof(struct sharedspace_s) );
1222 memset( &bob, 0, sizeof(struct sharedspace_s));
1223 write(fd, &bob, sizeof(struct sharedspace_s));
1224 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s) );
1225 }
1226
1227 /* mmap the region */
1228
1229 if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != MAP_FAILED ) {
1230 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared mmap region ok %d", sharedspace );
1231 close(fd);
1232 } else {
1233 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: mmap failed %d", errno );
1234 exit(errno);
1235 }
1236 }
4e1ae1cd 1237
3f4fda20 1238#ifdef use_pthreads
1239#define locktype pthread_rwlock_t
1240#else
1241#define locktype rwlock_t
1242#endif
4e1ae1cd 1243
3f4fda20 1244 if ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) {
1245#ifndef use_pthreads
1246 rwlock_init(sharedlock, USYNC_PROCESS, NULL );
1247#else
1248 pthread_rwlockattr_init(&rwlock_attr);
1249 pthread_rwlockattr_setpshared(&rwlock_attr, PTHREAD_PROCESS_SHARED);
1250 pthread_rwlock_init(sharedlock, &rwlock_attr );
1251#endif
1252 } else {
1253 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: rwlock mmap failed %d", errno );
1254 }
58bbdc54 1255
3f4fda20 1256#undef locktype
7193eb01 1257
3f4fda20 1258 /* set our default tokens */
403921ef 1259
3f4fda20 1260 oldrenewcount = sharedspace->renewcount;
7193eb01 1261
3f4fda20 1262 pag_for_children = 0;
7193eb01 1263
3f4fda20 1264 proc = (apr_proc_t *) ap_pcalloc (s->process->pool, sizeof (apr_proc_t));
7193eb01 1265
3f4fda20 1266 rv = apr_proc_fork (proc, s->process->pool);
7193eb01 1267
3f4fda20 1268 if (rv == APR_INCHILD)
42d78dfb 1269 {
1270 waklog_child_routine (s, NULL);
1271 }
3f4fda20 1272 else
42d78dfb 1273 {
1274 apr_pool_note_subprocess (s->process->pool, proc, APR_KILL_ALWAYS);
1275 }
3f4fda20 1276 /* parent and child */
1277 cfg->forked = proc->pid;
1278 pag_for_children = 1;
1279
1280 if ( use_existing == 0 ) {
1281 /* wait here until our child process has gone and done it's renewing thing. */
1282 while( sharedspace->renewcount == oldrenewcount ) {
1283 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: waiting for tokens..." );
1284 sleep(2);
1285 }
1286 }
1287
1288 if ( cfg->default_principal ) {
1289 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1290 }
1291 }
1292 return 0;
1293}
ebb1f61c 1294#else
3f4fda20 1295static void
1296waklog_init (server_rec * s, MK_POOL * p)
1297{
1298 extern char *version;
1299 int pid;
1300 waklog_config *cfg;
1301 char *cell;
1302 int fd = -1;
1303 int use_existing = 1;
1304 int oldrenewcount;
1305 char cache_file[MAXNAMELEN];
1306#ifdef use_pthreads
1307 pthread_rwlockattr_t rwlock_attr;
ebb1f61c 1308#endif
7193eb01 1309
3f4fda20 1310 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 1311 "mod_waklog: version %s initialized.", version);
7193eb01 1312
3f4fda20 1313 if ( sharedspace ) {
1314 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: shared memory already allocated." );
1315 } else {
1316
1317 snprintf( cache_file, MAXNAMELEN, "/tmp/waklog_cache.%d", getpid() );
1318
1319 if ( ( fd = open( cache_file, O_RDWR, 0600 ) ) == -1 ) {
1320
1321 if ( errno == ENOENT ) {
1322
1323 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: creating shared token cache file %s", cache_file );
1324 use_existing = 0;
1325 if ( ( fd = open( cache_file, O_RDWR|O_CREAT|O_TRUNC, 0600 ) ) == -1 ) {
1326 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file, errno );
1327 exit(errno);
1328 }
1329 } else {
1330 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file, errno );
1331 }
1332
1333 }
1334
1335 if ( use_existing == 0 ) {
1336 struct sharedspace_s bob;
1337 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: sizing our cache file %d to %d", fd, sizeof(struct sharedspace_s) );
1338 memset( &bob, 0, sizeof(struct sharedspace_s));
1339 write(fd, &bob, sizeof(struct sharedspace_s));
1340 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s) );
1341 }
4e1ae1cd 1342
3f4fda20 1343 /* mmap the region */
1344
1345 if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != -1 ) {
1346 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared mmap region ok %d", sharedspace );
1347 close(fd);
1348 } else {
1349 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: mmap failed %d", errno );
1350 exit(errno);
1351 }
1352 }
e21f34f0 1353
3f4fda20 1354#ifdef use_pthreads
1355#define locktype pthread_rwlock_t
1356#else
1357#define locktype rwlock_t
ea3e8708 1358#endif
e21f34f0 1359
3f4fda20 1360 /* mmap our shared space for our lock */
1361 if ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) {
1362#ifndef use_pthreads
1363 rwlock_init(sharedlock, USYNC_PROCESS, NULL );
1364#else
1365 pthread_rwlockattr_init(&rwlock_attr);
1366 pthread_rwlockattr_setpshared(&rwlock_attr, PTHREAD_PROCESS_SHARED);
1367 pthread_rwlock_init(sharedlock, &rwlock_attr );
1368#endif
1369 } else {
1370 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: rwlock mmap failed %d", errno );
1371 }
e21f34f0 1372
3f4fda20 1373#undef locktype
e21f34f0 1374
3f4fda20 1375 /* set our default tokens */
1376
1377 getModConfig (cfg, s);
42d78dfb 1378
1379 oldrenewcount = sharedspace->renewcount;
1380
1381 pag_for_children = 0;
1382
1383 pid = ap_bspawn_child (p, waklog_child_routine, s, kill_always,
1384 NULL, NULL, NULL);
1385
1386 pag_for_children = 1;
1387
3f4fda20 1388 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 1389 "mod_waklog: ap_bspawn_child: %d.", pid);
3f4fda20 1390
1391 if ( use_existing == 0 ) {
1392 /* wait here until our child process has gone and done it's renewing thing. */
1393 while( sharedspace->renewcount == oldrenewcount ) {
1394 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: waiting for tokens..." );
1395 sleep(2);
87822447 1396 }
3f4fda20 1397 }
1398
1399 if ( cfg->default_principal ) {
1400 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1401 }
1402
87822447 1403}
3f4fda20 1404#endif
1405
1406static int
1407waklog_phase0 (request_rec * r)
e21f34f0 1408{
3f4fda20 1409 waklog_config *cfg;
e21f34f0 1410
3f4fda20 1411 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1412 "mod_waklog: phase0 called");
3f4fda20 1413
1414 cfg = retrieve_config(r);
e21f34f0 1415
3f4fda20 1416 if ( cfg->protect && cfg->principal ) {
1417 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 using user %s", cfg->principal);
1418 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1419 } else if ( cfg->default_principal ) {
1420 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 using default user %s", cfg->default_principal);
1421 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1422 } else {
1423 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 not doing nothin.");
1424 }
e21f34f0 1425
3f4fda20 1426 return DECLINED;
e21f34f0 1427}
4e1ae1cd 1428
3f4fda20 1429static int
1430waklog_phase1 (request_rec * r)
bed98ff9 1431{
3f4fda20 1432 waklog_config *cfg;
313dde40 1433
3f4fda20 1434 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1435 "mod_waklog: phase1 called");
7193eb01 1436
3f4fda20 1437 cfg = retrieve_config(r);
313dde40 1438
3f4fda20 1439 if ( cfg->protect && cfg->principal ) {
1440 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 using user %s", cfg->principal);
1441 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1442 } else if ( cfg->default_principal ) {
1443 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 using default user %s", cfg->default_principal);
1444 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1445 } else {
1446 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 not doing nothin.");
1447 }
4e1ae1cd 1448
3f4fda20 1449 return DECLINED;
7193eb01 1450}
4e1ae1cd 1451
3f4fda20 1452static int
1453waklog_phase3 (request_rec * r)
7193eb01 1454{
3f4fda20 1455 waklog_config *cfg;
1e18ef7d 1456
3f4fda20 1457 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1458 "mod_waklog: phase 3 called");
1e18ef7d 1459
3f4fda20 1460 cfg = retrieve_config(r);
1461
1462 if ( cfg->protect && cfg->principal ) {
1463 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 using user %s", cfg->principal);
1464 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1465 } else if ( cfg->default_principal ) {
1466 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 using default user %s", cfg->default_principal);
1467 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1468 } else {
1469 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 not doing nothin.");
1470 }
1471
1472 return DECLINED;
1473}
bed98ff9 1474
3f4fda20 1475static int
1476waklog_phase6 (request_rec * r)
1477{
1478 waklog_config *cfg;
1479
1480 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1481 "mod_waklog: phase6 called");
3f4fda20 1482
1483 cfg = retrieve_config(r);
1484
1485 if ( cfg->protect && cfg->principal ) {
1486 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 using user %s", cfg->principal);
1487 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1488 } else if ( cfg->default_principal ) {
1489 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 using default user %s", cfg->default_principal);
1490 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1491 } else {
1492 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 not doing nothin.");
1493 }
1494
1495 return DECLINED;
1496}
bed98ff9 1497
3f4fda20 1498static int
1499waklog_phase7 (request_rec * r)
1500{
1501 waklog_config *cfg;
1502 int rc = 0;
1503
1504 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1505 "mod_waklog: phase7 called");
3f4fda20 1506
1507 cfg = retrieve_config (r);
1508
1509 if ( cfg->protect && cfg->usertokens ) {
1510 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using usertokens");
1511 rc = set_auth( r->server, r, 1, NULL, NULL, 0);
1512 } else if ( cfg->protect && cfg->principal ) {
1513 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using user %s", cfg->principal);
1514 rc = set_auth( r->server, r, 0, cfg->principal, cfg->keytab, 0);
1515 } else if ( cfg->default_principal ) {
1516 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using default user %s", cfg->default_principal);
1517 rc = set_auth( r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1518 }
1519
1520 if ( rc ) {
1521 return 400;
1522 }
1523
1524 return DECLINED;
1525}
87822447 1526
3f4fda20 1527static int
1528waklog_phase9 (request_rec * r)
1529{
1530 waklog_config *cfg;
bed98ff9 1531
3f4fda20 1532 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1533 "mod_waklog: phase9 called");
bed98ff9 1534
3f4fda20 1535 getModConfig (cfg, r->server);
1536
1537 if ( cfg->default_principal ) {
1538 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase9 using default user %s", cfg->default_principal);
1539 set_auth( r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1540 }
1541
1542 return DECLINED;
bed98ff9 1543}
1544
ff47641b 1545
87822447 1546static
c9d59a9c 1547#ifdef APACHE2
ff47641b 1548 int
87822447 1549#else
ff47641b 1550 void
87822447 1551#endif
ff47641b 1552waklog_new_connection (conn_rec * c
c9d59a9c 1553#ifdef APACHE2
42d78dfb 1554 , void *dummy
87822447 1555#endif
ff47641b 1556 )
1557{
1558
3f4fda20 1559 waklog_config *cfg;
ff47641b 1560
1561 log_error (APLOG_MARK, APLOG_DEBUG, 0, c->base_server,
42d78dfb 1562 "mod_waklog: new_connection called: pid: %d", getpid ());
1563
1564 getModConfig(cfg, c->base_server);
1565
1566 if ( cfg->default_principal ) {
1567 log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "mod_waklog: new conn setting default user %s",
1568 cfg->default_principal);
1569 set_auth( c->base_server, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1570 }
1571
1572
3f4fda20 1573 return
c9d59a9c 1574#ifdef APACHE2
3f4fda20 1575 0
87822447 1576#endif
3f4fda20 1577 ;
7193eb01 1578}
bed98ff9 1579
c4ad0387 1580
1196adfe 1581/*
1582** Here's a quick explaination for phase0 and phase2:
1583** Apache does a stat() on the path between phase0 and
1584** phase2, and must by ACLed rl to succeed. So, at
1585** phase0 we acquire credentials for umweb:servers from
1586** a keytab, and at phase2 we must ensure we remove them.
1587**
1588** Failure to "unlog" would be a security risk.
1589*/
ff47641b 1590static int
1591waklog_phase2 (request_rec * r)
c4ad0387 1592{
161ffd84 1593
ff47641b 1594 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1595 "mod_waklog: phase2 called");
1196adfe 1596
ff47641b 1597 if (child.token.ticketLen)
1598 {
1599 memset (&child.token, 0, sizeof (struct ktc_token));
c4ad0387 1600
ff47641b 1601 ktc_ForgetAllTokens ();
c4ad0387 1602
ff47641b 1603 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1604 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1605 getpid ());
c4ad0387 1606 }
1196adfe 1607
ff47641b 1608 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1609 "mod_waklog: phase2 returning");
1196adfe 1610
3f4fda20 1611 return DECLINED;
c4ad0387 1612}
1613
c9d59a9c 1614#ifndef APACHE2
313dde40 1615module MODULE_VAR_EXPORT waklog_module = {
3f4fda20 1616 STANDARD_MODULE_STUFF,
866ccfbd 1617 waklog_init, /* module initializer */
42d78dfb 1618 waklog_create_dir_config, /* create per-dir config structures */
866ccfbd 1619 waklog_merge_dir_config, /* merge per-dir config structures */
1620 waklog_create_server_config, /* create per-server config structures */
1621 waklog_merge_dir_config, /* merge per-server config structures */
1622 waklog_cmds, /* table of config file commands */
1623 NULL, /* [#8] MIME-typed-dispatched handlers */
1624 waklog_phase1, /* [#1] URI to filename translation */
1625 NULL, /* [#4] validate user id from request */
1626 NULL, /* [#5] check if the user is ok _here_ */
1627 waklog_phase3, /* [#3] check access by host address */
1628 waklog_phase6, /* [#6] determine MIME type */
1629 waklog_phase7, /* [#7] pre-run fixups */
1630 waklog_phase9, /* [#9] log a transaction */
1631 NULL, /* [#2] header parser */
1632 waklog_child_init, /* child_init */
1633 waklog_child_exit, /* child_exit */
1634 waklog_phase0 /* [#0] post read-request */
bed98ff9 1635#ifdef EAPI
866ccfbd 1636 , NULL, /* EAPI: add_module */
1637 NULL, /* EAPI: remove_module */
1638 NULL, /* EAPI: rewrite_command */
1639 waklog_new_connection /* EAPI: new_connection */
bed98ff9 1640#endif
1641};
87822447 1642#else
1643static void
ff47641b 1644waklog_register_hooks (apr_pool_t * p)
87822447 1645{
3f4fda20 1646 ap_hook_translate_name (waklog_phase1, NULL, NULL, APR_HOOK_FIRST);
ff47641b 1647 ap_hook_header_parser (waklog_phase2, NULL, NULL, APR_HOOK_FIRST);
3f4fda20 1648 ap_hook_access_checker (waklog_phase3, NULL, NULL, APR_HOOK_FIRST);
1649 ap_hook_type_checker (waklog_phase6, NULL, NULL, APR_HOOK_FIRST);
ff47641b 1650 ap_hook_fixups (waklog_phase7, NULL, NULL, APR_HOOK_FIRST);
3f4fda20 1651 ap_hook_log_transaction (waklog_phase9, NULL, NULL, APR_HOOK_FIRST);
ff47641b 1652 ap_hook_child_init (waklog_child_init, NULL, NULL, APR_HOOK_FIRST);
1653 ap_hook_post_read_request (waklog_phase0, NULL, NULL, APR_HOOK_FIRST);
1654 ap_hook_pre_connection (waklog_new_connection, NULL, NULL, APR_HOOK_FIRST);
1655 ap_hook_post_config (waklog_init_handler, NULL, NULL, APR_HOOK_MIDDLE);
87822447 1656}
1657
1658
3f4fda20 1659module AP_MODULE_DECLARE_DATA waklog_module = {
1660 STANDARD20_MODULE_STUFF,
42d78dfb 1661 waklog_create_dir_config, /* create per-dir conf structures */
1662 waklog_merge_dir_config, /* merge per-dir conf structures */
1663 waklog_create_server_config, /* create per-server conf structures */
1664 waklog_merge_dir_config, /* merge per-server conf structures */
1665 waklog_cmds, /* table of configuration directives */
1666 waklog_register_hooks /* register hooks */
87822447 1667};
1668#endif