Release
[hcoop/debian/libapache-mod-waklog.git] / mod_waklog.c
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 }
45 module 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"
58 extern 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)
66 module AP_MODULE_DECLARE_DATA waklog_module;
67 typedef struct { int dummy; } child_info;
68 const 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 */
95 int pag_for_children = 1;
96
97 typedef 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 }
114 waklog_config;
115
116 typedef 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
127 waklog_child_config child;
128
129 struct 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
140 struct sharedspace_s {
141 int renewcount;
142 struct tokencache_ent sharedtokens[SHARED_TABLE_SIZE];
143 };
144
145 struct sharedspace_s *sharedspace = NULL;
146
147 struct renew_ent {
148 char *keytab;
149 char *principal;
150 int lastrenewed;
151 };
152
153 #ifdef use_pthreads
154 pthread_rwlock_t *sharedlock = NULL;
155 #else
156 rwlock_t *sharedlock = NULL;
157 #endif
158
159 struct renew_ent renewtable[SHARED_TABLE_SIZE];
160
161 int 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
180 static void
181 log_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
199 waklog_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
226 int
227 set_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 /* Since we're fetching a key for AFS, we have to use single DES
550 and explicitely enable weak crypto using the secret API
551 call */
552 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
553 krb5_allow_weak_crypto (child.kcontext, 1);
554
555 if ( ( kerror = krb5_get_credentials (child.kcontext, 0, clientccache, &increds, &v5credsp ) ) ) {
556 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
557 if (attempt>=1) {
558 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_credentials: %s",
559 error_message(kerror));
560 goto cleanup;
561 } else {
562 continue;
563 }
564 }
565 cfg->cell_in_principal = cell_in_principal;
566 break;
567 }
568
569 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: get_credentials passed for %s", k5user);
570
571 if ( v5credsp->ticket.length >= MAXKTCTICKETLEN ) {
572 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: ticket size (%d) too big to fake",
573 v5credsp->ticket.length);
574 goto cleanup;
575 }
576
577 memset(&token, 0, sizeof(struct ktc_token));
578
579 token.startTime = v5credsp->times.starttime ? v5credsp->times.starttime : v5credsp->times.authtime;
580 token.endTime = v5credsp->times.endtime;
581
582 memmove( &token.sessionKey, v5credsp->keyblock.contents, v5credsp->keyblock.length);
583 token.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
584 token.ticketLen = v5credsp->ticket.length;
585 memmove( token.ticket, v5credsp->ticket.data, token.ticketLen);
586
587 /* build the name */
588
589 memmove( buf, v5credsp->client->data[0].data, min(v5credsp->client->data[0].length,
590 MAXKTCNAMELEN -1 ));
591 buf[v5credsp->client->data[0].length] = '\0';
592 if ( v5credsp->client->length > 1 ) {
593 strncat(buf, ".", sizeof(buf) - strlen(buf) - 1);
594 buflen = strlen(buf);
595 memmove(buf + buflen, v5credsp->client->data[1].data,
596 min(v5credsp->client->data[1].length,
597 MAXKTCNAMELEN - strlen(buf) - 1));
598 buf[buflen + v5credsp->client->data[1].length] = '\0';
599 }
600
601 /* assemble the client */
602 strncpy(client.name, buf, sizeof(client.name) - 1 );
603 strncpy(client.instance, "", sizeof(client.instance) - 1 );
604 memmove(buf, v5credsp->client->realm.data, min(v5credsp->client->realm.length,
605 MAXKTCNAMELEN - 1));
606 buf[v5credsp->client->realm.length] = '\0';
607 strncpy(client.cell, buf, sizeof(client.cell));
608
609 /* assemble the server's cell */
610 strncpy(server.cell, cfg->afs_cell, sizeof(server.cell) - 1);
611
612 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: preparing to init PTS connection for %s", server.cell);
613
614 /* fill out the AFS ID in the client name */
615 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
616 * strange things seem to happen. */
617
618 {
619 afs_int32 viceId = 0;
620
621 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: making PTS call to look up %s", client.name);
622
623 if ( ( rc = pr_SNameToId( client.name, &viceId ) ) == 0 ) {
624 snprintf( client.name, sizeof(client.name), "AFS ID %d", viceId );
625 } else {
626 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: PTS call returned error %d ", rc);
627 }
628
629 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: PTS call returned %s ", client.name);
630
631 }
632
633 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: server: name %s, instance %s, cell %s",
634 server.name, server.instance, server.cell );
635
636 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: client: name %s, instance %s, cell %s",
637 client.name, client.instance, client.cell );
638
639 /* copy the resulting stuff into the child structure */
640
641 strncpy(child.clientprincipal, k5user, sizeof(child.clientprincipal));
642 memcpy(&child.token, &token, sizeof(child.token));
643 memcpy(&child.server, &server, sizeof(child.server));
644 memcpy(&child.client, &client, sizeof(child.client));
645
646 /* stuff the resulting token-related stuff into our shared token cache */
647 /* note, that anything that was set from a keytab is "persistant", and is immune
648 * from LRU-aging. This is because nothing but the process that's running as root
649 * can update these, and it's running every hour or so and renewing these tokens.
650 * and we don't want them aged out.
651 */
652
653 mytime = oldest_time = time(0);
654
655 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: waiting for shared space for %s ", k5user);
656
657 #ifdef use_pthreads
658 pthread_rwlock_wrlock(sharedlock);
659 #else
660 rw_wrlock(sharedlock);
661 #endif
662
663 for( i = ( SHARED_TABLE_SIZE - 1 ); i >= 0; i-- ) {
664 if ( ( sharedspace->sharedtokens[i].lastused <= oldest_time) &&
665 ( sharedspace->sharedtokens[i].persist == 0 ) ) {
666 oldest = i;
667 oldest_time = sharedspace->sharedtokens[i].lastused;
668 }
669 if ( ! strcmp ( sharedspace->sharedtokens[i].clientprincipal,
670 child.clientprincipal ) ) {
671 memcpy(&sharedspace->sharedtokens[i].token, &child.token, sizeof(child.token) );
672 memcpy(&sharedspace->sharedtokens[i].client, &child.client, sizeof(child.client) );
673 memcpy(&sharedspace->sharedtokens[i].server, &child.server, sizeof(child.server) );
674 sharedspace->sharedtokens[i].lastused = mytime;
675 sharedspace->sharedtokens[i].persist = keytab ? 1 : 0;
676 stored = i;
677 break;
678 }
679 }
680
681 if ( stored == -1 ) {
682 memcpy(&sharedspace->sharedtokens[oldest].token, &child.token, sizeof(child.token) );
683 memcpy(&sharedspace->sharedtokens[oldest].client, &child.client, sizeof(child.client) );
684 memcpy(&sharedspace->sharedtokens[oldest].server, &child.server, sizeof(child.server) );
685 strcpy(sharedspace->sharedtokens[oldest].clientprincipal, child.clientprincipal );
686 sharedspace->sharedtokens[oldest].lastused = mytime;
687 sharedspace->sharedtokens[oldest].persist = keytab ? 1 : 0;
688 stored = oldest;
689 }
690
691 #ifdef use_pthreads
692 pthread_rwlock_unlock(sharedlock);
693 #else
694 rw_unlock(sharedlock);
695 #endif
696
697 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: token stored in slot %d for %s", stored,
698 child.clientprincipal );
699
700 } else if ( ! usecached ) {
701 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth divergent case");
702 }
703
704 if ( storeonly ) {
705 goto cleanup;
706 }
707
708 usecachedtoken:
709
710 /* don't ask. Something about AIX. We're leaving it here.*/
711 /* write(2, "", 0); */
712
713 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
714
715 if ((rc = ktc_SetToken(&child.server, &child.token, &child.client, 0))) {
716 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: settoken returned %s for %s -- trying again",
717 error_message(rc), k5user);
718 if ((rc = ktc_SetToken(&child.server, &child.token, &child.client, 0))) {
719 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: settoken2 returned %s for %s",
720 error_message(rc), k5user);
721 goto cleanup;
722 }
723 }
724
725 cleanup:
726 if (use_client_credentials)
727 krb5_cc_close(child.kcontext, clientccache);
728 if ( v5credsp )
729 krb5_free_cred_contents(child.kcontext, v5credsp);
730 if ( increds.client )
731 krb5_free_principal (child.kcontext, increds.client);
732 if ( increds.server )
733 krb5_free_principal (child.kcontext, increds.server);
734 if ( krb5kt )
735 (void) krb5_kt_close(child.kcontext, krb5kt);
736 if ( kprinc )
737 krb5_free_principal (child.kcontext, kprinc);
738
739 if ( rc ) {
740 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with %d", rc );
741 } else if ( kerror ) {
742 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror, error_message(kerror));
743 } else {
744 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth ending ok");
745 }
746
747 return kerror ? (int) kerror : (int) rc;
748
749 }
750
751
752 int get_cfg_usertokens(waklog_config *cfg)
753 {
754 if (cfg->usertokens==WAKLOG_UNSET)
755 return 0; /* default */
756 return cfg->usertokens;
757 }
758
759 int get_cfg_protect(waklog_config *cfg)
760 {
761 if (cfg->protect==WAKLOG_UNSET)
762 return 0; /* default */
763 return cfg->protect;
764 }
765
766 int get_cfg_disable_token_cache(waklog_config *cfg)
767 {
768 if (cfg->disable_token_cache==WAKLOG_UNSET)
769 return 0; /* default */
770 return cfg->disable_token_cache;
771 }
772
773
774 static void *
775 waklog_create_server_config (MK_POOL * p, server_rec * s)
776 {
777 waklog_config *cfg;
778
779 cfg = (waklog_config *) ap_pcalloc (p, sizeof (waklog_config));
780 cfg->p = p;
781 memset(cfg, 0, sizeof(waklog_config));
782 cfg->path = "(server)";
783 cfg->protect = WAKLOG_UNSET;
784 cfg->usertokens = WAKLOG_UNSET;
785 cfg->disable_token_cache = WAKLOG_UNSET;
786 cfg->keytab = NULL;
787 cfg->principal = NULL;
788 cfg->default_principal = NULL;
789 cfg->default_keytab = NULL;
790 cfg->afs_cell = NULL;
791 cfg->afs_cell_realm = NULL;
792 cfg->forked = 0;
793 cfg->configured = 0;
794
795 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
796 "mod_waklog: server config created.");
797
798 return (cfg);
799 }
800
801 /* initialize with host-config information */
802
803 static void *
804 waklog_create_dir_config (MK_POOL * p, char *dir)
805 {
806 waklog_config *cfg;
807
808 cfg = (waklog_config *) ap_pcalloc (p, sizeof (waklog_config));
809 memset(cfg, 0, sizeof(waklog_config));
810 cfg->p = p;
811 cfg->path = ap_pstrdup(p, dir );
812 cfg->protect = WAKLOG_UNSET;
813 cfg->usertokens = WAKLOG_UNSET;
814 cfg->disable_token_cache = WAKLOG_UNSET;
815 cfg->keytab = NULL;
816 cfg->principal = NULL;
817 cfg->default_principal = NULL;
818 cfg->default_keytab = NULL;
819 cfg->afs_cell = NULL;
820 cfg->afs_cell_realm = NULL;
821 cfg->forked = 0;
822 cfg->configured = 0;
823
824 return (cfg);
825 }
826
827 static void *waklog_merge_dir_config(MK_POOL *p, void *parent_conf, void *newloc_conf) {
828
829 waklog_config *merged = ( waklog_config * ) ap_pcalloc(p, sizeof(waklog_config ) );
830 waklog_config *parent = ( waklog_config * ) parent_conf;
831 waklog_config *child = ( waklog_config * ) newloc_conf;
832
833 merged->protect = child->protect != WAKLOG_UNSET ? child->protect : parent->protect;
834
835 merged->path = child->path != NULL ? child->path : parent->path;
836
837 merged->usertokens = child->usertokens != WAKLOG_UNSET ? child->usertokens : parent->usertokens;
838
839 merged->disable_token_cache = child->disable_token_cache != WAKLOG_UNSET ? child->disable_token_cache : parent->disable_token_cache;
840
841 merged->principal = child->principal != NULL ? child->principal : parent->principal;
842
843 merged->keytab = child->keytab != NULL ? child->keytab : parent->keytab;
844
845 merged->default_keytab = child->default_keytab != NULL ? child->default_keytab : parent->default_keytab;
846
847 merged->default_principal = child->default_principal != NULL ? child->default_principal : parent->default_principal;
848
849 merged->afs_cell = child->afs_cell != NULL ? child->afs_cell : parent->afs_cell;
850
851 merged->afs_cell_realm = child->afs_cell_realm != NULL ? child->afs_cell_realm : parent->afs_cell_realm;
852
853 return (void *) merged;
854
855 }
856
857 static void *waklog_merge_server_config(MK_POOL *p, void *parent_conf, void *newloc_conf) {
858
859 waklog_config *merged = ( waklog_config * ) ap_pcalloc(p, sizeof(waklog_config ) );
860 waklog_config *pconf = ( waklog_config * ) parent_conf;
861 waklog_config *nconf = ( waklog_config * ) newloc_conf;
862
863 merged->protect = nconf->protect == WAKLOG_UNSET ? pconf->protect : nconf->protect;
864
865 merged->usertokens = nconf->usertokens == WAKLOG_UNSET ? pconf->usertokens : nconf->usertokens;
866
867 merged->disable_token_cache = nconf->disable_token_cache == WAKLOG_UNSET ? pconf->disable_token_cache : nconf->disable_token_cache;
868
869 merged->keytab = nconf->keytab == NULL ? ap_pstrdup(p, pconf->keytab) :
870 ( nconf->keytab == NULL ? NULL : ap_pstrdup(p, nconf->keytab) );
871
872 merged->principal = nconf->principal == NULL ? ap_pstrdup(p, pconf->principal) :
873 ( nconf->principal == NULL ? NULL : ap_pstrdup(p, nconf->principal) );
874
875 merged->afs_cell = nconf->afs_cell == NULL ? ap_pstrdup(p, pconf->afs_cell) :
876 ( nconf->afs_cell == NULL ? NULL : ap_pstrdup(p, nconf->afs_cell) );
877
878 merged->afs_cell_realm = nconf->afs_cell_realm == NULL ? ap_pstrdup(p, pconf->afs_cell_realm) :
879 ( nconf->afs_cell_realm == NULL ? NULL : ap_pstrdup(p, nconf->afs_cell_realm) );
880
881 merged->default_keytab = nconf->default_keytab == NULL ? ap_pstrdup(p, pconf->default_keytab) :
882 ( nconf->default_keytab == NULL ? NULL : ap_pstrdup(p, nconf->default_keytab) );
883
884 merged->default_principal = nconf->default_principal == NULL ? ap_pstrdup(p, pconf->default_principal) :
885 ( nconf->default_principal == NULL ? NULL : ap_pstrdup(p, nconf->default_principal) );
886
887
888 return (void *) merged;
889
890 }
891
892 static const char *
893 set_waklog_enabled (cmd_parms * params, void *mconfig, int flag)
894 {
895 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
896 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
897
898 cfg->protect = flag;
899 cfg->configured = 1;
900 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
901 "mod_waklog: waklog_enabled set on %s", cfg->path ? cfg->path : "NULL");
902 return (NULL);
903 }
904
905
906 /* this adds a principal/keytab pair to get their tokens renewed by the
907 child process every few centons. */
908
909 void add_to_renewtable(MK_POOL *p, char *keytab, char *principal) {
910
911 int i;
912
913 if ( renewcount >= SHARED_TABLE_SIZE ) {
914 log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
915 decrease your tokens.");
916 return;
917 }
918
919 /* check to see if it's already there */
920
921 for ( i = 0; i < renewcount; i++ ) {
922 if ( ! strcmp(renewtable[i].principal, principal ) ) {
923 return;
924 }
925 }
926
927 renewtable[renewcount].keytab = ap_pstrdup(p, keytab);
928 renewtable[renewcount].principal = ap_pstrdup(p, principal);
929 renewtable[renewcount].lastrenewed = 0;
930 ++renewcount;
931
932 }
933
934 static const char *
935 set_waklog_location_principal (cmd_parms *params, void *mconfig, char *principal, char *keytab)
936 {
937 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
938 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
939
940 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
941 "mod_waklog: configuring principal: %s, keytab: %s", principal, keytab);
942
943 cfg->principal = ap_pstrdup(params->pool, principal);
944 cfg->keytab = ap_pstrdup (params->pool, keytab);
945
946 add_to_renewtable(params->pool, keytab, principal);
947
948 cfg->configured = 1;
949
950 return (NULL);
951 }
952
953 static const char *
954 set_waklog_afs_cell (cmd_parms * params, void *mconfig, char *file)
955 {
956 waklog_config *waklog_mconfig = ( waklog_config * ) mconfig;
957 waklog_config *waklog_srvconfig =
958 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
959
960 log_error (APLOG_MARK, APLOG_INFO, 0, params->server,
961 "mod_waklog: will use afs_cell: %s", file);
962
963 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
964 waklog_srvconfig->cell_in_principal = 1;
965
966 waklog_srvconfig->afs_cell = ap_pstrdup (params->pool, file);
967 waklog_srvconfig->configured = 1;
968
969 if (waklog_mconfig != NULL) {
970 waklog_mconfig->cell_in_principal = waklog_srvconfig->cell_in_principal;
971 waklog_mconfig->afs_cell = ap_pstrdup (params->pool, file);
972 waklog_mconfig->configured = 1;
973 }
974 return (NULL);
975 }
976
977 static const char *
978 set_waklog_afs_cell_realm (cmd_parms * params, void *mconfig, char *file)
979 {
980 waklog_config *waklog_mconfig = ( waklog_config * ) mconfig;
981 waklog_config *waklog_srvconfig =
982 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
983
984 log_error (APLOG_MARK, APLOG_INFO, 0, params->server,
985 "mod_waklog: will use afs_cell_realm: %s", file);
986
987 waklog_srvconfig->afs_cell_realm = ap_pstrdup (params->pool, file);
988
989 if (waklog_mconfig != NULL) {
990 waklog_mconfig->afs_cell_realm = ap_pstrdup (params->pool, file);
991 }
992 return (NULL);
993 }
994
995 static const char *
996 set_waklog_default_principal (cmd_parms * params, void *mconfig, char *principal, char *keytab)
997 {
998 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
999 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
1000
1001 waklog_config *srvcfg = ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
1002
1003 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
1004 "mod_waklog: set default princ/keytab: %s, %s for %s", principal, keytab, cfg->path ? cfg->path : "NULL");
1005
1006 cfg->default_principal = ap_pstrdup (params->pool, principal);
1007 cfg->default_keytab = ap_pstrdup(params->pool, keytab );
1008
1009 /* this also gets set at the server level */
1010 if ( mconfig && ( ! cfg->path ) ) {
1011 srvcfg->default_principal = ap_pstrdup (params->pool, principal);
1012 srvcfg->default_keytab = ap_pstrdup(params->pool, keytab );
1013 } else {
1014 log_error(APLOG_MARK, APLOG_ERR, 0, params->server, "only able to set default principal on a global level!");
1015 return "Unable to set DefaultPrincipal outside of top level config!";
1016 }
1017
1018 add_to_renewtable( params->pool, keytab, principal );
1019
1020 cfg->configured = 1;
1021
1022 return (NULL);
1023 }
1024
1025 static const char *
1026 set_waklog_use_usertokens (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->usertokens = flag;
1032
1033 cfg->configured = 1;
1034
1035 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
1036 "mod_waklog: waklog_use_user_tokens set");
1037 return (NULL);
1038 }
1039
1040
1041 static const char *
1042 set_waklog_disable_token_cache (cmd_parms * params, void *mconfig, int flag)
1043 {
1044 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
1045 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
1046
1047 cfg->disable_token_cache = flag;
1048
1049 cfg->configured = 1;
1050
1051 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
1052 "mod_waklog: waklog_disable_token_cache set");
1053 return (NULL);
1054 }
1055
1056
1057 #ifndef APACHE2
1058 static void waklog_child_exit( server_rec *s, MK_POOL *p ) {
1059 #else
1060 apr_status_t waklog_child_exit( void *sr ) {
1061
1062 server_rec *s = (server_rec *) sr;
1063 #endif
1064
1065 if ( child.ccache ) {
1066 krb5_cc_close(child.kcontext, child.ccache);
1067 }
1068
1069 if ( child.kcontext ) {
1070 krb5_free_context(child.kcontext);
1071 }
1072
1073 /* forget our tokens */
1074
1075 ktc_ForgetAllTokens ();
1076
1077 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
1078 "mod_waklog: waklog_child_exit complete");
1079
1080 #ifdef APACHE2
1081 return APR_SUCCESS;
1082 #endif
1083
1084 }
1085
1086 static void
1087 #ifdef APACHE2
1088 waklog_child_init (MK_POOL * p, server_rec * s)
1089 #else
1090 waklog_child_init (server_rec * s, MK_POOL * p)
1091 #endif
1092 {
1093
1094 krb5_error_code code;
1095 waklog_config *cfg;
1096
1097 char *cell;
1098
1099 log_error (APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init called for pid %d", getpid());
1100
1101 if ( !sharedspace ) {
1102 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: child_init called without shared space? %d", getpid());
1103 return;
1104 }
1105
1106 log_error (APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init called for pid %d", getpid());
1107
1108 memset (&child, 0, sizeof(child));
1109
1110 if ( ( code = krb5_init_context(&child.kcontext) ) ) {
1111 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't init kerberos context %d", code );
1112 }
1113
1114 if ( ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) ) {
1115 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", code );
1116 }
1117
1118 if ( pag_for_children ) {
1119 setpag ();
1120 }
1121
1122 getModConfig (cfg, s);
1123
1124 if ( cfg->default_principal != NULL ) {
1125 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init setting default user %s, %s", cfg->default_principal, cfg->default_keytab);
1126 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1127 }
1128
1129 cell = strdup(cfg->afs_cell);
1130 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR, cell );
1131
1132 #ifdef APACHE2
1133 apr_pool_cleanup_register(p, s, waklog_child_exit, apr_pool_cleanup_null);
1134 #endif
1135
1136 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
1137 "mod_waklog: child_init returned");
1138
1139 return;
1140 }
1141
1142 command_rec waklog_cmds[] = {
1143
1144 command ("WaklogAFSCell", set_waklog_afs_cell, 0, TAKE1,
1145 "Use the supplied AFS cell (required)"),
1146
1147 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm, 0, TAKE1,
1148 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1149
1150 command ("WaklogEnabled", set_waklog_enabled, 0, FLAG,
1151 "enable waklog on a server, location, or directory basis"),
1152
1153 command ("WaklogDefaultPrincipal", set_waklog_default_principal, 0, TAKE2,
1154 "Set the default principal that the server runs as"),
1155
1156 command ("WaklogLocationPrincipal", set_waklog_location_principal, 0, TAKE2,
1157 "Set the principal on a <Location>-specific basis"),
1158
1159 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache, 0, FLAG,
1160 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1161
1162 command ("WaklogUseUserTokens", set_waklog_use_usertokens, 0, FLAG,
1163 "Use the requesting user tokens (from webauth)"),
1164
1165 {NULL}
1166 };
1167
1168
1169 /* not currently using this */
1170
1171 static int
1172 token_cleanup (void *data)
1173 {
1174 request_rec *r = (request_rec *) data;
1175
1176 if (child.token.ticketLen)
1177 {
1178 memset (&child.token, 0, sizeof (struct ktc_token));
1179
1180 ktc_ForgetAllTokens ();
1181
1182 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1183 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1184 getpid ());
1185 }
1186 return 0;
1187 }
1188
1189 static int
1190 waklog_child_routine (void *data, child_info * pinfo)
1191 {
1192 int i;
1193 server_rec *s = (server_rec *) data;
1194 krb5_error_code code;
1195 char *cell;
1196 time_t sleep_time = ( TKT_LIFE / 2 ) ;
1197 time_t when;
1198 time_t left;
1199 waklog_config *cfg;
1200
1201 getModConfig( cfg, s );
1202
1203 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1204
1205 memset (&child, 0, sizeof(child));
1206
1207 if ( ( code = krb5_init_context(&child.kcontext) ) ) {
1208 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't init kerberos context %d", code );
1209 }
1210
1211 if ( ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) ) {
1212 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", code );
1213 }
1214
1215 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: about to pr_Initialize");
1216
1217 /* need to do this so we can make PTS calls */
1218 cell = strdup(cfg->afs_cell); /* stupid */
1219 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR, cell );
1220
1221 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: still here");
1222
1223 while(1) {
1224
1225 for ( i = 0; i < renewcount; ++i ) {
1226 renewtable[i].lastrenewed = time(0);
1227 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable[i].principal,
1228 renewtable[i].keytab);
1229
1230 set_auth( s, NULL, 0, renewtable[i].principal, renewtable[i].keytab, 1 );
1231
1232 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1233 things that it needs to read */
1234
1235 if ( cfg && cfg->default_principal && ( ! strcmp(cfg->default_principal, renewtable[i].principal ) ) ) {
1236 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: renewing/setting default tokens" );
1237 set_auth( s, NULL, 0, renewtable[i].principal, renewtable[i].keytab, 0 );
1238 }
1239
1240 }
1241
1242 sharedspace->renewcount++;
1243
1244 left = sleep_time;
1245
1246 while( left > 5 ) {
1247 when = time(0);
1248
1249 sleep(left);
1250
1251 left -= ( time(0) - when );
1252 }
1253
1254 }
1255
1256 pr_End();
1257
1258 }
1259
1260 #ifdef APACHE2
1261 static int
1262 waklog_init_handler (apr_pool_t * p, apr_pool_t * plog,
1263 apr_pool_t * ptemp, server_rec * s)
1264 {
1265 int rv;
1266 extern char *version;
1267 apr_proc_t *proc;
1268 waklog_config *cfg;
1269 void *data;
1270 int fd = -1;
1271 int use_existing = 1;
1272 int oldrenewcount;
1273 char cache_file[MAXNAMELEN];
1274 #ifdef use_pthreads
1275 pthread_rwlockattr_t rwlock_attr;
1276 #endif
1277
1278
1279 getModConfig (cfg, s);
1280
1281 /* initialize_module() will be called twice, and if it's a DSO
1282 * then all static data from the first call will be lost. Only
1283 * set up our static data on the second call.
1284 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1285 apr_pool_userdata_get (&data, userdata_key, s->process->pool);
1286
1287
1288 if (cfg->afs_cell==NULL) {
1289 log_error (APLOG_MARK, APLOG_ERR, 0, s,
1290 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1291 /** clobber apache */
1292 exit(-1);
1293 }
1294
1295 if (!data)
1296 {
1297 apr_pool_userdata_set ((const void *) 1, userdata_key,
1298 apr_pool_cleanup_null, s->process->pool);
1299 }
1300 else
1301 {
1302 log_error (APLOG_MARK, APLOG_INFO, 0, s,
1303 "mod_waklog: version %s initialized for cell %s", version, cfg->afs_cell);
1304
1305 if ( sharedspace ) {
1306 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: shared memory already allocated." );
1307 } else {
1308
1309 snprintf( cache_file, MAXNAMELEN, "/tmp/waklog_cache.%d", getpid() );
1310
1311 if ( ( fd = open( cache_file, O_RDWR, 0600 ) ) == -1 ) {
1312
1313 if ( errno == ENOENT ) {
1314
1315 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: creating shared token cache file %s", cache_file );
1316 use_existing = 0;
1317 if ( ( fd = open( cache_file, O_RDWR|O_CREAT|O_TRUNC, 0600 ) ) == -1 ) {
1318 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file, errno );
1319 exit(errno);
1320 }
1321 } else {
1322 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file, errno );
1323 }
1324 }
1325
1326 if ( use_existing == 0 ) {
1327 struct sharedspace_s bob;
1328 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: sizing our cache file %d to %d", fd, sizeof(struct sharedspace_s) );
1329 memset( &bob, 0, sizeof(struct sharedspace_s));
1330 write(fd, &bob, sizeof(struct sharedspace_s));
1331 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s) );
1332 }
1333
1334 /* mmap the region */
1335
1336 if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != MAP_FAILED ) {
1337 int err = 0;
1338 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared mmap region ok %d", sharedspace );
1339 err = unlink(cache_file);
1340 if (err) {
1341 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: unable to delete %s due to %d", cache_file, errno);
1342 } else {
1343 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1344 }
1345 } else {
1346 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: mmap failed %d", errno );
1347 exit(errno);
1348 }
1349 }
1350
1351 #ifdef use_pthreads
1352 #define locktype pthread_rwlock_t
1353 #else
1354 #define locktype rwlock_t
1355 #endif
1356
1357 if ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) {
1358 #ifndef use_pthreads
1359 rwlock_init(sharedlock, USYNC_PROCESS, NULL );
1360 #else
1361 pthread_rwlockattr_init(&rwlock_attr);
1362 pthread_rwlockattr_setpshared(&rwlock_attr, PTHREAD_PROCESS_SHARED);
1363 pthread_rwlock_init(sharedlock, &rwlock_attr );
1364 #endif
1365 } else {
1366 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: rwlock mmap failed %d", errno );
1367 }
1368
1369 #undef locktype
1370
1371 /* set our default tokens */
1372
1373 oldrenewcount = sharedspace->renewcount;
1374
1375 pag_for_children = 0;
1376
1377 proc = (apr_proc_t *) ap_pcalloc (s->process->pool, sizeof (apr_proc_t));
1378
1379 rv = apr_proc_fork (proc, s->process->pool);
1380
1381 if (rv == APR_INCHILD)
1382 {
1383 waklog_child_routine (s, NULL);
1384 }
1385 else
1386 {
1387 apr_pool_note_subprocess (s->process->pool, proc, APR_KILL_ALWAYS);
1388 }
1389 /* parent and child */
1390 cfg->forked = proc->pid;
1391 pag_for_children = 1;
1392
1393 if ( use_existing == 0 ) {
1394 /* wait here until our child process has gone and done it's renewing thing. */
1395 while( sharedspace->renewcount == oldrenewcount ) {
1396 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: waiting for tokens..." );
1397 sleep(2);
1398 }
1399 }
1400
1401 if ( cfg->default_principal ) {
1402 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1403 }
1404 }
1405 return 0;
1406 }
1407 #else
1408 static void
1409 waklog_init (server_rec * s, MK_POOL * p)
1410 {
1411 extern char *version;
1412 int pid;
1413 waklog_config *cfg;
1414 int fd = -1;
1415 int use_existing = 1;
1416 int oldrenewcount;
1417 char cache_file[MAXNAMELEN];
1418 #ifdef use_pthreads
1419 pthread_rwlockattr_t rwlock_attr;
1420 #endif
1421
1422 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
1423 "mod_waklog: version %s initialized.", version);
1424
1425 if ( sharedspace ) {
1426 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: shared memory already allocated." );
1427 } else {
1428
1429 snprintf( cache_file, MAXNAMELEN, "/tmp/waklog_cache.%d", getpid() );
1430
1431 if ( ( fd = open( cache_file, O_RDWR, 0600 ) ) == -1 ) {
1432
1433 if ( errno == ENOENT ) {
1434
1435 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: creating shared token cache file %s", cache_file );
1436 use_existing = 0;
1437 if ( ( fd = open( cache_file, O_RDWR|O_CREAT|O_TRUNC, 0600 ) ) == -1 ) {
1438 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file, errno );
1439 exit(errno);
1440 }
1441 } else {
1442 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file, errno );
1443 }
1444
1445 }
1446
1447 if ( use_existing == 0 ) {
1448 struct sharedspace_s bob;
1449 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: sizing our cache file %d to %d", fd, sizeof(struct sharedspace_s) );
1450 memset( &bob, 0, sizeof(struct sharedspace_s));
1451 write(fd, &bob, sizeof(struct sharedspace_s));
1452 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s) );
1453 }
1454
1455 /* mmap the region */
1456
1457 if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != (void *) -1 ) {
1458 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared mmap region ok %d", sharedspace );
1459 close(fd);
1460 } else {
1461 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: mmap failed %d", errno );
1462 exit(errno);
1463 }
1464 }
1465
1466 #ifdef use_pthreads
1467 #define locktype pthread_rwlock_t
1468 #else
1469 #define locktype rwlock_t
1470 #endif
1471
1472 /* mmap our shared space for our lock */
1473 if ( ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) ) {
1474 #ifndef use_pthreads
1475 rwlock_init(sharedlock, USYNC_PROCESS, NULL );
1476 #else
1477 pthread_rwlockattr_init(&rwlock_attr);
1478 pthread_rwlockattr_setpshared(&rwlock_attr, PTHREAD_PROCESS_SHARED);
1479 pthread_rwlock_init(sharedlock, &rwlock_attr );
1480 #endif
1481 } else {
1482 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: rwlock mmap failed %d", errno );
1483 }
1484
1485 #undef locktype
1486
1487 /* set our default tokens */
1488
1489 getModConfig (cfg, s);
1490
1491 oldrenewcount = sharedspace->renewcount;
1492
1493 pag_for_children = 0;
1494
1495 pid = ap_bspawn_child (p, waklog_child_routine, s, kill_always,
1496 NULL, NULL, NULL);
1497
1498 pag_for_children = 1;
1499
1500 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
1501 "mod_waklog: ap_bspawn_child: %d.", pid);
1502
1503 if ( use_existing == 0 ) {
1504 /* wait here until our child process has gone and done it's renewing thing. */
1505 while( sharedspace->renewcount == oldrenewcount ) {
1506 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: waiting for tokens..." );
1507 sleep(2);
1508 }
1509 }
1510
1511 if ( cfg->default_principal ) {
1512 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1513 }
1514
1515 }
1516 #endif
1517
1518 static int
1519 waklog_phase0 (request_rec * r)
1520 {
1521 waklog_config *cfg;
1522
1523 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1524 "mod_waklog: phase0 called");
1525
1526 cfg = retrieve_config(r);
1527
1528 if ( get_cfg_protect(cfg) && cfg->principal ) {
1529 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 using user %s", cfg->principal);
1530 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1531 } else if ( cfg->default_principal ) {
1532 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 using default user %s", cfg->default_principal);
1533 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1534 } else {
1535
1536 if (child.token.ticketLen) {
1537 memset( &child.token, 0, sizeof (struct ktc_token) );
1538 ktc_ForgetAllTokens();
1539 }
1540
1541 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 not doing nothin.");
1542 }
1543
1544 return DECLINED;
1545 }
1546
1547 static int
1548 waklog_phase1 (request_rec * r)
1549 {
1550 waklog_config *cfg;
1551
1552 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1553 "mod_waklog: phase1 called");
1554
1555 cfg = retrieve_config(r);
1556
1557 if ( get_cfg_protect(cfg) && cfg->principal ) {
1558 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 using user %s", cfg->principal);
1559 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1560 } else if ( cfg->default_principal ) {
1561 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 using default user %s", cfg->default_principal);
1562 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1563 } else {
1564 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 not doing nothin.");
1565 }
1566
1567 return DECLINED;
1568 }
1569
1570 static int
1571 waklog_phase3 (request_rec * r)
1572 {
1573 waklog_config *cfg;
1574
1575 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1576 "mod_waklog: phase 3 called");
1577
1578 cfg = retrieve_config(r);
1579
1580 if ( get_cfg_protect(cfg) && cfg->principal ) {
1581 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 using user %s", cfg->principal);
1582 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1583 } else if ( cfg->default_principal ) {
1584 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 using default user %s", cfg->default_principal);
1585 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1586 } else {
1587 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 not doing nothin.");
1588 }
1589
1590 return DECLINED;
1591 }
1592
1593 static int
1594 waklog_phase6 (request_rec * r)
1595 {
1596 waklog_config *cfg;
1597
1598 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1599 "mod_waklog: phase6 called");
1600
1601 cfg = retrieve_config(r);
1602
1603 if ( get_cfg_protect(cfg) && cfg->principal ) {
1604 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 using user %s", cfg->principal);
1605 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1606 } else if ( cfg->default_principal ) {
1607 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 using default user %s", cfg->default_principal);
1608 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1609 } else {
1610 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 not doing nothin.");
1611 }
1612
1613 return DECLINED;
1614 }
1615
1616 static int
1617 waklog_phase7 (request_rec * r)
1618 {
1619 waklog_config *cfg;
1620 int rc = 0;
1621
1622 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1623 "mod_waklog: phase7 called");
1624
1625 cfg = retrieve_config (r);
1626
1627 if ( get_cfg_protect(cfg) && get_cfg_usertokens(cfg) ) {
1628 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using usertokens");
1629 rc = set_auth( r->server, r, 1, NULL, NULL, 0);
1630 } else if ( get_cfg_protect(cfg) && cfg->principal ) {
1631 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using user %s", cfg->principal);
1632 rc = set_auth( r->server, r, 0, cfg->principal, cfg->keytab, 0);
1633 } else if ( cfg->default_principal ) {
1634 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using default user %s", cfg->default_principal);
1635 rc = set_auth( r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1636 } else {
1637 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: no tokens");
1638 if (child.token.ticketLen) {
1639 memset(&child.token, 0, sizeof(struct ktc_token));
1640 ktc_ForgetAllTokens();
1641 }
1642 }
1643
1644 if ( rc ) {
1645 return 400;
1646 }
1647
1648 return DECLINED;
1649 }
1650
1651 static int
1652 waklog_phase9 (request_rec * r)
1653 {
1654 waklog_config *cfg;
1655
1656 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1657 "mod_waklog: phase9 called");
1658
1659 getModConfig (cfg, r->server);
1660
1661 if ( cfg->default_principal ) {
1662 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase9 using default user %s", cfg->default_principal);
1663 set_auth( r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1664 }
1665
1666 return DECLINED;
1667 }
1668
1669
1670 static
1671 #ifdef APACHE2
1672 int
1673 #else
1674 void
1675 #endif
1676 waklog_new_connection (conn_rec * c
1677 #ifdef APACHE2
1678 , void *dummy
1679 #endif
1680 )
1681 {
1682
1683 waklog_config *cfg;
1684
1685 log_error (APLOG_MARK, APLOG_DEBUG, 0, c->base_server,
1686 "mod_waklog: new_connection called: pid: %d", getpid ());
1687
1688 getModConfig(cfg, c->base_server);
1689
1690 if ( cfg->default_principal ) {
1691 log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "mod_waklog: new conn setting default user %s",
1692 cfg->default_principal);
1693 set_auth( c->base_server, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1694 }
1695
1696
1697 return
1698 #ifdef APACHE2
1699 0
1700 #endif
1701 ;
1702 }
1703
1704
1705 /*
1706 ** Here's a quick explaination for phase0 and phase2:
1707 ** Apache does a stat() on the path between phase0 and
1708 ** phase2, and must by ACLed rl to succeed. So, at
1709 ** phase0 we acquire credentials for umweb:servers from
1710 ** a keytab, and at phase2 we must ensure we remove them.
1711 **
1712 ** Failure to "unlog" would be a security risk.
1713 */
1714 static int
1715 waklog_phase2 (request_rec * r)
1716 {
1717
1718 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1719 "mod_waklog: phase2 called");
1720
1721 if (child.token.ticketLen)
1722 {
1723 memset (&child.token, 0, sizeof (struct ktc_token));
1724
1725 ktc_ForgetAllTokens ();
1726
1727 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1728 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1729 getpid ());
1730 }
1731
1732 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1733 "mod_waklog: phase2 returning");
1734
1735 return DECLINED;
1736 }
1737
1738 #ifndef APACHE2
1739 module MODULE_VAR_EXPORT waklog_module = {
1740 STANDARD_MODULE_STUFF,
1741 waklog_init, /* module initializer */
1742 waklog_create_dir_config, /* create per-dir config structures */
1743 waklog_merge_dir_config, /* merge per-dir config structures */
1744 waklog_create_server_config, /* create per-server config structures */
1745 waklog_merge_dir_config, /* merge per-server config structures */
1746 waklog_cmds, /* table of config file commands */
1747 NULL, /* [#8] MIME-typed-dispatched handlers */
1748 waklog_phase1, /* [#1] URI to filename translation */
1749 NULL, /* [#4] validate user id from request */
1750 NULL, /* [#5] check if the user is ok _here_ */
1751 waklog_phase3, /* [#3] check access by host address */
1752 waklog_phase6, /* [#6] determine MIME type */
1753 waklog_phase7, /* [#7] pre-run fixups */
1754 waklog_phase9, /* [#9] log a transaction */
1755 waklog_phase2, /* [#2] header parser */
1756 waklog_child_init, /* child_init */
1757 waklog_child_exit, /* child_exit */
1758 waklog_phase0 /* [#0] post read-request */
1759 #ifdef EAPI
1760 , NULL, /* EAPI: add_module */
1761 NULL, /* EAPI: remove_module */
1762 NULL, /* EAPI: rewrite_command */
1763 waklog_new_connection /* EAPI: new_connection */
1764 #endif
1765 };
1766 #else
1767 static void
1768 waklog_register_hooks (apr_pool_t * p)
1769 {
1770 ap_hook_translate_name (waklog_phase1, NULL, NULL, APR_HOOK_FIRST);
1771 ap_hook_header_parser (waklog_phase2, NULL, NULL, APR_HOOK_FIRST);
1772 ap_hook_access_checker (waklog_phase3, NULL, NULL, APR_HOOK_FIRST);
1773 ap_hook_type_checker (waklog_phase6, NULL, NULL, APR_HOOK_FIRST);
1774 ap_hook_fixups (waklog_phase7, NULL, NULL, APR_HOOK_FIRST);
1775 ap_hook_log_transaction (waklog_phase9, NULL, NULL, APR_HOOK_FIRST);
1776 ap_hook_child_init (waklog_child_init, NULL, NULL, APR_HOOK_FIRST);
1777 ap_hook_post_read_request (waklog_phase0, NULL, NULL, APR_HOOK_FIRST);
1778 ap_hook_pre_connection (waklog_new_connection, NULL, NULL, APR_HOOK_FIRST);
1779 ap_hook_post_config (waklog_init_handler, NULL, NULL, APR_HOOK_MIDDLE);
1780 }
1781
1782
1783 module AP_MODULE_DECLARE_DATA waklog_module = {
1784 STANDARD20_MODULE_STUFF,
1785 waklog_create_dir_config, /* create per-dir conf structures */
1786 waklog_merge_dir_config, /* merge per-dir conf structures */
1787 waklog_create_server_config, /* create per-server conf structures */
1788 waklog_merge_dir_config, /* merge per-server conf structures */
1789 waklog_cmds, /* table of configuration directives */
1790 waklog_register_hooks /* register hooks */
1791 };
1792 #endif