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