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
57 #define command(name, func, var, type, usage) \
58 AP_INIT_ ## type (name, (void*) func, \
60 RSRC_CONF | ACCESS_CONF, usage)
61 module AP_MODULE_DECLARE_DATA waklog_module
;
62 typedef struct { int dummy
; } child_info
;
63 const char *userdata_key
= "waklog_init";
66 /**************************************************************************************************/
71 #include <afs/param.h>
73 #include <afs/venus.h>
75 #include <afs/dirpath.h>
76 #include <afs/ptuser.h>
79 #define TKT_LIFE ( 12 * 60 * 60 )
80 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
82 #define WAKLOG_UNSET -1
86 #define APLOG_DEBUG APLOG_ERR
89 /* this is used to turn off pag generation for the backround worker child during startup */
90 int pag_for_children
= 1;
98 int cell_in_principal
;
99 int disable_token_cache
;
102 char *default_principal
;
103 char *default_keytab
;
105 char *afs_cell_realm
;
113 struct ktc_token token
;
114 char clientprincipal
[MAXNAMELEN
];
115 krb5_context kcontext
;
117 struct ktc_principal server
;
118 struct ktc_principal client
;
120 } waklog_child_config
;
122 waklog_child_config child
;
124 struct tokencache_ent
{
125 char clientprincipal
[MAXNAMELEN
];
126 struct ktc_token token
;
127 struct ktc_principal client
;
128 struct ktc_principal server
;
133 #define SHARED_TABLE_SIZE 512
135 struct sharedspace_s
{
137 struct tokencache_ent sharedtokens
[SHARED_TABLE_SIZE
];
140 struct sharedspace_s
*sharedspace
= NULL
;
149 pthread_rwlock_t
*sharedlock
= NULL
;
151 rwlock_t
*sharedlock
= NULL
;
154 struct renew_ent renewtable
[SHARED_TABLE_SIZE
];
160 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
164 log_error (const char *file
, int line
, int level
, int status
,
165 const server_rec
* s
, const char *fmt
, ...)
171 vsnprintf (errstr
, 1024, fmt
, ap
);
175 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
177 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
182 waklog_config
*retrieve_config(request_rec
*r
) {
187 if ( r
&& r
->main
) {
195 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
198 getModConfig (cfg
, r
->server
);
205 /* set_auth -- sets the tokens of the current process to this user.
206 if "self" is set, it divines the user from the current requests' environment.
207 otherwise, it's gettng it from principal/keytab */
210 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
214 krb5_error_code kerror
= 0;
215 krb5_principal kprinc
= NULL
;
216 krb5_get_init_creds_opt kopts
;
219 krb5_ccache clientccache
;
220 struct ktc_principal server
= { "afs", "", "" };
221 struct ktc_principal client
;
222 struct ktc_token token
;
223 krb5_creds
*v5credsp
= NULL
;
224 krb5_keytab krb5kt
= NULL
;
225 char buf
[MAXNAMELEN
];
229 time_t oldest_time
= 0;
234 int cell_in_principal
;
236 int use_client_credentials
= 0;
238 char k5user
[MAXNAMELEN
] = "";
239 char *k5secret
= NULL
;
243 memset((char *) &increds
, 0, sizeof(increds
));
244 /* init some stuff if it ain't already */
245 /* XXX - In what situation will these not be initialized? */
247 if ( ! child
.kcontext
) {
248 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
249 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
255 if ( !child
.ccache
) {
256 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
257 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
263 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
264 self
, principal
? principal
: "NULL",
265 keytab
? keytab
: "NULL",
267 k5path
? k5path
: "NULL",
269 (r
&& r
->user
) ? r
->user
: "NULL"
271 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
275 /* pull the server config record that we care about... */
278 cfg
= retrieve_config(r
);
280 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
281 "mod_waklog: set_auth using no config" );
282 getModConfig (cfg
, s
);
286 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
291 /* pull out our principal name and stuff from the environment -- webauth better have sent
295 if ( ! ( r
&& r
->connection
&& r
->user
)) {
296 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
297 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
));
301 strncpy(k5user
, r
->user
, sizeof(k5user
));
303 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
304 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
308 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
310 /* if they've supplied a credentials cache */
311 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
313 /* the other thing we need is someone's password */
314 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
316 /* we'll pick this up later after we've checked the cache and current state */
320 strncpy(k5user
, principal
, sizeof(k5user
));
324 strncpy(k5user
, r
->user
, sizeof(k5user
));
327 if (r
&& r
->connection
&& r
->connection
->user
) {
328 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
332 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
);
335 /* see if we should just go ahead and ignore this call, since we already should be set to these
341 pthread_rwlock_rdlock( sharedlock
);
343 rw_rdlock( sharedlock
);
346 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
348 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
350 if ( ( !strcmp( k5user
,
351 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
352 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
354 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
360 /* copy the token out of the cache and into the child object */
362 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
363 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
364 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
365 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
367 /* set our last used time thing */
368 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
378 /* release the lock on the token cache */
380 pthread_rwlock_unlock( sharedlock
);
382 rw_unlock( sharedlock
);
386 /* release the lock on the token cache */
387 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
388 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
392 /* if this is something that was in the cache, and it's the same as the token we already have stored,
393 and we weren't calling this just to renew it... */
395 if ( usecached
&& indentical
) {
396 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
402 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
405 /* clear out the creds structure */
406 memset((void *) &v5creds
, 0, sizeof(v5creds
));
408 /* create a principal out of our k5user string */
410 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
411 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror
) );
415 /* create the credentials options */
417 krb5_get_init_creds_opt_init ( &kopts
);
418 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
419 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
420 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
421 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
423 if ( keytab
|| k5secret
) {
426 /* if we've been passed a keytab, we're going to be getting our credentials from it */
428 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
430 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
431 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
432 "mod_waklog: krb5_kt_resolve %s", error_message(kerror
) );
436 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
437 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
438 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
439 error_message(kerror
) );
442 } else if (k5secret
) {
444 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
446 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
447 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
448 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
449 error_message(kerror
) );
450 /* nuke the password so it doesn't end up in core files */
451 memset(k5secret
, 0, sizeof(k5secret
));
455 memset(k5secret
, 0, sizeof(k5secret
));
458 /* initialize the credentials cache and store the stuff we just got */
459 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
460 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
461 error_message(kerror
));
465 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
466 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
467 error_message(kerror
));
471 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
474 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", error_message(kerror
));
478 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
481 /* If we've got a path to a credentials cache, then try and use that. We can't just
482 * replace child.creds, because we want to ensure that only this request gets access to
485 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
486 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
487 "mod_waklog: can't open provided credentials cache %s err=%d",
492 use_client_credentials
= 1;
495 /* now, to the 'aklog' portion of our program. */
497 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
498 for(attempt
= 0; attempt
<= 1; attempt
++) {
499 strncpy( buf
, "afs", sizeof(buf
) - 1 );
500 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
502 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
503 if (cell_in_principal
) {
504 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
505 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
507 if (cfg
->afs_cell_realm
!= NULL
) {
508 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
509 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
512 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
514 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
515 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", error_message(kerror
));
519 if (!use_client_credentials
) {
520 clientccache
= child
.ccache
;
523 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
524 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", error_message(kerror
), clientccache
);
528 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
530 increds
.times
.endtime
= 0;
532 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
534 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
535 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
537 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
538 error_message(kerror
));
544 cfg
->cell_in_principal
= cell_in_principal
;
548 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
550 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
551 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
552 v5credsp
->ticket
.length
);
556 memset(&token
, 0, sizeof(struct ktc_token
));
558 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
559 token
.endTime
= v5credsp
->times
.endtime
;
561 memmove( &token
.sessionKey
, v5credsp
->keyblock
.contents
, v5credsp
->keyblock
.length
);
562 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
563 token
.ticketLen
= v5credsp
->ticket
.length
;
564 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
568 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
570 buf
[v5credsp
->client
->data
[0].length
] = '\0';
571 if ( v5credsp
->client
->length
> 1 ) {
572 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
573 buflen
= strlen(buf
);
574 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
575 min(v5credsp
->client
->data
[1].length
,
576 MAXKTCNAMELEN
- strlen(buf
) - 1));
577 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
580 /* assemble the client */
581 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
582 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
583 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
585 buf
[v5credsp
->client
->realm
.length
] = '\0';
586 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
588 /* assemble the server's cell */
589 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
591 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
593 /* fill out the AFS ID in the client name */
594 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
595 * strange things seem to happen. */
598 afs_int32 viceId
= 0;
600 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
602 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
603 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
605 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
608 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
612 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
613 server
.name
, server
.instance
, server
.cell
);
615 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
616 client
.name
, client
.instance
, client
.cell
);
618 /* copy the resulting stuff into the child structure */
620 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
621 memcpy(&child
.token
, &token
, sizeof(child
.token
));
622 memcpy(&child
.server
, &server
, sizeof(child
.server
));
623 memcpy(&child
.client
, &client
, sizeof(child
.client
));
625 /* stuff the resulting token-related stuff into our shared token cache */
626 /* note, that anything that was set from a keytab is "persistant", and is immune
627 * from LRU-aging. This is because nothing but the process that's running as root
628 * can update these, and it's running every hour or so and renewing these tokens.
629 * and we don't want them aged out.
632 mytime
= oldest_time
= time(0);
634 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
637 pthread_rwlock_wrlock(sharedlock
);
639 rw_wrlock(sharedlock
);
642 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
643 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
644 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
646 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
648 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
649 child
.clientprincipal
) ) {
650 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
651 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
652 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
653 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
654 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
660 if ( stored
== -1 ) {
661 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
662 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
663 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
664 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
665 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
666 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
671 pthread_rwlock_unlock(sharedlock
);
673 rw_unlock(sharedlock
);
676 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
677 child
.clientprincipal
);
679 } else if ( ! usecached
) {
680 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
689 /* don't ask. Something about AIX. We're leaving it here.*/
690 /* write(2, "", 0); */
692 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
694 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
695 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
696 error_message(rc
), k5user
);
697 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
698 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
699 error_message(rc
), k5user
);
705 if (use_client_credentials
)
706 krb5_cc_close(child
.kcontext
, clientccache
);
708 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
709 if ( increds
.client
)
710 krb5_free_principal (child
.kcontext
, increds
.client
);
711 if ( increds
.server
)
712 krb5_free_principal (child
.kcontext
, increds
.server
);
714 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
716 krb5_free_principal (child
.kcontext
, kprinc
);
719 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
720 } else if ( kerror
) {
721 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, error_message(kerror
));
723 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
726 return kerror
? (int) kerror
: (int) rc
;
731 int get_cfg_usertokens(waklog_config
*cfg
)
733 if (cfg
->usertokens
==WAKLOG_UNSET
)
734 return 0; /* default */
735 return cfg
->usertokens
;
738 int get_cfg_protect(waklog_config
*cfg
)
740 if (cfg
->protect
==WAKLOG_UNSET
)
741 return 0; /* default */
745 int get_cfg_disable_token_cache(waklog_config
*cfg
)
747 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
748 return 0; /* default */
749 return cfg
->disable_token_cache
;
754 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
758 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
760 memset(cfg
, 0, sizeof(waklog_config
));
761 cfg
->path
= "(server)";
762 cfg
->protect
= WAKLOG_UNSET
;
763 cfg
->usertokens
= WAKLOG_UNSET
;
764 cfg
->disable_token_cache
= WAKLOG_UNSET
;
766 cfg
->principal
= NULL
;
767 cfg
->default_principal
= NULL
;
768 cfg
->default_keytab
= NULL
;
769 cfg
->afs_cell
= NULL
;
770 cfg
->afs_cell_realm
= NULL
;
774 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
775 "mod_waklog: server config created.");
780 /* initialize with host-config information */
783 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
787 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
788 memset(cfg
, 0, sizeof(waklog_config
));
790 cfg
->path
= ap_pstrdup(p
, dir
);
791 cfg
->protect
= WAKLOG_UNSET
;
792 cfg
->usertokens
= WAKLOG_UNSET
;
793 cfg
->disable_token_cache
= WAKLOG_UNSET
;
795 cfg
->principal
= NULL
;
796 cfg
->default_principal
= NULL
;
797 cfg
->default_keytab
= NULL
;
798 cfg
->afs_cell
= NULL
;
799 cfg
->afs_cell_realm
= NULL
;
806 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
808 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
809 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
810 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
812 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
814 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
816 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
818 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
820 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
822 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
824 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
826 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
828 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
830 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
832 return (void *) merged
;
836 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
838 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
839 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
840 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
842 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
844 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
846 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
848 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
849 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
851 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
852 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
854 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
855 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
857 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
858 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
860 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
861 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
863 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
864 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
867 return (void *) merged
;
872 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
874 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
875 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
879 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
880 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
885 /* this adds a principal/keytab pair to get their tokens renewed by the
886 child process every few centons. */
888 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
892 if ( renewcount
>= SHARED_TABLE_SIZE
) {
893 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
894 decrease your tokens.");
898 /* check to see if it's already there */
900 for ( i
= 0; i
< renewcount
; i
++ ) {
901 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
906 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
907 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
908 renewtable
[renewcount
].lastrenewed
= 0;
914 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
916 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
917 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
919 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
920 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
922 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
923 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
925 add_to_renewtable(params
->pool
, keytab
, principal
);
933 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
935 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
936 waklog_config
*waklog_srvconfig
=
937 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
939 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
940 "mod_waklog: will use afs_cell: %s", file
);
942 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
943 waklog_srvconfig
->cell_in_principal
= 1;
945 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
946 waklog_srvconfig
->configured
= 1;
948 if (waklog_mconfig
!= NULL
) {
949 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
950 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
951 waklog_mconfig
->configured
= 1;
957 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
959 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
960 waklog_config
*waklog_srvconfig
=
961 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
963 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
964 "mod_waklog: will use afs_cell_realm: %s", file
);
966 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
968 if (waklog_mconfig
!= NULL
) {
969 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
975 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
977 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
978 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
980 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
982 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
983 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
985 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
986 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
988 /* this also gets set at the server level */
989 if ( mconfig
&& ( ! cfg
->path
) ) {
990 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
991 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
993 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
994 return "Unable to set DefaultPrincipal outside of top level config!";
997 add_to_renewtable( params
->pool
, keytab
, principal
);
1005 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1007 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1008 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1010 cfg
->usertokens
= flag
;
1012 cfg
->configured
= 1;
1014 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1015 "mod_waklog: waklog_use_user_tokens set");
1021 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1023 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1024 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1026 cfg
->disable_token_cache
= flag
;
1028 cfg
->configured
= 1;
1030 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1031 "mod_waklog: waklog_disable_token_cache set");
1037 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1039 apr_status_t
waklog_child_exit( void *sr
) {
1041 server_rec
*s
= (server_rec
*) sr
;
1044 if ( child
.ccache
) {
1045 krb5_cc_close(child
.kcontext
, child
.ccache
);
1048 if ( child
.kcontext
) {
1049 krb5_free_context(child
.kcontext
);
1052 /* forget our tokens */
1054 ktc_ForgetAllTokens ();
1056 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1057 "mod_waklog: waklog_child_exit complete");
1067 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1069 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1073 krb5_error_code code
;
1078 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1080 if ( !sharedspace
) {
1081 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1085 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1087 memset (&child
, 0, sizeof(child
));
1089 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1090 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1093 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1094 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1097 if ( pag_for_children
) {
1101 getModConfig (cfg
, s
);
1103 if ( cfg
->default_principal
!= NULL
) {
1104 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1105 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1108 cell
= strdup(cfg
->afs_cell
);
1109 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1112 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1115 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1116 "mod_waklog: child_init returned");
1121 command_rec waklog_cmds
[] = {
1123 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1124 "Use the supplied AFS cell (required)"),
1126 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1127 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1129 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1130 "enable waklog on a server, location, or directory basis"),
1132 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1133 "Set the default principal that the server runs as"),
1135 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1136 "Set the principal on a <Location>-specific basis"),
1138 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1139 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1141 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1142 "Use the requesting user tokens (from webauth)"),
1148 /* not currently using this */
1151 token_cleanup (void *data
)
1153 request_rec
*r
= (request_rec
*) data
;
1155 if (child
.token
.ticketLen
)
1157 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1159 ktc_ForgetAllTokens ();
1161 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1162 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1168 /* This function doesn't return anything but is passed to ap_bspawn_child on
1169 * Apache 1 which expects it to return a pid as an int. For want of better
1170 * understanding, err on the side of not changing Apache 1 code while fixing
1171 * the compile warning on Apache 2. */
1177 waklog_child_routine (void *data
, child_info
* pinfo
)
1180 server_rec
*s
= (server_rec
*) data
;
1181 krb5_error_code code
;
1183 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1188 getModConfig( cfg
, s
);
1190 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1192 memset (&child
, 0, sizeof(child
));
1194 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1195 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1198 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1199 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1202 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1204 /* need to do this so we can make PTS calls */
1205 cell
= strdup(cfg
->afs_cell
); /* stupid */
1206 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1208 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1212 for ( i
= 0; i
< renewcount
; ++i
) {
1213 renewtable
[i
].lastrenewed
= time(0);
1214 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1215 renewtable
[i
].keytab
);
1217 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1219 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1220 things that it needs to read */
1222 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1223 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1224 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1229 sharedspace
->renewcount
++;
1238 left
-= ( time(0) - when
);
1249 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1250 apr_pool_t
* ptemp
, server_rec
* s
)
1253 extern char *version
;
1258 int use_existing
= 1;
1260 char cache_file
[MAXNAMELEN
];
1262 pthread_rwlockattr_t rwlock_attr
;
1266 getModConfig (cfg
, s
);
1268 /* initialize_module() will be called twice, and if it's a DSO
1269 * then all static data from the first call will be lost. Only
1270 * set up our static data on the second call.
1271 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1272 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1275 if (cfg
->afs_cell
==NULL
) {
1276 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1277 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1278 /** clobber apache */
1284 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1285 apr_pool_cleanup_null
, s
->process
->pool
);
1289 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1290 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1292 if ( sharedspace
) {
1293 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1296 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1298 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1300 if ( errno
== ENOENT
) {
1302 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1304 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1305 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1309 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1313 if ( use_existing
== 0 ) {
1314 struct sharedspace_s bob
;
1315 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1316 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1317 if ( write(fd
, &bob
, sizeof(struct sharedspace_s
)) != sizeof(struct sharedspace_s
) ) {
1318 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: failed to write to our cache file %s (%d)", cache_file
, errno
);
1321 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1324 /* mmap the region */
1326 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1328 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1329 err
= unlink(cache_file
);
1331 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1333 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1336 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1342 #define locktype pthread_rwlock_t
1344 #define locktype rwlock_t
1347 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) != NULL
) {
1348 #ifndef use_pthreads
1349 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1351 pthread_rwlockattr_init(&rwlock_attr
);
1352 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1353 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1356 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1361 /* set our default tokens */
1363 oldrenewcount
= sharedspace
->renewcount
;
1365 pag_for_children
= 0;
1367 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1369 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1371 if (rv
== APR_INCHILD
)
1373 waklog_child_routine (s
, NULL
);
1377 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1379 /* parent and child */
1380 cfg
->forked
= proc
->pid
;
1381 pag_for_children
= 1;
1383 if ( use_existing
== 0 ) {
1384 /* wait here until our child process has gone and done it's renewing thing. */
1385 while( sharedspace
->renewcount
== oldrenewcount
) {
1386 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1391 if ( cfg
->default_principal
) {
1392 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1399 waklog_init (server_rec
* s
, MK_POOL
* p
)
1401 extern char *version
;
1405 int use_existing
= 1;
1407 char cache_file
[MAXNAMELEN
];
1409 pthread_rwlockattr_t rwlock_attr
;
1412 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1413 "mod_waklog: version %s initialized.", version
);
1415 if ( sharedspace
) {
1416 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1419 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1421 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1423 if ( errno
== ENOENT
) {
1425 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1427 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1428 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1432 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1437 if ( use_existing
== 0 ) {
1438 struct sharedspace_s bob
;
1439 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1440 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1441 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1442 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1445 /* mmap the region */
1447 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1448 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1451 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1457 #define locktype pthread_rwlock_t
1459 #define locktype rwlock_t
1462 /* mmap our shared space for our lock */
1463 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1464 #ifndef use_pthreads
1465 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1467 pthread_rwlockattr_init(&rwlock_attr
);
1468 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1469 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1472 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1477 /* set our default tokens */
1479 getModConfig (cfg
, s
);
1481 oldrenewcount
= sharedspace
->renewcount
;
1483 pag_for_children
= 0;
1485 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1488 pag_for_children
= 1;
1490 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1491 "mod_waklog: ap_bspawn_child: %d.", pid
);
1493 if ( use_existing
== 0 ) {
1494 /* wait here until our child process has gone and done it's renewing thing. */
1495 while( sharedspace
->renewcount
== oldrenewcount
) {
1496 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1501 if ( cfg
->default_principal
) {
1502 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1509 waklog_phase0 (request_rec
* r
)
1513 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1514 "mod_waklog: phase0 called");
1516 cfg
= retrieve_config(r
);
1518 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1519 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1520 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1521 } else if ( cfg
->default_principal
) {
1522 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1523 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1526 if (child
.token
.ticketLen
) {
1527 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1528 ktc_ForgetAllTokens();
1531 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1538 waklog_phase1 (request_rec
* r
)
1542 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1543 "mod_waklog: phase1 called");
1545 cfg
= retrieve_config(r
);
1547 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1548 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1549 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1550 } else if ( cfg
->default_principal
) {
1551 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1552 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1554 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1561 waklog_phase3 (request_rec
* r
)
1565 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1566 "mod_waklog: phase 3 called");
1568 cfg
= retrieve_config(r
);
1570 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1571 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1572 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1573 } else if ( cfg
->default_principal
) {
1574 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1575 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1577 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1584 waklog_phase6 (request_rec
* r
)
1588 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1589 "mod_waklog: phase6 called");
1591 cfg
= retrieve_config(r
);
1593 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1594 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1595 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1596 } else if ( cfg
->default_principal
) {
1597 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1598 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1600 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1607 waklog_phase7 (request_rec
* r
)
1612 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1613 "mod_waklog: phase7 called");
1615 cfg
= retrieve_config (r
);
1617 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1618 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1619 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1620 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1621 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1622 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1623 } else if ( cfg
->default_principal
) {
1624 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1625 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1627 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1628 if (child
.token
.ticketLen
) {
1629 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1630 ktc_ForgetAllTokens();
1642 waklog_phase9 (request_rec
* r
)
1646 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1647 "mod_waklog: phase9 called");
1649 getModConfig (cfg
, r
->server
);
1651 if ( cfg
->default_principal
) {
1652 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1653 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1666 waklog_new_connection (conn_rec
* c
1675 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1676 "mod_waklog: new_connection called: pid: %d", getpid ());
1678 getModConfig(cfg
, c
->base_server
);
1680 if ( cfg
->default_principal
) {
1681 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1682 cfg
->default_principal
);
1683 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1696 ** Here's a quick explaination for phase0 and phase2:
1697 ** Apache does a stat() on the path between phase0 and
1698 ** phase2, and must by ACLed rl to succeed. So, at
1699 ** phase0 we acquire credentials for umweb:servers from
1700 ** a keytab, and at phase2 we must ensure we remove them.
1702 ** Failure to "unlog" would be a security risk.
1705 waklog_phase2 (request_rec
* r
)
1708 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1709 "mod_waklog: phase2 called");
1711 if (child
.token
.ticketLen
)
1713 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1715 ktc_ForgetAllTokens ();
1717 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1718 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1722 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1723 "mod_waklog: phase2 returning");
1729 module MODULE_VAR_EXPORT waklog_module
= {
1730 STANDARD_MODULE_STUFF
,
1731 waklog_init
, /* module initializer */
1732 waklog_create_dir_config
, /* create per-dir config structures */
1733 waklog_merge_dir_config
, /* merge per-dir config structures */
1734 waklog_create_server_config
, /* create per-server config structures */
1735 waklog_merge_dir_config
, /* merge per-server config structures */
1736 waklog_cmds
, /* table of config file commands */
1737 NULL
, /* [#8] MIME-typed-dispatched handlers */
1738 waklog_phase1
, /* [#1] URI to filename translation */
1739 NULL
, /* [#4] validate user id from request */
1740 NULL
, /* [#5] check if the user is ok _here_ */
1741 waklog_phase3
, /* [#3] check access by host address */
1742 waklog_phase6
, /* [#6] determine MIME type */
1743 waklog_phase7
, /* [#7] pre-run fixups */
1744 waklog_phase9
, /* [#9] log a transaction */
1745 waklog_phase2
, /* [#2] header parser */
1746 waklog_child_init
, /* child_init */
1747 waklog_child_exit
, /* child_exit */
1748 waklog_phase0
/* [#0] post read-request */
1750 , NULL
, /* EAPI: add_module */
1751 NULL
, /* EAPI: remove_module */
1752 NULL
, /* EAPI: rewrite_command */
1753 waklog_new_connection
/* EAPI: new_connection */
1758 waklog_register_hooks (apr_pool_t
* p
)
1760 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1761 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1762 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1763 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1764 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1765 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1766 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1767 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1768 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1769 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1773 module AP_MODULE_DECLARE_DATA waklog_module
= {
1774 STANDARD20_MODULE_STUFF
,
1775 waklog_create_dir_config
, /* create per-dir conf structures */
1776 waklog_merge_dir_config
, /* merge per-dir conf structures */
1777 waklog_create_server_config
, /* create per-server conf structures */
1778 waklog_merge_dir_config
, /* merge per-server conf structures */
1779 waklog_cmds
, /* table of configuration directives */
1780 waklog_register_hooks
/* register hooks */