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
)
1274 extern char *version
;
1279 int use_existing
= 1;
1281 char cache_file
[MAXNAMELEN
];
1283 pthread_rwlockattr_t rwlock_attr
;
1287 getModConfig (cfg
, s
);
1289 /* initialize_module() will be called twice, and if it's a DSO
1290 * then all static data from the first call will be lost. Only
1291 * set up our static data on the second call.
1292 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1293 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1296 if (cfg
->afs_cell
==NULL
) {
1297 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1298 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1299 /** clobber apache */
1305 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1306 apr_pool_cleanup_null
, s
->process
->pool
);
1310 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1311 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1313 if ( sharedspace
) {
1314 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1317 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1319 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1321 if ( errno
== ENOENT
) {
1323 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1325 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1326 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1330 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1334 if ( use_existing
== 0 ) {
1335 struct sharedspace_s bob
;
1336 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1337 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1338 if ( write(fd
, &bob
, sizeof(struct sharedspace_s
)) != sizeof(struct sharedspace_s
) ) {
1339 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: failed to write to our cache file %s (%d)", cache_file
, errno
);
1342 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1345 /* mmap the region */
1347 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1349 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1350 err
= unlink(cache_file
);
1352 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1354 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1357 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1363 #define locktype pthread_rwlock_t
1365 #define locktype rwlock_t
1368 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) != NULL
) {
1369 #ifndef use_pthreads
1370 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1372 pthread_rwlockattr_init(&rwlock_attr
);
1373 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1374 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1377 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1382 /* set our default tokens */
1384 oldrenewcount
= sharedspace
->renewcount
;
1386 pag_for_children
= 0;
1388 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1390 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1392 if (rv
== APR_INCHILD
)
1394 waklog_child_routine (s
, NULL
);
1398 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1400 /* parent and child */
1401 cfg
->forked
= proc
->pid
;
1402 pag_for_children
= 1;
1404 if ( use_existing
== 0 ) {
1405 /* wait here until our child process has gone and done it's renewing thing. */
1406 while( sharedspace
->renewcount
== oldrenewcount
) {
1407 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1412 if ( cfg
->default_principal
) {
1413 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1420 waklog_init (server_rec
* s
, MK_POOL
* p
)
1422 extern char *version
;
1426 int use_existing
= 1;
1428 char cache_file
[MAXNAMELEN
];
1430 pthread_rwlockattr_t rwlock_attr
;
1433 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1434 "mod_waklog: version %s initialized.", version
);
1436 if ( sharedspace
) {
1437 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1440 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1442 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1444 if ( errno
== ENOENT
) {
1446 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1448 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1449 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1453 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1458 if ( use_existing
== 0 ) {
1459 struct sharedspace_s bob
;
1460 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1461 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1462 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1463 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1466 /* mmap the region */
1468 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1469 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1472 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1478 #define locktype pthread_rwlock_t
1480 #define locktype rwlock_t
1483 /* mmap our shared space for our lock */
1484 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1485 #ifndef use_pthreads
1486 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1488 pthread_rwlockattr_init(&rwlock_attr
);
1489 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1490 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1493 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1498 /* set our default tokens */
1500 getModConfig (cfg
, s
);
1502 oldrenewcount
= sharedspace
->renewcount
;
1504 pag_for_children
= 0;
1506 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1509 pag_for_children
= 1;
1511 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1512 "mod_waklog: ap_bspawn_child: %d.", pid
);
1514 if ( use_existing
== 0 ) {
1515 /* wait here until our child process has gone and done it's renewing thing. */
1516 while( sharedspace
->renewcount
== oldrenewcount
) {
1517 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1522 if ( cfg
->default_principal
) {
1523 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1530 waklog_phase0 (request_rec
* r
)
1534 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1535 "mod_waklog: phase0 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: phase0 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: phase0 using default user %s", cfg
->default_principal
);
1544 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1547 if (child
.token
.ticketLen
) {
1548 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1549 ktc_ForgetAllTokens();
1552 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1559 waklog_phase1 (request_rec
* r
)
1563 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1564 "mod_waklog: phase1 called");
1566 cfg
= retrieve_config(r
);
1568 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1569 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1570 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1571 } else if ( cfg
->default_principal
) {
1572 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1573 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1575 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1582 waklog_phase3 (request_rec
* r
)
1586 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1587 "mod_waklog: phase 3 called");
1589 cfg
= retrieve_config(r
);
1591 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1592 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1593 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1594 } else if ( cfg
->default_principal
) {
1595 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1596 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1598 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1605 waklog_phase6 (request_rec
* r
)
1609 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1610 "mod_waklog: phase6 called");
1612 cfg
= retrieve_config(r
);
1614 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1615 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1616 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1617 } else if ( cfg
->default_principal
) {
1618 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1619 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1621 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1628 waklog_phase7 (request_rec
* r
)
1633 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1634 "mod_waklog: phase7 called");
1636 cfg
= retrieve_config (r
);
1638 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1639 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1640 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1641 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1642 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1643 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1644 } else if ( cfg
->default_principal
) {
1645 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1646 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1648 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1649 if (child
.token
.ticketLen
) {
1650 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1651 ktc_ForgetAllTokens();
1663 waklog_phase9 (request_rec
* r
)
1667 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1668 "mod_waklog: phase9 called");
1670 getModConfig (cfg
, r
->server
);
1672 if ( cfg
->default_principal
) {
1673 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1674 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1687 waklog_new_connection (conn_rec
* c
1696 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1697 "mod_waklog: new_connection called: pid: %d", getpid ());
1699 getModConfig(cfg
, c
->base_server
);
1701 if ( cfg
->default_principal
) {
1702 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1703 cfg
->default_principal
);
1704 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1717 ** Here's a quick explaination for phase0 and phase2:
1718 ** Apache does a stat() on the path between phase0 and
1719 ** phase2, and must by ACLed rl to succeed. So, at
1720 ** phase0 we acquire credentials for umweb:servers from
1721 ** a keytab, and at phase2 we must ensure we remove them.
1723 ** Failure to "unlog" would be a security risk.
1726 waklog_phase2 (request_rec
* r
)
1729 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1730 "mod_waklog: phase2 called");
1732 if (child
.token
.ticketLen
)
1734 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1736 ktc_ForgetAllTokens ();
1738 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1739 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1743 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1744 "mod_waklog: phase2 returning");
1750 module MODULE_VAR_EXPORT waklog_module
= {
1751 STANDARD_MODULE_STUFF
,
1752 waklog_init
, /* module initializer */
1753 waklog_create_dir_config
, /* create per-dir config structures */
1754 waklog_merge_dir_config
, /* merge per-dir config structures */
1755 waklog_create_server_config
, /* create per-server config structures */
1756 waklog_merge_dir_config
, /* merge per-server config structures */
1757 waklog_cmds
, /* table of config file commands */
1758 NULL
, /* [#8] MIME-typed-dispatched handlers */
1759 waklog_phase1
, /* [#1] URI to filename translation */
1760 NULL
, /* [#4] validate user id from request */
1761 NULL
, /* [#5] check if the user is ok _here_ */
1762 waklog_phase3
, /* [#3] check access by host address */
1763 waklog_phase6
, /* [#6] determine MIME type */
1764 waklog_phase7
, /* [#7] pre-run fixups */
1765 waklog_phase9
, /* [#9] log a transaction */
1766 waklog_phase2
, /* [#2] header parser */
1767 waklog_child_init
, /* child_init */
1768 waklog_child_exit
, /* child_exit */
1769 waklog_phase0
/* [#0] post read-request */
1771 , NULL
, /* EAPI: add_module */
1772 NULL
, /* EAPI: remove_module */
1773 NULL
, /* EAPI: rewrite_command */
1774 waklog_new_connection
/* EAPI: new_connection */
1779 waklog_register_hooks (apr_pool_t
* p
)
1781 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1782 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1783 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1784 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1785 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1786 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1787 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1788 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1789 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1790 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1794 module AP_MODULE_DECLARE_DATA waklog_module
= {
1795 STANDARD20_MODULE_STUFF
,
1796 waklog_create_dir_config
, /* create per-dir conf structures */
1797 waklog_merge_dir_config
, /* merge per-dir conf structures */
1798 waklog_create_server_config
, /* create per-server conf structures */
1799 waklog_merge_dir_config
, /* merge per-server conf structures */
1800 waklog_cmds
, /* table of configuration directives */
1801 waklog_register_hooks
/* register hooks */