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