nuke hardwired AFS_CELL lameness
[hcoop/debian/libapache-mod-waklog.git] / mod_waklog.c
CommitLineData
87822447 1#define _LARGEFILE64_SOURCE
ff47641b 2#define _GNU_SOURCE
87822447 3
bed98ff9 4#include "httpd.h"
5#include "http_config.h"
bed98ff9 6#include "http_log.h"
7193eb01 7#include "http_protocol.h"
8#include "http_request.h"
9#include "http_core.h"
87822447 10
ff47641b 11#ifdef sun
12#include <synch.h>
13#elif linux
14#define use_pthreads
15#include <features.h>
16#include <sys/types.h>
17#include <sys/mman.h>
18#include <pthread.h>
19#else
20#error "make sure you include the right stuff here"
21#endif
22
23#ifndef MAXNAMELEN
24#define MAXNAMELEN 1024
25#endif
26
891fb458 27#ifdef STANDARD20_MODULE_STUFF
c9d59a9c 28#define APACHE2
29#endif
30
31/********************* APACHE1 ******************************************************************************/
32#ifndef APACHE2
ebb1f61c 33#include "ap_config.h"
34#if defined(sun)
35#include <sys/ioccom.h>
36#endif /* sun */
37#include <http_conf_globals.h>
38#define MK_POOL pool
39#define MK_TABLE_GET ap_table_get
40#define MK_TABLE_SET ap_table_set
41#define command(name, func, var, type, usage) \
42 { name, func, \
43 NULL , \
44 RSRC_CONF | ACCESS_CONF , type, usage }
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/* 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
c9d59a9c 205#ifdef APACHE2
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
c9d59a9c 298#ifdef APACHE2
3f4fda20 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
891fb458 491 if (cell_in_principal) {
3f4fda20 492 strncat(buf, "/", sizeof(buf) - strlen(buf) - 1);
493 strncat(buf, cfg->afs_cell, sizeof(buf) - strlen(buf) - 1);
3f4fda20 494 }
313dde40 495
3f4fda20 496 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: using AFS principal: %s", buf);
497
498 if ((kerror = krb5_parse_name (child.kcontext, buf, &increds.server))) {
499 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_parse name %s", error_message(kerror));
500 goto cleanup;
501 }
502
503 if ((kerror = krb5_cc_get_principal(child.kcontext, child.ccache, &increds.client))) {
504 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_cc_get_princ %s", error_message(kerror));
505 goto cleanup;
506 }
507
508 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: retrieved data from ccache for %s", k5user);
509
510 increds.times.endtime = 0;
511
512 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
513
514 if (kerror = krb5_get_credentials (child.kcontext, 0, child.ccache, &increds, &v5credsp )) {
515 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_credentials: %s",
516 error_message(kerror));
517 goto cleanup;
518 }
519
520 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: get_credentials passed for %s", k5user);
521
522 if ( v5credsp->ticket.length >= MAXKTCTICKETLEN ) {
523 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: ticket size (%d) too big to fake",
524 v5credsp->ticket.length);
525 goto cleanup;
526 }
313dde40 527
3f4fda20 528 memset(&token, 0, sizeof(struct ktc_token));
529
530 token.startTime = v5credsp->times.starttime ? v5credsp->times.starttime : v5credsp->times.authtime;
531 token.endTime = v5credsp->times.endtime;
532
533 memmove( &token.sessionKey, v5credsp->keyblock.contents, v5credsp->keyblock.length);
534 token.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
535 token.ticketLen = v5credsp->ticket.length;
536 memmove( token.ticket, v5credsp->ticket.data, token.ticketLen);
537
538 /* build the name */
539
540 memmove( buf, v5credsp->client->data[0].data, min(v5credsp->client->data[0].length,
541 MAXKTCNAMELEN -1 ));
542 buf[v5credsp->client->data[0].length] = '\0';
543 if ( v5credsp->client->length > 1 ) {
544 strncat(buf, ".", sizeof(buf) - strlen(buf) - 1);
545 buflen = strlen(buf);
546 memmove(buf + buflen, v5credsp->client->data[1].data,
547 min(v5credsp->client->data[1].length,
548 MAXKTCNAMELEN - strlen(buf) - 1));
549 buf[buflen + v5credsp->client->data[1].length] = '\0';
550 }
551
552 /* assemble the client */
553 strncpy(client.name, buf, sizeof(client.name) - 1 );
554 strncpy(client.instance, "", sizeof(client.instance) - 1 );
555 memmove(buf, v5credsp->client->realm.data, min(v5credsp->client->realm.length,
556 MAXKTCNAMELEN - 1));
557 buf[v5credsp->client->realm.length] = '\0';
558 strncpy(client.cell, buf, sizeof(client.cell));
559
560 /* assemble the server's cell */
891fb458 561 strncpy(server.cell, cfg->afs_cell, sizeof(server.cell) - 1);
3f4fda20 562
563 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: preparing to init PTS connection for %s", server.cell);
564
565 /* fill out the AFS ID in the client name */
566 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
567 * strange things seem to happen. */
568
569 {
570 afs_int32 viceId = 0;
571
572 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: making PTS call to look up %s", client.name);
573
574 if ( ( rc = pr_SNameToId( client.name, &viceId ) ) == 0 ) {
575 snprintf( client.name, sizeof(client.name), "AFS ID %d", viceId );
576 } else {
577 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: PTS call returned error %d ", rc);
578 }
579
580 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: PTS call returned %s ", client.name);
581
582 }
583
584 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: server: name %s, instance %s, cell %s",
585 server.name, server.instance, server.cell );
586
587 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: client: name %s, instance %s, cell %s",
588 client.name, client.instance, client.cell );
589
590 /* copy the resulting stuff into the child structure */
591
592 strncpy(child.clientprincipal, k5user, sizeof(child.clientprincipal));
593 memcpy(&child.token, &token, sizeof(child.token));
594 memcpy(&child.server, &server, sizeof(child.server));
595 memcpy(&child.client, &client, sizeof(child.client));
596
597 /* stuff the resulting token-related stuff into our shared token cache */
598 /* note, that anything that was set from a keytab is "persistant", and is immune
599 * from LRU-aging. This is because nothing but the process that's running as root
600 * can update these, and it's running every hour or so and renewing these tokens.
601 * and we don't want them aged out.
602 */
603
604 mytime = oldest_time = time(0);
605
606 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: waiting for shared space for %s ", k5user);
4e1ae1cd 607
3f4fda20 608#ifdef use_pthreads
609 pthread_rwlock_wrlock(sharedlock);
610#else
611 rw_wrlock(sharedlock);
612#endif
4e1ae1cd 613
3f4fda20 614 for( i = ( SHARED_TABLE_SIZE - 1 ); i >= 0; i-- ) {
615 if ( ( sharedspace->sharedtokens[i].lastused <= oldest_time) &&
616 ( sharedspace->sharedtokens[i].persist == 0 ) ) {
617 oldest = i;
618 oldest_time = sharedspace->sharedtokens[i].lastused;
619 }
620 if ( ! strcmp ( sharedspace->sharedtokens[i].clientprincipal,
621 child.clientprincipal ) ) {
622 memcpy(&sharedspace->sharedtokens[i].token, &child.token, sizeof(child.token) );
623 memcpy(&sharedspace->sharedtokens[i].client, &child.client, sizeof(child.client) );
624 memcpy(&sharedspace->sharedtokens[i].server, &child.server, sizeof(child.server) );
625 sharedspace->sharedtokens[i].lastused = mytime;
626 sharedspace->sharedtokens[i].persist = keytab ? 1 : 0;
627 stored = i;
628 break;
629 }
630 }
631
632 if ( stored == -1 ) {
633 memcpy(&sharedspace->sharedtokens[oldest].token, &child.token, sizeof(child.token) );
634 memcpy(&sharedspace->sharedtokens[oldest].client, &child.client, sizeof(child.client) );
635 memcpy(&sharedspace->sharedtokens[oldest].server, &child.server, sizeof(child.server) );
636 strcpy(sharedspace->sharedtokens[oldest].clientprincipal, child.clientprincipal );
637 sharedspace->sharedtokens[oldest].lastused = mytime;
638 sharedspace->sharedtokens[oldest].persist = keytab ? 1 : 0;
639 stored = oldest;
640 }
3ed1e28a 641
3f4fda20 642#ifdef use_pthreads
643 pthread_rwlock_unlock(sharedlock);
644#else
645 rw_unlock(sharedlock);
646#endif
647
648 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: token stored in slot %d for %s", stored,
649 child.clientprincipal );
650
651 } else if ( ! usecached ) {
652 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth divergent case");
653 }
654
655 if ( storeonly ) {
656 goto cleanup;
657 }
658
659 usecachedtoken:
660
661 /* don't ask. Something about AIX. We're leaving it here.*/
662 /* write(2, "", 0); */
663
664 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
665
666 if ((rc = ktc_SetToken(&child.server, &child.token, &child.client, 0))) {
667 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: settoken returned %s for %s -- trying again",
668 error_message(rc), k5user);
669 if ((rc = ktc_SetToken(&child.server, &child.token, &child.client, 0))) {
670 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: settoken2 returned %s for %s",
671 error_message(rc), k5user);
672 goto cleanup;
673 }
674 }
675
676 cleanup:
677 if ( v5credsp )
678 krb5_free_cred_contents(child.kcontext, v5credsp);
679 if ( increds.client )
680 krb5_free_principal (child.kcontext, increds.client);
681 if ( increds.server )
682 krb5_free_principal (child.kcontext, increds.server);
683 if ( krb5kt )
684 (void) krb5_kt_close(child.kcontext, krb5kt);
685 if ( kprinc )
686 krb5_free_principal (child.kcontext, kprinc);
687
688 if ( rc ) {
689 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with %d", rc );
690 } else if ( kerror ) {
691 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror, error_message(kerror));
692 } else {
693 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth ending ok");
694 }
695
696 return kerror ? (int) kerror : (int) rc;
697
4e1ae1cd 698}
699
700
7193eb01 701
3f4fda20 702static void *
703waklog_create_server_config (MK_POOL * p, server_rec * s)
704{
705 waklog_config *cfg;
706
707 cfg = (waklog_config *) ap_pcalloc (p, sizeof (waklog_config));
708 cfg->p = p;
709 memset(cfg, 0, sizeof(waklog_config));
710 cfg->path = "(server)";
711 cfg->protect = WAKLOG_UNSET;
712 cfg->usertokens = WAKLOG_UNSET;
713 cfg->keytab = WAKLOG_UNSET;
714 cfg->principal = WAKLOG_UNSET;
715 cfg->default_principal = WAKLOG_UNSET;
716 cfg->default_keytab = WAKLOG_UNSET;
717 cfg->afs_cell = WAKLOG_UNSET;
718 cfg->forked = 0;
719 cfg->configured = 0;
720
721 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 722 "mod_waklog: server config created.");
3f4fda20 723
724 return (cfg);
725}
7193eb01 726
3f4fda20 727/* initialize with host-config information */
58bbdc54 728
3f4fda20 729static void *
730waklog_create_dir_config (MK_POOL * p, char *dir)
731{
732 waklog_config *cfg;
733
734 cfg = (waklog_config *) ap_pcalloc (p, sizeof (waklog_config));
735 memset(cfg, 0, sizeof(waklog_config));
736 cfg->p = p;
737 cfg->path = ap_pstrdup(p, dir );
738 cfg->protect = WAKLOG_UNSET;
739 cfg->usertokens = WAKLOG_UNSET;
740 cfg->keytab = WAKLOG_UNSET;
741 cfg->principal = WAKLOG_UNSET;
742 cfg->default_principal = WAKLOG_UNSET;
743 cfg->default_keytab = WAKLOG_UNSET;
744 cfg->afs_cell = WAKLOG_UNSET;
745 cfg->forked = 0;
746 cfg->configured = 0;
747
748 return (cfg);
58bbdc54 749}
750
3f4fda20 751static void *waklog_merge_dir_config(MK_POOL *p, void *parent_conf, void *newloc_conf) {
58bbdc54 752
3f4fda20 753 waklog_config *merged = ( waklog_config * ) ap_pcalloc(p, sizeof(waklog_config ) );
754 waklog_config *parent = ( waklog_config * ) parent_conf;
755 waklog_config *child = ( waklog_config * ) newloc_conf;
756
757 merged->protect = child->protect != WAKLOG_UNSET ? child->protect : parent->protect;
758
759 merged->path = child->path != WAKLOG_UNSET ? child->path : parent->path;
760
761 merged->usertokens = child->usertokens != WAKLOG_UNSET ? child->usertokens : parent->usertokens;
762
763 merged->principal = child->principal != WAKLOG_UNSET ? child->principal : parent->principal;
764
765 merged->keytab = child->keytab != WAKLOG_UNSET ? child->keytab : parent->keytab;
766
767 merged->default_keytab = child->default_keytab != WAKLOG_UNSET ? child->default_keytab : parent->default_keytab;
768
769 merged->default_principal = child->default_principal != WAKLOG_UNSET ? child->default_principal : parent->default_principal;
770
771 merged->afs_cell = child->afs_cell != WAKLOG_UNSET ? child->afs_cell : parent->afs_cell;
772
773 return (void *) merged;
774
775}
58bbdc54 776
3f4fda20 777static void *waklog_merge_server_config(MK_POOL *p, void *parent_conf, void *newloc_conf) {
58bbdc54 778
3f4fda20 779 waklog_config *merged = ( waklog_config * ) ap_pcalloc(p, sizeof(waklog_config ) );
780 waklog_config *pconf = ( waklog_config * ) parent_conf;
781 waklog_config *nconf = ( waklog_config * ) newloc_conf;
782
783 merged->protect = nconf->protect == WAKLOG_UNSET ? pconf->protect : nconf->protect;
58bbdc54 784
3f4fda20 785 merged->usertokens = nconf->usertokens == WAKLOG_UNSET ? pconf->usertokens : nconf->usertokens;
58bbdc54 786
3f4fda20 787 merged->keytab = nconf->keytab == WAKLOG_UNSET ? ap_pstrdup(p, pconf->keytab) :
788 ( nconf->keytab == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->keytab) );
789
790 merged->principal = nconf->principal == WAKLOG_UNSET ? ap_pstrdup(p, pconf->principal) :
791 ( nconf->principal == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->principal) );
792
793 merged->afs_cell = nconf->afs_cell == WAKLOG_UNSET ? ap_pstrdup(p, pconf->afs_cell) :
794 ( nconf->afs_cell == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->afs_cell) );
795
796 merged->default_keytab = nconf->default_keytab == WAKLOG_UNSET ? ap_pstrdup(p, pconf->default_keytab) :
797 ( nconf->default_keytab == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->default_keytab) );
58bbdc54 798
3f4fda20 799 merged->default_principal = nconf->default_principal == WAKLOG_UNSET ? ap_pstrdup(p, pconf->default_principal) :
800 ( nconf->default_principal == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->default_principal) );
801
802
803 return (void *) merged;
804
805}
806
807static const char *
808set_waklog_protect (cmd_parms * params, void *mconfig, int flag)
58bbdc54 809{
3f4fda20 810 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
811 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
812
813 cfg->protect = flag;
814 cfg->configured = 1;
815 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
42d78dfb 816 "mod_waklog: waklog_protect set on %s", cfg->path ? cfg->path : "NULL");
3f4fda20 817 return (NULL);
818}
58bbdc54 819
7193eb01 820
3f4fda20 821/* this adds a principal/keytab pair to get their tokens renewed by the
822 child process every few centons. */
7193eb01 823
3f4fda20 824void add_to_renewtable(MK_POOL *p, char *keytab, char *principal) {
87822447 825
3f4fda20 826 int i;
827
828 if ( renewcount >= SHARED_TABLE_SIZE ) {
829 log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
830 decrease your tokens.");
b74fad73 831 return;
3f4fda20 832 }
833
834 /* check to see if it's already there */
835
836 for ( i = 0; i < renewcount; i++ ) {
837 if ( ! strcmp(renewtable[i].principal, principal ) ) {
838 return;
839 }
840 }
841
842 renewtable[renewcount].keytab = ap_pstrdup(p, keytab);
843 renewtable[renewcount].principal = ap_pstrdup(p, principal);
844 renewtable[renewcount].lastrenewed = 0;
845 ++renewcount;
846
b74fad73 847}
848
3f4fda20 849static const char *
850set_waklog_principal (cmd_parms *params, void *mconfig, char *principal, char *keytab)
851{
852 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
853 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
854
855 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
42d78dfb 856 "mod_waklog: configuring principal: %s, keytab: %s", principal, keytab);
857
858 cfg->principal = ap_pstrdup(params->pool, principal);
3f4fda20 859 cfg->keytab = ap_pstrdup (params->pool, keytab);
860
861 add_to_renewtable(params->pool, keytab, principal);
862
863 cfg->configured = 1;
864
865 return (NULL);
866}
b74fad73 867
3f4fda20 868static const char *
869set_waklog_use_afs_cell (cmd_parms * params, void *mconfig, char *file)
313dde40 870{
891fb458 871 waklog_config *waklog_mconfig = ( waklog_config * ) mconfig;
872 waklog_config *waklog_srvconfig =
3f4fda20 873 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
874
891fb458 875 log_error (APLOG_MARK, APLOG_INFO, 0, params->server,
42d78dfb 876 "mod_waklog: will use afs_cell: %s", file);
313dde40 877
891fb458 878 waklog_srvconfig->afs_cell = ap_pstrdup (params->pool, file);
879 waklog_srvconfig->configured = 1;
880
881 if (waklog_mconfig != NULL) {
882 waklog_mconfig->afs_cell = ap_pstrdup (params->pool, file);
883 waklog_mconfig->configured = 1;
884 }
3f4fda20 885 return (NULL);
886}
58bbdc54 887
3f4fda20 888static const char *
889set_waklog_default_principal (cmd_parms * params, void *mconfig, char *principal, char *keytab)
890{
891 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
892 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
58bbdc54 893
3f4fda20 894 waklog_config *srvcfg = ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
4e1ae1cd 895
3f4fda20 896 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
42d78dfb 897 "mod_waklog: set default princ/keytab: %s, %s for %s", principal, keytab, cfg->path ? cfg->path : "NULL");
313dde40 898
3f4fda20 899 cfg->default_principal = ap_pstrdup (params->pool, principal);
900 cfg->default_keytab = ap_pstrdup(params->pool, keytab );
901
902 /* this also gets set at the server level */
903 if ( mconfig && ( ! cfg->path ) ) {
904 srvcfg->default_principal = ap_pstrdup (params->pool, principal);
905 srvcfg->default_keytab = ap_pstrdup(params->pool, keytab );
906 } else {
907 log_error(APLOG_MARK, APLOG_ERR, 0, params->server, "only able to set default principal on a global level!");
908 return "Unable to set DefaultPrincipal outside of top level config!";
909 }
910
911 add_to_renewtable( params->pool, keytab, principal );
912
913 cfg->configured = 1;
914
915 return (NULL);
916}
313dde40 917
3f4fda20 918static const char *
919set_waklog_use_usertokens (cmd_parms * params, void *mconfig, int flag)
bed98ff9 920{
3f4fda20 921 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
922 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
bed98ff9 923
3f4fda20 924 cfg->usertokens = flag;
bed98ff9 925
3f4fda20 926 cfg->configured = 1;
bed98ff9 927
3f4fda20 928 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
42d78dfb 929 "mod_waklog: waklog_use_user_tokens set");
3f4fda20 930 return (NULL);
bed98ff9 931}
932
933
c9d59a9c 934#ifndef APACHE2
3f4fda20 935static void waklog_child_exit( server_rec *s, MK_POOL *p ) {
936#else
937apr_status_t waklog_child_exit( void *sr ) {
4e1ae1cd 938
3f4fda20 939 server_rec *s = (server_rec *) sr;
940#endif
941
942 if ( child.ccache ) {
943 krb5_cc_close(child.kcontext, child.ccache);
944 }
945
946 if ( child.kcontext ) {
947 krb5_free_context(child.kcontext);
948 }
949
950 /* forget our tokens */
951
952 ktc_ForgetAllTokens ();
953
954 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 955 "mod_waklog: waklog_child_exit complete");
4e1ae1cd 956
c9d59a9c 957#ifdef APACHE2
3f4fda20 958 return APR_SUCCESS;
959#endif
960
961}
4e1ae1cd 962
3f4fda20 963static void
c9d59a9c 964#ifdef APACHE2
3f4fda20 965waklog_child_init (MK_POOL * p, server_rec * s)
966#else
967waklog_child_init (server_rec * s, MK_POOL * p)
968#endif
969{
b52ccbb1 970
3f4fda20 971 krb5_error_code code;
972 waklog_config *cfg;
973
974 char *cell;
975
3f4fda20 976 log_error (APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init called for pid %d", getpid());
977
978 if ( !sharedspace ) {
979 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: child_init called without shared space? %d", getpid());
980 return;
981 }
982
983 log_error (APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init called for pid %d", getpid());
7193eb01 984
3f4fda20 985 memset (&child, 0, sizeof(child));
986
987 if ( code = krb5_init_context(&child.kcontext) ) {
988 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't init kerberos context %d", code );
989 }
990
991 if ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) {
992 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", code );
993 }
994
995 if ( pag_for_children ) {
996 setpag ();
997 }
7193eb01 998
3f4fda20 999 getModConfig (cfg, s);
7193eb01 1000
3f4fda20 1001 if ( cfg->default_principal != WAKLOG_UNSET ) {
1002 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init setting default user %s, %s", cfg->default_principal, cfg->default_keytab);
1003 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1004 }
7193eb01 1005
891fb458 1006 cell = strdup(cfg->afs_cell);
3f4fda20 1007 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR, cell );
7193eb01 1008
c9d59a9c 1009#ifdef APACHE2
3f4fda20 1010 apr_pool_cleanup_register(p, s, waklog_child_exit, apr_pool_cleanup_null);
1011#endif
7193eb01 1012
3f4fda20 1013 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 1014 "mod_waklog: child_init returned");
7193eb01 1015
3f4fda20 1016 return;
1017}
b52ccbb1 1018
3f4fda20 1019command_rec waklog_cmds[] = {
1020
1021 command ("WaklogProtected", set_waklog_protect, 0, FLAG,
42d78dfb 1022 "enable waklog on a location or directory basis"),
7193eb01 1023
3f4fda20 1024 command ("WaklogPrincipal", set_waklog_principal, 0, TAKE2,
42d78dfb 1025 "Use the supplied keytab rather than the default"),
7193eb01 1026
3f4fda20 1027 command ("WaklogUseAFSCell", set_waklog_use_afs_cell, 0, TAKE1,
42d78dfb 1028 "Use the supplied AFS cell rather than the default"),
7193eb01 1029
3f4fda20 1030 command ("WaklogUseUserTokens", set_waklog_use_usertokens, 0, FLAG,
1031 "Use the requesting user tokens (from webauth)"),
7193eb01 1032
3f4fda20 1033 command ("WaklogDefaultPrincipal", set_waklog_default_principal, 0, TAKE2,
1034 "Set the default principal that the server runs as"),
1035
1036 {NULL}
1037};
7193eb01 1038
7193eb01 1039
3f4fda20 1040/* not currently using this */
7193eb01 1041
3f4fda20 1042static int
1043token_cleanup (void *data)
1044{
1045 request_rec *r = (request_rec *) data;
e2df6441 1046
3f4fda20 1047 if (child.token.ticketLen)
1048 {
1049 memset (&child.token, 0, sizeof (struct ktc_token));
e21f34f0 1050
3f4fda20 1051 ktc_ForgetAllTokens ();
7193eb01 1052
3f4fda20 1053 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1054 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1055 getpid ());
3f4fda20 1056 }
1057 return 0;
7193eb01 1058}
1059
3f4fda20 1060static int
1061waklog_child_routine (void *data, child_info * pinfo)
7193eb01 1062{
3f4fda20 1063 int i;
1064 server_rec *s = (server_rec *) data;
1065 krb5_error_code code;
1066 char *cell;
1067 time_t sleep_time = ( TKT_LIFE / 2 ) ;
1068 time_t when;
1069 time_t left;
1070 waklog_config *cfg;
1071
1072 getModConfig( cfg, s );
1073
1074 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1075
1076 memset (&child, 0, sizeof(child));
1077
1078 if ( code = krb5_init_context(&child.kcontext) ) {
1079 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't init kerberos context %d", code );
1080 }
1081
1082 if ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) {
1083 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", code );
1084 }
1085
1086 /* need to do this so we can make PTS calls */
891fb458 1087 cell = strdup(cfg->afs_cell); /* stupid */
3f4fda20 1088 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR, cell );
1089
1090 while(1) {
1091
1092 for ( i = 0; i < renewcount; ++i ) {
1093 renewtable[i].lastrenewed = time(0);
1094 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable[i].principal,
1095 renewtable[i].keytab);
1096
1097 set_auth( s, NULL, 0, renewtable[i].principal, renewtable[i].keytab, 1 );
1098
1099 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1100 things that it needs to read */
1101
1102 if ( cfg && cfg->default_principal && ( ! strcmp(cfg->default_principal, renewtable[i].principal ) ) ) {
1103 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: renewing/setting default tokens" );
1104 set_auth( s, NULL, 0, renewtable[i].principal, renewtable[i].keytab, 0 );
1105 }
1106
4e1ae1cd 1107 }
1108
3f4fda20 1109 sharedspace->renewcount++;
1110
1111 left = sleep_time;
1112
1113 while( left > 5 ) {
1114 when = time(0);
1115
1116 sleep(left);
1117
1118 left -= ( time(0) - when );
4e1ae1cd 1119 }
3f4fda20 1120
1121 }
4e1ae1cd 1122
3f4fda20 1123 pr_End();
403921ef 1124
3f4fda20 1125}
4e1ae1cd 1126
c9d59a9c 1127#ifdef APACHE2
3f4fda20 1128static int
1129waklog_init_handler (apr_pool_t * p, apr_pool_t * plog,
42d78dfb 1130 apr_pool_t * ptemp, server_rec * s)
3f4fda20 1131{
1132 int rv;
1133 extern char *version;
1134 apr_proc_t *proc;
1135 waklog_config *cfg;
1136 void *data;
1137 int fd = -1;
1138 int use_existing = 1;
1139 int oldrenewcount;
1140 char cache_file[MAXNAMELEN];
1141#ifdef use_pthreads
1142 pthread_rwlockattr_t rwlock_attr;
1143#endif
4e1ae1cd 1144
1145
3f4fda20 1146 getModConfig (cfg, s);
4e1ae1cd 1147
3f4fda20 1148 /* initialize_module() will be called twice, and if it's a DSO
1149 * then all static data from the first call will be lost. Only
1150 * set up our static data on the second call.
1151 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1152 apr_pool_userdata_get (&data, userdata_key, s->process->pool);
7193eb01 1153
891fb458 1154
1155 if (cfg->afs_cell==NULL) {
1156 log_error (APLOG_MARK, APLOG_ERR, 0, s,
1157 "mod_waklog: afs_cell==NULL; please provide the WaklogUseAFSCell directive");
1158 /** clobber apache */
1159 exit(-1);
1160 }
1161
3f4fda20 1162 if (!data)
1163 {
1164 apr_pool_userdata_set ((const void *) 1, userdata_key,
42d78dfb 1165 apr_pool_cleanup_null, s->process->pool);
4e1ae1cd 1166 }
3f4fda20 1167 else
1168 {
1169 log_error (APLOG_MARK, APLOG_INFO, 0, s,
891fb458 1170 "mod_waklog: version %s initialized for cell %s", version, cfg->afs_cell);
3f4fda20 1171
1172 if ( sharedspace ) {
1173 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: shared memory already allocated." );
1174 } else {
1175
1176 snprintf( cache_file, MAXNAMELEN, "/tmp/waklog_cache.%d", getpid() );
1177
1178 if ( ( fd = open( cache_file, O_RDWR, 0600 ) ) == -1 ) {
1179
1180 if ( errno == ENOENT ) {
1181
1182 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: creating shared token cache file %s", cache_file );
1183 use_existing = 0;
1184 if ( ( fd = open( cache_file, O_RDWR|O_CREAT|O_TRUNC, 0600 ) ) == -1 ) {
1185 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file, errno );
1186 exit(errno);
1187 }
1188 } else {
1189 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file, errno );
1190 }
1191 }
1192
1193 if ( use_existing == 0 ) {
1194 struct sharedspace_s bob;
1195 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: sizing our cache file %d to %d", fd, sizeof(struct sharedspace_s) );
1196 memset( &bob, 0, sizeof(struct sharedspace_s));
1197 write(fd, &bob, sizeof(struct sharedspace_s));
1198 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s) );
1199 }
1200
1201 /* mmap the region */
1202
1203 if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != MAP_FAILED ) {
1204 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared mmap region ok %d", sharedspace );
1205 close(fd);
1206 } else {
1207 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: mmap failed %d", errno );
1208 exit(errno);
1209 }
1210 }
4e1ae1cd 1211
3f4fda20 1212#ifdef use_pthreads
1213#define locktype pthread_rwlock_t
1214#else
1215#define locktype rwlock_t
1216#endif
4e1ae1cd 1217
3f4fda20 1218 if ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) {
1219#ifndef use_pthreads
1220 rwlock_init(sharedlock, USYNC_PROCESS, NULL );
1221#else
1222 pthread_rwlockattr_init(&rwlock_attr);
1223 pthread_rwlockattr_setpshared(&rwlock_attr, PTHREAD_PROCESS_SHARED);
1224 pthread_rwlock_init(sharedlock, &rwlock_attr );
1225#endif
1226 } else {
1227 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: rwlock mmap failed %d", errno );
1228 }
58bbdc54 1229
3f4fda20 1230#undef locktype
7193eb01 1231
3f4fda20 1232 /* set our default tokens */
403921ef 1233
3f4fda20 1234 oldrenewcount = sharedspace->renewcount;
7193eb01 1235
3f4fda20 1236 pag_for_children = 0;
7193eb01 1237
3f4fda20 1238 proc = (apr_proc_t *) ap_pcalloc (s->process->pool, sizeof (apr_proc_t));
7193eb01 1239
3f4fda20 1240 rv = apr_proc_fork (proc, s->process->pool);
7193eb01 1241
3f4fda20 1242 if (rv == APR_INCHILD)
42d78dfb 1243 {
1244 waklog_child_routine (s, NULL);
1245 }
3f4fda20 1246 else
42d78dfb 1247 {
1248 apr_pool_note_subprocess (s->process->pool, proc, APR_KILL_ALWAYS);
1249 }
3f4fda20 1250 /* parent and child */
1251 cfg->forked = proc->pid;
1252 pag_for_children = 1;
1253
1254 if ( use_existing == 0 ) {
1255 /* wait here until our child process has gone and done it's renewing thing. */
1256 while( sharedspace->renewcount == oldrenewcount ) {
1257 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: waiting for tokens..." );
1258 sleep(2);
1259 }
1260 }
1261
1262 if ( cfg->default_principal ) {
1263 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1264 }
1265 }
1266 return 0;
1267}
ebb1f61c 1268#else
3f4fda20 1269static void
1270waklog_init (server_rec * s, MK_POOL * p)
1271{
1272 extern char *version;
1273 int pid;
1274 waklog_config *cfg;
1275 char *cell;
1276 int fd = -1;
1277 int use_existing = 1;
1278 int oldrenewcount;
1279 char cache_file[MAXNAMELEN];
1280#ifdef use_pthreads
1281 pthread_rwlockattr_t rwlock_attr;
ebb1f61c 1282#endif
7193eb01 1283
3f4fda20 1284 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 1285 "mod_waklog: version %s initialized.", version);
7193eb01 1286
3f4fda20 1287 if ( sharedspace ) {
1288 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: shared memory already allocated." );
1289 } else {
1290
1291 snprintf( cache_file, MAXNAMELEN, "/tmp/waklog_cache.%d", getpid() );
1292
1293 if ( ( fd = open( cache_file, O_RDWR, 0600 ) ) == -1 ) {
1294
1295 if ( errno == ENOENT ) {
1296
1297 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: creating shared token cache file %s", cache_file );
1298 use_existing = 0;
1299 if ( ( fd = open( cache_file, O_RDWR|O_CREAT|O_TRUNC, 0600 ) ) == -1 ) {
1300 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file, errno );
1301 exit(errno);
1302 }
1303 } else {
1304 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file, errno );
1305 }
1306
1307 }
1308
1309 if ( use_existing == 0 ) {
1310 struct sharedspace_s bob;
1311 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: sizing our cache file %d to %d", fd, sizeof(struct sharedspace_s) );
1312 memset( &bob, 0, sizeof(struct sharedspace_s));
1313 write(fd, &bob, sizeof(struct sharedspace_s));
1314 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s) );
1315 }
4e1ae1cd 1316
3f4fda20 1317 /* mmap the region */
1318
1319 if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != -1 ) {
1320 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared mmap region ok %d", sharedspace );
1321 close(fd);
1322 } else {
1323 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: mmap failed %d", errno );
1324 exit(errno);
1325 }
1326 }
e21f34f0 1327
3f4fda20 1328#ifdef use_pthreads
1329#define locktype pthread_rwlock_t
1330#else
1331#define locktype rwlock_t
ea3e8708 1332#endif
e21f34f0 1333
3f4fda20 1334 /* mmap our shared space for our lock */
1335 if ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) {
1336#ifndef use_pthreads
1337 rwlock_init(sharedlock, USYNC_PROCESS, NULL );
1338#else
1339 pthread_rwlockattr_init(&rwlock_attr);
1340 pthread_rwlockattr_setpshared(&rwlock_attr, PTHREAD_PROCESS_SHARED);
1341 pthread_rwlock_init(sharedlock, &rwlock_attr );
1342#endif
1343 } else {
1344 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: rwlock mmap failed %d", errno );
1345 }
e21f34f0 1346
3f4fda20 1347#undef locktype
e21f34f0 1348
3f4fda20 1349 /* set our default tokens */
1350
1351 getModConfig (cfg, s);
42d78dfb 1352
1353 oldrenewcount = sharedspace->renewcount;
1354
1355 pag_for_children = 0;
1356
1357 pid = ap_bspawn_child (p, waklog_child_routine, s, kill_always,
1358 NULL, NULL, NULL);
1359
1360 pag_for_children = 1;
1361
3f4fda20 1362 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
42d78dfb 1363 "mod_waklog: ap_bspawn_child: %d.", pid);
3f4fda20 1364
1365 if ( use_existing == 0 ) {
1366 /* wait here until our child process has gone and done it's renewing thing. */
1367 while( sharedspace->renewcount == oldrenewcount ) {
1368 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: waiting for tokens..." );
1369 sleep(2);
87822447 1370 }
3f4fda20 1371 }
1372
1373 if ( cfg->default_principal ) {
1374 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1375 }
1376
87822447 1377}
3f4fda20 1378#endif
1379
1380static int
1381waklog_phase0 (request_rec * r)
e21f34f0 1382{
3f4fda20 1383 waklog_config *cfg;
e21f34f0 1384
3f4fda20 1385 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1386 "mod_waklog: phase0 called");
3f4fda20 1387
1388 cfg = retrieve_config(r);
e21f34f0 1389
3f4fda20 1390 if ( cfg->protect && cfg->principal ) {
1391 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 using user %s", cfg->principal);
1392 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1393 } else if ( cfg->default_principal ) {
1394 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 using default user %s", cfg->default_principal);
1395 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1396 } else {
1397 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 not doing nothin.");
1398 }
e21f34f0 1399
3f4fda20 1400 return DECLINED;
e21f34f0 1401}
4e1ae1cd 1402
3f4fda20 1403static int
1404waklog_phase1 (request_rec * r)
bed98ff9 1405{
3f4fda20 1406 waklog_config *cfg;
313dde40 1407
3f4fda20 1408 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1409 "mod_waklog: phase1 called");
7193eb01 1410
3f4fda20 1411 cfg = retrieve_config(r);
313dde40 1412
3f4fda20 1413 if ( cfg->protect && cfg->principal ) {
1414 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 using user %s", cfg->principal);
1415 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1416 } else if ( cfg->default_principal ) {
1417 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 using default user %s", cfg->default_principal);
1418 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1419 } else {
1420 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 not doing nothin.");
1421 }
4e1ae1cd 1422
3f4fda20 1423 return DECLINED;
7193eb01 1424}
4e1ae1cd 1425
3f4fda20 1426static int
1427waklog_phase3 (request_rec * r)
7193eb01 1428{
3f4fda20 1429 waklog_config *cfg;
1e18ef7d 1430
3f4fda20 1431 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1432 "mod_waklog: phase 3 called");
1e18ef7d 1433
3f4fda20 1434 cfg = retrieve_config(r);
1435
1436 if ( cfg->protect && cfg->principal ) {
1437 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 using user %s", cfg->principal);
1438 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1439 } else if ( cfg->default_principal ) {
1440 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 using default user %s", cfg->default_principal);
1441 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1442 } else {
1443 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 not doing nothin.");
1444 }
1445
1446 return DECLINED;
1447}
bed98ff9 1448
3f4fda20 1449static int
1450waklog_phase6 (request_rec * r)
1451{
1452 waklog_config *cfg;
1453
1454 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1455 "mod_waklog: phase6 called");
3f4fda20 1456
1457 cfg = retrieve_config(r);
1458
1459 if ( cfg->protect && cfg->principal ) {
1460 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 using user %s", cfg->principal);
1461 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1462 } else if ( cfg->default_principal ) {
1463 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 using default user %s", cfg->default_principal);
1464 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1465 } else {
1466 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 not doing nothin.");
1467 }
1468
1469 return DECLINED;
1470}
bed98ff9 1471
3f4fda20 1472static int
1473waklog_phase7 (request_rec * r)
1474{
1475 waklog_config *cfg;
1476 int rc = 0;
1477
1478 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1479 "mod_waklog: phase7 called");
3f4fda20 1480
1481 cfg = retrieve_config (r);
1482
1483 if ( cfg->protect && cfg->usertokens ) {
1484 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using usertokens");
1485 rc = set_auth( r->server, r, 1, NULL, NULL, 0);
1486 } else if ( cfg->protect && cfg->principal ) {
1487 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using user %s", cfg->principal);
1488 rc = set_auth( r->server, r, 0, cfg->principal, cfg->keytab, 0);
1489 } else if ( cfg->default_principal ) {
1490 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using default user %s", cfg->default_principal);
1491 rc = set_auth( r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1492 }
1493
1494 if ( rc ) {
1495 return 400;
1496 }
1497
1498 return DECLINED;
1499}
87822447 1500
3f4fda20 1501static int
1502waklog_phase9 (request_rec * r)
1503{
1504 waklog_config *cfg;
bed98ff9 1505
3f4fda20 1506 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1507 "mod_waklog: phase9 called");
bed98ff9 1508
3f4fda20 1509 getModConfig (cfg, r->server);
1510
1511 if ( cfg->default_principal ) {
1512 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase9 using default user %s", cfg->default_principal);
1513 set_auth( r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1514 }
1515
1516 return DECLINED;
bed98ff9 1517}
1518
ff47641b 1519
87822447 1520static
c9d59a9c 1521#ifdef APACHE2
ff47641b 1522 int
87822447 1523#else
ff47641b 1524 void
87822447 1525#endif
ff47641b 1526waklog_new_connection (conn_rec * c
c9d59a9c 1527#ifdef APACHE2
42d78dfb 1528 , void *dummy
87822447 1529#endif
ff47641b 1530 )
1531{
1532
3f4fda20 1533 waklog_config *cfg;
ff47641b 1534
1535 log_error (APLOG_MARK, APLOG_DEBUG, 0, c->base_server,
42d78dfb 1536 "mod_waklog: new_connection called: pid: %d", getpid ());
1537
1538 getModConfig(cfg, c->base_server);
1539
1540 if ( cfg->default_principal ) {
1541 log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "mod_waklog: new conn setting default user %s",
1542 cfg->default_principal);
1543 set_auth( c->base_server, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1544 }
1545
1546
3f4fda20 1547 return
c9d59a9c 1548#ifdef APACHE2
3f4fda20 1549 0
87822447 1550#endif
3f4fda20 1551 ;
7193eb01 1552}
bed98ff9 1553
c4ad0387 1554
1196adfe 1555/*
1556** Here's a quick explaination for phase0 and phase2:
1557** Apache does a stat() on the path between phase0 and
1558** phase2, and must by ACLed rl to succeed. So, at
1559** phase0 we acquire credentials for umweb:servers from
1560** a keytab, and at phase2 we must ensure we remove them.
1561**
1562** Failure to "unlog" would be a security risk.
1563*/
ff47641b 1564static int
1565waklog_phase2 (request_rec * r)
c4ad0387 1566{
161ffd84 1567
ff47641b 1568 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1569 "mod_waklog: phase2 called");
1196adfe 1570
ff47641b 1571 if (child.token.ticketLen)
1572 {
1573 memset (&child.token, 0, sizeof (struct ktc_token));
c4ad0387 1574
ff47641b 1575 ktc_ForgetAllTokens ();
c4ad0387 1576
ff47641b 1577 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1578 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1579 getpid ());
c4ad0387 1580 }
1196adfe 1581
ff47641b 1582 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
42d78dfb 1583 "mod_waklog: phase2 returning");
1196adfe 1584
3f4fda20 1585 return DECLINED;
c4ad0387 1586}
1587
c9d59a9c 1588#ifndef APACHE2
313dde40 1589module MODULE_VAR_EXPORT waklog_module = {
3f4fda20 1590 STANDARD_MODULE_STUFF,
866ccfbd 1591 waklog_init, /* module initializer */
42d78dfb 1592 waklog_create_dir_config, /* create per-dir config structures */
866ccfbd 1593 waklog_merge_dir_config, /* merge per-dir config structures */
1594 waklog_create_server_config, /* create per-server config structures */
1595 waklog_merge_dir_config, /* merge per-server config structures */
1596 waklog_cmds, /* table of config file commands */
1597 NULL, /* [#8] MIME-typed-dispatched handlers */
1598 waklog_phase1, /* [#1] URI to filename translation */
1599 NULL, /* [#4] validate user id from request */
1600 NULL, /* [#5] check if the user is ok _here_ */
1601 waklog_phase3, /* [#3] check access by host address */
1602 waklog_phase6, /* [#6] determine MIME type */
1603 waklog_phase7, /* [#7] pre-run fixups */
1604 waklog_phase9, /* [#9] log a transaction */
1605 NULL, /* [#2] header parser */
1606 waklog_child_init, /* child_init */
1607 waklog_child_exit, /* child_exit */
1608 waklog_phase0 /* [#0] post read-request */
bed98ff9 1609#ifdef EAPI
866ccfbd 1610 , NULL, /* EAPI: add_module */
1611 NULL, /* EAPI: remove_module */
1612 NULL, /* EAPI: rewrite_command */
1613 waklog_new_connection /* EAPI: new_connection */
bed98ff9 1614#endif
1615};
87822447 1616#else
1617static void
ff47641b 1618waklog_register_hooks (apr_pool_t * p)
87822447 1619{
3f4fda20 1620 ap_hook_translate_name (waklog_phase1, NULL, NULL, APR_HOOK_FIRST);
ff47641b 1621 ap_hook_header_parser (waklog_phase2, NULL, NULL, APR_HOOK_FIRST);
3f4fda20 1622 ap_hook_access_checker (waklog_phase3, NULL, NULL, APR_HOOK_FIRST);
1623 ap_hook_type_checker (waklog_phase6, NULL, NULL, APR_HOOK_FIRST);
ff47641b 1624 ap_hook_fixups (waklog_phase7, NULL, NULL, APR_HOOK_FIRST);
3f4fda20 1625 ap_hook_log_transaction (waklog_phase9, NULL, NULL, APR_HOOK_FIRST);
ff47641b 1626 ap_hook_child_init (waklog_child_init, NULL, NULL, APR_HOOK_FIRST);
1627 ap_hook_post_read_request (waklog_phase0, NULL, NULL, APR_HOOK_FIRST);
1628 ap_hook_pre_connection (waklog_new_connection, NULL, NULL, APR_HOOK_FIRST);
1629 ap_hook_post_config (waklog_init_handler, NULL, NULL, APR_HOOK_MIDDLE);
87822447 1630}
1631
1632
3f4fda20 1633module AP_MODULE_DECLARE_DATA waklog_module = {
1634 STANDARD20_MODULE_STUFF,
42d78dfb 1635 waklog_create_dir_config, /* create per-dir conf structures */
1636 waklog_merge_dir_config, /* merge per-dir conf structures */
1637 waklog_create_server_config, /* create per-server conf structures */
1638 waklog_merge_dir_config, /* merge per-server conf structures */
1639 waklog_cmds, /* table of configuration directives */
1640 waklog_register_hooks /* register hooks */
87822447 1641};
1642#endif