1 #define _LARGEFILE64_SOURCE
5 #include "http_config.h"
7 #include "http_protocol.h"
8 #include "http_request.h"
14 #include <sys/ioccom.h>
18 #include <sys/types.h>
22 #error "make sure you include the right stuff here"
26 #define MAXNAMELEN 1024
29 #ifdef STANDARD20_MODULE_STUFF
33 /********************* APACHE1 ******************************************************************************/
35 #include "ap_config.h"
36 #include <http_conf_globals.h>
38 #define MK_TABLE_GET ap_table_get
39 #define MK_TABLE_SET ap_table_set
40 #define command(name, func, var, type, usage) \
43 RSRC_CONF | ACCESS_CONF , type, usage }
46 /********************* APACHE2 ******************************************************************************/
48 #include "http_connection.h"
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 );
169 log_error (const char *file
, int line
, int level
, int status
,
170 const server_rec
* s
, const char *fmt
, ...)
176 vsnprintf (errstr
, 1024, fmt
, ap
);
180 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
182 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
187 waklog_config
*retrieve_config(request_rec
*r
) {
192 if ( r
&& r
->main
) {
200 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
203 getModConfig (cfg
, r
->server
);
210 /* set_auth -- sets the tokens of the current process to this user.
211 if "self" is set, it divines the user from the current requests' environment.
212 otherwise, it's gettng it from principal/keytab */
215 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
219 krb5_error_code kerror
= 0;
220 krb5_principal kprinc
= NULL
;
221 krb5_get_init_creds_opt kopts
;
224 krb5_ccache clientccache
;
225 struct ktc_principal server
= { "afs", "", "" };
226 struct ktc_principal client
;
227 struct ktc_token token
;
228 krb5_creds
*v5credsp
= NULL
;
229 krb5_keytab krb5kt
= NULL
;
230 char buf
[MAXNAMELEN
];
234 time_t oldest_time
= 0;
239 int cell_in_principal
;
241 int use_client_credentials
= 0;
243 char k5user
[MAXNAMELEN
] = "";
244 char *k5secret
= NULL
;
248 memset((char *) &increds
, 0, sizeof(increds
));
249 /* init some stuff if it ain't already */
250 /* XXX - In what situation will these not be initialized? */
252 if ( ! child
.kcontext
) {
253 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
254 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
260 if ( !child
.ccache
) {
261 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
262 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
268 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
269 self
, principal
? principal
: "NULL",
270 keytab
? keytab
: "NULL",
272 k5path
? k5path
: "NULL",
274 (r
&& r
->user
) ? r
->user
: "NULL"
276 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
280 /* pull the server config record that we care about... */
283 cfg
= retrieve_config(r
);
285 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
286 "mod_waklog: set_auth using no config" );
287 getModConfig (cfg
, s
);
291 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
296 /* pull out our principal name and stuff from the environment -- webauth better have sent
300 if ( ! ( r
&& r
->connection
&& r
->user
)) {
301 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
302 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
));
306 strncpy(k5user
, r
->user
, sizeof(k5user
));
308 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
309 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
313 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
315 /* if they've supplied a credentials cache */
316 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
318 /* the other thing we need is someone's password */
319 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
321 /* we'll pick this up later after we've checked the cache and current state */
325 strncpy(k5user
, principal
, sizeof(k5user
));
329 strncpy(k5user
, r
->user
, sizeof(k5user
));
332 if (r
&& r
->connection
&& r
->connection
->user
) {
333 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
337 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
);
340 /* see if we should just go ahead and ignore this call, since we already should be set to these
346 pthread_rwlock_rdlock( sharedlock
);
348 rw_rdlock( sharedlock
);
351 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
353 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
355 if ( ( !strcmp( k5user
,
356 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
357 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
359 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
365 /* copy the token out of the cache and into the child object */
367 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
368 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
369 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
370 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
372 /* set our last used time thing */
373 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
383 /* release the lock on the token cache */
385 pthread_rwlock_unlock( sharedlock
);
387 rw_unlock( sharedlock
);
391 /* release the lock on the token cache */
392 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
393 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
397 /* if this is something that was in the cache, and it's the same as the token we already have stored,
398 and we weren't calling this just to renew it... */
400 if ( usecached
&& indentical
) {
401 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
407 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
410 /* clear out the creds structure */
411 memset((void *) &v5creds
, 0, sizeof(v5creds
));
413 /* create a principal out of our k5user string */
415 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
416 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror
) );
420 /* create the credentials options */
422 krb5_get_init_creds_opt_init ( &kopts
);
423 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
424 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
425 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
426 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
428 if ( keytab
|| k5secret
) {
431 /* if we've been passed a keytab, we're going to be getting our credentials from it */
433 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
435 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
436 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
437 "mod_waklog: krb5_kt_resolve %s", error_message(kerror
) );
441 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
442 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
443 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
444 error_message(kerror
) );
447 } else if (k5secret
) {
449 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
451 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
452 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
453 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
454 error_message(kerror
) );
455 /* nuke the password so it doesn't end up in core files */
456 memset(k5secret
, 0, sizeof(k5secret
));
460 memset(k5secret
, 0, sizeof(k5secret
));
463 /* initialize the credentials cache and store the stuff we just got */
464 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
465 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
466 error_message(kerror
));
470 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
471 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
472 error_message(kerror
));
476 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
479 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", error_message(kerror
));
483 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
486 /* If we've got a path to a credentials cache, then try and use that. We can't just
487 * replace child.creds, because we want to ensure that only this request gets access to
490 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
491 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
492 "mod_waklog: can't open provided credentials cache %s err=%d",
497 use_client_credentials
= 1;
500 /* now, to the 'aklog' portion of our program. */
502 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
503 for(attempt
= 0; attempt
<= 1; attempt
++) {
504 strncpy( buf
, "afs", sizeof(buf
) - 1 );
505 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
507 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
508 if (cell_in_principal
) {
509 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
510 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
512 if (cfg
->afs_cell_realm
!= NULL
) {
513 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
514 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
517 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
519 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
520 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", error_message(kerror
));
524 if (!use_client_credentials
) {
525 clientccache
= child
.ccache
;
528 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
529 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", error_message(kerror
), clientccache
);
533 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
535 increds
.times
.endtime
= 0;
537 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
539 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
540 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
542 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
543 error_message(kerror
));
549 cfg
->cell_in_principal
= cell_in_principal
;
553 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
555 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
556 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
557 v5credsp
->ticket
.length
);
561 memset(&token
, 0, sizeof(struct ktc_token
));
563 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
564 token
.endTime
= v5credsp
->times
.endtime
;
566 memmove( &token
.sessionKey
, v5credsp
->keyblock
.contents
, v5credsp
->keyblock
.length
);
567 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
568 token
.ticketLen
= v5credsp
->ticket
.length
;
569 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
573 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
575 buf
[v5credsp
->client
->data
[0].length
] = '\0';
576 if ( v5credsp
->client
->length
> 1 ) {
577 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
578 buflen
= strlen(buf
);
579 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
580 min(v5credsp
->client
->data
[1].length
,
581 MAXKTCNAMELEN
- strlen(buf
) - 1));
582 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
585 /* assemble the client */
586 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
587 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
588 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
590 buf
[v5credsp
->client
->realm
.length
] = '\0';
591 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
593 /* assemble the server's cell */
594 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
596 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
598 /* fill out the AFS ID in the client name */
599 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
600 * strange things seem to happen. */
603 afs_int32 viceId
= 0;
605 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
607 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
608 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
610 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
613 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
617 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
618 server
.name
, server
.instance
, server
.cell
);
620 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
621 client
.name
, client
.instance
, client
.cell
);
623 /* copy the resulting stuff into the child structure */
625 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
626 memcpy(&child
.token
, &token
, sizeof(child
.token
));
627 memcpy(&child
.server
, &server
, sizeof(child
.server
));
628 memcpy(&child
.client
, &client
, sizeof(child
.client
));
630 /* stuff the resulting token-related stuff into our shared token cache */
631 /* note, that anything that was set from a keytab is "persistant", and is immune
632 * from LRU-aging. This is because nothing but the process that's running as root
633 * can update these, and it's running every hour or so and renewing these tokens.
634 * and we don't want them aged out.
637 mytime
= oldest_time
= time(0);
639 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
642 pthread_rwlock_wrlock(sharedlock
);
644 rw_wrlock(sharedlock
);
647 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
648 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
649 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
651 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
653 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
654 child
.clientprincipal
) ) {
655 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
656 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
657 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
658 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
659 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
665 if ( stored
== -1 ) {
666 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
667 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
668 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
669 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
670 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
671 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
676 pthread_rwlock_unlock(sharedlock
);
678 rw_unlock(sharedlock
);
681 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
682 child
.clientprincipal
);
684 } else if ( ! usecached
) {
685 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
694 /* don't ask. Something about AIX. We're leaving it here.*/
695 /* write(2, "", 0); */
697 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
699 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
700 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
701 error_message(rc
), k5user
);
702 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
703 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
704 error_message(rc
), k5user
);
710 if (use_client_credentials
)
711 krb5_cc_close(child
.kcontext
, clientccache
);
713 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
714 if ( increds
.client
)
715 krb5_free_principal (child
.kcontext
, increds
.client
);
716 if ( increds
.server
)
717 krb5_free_principal (child
.kcontext
, increds
.server
);
719 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
721 krb5_free_principal (child
.kcontext
, kprinc
);
724 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
725 } else if ( kerror
) {
726 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, error_message(kerror
));
728 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
731 return kerror
? (int) kerror
: (int) rc
;
736 int get_cfg_usertokens(waklog_config
*cfg
)
738 if (cfg
->usertokens
==WAKLOG_UNSET
)
739 return 0; /* default */
740 return cfg
->usertokens
;
743 int get_cfg_protect(waklog_config
*cfg
)
745 if (cfg
->protect
==WAKLOG_UNSET
)
746 return 0; /* default */
750 int get_cfg_disable_token_cache(waklog_config
*cfg
)
752 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
753 return 0; /* default */
754 return cfg
->disable_token_cache
;
759 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
763 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
765 memset(cfg
, 0, sizeof(waklog_config
));
766 cfg
->path
= "(server)";
767 cfg
->protect
= WAKLOG_UNSET
;
768 cfg
->usertokens
= WAKLOG_UNSET
;
769 cfg
->disable_token_cache
= WAKLOG_UNSET
;
771 cfg
->principal
= NULL
;
772 cfg
->default_principal
= NULL
;
773 cfg
->default_keytab
= NULL
;
774 cfg
->afs_cell
= NULL
;
775 cfg
->afs_cell_realm
= NULL
;
779 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
780 "mod_waklog: server config created.");
785 /* initialize with host-config information */
788 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
792 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
793 memset(cfg
, 0, sizeof(waklog_config
));
795 cfg
->path
= ap_pstrdup(p
, dir
);
796 cfg
->protect
= WAKLOG_UNSET
;
797 cfg
->usertokens
= WAKLOG_UNSET
;
798 cfg
->disable_token_cache
= WAKLOG_UNSET
;
800 cfg
->principal
= NULL
;
801 cfg
->default_principal
= NULL
;
802 cfg
->default_keytab
= NULL
;
803 cfg
->afs_cell
= NULL
;
804 cfg
->afs_cell_realm
= NULL
;
811 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
813 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
814 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
815 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
817 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
819 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
821 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
823 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
825 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
827 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
829 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
831 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
833 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
835 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
837 return (void *) merged
;
841 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
843 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
844 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
845 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
847 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
849 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
851 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
853 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
854 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
856 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
857 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
859 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
860 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
862 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
863 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
865 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
866 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
868 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
869 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
872 return (void *) merged
;
877 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
879 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
880 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
884 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
885 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
890 /* this adds a principal/keytab pair to get their tokens renewed by the
891 child process every few centons. */
893 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
897 if ( renewcount
>= SHARED_TABLE_SIZE
) {
898 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
899 decrease your tokens.");
903 /* check to see if it's already there */
905 for ( i
= 0; i
< renewcount
; i
++ ) {
906 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
911 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
912 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
913 renewtable
[renewcount
].lastrenewed
= 0;
919 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
921 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
922 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
924 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
925 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
927 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
928 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
930 add_to_renewtable(params
->pool
, keytab
, principal
);
938 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
940 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
941 waklog_config
*waklog_srvconfig
=
942 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
944 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
945 "mod_waklog: will use afs_cell: %s", file
);
947 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
948 waklog_srvconfig
->cell_in_principal
= 1;
950 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
951 waklog_srvconfig
->configured
= 1;
953 if (waklog_mconfig
!= NULL
) {
954 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
955 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
956 waklog_mconfig
->configured
= 1;
962 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
964 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
965 waklog_config
*waklog_srvconfig
=
966 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
968 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
969 "mod_waklog: will use afs_cell_realm: %s", file
);
971 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
973 if (waklog_mconfig
!= NULL
) {
974 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
980 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
982 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
983 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
985 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
987 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
988 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
990 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
991 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
993 /* this also gets set at the server level */
994 if ( mconfig
&& ( ! cfg
->path
) ) {
995 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
996 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
998 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
999 return "Unable to set DefaultPrincipal outside of top level config!";
1002 add_to_renewtable( params
->pool
, keytab
, principal
);
1004 cfg
->configured
= 1;
1010 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1012 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1013 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1015 cfg
->usertokens
= flag
;
1017 cfg
->configured
= 1;
1019 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1020 "mod_waklog: waklog_use_user_tokens set");
1026 set_waklog_disable_token_cache (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
->disable_token_cache
= flag
;
1033 cfg
->configured
= 1;
1035 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1036 "mod_waklog: waklog_disable_token_cache set");
1042 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1044 apr_status_t
waklog_child_exit( void *sr
) {
1046 server_rec
*s
= (server_rec
*) sr
;
1049 if ( child
.ccache
) {
1050 krb5_cc_close(child
.kcontext
, child
.ccache
);
1053 if ( child
.kcontext
) {
1054 krb5_free_context(child
.kcontext
);
1057 /* forget our tokens */
1059 ktc_ForgetAllTokens ();
1061 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1062 "mod_waklog: waklog_child_exit complete");
1072 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1074 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1078 krb5_error_code code
;
1083 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1085 if ( !sharedspace
) {
1086 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1090 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1092 memset (&child
, 0, sizeof(child
));
1094 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1095 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1098 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1099 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1102 if ( pag_for_children
) {
1106 getModConfig (cfg
, s
);
1108 if ( cfg
->default_principal
!= NULL
) {
1109 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1110 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1113 cell
= strdup(cfg
->afs_cell
);
1114 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1117 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1120 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1121 "mod_waklog: child_init returned");
1126 command_rec waklog_cmds
[] = {
1128 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1129 "Use the supplied AFS cell (required)"),
1131 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1132 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1134 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1135 "enable waklog on a server, location, or directory basis"),
1137 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1138 "Set the default principal that the server runs as"),
1140 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1141 "Set the principal on a <Location>-specific basis"),
1143 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1144 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1146 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1147 "Use the requesting user tokens (from webauth)"),
1153 /* not currently using this */
1156 token_cleanup (void *data
)
1158 request_rec
*r
= (request_rec
*) data
;
1160 if (child
.token
.ticketLen
)
1162 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1164 ktc_ForgetAllTokens ();
1166 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1167 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1173 /* This function doesn't return anything but is passed to ap_bspawn_child on
1174 * Apache 1 which expects it to return a pid as an int. For want of better
1175 * understanding, err on the side of not changing Apache 1 code while fixing
1176 * the compile warning on Apache 2. */
1182 waklog_child_routine (void *data
, child_info
* pinfo
)
1185 server_rec
*s
= (server_rec
*) data
;
1186 krb5_error_code code
;
1188 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1193 getModConfig( cfg
, s
);
1195 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1197 memset (&child
, 0, sizeof(child
));
1199 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1200 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1203 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1204 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1207 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1209 /* need to do this so we can make PTS calls */
1210 cell
= strdup(cfg
->afs_cell
); /* stupid */
1211 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1213 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1217 for ( i
= 0; i
< renewcount
; ++i
) {
1218 renewtable
[i
].lastrenewed
= time(0);
1219 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1220 renewtable
[i
].keytab
);
1222 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1224 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1225 things that it needs to read */
1227 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1228 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1229 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1234 sharedspace
->renewcount
++;
1243 left
-= ( time(0) - when
);
1254 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1255 apr_pool_t
* ptemp
, server_rec
* s
)
1258 extern char *version
;
1263 int use_existing
= 1;
1265 char cache_file
[MAXNAMELEN
];
1267 pthread_rwlockattr_t rwlock_attr
;
1271 getModConfig (cfg
, s
);
1273 /* initialize_module() will be called twice, and if it's a DSO
1274 * then all static data from the first call will be lost. Only
1275 * set up our static data on the second call.
1276 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1277 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1280 if (cfg
->afs_cell
==NULL
) {
1281 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1282 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1283 /** clobber apache */
1289 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1290 apr_pool_cleanup_null
, s
->process
->pool
);
1294 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1295 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1297 if ( sharedspace
) {
1298 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1301 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1303 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1305 if ( errno
== ENOENT
) {
1307 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1309 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1310 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1314 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1318 if ( use_existing
== 0 ) {
1319 struct sharedspace_s bob
;
1320 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1321 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1322 if ( write(fd
, &bob
, sizeof(struct sharedspace_s
)) != sizeof(struct sharedspace_s
) ) {
1323 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: failed to write to our cache file %s (%d)", cache_file
, errno
);
1326 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1329 /* mmap the region */
1331 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1333 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1334 err
= unlink(cache_file
);
1336 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1338 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1341 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1347 #define locktype pthread_rwlock_t
1349 #define locktype rwlock_t
1352 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) != NULL
) {
1353 #ifndef use_pthreads
1354 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1356 pthread_rwlockattr_init(&rwlock_attr
);
1357 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1358 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1361 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1366 /* set our default tokens */
1368 oldrenewcount
= sharedspace
->renewcount
;
1370 pag_for_children
= 0;
1372 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1374 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1376 if (rv
== APR_INCHILD
)
1378 waklog_child_routine (s
, NULL
);
1382 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1384 /* parent and child */
1385 cfg
->forked
= proc
->pid
;
1386 pag_for_children
= 1;
1388 if ( use_existing
== 0 ) {
1389 /* wait here until our child process has gone and done it's renewing thing. */
1390 while( sharedspace
->renewcount
== oldrenewcount
) {
1391 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1396 if ( cfg
->default_principal
) {
1397 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1404 waklog_init (server_rec
* s
, MK_POOL
* p
)
1406 extern char *version
;
1410 int use_existing
= 1;
1412 char cache_file
[MAXNAMELEN
];
1414 pthread_rwlockattr_t rwlock_attr
;
1417 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1418 "mod_waklog: version %s initialized.", version
);
1420 if ( sharedspace
) {
1421 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1424 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1426 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1428 if ( errno
== ENOENT
) {
1430 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1432 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1433 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1437 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1442 if ( use_existing
== 0 ) {
1443 struct sharedspace_s bob
;
1444 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1445 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1446 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1447 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1450 /* mmap the region */
1452 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1453 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1456 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1462 #define locktype pthread_rwlock_t
1464 #define locktype rwlock_t
1467 /* mmap our shared space for our lock */
1468 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1469 #ifndef use_pthreads
1470 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1472 pthread_rwlockattr_init(&rwlock_attr
);
1473 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1474 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1477 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1482 /* set our default tokens */
1484 getModConfig (cfg
, s
);
1486 oldrenewcount
= sharedspace
->renewcount
;
1488 pag_for_children
= 0;
1490 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1493 pag_for_children
= 1;
1495 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1496 "mod_waklog: ap_bspawn_child: %d.", pid
);
1498 if ( use_existing
== 0 ) {
1499 /* wait here until our child process has gone and done it's renewing thing. */
1500 while( sharedspace
->renewcount
== oldrenewcount
) {
1501 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1506 if ( cfg
->default_principal
) {
1507 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1514 waklog_phase0 (request_rec
* r
)
1518 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1519 "mod_waklog: phase0 called");
1521 cfg
= retrieve_config(r
);
1523 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1524 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1525 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1526 } else if ( cfg
->default_principal
) {
1527 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1528 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1531 if (child
.token
.ticketLen
) {
1532 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1533 ktc_ForgetAllTokens();
1536 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1543 waklog_phase1 (request_rec
* r
)
1547 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1548 "mod_waklog: phase1 called");
1550 cfg
= retrieve_config(r
);
1552 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1553 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1554 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1555 } else if ( cfg
->default_principal
) {
1556 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1557 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1559 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1566 waklog_phase3 (request_rec
* r
)
1570 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1571 "mod_waklog: phase 3 called");
1573 cfg
= retrieve_config(r
);
1575 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1576 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1577 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1578 } else if ( cfg
->default_principal
) {
1579 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1580 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1582 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1589 waklog_phase6 (request_rec
* r
)
1593 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1594 "mod_waklog: phase6 called");
1596 cfg
= retrieve_config(r
);
1598 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1599 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1600 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1601 } else if ( cfg
->default_principal
) {
1602 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1603 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1605 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1612 waklog_phase7 (request_rec
* r
)
1617 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1618 "mod_waklog: phase7 called");
1620 cfg
= retrieve_config (r
);
1622 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1623 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1624 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1625 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1626 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1627 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1628 } else if ( cfg
->default_principal
) {
1629 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1630 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1632 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1633 if (child
.token
.ticketLen
) {
1634 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1635 ktc_ForgetAllTokens();
1647 waklog_phase9 (request_rec
* r
)
1651 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1652 "mod_waklog: phase9 called");
1654 getModConfig (cfg
, r
->server
);
1656 if ( cfg
->default_principal
) {
1657 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1658 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1671 waklog_new_connection (conn_rec
* c
1680 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1681 "mod_waklog: new_connection called: pid: %d", getpid ());
1683 getModConfig(cfg
, c
->base_server
);
1685 if ( cfg
->default_principal
) {
1686 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1687 cfg
->default_principal
);
1688 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1701 ** Here's a quick explaination for phase0 and phase2:
1702 ** Apache does a stat() on the path between phase0 and
1703 ** phase2, and must by ACLed rl to succeed. So, at
1704 ** phase0 we acquire credentials for umweb:servers from
1705 ** a keytab, and at phase2 we must ensure we remove them.
1707 ** Failure to "unlog" would be a security risk.
1710 waklog_phase2 (request_rec
* r
)
1713 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1714 "mod_waklog: phase2 called");
1716 if (child
.token
.ticketLen
)
1718 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1720 ktc_ForgetAllTokens ();
1722 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1723 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1727 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1728 "mod_waklog: phase2 returning");
1734 module MODULE_VAR_EXPORT waklog_module
= {
1735 STANDARD_MODULE_STUFF
,
1736 waklog_init
, /* module initializer */
1737 waklog_create_dir_config
, /* create per-dir config structures */
1738 waklog_merge_dir_config
, /* merge per-dir config structures */
1739 waklog_create_server_config
, /* create per-server config structures */
1740 waklog_merge_dir_config
, /* merge per-server config structures */
1741 waklog_cmds
, /* table of config file commands */
1742 NULL
, /* [#8] MIME-typed-dispatched handlers */
1743 waklog_phase1
, /* [#1] URI to filename translation */
1744 NULL
, /* [#4] validate user id from request */
1745 NULL
, /* [#5] check if the user is ok _here_ */
1746 waklog_phase3
, /* [#3] check access by host address */
1747 waklog_phase6
, /* [#6] determine MIME type */
1748 waklog_phase7
, /* [#7] pre-run fixups */
1749 waklog_phase9
, /* [#9] log a transaction */
1750 waklog_phase2
, /* [#2] header parser */
1751 waklog_child_init
, /* child_init */
1752 waklog_child_exit
, /* child_exit */
1753 waklog_phase0
/* [#0] post read-request */
1755 , NULL
, /* EAPI: add_module */
1756 NULL
, /* EAPI: remove_module */
1757 NULL
, /* EAPI: rewrite_command */
1758 waklog_new_connection
/* EAPI: new_connection */
1763 waklog_register_hooks (apr_pool_t
* p
)
1765 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1766 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1767 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1768 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1769 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1770 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1771 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1772 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1773 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1774 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1778 module AP_MODULE_DECLARE_DATA waklog_module
= {
1779 STANDARD20_MODULE_STUFF
,
1780 waklog_create_dir_config
, /* create per-dir conf structures */
1781 waklog_merge_dir_config
, /* merge per-dir conf structures */
1782 waklog_create_server_config
, /* create per-server conf structures */
1783 waklog_merge_dir_config
, /* merge per-server conf structures */
1784 waklog_cmds
, /* table of configuration directives */
1785 waklog_register_hooks
/* register hooks */