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