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