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