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 /* Since we're fetching a key for AFS, we have to use single DES
550 and explicitely enable weak crypto using the secret API
552 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
553 krb5_allow_weak_crypto (child
.kcontext
, 1);
555 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
556 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
558 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
559 error_message(kerror
));
565 cfg
->cell_in_principal
= cell_in_principal
;
569 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
571 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
572 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
573 v5credsp
->ticket
.length
);
577 memset(&token
, 0, sizeof(struct ktc_token
));
579 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
580 token
.endTime
= v5credsp
->times
.endtime
;
582 memmove( &token
.sessionKey
, v5credsp
->keyblock
.contents
, v5credsp
->keyblock
.length
);
583 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
584 token
.ticketLen
= v5credsp
->ticket
.length
;
585 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
589 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
591 buf
[v5credsp
->client
->data
[0].length
] = '\0';
592 if ( v5credsp
->client
->length
> 1 ) {
593 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
594 buflen
= strlen(buf
);
595 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
596 min(v5credsp
->client
->data
[1].length
,
597 MAXKTCNAMELEN
- strlen(buf
) - 1));
598 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
601 /* assemble the client */
602 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
603 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
604 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
606 buf
[v5credsp
->client
->realm
.length
] = '\0';
607 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
609 /* assemble the server's cell */
610 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
612 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
614 /* fill out the AFS ID in the client name */
615 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
616 * strange things seem to happen. */
619 afs_int32 viceId
= 0;
621 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
623 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
624 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
626 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
629 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
633 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
634 server
.name
, server
.instance
, server
.cell
);
636 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
637 client
.name
, client
.instance
, client
.cell
);
639 /* copy the resulting stuff into the child structure */
641 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
642 memcpy(&child
.token
, &token
, sizeof(child
.token
));
643 memcpy(&child
.server
, &server
, sizeof(child
.server
));
644 memcpy(&child
.client
, &client
, sizeof(child
.client
));
646 /* stuff the resulting token-related stuff into our shared token cache */
647 /* note, that anything that was set from a keytab is "persistant", and is immune
648 * from LRU-aging. This is because nothing but the process that's running as root
649 * can update these, and it's running every hour or so and renewing these tokens.
650 * and we don't want them aged out.
653 mytime
= oldest_time
= time(0);
655 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
658 pthread_rwlock_wrlock(sharedlock
);
660 rw_wrlock(sharedlock
);
663 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
664 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
665 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
667 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
669 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
670 child
.clientprincipal
) ) {
671 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
672 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
673 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
674 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
675 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
681 if ( stored
== -1 ) {
682 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
683 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
684 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
685 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
686 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
687 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
692 pthread_rwlock_unlock(sharedlock
);
694 rw_unlock(sharedlock
);
697 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
698 child
.clientprincipal
);
700 } else if ( ! usecached
) {
701 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
710 /* don't ask. Something about AIX. We're leaving it here.*/
711 /* write(2, "", 0); */
713 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
715 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
716 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
717 error_message(rc
), k5user
);
718 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
719 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
720 error_message(rc
), k5user
);
726 if (use_client_credentials
)
727 krb5_cc_close(child
.kcontext
, clientccache
);
729 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
730 if ( increds
.client
)
731 krb5_free_principal (child
.kcontext
, increds
.client
);
732 if ( increds
.server
)
733 krb5_free_principal (child
.kcontext
, increds
.server
);
735 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
737 krb5_free_principal (child
.kcontext
, kprinc
);
740 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
741 } else if ( kerror
) {
742 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, error_message(kerror
));
744 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
747 return kerror
? (int) kerror
: (int) rc
;
752 int get_cfg_usertokens(waklog_config
*cfg
)
754 if (cfg
->usertokens
==WAKLOG_UNSET
)
755 return 0; /* default */
756 return cfg
->usertokens
;
759 int get_cfg_protect(waklog_config
*cfg
)
761 if (cfg
->protect
==WAKLOG_UNSET
)
762 return 0; /* default */
766 int get_cfg_disable_token_cache(waklog_config
*cfg
)
768 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
769 return 0; /* default */
770 return cfg
->disable_token_cache
;
775 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
779 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
781 memset(cfg
, 0, sizeof(waklog_config
));
782 cfg
->path
= "(server)";
783 cfg
->protect
= WAKLOG_UNSET
;
784 cfg
->usertokens
= WAKLOG_UNSET
;
785 cfg
->disable_token_cache
= WAKLOG_UNSET
;
787 cfg
->principal
= NULL
;
788 cfg
->default_principal
= NULL
;
789 cfg
->default_keytab
= NULL
;
790 cfg
->afs_cell
= NULL
;
791 cfg
->afs_cell_realm
= NULL
;
795 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
796 "mod_waklog: server config created.");
801 /* initialize with host-config information */
804 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
808 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
809 memset(cfg
, 0, sizeof(waklog_config
));
811 cfg
->path
= ap_pstrdup(p
, dir
);
812 cfg
->protect
= WAKLOG_UNSET
;
813 cfg
->usertokens
= WAKLOG_UNSET
;
814 cfg
->disable_token_cache
= WAKLOG_UNSET
;
816 cfg
->principal
= NULL
;
817 cfg
->default_principal
= NULL
;
818 cfg
->default_keytab
= NULL
;
819 cfg
->afs_cell
= NULL
;
820 cfg
->afs_cell_realm
= NULL
;
827 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
829 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
830 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
831 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
833 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
835 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
837 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
839 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
841 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
843 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
845 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
847 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
849 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
851 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
853 return (void *) merged
;
857 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
859 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
860 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
861 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
863 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
865 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
867 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
869 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
870 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
872 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
873 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
875 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
876 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
878 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
879 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
881 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
882 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
884 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
885 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
888 return (void *) merged
;
893 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
895 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
896 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
900 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
901 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
906 /* this adds a principal/keytab pair to get their tokens renewed by the
907 child process every few centons. */
909 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
913 if ( renewcount
>= SHARED_TABLE_SIZE
) {
914 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
915 decrease your tokens.");
919 /* check to see if it's already there */
921 for ( i
= 0; i
< renewcount
; i
++ ) {
922 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
927 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
928 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
929 renewtable
[renewcount
].lastrenewed
= 0;
935 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
937 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
938 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
940 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
941 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
943 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
944 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
946 add_to_renewtable(params
->pool
, keytab
, principal
);
954 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
956 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
957 waklog_config
*waklog_srvconfig
=
958 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
960 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
961 "mod_waklog: will use afs_cell: %s", file
);
963 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
964 waklog_srvconfig
->cell_in_principal
= 1;
966 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
967 waklog_srvconfig
->configured
= 1;
969 if (waklog_mconfig
!= NULL
) {
970 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
971 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
972 waklog_mconfig
->configured
= 1;
978 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
980 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
981 waklog_config
*waklog_srvconfig
=
982 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
984 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
985 "mod_waklog: will use afs_cell_realm: %s", file
);
987 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
989 if (waklog_mconfig
!= NULL
) {
990 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
996 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
998 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
999 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1001 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1003 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1004 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
1006 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1007 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1009 /* this also gets set at the server level */
1010 if ( mconfig
&& ( ! cfg
->path
) ) {
1011 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1012 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1014 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
1015 return "Unable to set DefaultPrincipal outside of top level config!";
1018 add_to_renewtable( params
->pool
, keytab
, principal
);
1020 cfg
->configured
= 1;
1026 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1028 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1029 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1031 cfg
->usertokens
= flag
;
1033 cfg
->configured
= 1;
1035 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1036 "mod_waklog: waklog_use_user_tokens set");
1042 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1044 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1045 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1047 cfg
->disable_token_cache
= flag
;
1049 cfg
->configured
= 1;
1051 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1052 "mod_waklog: waklog_disable_token_cache set");
1058 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1060 apr_status_t
waklog_child_exit( void *sr
) {
1062 server_rec
*s
= (server_rec
*) sr
;
1065 if ( child
.ccache
) {
1066 krb5_cc_close(child
.kcontext
, child
.ccache
);
1069 if ( child
.kcontext
) {
1070 krb5_free_context(child
.kcontext
);
1073 /* forget our tokens */
1075 ktc_ForgetAllTokens ();
1077 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1078 "mod_waklog: waklog_child_exit complete");
1088 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1090 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1094 krb5_error_code code
;
1099 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1101 if ( !sharedspace
) {
1102 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1106 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1108 memset (&child
, 0, sizeof(child
));
1110 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1111 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1114 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1115 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1118 if ( pag_for_children
) {
1122 getModConfig (cfg
, s
);
1124 if ( cfg
->default_principal
!= NULL
) {
1125 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1126 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1129 cell
= strdup(cfg
->afs_cell
);
1130 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1133 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1136 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1137 "mod_waklog: child_init returned");
1142 command_rec waklog_cmds
[] = {
1144 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1145 "Use the supplied AFS cell (required)"),
1147 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1148 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1150 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1151 "enable waklog on a server, location, or directory basis"),
1153 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1154 "Set the default principal that the server runs as"),
1156 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1157 "Set the principal on a <Location>-specific basis"),
1159 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1160 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1162 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1163 "Use the requesting user tokens (from webauth)"),
1169 /* not currently using this */
1172 token_cleanup (void *data
)
1174 request_rec
*r
= (request_rec
*) data
;
1176 if (child
.token
.ticketLen
)
1178 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1180 ktc_ForgetAllTokens ();
1182 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1183 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1190 waklog_child_routine (void *data
, child_info
* pinfo
)
1193 server_rec
*s
= (server_rec
*) data
;
1194 krb5_error_code code
;
1196 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1201 getModConfig( cfg
, s
);
1203 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1205 memset (&child
, 0, sizeof(child
));
1207 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1208 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1211 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1212 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1215 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1217 /* need to do this so we can make PTS calls */
1218 cell
= strdup(cfg
->afs_cell
); /* stupid */
1219 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1221 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1225 for ( i
= 0; i
< renewcount
; ++i
) {
1226 renewtable
[i
].lastrenewed
= time(0);
1227 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1228 renewtable
[i
].keytab
);
1230 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1232 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1233 things that it needs to read */
1235 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1236 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1237 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1242 sharedspace
->renewcount
++;
1251 left
-= ( time(0) - when
);
1262 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1263 apr_pool_t
* ptemp
, server_rec
* s
)
1266 extern char *version
;
1271 int use_existing
= 1;
1273 char cache_file
[MAXNAMELEN
];
1275 pthread_rwlockattr_t rwlock_attr
;
1279 getModConfig (cfg
, s
);
1281 /* initialize_module() will be called twice, and if it's a DSO
1282 * then all static data from the first call will be lost. Only
1283 * set up our static data on the second call.
1284 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1285 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1288 if (cfg
->afs_cell
==NULL
) {
1289 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1290 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1291 /** clobber apache */
1297 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1298 apr_pool_cleanup_null
, s
->process
->pool
);
1302 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1303 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1305 if ( sharedspace
) {
1306 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1309 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1311 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1313 if ( errno
== ENOENT
) {
1315 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1317 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1318 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1322 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1326 if ( use_existing
== 0 ) {
1327 struct sharedspace_s bob
;
1328 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1329 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1330 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1331 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1334 /* mmap the region */
1336 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1338 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1339 err
= unlink(cache_file
);
1341 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1343 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1346 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1352 #define locktype pthread_rwlock_t
1354 #define locktype rwlock_t
1357 if ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) {
1358 #ifndef use_pthreads
1359 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1361 pthread_rwlockattr_init(&rwlock_attr
);
1362 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1363 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1366 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1371 /* set our default tokens */
1373 oldrenewcount
= sharedspace
->renewcount
;
1375 pag_for_children
= 0;
1377 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1379 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1381 if (rv
== APR_INCHILD
)
1383 waklog_child_routine (s
, NULL
);
1387 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1389 /* parent and child */
1390 cfg
->forked
= proc
->pid
;
1391 pag_for_children
= 1;
1393 if ( use_existing
== 0 ) {
1394 /* wait here until our child process has gone and done it's renewing thing. */
1395 while( sharedspace
->renewcount
== oldrenewcount
) {
1396 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1401 if ( cfg
->default_principal
) {
1402 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1409 waklog_init (server_rec
* s
, MK_POOL
* p
)
1411 extern char *version
;
1415 int use_existing
= 1;
1417 char cache_file
[MAXNAMELEN
];
1419 pthread_rwlockattr_t rwlock_attr
;
1422 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1423 "mod_waklog: version %s initialized.", version
);
1425 if ( sharedspace
) {
1426 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1429 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1431 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1433 if ( errno
== ENOENT
) {
1435 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1437 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1438 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1442 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1447 if ( use_existing
== 0 ) {
1448 struct sharedspace_s bob
;
1449 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1450 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1451 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1452 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1455 /* mmap the region */
1457 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1458 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1461 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1467 #define locktype pthread_rwlock_t
1469 #define locktype rwlock_t
1472 /* mmap our shared space for our lock */
1473 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1474 #ifndef use_pthreads
1475 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1477 pthread_rwlockattr_init(&rwlock_attr
);
1478 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1479 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1482 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1487 /* set our default tokens */
1489 getModConfig (cfg
, s
);
1491 oldrenewcount
= sharedspace
->renewcount
;
1493 pag_for_children
= 0;
1495 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1498 pag_for_children
= 1;
1500 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1501 "mod_waklog: ap_bspawn_child: %d.", pid
);
1503 if ( use_existing
== 0 ) {
1504 /* wait here until our child process has gone and done it's renewing thing. */
1505 while( sharedspace
->renewcount
== oldrenewcount
) {
1506 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1511 if ( cfg
->default_principal
) {
1512 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1519 waklog_phase0 (request_rec
* r
)
1523 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1524 "mod_waklog: phase0 called");
1526 cfg
= retrieve_config(r
);
1528 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1529 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1530 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1531 } else if ( cfg
->default_principal
) {
1532 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1533 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1536 if (child
.token
.ticketLen
) {
1537 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1538 ktc_ForgetAllTokens();
1541 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1548 waklog_phase1 (request_rec
* r
)
1552 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1553 "mod_waklog: phase1 called");
1555 cfg
= retrieve_config(r
);
1557 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1558 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1559 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1560 } else if ( cfg
->default_principal
) {
1561 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1562 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1564 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1571 waklog_phase3 (request_rec
* r
)
1575 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1576 "mod_waklog: phase 3 called");
1578 cfg
= retrieve_config(r
);
1580 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1581 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1582 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1583 } else if ( cfg
->default_principal
) {
1584 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1585 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1587 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1594 waklog_phase6 (request_rec
* r
)
1598 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1599 "mod_waklog: phase6 called");
1601 cfg
= retrieve_config(r
);
1603 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1604 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1605 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1606 } else if ( cfg
->default_principal
) {
1607 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1608 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1610 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1617 waklog_phase7 (request_rec
* r
)
1622 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1623 "mod_waklog: phase7 called");
1625 cfg
= retrieve_config (r
);
1627 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1628 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1629 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1630 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1631 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1632 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1633 } else if ( cfg
->default_principal
) {
1634 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1635 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1637 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1638 if (child
.token
.ticketLen
) {
1639 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1640 ktc_ForgetAllTokens();
1652 waklog_phase9 (request_rec
* r
)
1656 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1657 "mod_waklog: phase9 called");
1659 getModConfig (cfg
, r
->server
);
1661 if ( cfg
->default_principal
) {
1662 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1663 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1676 waklog_new_connection (conn_rec
* c
1685 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1686 "mod_waklog: new_connection called: pid: %d", getpid ());
1688 getModConfig(cfg
, c
->base_server
);
1690 if ( cfg
->default_principal
) {
1691 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1692 cfg
->default_principal
);
1693 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1706 ** Here's a quick explaination for phase0 and phase2:
1707 ** Apache does a stat() on the path between phase0 and
1708 ** phase2, and must by ACLed rl to succeed. So, at
1709 ** phase0 we acquire credentials for umweb:servers from
1710 ** a keytab, and at phase2 we must ensure we remove them.
1712 ** Failure to "unlog" would be a security risk.
1715 waklog_phase2 (request_rec
* r
)
1718 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1719 "mod_waklog: phase2 called");
1721 if (child
.token
.ticketLen
)
1723 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1725 ktc_ForgetAllTokens ();
1727 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1728 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1732 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1733 "mod_waklog: phase2 returning");
1739 module MODULE_VAR_EXPORT waklog_module
= {
1740 STANDARD_MODULE_STUFF
,
1741 waklog_init
, /* module initializer */
1742 waklog_create_dir_config
, /* create per-dir config structures */
1743 waklog_merge_dir_config
, /* merge per-dir config structures */
1744 waklog_create_server_config
, /* create per-server config structures */
1745 waklog_merge_dir_config
, /* merge per-server config structures */
1746 waklog_cmds
, /* table of config file commands */
1747 NULL
, /* [#8] MIME-typed-dispatched handlers */
1748 waklog_phase1
, /* [#1] URI to filename translation */
1749 NULL
, /* [#4] validate user id from request */
1750 NULL
, /* [#5] check if the user is ok _here_ */
1751 waklog_phase3
, /* [#3] check access by host address */
1752 waklog_phase6
, /* [#6] determine MIME type */
1753 waklog_phase7
, /* [#7] pre-run fixups */
1754 waklog_phase9
, /* [#9] log a transaction */
1755 waklog_phase2
, /* [#2] header parser */
1756 waklog_child_init
, /* child_init */
1757 waklog_child_exit
, /* child_exit */
1758 waklog_phase0
/* [#0] post read-request */
1760 , NULL
, /* EAPI: add_module */
1761 NULL
, /* EAPI: remove_module */
1762 NULL
, /* EAPI: rewrite_command */
1763 waklog_new_connection
/* EAPI: new_connection */
1768 waklog_register_hooks (apr_pool_t
* p
)
1770 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1771 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1772 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1773 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1774 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1775 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1776 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1777 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1778 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1779 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1783 module AP_MODULE_DECLARE_DATA waklog_module
= {
1784 STANDARD20_MODULE_STUFF
,
1785 waklog_create_dir_config
, /* create per-dir conf structures */
1786 waklog_merge_dir_config
, /* merge per-dir conf structures */
1787 waklog_create_server_config
, /* create per-server conf structures */
1788 waklog_merge_dir_config
, /* merge per-server conf structures */
1789 waklog_cmds
, /* table of configuration directives */
1790 waklog_register_hooks
/* register hooks */