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