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 <apr_strings.h>
49 #include <apr_base64.h>
50 #define ap_pcalloc apr_pcalloc
51 #define ap_pdupstr apr_pdupstr
52 #define ap_pstrdup apr_pstrdup
53 #define MK_POOL apr_pool_t
54 #define MK_TABLE_GET apr_table_get
55 #define MK_TABLE_SET apr_table_set
57 extern unixd_config_rec unixd_config
;
58 #define ap_user_id unixd_config.user_id
59 #define ap_group_id unixd_config.group_id
60 #define ap_user_name unixd_config.user_name
61 #define command(name, func, var, type, usage) \
62 AP_INIT_ ## type (name, (void*) func, \
64 RSRC_CONF | ACCESS_CONF, usage)
65 module AP_MODULE_DECLARE_DATA waklog_module
;
66 typedef struct { int dummy
; } child_info
;
67 const char *userdata_key
= "waklog_init";
70 /**************************************************************************************************/
74 #include <afs/param.h>
76 #include <afs/venus.h>
78 #include <afs/dirpath.h>
79 #include <afs/ptuser.h>
82 #define TKT_LIFE ( 12 * 60 * 60 )
83 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
85 #define WAKLOG_UNSET -1
89 #define APLOG_DEBUG APLOG_ERR
92 /* this is used to turn off pag generation for the backround worker child during startup */
93 int pag_for_children
= 1;
101 int cell_in_principal
;
102 int disable_token_cache
;
105 char *default_principal
;
106 char *default_keytab
;
108 char *afs_cell_realm
;
116 struct ktc_token token
;
117 char clientprincipal
[MAXNAMELEN
];
118 krb5_context kcontext
;
120 struct ktc_principal server
;
121 struct ktc_principal client
;
123 } waklog_child_config
;
125 waklog_child_config child
;
127 struct tokencache_ent
{
128 char clientprincipal
[MAXNAMELEN
];
129 struct ktc_token token
;
130 struct ktc_principal client
;
131 struct ktc_principal server
;
136 #define SHARED_TABLE_SIZE 512
138 struct sharedspace_s
{
140 struct tokencache_ent sharedtokens
[SHARED_TABLE_SIZE
];
143 struct sharedspace_s
*sharedspace
= NULL
;
152 pthread_rwlock_t
*sharedlock
= NULL
;
154 rwlock_t
*sharedlock
= NULL
;
157 struct renew_ent renewtable
[SHARED_TABLE_SIZE
];
163 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
167 log_error (const char *file
, int line
, int level
, int status
,
168 const server_rec
* s
, const char *fmt
, ...)
174 vsnprintf (errstr
, 1024, fmt
, ap
);
178 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
180 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
185 waklog_config
*retrieve_config(request_rec
*r
) {
190 if ( r
&& r
->main
) {
198 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
201 getModConfig (cfg
, r
->server
);
208 /* set_auth -- sets the tokens of the current process to this user.
209 if "self" is set, it divines the user from the current requests' environment.
210 otherwise, it's gettng it from principal/keytab */
213 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
217 krb5_error_code kerror
= 0;
218 krb5_principal kprinc
= NULL
;
219 krb5_get_init_creds_opt kopts
;
222 krb5_ccache clientccache
;
223 struct ktc_principal server
= { "afs", "", "" };
224 struct ktc_principal client
;
225 struct ktc_token token
;
226 krb5_creds
*v5credsp
= NULL
;
227 krb5_keytab krb5kt
= NULL
;
228 char buf
[MAXNAMELEN
];
232 time_t oldest_time
= 0;
237 int cell_in_principal
;
239 int use_client_credentials
= 0;
241 char k5user
[MAXNAMELEN
] = "";
242 char *k5secret
= NULL
;
246 memset((char *) &increds
, 0, sizeof(increds
));
247 /* init some stuff if it ain't already */
248 /* XXX - In what situation will these not be initialized? */
250 if ( ! child
.kcontext
) {
251 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
252 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
258 if ( !child
.ccache
) {
259 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
260 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
266 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
267 self
, principal
? principal
: "NULL",
268 keytab
? keytab
: "NULL",
270 k5path
? k5path
: "NULL",
272 (r
&& r
->user
) ? r
->user
: "NULL"
274 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
278 /* pull the server config record that we care about... */
281 cfg
= retrieve_config(r
);
283 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
284 "mod_waklog: set_auth using no config" );
285 getModConfig (cfg
, s
);
289 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
294 /* pull out our principal name and stuff from the environment -- webauth better have sent
298 if ( ! ( r
&& r
->connection
&& r
->user
)) {
299 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
300 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
==NULL
));
304 strncpy(k5user
, r
->user
, sizeof(k5user
));
306 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
307 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
311 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
313 /* if they've supplied a credentials cache */
314 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
316 /* the other thing we need is someone's password */
317 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
319 /* we'll pick this up later after we've checked the cache and current state */
323 strncpy(k5user
, principal
, sizeof(k5user
));
327 strncpy(k5user
, r
->user
, sizeof(k5user
));
330 if (r
&& r
->connection
&& r
->connection
->user
) {
331 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
335 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
? k5user
: "NULL");
338 /* see if we should just go ahead and ignore this call, since we already should be set to these
344 pthread_rwlock_rdlock( sharedlock
);
346 rw_rdlock( sharedlock
);
349 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
351 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
353 if ( ( !strcmp( k5user
,
354 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
355 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
357 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
363 /* copy the token out of the cache and into the child object */
365 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
366 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
367 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
368 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
370 /* set our last used time thing */
371 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
381 /* release the lock on the token cache */
383 pthread_rwlock_unlock( sharedlock
);
385 rw_unlock( sharedlock
);
389 /* release the lock on the token cache */
390 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
391 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
395 /* if this is something that was in the cache, and it's the same as the token we already have stored,
396 and we weren't calling this just to renew it... */
398 if ( usecached
&& indentical
) {
399 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
405 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
406 if (( ! usecached
) && ( k5user
)) {
408 /* clear out the creds structure */
409 memset((void *) &v5creds
, 0, sizeof(v5creds
));
411 /* create a principal out of our k5user string */
413 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
414 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror
) );
418 /* create the credentials options */
420 krb5_get_init_creds_opt_init ( &kopts
);
421 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
422 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
423 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
424 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
426 if ( keytab
|| k5secret
) {
429 /* if we've been passed a keytab, we're going to be getting our credentials from it */
431 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
433 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
434 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
435 "mod_waklog: krb5_kt_resolve %s", error_message(kerror
) );
439 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
440 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
441 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
442 error_message(kerror
) );
445 } else if (k5secret
) {
447 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
449 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
450 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
451 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
452 error_message(kerror
) );
453 /* nuke the password so it doesn't end up in core files */
454 memset(k5secret
, 0, sizeof(k5secret
));
458 memset(k5secret
, 0, sizeof(k5secret
));
461 /* initialize the credentials cache and store the stuff we just got */
462 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
463 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
464 error_message(kerror
));
468 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
469 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
470 error_message(kerror
));
474 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
477 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", error_message(kerror
));
481 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
484 /* If we've got a path to a credentials cache, then try and use that. We can't just
485 * replace child.creds, because we want to ensure that only this request gets access to
488 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
489 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
490 "mod_waklog: can't open provided credentials cache %s err=%d",
495 use_client_credentials
= 1;
498 /* now, to the 'aklog' portion of our program. */
500 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
501 for(attempt
= 0; attempt
<= 1; attempt
++) {
502 strncpy( buf
, "afs", sizeof(buf
) - 1 );
503 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
505 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
506 if (cell_in_principal
) {
507 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
508 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
510 if (cfg
->afs_cell_realm
!= NULL
) {
511 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
512 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
515 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
517 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
518 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", error_message(kerror
));
522 if (!use_client_credentials
) {
523 clientccache
= child
.ccache
;
526 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
527 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", error_message(kerror
), clientccache
);
531 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
533 increds
.times
.endtime
= 0;
535 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
537 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
538 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
540 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
541 error_message(kerror
));
547 cfg
->cell_in_principal
= cell_in_principal
;
551 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
553 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
554 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
555 v5credsp
->ticket
.length
);
559 memset(&token
, 0, sizeof(struct ktc_token
));
561 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
562 token
.endTime
= v5credsp
->times
.endtime
;
564 memmove( &token
.sessionKey
, v5credsp
->keyblock
.contents
, v5credsp
->keyblock
.length
);
565 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
566 token
.ticketLen
= v5credsp
->ticket
.length
;
567 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
571 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
573 buf
[v5credsp
->client
->data
[0].length
] = '\0';
574 if ( v5credsp
->client
->length
> 1 ) {
575 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
576 buflen
= strlen(buf
);
577 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
578 min(v5credsp
->client
->data
[1].length
,
579 MAXKTCNAMELEN
- strlen(buf
) - 1));
580 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
583 /* assemble the client */
584 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
585 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
586 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
588 buf
[v5credsp
->client
->realm
.length
] = '\0';
589 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
591 /* assemble the server's cell */
592 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
594 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
596 /* fill out the AFS ID in the client name */
597 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
598 * strange things seem to happen. */
601 afs_int32 viceId
= 0;
603 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
605 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
606 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
608 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
611 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
615 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
616 server
.name
, server
.instance
, server
.cell
);
618 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
619 client
.name
, client
.instance
, client
.cell
);
621 /* copy the resulting stuff into the child structure */
623 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
624 memcpy(&child
.token
, &token
, sizeof(child
.token
));
625 memcpy(&child
.server
, &server
, sizeof(child
.server
));
626 memcpy(&child
.client
, &client
, sizeof(child
.client
));
628 /* stuff the resulting token-related stuff into our shared token cache */
629 /* note, that anything that was set from a keytab is "persistant", and is immune
630 * from LRU-aging. This is because nothing but the process that's running as root
631 * can update these, and it's running every hour or so and renewing these tokens.
632 * and we don't want them aged out.
635 mytime
= oldest_time
= time(0);
637 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
640 pthread_rwlock_wrlock(sharedlock
);
642 rw_wrlock(sharedlock
);
645 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
646 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
647 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
649 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
651 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
652 child
.clientprincipal
) ) {
653 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
654 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
655 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
656 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
657 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
663 if ( stored
== -1 ) {
664 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
665 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
666 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
667 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
668 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
669 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
674 pthread_rwlock_unlock(sharedlock
);
676 rw_unlock(sharedlock
);
679 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
680 child
.clientprincipal
);
682 } else if ( ! usecached
) {
683 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
692 /* don't ask. Something about AIX. We're leaving it here.*/
693 /* write(2, "", 0); */
695 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
697 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
698 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
699 error_message(rc
), k5user
);
700 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
701 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
702 error_message(rc
), k5user
);
708 if (use_client_credentials
)
709 krb5_cc_close(child
.kcontext
, clientccache
);
711 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
712 if ( increds
.client
)
713 krb5_free_principal (child
.kcontext
, increds
.client
);
714 if ( increds
.server
)
715 krb5_free_principal (child
.kcontext
, increds
.server
);
717 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
719 krb5_free_principal (child
.kcontext
, kprinc
);
722 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
723 } else if ( kerror
) {
724 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, error_message(kerror
));
726 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
729 return kerror
? (int) kerror
: (int) rc
;
734 int get_cfg_usertokens(waklog_config
*cfg
)
736 if (cfg
->usertokens
==WAKLOG_UNSET
)
737 return 0; /* default */
738 return cfg
->usertokens
;
741 int get_cfg_protect(waklog_config
*cfg
)
743 if (cfg
->protect
==WAKLOG_UNSET
)
744 return 0; /* default */
748 int get_cfg_disable_token_cache(waklog_config
*cfg
)
750 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
751 return 0; /* default */
752 return cfg
->disable_token_cache
;
757 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
761 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
763 memset(cfg
, 0, sizeof(waklog_config
));
764 cfg
->path
= "(server)";
765 cfg
->protect
= WAKLOG_UNSET
;
766 cfg
->usertokens
= WAKLOG_UNSET
;
767 cfg
->disable_token_cache
= WAKLOG_UNSET
;
769 cfg
->principal
= NULL
;
770 cfg
->default_principal
= NULL
;
771 cfg
->default_keytab
= NULL
;
772 cfg
->afs_cell
= NULL
;
773 cfg
->afs_cell_realm
= NULL
;
777 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
778 "mod_waklog: server config created.");
783 /* initialize with host-config information */
786 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
790 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
791 memset(cfg
, 0, sizeof(waklog_config
));
793 cfg
->path
= ap_pstrdup(p
, dir
);
794 cfg
->protect
= WAKLOG_UNSET
;
795 cfg
->usertokens
= WAKLOG_UNSET
;
796 cfg
->disable_token_cache
= WAKLOG_UNSET
;
798 cfg
->principal
= NULL
;
799 cfg
->default_principal
= NULL
;
800 cfg
->default_keytab
= NULL
;
801 cfg
->afs_cell
= NULL
;
802 cfg
->afs_cell_realm
= NULL
;
809 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
811 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
812 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
813 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
815 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
817 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
819 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
821 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
823 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
825 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
827 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
829 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
831 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
833 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
835 return (void *) merged
;
839 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
841 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
842 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
843 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
845 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
847 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
849 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
851 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
852 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
854 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
855 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
857 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
858 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
860 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
861 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
863 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
864 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
866 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
867 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
870 return (void *) merged
;
875 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
877 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
878 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
882 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
883 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
888 /* this adds a principal/keytab pair to get their tokens renewed by the
889 child process every few centons. */
891 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
895 if ( renewcount
>= SHARED_TABLE_SIZE
) {
896 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
897 decrease your tokens.");
901 /* check to see if it's already there */
903 for ( i
= 0; i
< renewcount
; i
++ ) {
904 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
909 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
910 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
911 renewtable
[renewcount
].lastrenewed
= 0;
917 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
919 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
920 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
922 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
923 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
925 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
926 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
928 add_to_renewtable(params
->pool
, keytab
, principal
);
936 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
938 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
939 waklog_config
*waklog_srvconfig
=
940 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
942 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
943 "mod_waklog: will use afs_cell: %s", file
);
945 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
946 waklog_srvconfig
->cell_in_principal
= 1;
948 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
949 waklog_srvconfig
->configured
= 1;
951 if (waklog_mconfig
!= NULL
) {
952 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
953 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
954 waklog_mconfig
->configured
= 1;
960 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
962 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
963 waklog_config
*waklog_srvconfig
=
964 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
966 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
967 "mod_waklog: will use afs_cell_realm: %s", file
);
969 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
971 if (waklog_mconfig
!= NULL
) {
972 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
978 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
980 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
981 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
983 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
985 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
986 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
988 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
989 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
991 /* this also gets set at the server level */
992 if ( mconfig
&& ( ! cfg
->path
) ) {
993 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
994 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
996 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
997 return "Unable to set DefaultPrincipal outside of top level config!";
1000 add_to_renewtable( params
->pool
, keytab
, principal
);
1002 cfg
->configured
= 1;
1008 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1010 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1011 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1013 cfg
->usertokens
= flag
;
1015 cfg
->configured
= 1;
1017 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1018 "mod_waklog: waklog_use_user_tokens set");
1024 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1026 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1027 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1029 cfg
->disable_token_cache
= flag
;
1031 cfg
->configured
= 1;
1033 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1034 "mod_waklog: waklog_disable_token_cache set");
1040 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1042 apr_status_t
waklog_child_exit( void *sr
) {
1044 server_rec
*s
= (server_rec
*) sr
;
1047 if ( child
.ccache
) {
1048 krb5_cc_close(child
.kcontext
, child
.ccache
);
1051 if ( child
.kcontext
) {
1052 krb5_free_context(child
.kcontext
);
1055 /* forget our tokens */
1057 ktc_ForgetAllTokens ();
1059 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1060 "mod_waklog: waklog_child_exit complete");
1070 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1072 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1076 krb5_error_code code
;
1081 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1083 if ( !sharedspace
) {
1084 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1088 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1090 memset (&child
, 0, sizeof(child
));
1092 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1093 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1096 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1097 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1100 if ( pag_for_children
) {
1104 getModConfig (cfg
, s
);
1106 if ( cfg
->default_principal
!= NULL
) {
1107 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1108 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1111 cell
= strdup(cfg
->afs_cell
);
1112 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1115 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1118 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1119 "mod_waklog: child_init returned");
1124 command_rec waklog_cmds
[] = {
1126 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1127 "Use the supplied AFS cell (required)"),
1129 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1130 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1132 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1133 "enable waklog on a server, location, or directory basis"),
1135 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1136 "Set the default principal that the server runs as"),
1138 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1139 "Set the principal on a <Location>-specific basis"),
1141 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1142 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1144 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1145 "Use the requesting user tokens (from webauth)"),
1151 /* not currently using this */
1154 token_cleanup (void *data
)
1156 request_rec
*r
= (request_rec
*) data
;
1158 if (child
.token
.ticketLen
)
1160 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1162 ktc_ForgetAllTokens ();
1164 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1165 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1172 waklog_child_routine (void *data
, child_info
* pinfo
)
1175 server_rec
*s
= (server_rec
*) data
;
1176 krb5_error_code code
;
1178 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1183 getModConfig( cfg
, s
);
1185 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1187 memset (&child
, 0, sizeof(child
));
1189 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1190 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1193 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1194 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1197 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1199 /* need to do this so we can make PTS calls */
1200 cell
= strdup(cfg
->afs_cell
); /* stupid */
1201 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1203 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1207 for ( i
= 0; i
< renewcount
; ++i
) {
1208 renewtable
[i
].lastrenewed
= time(0);
1209 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1210 renewtable
[i
].keytab
);
1212 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1214 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1215 things that it needs to read */
1217 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1218 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1219 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1224 sharedspace
->renewcount
++;
1233 left
-= ( time(0) - when
);
1244 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1245 apr_pool_t
* ptemp
, server_rec
* s
)
1248 extern char *version
;
1253 int use_existing
= 1;
1255 char cache_file
[MAXNAMELEN
];
1257 pthread_rwlockattr_t rwlock_attr
;
1261 getModConfig (cfg
, s
);
1263 /* initialize_module() will be called twice, and if it's a DSO
1264 * then all static data from the first call will be lost. Only
1265 * set up our static data on the second call.
1266 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1267 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1270 if (cfg
->afs_cell
==NULL
) {
1271 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1272 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1273 /** clobber apache */
1279 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1280 apr_pool_cleanup_null
, s
->process
->pool
);
1284 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1285 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1287 if ( sharedspace
) {
1288 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1291 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1293 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1295 if ( errno
== ENOENT
) {
1297 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1299 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1300 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1304 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1308 if ( use_existing
== 0 ) {
1309 struct sharedspace_s bob
;
1310 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1311 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1312 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1313 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1316 /* mmap the region */
1318 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1320 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1321 err
= unlink(cache_file
);
1323 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1325 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1328 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1334 #define locktype pthread_rwlock_t
1336 #define locktype rwlock_t
1339 if ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) {
1340 #ifndef use_pthreads
1341 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1343 pthread_rwlockattr_init(&rwlock_attr
);
1344 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1345 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1348 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1353 /* set our default tokens */
1355 oldrenewcount
= sharedspace
->renewcount
;
1357 pag_for_children
= 0;
1359 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1361 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1363 if (rv
== APR_INCHILD
)
1365 waklog_child_routine (s
, NULL
);
1369 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1371 /* parent and child */
1372 cfg
->forked
= proc
->pid
;
1373 pag_for_children
= 1;
1375 if ( use_existing
== 0 ) {
1376 /* wait here until our child process has gone and done it's renewing thing. */
1377 while( sharedspace
->renewcount
== oldrenewcount
) {
1378 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1383 if ( cfg
->default_principal
) {
1384 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1391 waklog_init (server_rec
* s
, MK_POOL
* p
)
1393 extern char *version
;
1397 int use_existing
= 1;
1399 char cache_file
[MAXNAMELEN
];
1401 pthread_rwlockattr_t rwlock_attr
;
1404 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1405 "mod_waklog: version %s initialized.", version
);
1407 if ( sharedspace
) {
1408 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1411 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1413 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1415 if ( errno
== ENOENT
) {
1417 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1419 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1420 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1424 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1429 if ( use_existing
== 0 ) {
1430 struct sharedspace_s bob
;
1431 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1432 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1433 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1434 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1437 /* mmap the region */
1439 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1440 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1443 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1449 #define locktype pthread_rwlock_t
1451 #define locktype rwlock_t
1454 /* mmap our shared space for our lock */
1455 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1456 #ifndef use_pthreads
1457 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1459 pthread_rwlockattr_init(&rwlock_attr
);
1460 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1461 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1464 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1469 /* set our default tokens */
1471 getModConfig (cfg
, s
);
1473 oldrenewcount
= sharedspace
->renewcount
;
1475 pag_for_children
= 0;
1477 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1480 pag_for_children
= 1;
1482 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1483 "mod_waklog: ap_bspawn_child: %d.", pid
);
1485 if ( use_existing
== 0 ) {
1486 /* wait here until our child process has gone and done it's renewing thing. */
1487 while( sharedspace
->renewcount
== oldrenewcount
) {
1488 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1493 if ( cfg
->default_principal
) {
1494 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1501 waklog_phase0 (request_rec
* r
)
1505 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1506 "mod_waklog: phase0 called");
1508 cfg
= retrieve_config(r
);
1510 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1511 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1512 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1513 } else if ( cfg
->default_principal
) {
1514 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1515 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1518 if (child
.token
.ticketLen
) {
1519 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1520 ktc_ForgetAllTokens();
1523 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1530 waklog_phase1 (request_rec
* r
)
1534 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1535 "mod_waklog: phase1 called");
1537 cfg
= retrieve_config(r
);
1539 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1540 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1541 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1542 } else if ( cfg
->default_principal
) {
1543 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1544 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1546 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1553 waklog_phase3 (request_rec
* r
)
1557 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1558 "mod_waklog: phase 3 called");
1560 cfg
= retrieve_config(r
);
1562 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1563 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1564 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1565 } else if ( cfg
->default_principal
) {
1566 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1567 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1569 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1576 waklog_phase6 (request_rec
* r
)
1580 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1581 "mod_waklog: phase6 called");
1583 cfg
= retrieve_config(r
);
1585 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1586 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1587 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1588 } else if ( cfg
->default_principal
) {
1589 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1590 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1592 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1599 waklog_phase7 (request_rec
* r
)
1604 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1605 "mod_waklog: phase7 called");
1607 cfg
= retrieve_config (r
);
1609 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1610 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1611 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1612 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1613 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1614 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1615 } else if ( cfg
->default_principal
) {
1616 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1617 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1619 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1620 if (child
.token
.ticketLen
) {
1621 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1622 ktc_ForgetAllTokens();
1634 waklog_phase9 (request_rec
* r
)
1638 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1639 "mod_waklog: phase9 called");
1641 getModConfig (cfg
, r
->server
);
1643 if ( cfg
->default_principal
) {
1644 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1645 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1658 waklog_new_connection (conn_rec
* c
1667 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1668 "mod_waklog: new_connection called: pid: %d", getpid ());
1670 getModConfig(cfg
, c
->base_server
);
1672 if ( cfg
->default_principal
) {
1673 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1674 cfg
->default_principal
);
1675 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1688 ** Here's a quick explaination for phase0 and phase2:
1689 ** Apache does a stat() on the path between phase0 and
1690 ** phase2, and must by ACLed rl to succeed. So, at
1691 ** phase0 we acquire credentials for umweb:servers from
1692 ** a keytab, and at phase2 we must ensure we remove them.
1694 ** Failure to "unlog" would be a security risk.
1697 waklog_phase2 (request_rec
* r
)
1700 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1701 "mod_waklog: phase2 called");
1703 if (child
.token
.ticketLen
)
1705 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1707 ktc_ForgetAllTokens ();
1709 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1710 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1714 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1715 "mod_waklog: phase2 returning");
1721 module MODULE_VAR_EXPORT waklog_module
= {
1722 STANDARD_MODULE_STUFF
,
1723 waklog_init
, /* module initializer */
1724 waklog_create_dir_config
, /* create per-dir config structures */
1725 waklog_merge_dir_config
, /* merge per-dir config structures */
1726 waklog_create_server_config
, /* create per-server config structures */
1727 waklog_merge_dir_config
, /* merge per-server config structures */
1728 waklog_cmds
, /* table of config file commands */
1729 NULL
, /* [#8] MIME-typed-dispatched handlers */
1730 waklog_phase1
, /* [#1] URI to filename translation */
1731 NULL
, /* [#4] validate user id from request */
1732 NULL
, /* [#5] check if the user is ok _here_ */
1733 waklog_phase3
, /* [#3] check access by host address */
1734 waklog_phase6
, /* [#6] determine MIME type */
1735 waklog_phase7
, /* [#7] pre-run fixups */
1736 waklog_phase9
, /* [#9] log a transaction */
1737 waklog_phase2
, /* [#2] header parser */
1738 waklog_child_init
, /* child_init */
1739 waklog_child_exit
, /* child_exit */
1740 waklog_phase0
/* [#0] post read-request */
1742 , NULL
, /* EAPI: add_module */
1743 NULL
, /* EAPI: remove_module */
1744 NULL
, /* EAPI: rewrite_command */
1745 waklog_new_connection
/* EAPI: new_connection */
1750 waklog_register_hooks (apr_pool_t
* p
)
1752 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1753 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1754 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1755 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1756 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1757 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1758 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1759 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1760 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1761 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1765 module AP_MODULE_DECLARE_DATA waklog_module
= {
1766 STANDARD20_MODULE_STUFF
,
1767 waklog_create_dir_config
, /* create per-dir conf structures */
1768 waklog_merge_dir_config
, /* merge per-dir conf structures */
1769 waklog_create_server_config
, /* create per-server conf structures */
1770 waklog_merge_dir_config
, /* merge per-server conf structures */
1771 waklog_cmds
, /* table of configuration directives */
1772 waklog_register_hooks
/* register hooks */