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