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