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