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>
52 #define ap_pcalloc apr_pcalloc
53 #define ap_pdupstr apr_pdupstr
54 #define ap_pstrdup apr_pstrdup
55 #define MK_POOL apr_pool_t
56 #define MK_TABLE_GET apr_table_get
57 #define MK_TABLE_SET apr_table_set
58 #define command(name, func, var, type, usage) \
59 AP_INIT_ ## type (name, (void*) func, \
61 RSRC_CONF | ACCESS_CONF, usage)
62 module AP_MODULE_DECLARE_DATA waklog_module
;
63 typedef struct { int dummy
; } child_info
;
64 const char *userdata_key
= "waklog_init";
67 #ifdef APLOG_USE_MODULE
68 APLOG_USE_MODULE(waklog
);
72 /**************************************************************************************************/
77 #include <afs/param.h>
79 #include <afs/venus.h>
81 #include <afs/dirpath.h>
82 #include <afs/ptuser.h>
83 #include <afs/com_err.h>
86 #define TKT_LIFE ( 12 * 60 * 60 )
87 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
89 #define WAKLOG_UNSET -1
93 #define APLOG_DEBUG APLOG_ERR
96 /* this is used to turn off pag generation for the backround worker child during startup */
97 int pag_for_children
= 1;
105 int cell_in_principal
;
106 int disable_token_cache
;
109 char *default_principal
;
110 char *default_keytab
;
112 char *afs_cell_realm
;
120 struct ktc_token token
;
121 char clientprincipal
[MAXNAMELEN
];
122 krb5_context kcontext
;
124 struct ktc_principal server
;
125 struct ktc_principal client
;
127 } waklog_child_config
;
129 waklog_child_config child
;
131 struct tokencache_ent
{
132 char clientprincipal
[MAXNAMELEN
];
133 struct ktc_token token
;
134 struct ktc_principal client
;
135 struct ktc_principal server
;
140 #define SHARED_TABLE_SIZE 512
142 struct sharedspace_s
{
144 struct tokencache_ent sharedtokens
[SHARED_TABLE_SIZE
];
147 struct sharedspace_s
*sharedspace
= NULL
;
156 pthread_rwlock_t
*sharedlock
= NULL
;
158 rwlock_t
*sharedlock
= NULL
;
161 struct renew_ent renewtable
[SHARED_TABLE_SIZE
];
167 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
170 #ifdef APLOG_USE_MODULE
172 log_error (const char *file
, int line
, int module_index
, int level
, int status
,
173 const server_rec
* s
, const char *fmt
, ...)
176 log_error (const char *file
, int line
, int level
, int status
,
177 const server_rec
* s
, const char *fmt
, ...)
184 vsnprintf (errstr
, 1024, fmt
, ap
);
188 #ifdef APLOG_USE_MODULE
190 ap_log_error (file
, line
, module_index
, level
| APLOG_NOERRNO
, status
, s
, "%s", errstr
);
192 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
195 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
200 waklog_config
*retrieve_config(request_rec
*r
) {
205 if ( r
&& r
->main
) {
213 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
216 getModConfig (cfg
, r
->server
);
223 /* set_auth -- sets the tokens of the current process to this user.
224 if "self" is set, it divines the user from the current requests' environment.
225 otherwise, it's gettng it from principal/keytab */
228 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
232 krb5_error_code kerror
= 0;
233 krb5_principal kprinc
= NULL
;
234 krb5_get_init_creds_opt kopts
;
237 krb5_ccache clientccache
;
238 struct ktc_principal server
= { "afs", "", "" };
239 struct ktc_principal client
;
240 struct ktc_token token
;
241 krb5_creds
*v5credsp
= NULL
;
242 krb5_keytab krb5kt
= NULL
;
243 char buf
[MAXNAMELEN
];
247 time_t oldest_time
= 0;
252 int cell_in_principal
;
254 int use_client_credentials
= 0;
256 char k5user
[MAXNAMELEN
] = "";
257 char *k5secret
= NULL
;
261 memset((char *) &increds
, 0, sizeof(increds
));
262 /* init some stuff if it ain't already */
263 /* XXX - In what situation will these not be initialized? */
265 if ( ! child
.kcontext
) {
266 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
267 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
273 if ( !child
.ccache
) {
274 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
275 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
281 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
282 self
, principal
? principal
: "NULL",
283 keytab
? keytab
: "NULL",
285 k5path
? k5path
: "NULL",
287 (r
&& r
->user
) ? r
->user
: "NULL"
289 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
293 /* pull the server config record that we care about... */
296 cfg
= retrieve_config(r
);
298 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
299 "mod_waklog: set_auth using no config" );
300 getModConfig (cfg
, s
);
304 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
309 /* pull out our principal name and stuff from the environment -- webauth better have sent
313 if ( ! ( r
&& r
->connection
&& r
->user
)) {
314 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
315 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
));
319 strncpy(k5user
, r
->user
, sizeof(k5user
));
321 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
322 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
326 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
328 /* if they've supplied a credentials cache */
329 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
331 /* the other thing we need is someone's password */
332 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
334 /* we'll pick this up later after we've checked the cache and current state */
338 strncpy(k5user
, principal
, sizeof(k5user
));
342 strncpy(k5user
, r
->user
, sizeof(k5user
));
345 if (r
&& r
->connection
&& r
->connection
->user
) {
346 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
350 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
);
353 /* see if we should just go ahead and ignore this call, since we already should be set to these
359 pthread_rwlock_rdlock( sharedlock
);
361 rw_rdlock( sharedlock
);
364 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
366 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
368 if ( ( !strcmp( k5user
,
369 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
370 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
372 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
378 /* copy the token out of the cache and into the child object */
380 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
381 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
382 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
383 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
385 /* set our last used time thing */
386 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
396 /* release the lock on the token cache */
398 pthread_rwlock_unlock( sharedlock
);
400 rw_unlock( sharedlock
);
404 /* release the lock on the token cache */
405 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
406 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
410 /* if this is something that was in the cache, and it's the same as the token we already have stored,
411 and we weren't calling this just to renew it... */
413 if ( usecached
&& indentical
) {
414 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
420 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
423 /* clear out the creds structure */
424 memset((void *) &v5creds
, 0, sizeof(v5creds
));
426 /* create a principal out of our k5user string */
428 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
429 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) afs_error_message(kerror
) );
433 /* create the credentials options */
435 krb5_get_init_creds_opt_init ( &kopts
);
436 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
437 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
438 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
439 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
441 if ( keytab
|| k5secret
) {
444 /* if we've been passed a keytab, we're going to be getting our credentials from it */
446 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
448 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
449 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
450 "mod_waklog: krb5_kt_resolve %s", afs_error_message(kerror
) );
454 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
455 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
456 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
457 afs_error_message(kerror
) );
460 } else if (k5secret
) {
462 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
464 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
465 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
466 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
467 afs_error_message(kerror
) );
468 /* nuke the password so it doesn't end up in core files */
469 memset(k5secret
, 0, strlen(k5secret
));
473 memset(k5secret
, 0, strlen(k5secret
));
476 /* initialize the credentials cache and store the stuff we just got */
477 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
478 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
479 afs_error_message(kerror
));
483 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
484 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
485 afs_error_message(kerror
));
489 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
492 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", afs_error_message(kerror
));
496 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
499 /* If we've got a path to a credentials cache, then try and use that. We can't just
500 * replace child.creds, because we want to ensure that only this request gets access to
503 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
504 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
505 "mod_waklog: can't open provided credentials cache %s err=%d",
510 use_client_credentials
= 1;
513 /* now, to the 'aklog' portion of our program. */
515 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
516 for(attempt
= 0; attempt
<= 1; attempt
++) {
517 strncpy( buf
, "afs", sizeof(buf
) - 1 );
518 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
520 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
521 if (cell_in_principal
) {
522 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
523 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
525 if (cfg
->afs_cell_realm
!= NULL
) {
526 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
527 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
530 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
532 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
533 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", afs_error_message(kerror
));
537 if (!use_client_credentials
) {
538 clientccache
= child
.ccache
;
541 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
542 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", afs_error_message(kerror
), clientccache
);
546 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
548 increds
.times
.endtime
= 0;
550 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
551 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
553 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
554 afs_error_message(kerror
));
560 cfg
->cell_in_principal
= cell_in_principal
;
564 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
566 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
567 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
568 v5credsp
->ticket
.length
);
572 memset(&token
, 0, sizeof(struct ktc_token
));
574 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
575 token
.endTime
= v5credsp
->times
.endtime
;
577 if (tkt_DeriveDesKey(v5credsp
->keyblock
.enctype
, v5credsp
->keyblock
.contents
,
578 v5credsp
->keyblock
.length
, &token
.sessionKey
) != 0) {
579 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: tkt_DeriveDesKey failure (enctype: %d)",
580 v5credsp
->keyblock
.enctype
);
583 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
584 token
.ticketLen
= v5credsp
->ticket
.length
;
585 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
589 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
591 buf
[v5credsp
->client
->data
[0].length
] = '\0';
592 if ( v5credsp
->client
->length
> 1 ) {
593 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
594 buflen
= strlen(buf
);
595 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
596 min(v5credsp
->client
->data
[1].length
,
597 MAXKTCNAMELEN
- strlen(buf
) - 1));
598 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
601 /* assemble the client */
602 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
603 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
604 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
606 buf
[v5credsp
->client
->realm
.length
] = '\0';
607 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
609 /* assemble the server's cell */
610 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
612 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
614 /* fill out the AFS ID in the client name */
615 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
616 * strange things seem to happen. */
619 afs_int32 viceId
= 0;
621 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
623 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
624 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
626 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
629 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
633 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
634 server
.name
, server
.instance
, server
.cell
);
636 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
637 client
.name
, client
.instance
, client
.cell
);
639 /* copy the resulting stuff into the child structure */
641 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
642 memcpy(&child
.token
, &token
, sizeof(child
.token
));
643 memcpy(&child
.server
, &server
, sizeof(child
.server
));
644 memcpy(&child
.client
, &client
, sizeof(child
.client
));
646 /* stuff the resulting token-related stuff into our shared token cache */
647 /* note, that anything that was set from a keytab is "persistant", and is immune
648 * from LRU-aging. This is because nothing but the process that's running as root
649 * can update these, and it's running every hour or so and renewing these tokens.
650 * and we don't want them aged out.
653 mytime
= oldest_time
= time(0);
655 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
658 pthread_rwlock_wrlock(sharedlock
);
660 rw_wrlock(sharedlock
);
663 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
664 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
665 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
667 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
669 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
670 child
.clientprincipal
) ) {
671 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
672 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
673 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
674 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
675 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
681 if ( stored
== -1 ) {
682 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
683 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
684 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
685 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
686 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
687 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
692 pthread_rwlock_unlock(sharedlock
);
694 rw_unlock(sharedlock
);
697 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
698 child
.clientprincipal
);
700 } else if ( ! usecached
) {
701 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
710 /* don't ask. Something about AIX. We're leaving it here.*/
711 /* write(2, "", 0); */
713 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
715 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
716 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
717 afs_error_message(rc
), k5user
);
718 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
719 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
720 afs_error_message(rc
), k5user
);
726 if (use_client_credentials
)
727 krb5_cc_close(child
.kcontext
, clientccache
);
729 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
730 if ( increds
.client
)
731 krb5_free_principal (child
.kcontext
, increds
.client
);
732 if ( increds
.server
)
733 krb5_free_principal (child
.kcontext
, increds
.server
);
735 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
737 krb5_free_principal (child
.kcontext
, kprinc
);
740 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
741 } else if ( kerror
) {
742 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, afs_error_message(kerror
));
744 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
747 return kerror
? (int) kerror
: (int) rc
;
752 int get_cfg_usertokens(waklog_config
*cfg
)
754 if (cfg
->usertokens
==WAKLOG_UNSET
)
755 return 0; /* default */
756 return cfg
->usertokens
;
759 int get_cfg_protect(waklog_config
*cfg
)
761 if (cfg
->protect
==WAKLOG_UNSET
)
762 return 0; /* default */
766 int get_cfg_disable_token_cache(waklog_config
*cfg
)
768 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
769 return 0; /* default */
770 return cfg
->disable_token_cache
;
775 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
779 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
781 memset(cfg
, 0, sizeof(waklog_config
));
782 cfg
->path
= "(server)";
783 cfg
->protect
= WAKLOG_UNSET
;
784 cfg
->usertokens
= WAKLOG_UNSET
;
785 cfg
->disable_token_cache
= WAKLOG_UNSET
;
787 cfg
->principal
= NULL
;
788 cfg
->default_principal
= NULL
;
789 cfg
->default_keytab
= NULL
;
790 cfg
->afs_cell
= NULL
;
791 cfg
->afs_cell_realm
= NULL
;
795 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
796 "mod_waklog: server config created.");
801 /* initialize with host-config information */
804 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
808 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
809 memset(cfg
, 0, sizeof(waklog_config
));
811 cfg
->path
= ap_pstrdup(p
, dir
);
812 cfg
->protect
= WAKLOG_UNSET
;
813 cfg
->usertokens
= WAKLOG_UNSET
;
814 cfg
->disable_token_cache
= WAKLOG_UNSET
;
816 cfg
->principal
= NULL
;
817 cfg
->default_principal
= NULL
;
818 cfg
->default_keytab
= NULL
;
819 cfg
->afs_cell
= NULL
;
820 cfg
->afs_cell_realm
= NULL
;
827 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
829 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
830 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
831 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
833 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
835 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
837 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
839 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
841 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
843 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
845 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
847 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
849 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
851 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
853 return (void *) merged
;
857 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
859 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
860 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
861 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
863 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
865 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
867 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
869 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
870 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
872 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
873 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
875 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
876 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
878 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
879 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
881 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
882 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
884 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
885 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
888 return (void *) merged
;
893 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
895 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
896 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
900 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
901 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
906 /* this adds a principal/keytab pair to get their tokens renewed by the
907 child process every few centons. */
909 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
913 if ( renewcount
>= SHARED_TABLE_SIZE
) {
914 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
915 decrease your tokens.");
919 /* check to see if it's already there */
921 for ( i
= 0; i
< renewcount
; i
++ ) {
922 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
927 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
928 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
929 renewtable
[renewcount
].lastrenewed
= 0;
935 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
937 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
938 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
940 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
941 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
943 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
944 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
946 add_to_renewtable(params
->pool
, keytab
, principal
);
954 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
956 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
957 waklog_config
*waklog_srvconfig
=
958 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
960 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
961 "mod_waklog: will use afs_cell: %s", file
);
963 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
964 waklog_srvconfig
->cell_in_principal
= 1;
966 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
967 waklog_srvconfig
->configured
= 1;
969 if (waklog_mconfig
!= NULL
) {
970 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
971 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
972 waklog_mconfig
->configured
= 1;
978 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
980 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
981 waklog_config
*waklog_srvconfig
=
982 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
984 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
985 "mod_waklog: will use afs_cell_realm: %s", file
);
987 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
989 if (waklog_mconfig
!= NULL
) {
990 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
996 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
998 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
999 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1001 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1003 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1004 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
1006 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1007 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1009 /* this also gets set at the server level */
1010 if ( mconfig
&& ( ! cfg
->path
) ) {
1011 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1012 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1014 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
1015 return "Unable to set DefaultPrincipal outside of top level config!";
1018 add_to_renewtable( params
->pool
, keytab
, principal
);
1020 cfg
->configured
= 1;
1026 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1028 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1029 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1031 cfg
->usertokens
= flag
;
1033 cfg
->configured
= 1;
1035 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1036 "mod_waklog: waklog_use_user_tokens set");
1042 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1044 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1045 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1047 cfg
->disable_token_cache
= flag
;
1049 cfg
->configured
= 1;
1051 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1052 "mod_waklog: waklog_disable_token_cache set");
1058 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1060 apr_status_t
waklog_child_exit( void *sr
) {
1062 server_rec
*s
= (server_rec
*) sr
;
1065 if ( child
.ccache
) {
1066 krb5_cc_close(child
.kcontext
, child
.ccache
);
1069 if ( child
.kcontext
) {
1070 krb5_free_context(child
.kcontext
);
1073 /* forget our tokens */
1075 ktc_ForgetAllTokens ();
1077 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1078 "mod_waklog: waklog_child_exit complete");
1088 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1090 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1094 krb5_error_code code
;
1099 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1101 if ( !sharedspace
) {
1102 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1106 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1108 memset (&child
, 0, sizeof(child
));
1110 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1111 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1114 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1115 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1118 if ( pag_for_children
) {
1122 getModConfig (cfg
, s
);
1124 if ( cfg
->default_principal
!= NULL
) {
1125 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1126 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1129 cell
= strdup(cfg
->afs_cell
);
1130 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1133 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1136 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1137 "mod_waklog: child_init returned");
1142 command_rec waklog_cmds
[] = {
1144 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1145 "Use the supplied AFS cell (required)"),
1147 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1148 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1150 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1151 "enable waklog on a server, location, or directory basis"),
1153 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1154 "Set the default principal that the server runs as"),
1156 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1157 "Set the principal on a <Location>-specific basis"),
1159 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1160 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1162 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1163 "Use the requesting user tokens (from webauth)"),
1169 /* not currently using this */
1172 token_cleanup (void *data
)
1174 request_rec
*r
= (request_rec
*) data
;
1176 if (child
.token
.ticketLen
)
1178 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1180 ktc_ForgetAllTokens ();
1182 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1183 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1189 /* This function doesn't return anything but is passed to ap_bspawn_child on
1190 * Apache 1 which expects it to return a pid as an int. For want of better
1191 * understanding, err on the side of not changing Apache 1 code while fixing
1192 * the compile warning on Apache 2. */
1198 waklog_child_routine (void *data
, child_info
* pinfo
)
1201 server_rec
*s
= (server_rec
*) data
;
1202 krb5_error_code code
;
1204 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1209 getModConfig( cfg
, s
);
1211 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1213 memset (&child
, 0, sizeof(child
));
1215 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1216 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1219 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1220 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1223 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1225 /* need to do this so we can make PTS calls */
1226 cell
= strdup(cfg
->afs_cell
); /* stupid */
1227 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1229 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1233 for ( i
= 0; i
< renewcount
; ++i
) {
1234 renewtable
[i
].lastrenewed
= time(0);
1235 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1236 renewtable
[i
].keytab
);
1238 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1240 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1241 things that it needs to read */
1243 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1244 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1245 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1250 sharedspace
->renewcount
++;
1259 left
-= ( time(0) - when
);
1270 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1271 apr_pool_t
* ptemp
, server_rec
* s
)
1278 int use_existing
= 1;
1280 char cache_file
[MAXNAMELEN
];
1282 pthread_rwlockattr_t rwlock_attr
;
1286 getModConfig (cfg
, s
);
1288 /* initialize_module() will be called twice, and if it's a DSO
1289 * then all static data from the first call will be lost. Only
1290 * set up our static data on the second call.
1291 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1292 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1295 if (cfg
->afs_cell
==NULL
) {
1296 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1297 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1298 /** clobber apache */
1304 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1305 apr_pool_cleanup_null
, s
->process
->pool
);
1309 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1310 "mod_waklog: version %s initialized for cell %s", VERSION
, cfg
->afs_cell
);
1312 if ( sharedspace
) {
1313 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1316 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1318 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1320 if ( errno
== ENOENT
) {
1322 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1324 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1325 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1329 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1333 if ( use_existing
== 0 ) {
1334 struct sharedspace_s bob
;
1335 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1336 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1337 if ( write(fd
, &bob
, sizeof(struct sharedspace_s
)) != sizeof(struct sharedspace_s
) ) {
1338 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: failed to write to our cache file %s (%d)", cache_file
, errno
);
1341 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1344 /* mmap the region */
1346 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1348 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1349 err
= unlink(cache_file
);
1351 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1353 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1356 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1362 #define locktype pthread_rwlock_t
1364 #define locktype rwlock_t
1367 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) != NULL
) {
1368 #ifndef use_pthreads
1369 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1371 pthread_rwlockattr_init(&rwlock_attr
);
1372 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1373 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1376 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1381 /* set our default tokens */
1383 oldrenewcount
= sharedspace
->renewcount
;
1385 pag_for_children
= 0;
1387 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1389 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1391 if (rv
== APR_INCHILD
)
1393 waklog_child_routine (s
, NULL
);
1397 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1399 /* parent and child */
1400 cfg
->forked
= proc
->pid
;
1401 pag_for_children
= 1;
1403 if ( use_existing
== 0 ) {
1404 /* wait here until our child process has gone and done it's renewing thing. */
1405 while( sharedspace
->renewcount
== oldrenewcount
) {
1406 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1411 if ( cfg
->default_principal
) {
1412 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1419 waklog_init (server_rec
* s
, MK_POOL
* p
)
1424 int use_existing
= 1;
1426 char cache_file
[MAXNAMELEN
];
1428 pthread_rwlockattr_t rwlock_attr
;
1431 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1432 "mod_waklog: version %s initialized.", VERSION
);
1434 if ( sharedspace
) {
1435 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1438 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1440 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1442 if ( errno
== ENOENT
) {
1444 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1446 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1447 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1451 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1456 if ( use_existing
== 0 ) {
1457 struct sharedspace_s bob
;
1458 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1459 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1460 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1461 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1464 /* mmap the region */
1466 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1467 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1470 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1476 #define locktype pthread_rwlock_t
1478 #define locktype rwlock_t
1481 /* mmap our shared space for our lock */
1482 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1483 #ifndef use_pthreads
1484 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1486 pthread_rwlockattr_init(&rwlock_attr
);
1487 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1488 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1491 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1496 /* set our default tokens */
1498 getModConfig (cfg
, s
);
1500 oldrenewcount
= sharedspace
->renewcount
;
1502 pag_for_children
= 0;
1504 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1507 pag_for_children
= 1;
1509 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1510 "mod_waklog: ap_bspawn_child: %d.", pid
);
1512 if ( use_existing
== 0 ) {
1513 /* wait here until our child process has gone and done it's renewing thing. */
1514 while( sharedspace
->renewcount
== oldrenewcount
) {
1515 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1520 if ( cfg
->default_principal
) {
1521 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1528 waklog_phase0 (request_rec
* r
)
1532 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1533 "mod_waklog: phase0 called");
1535 cfg
= retrieve_config(r
);
1537 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1538 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1539 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1540 } else if ( cfg
->default_principal
) {
1541 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1542 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1545 if (child
.token
.ticketLen
) {
1546 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1547 ktc_ForgetAllTokens();
1550 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1557 waklog_phase1 (request_rec
* r
)
1561 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1562 "mod_waklog: phase1 called");
1564 cfg
= retrieve_config(r
);
1566 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1567 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1568 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1569 } else if ( cfg
->default_principal
) {
1570 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1571 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1573 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1580 waklog_phase3 (request_rec
* r
)
1584 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1585 "mod_waklog: phase 3 called");
1587 cfg
= retrieve_config(r
);
1589 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1590 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1591 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1592 } else if ( cfg
->default_principal
) {
1593 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1594 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1596 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1603 waklog_phase6 (request_rec
* r
)
1607 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1608 "mod_waklog: phase6 called");
1610 cfg
= retrieve_config(r
);
1612 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1613 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1614 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: phase6 using default user %s", cfg
->default_principal
);
1617 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: phase6 not doing nothin.");
1626 waklog_phase7 (request_rec
* r
)
1631 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1632 "mod_waklog: phase7 called");
1634 cfg
= retrieve_config (r
);
1636 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1637 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1638 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1639 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1640 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1641 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1642 } else if ( cfg
->default_principal
) {
1643 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1644 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1646 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1647 if (child
.token
.ticketLen
) {
1648 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1649 ktc_ForgetAllTokens();
1661 waklog_phase9 (request_rec
* r
)
1665 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1666 "mod_waklog: phase9 called");
1668 getModConfig (cfg
, r
->server
);
1670 if ( cfg
->default_principal
) {
1671 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1672 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1685 waklog_new_connection (conn_rec
* c
1694 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1695 "mod_waklog: new_connection called: pid: %d", getpid ());
1697 getModConfig(cfg
, c
->base_server
);
1699 if ( cfg
->default_principal
) {
1700 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1701 cfg
->default_principal
);
1702 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1715 ** Here's a quick explaination for phase0 and phase2:
1716 ** Apache does a stat() on the path between phase0 and
1717 ** phase2, and must by ACLed rl to succeed. So, at
1718 ** phase0 we acquire credentials for umweb:servers from
1719 ** a keytab, and at phase2 we must ensure we remove them.
1721 ** Failure to "unlog" would be a security risk.
1724 waklog_phase2 (request_rec
* r
)
1727 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1728 "mod_waklog: phase2 called");
1730 if (child
.token
.ticketLen
)
1732 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1734 ktc_ForgetAllTokens ();
1736 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1737 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1741 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1742 "mod_waklog: phase2 returning");
1748 module MODULE_VAR_EXPORT waklog_module
= {
1749 STANDARD_MODULE_STUFF
,
1750 waklog_init
, /* module initializer */
1751 waklog_create_dir_config
, /* create per-dir config structures */
1752 waklog_merge_dir_config
, /* merge per-dir config structures */
1753 waklog_create_server_config
, /* create per-server config structures */
1754 waklog_merge_dir_config
, /* merge per-server config structures */
1755 waklog_cmds
, /* table of config file commands */
1756 NULL
, /* [#8] MIME-typed-dispatched handlers */
1757 waklog_phase1
, /* [#1] URI to filename translation */
1758 NULL
, /* [#4] validate user id from request */
1759 NULL
, /* [#5] check if the user is ok _here_ */
1760 waklog_phase3
, /* [#3] check access by host address */
1761 waklog_phase6
, /* [#6] determine MIME type */
1762 waklog_phase7
, /* [#7] pre-run fixups */
1763 waklog_phase9
, /* [#9] log a transaction */
1764 waklog_phase2
, /* [#2] header parser */
1765 waklog_child_init
, /* child_init */
1766 waklog_child_exit
, /* child_exit */
1767 waklog_phase0
/* [#0] post read-request */
1769 , NULL
, /* EAPI: add_module */
1770 NULL
, /* EAPI: remove_module */
1771 NULL
, /* EAPI: rewrite_command */
1772 waklog_new_connection
/* EAPI: new_connection */
1777 waklog_register_hooks (apr_pool_t
* p
)
1779 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1780 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1781 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1782 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1783 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1784 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1785 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1786 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1787 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1788 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1792 module AP_MODULE_DECLARE_DATA waklog_module
= {
1793 STANDARD20_MODULE_STUFF
,
1794 waklog_create_dir_config
, /* create per-dir conf structures */
1795 waklog_merge_dir_config
, /* merge per-dir conf structures */
1796 waklog_create_server_config
, /* create per-server conf structures */
1797 waklog_merge_dir_config
, /* merge per-server conf structures */
1798 waklog_cmds
, /* table of configuration directives */
1799 waklog_register_hooks
/* register hooks */