1 #define _LARGEFILE64_SOURCE
5 #include "http_config.h"
7 #include "http_protocol.h"
8 #include "http_request.h"
16 #include <sys/types.h>
20 #error "make sure you include the right stuff here"
24 #define MAXNAMELEN 1024
27 #ifdef STANDARD20_MODULE_STUFF
31 /********************* APACHE1 ******************************************************************************/
33 #include "ap_config.h"
35 #include <sys/ioccom.h>
37 #include <http_conf_globals.h>
39 #define MK_TABLE_GET ap_table_get
40 #define MK_TABLE_SET ap_table_set
41 #define command(name, func, var, type, usage) \
44 RSRC_CONF | ACCESS_CONF , type, usage }
47 /********************* APACHE2 ******************************************************************************/
49 #include <apr_strings.h>
50 #include <apr_base64.h>
51 #define ap_pcalloc apr_pcalloc
52 #define ap_pdupstr apr_pdupstr
53 #define ap_pstrdup apr_pstrdup
54 #define MK_POOL apr_pool_t
55 #define MK_TABLE_GET apr_table_get
56 #define MK_TABLE_SET apr_table_set
58 extern unixd_config_rec unixd_config
;
59 #define ap_user_id unixd_config.user_id
60 #define ap_group_id unixd_config.group_id
61 #define ap_user_name unixd_config.user_name
62 #define command(name, func, var, type, usage) \
63 AP_INIT_ ## type (name, (void*) func, \
65 RSRC_CONF | ACCESS_CONF, usage)
66 module AP_MODULE_DECLARE_DATA waklog_module
;
67 typedef struct { int dummy
; } child_info
;
68 const char *userdata_key
= "waklog_init";
71 /**************************************************************************************************/
75 #include <afs/venus.h>
77 #include <afs/dirpath.h>
78 #include <afs/ptuser.h>
81 #define TKT_LIFE ( 12 * 60 * 60 )
82 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
86 #define WAKLOG_UNSET 0
90 #define APLOG_DEBUG APLOG_ERR
93 /* this is used to turn off pag generation for the backround worker child during startup */
94 int pag_for_children
= 1;
102 int cell_in_principal
;
103 int disable_token_cache
;
106 char *default_principal
;
107 char *default_keytab
;
116 struct ktc_token token
;
117 char clientprincipal
[MAXNAMELEN
];
118 krb5_context kcontext
;
120 struct ktc_principal server
;
121 struct ktc_principal client
;
123 } waklog_child_config
;
125 waklog_child_config child
;
127 struct tokencache_ent
{
128 char clientprincipal
[MAXNAMELEN
];
129 struct ktc_token token
;
130 struct ktc_principal client
;
131 struct ktc_principal server
;
136 #define SHARED_TABLE_SIZE 512
138 struct sharedspace_s
{
140 struct tokencache_ent sharedtokens
[SHARED_TABLE_SIZE
];
143 struct sharedspace_s
*sharedspace
= NULL
;
152 pthread_rwlock_t
*sharedlock
= NULL
;
154 rwlock_t
*sharedlock
= NULL
;
157 struct renew_ent renewtable
[SHARED_TABLE_SIZE
];
163 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
168 #include <sys/ioccom.h>
171 #include <afs/venus.h>
172 #include <afs/auth.h>
173 #include <afs/dirpath.h>
174 #include <afs/ptuser.h>
175 #include <rx/rxkad.h>
179 log_error (const char *file
, int line
, int level
, int status
,
180 const server_rec
* s
, const char *fmt
, ...)
186 vsnprintf (errstr
, 1024, fmt
, ap
);
190 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
192 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
197 waklog_config
*retrieve_config(request_rec
*r
) {
202 if ( r
&& r
->main
) {
210 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
213 getModConfig (cfg
, r
->server
);
220 /* set_auth -- sets the tokens of the current process to this user.
221 if "self" is set, it divines the user from the current requests' environment.
222 otherwise, it's gettng it from principal/keytab */
225 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
229 krb5_error_code kerror
= 0;
230 krb5_principal kprinc
= NULL
;
231 krb5_get_init_creds_opt kopts
;
234 struct ktc_principal server
= { "afs", "", "" };
235 struct ktc_principal client
;
236 struct ktc_token token
;
237 krb5_creds
*v5credsp
= NULL
;
238 krb5_keytab krb5kt
= NULL
;
239 char buf
[MAXNAMELEN
];
243 time_t oldest_time
= 0;
248 int cell_in_principal
;
250 int use_client_credentials
= 0;
252 char k5user
[MAXNAMELEN
];
256 k5path
= !r
? NULL
: MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
258 memset((char *) &increds
, 0, sizeof(increds
));
259 /* init some stuff if it ain't already */
261 if ( ! child
.kcontext
) {
262 kerror
= krb5_init_context(&child
.kcontext
);
265 if (!k5path
|| !*k5path
) {
266 k5path
= "MEMORY:tmpcache";
268 if ( ( ! child
.ccache
) && ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &child
.ccache
) ) ) {
269 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
273 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s",
274 self
, principal
? principal
: "NULL",
275 keytab
? keytab
: "NULL", storeonly
, k5path
? k5path
: "NULL");
277 /* pull the server config record that we care about... */
280 cfg
= retrieve_config(r
);
282 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
283 "mod_waklog: set_auth using no config" );
284 getModConfig (cfg
, s
);
288 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
293 /* pull out our principal name and stuff from the environment -- webauth better have sent
294 through. This here is also where you'd suck stuff out of KRB5CCNAME if we were
295 using something like Cosign */
297 if ( ! ( r
&& r
->connection
&& r
->user
)) {
298 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
299 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
==NULL
));
303 strncpy(k5user
, r
->user
, sizeof(k5user
));
305 /* the other thing we need is someone's password */
306 if ( ! ( k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" ) ) ) {
307 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cant do self auth without a secret");
311 /* we'll pick this up later after we've checked the cache and current state */
316 strncpy(k5user
, r
->user
, sizeof(k5user
));
318 } else if ( principal
) {
319 strncpy( k5user
, principal
, sizeof(k5user
));
322 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
? k5user
: "NULL");
325 /* see if we should just go ahead and ignore this call, since we already should be set to these
331 pthread_rwlock_rdlock( sharedlock
);
333 rw_rdlock( sharedlock
);
336 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
338 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
340 if ( ( !strcmp( k5user
,
341 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
342 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
344 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
350 /* copy the token out of the cache and into the child object */
352 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
353 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
354 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
355 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
357 /* set our last used time thing */
358 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
368 /* release the lock on the token cache */
370 pthread_rwlock_unlock( sharedlock
);
372 rw_unlock( sharedlock
);
376 /* release the lock on the token cache */
377 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
378 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
382 /* if this is something that was in the cache, and it's the same as the token we already have stored,
383 and we weren't calling this just to renew it... */
385 if ( usecached
&& indentical
) {
386 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
392 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
393 if (( ! usecached
) && ( k5user
)) {
395 /* clear out the creds structure */
396 memset((void *) &v5creds
, 0, sizeof(v5creds
));
398 /* create a principal out of our k5user string */
400 if ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) {
401 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror
) );
405 /* create the credentials options */
407 krb5_get_init_creds_opt_init ( &kopts
);
408 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
409 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
410 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
411 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
415 /* if we've been passed a keytab, we're going to be getting our credentials from it */
417 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
419 if ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) {
420 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
421 "mod_waklog: krb5_kt_resolve %s", error_message(kerror
) );
425 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
426 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
427 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
428 error_message(kerror
) );
434 /* if 'self' is set, we're going to use the credentials provided in the credential information */
435 /* if you're using CoSign, you'd actually just set the ccache to the KRB5CCNAME credentials */
436 /* and skip ahead... Our WebSSO is lame, but has a way for us to snarf the password out of */
437 /* the encrypted token for proxy-authentication stuff. We only hand out keys that allow this */
438 /* functionality to VERY special people. */
440 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
441 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
442 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
443 error_message(kerror
) );
444 /* nuke the password so it doesn't end up in core files */
445 memset(k5secret
, 0, sizeof(k5secret
));
449 memset(k5secret
, 0, sizeof(k5secret
));
452 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: no keytab, no self; assuming mod_auth_kerb or similar");
453 use_client_credentials
= 1;
456 /* initialize the credentials cache and store the stuff we just got */
457 if (!use_client_credentials
) {
458 if ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
)) {
459 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
460 error_message(kerror
));
464 if ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) {
465 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
466 error_message(kerror
));
471 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
474 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", error_message(kerror
));
478 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
480 /* now, to the 'aklog' portion of our program. */
482 strncpy( buf
, "afs", sizeof(buf
) - 1 );
484 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
485 for(attempt
= 0; attempt
<= 1; attempt
++) {
486 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
488 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
489 if (cell_in_principal
) {
490 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
491 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
494 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
496 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
497 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", error_message(kerror
));
501 if (use_client_credentials
) {
502 if (( kerror
= krb5_cc_resolve( child
.kcontext
, k5path
, &child
.ccache
)) != 0 ) {
503 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_resolve %s", error_message(kerror
));
508 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, child
.ccache
, &increds
.client
))) {
509 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s", error_message(kerror
));
513 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
515 increds
.times
.endtime
= 0;
517 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
519 if (kerror
= krb5_get_credentials (child
.kcontext
, 0, child
.ccache
, &increds
, &v5credsp
)) {
520 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
522 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
523 error_message(kerror
));
529 cfg
->cell_in_principal
= cell_in_principal
;
533 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
535 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
536 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
537 v5credsp
->ticket
.length
);
541 memset(&token
, 0, sizeof(struct ktc_token
));
543 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
544 token
.endTime
= v5credsp
->times
.endtime
;
546 memmove( &token
.sessionKey
, v5credsp
->keyblock
.contents
, v5credsp
->keyblock
.length
);
547 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
548 token
.ticketLen
= v5credsp
->ticket
.length
;
549 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
553 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
555 buf
[v5credsp
->client
->data
[0].length
] = '\0';
556 if ( v5credsp
->client
->length
> 1 ) {
557 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
558 buflen
= strlen(buf
);
559 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
560 min(v5credsp
->client
->data
[1].length
,
561 MAXKTCNAMELEN
- strlen(buf
) - 1));
562 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
565 /* assemble the client */
566 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
567 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
568 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
570 buf
[v5credsp
->client
->realm
.length
] = '\0';
571 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
573 /* assemble the server's cell */
574 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
576 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
578 /* fill out the AFS ID in the client name */
579 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
580 * strange things seem to happen. */
583 afs_int32 viceId
= 0;
585 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
587 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
588 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
590 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
593 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
597 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
598 server
.name
, server
.instance
, server
.cell
);
600 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
601 client
.name
, client
.instance
, client
.cell
);
603 /* copy the resulting stuff into the child structure */
605 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
606 memcpy(&child
.token
, &token
, sizeof(child
.token
));
607 memcpy(&child
.server
, &server
, sizeof(child
.server
));
608 memcpy(&child
.client
, &client
, sizeof(child
.client
));
610 /* stuff the resulting token-related stuff into our shared token cache */
611 /* note, that anything that was set from a keytab is "persistant", and is immune
612 * from LRU-aging. This is because nothing but the process that's running as root
613 * can update these, and it's running every hour or so and renewing these tokens.
614 * and we don't want them aged out.
617 mytime
= oldest_time
= time(0);
619 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
622 pthread_rwlock_wrlock(sharedlock
);
624 rw_wrlock(sharedlock
);
627 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
628 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
629 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
631 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
633 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
634 child
.clientprincipal
) ) {
635 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
636 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
637 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
638 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
639 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
645 if ( stored
== -1 ) {
646 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
647 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
648 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
649 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
650 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
651 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
656 pthread_rwlock_unlock(sharedlock
);
658 rw_unlock(sharedlock
);
661 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
662 child
.clientprincipal
);
664 } else if ( ! usecached
) {
665 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
674 /* don't ask. Something about AIX. We're leaving it here.*/
675 /* write(2, "", 0); */
677 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
679 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
680 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
681 error_message(rc
), k5user
);
682 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
683 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
684 error_message(rc
), k5user
);
691 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
692 if ( increds
.client
)
693 krb5_free_principal (child
.kcontext
, increds
.client
);
694 if ( increds
.server
)
695 krb5_free_principal (child
.kcontext
, increds
.server
);
697 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
699 krb5_free_principal (child
.kcontext
, kprinc
);
702 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
703 } else if ( kerror
) {
704 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, error_message(kerror
));
706 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
709 return kerror
? (int) kerror
: (int) rc
;
716 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
720 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
722 memset(cfg
, 0, sizeof(waklog_config
));
723 cfg
->path
= "(server)";
724 cfg
->protect
= WAKLOG_UNSET
;
725 cfg
->usertokens
= WAKLOG_UNSET
;
726 cfg
->disable_token_cache
= WAKLOG_UNSET
;
727 cfg
->keytab
= WAKLOG_UNSET
;
728 cfg
->principal
= WAKLOG_UNSET
;
729 cfg
->default_principal
= WAKLOG_UNSET
;
730 cfg
->default_keytab
= WAKLOG_UNSET
;
731 cfg
->afs_cell
= WAKLOG_UNSET
;
735 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
736 "mod_waklog: server config created.");
741 /* initialize with host-config information */
744 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
748 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
749 memset(cfg
, 0, sizeof(waklog_config
));
751 cfg
->path
= ap_pstrdup(p
, dir
);
752 cfg
->protect
= WAKLOG_UNSET
;
753 cfg
->usertokens
= WAKLOG_UNSET
;
754 cfg
->disable_token_cache
= WAKLOG_UNSET
;
755 cfg
->keytab
= WAKLOG_UNSET
;
756 cfg
->principal
= WAKLOG_UNSET
;
757 cfg
->default_principal
= WAKLOG_UNSET
;
758 cfg
->default_keytab
= WAKLOG_UNSET
;
759 cfg
->afs_cell
= WAKLOG_UNSET
;
766 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
768 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
769 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
770 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
772 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
774 merged
->path
= child
->path
!= WAKLOG_UNSET
? child
->path
: parent
->path
;
776 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
778 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
780 merged
->principal
= child
->principal
!= WAKLOG_UNSET
? child
->principal
: parent
->principal
;
782 merged
->keytab
= child
->keytab
!= WAKLOG_UNSET
? child
->keytab
: parent
->keytab
;
784 merged
->default_keytab
= child
->default_keytab
!= WAKLOG_UNSET
? child
->default_keytab
: parent
->default_keytab
;
786 merged
->default_principal
= child
->default_principal
!= WAKLOG_UNSET
? child
->default_principal
: parent
->default_principal
;
788 merged
->afs_cell
= child
->afs_cell
!= WAKLOG_UNSET
? child
->afs_cell
: parent
->afs_cell
;
790 return (void *) merged
;
794 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
796 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
797 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
798 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
800 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
802 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
804 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
806 merged
->keytab
= nconf
->keytab
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->keytab
) :
807 ( nconf
->keytab
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->keytab
) );
809 merged
->principal
= nconf
->principal
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->principal
) :
810 ( nconf
->principal
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->principal
) );
812 merged
->afs_cell
= nconf
->afs_cell
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->afs_cell
) :
813 ( nconf
->afs_cell
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->afs_cell
) );
815 merged
->default_keytab
= nconf
->default_keytab
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->default_keytab
) :
816 ( nconf
->default_keytab
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->default_keytab
) );
818 merged
->default_principal
= nconf
->default_principal
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->default_principal
) :
819 ( nconf
->default_principal
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->default_principal
) );
822 return (void *) merged
;
827 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
829 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
830 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
834 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
835 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
840 /* this adds a principal/keytab pair to get their tokens renewed by the
841 child process every few centons. */
843 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
847 if ( renewcount
>= SHARED_TABLE_SIZE
) {
848 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
849 decrease your tokens.");
853 /* check to see if it's already there */
855 for ( i
= 0; i
< renewcount
; i
++ ) {
856 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
861 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
862 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
863 renewtable
[renewcount
].lastrenewed
= 0;
869 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
871 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
872 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
874 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
875 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
877 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
878 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
880 add_to_renewtable(params
->pool
, keytab
, principal
);
888 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
890 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
891 waklog_config
*waklog_srvconfig
=
892 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
894 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
895 "mod_waklog: will use afs_cell: %s", file
);
897 waklog_srvconfig
->cell_in_principal
= 0;
898 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
899 waklog_srvconfig
->configured
= 1;
901 if (waklog_mconfig
!= NULL
) {
902 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
903 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
904 waklog_mconfig
->configured
= 1;
910 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
912 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
913 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
915 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
917 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
918 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
920 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
921 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
923 /* this also gets set at the server level */
924 if ( mconfig
&& ( ! cfg
->path
) ) {
925 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
926 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
928 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
929 return "Unable to set DefaultPrincipal outside of top level config!";
932 add_to_renewtable( params
->pool
, keytab
, principal
);
940 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
942 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
943 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
945 cfg
->usertokens
= flag
;
949 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
950 "mod_waklog: waklog_use_user_tokens set");
956 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
958 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
959 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
961 cfg
->disable_token_cache
= flag
;
965 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
966 "mod_waklog: waklog_disable_token_cache set");
972 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
974 apr_status_t
waklog_child_exit( void *sr
) {
976 server_rec
*s
= (server_rec
*) sr
;
979 if ( child
.ccache
) {
980 krb5_cc_close(child
.kcontext
, child
.ccache
);
983 if ( child
.kcontext
) {
984 krb5_free_context(child
.kcontext
);
987 /* forget our tokens */
989 ktc_ForgetAllTokens ();
991 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
992 "mod_waklog: waklog_child_exit complete");
1002 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1004 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1008 krb5_error_code code
;
1013 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1015 if ( !sharedspace
) {
1016 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1020 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1022 memset (&child
, 0, sizeof(child
));
1024 if ( code
= krb5_init_context(&child
.kcontext
) ) {
1025 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1028 if ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) {
1029 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1032 if ( pag_for_children
) {
1036 getModConfig (cfg
, s
);
1038 if ( cfg
->default_principal
!= WAKLOG_UNSET
) {
1039 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1040 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1043 cell
= strdup(cfg
->afs_cell
);
1044 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1047 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1050 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1051 "mod_waklog: child_init returned");
1056 command_rec waklog_cmds
[] = {
1058 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1059 "Use the supplied AFS cell (required)"),
1061 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1062 "enable waklog on a server, location, or directory basis"),
1064 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1065 "Set the default principal that the server runs as"),
1067 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1068 "Set the principal on a <Location>-specific basis"),
1070 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1071 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1073 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1074 "Use the requesting user tokens (from webauth)"),
1080 /* not currently using this */
1083 token_cleanup (void *data
)
1085 request_rec
*r
= (request_rec
*) data
;
1087 if (child
.token
.ticketLen
)
1089 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1091 ktc_ForgetAllTokens ();
1093 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1094 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1101 waklog_child_routine (void *data
, child_info
* pinfo
)
1104 server_rec
*s
= (server_rec
*) data
;
1105 krb5_error_code code
;
1107 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1112 getModConfig( cfg
, s
);
1114 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1116 memset (&child
, 0, sizeof(child
));
1118 if ( code
= krb5_init_context(&child
.kcontext
) ) {
1119 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1122 if ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) {
1123 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1126 /* need to do this so we can make PTS calls */
1127 cell
= strdup(cfg
->afs_cell
); /* stupid */
1128 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1132 for ( i
= 0; i
< renewcount
; ++i
) {
1133 renewtable
[i
].lastrenewed
= time(0);
1134 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1135 renewtable
[i
].keytab
);
1137 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1139 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1140 things that it needs to read */
1142 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1143 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1144 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1149 sharedspace
->renewcount
++;
1158 left
-= ( time(0) - when
);
1169 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1170 apr_pool_t
* ptemp
, server_rec
* s
)
1173 extern char *version
;
1178 int use_existing
= 1;
1180 char cache_file
[MAXNAMELEN
];
1182 pthread_rwlockattr_t rwlock_attr
;
1186 getModConfig (cfg
, s
);
1188 /* initialize_module() will be called twice, and if it's a DSO
1189 * then all static data from the first call will be lost. Only
1190 * set up our static data on the second call.
1191 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1192 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1195 if (cfg
->afs_cell
==NULL
) {
1196 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1197 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1198 /** clobber apache */
1204 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1205 apr_pool_cleanup_null
, s
->process
->pool
);
1209 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1210 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1212 if ( sharedspace
) {
1213 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1216 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1218 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1220 if ( errno
== ENOENT
) {
1222 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1224 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1225 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1229 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1233 if ( use_existing
== 0 ) {
1234 struct sharedspace_s bob
;
1235 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1236 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1237 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1238 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1241 /* mmap the region */
1243 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1244 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1247 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1253 #define locktype pthread_rwlock_t
1255 #define locktype rwlock_t
1258 if ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) {
1259 #ifndef use_pthreads
1260 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1262 pthread_rwlockattr_init(&rwlock_attr
);
1263 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1264 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1267 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1272 /* set our default tokens */
1274 oldrenewcount
= sharedspace
->renewcount
;
1276 pag_for_children
= 0;
1278 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1280 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1282 if (rv
== APR_INCHILD
)
1284 waklog_child_routine (s
, NULL
);
1288 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1290 /* parent and child */
1291 cfg
->forked
= proc
->pid
;
1292 pag_for_children
= 1;
1294 if ( use_existing
== 0 ) {
1295 /* wait here until our child process has gone and done it's renewing thing. */
1296 while( sharedspace
->renewcount
== oldrenewcount
) {
1297 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1302 if ( cfg
->default_principal
) {
1303 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1310 waklog_init (server_rec
* s
, MK_POOL
* p
)
1312 extern char *version
;
1317 int use_existing
= 1;
1319 char cache_file
[MAXNAMELEN
];
1321 pthread_rwlockattr_t rwlock_attr
;
1324 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1325 "mod_waklog: version %s initialized.", version
);
1327 if ( sharedspace
) {
1328 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1331 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1333 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1335 if ( errno
== ENOENT
) {
1337 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1339 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1340 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1344 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1349 if ( use_existing
== 0 ) {
1350 struct sharedspace_s bob
;
1351 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1352 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1353 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1354 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1357 /* mmap the region */
1359 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != -1 ) {
1360 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1363 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1369 #define locktype pthread_rwlock_t
1371 #define locktype rwlock_t
1374 /* mmap our shared space for our lock */
1375 if ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) {
1376 #ifndef use_pthreads
1377 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1379 pthread_rwlockattr_init(&rwlock_attr
);
1380 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1381 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1384 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1389 /* set our default tokens */
1391 getModConfig (cfg
, s
);
1393 oldrenewcount
= sharedspace
->renewcount
;
1395 pag_for_children
= 0;
1397 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1400 pag_for_children
= 1;
1402 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1403 "mod_waklog: ap_bspawn_child: %d.", pid
);
1405 if ( use_existing
== 0 ) {
1406 /* wait here until our child process has gone and done it's renewing thing. */
1407 while( sharedspace
->renewcount
== oldrenewcount
) {
1408 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1413 if ( cfg
->default_principal
) {
1414 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1421 waklog_phase0 (request_rec
* r
)
1425 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1426 "mod_waklog: phase0 called");
1428 cfg
= retrieve_config(r
);
1430 if ( cfg
->protect
&& cfg
->principal
) {
1431 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 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: phase0 using default user %s", cfg
->default_principal
);
1435 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1437 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1444 waklog_phase1 (request_rec
* r
)
1448 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1449 "mod_waklog: phase1 called");
1451 cfg
= retrieve_config(r
);
1453 if ( cfg
->protect
&& cfg
->principal
) {
1454 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 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: phase1 using default user %s", cfg
->default_principal
);
1458 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1460 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1467 waklog_phase3 (request_rec
* r
)
1471 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1472 "mod_waklog: phase 3 called");
1474 cfg
= retrieve_config(r
);
1476 if ( cfg
->protect
&& cfg
->principal
) {
1477 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1478 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1479 } else if ( cfg
->default_principal
) {
1480 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1481 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1483 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1490 waklog_phase6 (request_rec
* r
)
1494 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1495 "mod_waklog: phase6 called");
1497 cfg
= retrieve_config(r
);
1499 if ( cfg
->protect
&& cfg
->principal
) {
1500 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1501 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1502 } else if ( cfg
->default_principal
) {
1503 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1504 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1506 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1513 waklog_phase7 (request_rec
* r
)
1518 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1519 "mod_waklog: phase7 called");
1521 cfg
= retrieve_config (r
);
1523 if ( cfg
->protect
&& cfg
->usertokens
) {
1524 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1525 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1526 } else if ( cfg
->protect
&& cfg
->principal
) {
1527 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1528 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1529 } else if ( cfg
->default_principal
) {
1530 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1531 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1542 waklog_phase9 (request_rec
* r
)
1546 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1547 "mod_waklog: phase9 called");
1549 getModConfig (cfg
, r
->server
);
1551 if ( cfg
->default_principal
) {
1552 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1553 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1566 waklog_new_connection (conn_rec
* c
1575 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1576 "mod_waklog: new_connection called: pid: %d", getpid ());
1578 getModConfig(cfg
, c
->base_server
);
1580 if ( cfg
->default_principal
) {
1581 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1582 cfg
->default_principal
);
1583 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1596 ** Here's a quick explaination for phase0 and phase2:
1597 ** Apache does a stat() on the path between phase0 and
1598 ** phase2, and must by ACLed rl to succeed. So, at
1599 ** phase0 we acquire credentials for umweb:servers from
1600 ** a keytab, and at phase2 we must ensure we remove them.
1602 ** Failure to "unlog" would be a security risk.
1605 waklog_phase2 (request_rec
* r
)
1608 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1609 "mod_waklog: phase2 called");
1611 if (child
.token
.ticketLen
)
1613 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1615 ktc_ForgetAllTokens ();
1617 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1618 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1622 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1623 "mod_waklog: phase2 returning");
1629 module MODULE_VAR_EXPORT waklog_module
= {
1630 STANDARD_MODULE_STUFF
,
1631 waklog_init
, /* module initializer */
1632 waklog_create_dir_config
, /* create per-dir config structures */
1633 waklog_merge_dir_config
, /* merge per-dir config structures */
1634 waklog_create_server_config
, /* create per-server config structures */
1635 waklog_merge_dir_config
, /* merge per-server config structures */
1636 waklog_cmds
, /* table of config file commands */
1637 NULL
, /* [#8] MIME-typed-dispatched handlers */
1638 waklog_phase1
, /* [#1] URI to filename translation */
1639 NULL
, /* [#4] validate user id from request */
1640 NULL
, /* [#5] check if the user is ok _here_ */
1641 waklog_phase3
, /* [#3] check access by host address */
1642 waklog_phase6
, /* [#6] determine MIME type */
1643 waklog_phase7
, /* [#7] pre-run fixups */
1644 waklog_phase9
, /* [#9] log a transaction */
1645 NULL
, /* [#2] header parser */
1646 waklog_child_init
, /* child_init */
1647 waklog_child_exit
, /* child_exit */
1648 waklog_phase0
/* [#0] post read-request */
1650 , NULL
, /* EAPI: add_module */
1651 NULL
, /* EAPI: remove_module */
1652 NULL
, /* EAPI: rewrite_command */
1653 waklog_new_connection
/* EAPI: new_connection */
1658 waklog_register_hooks (apr_pool_t
* p
)
1660 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1661 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1662 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1663 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1664 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1665 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1666 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1667 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1668 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1669 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1673 module AP_MODULE_DECLARE_DATA waklog_module
= {
1674 STANDARD20_MODULE_STUFF
,
1675 waklog_create_dir_config
, /* create per-dir conf structures */
1676 waklog_merge_dir_config
, /* merge per-dir conf structures */
1677 waklog_create_server_config
, /* create per-server conf structures */
1678 waklog_merge_dir_config
, /* merge per-server conf structures */
1679 waklog_cmds
, /* table of configuration directives */
1680 waklog_register_hooks
/* register hooks */