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