1 #define _LARGEFILE64_SOURCE
5 #include "http_config.h"
7 #include "http_protocol.h"
8 #include "http_request.h"
14 #include <sys/ioccom.h>
18 #include <sys/types.h>
22 #error "make sure you include the right stuff here"
26 #define MAXNAMELEN 1024
29 #ifdef STANDARD20_MODULE_STUFF
33 /********************* APACHE1 ******************************************************************************/
35 #include "ap_config.h"
36 #include <http_conf_globals.h>
38 #define MK_TABLE_GET ap_table_get
39 #define MK_TABLE_SET ap_table_set
40 #define command(name, func, var, type, usage) \
43 RSRC_CONF | ACCESS_CONF , type, usage }
46 /********************* APACHE2 ******************************************************************************/
48 #include "http_connection.h"
49 #include <apr_strings.h>
50 #include <apr_base64.h>
51 #define ap_pcalloc apr_pcalloc
52 #define ap_pdupstr apr_pdupstr
53 #define ap_pstrdup apr_pstrdup
54 #define MK_POOL apr_pool_t
55 #define MK_TABLE_GET apr_table_get
56 #define MK_TABLE_SET apr_table_set
57 #define command(name, func, var, type, usage) \
58 AP_INIT_ ## type (name, (void*) func, \
60 RSRC_CONF | ACCESS_CONF, usage)
61 module AP_MODULE_DECLARE_DATA waklog_module
;
62 typedef struct { int dummy
; } child_info
;
63 const char *userdata_key
= "waklog_init";
66 #ifdef APLOG_USE_MODULE
67 APLOG_USE_MODULE(waklog
);
71 /**************************************************************************************************/
76 #include <afs/param.h>
78 #include <afs/venus.h>
80 #include <afs/dirpath.h>
81 #include <afs/ptuser.h>
82 #include <afs/com_err.h>
85 #define TKT_LIFE ( 12 * 60 * 60 )
86 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
88 #define WAKLOG_UNSET -1
92 #define APLOG_DEBUG APLOG_ERR
95 /* this is used to turn off pag generation for the backround worker child during startup */
96 int pag_for_children
= 1;
104 int cell_in_principal
;
105 int disable_token_cache
;
108 char *default_principal
;
109 char *default_keytab
;
111 char *afs_cell_realm
;
119 struct ktc_token token
;
120 char clientprincipal
[MAXNAMELEN
];
121 krb5_context kcontext
;
123 struct ktc_principal server
;
124 struct ktc_principal client
;
126 } waklog_child_config
;
128 waklog_child_config child
;
130 struct tokencache_ent
{
131 char clientprincipal
[MAXNAMELEN
];
132 struct ktc_token token
;
133 struct ktc_principal client
;
134 struct ktc_principal server
;
139 #define SHARED_TABLE_SIZE 512
141 struct sharedspace_s
{
143 struct tokencache_ent sharedtokens
[SHARED_TABLE_SIZE
];
146 struct sharedspace_s
*sharedspace
= NULL
;
155 pthread_rwlock_t
*sharedlock
= NULL
;
157 rwlock_t
*sharedlock
= NULL
;
160 struct renew_ent renewtable
[SHARED_TABLE_SIZE
];
166 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
169 #ifdef APLOG_USE_MODULE
171 log_error (const char *file
, int line
, int module_index
, int level
, int status
,
172 const server_rec
* s
, const char *fmt
, ...)
175 log_error (const char *file
, int line
, int level
, int status
,
176 const server_rec
* s
, const char *fmt
, ...)
183 vsnprintf (errstr
, 1024, fmt
, ap
);
187 #ifdef APLOG_USE_MODULE
189 ap_log_error (file
, line
, module_index
, level
| APLOG_NOERRNO
, status
, s
, "%s", errstr
);
191 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
194 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
199 waklog_config
*retrieve_config(request_rec
*r
) {
204 if ( r
&& r
->main
) {
212 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
215 getModConfig (cfg
, r
->server
);
222 /* set_auth -- sets the tokens of the current process to this user.
223 if "self" is set, it divines the user from the current requests' environment.
224 otherwise, it's gettng it from principal/keytab */
227 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
231 krb5_error_code kerror
= 0;
232 krb5_principal kprinc
= NULL
;
233 krb5_get_init_creds_opt kopts
;
236 krb5_ccache clientccache
;
237 struct ktc_principal server
= { "afs", "", "" };
238 struct ktc_principal client
;
239 struct ktc_token token
;
240 krb5_creds
*v5credsp
= NULL
;
241 krb5_keytab krb5kt
= NULL
;
242 char buf
[MAXNAMELEN
];
246 time_t oldest_time
= 0;
251 int cell_in_principal
;
253 int use_client_credentials
= 0;
255 char k5user
[MAXNAMELEN
] = "";
256 char *k5secret
= NULL
;
260 memset((char *) &increds
, 0, sizeof(increds
));
261 /* init some stuff if it ain't already */
262 /* XXX - In what situation will these not be initialized? */
264 if ( ! child
.kcontext
) {
265 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
266 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
272 if ( !child
.ccache
) {
273 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
274 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
280 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
281 self
, principal
? principal
: "NULL",
282 keytab
? keytab
: "NULL",
284 k5path
? k5path
: "NULL",
286 (r
&& r
->user
) ? r
->user
: "NULL"
288 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
292 /* pull the server config record that we care about... */
295 cfg
= retrieve_config(r
);
297 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
298 "mod_waklog: set_auth using no config" );
299 getModConfig (cfg
, s
);
303 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
308 /* pull out our principal name and stuff from the environment -- webauth better have sent
312 if ( ! ( r
&& r
->connection
&& r
->user
)) {
313 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
314 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
));
318 strncpy(k5user
, r
->user
, sizeof(k5user
));
320 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
321 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
325 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
327 /* if they've supplied a credentials cache */
328 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
330 /* the other thing we need is someone's password */
331 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
333 /* we'll pick this up later after we've checked the cache and current state */
337 strncpy(k5user
, principal
, sizeof(k5user
));
341 strncpy(k5user
, r
->user
, sizeof(k5user
));
344 if (r
&& r
->connection
&& r
->connection
->user
) {
345 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
349 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
);
352 /* see if we should just go ahead and ignore this call, since we already should be set to these
358 pthread_rwlock_rdlock( sharedlock
);
360 rw_rdlock( sharedlock
);
363 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
365 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
367 if ( ( !strcmp( k5user
,
368 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
369 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
371 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
377 /* copy the token out of the cache and into the child object */
379 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
380 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
381 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
382 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
384 /* set our last used time thing */
385 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
395 /* release the lock on the token cache */
397 pthread_rwlock_unlock( sharedlock
);
399 rw_unlock( sharedlock
);
403 /* release the lock on the token cache */
404 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
405 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
409 /* if this is something that was in the cache, and it's the same as the token we already have stored,
410 and we weren't calling this just to renew it... */
412 if ( usecached
&& indentical
) {
413 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
419 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
422 /* clear out the creds structure */
423 memset((void *) &v5creds
, 0, sizeof(v5creds
));
425 /* create a principal out of our k5user string */
427 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
428 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) afs_error_message(kerror
) );
432 /* create the credentials options */
434 krb5_get_init_creds_opt_init ( &kopts
);
435 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
436 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
437 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
438 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
440 if ( keytab
|| k5secret
) {
443 /* if we've been passed a keytab, we're going to be getting our credentials from it */
445 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
447 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
448 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
449 "mod_waklog: krb5_kt_resolve %s", afs_error_message(kerror
) );
453 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
454 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
455 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
456 afs_error_message(kerror
) );
459 } else if (k5secret
) {
461 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
463 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
464 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
465 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
466 afs_error_message(kerror
) );
467 /* nuke the password so it doesn't end up in core files */
468 memset(k5secret
, 0, strlen(k5secret
));
472 memset(k5secret
, 0, strlen(k5secret
));
475 /* initialize the credentials cache and store the stuff we just got */
476 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
477 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
478 afs_error_message(kerror
));
482 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
483 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
484 afs_error_message(kerror
));
488 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
491 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", afs_error_message(kerror
));
495 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
498 /* If we've got a path to a credentials cache, then try and use that. We can't just
499 * replace child.creds, because we want to ensure that only this request gets access to
502 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
503 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
504 "mod_waklog: can't open provided credentials cache %s err=%d",
509 use_client_credentials
= 1;
512 /* now, to the 'aklog' portion of our program. */
514 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
515 for(attempt
= 0; attempt
<= 1; attempt
++) {
516 strncpy( buf
, "afs", sizeof(buf
) - 1 );
517 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
519 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
520 if (cell_in_principal
) {
521 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
522 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
524 if (cfg
->afs_cell_realm
!= NULL
) {
525 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
526 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
529 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
531 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
532 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", afs_error_message(kerror
));
536 if (!use_client_credentials
) {
537 clientccache
= child
.ccache
;
540 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
541 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", afs_error_message(kerror
), clientccache
);
545 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
547 increds
.times
.endtime
= 0;
549 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
550 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
552 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
553 afs_error_message(kerror
));
559 cfg
->cell_in_principal
= cell_in_principal
;
563 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
565 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
566 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
567 v5credsp
->ticket
.length
);
571 memset(&token
, 0, sizeof(struct ktc_token
));
573 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
574 token
.endTime
= v5credsp
->times
.endtime
;
576 if (tkt_DeriveDesKey(v5credsp
->keyblock
.enctype
, v5credsp
->keyblock
.contents
,
577 v5credsp
->keyblock
.length
, &token
.sessionKey
) != 0) {
578 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: tkt_DeriveDesKey failure (enctype: %d)",
579 v5credsp
->keyblock
.enctype
);
582 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
583 token
.ticketLen
= v5credsp
->ticket
.length
;
584 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
588 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
590 buf
[v5credsp
->client
->data
[0].length
] = '\0';
591 if ( v5credsp
->client
->length
> 1 ) {
592 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
593 buflen
= strlen(buf
);
594 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
595 min(v5credsp
->client
->data
[1].length
,
596 MAXKTCNAMELEN
- strlen(buf
) - 1));
597 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
600 /* assemble the client */
601 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
602 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
603 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
605 buf
[v5credsp
->client
->realm
.length
] = '\0';
606 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
608 /* assemble the server's cell */
609 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
611 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
613 /* fill out the AFS ID in the client name */
614 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
615 * strange things seem to happen. */
618 afs_int32 viceId
= 0;
620 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
622 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
623 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
625 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
628 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
632 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
633 server
.name
, server
.instance
, server
.cell
);
635 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
636 client
.name
, client
.instance
, client
.cell
);
638 /* copy the resulting stuff into the child structure */
640 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
641 memcpy(&child
.token
, &token
, sizeof(child
.token
));
642 memcpy(&child
.server
, &server
, sizeof(child
.server
));
643 memcpy(&child
.client
, &client
, sizeof(child
.client
));
645 /* stuff the resulting token-related stuff into our shared token cache */
646 /* note, that anything that was set from a keytab is "persistant", and is immune
647 * from LRU-aging. This is because nothing but the process that's running as root
648 * can update these, and it's running every hour or so and renewing these tokens.
649 * and we don't want them aged out.
652 mytime
= oldest_time
= time(0);
654 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
657 pthread_rwlock_wrlock(sharedlock
);
659 rw_wrlock(sharedlock
);
662 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
663 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
664 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
666 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
668 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
669 child
.clientprincipal
) ) {
670 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
671 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
672 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
673 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
674 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
680 if ( stored
== -1 ) {
681 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
682 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
683 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
684 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
685 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
686 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
691 pthread_rwlock_unlock(sharedlock
);
693 rw_unlock(sharedlock
);
696 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
697 child
.clientprincipal
);
699 } else if ( ! usecached
) {
700 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
709 /* don't ask. Something about AIX. We're leaving it here.*/
710 /* write(2, "", 0); */
712 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
714 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
715 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
716 afs_error_message(rc
), k5user
);
717 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
718 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
719 afs_error_message(rc
), k5user
);
725 if (use_client_credentials
)
726 krb5_cc_close(child
.kcontext
, clientccache
);
728 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
729 if ( increds
.client
)
730 krb5_free_principal (child
.kcontext
, increds
.client
);
731 if ( increds
.server
)
732 krb5_free_principal (child
.kcontext
, increds
.server
);
734 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
736 krb5_free_principal (child
.kcontext
, kprinc
);
739 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
740 } else if ( kerror
) {
741 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, afs_error_message(kerror
));
743 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
746 return kerror
? (int) kerror
: (int) rc
;
751 int get_cfg_usertokens(waklog_config
*cfg
)
753 if (cfg
->usertokens
==WAKLOG_UNSET
)
754 return 0; /* default */
755 return cfg
->usertokens
;
758 int get_cfg_protect(waklog_config
*cfg
)
760 if (cfg
->protect
==WAKLOG_UNSET
)
761 return 0; /* default */
765 int get_cfg_disable_token_cache(waklog_config
*cfg
)
767 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
768 return 0; /* default */
769 return cfg
->disable_token_cache
;
774 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
778 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
780 memset(cfg
, 0, sizeof(waklog_config
));
781 cfg
->path
= "(server)";
782 cfg
->protect
= WAKLOG_UNSET
;
783 cfg
->usertokens
= WAKLOG_UNSET
;
784 cfg
->disable_token_cache
= WAKLOG_UNSET
;
786 cfg
->principal
= NULL
;
787 cfg
->default_principal
= NULL
;
788 cfg
->default_keytab
= NULL
;
789 cfg
->afs_cell
= NULL
;
790 cfg
->afs_cell_realm
= NULL
;
794 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
795 "mod_waklog: server config created.");
800 /* initialize with host-config information */
803 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
807 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
808 memset(cfg
, 0, sizeof(waklog_config
));
810 cfg
->path
= ap_pstrdup(p
, dir
);
811 cfg
->protect
= WAKLOG_UNSET
;
812 cfg
->usertokens
= WAKLOG_UNSET
;
813 cfg
->disable_token_cache
= WAKLOG_UNSET
;
815 cfg
->principal
= NULL
;
816 cfg
->default_principal
= NULL
;
817 cfg
->default_keytab
= NULL
;
818 cfg
->afs_cell
= NULL
;
819 cfg
->afs_cell_realm
= NULL
;
826 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
828 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
829 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
830 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
832 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
834 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
836 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
838 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
840 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
842 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
844 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
846 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
848 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
850 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
852 return (void *) merged
;
856 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
858 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
859 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
860 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
862 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
864 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
866 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
868 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
869 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
871 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
872 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
874 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
875 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
877 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
878 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
880 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
881 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
883 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
884 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
887 return (void *) merged
;
892 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
894 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
895 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
899 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
900 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
905 /* this adds a principal/keytab pair to get their tokens renewed by the
906 child process every few centons. */
908 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
912 if ( renewcount
>= SHARED_TABLE_SIZE
) {
913 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
914 decrease your tokens.");
918 /* check to see if it's already there */
920 for ( i
= 0; i
< renewcount
; i
++ ) {
921 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
926 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
927 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
928 renewtable
[renewcount
].lastrenewed
= 0;
934 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
936 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
937 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
939 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
940 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
942 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
943 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
945 add_to_renewtable(params
->pool
, keytab
, principal
);
953 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
955 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
956 waklog_config
*waklog_srvconfig
=
957 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
959 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
960 "mod_waklog: will use afs_cell: %s", file
);
962 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
963 waklog_srvconfig
->cell_in_principal
= 1;
965 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
966 waklog_srvconfig
->configured
= 1;
968 if (waklog_mconfig
!= NULL
) {
969 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
970 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
971 waklog_mconfig
->configured
= 1;
977 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
979 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
980 waklog_config
*waklog_srvconfig
=
981 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
983 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
984 "mod_waklog: will use afs_cell_realm: %s", file
);
986 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
988 if (waklog_mconfig
!= NULL
) {
989 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
995 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
997 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
998 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1000 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1002 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1003 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
1005 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1006 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1008 /* this also gets set at the server level */
1009 if ( mconfig
&& ( ! cfg
->path
) ) {
1010 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1011 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1013 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
1014 return "Unable to set DefaultPrincipal outside of top level config!";
1017 add_to_renewtable( params
->pool
, keytab
, principal
);
1019 cfg
->configured
= 1;
1025 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1027 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1028 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1030 cfg
->usertokens
= flag
;
1032 cfg
->configured
= 1;
1034 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1035 "mod_waklog: waklog_use_user_tokens set");
1041 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1043 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1044 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1046 cfg
->disable_token_cache
= flag
;
1048 cfg
->configured
= 1;
1050 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1051 "mod_waklog: waklog_disable_token_cache set");
1057 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1059 apr_status_t
waklog_child_exit( void *sr
) {
1061 server_rec
*s
= (server_rec
*) sr
;
1064 if ( child
.ccache
) {
1065 krb5_cc_close(child
.kcontext
, child
.ccache
);
1068 if ( child
.kcontext
) {
1069 krb5_free_context(child
.kcontext
);
1072 /* forget our tokens */
1074 ktc_ForgetAllTokens ();
1076 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1077 "mod_waklog: waklog_child_exit complete");
1087 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1089 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1093 krb5_error_code code
;
1098 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1100 if ( !sharedspace
) {
1101 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1105 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1107 memset (&child
, 0, sizeof(child
));
1109 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1110 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1113 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1114 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1117 if ( pag_for_children
) {
1121 getModConfig (cfg
, s
);
1123 if ( cfg
->default_principal
!= NULL
) {
1124 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1125 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1128 cell
= strdup(cfg
->afs_cell
);
1129 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1132 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1135 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1136 "mod_waklog: child_init returned");
1141 command_rec waklog_cmds
[] = {
1143 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1144 "Use the supplied AFS cell (required)"),
1146 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1147 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1149 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1150 "enable waklog on a server, location, or directory basis"),
1152 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1153 "Set the default principal that the server runs as"),
1155 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1156 "Set the principal on a <Location>-specific basis"),
1158 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1159 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1161 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1162 "Use the requesting user tokens (from webauth)"),
1168 /* not currently using this */
1171 token_cleanup (void *data
)
1173 request_rec
*r
= (request_rec
*) data
;
1175 if (child
.token
.ticketLen
)
1177 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1179 ktc_ForgetAllTokens ();
1181 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1182 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1188 /* This function doesn't return anything but is passed to ap_bspawn_child on
1189 * Apache 1 which expects it to return a pid as an int. For want of better
1190 * understanding, err on the side of not changing Apache 1 code while fixing
1191 * the compile warning on Apache 2. */
1197 waklog_child_routine (void *data
, child_info
* pinfo
)
1200 server_rec
*s
= (server_rec
*) data
;
1201 krb5_error_code code
;
1203 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1208 getModConfig( cfg
, s
);
1210 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1212 memset (&child
, 0, sizeof(child
));
1214 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1215 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1218 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1219 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1222 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1224 /* need to do this so we can make PTS calls */
1225 cell
= strdup(cfg
->afs_cell
); /* stupid */
1226 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1228 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1232 for ( i
= 0; i
< renewcount
; ++i
) {
1233 renewtable
[i
].lastrenewed
= time(0);
1234 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1235 renewtable
[i
].keytab
);
1237 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1239 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1240 things that it needs to read */
1242 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1243 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1244 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1249 sharedspace
->renewcount
++;
1258 left
-= ( time(0) - when
);
1269 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1270 apr_pool_t
* ptemp
, server_rec
* s
)
1273 extern char *version
;
1278 int use_existing
= 1;
1280 char cache_file
[MAXNAMELEN
];
1282 pthread_rwlockattr_t rwlock_attr
;
1286 getModConfig (cfg
, s
);
1288 /* initialize_module() will be called twice, and if it's a DSO
1289 * then all static data from the first call will be lost. Only
1290 * set up our static data on the second call.
1291 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1292 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1295 if (cfg
->afs_cell
==NULL
) {
1296 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1297 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1298 /** clobber apache */
1304 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1305 apr_pool_cleanup_null
, s
->process
->pool
);
1309 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1310 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1312 if ( sharedspace
) {
1313 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1316 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1318 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1320 if ( errno
== ENOENT
) {
1322 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1324 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1325 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1329 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1333 if ( use_existing
== 0 ) {
1334 struct sharedspace_s bob
;
1335 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1336 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1337 if ( write(fd
, &bob
, sizeof(struct sharedspace_s
)) != sizeof(struct sharedspace_s
) ) {
1338 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: failed to write to our cache file %s (%d)", cache_file
, errno
);
1341 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1344 /* mmap the region */
1346 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1348 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1349 err
= unlink(cache_file
);
1351 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1353 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1356 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1362 #define locktype pthread_rwlock_t
1364 #define locktype rwlock_t
1367 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) != NULL
) {
1368 #ifndef use_pthreads
1369 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1371 pthread_rwlockattr_init(&rwlock_attr
);
1372 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1373 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1376 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1381 /* set our default tokens */
1383 oldrenewcount
= sharedspace
->renewcount
;
1385 pag_for_children
= 0;
1387 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1389 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1391 if (rv
== APR_INCHILD
)
1393 waklog_child_routine (s
, NULL
);
1397 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1399 /* parent and child */
1400 cfg
->forked
= proc
->pid
;
1401 pag_for_children
= 1;
1403 if ( use_existing
== 0 ) {
1404 /* wait here until our child process has gone and done it's renewing thing. */
1405 while( sharedspace
->renewcount
== oldrenewcount
) {
1406 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1411 if ( cfg
->default_principal
) {
1412 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1419 waklog_init (server_rec
* s
, MK_POOL
* p
)
1421 extern char *version
;
1425 int use_existing
= 1;
1427 char cache_file
[MAXNAMELEN
];
1429 pthread_rwlockattr_t rwlock_attr
;
1432 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1433 "mod_waklog: version %s initialized.", version
);
1435 if ( sharedspace
) {
1436 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1439 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1441 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1443 if ( errno
== ENOENT
) {
1445 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1447 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1448 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1452 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1457 if ( use_existing
== 0 ) {
1458 struct sharedspace_s bob
;
1459 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1460 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1461 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1462 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1465 /* mmap the region */
1467 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1468 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1471 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1477 #define locktype pthread_rwlock_t
1479 #define locktype rwlock_t
1482 /* mmap our shared space for our lock */
1483 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1484 #ifndef use_pthreads
1485 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1487 pthread_rwlockattr_init(&rwlock_attr
);
1488 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1489 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1492 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1497 /* set our default tokens */
1499 getModConfig (cfg
, s
);
1501 oldrenewcount
= sharedspace
->renewcount
;
1503 pag_for_children
= 0;
1505 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1508 pag_for_children
= 1;
1510 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1511 "mod_waklog: ap_bspawn_child: %d.", pid
);
1513 if ( use_existing
== 0 ) {
1514 /* wait here until our child process has gone and done it's renewing thing. */
1515 while( sharedspace
->renewcount
== oldrenewcount
) {
1516 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1521 if ( cfg
->default_principal
) {
1522 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1529 waklog_phase0 (request_rec
* r
)
1533 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1534 "mod_waklog: phase0 called");
1536 cfg
= retrieve_config(r
);
1538 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1539 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1540 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1541 } else if ( cfg
->default_principal
) {
1542 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1543 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1546 if (child
.token
.ticketLen
) {
1547 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1548 ktc_ForgetAllTokens();
1551 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1558 waklog_phase1 (request_rec
* r
)
1562 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1563 "mod_waklog: phase1 called");
1565 cfg
= retrieve_config(r
);
1567 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1568 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1569 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1570 } else if ( cfg
->default_principal
) {
1571 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1572 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1574 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1581 waklog_phase3 (request_rec
* r
)
1585 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1586 "mod_waklog: phase 3 called");
1588 cfg
= retrieve_config(r
);
1590 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1591 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1592 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1593 } else if ( cfg
->default_principal
) {
1594 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1595 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1597 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1604 waklog_phase6 (request_rec
* r
)
1608 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1609 "mod_waklog: phase6 called");
1611 cfg
= retrieve_config(r
);
1613 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1614 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1615 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1616 } else if ( cfg
->default_principal
) {
1617 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1618 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1620 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1627 waklog_phase7 (request_rec
* r
)
1632 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1633 "mod_waklog: phase7 called");
1635 cfg
= retrieve_config (r
);
1637 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1638 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1639 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1640 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1641 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1642 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1643 } else if ( cfg
->default_principal
) {
1644 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1645 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1647 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1648 if (child
.token
.ticketLen
) {
1649 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1650 ktc_ForgetAllTokens();
1662 waklog_phase9 (request_rec
* r
)
1666 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1667 "mod_waklog: phase9 called");
1669 getModConfig (cfg
, r
->server
);
1671 if ( cfg
->default_principal
) {
1672 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1673 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1686 waklog_new_connection (conn_rec
* c
1695 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1696 "mod_waklog: new_connection called: pid: %d", getpid ());
1698 getModConfig(cfg
, c
->base_server
);
1700 if ( cfg
->default_principal
) {
1701 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1702 cfg
->default_principal
);
1703 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1716 ** Here's a quick explaination for phase0 and phase2:
1717 ** Apache does a stat() on the path between phase0 and
1718 ** phase2, and must by ACLed rl to succeed. So, at
1719 ** phase0 we acquire credentials for umweb:servers from
1720 ** a keytab, and at phase2 we must ensure we remove them.
1722 ** Failure to "unlog" would be a security risk.
1725 waklog_phase2 (request_rec
* r
)
1728 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1729 "mod_waklog: phase2 called");
1731 if (child
.token
.ticketLen
)
1733 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1735 ktc_ForgetAllTokens ();
1737 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1738 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1742 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1743 "mod_waklog: phase2 returning");
1749 module MODULE_VAR_EXPORT waklog_module
= {
1750 STANDARD_MODULE_STUFF
,
1751 waklog_init
, /* module initializer */
1752 waklog_create_dir_config
, /* create per-dir config structures */
1753 waklog_merge_dir_config
, /* merge per-dir config structures */
1754 waklog_create_server_config
, /* create per-server config structures */
1755 waklog_merge_dir_config
, /* merge per-server config structures */
1756 waklog_cmds
, /* table of config file commands */
1757 NULL
, /* [#8] MIME-typed-dispatched handlers */
1758 waklog_phase1
, /* [#1] URI to filename translation */
1759 NULL
, /* [#4] validate user id from request */
1760 NULL
, /* [#5] check if the user is ok _here_ */
1761 waklog_phase3
, /* [#3] check access by host address */
1762 waklog_phase6
, /* [#6] determine MIME type */
1763 waklog_phase7
, /* [#7] pre-run fixups */
1764 waklog_phase9
, /* [#9] log a transaction */
1765 waklog_phase2
, /* [#2] header parser */
1766 waklog_child_init
, /* child_init */
1767 waklog_child_exit
, /* child_exit */
1768 waklog_phase0
/* [#0] post read-request */
1770 , NULL
, /* EAPI: add_module */
1771 NULL
, /* EAPI: remove_module */
1772 NULL
, /* EAPI: rewrite_command */
1773 waklog_new_connection
/* EAPI: new_connection */
1778 waklog_register_hooks (apr_pool_t
* p
)
1780 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1781 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1782 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1783 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1784 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1785 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1786 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1787 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1788 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1789 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1793 module AP_MODULE_DECLARE_DATA waklog_module
= {
1794 STANDARD20_MODULE_STUFF
,
1795 waklog_create_dir_config
, /* create per-dir conf structures */
1796 waklog_merge_dir_config
, /* merge per-dir conf structures */
1797 waklog_create_server_config
, /* create per-server conf structures */
1798 waklog_merge_dir_config
, /* merge per-server conf structures */
1799 waklog_cmds
, /* table of configuration directives */
1800 waklog_register_hooks
/* register hooks */