1 #define _LARGEFILE64_SOURCE
5 #include "http_config.h"
7 #include "http_protocol.h"
8 #include "http_request.h"
16 #include <sys/types.h>
20 #error "make sure you include the right stuff here"
24 #define MAXNAMELEN 1024
27 #ifdef STANDARD20_MODULE_STUFF
31 /********************* APACHE1 ******************************************************************************/
33 #include "ap_config.h"
35 #include <sys/ioccom.h>
37 #include <http_conf_globals.h>
39 #define MK_TABLE_GET ap_table_get
40 #define MK_TABLE_SET ap_table_set
41 #define command(name, func, var, type, usage) \
44 RSRC_CONF | ACCESS_CONF , type, usage }
47 /********************* APACHE2 ******************************************************************************/
49 #include <apr_strings.h>
50 #include <apr_base64.h>
51 #define ap_pcalloc apr_pcalloc
52 #define ap_pdupstr apr_pdupstr
53 #define ap_pstrdup apr_pstrdup
54 #define MK_POOL apr_pool_t
55 #define MK_TABLE_GET apr_table_get
56 #define MK_TABLE_SET apr_table_set
58 extern unixd_config_rec unixd_config
;
59 #define ap_user_id unixd_config.user_id
60 #define ap_group_id unixd_config.group_id
61 #define ap_user_name unixd_config.user_name
62 #define command(name, func, var, type, usage) \
63 AP_INIT_ ## type (name, (void*) func, \
65 RSRC_CONF | ACCESS_CONF, usage)
66 module AP_MODULE_DECLARE_DATA waklog_module
;
67 typedef struct { int dummy
; } child_info
;
68 const char *userdata_key
= "waklog_init";
71 /**************************************************************************************************/
75 #include <afs/venus.h>
77 #include <afs/dirpath.h>
78 #include <afs/ptuser.h>
81 #define TKT_LIFE ( 12 * 60 * 60 )
82 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
84 #define WAKLOG_UNSET -1
88 #define APLOG_DEBUG APLOG_ERR
91 /* this is used to turn off pag generation for the backround worker child during startup */
92 int pag_for_children
= 1;
100 int cell_in_principal
;
101 int disable_token_cache
;
104 char *default_principal
;
105 char *default_keytab
;
107 char *afs_cell_realm
;
115 struct ktc_token token
;
116 char clientprincipal
[MAXNAMELEN
];
117 krb5_context kcontext
;
119 struct ktc_principal server
;
120 struct ktc_principal client
;
122 } waklog_child_config
;
124 waklog_child_config child
;
126 struct tokencache_ent
{
127 char clientprincipal
[MAXNAMELEN
];
128 struct ktc_token token
;
129 struct ktc_principal client
;
130 struct ktc_principal server
;
135 #define SHARED_TABLE_SIZE 512
137 struct sharedspace_s
{
139 struct tokencache_ent sharedtokens
[SHARED_TABLE_SIZE
];
142 struct sharedspace_s
*sharedspace
= NULL
;
151 pthread_rwlock_t
*sharedlock
= NULL
;
153 rwlock_t
*sharedlock
= NULL
;
156 struct renew_ent renewtable
[SHARED_TABLE_SIZE
];
162 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
167 #include <sys/ioccom.h>
170 #include <afs/venus.h>
171 #include <afs/auth.h>
172 #include <afs/dirpath.h>
173 #include <afs/ptuser.h>
174 #include <rx/rxkad.h>
178 log_error (const char *file
, int line
, int level
, int status
,
179 const server_rec
* s
, const char *fmt
, ...)
185 vsnprintf (errstr
, 1024, fmt
, ap
);
189 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
191 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
196 waklog_config
*retrieve_config(request_rec
*r
) {
201 if ( r
&& r
->main
) {
209 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
212 getModConfig (cfg
, r
->server
);
219 /* set_auth -- sets the tokens of the current process to this user.
220 if "self" is set, it divines the user from the current requests' environment.
221 otherwise, it's gettng it from principal/keytab */
224 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
228 krb5_error_code kerror
= 0;
229 krb5_principal kprinc
= NULL
;
230 krb5_get_init_creds_opt kopts
;
233 krb5_ccache clientccache
;
234 struct ktc_principal server
= { "afs", "", "" };
235 struct ktc_principal client
;
236 struct ktc_token token
;
237 krb5_creds
*v5credsp
= NULL
;
238 krb5_keytab krb5kt
= NULL
;
239 char buf
[MAXNAMELEN
];
243 time_t oldest_time
= 0;
248 int cell_in_principal
;
250 int use_client_credentials
= 0;
252 char k5user
[MAXNAMELEN
] = "";
253 char *k5secret
= NULL
;
257 memset((char *) &increds
, 0, sizeof(increds
));
258 /* init some stuff if it ain't already */
259 /* XXX - In what situation will these not be initialized? */
261 if ( ! child
.kcontext
) {
262 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
263 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
269 if ( !child
.ccache
) {
270 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
271 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
277 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
278 self
, principal
? principal
: "NULL",
279 keytab
? keytab
: "NULL",
281 k5path
? k5path
: "NULL",
283 (r
&& r
->user
) ? r
->user
: "NULL"
285 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
289 /* pull the server config record that we care about... */
292 cfg
= retrieve_config(r
);
294 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
295 "mod_waklog: set_auth using no config" );
296 getModConfig (cfg
, s
);
300 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
305 /* pull out our principal name and stuff from the environment -- webauth better have sent
309 if ( ! ( r
&& r
->connection
&& r
->user
)) {
310 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
311 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
==NULL
));
315 strncpy(k5user
, r
->user
, sizeof(k5user
));
317 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
318 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
322 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
324 /* if they've supplied a credentials cache */
325 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
327 /* the other thing we need is someone's password */
328 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
330 /* we'll pick this up later after we've checked the cache and current state */
334 strncpy(k5user
, principal
, sizeof(k5user
));
338 strncpy(k5user
, r
->user
, sizeof(k5user
));
341 if (r
&& r
->connection
&& r
->connection
->user
) {
342 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
346 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
? k5user
: "NULL");
349 /* see if we should just go ahead and ignore this call, since we already should be set to these
355 pthread_rwlock_rdlock( sharedlock
);
357 rw_rdlock( sharedlock
);
360 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
362 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
364 if ( ( !strcmp( k5user
,
365 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
366 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
368 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
374 /* copy the token out of the cache and into the child object */
376 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
377 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
378 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
379 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
381 /* set our last used time thing */
382 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
392 /* release the lock on the token cache */
394 pthread_rwlock_unlock( sharedlock
);
396 rw_unlock( sharedlock
);
400 /* release the lock on the token cache */
401 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
402 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
406 /* if this is something that was in the cache, and it's the same as the token we already have stored,
407 and we weren't calling this just to renew it... */
409 if ( usecached
&& indentical
) {
410 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
416 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
417 if (( ! usecached
) && ( k5user
)) {
419 /* clear out the creds structure */
420 memset((void *) &v5creds
, 0, sizeof(v5creds
));
422 /* create a principal out of our k5user string */
424 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
425 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror
) );
429 /* create the credentials options */
431 krb5_get_init_creds_opt_init ( &kopts
);
432 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
433 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
434 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
435 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
437 if ( keytab
|| k5secret
) {
440 /* if we've been passed a keytab, we're going to be getting our credentials from it */
442 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
444 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
445 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
446 "mod_waklog: krb5_kt_resolve %s", error_message(kerror
) );
450 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
451 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
452 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
453 error_message(kerror
) );
456 } else if (k5secret
) {
458 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
460 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
461 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
462 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
463 error_message(kerror
) );
464 /* nuke the password so it doesn't end up in core files */
465 memset(k5secret
, 0, sizeof(k5secret
));
469 memset(k5secret
, 0, sizeof(k5secret
));
472 /* initialize the credentials cache and store the stuff we just got */
473 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
474 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
475 error_message(kerror
));
479 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
480 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
481 error_message(kerror
));
485 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
488 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", error_message(kerror
));
492 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
495 /* If we've got a path to a credentials cache, then try and use that. We can't just
496 * replace child.creds, because we want to ensure that only this request gets access to
499 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
500 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
501 "mod_waklog: can't open provided credentials cache %s err=%d",
506 use_client_credentials
= 1;
509 /* now, to the 'aklog' portion of our program. */
511 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
512 for(attempt
= 0; attempt
<= 1; attempt
++) {
513 strncpy( buf
, "afs", sizeof(buf
) - 1 );
514 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
516 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
517 if (cell_in_principal
) {
518 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
519 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
521 if (cfg
->afs_cell_realm
!= NULL
) {
522 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
523 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
526 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
528 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
529 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", error_message(kerror
));
533 if (!use_client_credentials
) {
534 clientccache
= child
.ccache
;
537 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
538 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", error_message(kerror
), clientccache
);
542 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
544 increds
.times
.endtime
= 0;
546 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
548 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
549 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
551 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
552 error_message(kerror
));
558 cfg
->cell_in_principal
= cell_in_principal
;
562 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
564 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
565 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
566 v5credsp
->ticket
.length
);
570 memset(&token
, 0, sizeof(struct ktc_token
));
572 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
573 token
.endTime
= v5credsp
->times
.endtime
;
575 memmove( &token
.sessionKey
, v5credsp
->keyblock
.contents
, v5credsp
->keyblock
.length
);
576 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
577 token
.ticketLen
= v5credsp
->ticket
.length
;
578 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
582 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
584 buf
[v5credsp
->client
->data
[0].length
] = '\0';
585 if ( v5credsp
->client
->length
> 1 ) {
586 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
587 buflen
= strlen(buf
);
588 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
589 min(v5credsp
->client
->data
[1].length
,
590 MAXKTCNAMELEN
- strlen(buf
) - 1));
591 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
594 /* assemble the client */
595 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
596 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
597 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
599 buf
[v5credsp
->client
->realm
.length
] = '\0';
600 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
602 /* assemble the server's cell */
603 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
605 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
607 /* fill out the AFS ID in the client name */
608 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
609 * strange things seem to happen. */
612 afs_int32 viceId
= 0;
614 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
616 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
617 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
619 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
622 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
626 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
627 server
.name
, server
.instance
, server
.cell
);
629 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
630 client
.name
, client
.instance
, client
.cell
);
632 /* copy the resulting stuff into the child structure */
634 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
635 memcpy(&child
.token
, &token
, sizeof(child
.token
));
636 memcpy(&child
.server
, &server
, sizeof(child
.server
));
637 memcpy(&child
.client
, &client
, sizeof(child
.client
));
639 /* stuff the resulting token-related stuff into our shared token cache */
640 /* note, that anything that was set from a keytab is "persistant", and is immune
641 * from LRU-aging. This is because nothing but the process that's running as root
642 * can update these, and it's running every hour or so and renewing these tokens.
643 * and we don't want them aged out.
646 mytime
= oldest_time
= time(0);
648 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
651 pthread_rwlock_wrlock(sharedlock
);
653 rw_wrlock(sharedlock
);
656 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
657 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
658 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
660 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
662 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
663 child
.clientprincipal
) ) {
664 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
665 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
666 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
667 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
668 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
674 if ( stored
== -1 ) {
675 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
676 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
677 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
678 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
679 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
680 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
685 pthread_rwlock_unlock(sharedlock
);
687 rw_unlock(sharedlock
);
690 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
691 child
.clientprincipal
);
693 } else if ( ! usecached
) {
694 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
703 /* don't ask. Something about AIX. We're leaving it here.*/
704 /* write(2, "", 0); */
706 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
708 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
709 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
710 error_message(rc
), k5user
);
711 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
712 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
713 error_message(rc
), k5user
);
719 if (use_client_credentials
)
720 krb5_cc_close(child
.kcontext
, clientccache
);
722 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
723 if ( increds
.client
)
724 krb5_free_principal (child
.kcontext
, increds
.client
);
725 if ( increds
.server
)
726 krb5_free_principal (child
.kcontext
, increds
.server
);
728 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
730 krb5_free_principal (child
.kcontext
, kprinc
);
733 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
734 } else if ( kerror
) {
735 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, error_message(kerror
));
737 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
740 return kerror
? (int) kerror
: (int) rc
;
745 int get_cfg_usertokens(waklog_config
*cfg
)
747 if (cfg
->usertokens
==WAKLOG_UNSET
)
748 return 0; /* default */
749 return cfg
->usertokens
;
752 int get_cfg_protect(waklog_config
*cfg
)
754 if (cfg
->protect
==WAKLOG_UNSET
)
755 return 0; /* default */
759 int get_cfg_disable_token_cache(waklog_config
*cfg
)
761 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
762 return 0; /* default */
763 return cfg
->disable_token_cache
;
768 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
772 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
774 memset(cfg
, 0, sizeof(waklog_config
));
775 cfg
->path
= "(server)";
776 cfg
->protect
= WAKLOG_UNSET
;
777 cfg
->usertokens
= WAKLOG_UNSET
;
778 cfg
->disable_token_cache
= WAKLOG_UNSET
;
780 cfg
->principal
= NULL
;
781 cfg
->default_principal
= NULL
;
782 cfg
->default_keytab
= NULL
;
783 cfg
->afs_cell
= NULL
;
784 cfg
->afs_cell_realm
= NULL
;
788 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
789 "mod_waklog: server config created.");
794 /* initialize with host-config information */
797 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
801 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
802 memset(cfg
, 0, sizeof(waklog_config
));
804 cfg
->path
= ap_pstrdup(p
, dir
);
805 cfg
->protect
= WAKLOG_UNSET
;
806 cfg
->usertokens
= WAKLOG_UNSET
;
807 cfg
->disable_token_cache
= WAKLOG_UNSET
;
809 cfg
->principal
= NULL
;
810 cfg
->default_principal
= NULL
;
811 cfg
->default_keytab
= NULL
;
812 cfg
->afs_cell
= NULL
;
813 cfg
->afs_cell_realm
= NULL
;
820 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
822 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
823 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
824 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
826 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
828 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
830 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
832 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
834 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
836 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
838 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
840 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
842 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
844 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
846 return (void *) merged
;
850 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
852 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
853 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
854 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
856 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
858 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
860 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
862 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
863 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
865 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
866 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
868 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
869 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
871 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
872 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
874 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
875 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
877 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
878 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
881 return (void *) merged
;
886 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
888 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
889 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
893 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
894 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
899 /* this adds a principal/keytab pair to get their tokens renewed by the
900 child process every few centons. */
902 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
906 if ( renewcount
>= SHARED_TABLE_SIZE
) {
907 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
908 decrease your tokens.");
912 /* check to see if it's already there */
914 for ( i
= 0; i
< renewcount
; i
++ ) {
915 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
920 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
921 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
922 renewtable
[renewcount
].lastrenewed
= 0;
928 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
930 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
931 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
933 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
934 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
936 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
937 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
939 add_to_renewtable(params
->pool
, keytab
, principal
);
947 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
949 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
950 waklog_config
*waklog_srvconfig
=
951 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
953 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
954 "mod_waklog: will use afs_cell: %s", file
);
956 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
957 waklog_srvconfig
->cell_in_principal
= 1;
959 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
960 waklog_srvconfig
->configured
= 1;
962 if (waklog_mconfig
!= NULL
) {
963 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
964 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
965 waklog_mconfig
->configured
= 1;
971 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
973 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
974 waklog_config
*waklog_srvconfig
=
975 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
977 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
978 "mod_waklog: will use afs_cell_realm: %s", file
);
980 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
982 if (waklog_mconfig
!= NULL
) {
983 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
989 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
991 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
992 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
994 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
996 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
997 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
999 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1000 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1002 /* this also gets set at the server level */
1003 if ( mconfig
&& ( ! cfg
->path
) ) {
1004 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1005 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1007 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
1008 return "Unable to set DefaultPrincipal outside of top level config!";
1011 add_to_renewtable( params
->pool
, keytab
, principal
);
1013 cfg
->configured
= 1;
1019 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1021 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1022 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1024 cfg
->usertokens
= flag
;
1026 cfg
->configured
= 1;
1028 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1029 "mod_waklog: waklog_use_user_tokens set");
1035 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1037 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1038 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1040 cfg
->disable_token_cache
= flag
;
1042 cfg
->configured
= 1;
1044 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1045 "mod_waklog: waklog_disable_token_cache set");
1051 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1053 apr_status_t
waklog_child_exit( void *sr
) {
1055 server_rec
*s
= (server_rec
*) sr
;
1058 if ( child
.ccache
) {
1059 krb5_cc_close(child
.kcontext
, child
.ccache
);
1062 if ( child
.kcontext
) {
1063 krb5_free_context(child
.kcontext
);
1066 /* forget our tokens */
1068 ktc_ForgetAllTokens ();
1070 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1071 "mod_waklog: waklog_child_exit complete");
1081 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1083 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1087 krb5_error_code code
;
1092 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1094 if ( !sharedspace
) {
1095 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1099 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1101 memset (&child
, 0, sizeof(child
));
1103 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1104 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1107 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1108 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1111 if ( pag_for_children
) {
1115 getModConfig (cfg
, s
);
1117 if ( cfg
->default_principal
!= NULL
) {
1118 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1119 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1122 cell
= strdup(cfg
->afs_cell
);
1123 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1126 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1129 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1130 "mod_waklog: child_init returned");
1135 command_rec waklog_cmds
[] = {
1137 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1138 "Use the supplied AFS cell (required)"),
1140 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1141 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1143 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1144 "enable waklog on a server, location, or directory basis"),
1146 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1147 "Set the default principal that the server runs as"),
1149 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1150 "Set the principal on a <Location>-specific basis"),
1152 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1153 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1155 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1156 "Use the requesting user tokens (from webauth)"),
1162 /* not currently using this */
1165 token_cleanup (void *data
)
1167 request_rec
*r
= (request_rec
*) data
;
1169 if (child
.token
.ticketLen
)
1171 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1173 ktc_ForgetAllTokens ();
1175 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1176 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1183 waklog_child_routine (void *data
, child_info
* pinfo
)
1186 server_rec
*s
= (server_rec
*) data
;
1187 krb5_error_code code
;
1189 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1194 getModConfig( cfg
, s
);
1196 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1198 memset (&child
, 0, sizeof(child
));
1200 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1201 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1204 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1205 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1208 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1210 /* need to do this so we can make PTS calls */
1211 cell
= strdup(cfg
->afs_cell
); /* stupid */
1212 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1214 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1218 for ( i
= 0; i
< renewcount
; ++i
) {
1219 renewtable
[i
].lastrenewed
= time(0);
1220 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1221 renewtable
[i
].keytab
);
1223 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1225 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1226 things that it needs to read */
1228 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1229 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1230 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1235 sharedspace
->renewcount
++;
1244 left
-= ( time(0) - when
);
1255 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1256 apr_pool_t
* ptemp
, server_rec
* s
)
1259 extern char *version
;
1264 int use_existing
= 1;
1266 char cache_file
[MAXNAMELEN
];
1268 pthread_rwlockattr_t rwlock_attr
;
1272 getModConfig (cfg
, s
);
1274 /* initialize_module() will be called twice, and if it's a DSO
1275 * then all static data from the first call will be lost. Only
1276 * set up our static data on the second call.
1277 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1278 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1281 if (cfg
->afs_cell
==NULL
) {
1282 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1283 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1284 /** clobber apache */
1290 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1291 apr_pool_cleanup_null
, s
->process
->pool
);
1295 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1296 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1298 if ( sharedspace
) {
1299 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1302 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1304 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1306 if ( errno
== ENOENT
) {
1308 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1310 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1311 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1315 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1319 if ( use_existing
== 0 ) {
1320 struct sharedspace_s bob
;
1321 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1322 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1323 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1324 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1327 /* mmap the region */
1329 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1331 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1332 err
= unlink(cache_file
);
1334 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1336 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared cache deleted");
1339 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1345 #define locktype pthread_rwlock_t
1347 #define locktype rwlock_t
1350 if ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) {
1351 #ifndef use_pthreads
1352 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1354 pthread_rwlockattr_init(&rwlock_attr
);
1355 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1356 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1359 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1364 /* set our default tokens */
1366 oldrenewcount
= sharedspace
->renewcount
;
1368 pag_for_children
= 0;
1370 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1372 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1374 if (rv
== APR_INCHILD
)
1376 waklog_child_routine (s
, NULL
);
1380 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1382 /* parent and child */
1383 cfg
->forked
= proc
->pid
;
1384 pag_for_children
= 1;
1386 if ( use_existing
== 0 ) {
1387 /* wait here until our child process has gone and done it's renewing thing. */
1388 while( sharedspace
->renewcount
== oldrenewcount
) {
1389 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1394 if ( cfg
->default_principal
) {
1395 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1402 waklog_init (server_rec
* s
, MK_POOL
* p
)
1404 extern char *version
;
1408 int use_existing
= 1;
1410 char cache_file
[MAXNAMELEN
];
1412 pthread_rwlockattr_t rwlock_attr
;
1415 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1416 "mod_waklog: version %s initialized.", version
);
1418 if ( sharedspace
) {
1419 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1422 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1424 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1426 if ( errno
== ENOENT
) {
1428 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1430 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1431 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1435 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1440 if ( use_existing
== 0 ) {
1441 struct sharedspace_s bob
;
1442 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1443 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1444 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1445 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1448 /* mmap the region */
1450 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1451 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1454 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1460 #define locktype pthread_rwlock_t
1462 #define locktype rwlock_t
1465 /* mmap our shared space for our lock */
1466 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1467 #ifndef use_pthreads
1468 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1470 pthread_rwlockattr_init(&rwlock_attr
);
1471 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1472 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1475 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1480 /* set our default tokens */
1482 getModConfig (cfg
, s
);
1484 oldrenewcount
= sharedspace
->renewcount
;
1486 pag_for_children
= 0;
1488 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1491 pag_for_children
= 1;
1493 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1494 "mod_waklog: ap_bspawn_child: %d.", pid
);
1496 if ( use_existing
== 0 ) {
1497 /* wait here until our child process has gone and done it's renewing thing. */
1498 while( sharedspace
->renewcount
== oldrenewcount
) {
1499 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1504 if ( cfg
->default_principal
) {
1505 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1512 waklog_phase0 (request_rec
* r
)
1516 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1517 "mod_waklog: phase0 called");
1519 cfg
= retrieve_config(r
);
1521 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1522 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1523 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1524 } else if ( cfg
->default_principal
) {
1525 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1526 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1529 if (child
.token
.ticketLen
) {
1530 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1531 ktc_ForgetAllTokens();
1534 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1541 waklog_phase1 (request_rec
* r
)
1545 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1546 "mod_waklog: phase1 called");
1548 cfg
= retrieve_config(r
);
1550 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1551 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1552 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1553 } else if ( cfg
->default_principal
) {
1554 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1555 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1557 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1564 waklog_phase3 (request_rec
* r
)
1568 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1569 "mod_waklog: phase 3 called");
1571 cfg
= retrieve_config(r
);
1573 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1574 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1575 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1576 } else if ( cfg
->default_principal
) {
1577 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1578 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1580 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1587 waklog_phase6 (request_rec
* r
)
1591 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1592 "mod_waklog: phase6 called");
1594 cfg
= retrieve_config(r
);
1596 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1597 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1598 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1599 } else if ( cfg
->default_principal
) {
1600 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1601 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1603 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1610 waklog_phase7 (request_rec
* r
)
1615 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1616 "mod_waklog: phase7 called");
1618 cfg
= retrieve_config (r
);
1620 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1621 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1622 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1623 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1624 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1625 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1626 } else if ( cfg
->default_principal
) {
1627 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1628 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1630 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1631 if (child
.token
.ticketLen
) {
1632 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1633 ktc_ForgetAllTokens();
1645 waklog_phase9 (request_rec
* r
)
1649 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1650 "mod_waklog: phase9 called");
1652 getModConfig (cfg
, r
->server
);
1654 if ( cfg
->default_principal
) {
1655 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1656 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1669 waklog_new_connection (conn_rec
* c
1678 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1679 "mod_waklog: new_connection called: pid: %d", getpid ());
1681 getModConfig(cfg
, c
->base_server
);
1683 if ( cfg
->default_principal
) {
1684 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1685 cfg
->default_principal
);
1686 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1699 ** Here's a quick explaination for phase0 and phase2:
1700 ** Apache does a stat() on the path between phase0 and
1701 ** phase2, and must by ACLed rl to succeed. So, at
1702 ** phase0 we acquire credentials for umweb:servers from
1703 ** a keytab, and at phase2 we must ensure we remove them.
1705 ** Failure to "unlog" would be a security risk.
1708 waklog_phase2 (request_rec
* r
)
1711 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1712 "mod_waklog: phase2 called");
1714 if (child
.token
.ticketLen
)
1716 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1718 ktc_ForgetAllTokens ();
1720 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1721 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1725 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1726 "mod_waklog: phase2 returning");
1732 module MODULE_VAR_EXPORT waklog_module
= {
1733 STANDARD_MODULE_STUFF
,
1734 waklog_init
, /* module initializer */
1735 waklog_create_dir_config
, /* create per-dir config structures */
1736 waklog_merge_dir_config
, /* merge per-dir config structures */
1737 waklog_create_server_config
, /* create per-server config structures */
1738 waklog_merge_dir_config
, /* merge per-server config structures */
1739 waklog_cmds
, /* table of config file commands */
1740 NULL
, /* [#8] MIME-typed-dispatched handlers */
1741 waklog_phase1
, /* [#1] URI to filename translation */
1742 NULL
, /* [#4] validate user id from request */
1743 NULL
, /* [#5] check if the user is ok _here_ */
1744 waklog_phase3
, /* [#3] check access by host address */
1745 waklog_phase6
, /* [#6] determine MIME type */
1746 waklog_phase7
, /* [#7] pre-run fixups */
1747 waklog_phase9
, /* [#9] log a transaction */
1748 waklog_phase2
, /* [#2] header parser */
1749 waklog_child_init
, /* child_init */
1750 waklog_child_exit
, /* child_exit */
1751 waklog_phase0
/* [#0] post read-request */
1753 , NULL
, /* EAPI: add_module */
1754 NULL
, /* EAPI: remove_module */
1755 NULL
, /* EAPI: rewrite_command */
1756 waklog_new_connection
/* EAPI: new_connection */
1761 waklog_register_hooks (apr_pool_t
* p
)
1763 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1764 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1765 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1766 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1767 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1768 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1769 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1770 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1771 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1772 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1776 module AP_MODULE_DECLARE_DATA waklog_module
= {
1777 STANDARD20_MODULE_STUFF
,
1778 waklog_create_dir_config
, /* create per-dir conf structures */
1779 waklog_merge_dir_config
, /* merge per-dir conf structures */
1780 waklog_create_server_config
, /* create per-server conf structures */
1781 waklog_merge_dir_config
, /* merge per-server conf structures */
1782 waklog_cmds
, /* table of configuration directives */
1783 waklog_register_hooks
/* register hooks */