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
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 /**************************************************************************************************/
76 #include <afs/param.h>
78 #include <afs/venus.h>
80 #include <afs/dirpath.h>
81 #include <afs/ptuser.h>
84 #define TKT_LIFE ( 12 * 60 * 60 )
85 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
87 #define WAKLOG_UNSET -1
91 #define APLOG_DEBUG APLOG_ERR
94 /* this is used to turn off pag generation for the backround worker child during startup */
95 int pag_for_children
= 1;
103 int cell_in_principal
;
104 int disable_token_cache
;
107 char *default_principal
;
108 char *default_keytab
;
110 char *afs_cell_realm
;
118 struct ktc_token token
;
119 char clientprincipal
[MAXNAMELEN
];
120 krb5_context kcontext
;
122 struct ktc_principal server
;
123 struct ktc_principal client
;
125 } waklog_child_config
;
127 waklog_child_config child
;
129 struct tokencache_ent
{
130 char clientprincipal
[MAXNAMELEN
];
131 struct ktc_token token
;
132 struct ktc_principal client
;
133 struct ktc_principal server
;
138 #define SHARED_TABLE_SIZE 512
140 struct sharedspace_s
{
142 struct tokencache_ent sharedtokens
[SHARED_TABLE_SIZE
];
145 struct sharedspace_s
*sharedspace
= NULL
;
154 pthread_rwlock_t
*sharedlock
= NULL
;
156 rwlock_t
*sharedlock
= NULL
;
159 struct renew_ent renewtable
[SHARED_TABLE_SIZE
];
165 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
169 log_error (const char *file
, int line
, int level
, int status
,
170 const server_rec
* s
, const char *fmt
, ...)
176 vsnprintf (errstr
, 1024, fmt
, ap
);
180 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
182 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
187 waklog_config
*retrieve_config(request_rec
*r
) {
192 if ( r
&& r
->main
) {
200 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
203 getModConfig (cfg
, r
->server
);
210 /* set_auth -- sets the tokens of the current process to this user.
211 if "self" is set, it divines the user from the current requests' environment.
212 otherwise, it's gettng it from principal/keytab */
215 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
219 krb5_error_code kerror
= 0;
220 krb5_principal kprinc
= NULL
;
221 krb5_get_init_creds_opt kopts
;
224 krb5_ccache clientccache
;
225 struct ktc_principal server
= { "afs", "", "" };
226 struct ktc_principal client
;
227 struct ktc_token token
;
228 krb5_creds
*v5credsp
= NULL
;
229 krb5_keytab krb5kt
= NULL
;
230 char buf
[MAXNAMELEN
];
234 time_t oldest_time
= 0;
239 int cell_in_principal
;
241 int use_client_credentials
= 0;
243 char k5user
[MAXNAMELEN
] = "";
244 char *k5secret
= NULL
;
248 memset((char *) &increds
, 0, sizeof(increds
));
249 /* init some stuff if it ain't already */
250 /* XXX - In what situation will these not be initialized? */
252 if ( ! child
.kcontext
) {
253 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
254 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
260 if ( !child
.ccache
) {
261 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
262 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
268 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
269 self
, principal
? principal
: "NULL",
270 keytab
? keytab
: "NULL",
272 k5path
? k5path
: "NULL",
274 (r
&& r
->user
) ? r
->user
: "NULL"
276 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
280 /* pull the server config record that we care about... */
283 cfg
= retrieve_config(r
);
285 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
286 "mod_waklog: set_auth using no config" );
287 getModConfig (cfg
, s
);
291 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
296 /* pull out our principal name and stuff from the environment -- webauth better have sent
300 if ( ! ( r
&& r
->connection
&& r
->user
)) {
301 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
302 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
));
306 strncpy(k5user
, r
->user
, sizeof(k5user
));
308 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
309 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
313 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
315 /* if they've supplied a credentials cache */
316 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
318 /* the other thing we need is someone's password */
319 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
321 /* we'll pick this up later after we've checked the cache and current state */
325 strncpy(k5user
, principal
, sizeof(k5user
));
329 strncpy(k5user
, r
->user
, sizeof(k5user
));
332 if (r
&& r
->connection
&& r
->connection
->user
) {
333 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
337 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
);
340 /* see if we should just go ahead and ignore this call, since we already should be set to these
346 pthread_rwlock_rdlock( sharedlock
);
348 rw_rdlock( sharedlock
);
351 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
353 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
355 if ( ( !strcmp( k5user
,
356 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
357 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
359 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
365 /* copy the token out of the cache and into the child object */
367 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
368 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
369 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
370 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
372 /* set our last used time thing */
373 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
383 /* release the lock on the token cache */
385 pthread_rwlock_unlock( sharedlock
);
387 rw_unlock( sharedlock
);
391 /* release the lock on the token cache */
392 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
393 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
397 /* if this is something that was in the cache, and it's the same as the token we already have stored,
398 and we weren't calling this just to renew it... */
400 if ( usecached
&& indentical
) {
401 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
407 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
410 /* clear out the creds structure */
411 memset((void *) &v5creds
, 0, sizeof(v5creds
));
413 /* create a principal out of our k5user string */
415 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
416 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) afs_error_message(kerror
) );
420 /* create the credentials options */
422 krb5_get_init_creds_opt_init ( &kopts
);
423 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
424 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
425 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
426 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
428 if ( keytab
|| k5secret
) {
431 /* if we've been passed a keytab, we're going to be getting our credentials from it */
433 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
435 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
436 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
437 "mod_waklog: krb5_kt_resolve %s", afs_error_message(kerror
) );
441 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
442 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
443 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
444 afs_error_message(kerror
) );
447 } else if (k5secret
) {
449 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
451 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
452 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
453 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
454 afs_error_message(kerror
) );
455 /* nuke the password so it doesn't end up in core files */
456 memset(k5secret
, 0, sizeof(k5secret
));
460 memset(k5secret
, 0, sizeof(k5secret
));
463 /* initialize the credentials cache and store the stuff we just got */
464 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
465 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
466 afs_error_message(kerror
));
470 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
471 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
472 afs_error_message(kerror
));
476 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
479 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", afs_error_message(kerror
));
483 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
486 /* If we've got a path to a credentials cache, then try and use that. We can't just
487 * replace child.creds, because we want to ensure that only this request gets access to
490 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
491 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
492 "mod_waklog: can't open provided credentials cache %s err=%d",
497 use_client_credentials
= 1;
500 /* now, to the 'aklog' portion of our program. */
502 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
503 for(attempt
= 0; attempt
<= 1; attempt
++) {
504 strncpy( buf
, "afs", sizeof(buf
) - 1 );
505 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
507 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
508 if (cell_in_principal
) {
509 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
510 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
512 if (cfg
->afs_cell_realm
!= NULL
) {
513 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
514 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
517 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
519 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
520 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", afs_error_message(kerror
));
524 if (!use_client_credentials
) {
525 clientccache
= child
.ccache
;
528 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
529 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", afs_error_message(kerror
), clientccache
);
533 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
535 increds
.times
.endtime
= 0;
537 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
538 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
540 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
541 afs_error_message(kerror
));
547 cfg
->cell_in_principal
= cell_in_principal
;
551 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
553 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
554 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
555 v5credsp
->ticket
.length
);
559 memset(&token
, 0, sizeof(struct ktc_token
));
561 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
562 token
.endTime
= v5credsp
->times
.endtime
;
564 if (tkt_DeriveDesKey(v5credsp
->keyblock
.enctype
, v5credsp
->keyblock
.contents
,
565 v5credsp
->keyblock
.length
, &token
.sessionKey
) != 0) {
566 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: tkt_DeriveDesKey failure (enctype: %d)",
567 v5credsp
->keyblock
.enctype
);
570 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
571 token
.ticketLen
= v5credsp
->ticket
.length
;
572 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
576 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
578 buf
[v5credsp
->client
->data
[0].length
] = '\0';
579 if ( v5credsp
->client
->length
> 1 ) {
580 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
581 buflen
= strlen(buf
);
582 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
583 min(v5credsp
->client
->data
[1].length
,
584 MAXKTCNAMELEN
- strlen(buf
) - 1));
585 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
588 /* assemble the client */
589 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
590 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
591 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
593 buf
[v5credsp
->client
->realm
.length
] = '\0';
594 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
596 /* assemble the server's cell */
597 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
599 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
601 /* fill out the AFS ID in the client name */
602 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
603 * strange things seem to happen. */
606 afs_int32 viceId
= 0;
608 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
610 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
611 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
613 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
616 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
620 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
621 server
.name
, server
.instance
, server
.cell
);
623 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
624 client
.name
, client
.instance
, client
.cell
);
626 /* copy the resulting stuff into the child structure */
628 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
629 memcpy(&child
.token
, &token
, sizeof(child
.token
));
630 memcpy(&child
.server
, &server
, sizeof(child
.server
));
631 memcpy(&child
.client
, &client
, sizeof(child
.client
));
633 /* stuff the resulting token-related stuff into our shared token cache */
634 /* note, that anything that was set from a keytab is "persistant", and is immune
635 * from LRU-aging. This is because nothing but the process that's running as root
636 * can update these, and it's running every hour or so and renewing these tokens.
637 * and we don't want them aged out.
640 mytime
= oldest_time
= time(0);
642 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
645 pthread_rwlock_wrlock(sharedlock
);
647 rw_wrlock(sharedlock
);
650 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
651 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
652 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
654 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
656 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
657 child
.clientprincipal
) ) {
658 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
659 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
660 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
661 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
662 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
668 if ( stored
== -1 ) {
669 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
670 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
671 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
672 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
673 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
674 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
679 pthread_rwlock_unlock(sharedlock
);
681 rw_unlock(sharedlock
);
684 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
685 child
.clientprincipal
);
687 } else if ( ! usecached
) {
688 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
697 /* don't ask. Something about AIX. We're leaving it here.*/
698 /* write(2, "", 0); */
700 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
702 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
703 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
704 afs_error_message(rc
), k5user
);
705 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
706 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
707 afs_error_message(rc
), k5user
);
713 if (use_client_credentials
)
714 krb5_cc_close(child
.kcontext
, clientccache
);
716 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
717 if ( increds
.client
)
718 krb5_free_principal (child
.kcontext
, increds
.client
);
719 if ( increds
.server
)
720 krb5_free_principal (child
.kcontext
, increds
.server
);
722 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
724 krb5_free_principal (child
.kcontext
, kprinc
);
727 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
728 } else if ( kerror
) {
729 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, afs_error_message(kerror
));
731 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
734 return kerror
? (int) kerror
: (int) rc
;
739 int get_cfg_usertokens(waklog_config
*cfg
)
741 if (cfg
->usertokens
==WAKLOG_UNSET
)
742 return 0; /* default */
743 return cfg
->usertokens
;
746 int get_cfg_protect(waklog_config
*cfg
)
748 if (cfg
->protect
==WAKLOG_UNSET
)
749 return 0; /* default */
753 int get_cfg_disable_token_cache(waklog_config
*cfg
)
755 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
756 return 0; /* default */
757 return cfg
->disable_token_cache
;
762 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
766 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
768 memset(cfg
, 0, sizeof(waklog_config
));
769 cfg
->path
= "(server)";
770 cfg
->protect
= WAKLOG_UNSET
;
771 cfg
->usertokens
= WAKLOG_UNSET
;
772 cfg
->disable_token_cache
= WAKLOG_UNSET
;
774 cfg
->principal
= NULL
;
775 cfg
->default_principal
= NULL
;
776 cfg
->default_keytab
= NULL
;
777 cfg
->afs_cell
= NULL
;
778 cfg
->afs_cell_realm
= NULL
;
782 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
783 "mod_waklog: server config created.");
788 /* initialize with host-config information */
791 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
795 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
796 memset(cfg
, 0, sizeof(waklog_config
));
798 cfg
->path
= ap_pstrdup(p
, dir
);
799 cfg
->protect
= WAKLOG_UNSET
;
800 cfg
->usertokens
= WAKLOG_UNSET
;
801 cfg
->disable_token_cache
= WAKLOG_UNSET
;
803 cfg
->principal
= NULL
;
804 cfg
->default_principal
= NULL
;
805 cfg
->default_keytab
= NULL
;
806 cfg
->afs_cell
= NULL
;
807 cfg
->afs_cell_realm
= NULL
;
814 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
816 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
817 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
818 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
820 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
822 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
824 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
826 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
828 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
830 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
832 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
834 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
836 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
838 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
840 return (void *) merged
;
844 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
846 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
847 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
848 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
850 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
852 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
854 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
856 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
857 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
859 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
860 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
862 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
863 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
865 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
866 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
868 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
869 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
871 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
872 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
875 return (void *) merged
;
880 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
882 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
883 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
887 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
888 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
893 /* this adds a principal/keytab pair to get their tokens renewed by the
894 child process every few centons. */
896 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
900 if ( renewcount
>= SHARED_TABLE_SIZE
) {
901 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
902 decrease your tokens.");
906 /* check to see if it's already there */
908 for ( i
= 0; i
< renewcount
; i
++ ) {
909 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
914 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
915 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
916 renewtable
[renewcount
].lastrenewed
= 0;
922 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
924 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
925 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
927 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
928 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
930 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
931 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
933 add_to_renewtable(params
->pool
, keytab
, principal
);
941 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
943 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
944 waklog_config
*waklog_srvconfig
=
945 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
947 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
948 "mod_waklog: will use afs_cell: %s", file
);
950 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
951 waklog_srvconfig
->cell_in_principal
= 1;
953 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
954 waklog_srvconfig
->configured
= 1;
956 if (waklog_mconfig
!= NULL
) {
957 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
958 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
959 waklog_mconfig
->configured
= 1;
965 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
967 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
968 waklog_config
*waklog_srvconfig
=
969 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
971 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
972 "mod_waklog: will use afs_cell_realm: %s", file
);
974 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
976 if (waklog_mconfig
!= NULL
) {
977 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
983 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
985 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
986 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
988 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
990 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
991 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
993 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
994 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
996 /* this also gets set at the server level */
997 if ( mconfig
&& ( ! cfg
->path
) ) {
998 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
999 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1001 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
1002 return "Unable to set DefaultPrincipal outside of top level config!";
1005 add_to_renewtable( params
->pool
, keytab
, principal
);
1007 cfg
->configured
= 1;
1013 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1015 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1016 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1018 cfg
->usertokens
= flag
;
1020 cfg
->configured
= 1;
1022 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1023 "mod_waklog: waklog_use_user_tokens set");
1029 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1031 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1032 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1034 cfg
->disable_token_cache
= flag
;
1036 cfg
->configured
= 1;
1038 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1039 "mod_waklog: waklog_disable_token_cache set");
1045 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1047 apr_status_t
waklog_child_exit( void *sr
) {
1049 server_rec
*s
= (server_rec
*) sr
;
1052 if ( child
.ccache
) {
1053 krb5_cc_close(child
.kcontext
, child
.ccache
);
1056 if ( child
.kcontext
) {
1057 krb5_free_context(child
.kcontext
);
1060 /* forget our tokens */
1062 ktc_ForgetAllTokens ();
1064 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1065 "mod_waklog: waklog_child_exit complete");
1075 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1077 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1081 krb5_error_code code
;
1086 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1088 if ( !sharedspace
) {
1089 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1093 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1095 memset (&child
, 0, sizeof(child
));
1097 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1098 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1101 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1102 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1105 if ( pag_for_children
) {
1109 getModConfig (cfg
, s
);
1111 if ( cfg
->default_principal
!= NULL
) {
1112 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1113 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1116 cell
= strdup(cfg
->afs_cell
);
1117 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1120 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1123 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1124 "mod_waklog: child_init returned");
1129 command_rec waklog_cmds
[] = {
1131 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1132 "Use the supplied AFS cell (required)"),
1134 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1135 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1137 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1138 "enable waklog on a server, location, or directory basis"),
1140 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1141 "Set the default principal that the server runs as"),
1143 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1144 "Set the principal on a <Location>-specific basis"),
1146 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1147 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1149 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1150 "Use the requesting user tokens (from webauth)"),
1156 /* not currently using this */
1159 token_cleanup (void *data
)
1161 request_rec
*r
= (request_rec
*) data
;
1163 if (child
.token
.ticketLen
)
1165 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1167 ktc_ForgetAllTokens ();
1169 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1170 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1176 /* This function doesn't return anything but is passed to ap_bspawn_child on
1177 * Apache 1 which expects it to return a pid as an int. For want of better
1178 * understanding, err on the side of not changing Apache 1 code while fixing
1179 * the compile warning on Apache 2. */
1185 waklog_child_routine (void *data
, child_info
* pinfo
)
1188 server_rec
*s
= (server_rec
*) data
;
1189 krb5_error_code code
;
1191 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1196 getModConfig( cfg
, s
);
1198 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1200 memset (&child
, 0, sizeof(child
));
1202 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1203 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1206 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1207 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1210 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1212 /* need to do this so we can make PTS calls */
1213 cell
= strdup(cfg
->afs_cell
); /* stupid */
1214 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1216 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1220 for ( i
= 0; i
< renewcount
; ++i
) {
1221 renewtable
[i
].lastrenewed
= time(0);
1222 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1223 renewtable
[i
].keytab
);
1225 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1227 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1228 things that it needs to read */
1230 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1231 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1232 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1237 sharedspace
->renewcount
++;
1246 left
-= ( time(0) - when
);
1257 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1258 apr_pool_t
* ptemp
, server_rec
* s
)
1261 extern char *version
;
1266 int use_existing
= 1;
1268 char cache_file
[MAXNAMELEN
];
1270 pthread_rwlockattr_t rwlock_attr
;
1274 getModConfig (cfg
, s
);
1276 /* initialize_module() will be called twice, and if it's a DSO
1277 * then all static data from the first call will be lost. Only
1278 * set up our static data on the second call.
1279 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1280 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1283 if (cfg
->afs_cell
==NULL
) {
1284 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1285 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1286 /** clobber apache */
1292 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1293 apr_pool_cleanup_null
, s
->process
->pool
);
1297 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1298 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1300 if ( sharedspace
) {
1301 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1304 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1306 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1308 if ( errno
== ENOENT
) {
1310 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1312 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1313 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1317 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1321 if ( use_existing
== 0 ) {
1322 struct sharedspace_s bob
;
1323 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1324 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1325 if ( write(fd
, &bob
, sizeof(struct sharedspace_s
)) != sizeof(struct sharedspace_s
) ) {
1326 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: failed to write to our cache file %s (%d)", cache_file
, errno
);
1329 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1332 /* mmap the region */
1334 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1336 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1337 err
= unlink(cache_file
);
1339 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1341 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1344 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1350 #define locktype pthread_rwlock_t
1352 #define locktype rwlock_t
1355 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) != NULL
) {
1356 #ifndef use_pthreads
1357 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1359 pthread_rwlockattr_init(&rwlock_attr
);
1360 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1361 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1364 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1369 /* set our default tokens */
1371 oldrenewcount
= sharedspace
->renewcount
;
1373 pag_for_children
= 0;
1375 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1377 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1379 if (rv
== APR_INCHILD
)
1381 waklog_child_routine (s
, NULL
);
1385 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1387 /* parent and child */
1388 cfg
->forked
= proc
->pid
;
1389 pag_for_children
= 1;
1391 if ( use_existing
== 0 ) {
1392 /* wait here until our child process has gone and done it's renewing thing. */
1393 while( sharedspace
->renewcount
== oldrenewcount
) {
1394 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1399 if ( cfg
->default_principal
) {
1400 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1407 waklog_init (server_rec
* s
, MK_POOL
* p
)
1409 extern char *version
;
1413 int use_existing
= 1;
1415 char cache_file
[MAXNAMELEN
];
1417 pthread_rwlockattr_t rwlock_attr
;
1420 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1421 "mod_waklog: version %s initialized.", version
);
1423 if ( sharedspace
) {
1424 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1427 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1429 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1431 if ( errno
== ENOENT
) {
1433 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1435 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1436 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1440 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1445 if ( use_existing
== 0 ) {
1446 struct sharedspace_s bob
;
1447 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1448 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1449 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1450 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1453 /* mmap the region */
1455 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1456 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1459 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1465 #define locktype pthread_rwlock_t
1467 #define locktype rwlock_t
1470 /* mmap our shared space for our lock */
1471 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1472 #ifndef use_pthreads
1473 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1475 pthread_rwlockattr_init(&rwlock_attr
);
1476 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1477 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1480 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1485 /* set our default tokens */
1487 getModConfig (cfg
, s
);
1489 oldrenewcount
= sharedspace
->renewcount
;
1491 pag_for_children
= 0;
1493 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1496 pag_for_children
= 1;
1498 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1499 "mod_waklog: ap_bspawn_child: %d.", pid
);
1501 if ( use_existing
== 0 ) {
1502 /* wait here until our child process has gone and done it's renewing thing. */
1503 while( sharedspace
->renewcount
== oldrenewcount
) {
1504 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1509 if ( cfg
->default_principal
) {
1510 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1517 waklog_phase0 (request_rec
* r
)
1521 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1522 "mod_waklog: phase0 called");
1524 cfg
= retrieve_config(r
);
1526 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1527 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1528 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1529 } else if ( cfg
->default_principal
) {
1530 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1531 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1534 if (child
.token
.ticketLen
) {
1535 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1536 ktc_ForgetAllTokens();
1539 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1546 waklog_phase1 (request_rec
* r
)
1550 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1551 "mod_waklog: phase1 called");
1553 cfg
= retrieve_config(r
);
1555 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1556 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1557 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1558 } else if ( cfg
->default_principal
) {
1559 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1560 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1562 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1569 waklog_phase3 (request_rec
* r
)
1573 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1574 "mod_waklog: phase 3 called");
1576 cfg
= retrieve_config(r
);
1578 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1579 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1580 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1581 } else if ( cfg
->default_principal
) {
1582 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1583 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1585 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1592 waklog_phase6 (request_rec
* r
)
1596 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1597 "mod_waklog: phase6 called");
1599 cfg
= retrieve_config(r
);
1601 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1602 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1603 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1604 } else if ( cfg
->default_principal
) {
1605 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1606 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1608 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1615 waklog_phase7 (request_rec
* r
)
1620 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1621 "mod_waklog: phase7 called");
1623 cfg
= retrieve_config (r
);
1625 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1626 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1627 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1628 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1629 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1630 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1631 } else if ( cfg
->default_principal
) {
1632 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1633 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1635 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1636 if (child
.token
.ticketLen
) {
1637 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1638 ktc_ForgetAllTokens();
1650 waklog_phase9 (request_rec
* r
)
1654 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1655 "mod_waklog: phase9 called");
1657 getModConfig (cfg
, r
->server
);
1659 if ( cfg
->default_principal
) {
1660 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1661 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1674 waklog_new_connection (conn_rec
* c
1683 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1684 "mod_waklog: new_connection called: pid: %d", getpid ());
1686 getModConfig(cfg
, c
->base_server
);
1688 if ( cfg
->default_principal
) {
1689 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1690 cfg
->default_principal
);
1691 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1704 ** Here's a quick explaination for phase0 and phase2:
1705 ** Apache does a stat() on the path between phase0 and
1706 ** phase2, and must by ACLed rl to succeed. So, at
1707 ** phase0 we acquire credentials for umweb:servers from
1708 ** a keytab, and at phase2 we must ensure we remove them.
1710 ** Failure to "unlog" would be a security risk.
1713 waklog_phase2 (request_rec
* r
)
1716 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1717 "mod_waklog: phase2 called");
1719 if (child
.token
.ticketLen
)
1721 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1723 ktc_ForgetAllTokens ();
1725 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1726 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1730 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1731 "mod_waklog: phase2 returning");
1737 module MODULE_VAR_EXPORT waklog_module
= {
1738 STANDARD_MODULE_STUFF
,
1739 waklog_init
, /* module initializer */
1740 waklog_create_dir_config
, /* create per-dir config structures */
1741 waklog_merge_dir_config
, /* merge per-dir config structures */
1742 waklog_create_server_config
, /* create per-server config structures */
1743 waklog_merge_dir_config
, /* merge per-server config structures */
1744 waklog_cmds
, /* table of config file commands */
1745 NULL
, /* [#8] MIME-typed-dispatched handlers */
1746 waklog_phase1
, /* [#1] URI to filename translation */
1747 NULL
, /* [#4] validate user id from request */
1748 NULL
, /* [#5] check if the user is ok _here_ */
1749 waklog_phase3
, /* [#3] check access by host address */
1750 waklog_phase6
, /* [#6] determine MIME type */
1751 waklog_phase7
, /* [#7] pre-run fixups */
1752 waklog_phase9
, /* [#9] log a transaction */
1753 waklog_phase2
, /* [#2] header parser */
1754 waklog_child_init
, /* child_init */
1755 waklog_child_exit
, /* child_exit */
1756 waklog_phase0
/* [#0] post read-request */
1758 , NULL
, /* EAPI: add_module */
1759 NULL
, /* EAPI: remove_module */
1760 NULL
, /* EAPI: rewrite_command */
1761 waklog_new_connection
/* EAPI: new_connection */
1766 waklog_register_hooks (apr_pool_t
* p
)
1768 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1769 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1770 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1771 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1772 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1773 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1774 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1775 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1776 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1777 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1781 module AP_MODULE_DECLARE_DATA waklog_module
= {
1782 STANDARD20_MODULE_STUFF
,
1783 waklog_create_dir_config
, /* create per-dir conf structures */
1784 waklog_merge_dir_config
, /* merge per-dir conf structures */
1785 waklog_create_server_config
, /* create per-server conf structures */
1786 waklog_merge_dir_config
, /* merge per-server conf structures */
1787 waklog_cmds
, /* table of configuration directives */
1788 waklog_register_hooks
/* register hooks */