02719563018122e38592cc14ad45999cf20e162f
[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 #define command(name, func, var, type, usage) \
42 { name, func, \
43 (void*)XtOffsetOf(waklog_commands, var), \
44 OR_AUTHCFG | RSRC_CONF, type, usage }
45
46 /********************* APACHE2 ******************************************************************************/
47 #else
48 #include <apr_strings.h>
49 #include <apr_base64.h>
50 //#include <ap_compat.h>
51 #define ap_pcalloc apr_pcalloc
52 #define ap_pdupstr apr_pdupstr
53 #define ap_pstrdup apr_pstrdup
54
55 module AP_MODULE_DECLARE_DATA waklog_module;
56
57 #define MK_POOL apr_pool_t
58 #define MK_TABLE_GET apr_table_get
59 #define MK_TABLE_SET apr_table_set
60 #include "unixd.h"
61 extern unixd_config_rec unixd_config;
62 #define ap_user_id unixd_config.user_id
63 #define ap_group_id unixd_config.group_id
64 #define ap_user_name unixd_config.user_name
65 #define command(name, func, var, type, usage) \
66 AP_INIT_ ## type (name, (void*) func, \
67 NULL, \
68 RSRC_CONF | ACCESS_CONF, usage)
69 typedef struct
70 {
71 int dummy;
72 }
73 child_info;
74
75 const char *userdata_key = "waklog_init";
76 #endif /* STANDARD20_MODULE_STUFF */
77 /**************************************************************************************************/
78
79 #include <krb5.h>
80 #include <stropts.h>
81 #include <afs/venus.h>
82 #include <afs/auth.h>
83 #include <afs/dirpath.h>
84 #include <afs/ptuser.h>
85 #include <rx/rxkad.h>
86
87 #define TKT_LIFE ( 12 * 60 * 60 )
88 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
89
90 #define WAKLOG_ON 1
91 #define WAKLOG_OFF 2
92 #define WAKLOG_UNSET 0
93
94 #ifdef WAKLOG_DEBUG
95 #undef APLOG_DEBUG
96 #define APLOG_DEBUG APLOG_ERR
97 #endif
98
99 #ifndef CELL_IN_PRINCIPAL
100 int cell_in_principal = 1;
101 #else
102 int cell_in_principal = 0;
103 #endif
104
105 /* this is used to turn off pag generation for the backround worker child during startup */
106 int pag_for_children = 1;
107
108 typedef struct
109 {
110 int forked;
111 int configured;
112 int protect;
113 int usertokens;
114 char *keytab;
115 char *principal;
116 char *default_principal;
117 char *default_keytab;
118 char *afs_cell;
119 char *path;
120 MK_POOL *p;
121 }
122 waklog_config;
123
124 typedef struct
125 {
126 struct ktc_token token;
127 char clientprincipal[MAXNAMELEN];
128 krb5_context kcontext;
129 krb5_ccache ccache;
130 struct ktc_principal server;
131 struct ktc_principal client;
132 int pr_init;
133 } waklog_child_config;
134
135 waklog_child_config child;
136
137 struct tokencache_ent {
138 char clientprincipal[MAXNAMELEN];
139 struct ktc_token token;
140 struct ktc_principal client;
141 struct ktc_principal server;
142 time_t lastused;
143 int persist;
144 };
145
146 #define SHARED_TABLE_SIZE 512
147
148 struct sharedspace_s {
149 int renewcount;
150 struct tokencache_ent sharedtokens[SHARED_TABLE_SIZE];
151 };
152
153 struct sharedspace_s *sharedspace = NULL;
154
155 struct renew_ent {
156 char *keytab;
157 char *principal;
158 int lastrenewed;
159 };
160
161 #ifdef use_pthreads
162 pthread_rwlock_t *sharedlock = NULL;
163 #else
164 rwlock_t *sharedlock = NULL;
165 #endif
166
167 struct renew_ent renewtable[SHARED_TABLE_SIZE];
168
169 int renewcount = 0;
170
171 module waklog_module;
172
173
174 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
175
176 #include <krb5.h>
177
178 #if defined(sun)
179 #include <sys/ioccom.h>
180 #endif /* sun */
181 #include <stropts.h>
182 #include <afs/venus.h>
183 #include <afs/auth.h>
184 #include <afs/dirpath.h>
185 #include <afs/ptuser.h>
186 #include <rx/rxkad.h>
187
188 #define KEYTAB "/etc/keytab.wwwserver"
189 #define PRINCIPAL "someplacewwwserver"
190 #define AFS_CELL "someplace.edu"
191
192 /* If there's an error, retry more aggressively */
193 #define ERR_SLEEP_TIME 5*60
194
195
196 #define K5PATH "FILE:/tmp/waklog.creds.k5"
197
198 static void
199 log_error(const char *file, int line, int level, int status,
200 const server_rec *s, const char *fmt, ...)
201 {
202 char errstr[1024];
203 va_list ap;
204
205 va_start(ap, fmt);
206 vsnprintf(errstr, sizeof(errstr), fmt, ap);
207 va_end(ap);
208
209 #ifdef STANDARD20_MODULE_STUFF
210 ap_log_error(file, line, level | APLOG_NOERRNO, status, s, "%s", errstr);
211 #else
212 ap_log_error(file, line, level | APLOG_NOERRNO, s, "%s", errstr);
213 #endif
214
215 }
216
217 static void *
218 waklog_create_server_config( MK_POOL *p, server_rec *s )
219 {
220 waklog_config *cfg;
221
222 cfg = (waklog_config *)ap_pcalloc( p, sizeof( waklog_config ));
223 cfg->p = p;
224 cfg->forked = 0;
225 cfg->configured = 0;
226 cfg->protect = 0;
227 cfg->keytab = KEYTAB;
228 cfg->principal = PRINCIPAL;
229 cfg->afs_cell = AFS_CELL;
230
231 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: server config created." );
232
233 return( cfg );
234 }
235
236
237 static const char *
238 set_waklog_protect( cmd_parms *params, void *mconfig, int flag )
239 {
240 waklog_config *cfg;
241
242 getModConfig(cfg, params->server );
243
244 cfg->protect = flag;
245 cfg->configured = 1;
246 log_error( APLOG_MARK, APLOG_DEBUG, 0, params->server, "mod_waklog: waklog_protect set" );
247 return( NULL );
248 }
249
250
251 static const char *
252 set_waklog_keytab( cmd_parms *params, void *mconfig, char *file )
253 {
254 waklog_config *cfg;
255
256 getModConfig(cfg, params->server );
257
258 log_error( APLOG_MARK, APLOG_INFO, 0, params->server,
259 "mod_waklog: will use keytab: %s", file );
260
261 cfg->keytab = ap_pstrdup ( params->pool, file );
262 cfg->configured = 1;
263 return( NULL );
264 }
265
266
267 static const char *
268 set_waklog_use_principal( cmd_parms *params, void *mconfig, char *file )
269 {
270 waklog_config *cfg;
271
272 getModConfig(cfg, params->server );
273
274 log_error( APLOG_MARK, APLOG_INFO, 0, params->server,
275 "mod_waklog: will use principal: %s", file );
276
277 cfg->principal = ap_pstrdup ( params->pool, file );
278 cfg->configured = 1;
279 return( NULL );
280 }
281
282
283 static const char *
284 set_waklog_use_afs_cell( cmd_parms *params, void *mconfig, char *file )
285 {
286 waklog_config *cfg;
287
288 getModConfig(cfg, params->server );
289
290 log_error( APLOG_MARK, APLOG_INFO, 0, params->server,
291 "mod_waklog: will use afs_cell: %s", file );
292
293 cfg->afs_cell = ap_pstrdup( params->pool, file );
294 cfg->configured = 1;
295 return( NULL );
296 }
297
298
299 static void
300 #ifdef STANDARD20_MODULE_STUFF
301 waklog_child_init(MK_POOL *p, server_rec *s)
302 #else
303 waklog_child_init(server_rec *s, MK_POOL *p)
304 #endif
305 {
306
307 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
308 "mod_waklog: child_init called" );
309
310 memset( &child.token, 0, sizeof( struct ktc_token ) );
311
312 setpag();
313
314 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
315 "mod_waklog: child_init returned" );
316
317 return;
318 }
319
320 typedef struct {
321 int wak_protect;
322 char *wak_keytab;
323 char *wak_ktprinc;
324 char *wak_afscell;
325 } waklog_commands;
326
327 command_rec waklog_cmds[ ] =
328 {
329 command("WaklogProtected", set_waklog_protect, wak_protect, FLAG, "enable waklog on a location or directory basis"),
330
331 command("WaklogKeytab", set_waklog_keytab, wak_keytab, TAKE1, "Use the supplied keytab rather than the default"),
332
333 command("WaklogUseKeytabPrincipal", set_waklog_use_principal, wak_ktprinc, TAKE1, "Use the supplied keytab principal rather than the default"),
334
335 command("WaklogUseAFSCell", set_waklog_use_afs_cell, wak_afscell, TAKE1, "Use the supplied AFS cell rather than the default"),
336
337 { NULL }
338 };
339
340
341 static int
342 token_cleanup( void *data )
343 {
344 request_rec *r = (request_rec *)data;
345
346 if ( child.token.ticketLen ) {
347 memset( &child.token, 0, sizeof( struct ktc_token ) );
348
349 ktc_ForgetAllTokens();
350
351 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
352 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d", getpid() );
353 }
354 return 0;
355 }
356
357
358 static int
359 waklog_kinit( server_rec *s )
360 {
361 krb5_error_code kerror = 0;
362 krb5_context kcontext = NULL;
363 krb5_principal kprinc = NULL;
364 krb5_get_init_creds_opt kopts;
365 krb5_creds v5creds;
366 krb5_ccache kccache = NULL;
367 krb5_keytab keytab = NULL;
368 char ktbuf[ MAX_KEYTAB_NAME_LEN + 1 ];
369 int i;
370 waklog_config *cfg;
371
372 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
373 "mod_waklog: waklog_kinit called: pid: %d", getpid() );
374
375 getModConfig(cfg, s);
376
377 if (( kerror = krb5_init_context( &kcontext ))) {
378 log_error( APLOG_MARK, APLOG_ERR, 0, s,
379 "mod_waklog: %s", (char *)error_message( kerror ));
380
381 goto cleanup;
382 }
383
384 /* use the path */
385 if (( kerror = krb5_cc_resolve( kcontext, K5PATH, &kccache )) != 0 ) {
386 log_error( APLOG_MARK, APLOG_ERR, 0, s,
387 "mod_waklog: %s", (char *)error_message( kerror ));
388
389 goto cleanup;
390 }
391
392 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
393 "mod_waklog: principal: %s", cfg->principal );
394
395 if (( kerror = krb5_parse_name( kcontext, cfg->principal, &kprinc ))) {
396 log_error( APLOG_MARK, APLOG_ERR, 0, s,
397 "mod_waklog: %s", (char *)error_message( kerror ));
398
399 goto cleanup;
400 }
401
402 krb5_get_init_creds_opt_init( &kopts );
403 krb5_get_init_creds_opt_set_tkt_life( &kopts, TKT_LIFE );
404 krb5_get_init_creds_opt_set_renew_life( &kopts, 0 );
405 krb5_get_init_creds_opt_set_forwardable( &kopts, 1 );
406 krb5_get_init_creds_opt_set_proxiable( &kopts, 0 );
407
408 /* keytab from config */
409 strncpy( ktbuf, cfg->keytab, sizeof( ktbuf ) - 1 );
410
411 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
412 "mod_waklog: waklog_kinit using: %s", ktbuf );
413
414 if (( kerror = krb5_kt_resolve( kcontext, ktbuf, &keytab )) != 0 ) {
415 log_error( APLOG_MARK, APLOG_ERR, 0, s,
416 "mod_waklog:krb5_kt_resolve %s", (char *)error_message( kerror ));
417
418 goto cleanup;
419 }
420
421 memset( (char *)&v5creds, 0, sizeof(v5creds));
422
423 /* get the krbtgt */
424 if (( kerror = krb5_get_init_creds_keytab( kcontext, &v5creds,
425 kprinc, keytab, 0, NULL, &kopts ))) {
426
427 log_error( APLOG_MARK, APLOG_ERR, 0, s,
428 "mod_waklog:krb5_get_init_creds_keytab %s", (char *)error_message( kerror ));
429
430 goto cleanup;
431 }
432
433 if (( kerror = krb5_cc_initialize( kcontext, kccache, kprinc )) != 0 ) {
434 log_error( APLOG_MARK, APLOG_ERR, 0, s,
435 "mod_waklog:krb5_cc_initialize %s", (char *)error_message( kerror ));
436
437 goto cleanup;
438 }
439
440 kerror = krb5_cc_store_cred( kcontext, kccache, &v5creds );
441 krb5_free_cred_contents( kcontext, &v5creds );
442 if ( kerror != 0 ) {
443 log_error( APLOG_MARK, APLOG_ERR, 0, s,
444 "mod_waklog: %s", (char *)error_message( kerror ));
445
446 goto cleanup;
447 }
448
449 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
450 "mod_waklog: waklog_kinit success" );
451
452 cleanup:
453 if ( keytab )
454 (void)krb5_kt_close( kcontext, keytab );
455 if ( kprinc )
456 krb5_free_principal( kcontext, kprinc );
457 if ( kccache )
458 krb5_cc_close( kcontext, kccache );
459 if ( kcontext )
460 krb5_free_context( kcontext );
461
462 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
463 "mod_waklog: waklog_kinit: exiting" );
464
465 return( kerror );
466 }
467
468
469 static void
470 waklog_aklog( request_rec *r )
471 {
472 int rc;
473 char buf[ MAXKTCTICKETLEN ];
474 const char *k5path = NULL;
475 krb5_error_code kerror;
476 krb5_context kcontext = NULL;
477 krb5_creds increds;
478 krb5_creds *v5credsp = NULL;
479 krb5_ccache kccache = NULL;
480 struct ktc_principal server = { "afs", "", "" };
481 struct ktc_principal client;
482 struct ktc_token token;
483 waklog_config *cfg;
484 int buflen;
485
486 k5path = MK_TABLE_GET( r->subprocess_env, "KRB5CCNAME" );
487
488 log_error( APLOG_MARK, APLOG_INFO, 0, r->server,
489 "mod_waklog: waklog_aklog called: k5path: %s", k5path );
490
491 if ( k5path == NULL ) {
492 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
493 "mod_waklog: waklog_aklog giving up" );
494 goto cleanup;
495 }
496
497 /*
498 ** Get/build creds from file/tgs, then see if we need to SetToken
499 */
500
501 if (( kerror = krb5_init_context( &kcontext ))) {
502 /* Authentication Required ( kerberos error ) */
503 log_error( APLOG_MARK, APLOG_ERR, 0, r->server,
504 (char *)error_message( kerror ));
505
506 goto cleanup;
507 }
508
509 memset( (char *)&increds, 0, sizeof(increds));
510
511 getModConfig(cfg, r->server );
512
513 /* afs/<cell> or afs */
514 strncpy( buf, "afs", sizeof( buf ) - 1 );
515 if ( strcmp( cfg->afs_cell, AFS_CELL ) ) {
516 strncat( buf, "/" , sizeof( buf ) - strlen( buf ) - 1 );
517 strncat( buf, cfg->afs_cell, sizeof( buf ) - strlen( buf ) - 1 );
518 }
519
520 /* set server part */
521 if (( kerror = krb5_parse_name( kcontext, buf, &increds.server ))) {
522 log_error( APLOG_MARK, APLOG_ERR, 0, r->server,
523 (char *)error_message( kerror ));
524
525 goto cleanup;
526 }
527
528 if (( kerror = krb5_cc_resolve( kcontext, k5path, &kccache )) != 0 ) {
529 log_error( APLOG_MARK, APLOG_ERR, 0, r->server,
530 (char *)error_message( kerror ));
531
532 goto cleanup;
533 }
534
535 /* set client part */
536 krb5_cc_get_principal( kcontext, kccache, &increds.client );
537
538 increds.times.endtime = 0;
539 /* Ask for DES since that is what V4 understands */
540 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
541
542 /* get the V5 credentials */
543 if (( kerror = krb5_get_credentials( kcontext, 0, kccache,
544 &increds, &v5credsp ) ) ) {
545 log_error( APLOG_MARK, APLOG_ERR, 0, r->server,
546 "mod_waklog: krb5_get_credentials: %s", error_message( kerror ));
547 goto cleanup;
548 }
549
550 /* don't overflow */
551 if ( v5credsp->ticket.length >= MAXKTCTICKETLEN ) { /* from krb524d.c */
552 log_error( APLOG_MARK, APLOG_ERR, 0, r->server,
553 "mod_waklog: ticket size (%d) too big to fake", v5credsp->ticket.length );
554 goto cleanup;
555 }
556
557 /* assemble the token */
558 memset( &token, 0, sizeof( struct ktc_token ) );
559
560 token.startTime = v5credsp->times.starttime ? v5credsp->times.starttime : v5credsp->times.authtime;
561 token.endTime = v5credsp->times.endtime;
562 memmove( &token.sessionKey, v5credsp->keyblock.contents, v5credsp->keyblock.length );
563 token.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
564 token.ticketLen = v5credsp->ticket.length;
565 memmove( token.ticket, v5credsp->ticket.data, token.ticketLen );
566
567 /* make sure we have to do this */
568 if ( child.token.kvno != token.kvno ||
569 child.token.ticketLen != token.ticketLen ||
570 (memcmp( &child.token.sessionKey, &token.sessionKey,
571 sizeof( token.sessionKey ) )) ||
572 (memcmp( child.token.ticket, token.ticket, token.ticketLen )) ) {
573
574 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
575 "mod_waklog: client: %s", buf );
576
577 /* build the name */
578 memmove( buf, v5credsp->client->data[0].data,
579 min( v5credsp->client->data[0].length, MAXKTCNAMELEN - 1 ) );
580 buf[ v5credsp->client->data[0].length ] = '\0';
581 if ( v5credsp->client->length > 1 ) {
582 strncat( buf, ".", sizeof( buf ) - strlen( buf ) - 1 );
583 buflen = strlen( buf );
584 memmove( buf + buflen, v5credsp->client->data[1].data,
585 min( v5credsp->client->data[1].length, MAXKTCNAMELEN - strlen( buf ) - 1 ) );
586 buf[ buflen + v5credsp->client->data[1].length ] = '\0';
587 }
588
589 /* assemble the client */
590 strncpy( client.name, buf, sizeof( client.name ) - 1 );
591 strncpy( client.instance, "", sizeof( client.instance) - 1 );
592 memmove( buf, v5credsp->client->realm.data,
593 min( v5credsp->client->realm.length, MAXKTCNAMELEN - 1 ) );
594 buf[ v5credsp->client->realm.length ] = '\0';
595 strncpy( client.cell, buf, sizeof( client.cell ) - 1 );
596
597 /* assemble the server's cell */
598 strncpy( server.cell, cfg->afs_cell , sizeof( server.cell ) - 1 );
599
600 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
601 "mod_waklog: server: name=%s, instance=%s, cell=%s",
602 server.name, server.instance, server.cell );
603
604 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
605 "mod_waklog: client: name=%s, instance=%s, cell=%s",
606 client.name, client.instance, client.cell );
607
608 /* use the path */
609
610 /* rumor: we have to do this for AIX 4.1.4 with AFS 3.4+ */
611 write( 2, "", 0 );
612
613 if ( ( rc = ktc_SetToken( &server, &token, &client, 0 ) ) ) {
614 log_error( APLOG_MARK, APLOG_ERR, 0, r->server,
615 "mod_waklog: settoken returned %d", rc );
616 goto cleanup;
617 }
618
619 /* save this */
620 memmove( &child.token, &token, sizeof( struct ktc_token ) );
621
622 /* we'll need to unlog when this connection is done. */
623 #ifndef STANDARD20_MODULE_STUFF
624 ap_register_cleanup( r->pool, (void *)r, token_cleanup, ap_null_cleanup );
625 #else
626 /* FIXME!!!! */
627 #endif
628 }
629
630 cleanup:
631 if ( v5credsp )
632 krb5_free_cred_contents( kcontext, v5credsp );
633 if ( increds.client )
634 krb5_free_principal( kcontext, increds.client );
635 if ( increds.server )
636 krb5_free_principal( kcontext, increds.server );
637 if ( kccache )
638 krb5_cc_close( kcontext, kccache );
639 if ( kcontext )
640 krb5_free_context( kcontext );
641
642 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
643 "mod_waklog: finished with waklog_aklog" );
644
645 return;
646
647 }
648
649 static int
650 waklog_child_routine( void *s, child_info *pinfo )
651 {
652 if ( !getuid() ) {
653 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
654 "mod_waklog: waklog_child_routine called as root" );
655
656 /* this was causing the credential file to get owned by root */
657 #ifdef STANDARD20_MODULE_STUFF
658 setgid(ap_group_id);
659 setuid(ap_user_id);
660 #endif
661 }
662
663 while( 1 ) {
664 waklog_kinit( s );
665 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
666 "mod_waklog: child_routine sleeping" );
667 sleep( SLEEP_TIME );
668 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
669 "mod_waklog: slept, calling waklog_kinit" );
670 }
671
672 }
673
674 #ifdef STANDARD20_MODULE_STUFF
675 static int
676 waklog_init_handler(apr_pool_t *p, apr_pool_t *plog,
677 apr_pool_t *ptemp, server_rec *s)
678 {
679 int rv;
680 extern char *version;
681 apr_proc_t *proc;
682 waklog_config *cfg;
683 void *data;
684
685 getModConfig(cfg, s);
686
687 /* initialize_module() will be called twice, and if it's a DSO
688 * then all static data from the first call will be lost. Only
689 * set up our static data on the second call.
690 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
691 apr_pool_userdata_get(&data, userdata_key, s->process->pool);
692
693 if (!data) {
694 apr_pool_userdata_set((const void *)1, userdata_key,
695 apr_pool_cleanup_null, s->process->pool);
696 } else {
697 log_error( APLOG_MARK, APLOG_INFO, 0, s,
698 "mod_waklog: version %s initialized.", version );
699
700 proc = (apr_proc_t *)ap_pcalloc( s->process->pool, sizeof(apr_proc_t));
701
702 rv = apr_proc_fork(proc, s->process->pool);
703
704 if (rv == APR_INCHILD) {
705 waklog_child_routine(s, NULL);
706 } else {
707 apr_pool_note_subprocess(s->process->pool, proc, APR_KILL_ALWAYS);
708 }
709 /* parent and child */
710 cfg->forked = proc->pid;
711 }
712 return 0;
713 }
714 #else
715 static void
716 waklog_init( server_rec *s, MK_POOL *p )
717 {
718 extern char *version;
719 int pid;
720
721 log_error( APLOG_MARK, APLOG_INFO, 0, s,
722 "mod_waklog: version %s initialized.", version );
723
724 pid = ap_bspawn_child( p, waklog_child_routine, s, kill_always,
725 NULL, NULL, NULL );
726
727 log_error( APLOG_MARK, APLOG_DEBUG, 0, s,
728 "mod_waklog: ap_bspawn_child: %d.", pid );
729 }
730 #endif
731
732 static int
733 waklog_phase0( request_rec *r )
734 {
735 waklog_config *cfg;
736
737 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
738 "mod_waklog: phase0 called" );
739
740 getModConfig(cfg, r->server );
741
742 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
743 "mod_waklog: phase0, checking cfg->protect" );
744 if ( !cfg->protect ) {
745 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
746 "mod_waklog: phase0 declining" );
747 return( DECLINED );
748 }
749
750 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
751 "mod_waklog: phase0, NOT setting environment variable" );
752 /* set our environment variable */
753 apr_table_set( r->subprocess_env, "KRB5CCNAME", K5PATH );
754
755 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
756 "mod_waklog: phase0, checking child.token.ticketLen" );
757 /* do this only if we are still unauthenticated */
758 if ( !child.token.ticketLen ) {
759
760 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
761 "mod_waklog: phase0, calling waklog_aklog" );
762 /* stuff the credentials into the kernel */
763 waklog_aklog( r );
764 }
765
766 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
767 "mod_waklog: phase0 returning" );
768 return DECLINED;
769 }
770
771
772 static int
773 waklog_phase7( request_rec *r )
774 {
775 waklog_config *cfg;
776
777 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
778 "mod_waklog: phase7 called" );
779
780 getModConfig(cfg, r->server );
781
782 if ( !cfg->protect ) {
783 return( DECLINED );
784 }
785
786 /* stuff the credentials into the kernel */
787
788 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
789 "mod_waklog: phase7, calling waklog_aklog" );
790 waklog_aklog( r );
791
792 log_error( APLOG_MARK, APLOG_DEBUG, 0, r->server,
793 "mod_waklog: phase7 returning" );
794
795 return DECLINED;
796 }
797
798
799 static
800 #ifdef STANDARD20_MODULE_STUFF
801 int
802 #else
803 void
804 #endif
805 waklog_new_connection (conn_rec * c
806 #ifdef STANDARD20_MODULE_STUFF
807 , void *dummy
808 #endif
809 )
810 {
811
812 waklog_commands *cfg;
813
814 log_error (APLOG_MARK, APLOG_DEBUG, 0, c->base_server,
815 "mod_waklog: new_connection called: pid: %d", getpid ());
816 /*
817 getModConfig(cfg, c->base_server);
818
819 if ( cfg->default_principal ) {
820 log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "mod_waklog: new conn setting default user %s",
821 cfg->default_principal);
822 set_auth( c->base_server, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
823 }
824 */
825
826 return
827 #ifdef STANDARD20_MODULE_STUFF
828 0
829 #endif
830 ;
831 }
832
833
834 /*
835 ** Here's a quick explaination for phase0 and phase2:
836 ** Apache does a stat() on the path between phase0 and
837 ** phase2, and must by ACLed rl to succeed. So, at
838 ** phase0 we acquire credentials for umweb:servers from
839 ** a keytab, and at phase2 we must ensure we remove them.
840 **
841 ** Failure to "unlog" would be a security risk.
842 */
843 static int
844 waklog_phase2 (request_rec * r)
845 {
846
847 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
848 "mod_waklog: phase2 called");
849
850 if (child.token.ticketLen)
851 {
852 memset (&child.token, 0, sizeof (struct ktc_token));
853
854 ktc_ForgetAllTokens ();
855
856 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
857 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
858 getpid ());
859 }
860
861 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
862 "mod_waklog: phase2 returning");
863
864 return DECLINED;
865 }
866
867 #ifndef STANDARD20_MODULE_STUFF
868 module MODULE_VAR_EXPORT waklog_module = {
869 STANDARD_MODULE_STUFF,
870 waklog_init, /* module initializer */
871 #if 0
872 waklog_create_dir_config, /* create per-dir config structures */
873 #else /* 0 */
874 NULL, /* create per-dir config structures */
875 #endif /* 0 */
876 NULL, /* merge per-dir config structures */
877 waklog_create_server_config, /* create per-server config structures */
878 NULL, /* merge per-server config structures */
879 waklog_cmds, /* table of config file commands */
880 NULL, /* [#8] MIME-typed-dispatched handlers */
881 NULL, /* [#1] URI to filename translation */
882 NULL, /* [#4] validate user id from request */
883 NULL, /* [#5] check if the user is ok _here_ */
884 NULL, /* [#3] check access by host address */
885 NULL, /* [#6] determine MIME type */
886 waklog_phase7, /* [#7] pre-run fixups */
887 NULL, /* [#9] log a transaction */
888 waklog_phase2, /* [#2] header parser */
889 waklog_child_init, /* child_init */
890 NULL, /* child_exit */
891 waklog_phase0 /* [#0] post read-request */
892 #ifdef EAPI
893 ,NULL, /* EAPI: add_module */
894 NULL, /* EAPI: remove_module */
895 NULL, /* EAPI: rewrite_command */
896 waklog_new_connection /* EAPI: new_connection */
897 #endif
898 };
899 #else
900 static void
901 waklog_register_hooks (apr_pool_t * p)
902 {
903 ap_hook_header_parser (waklog_phase2, NULL, NULL, APR_HOOK_FIRST);
904 ap_hook_fixups (waklog_phase7, NULL, NULL, APR_HOOK_FIRST);
905 ap_hook_child_init (waklog_child_init, NULL, NULL, APR_HOOK_FIRST);
906 ap_hook_post_read_request (waklog_phase0, NULL, NULL, APR_HOOK_FIRST);
907 ap_hook_pre_connection (waklog_new_connection, NULL, NULL, APR_HOOK_FIRST);
908 ap_hook_post_config (waklog_init_handler, NULL, NULL, APR_HOOK_MIDDLE);
909 }
910
911
912 module AP_MODULE_DECLARE_DATA waklog_module =
913 {
914 STANDARD20_MODULE_STUFF,
915 NULL, /* create per-dir conf structures */
916 NULL, /* merge per-dir conf structures */
917 waklog_create_server_config, /* create per-server conf structures */
918 NULL, /* merge per-server conf structures */
919 waklog_cmds, /* table of configuration directives */
920 waklog_register_hooks /* register hooks */
921 };
922 #endif
923