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