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