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