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