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