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 /**************************************************************************************************/
76 #include <afs/param.h>
78 #include <afs/venus.h>
80 #include <afs/dirpath.h>
81 #include <afs/ptuser.h>
84 #define TKT_LIFE ( 12 * 60 * 60 )
85 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
87 #define WAKLOG_UNSET -1
91 #define APLOG_DEBUG APLOG_ERR
94 /* this is used to turn off pag generation for the backround worker child during startup */
95 int pag_for_children
= 1;
103 int cell_in_principal
;
104 int disable_token_cache
;
107 char *default_principal
;
108 char *default_keytab
;
110 char *afs_cell_realm
;
118 struct ktc_token token
;
119 char clientprincipal
[MAXNAMELEN
];
120 krb5_context kcontext
;
122 struct ktc_principal server
;
123 struct ktc_principal client
;
125 } waklog_child_config
;
127 waklog_child_config child
;
129 struct tokencache_ent
{
130 char clientprincipal
[MAXNAMELEN
];
131 struct ktc_token token
;
132 struct ktc_principal client
;
133 struct ktc_principal server
;
138 #define SHARED_TABLE_SIZE 512
140 struct sharedspace_s
{
142 struct tokencache_ent sharedtokens
[SHARED_TABLE_SIZE
];
145 struct sharedspace_s
*sharedspace
= NULL
;
154 pthread_rwlock_t
*sharedlock
= NULL
;
156 rwlock_t
*sharedlock
= NULL
;
159 struct renew_ent renewtable
[SHARED_TABLE_SIZE
];
165 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
170 #include <sys/ioccom.h>
173 #include <afs/venus.h>
174 #include <afs/auth.h>
175 #include <afs/dirpath.h>
176 #include <afs/ptuser.h>
177 #include <rx/rxkad.h>
181 log_error (const char *file
, int line
, int level
, int status
,
182 const server_rec
* s
, const char *fmt
, ...)
188 vsnprintf (errstr
, 1024, fmt
, ap
);
192 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
194 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
199 waklog_config
*retrieve_config(request_rec
*r
) {
204 if ( r
&& r
->main
) {
212 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
215 getModConfig (cfg
, r
->server
);
222 /* set_auth -- sets the tokens of the current process to this user.
223 if "self" is set, it divines the user from the current requests' environment.
224 otherwise, it's gettng it from principal/keytab */
227 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
231 krb5_error_code kerror
= 0;
232 krb5_principal kprinc
= NULL
;
233 krb5_get_init_creds_opt kopts
;
236 krb5_ccache clientccache
;
237 struct ktc_principal server
= { "afs", "", "" };
238 struct ktc_principal client
;
239 struct ktc_token token
;
240 krb5_creds
*v5credsp
= NULL
;
241 krb5_keytab krb5kt
= NULL
;
242 char buf
[MAXNAMELEN
];
246 time_t oldest_time
= 0;
251 int cell_in_principal
;
253 int use_client_credentials
= 0;
255 char k5user
[MAXNAMELEN
] = "";
256 char *k5secret
= NULL
;
260 memset((char *) &increds
, 0, sizeof(increds
));
261 /* init some stuff if it ain't already */
262 /* XXX - In what situation will these not be initialized? */
264 if ( ! child
.kcontext
) {
265 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
266 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
272 if ( !child
.ccache
) {
273 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
274 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
280 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
281 self
, principal
? principal
: "NULL",
282 keytab
? keytab
: "NULL",
284 k5path
? k5path
: "NULL",
286 (r
&& r
->user
) ? r
->user
: "NULL"
288 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
292 /* pull the server config record that we care about... */
295 cfg
= retrieve_config(r
);
297 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
298 "mod_waklog: set_auth using no config" );
299 getModConfig (cfg
, s
);
303 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
308 /* pull out our principal name and stuff from the environment -- webauth better have sent
312 if ( ! ( r
&& r
->connection
&& r
->user
)) {
313 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
314 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
==NULL
));
318 strncpy(k5user
, r
->user
, sizeof(k5user
));
320 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
321 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
325 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
327 /* if they've supplied a credentials cache */
328 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
330 /* the other thing we need is someone's password */
331 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
333 /* we'll pick this up later after we've checked the cache and current state */
337 strncpy(k5user
, principal
, sizeof(k5user
));
341 strncpy(k5user
, r
->user
, sizeof(k5user
));
344 if (r
&& r
->connection
&& r
->connection
->user
) {
345 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
349 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
? k5user
: "NULL");
352 /* see if we should just go ahead and ignore this call, since we already should be set to these
358 pthread_rwlock_rdlock( sharedlock
);
360 rw_rdlock( sharedlock
);
363 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
365 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
367 if ( ( !strcmp( k5user
,
368 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
369 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
371 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
377 /* copy the token out of the cache and into the child object */
379 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
380 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
381 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
382 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
384 /* set our last used time thing */
385 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
395 /* release the lock on the token cache */
397 pthread_rwlock_unlock( sharedlock
);
399 rw_unlock( sharedlock
);
403 /* release the lock on the token cache */
404 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
405 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
409 /* if this is something that was in the cache, and it's the same as the token we already have stored,
410 and we weren't calling this just to renew it... */
412 if ( usecached
&& indentical
) {
413 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
419 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
420 if (( ! usecached
) && ( k5user
)) {
422 /* clear out the creds structure */
423 memset((void *) &v5creds
, 0, sizeof(v5creds
));
425 /* create a principal out of our k5user string */
427 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
428 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror
) );
432 /* create the credentials options */
434 krb5_get_init_creds_opt_init ( &kopts
);
435 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
436 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
437 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
438 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
440 if ( keytab
|| k5secret
) {
443 /* if we've been passed a keytab, we're going to be getting our credentials from it */
445 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
447 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
448 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
449 "mod_waklog: krb5_kt_resolve %s", error_message(kerror
) );
453 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
454 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
455 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
456 error_message(kerror
) );
459 } else if (k5secret
) {
461 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
463 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
464 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
465 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
466 error_message(kerror
) );
467 /* nuke the password so it doesn't end up in core files */
468 memset(k5secret
, 0, sizeof(k5secret
));
472 memset(k5secret
, 0, sizeof(k5secret
));
475 /* initialize the credentials cache and store the stuff we just got */
476 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
477 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
478 error_message(kerror
));
482 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
483 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
484 error_message(kerror
));
488 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
491 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", error_message(kerror
));
495 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
498 /* If we've got a path to a credentials cache, then try and use that. We can't just
499 * replace child.creds, because we want to ensure that only this request gets access to
502 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
503 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
504 "mod_waklog: can't open provided credentials cache %s err=%d",
509 use_client_credentials
= 1;
512 /* now, to the 'aklog' portion of our program. */
514 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
515 for(attempt
= 0; attempt
<= 1; attempt
++) {
516 strncpy( buf
, "afs", sizeof(buf
) - 1 );
517 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
519 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
520 if (cell_in_principal
) {
521 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
522 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
524 if (cfg
->afs_cell_realm
!= NULL
) {
525 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
526 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
529 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
531 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
532 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", error_message(kerror
));
536 if (!use_client_credentials
) {
537 clientccache
= child
.ccache
;
540 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
541 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", error_message(kerror
), clientccache
);
545 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
547 increds
.times
.endtime
= 0;
549 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
551 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
552 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
554 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
555 error_message(kerror
));
561 cfg
->cell_in_principal
= cell_in_principal
;
565 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
567 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
568 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
569 v5credsp
->ticket
.length
);
573 memset(&token
, 0, sizeof(struct ktc_token
));
575 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
576 token
.endTime
= v5credsp
->times
.endtime
;
578 memmove( &token
.sessionKey
, v5credsp
->keyblock
.contents
, v5credsp
->keyblock
.length
);
579 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
580 token
.ticketLen
= v5credsp
->ticket
.length
;
581 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
585 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
587 buf
[v5credsp
->client
->data
[0].length
] = '\0';
588 if ( v5credsp
->client
->length
> 1 ) {
589 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
590 buflen
= strlen(buf
);
591 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
592 min(v5credsp
->client
->data
[1].length
,
593 MAXKTCNAMELEN
- strlen(buf
) - 1));
594 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
597 /* assemble the client */
598 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
599 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
600 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
602 buf
[v5credsp
->client
->realm
.length
] = '\0';
603 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
605 /* assemble the server's cell */
606 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
608 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
610 /* fill out the AFS ID in the client name */
611 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
612 * strange things seem to happen. */
615 afs_int32 viceId
= 0;
617 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
619 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
620 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
622 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
625 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
629 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
630 server
.name
, server
.instance
, server
.cell
);
632 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
633 client
.name
, client
.instance
, client
.cell
);
635 /* copy the resulting stuff into the child structure */
637 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
638 memcpy(&child
.token
, &token
, sizeof(child
.token
));
639 memcpy(&child
.server
, &server
, sizeof(child
.server
));
640 memcpy(&child
.client
, &client
, sizeof(child
.client
));
642 /* stuff the resulting token-related stuff into our shared token cache */
643 /* note, that anything that was set from a keytab is "persistant", and is immune
644 * from LRU-aging. This is because nothing but the process that's running as root
645 * can update these, and it's running every hour or so and renewing these tokens.
646 * and we don't want them aged out.
649 mytime
= oldest_time
= time(0);
651 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
654 pthread_rwlock_wrlock(sharedlock
);
656 rw_wrlock(sharedlock
);
659 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
660 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
661 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
663 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
665 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
666 child
.clientprincipal
) ) {
667 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
668 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
669 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
670 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
671 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
677 if ( stored
== -1 ) {
678 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
679 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
680 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
681 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
682 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
683 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
688 pthread_rwlock_unlock(sharedlock
);
690 rw_unlock(sharedlock
);
693 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
694 child
.clientprincipal
);
696 } else if ( ! usecached
) {
697 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
706 /* don't ask. Something about AIX. We're leaving it here.*/
707 /* write(2, "", 0); */
709 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
711 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
712 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
713 error_message(rc
), k5user
);
714 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
715 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
716 error_message(rc
), k5user
);
722 if (use_client_credentials
)
723 krb5_cc_close(child
.kcontext
, clientccache
);
725 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
726 if ( increds
.client
)
727 krb5_free_principal (child
.kcontext
, increds
.client
);
728 if ( increds
.server
)
729 krb5_free_principal (child
.kcontext
, increds
.server
);
731 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
733 krb5_free_principal (child
.kcontext
, kprinc
);
736 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
737 } else if ( kerror
) {
738 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, error_message(kerror
));
740 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
743 return kerror
? (int) kerror
: (int) rc
;
748 int get_cfg_usertokens(waklog_config
*cfg
)
750 if (cfg
->usertokens
==WAKLOG_UNSET
)
751 return 0; /* default */
752 return cfg
->usertokens
;
755 int get_cfg_protect(waklog_config
*cfg
)
757 if (cfg
->protect
==WAKLOG_UNSET
)
758 return 0; /* default */
762 int get_cfg_disable_token_cache(waklog_config
*cfg
)
764 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
765 return 0; /* default */
766 return cfg
->disable_token_cache
;
771 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
775 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
777 memset(cfg
, 0, sizeof(waklog_config
));
778 cfg
->path
= "(server)";
779 cfg
->protect
= WAKLOG_UNSET
;
780 cfg
->usertokens
= WAKLOG_UNSET
;
781 cfg
->disable_token_cache
= WAKLOG_UNSET
;
783 cfg
->principal
= NULL
;
784 cfg
->default_principal
= NULL
;
785 cfg
->default_keytab
= NULL
;
786 cfg
->afs_cell
= NULL
;
787 cfg
->afs_cell_realm
= NULL
;
791 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
792 "mod_waklog: server config created.");
797 /* initialize with host-config information */
800 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
804 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
805 memset(cfg
, 0, sizeof(waklog_config
));
807 cfg
->path
= ap_pstrdup(p
, dir
);
808 cfg
->protect
= WAKLOG_UNSET
;
809 cfg
->usertokens
= WAKLOG_UNSET
;
810 cfg
->disable_token_cache
= WAKLOG_UNSET
;
812 cfg
->principal
= NULL
;
813 cfg
->default_principal
= NULL
;
814 cfg
->default_keytab
= NULL
;
815 cfg
->afs_cell
= NULL
;
816 cfg
->afs_cell_realm
= NULL
;
823 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
825 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
826 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
827 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
829 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
831 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
833 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
835 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
837 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
839 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
841 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
843 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
845 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
847 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
849 return (void *) merged
;
853 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
855 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
856 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
857 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
859 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
861 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
863 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
865 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
866 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
868 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
869 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
871 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
872 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
874 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
875 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
877 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
878 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
880 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
881 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
884 return (void *) merged
;
889 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
891 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
892 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
896 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
897 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
902 /* this adds a principal/keytab pair to get their tokens renewed by the
903 child process every few centons. */
905 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
909 if ( renewcount
>= SHARED_TABLE_SIZE
) {
910 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
911 decrease your tokens.");
915 /* check to see if it's already there */
917 for ( i
= 0; i
< renewcount
; i
++ ) {
918 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
923 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
924 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
925 renewtable
[renewcount
].lastrenewed
= 0;
931 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
933 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
934 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
936 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
937 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
939 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
940 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
942 add_to_renewtable(params
->pool
, keytab
, principal
);
950 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
952 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
953 waklog_config
*waklog_srvconfig
=
954 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
956 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
957 "mod_waklog: will use afs_cell: %s", file
);
959 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
960 waklog_srvconfig
->cell_in_principal
= 1;
962 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
963 waklog_srvconfig
->configured
= 1;
965 if (waklog_mconfig
!= NULL
) {
966 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
967 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
968 waklog_mconfig
->configured
= 1;
974 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
976 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
977 waklog_config
*waklog_srvconfig
=
978 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
980 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
981 "mod_waklog: will use afs_cell_realm: %s", file
);
983 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
985 if (waklog_mconfig
!= NULL
) {
986 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
992 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
994 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
995 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
997 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
999 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1000 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
1002 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1003 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1005 /* this also gets set at the server level */
1006 if ( mconfig
&& ( ! cfg
->path
) ) {
1007 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1008 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1010 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
1011 return "Unable to set DefaultPrincipal outside of top level config!";
1014 add_to_renewtable( params
->pool
, keytab
, principal
);
1016 cfg
->configured
= 1;
1022 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1024 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1025 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1027 cfg
->usertokens
= flag
;
1029 cfg
->configured
= 1;
1031 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1032 "mod_waklog: waklog_use_user_tokens set");
1038 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1040 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1041 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1043 cfg
->disable_token_cache
= flag
;
1045 cfg
->configured
= 1;
1047 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1048 "mod_waklog: waklog_disable_token_cache set");
1054 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1056 apr_status_t
waklog_child_exit( void *sr
) {
1058 server_rec
*s
= (server_rec
*) sr
;
1061 if ( child
.ccache
) {
1062 krb5_cc_close(child
.kcontext
, child
.ccache
);
1065 if ( child
.kcontext
) {
1066 krb5_free_context(child
.kcontext
);
1069 /* forget our tokens */
1071 ktc_ForgetAllTokens ();
1073 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1074 "mod_waklog: waklog_child_exit complete");
1084 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1086 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1090 krb5_error_code code
;
1095 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1097 if ( !sharedspace
) {
1098 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1102 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1104 memset (&child
, 0, sizeof(child
));
1106 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1107 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1110 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1111 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1114 if ( pag_for_children
) {
1118 getModConfig (cfg
, s
);
1120 if ( cfg
->default_principal
!= NULL
) {
1121 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1122 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1125 cell
= strdup(cfg
->afs_cell
);
1126 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1129 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1132 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1133 "mod_waklog: child_init returned");
1138 command_rec waklog_cmds
[] = {
1140 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1141 "Use the supplied AFS cell (required)"),
1143 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1144 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1146 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1147 "enable waklog on a server, location, or directory basis"),
1149 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1150 "Set the default principal that the server runs as"),
1152 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1153 "Set the principal on a <Location>-specific basis"),
1155 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1156 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1158 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1159 "Use the requesting user tokens (from webauth)"),
1165 /* not currently using this */
1168 token_cleanup (void *data
)
1170 request_rec
*r
= (request_rec
*) data
;
1172 if (child
.token
.ticketLen
)
1174 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1176 ktc_ForgetAllTokens ();
1178 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1179 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1186 waklog_child_routine (void *data
, child_info
* pinfo
)
1189 server_rec
*s
= (server_rec
*) data
;
1190 krb5_error_code code
;
1192 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1197 getModConfig( cfg
, s
);
1199 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1201 memset (&child
, 0, sizeof(child
));
1203 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1204 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1207 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1208 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1211 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1213 /* need to do this so we can make PTS calls */
1214 cell
= strdup(cfg
->afs_cell
); /* stupid */
1215 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1217 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1221 for ( i
= 0; i
< renewcount
; ++i
) {
1222 renewtable
[i
].lastrenewed
= time(0);
1223 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1224 renewtable
[i
].keytab
);
1226 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1228 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1229 things that it needs to read */
1231 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1232 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1233 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1238 sharedspace
->renewcount
++;
1247 left
-= ( time(0) - when
);
1258 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1259 apr_pool_t
* ptemp
, server_rec
* s
)
1262 extern char *version
;
1267 int use_existing
= 1;
1269 char cache_file
[MAXNAMELEN
];
1271 pthread_rwlockattr_t rwlock_attr
;
1275 getModConfig (cfg
, s
);
1277 /* initialize_module() will be called twice, and if it's a DSO
1278 * then all static data from the first call will be lost. Only
1279 * set up our static data on the second call.
1280 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1281 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1284 if (cfg
->afs_cell
==NULL
) {
1285 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1286 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1287 /** clobber apache */
1293 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1294 apr_pool_cleanup_null
, s
->process
->pool
);
1298 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1299 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1301 if ( sharedspace
) {
1302 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1305 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1307 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1309 if ( errno
== ENOENT
) {
1311 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1313 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1314 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1318 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1322 if ( use_existing
== 0 ) {
1323 struct sharedspace_s bob
;
1324 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1325 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1326 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1327 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1330 /* mmap the region */
1332 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1334 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1335 err
= unlink(cache_file
);
1337 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1339 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1342 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1348 #define locktype pthread_rwlock_t
1350 #define locktype rwlock_t
1353 if ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) {
1354 #ifndef use_pthreads
1355 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1357 pthread_rwlockattr_init(&rwlock_attr
);
1358 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1359 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1362 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1367 /* set our default tokens */
1369 oldrenewcount
= sharedspace
->renewcount
;
1371 pag_for_children
= 0;
1373 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1375 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1377 if (rv
== APR_INCHILD
)
1379 waklog_child_routine (s
, NULL
);
1383 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1385 /* parent and child */
1386 cfg
->forked
= proc
->pid
;
1387 pag_for_children
= 1;
1389 if ( use_existing
== 0 ) {
1390 /* wait here until our child process has gone and done it's renewing thing. */
1391 while( sharedspace
->renewcount
== oldrenewcount
) {
1392 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1397 if ( cfg
->default_principal
) {
1398 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1405 waklog_init (server_rec
* s
, MK_POOL
* p
)
1407 extern char *version
;
1411 int use_existing
= 1;
1413 char cache_file
[MAXNAMELEN
];
1415 pthread_rwlockattr_t rwlock_attr
;
1418 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1419 "mod_waklog: version %s initialized.", version
);
1421 if ( sharedspace
) {
1422 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1425 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1427 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1429 if ( errno
== ENOENT
) {
1431 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1433 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1434 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1438 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1443 if ( use_existing
== 0 ) {
1444 struct sharedspace_s bob
;
1445 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1446 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1447 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1448 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1451 /* mmap the region */
1453 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1454 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1457 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1463 #define locktype pthread_rwlock_t
1465 #define locktype rwlock_t
1468 /* mmap our shared space for our lock */
1469 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1470 #ifndef use_pthreads
1471 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1473 pthread_rwlockattr_init(&rwlock_attr
);
1474 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1475 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1478 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1483 /* set our default tokens */
1485 getModConfig (cfg
, s
);
1487 oldrenewcount
= sharedspace
->renewcount
;
1489 pag_for_children
= 0;
1491 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1494 pag_for_children
= 1;
1496 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1497 "mod_waklog: ap_bspawn_child: %d.", pid
);
1499 if ( use_existing
== 0 ) {
1500 /* wait here until our child process has gone and done it's renewing thing. */
1501 while( sharedspace
->renewcount
== oldrenewcount
) {
1502 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1507 if ( cfg
->default_principal
) {
1508 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1515 waklog_phase0 (request_rec
* r
)
1519 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1520 "mod_waklog: phase0 called");
1522 cfg
= retrieve_config(r
);
1524 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1525 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1526 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1527 } else if ( cfg
->default_principal
) {
1528 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1529 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1532 if (child
.token
.ticketLen
) {
1533 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1534 ktc_ForgetAllTokens();
1537 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1544 waklog_phase1 (request_rec
* r
)
1548 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1549 "mod_waklog: phase1 called");
1551 cfg
= retrieve_config(r
);
1553 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1554 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1555 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1556 } else if ( cfg
->default_principal
) {
1557 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1558 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1560 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1567 waklog_phase3 (request_rec
* r
)
1571 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1572 "mod_waklog: phase 3 called");
1574 cfg
= retrieve_config(r
);
1576 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1577 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1578 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1579 } else if ( cfg
->default_principal
) {
1580 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1581 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1583 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1590 waklog_phase6 (request_rec
* r
)
1594 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1595 "mod_waklog: phase6 called");
1597 cfg
= retrieve_config(r
);
1599 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1600 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1601 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1602 } else if ( cfg
->default_principal
) {
1603 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1604 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1606 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1613 waklog_phase7 (request_rec
* r
)
1618 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1619 "mod_waklog: phase7 called");
1621 cfg
= retrieve_config (r
);
1623 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1624 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1625 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1626 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1627 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1628 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1629 } else if ( cfg
->default_principal
) {
1630 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1631 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1633 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1634 if (child
.token
.ticketLen
) {
1635 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1636 ktc_ForgetAllTokens();
1648 waklog_phase9 (request_rec
* r
)
1652 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1653 "mod_waklog: phase9 called");
1655 getModConfig (cfg
, r
->server
);
1657 if ( cfg
->default_principal
) {
1658 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1659 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1672 waklog_new_connection (conn_rec
* c
1681 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1682 "mod_waklog: new_connection called: pid: %d", getpid ());
1684 getModConfig(cfg
, c
->base_server
);
1686 if ( cfg
->default_principal
) {
1687 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1688 cfg
->default_principal
);
1689 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1702 ** Here's a quick explaination for phase0 and phase2:
1703 ** Apache does a stat() on the path between phase0 and
1704 ** phase2, and must by ACLed rl to succeed. So, at
1705 ** phase0 we acquire credentials for umweb:servers from
1706 ** a keytab, and at phase2 we must ensure we remove them.
1708 ** Failure to "unlog" would be a security risk.
1711 waklog_phase2 (request_rec
* r
)
1714 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1715 "mod_waklog: phase2 called");
1717 if (child
.token
.ticketLen
)
1719 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1721 ktc_ForgetAllTokens ();
1723 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1724 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1728 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1729 "mod_waklog: phase2 returning");
1735 module MODULE_VAR_EXPORT waklog_module
= {
1736 STANDARD_MODULE_STUFF
,
1737 waklog_init
, /* module initializer */
1738 waklog_create_dir_config
, /* create per-dir config structures */
1739 waklog_merge_dir_config
, /* merge per-dir config structures */
1740 waklog_create_server_config
, /* create per-server config structures */
1741 waklog_merge_dir_config
, /* merge per-server config structures */
1742 waklog_cmds
, /* table of config file commands */
1743 NULL
, /* [#8] MIME-typed-dispatched handlers */
1744 waklog_phase1
, /* [#1] URI to filename translation */
1745 NULL
, /* [#4] validate user id from request */
1746 NULL
, /* [#5] check if the user is ok _here_ */
1747 waklog_phase3
, /* [#3] check access by host address */
1748 waklog_phase6
, /* [#6] determine MIME type */
1749 waklog_phase7
, /* [#7] pre-run fixups */
1750 waklog_phase9
, /* [#9] log a transaction */
1751 waklog_phase2
, /* [#2] header parser */
1752 waklog_child_init
, /* child_init */
1753 waklog_child_exit
, /* child_exit */
1754 waklog_phase0
/* [#0] post read-request */
1756 , NULL
, /* EAPI: add_module */
1757 NULL
, /* EAPI: remove_module */
1758 NULL
, /* EAPI: rewrite_command */
1759 waklog_new_connection
/* EAPI: new_connection */
1764 waklog_register_hooks (apr_pool_t
* p
)
1766 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1767 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1768 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1769 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1770 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1771 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1772 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1773 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1774 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1775 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1779 module AP_MODULE_DECLARE_DATA waklog_module
= {
1780 STANDARD20_MODULE_STUFF
,
1781 waklog_create_dir_config
, /* create per-dir conf structures */
1782 waklog_merge_dir_config
, /* merge per-dir conf structures */
1783 waklog_create_server_config
, /* create per-server conf structures */
1784 waklog_merge_dir_config
, /* merge per-server conf structures */
1785 waklog_cmds
, /* table of configuration directives */
1786 waklog_register_hooks
/* register hooks */