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 /* Since we're fetching a key for AFS, we have to use single DES
538 and explicitely enable weak crypto using the secret API
540 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
541 krb5_allow_weak_crypto (child
.kcontext
, 1);
543 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
544 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
546 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
547 afs_error_message(kerror
));
553 cfg
->cell_in_principal
= cell_in_principal
;
557 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
559 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
560 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
561 v5credsp
->ticket
.length
);
565 memset(&token
, 0, sizeof(struct ktc_token
));
567 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
568 token
.endTime
= v5credsp
->times
.endtime
;
570 if (tkt_DeriveDesKey(v5credsp
->keyblock
.enctype
, v5credsp
->keyblock
.contents
,
571 v5credsp
->keyblock
.length
, &token
.sessionKey
) != 0) {
572 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: tkt_DeriveDesKey failure (enctype: %d)",
573 v5credsp
->keyblock
.enctype
);
576 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
577 token
.ticketLen
= v5credsp
->ticket
.length
;
578 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
582 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
584 buf
[v5credsp
->client
->data
[0].length
] = '\0';
585 if ( v5credsp
->client
->length
> 1 ) {
586 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
587 buflen
= strlen(buf
);
588 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
589 min(v5credsp
->client
->data
[1].length
,
590 MAXKTCNAMELEN
- strlen(buf
) - 1));
591 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
594 /* assemble the client */
595 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
596 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
597 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
599 buf
[v5credsp
->client
->realm
.length
] = '\0';
600 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
602 /* assemble the server's cell */
603 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
605 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
607 /* fill out the AFS ID in the client name */
608 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
609 * strange things seem to happen. */
612 afs_int32 viceId
= 0;
614 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
616 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
617 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
619 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
622 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
626 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
627 server
.name
, server
.instance
, server
.cell
);
629 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
630 client
.name
, client
.instance
, client
.cell
);
632 /* copy the resulting stuff into the child structure */
634 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
635 memcpy(&child
.token
, &token
, sizeof(child
.token
));
636 memcpy(&child
.server
, &server
, sizeof(child
.server
));
637 memcpy(&child
.client
, &client
, sizeof(child
.client
));
639 /* stuff the resulting token-related stuff into our shared token cache */
640 /* note, that anything that was set from a keytab is "persistant", and is immune
641 * from LRU-aging. This is because nothing but the process that's running as root
642 * can update these, and it's running every hour or so and renewing these tokens.
643 * and we don't want them aged out.
646 mytime
= oldest_time
= time(0);
648 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
651 pthread_rwlock_wrlock(sharedlock
);
653 rw_wrlock(sharedlock
);
656 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
657 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
658 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
660 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
662 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
663 child
.clientprincipal
) ) {
664 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
665 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
666 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
667 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
668 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
674 if ( stored
== -1 ) {
675 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
676 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
677 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
678 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
679 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
680 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
685 pthread_rwlock_unlock(sharedlock
);
687 rw_unlock(sharedlock
);
690 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
691 child
.clientprincipal
);
693 } else if ( ! usecached
) {
694 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
703 /* don't ask. Something about AIX. We're leaving it here.*/
704 /* write(2, "", 0); */
706 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
708 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
709 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
710 afs_error_message(rc
), k5user
);
711 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
712 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
713 afs_error_message(rc
), k5user
);
719 if (use_client_credentials
)
720 krb5_cc_close(child
.kcontext
, clientccache
);
722 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
723 if ( increds
.client
)
724 krb5_free_principal (child
.kcontext
, increds
.client
);
725 if ( increds
.server
)
726 krb5_free_principal (child
.kcontext
, increds
.server
);
728 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
730 krb5_free_principal (child
.kcontext
, kprinc
);
733 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
734 } else if ( kerror
) {
735 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, afs_error_message(kerror
));
737 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
740 return kerror
? (int) kerror
: (int) rc
;
745 int get_cfg_usertokens(waklog_config
*cfg
)
747 if (cfg
->usertokens
==WAKLOG_UNSET
)
748 return 0; /* default */
749 return cfg
->usertokens
;
752 int get_cfg_protect(waklog_config
*cfg
)
754 if (cfg
->protect
==WAKLOG_UNSET
)
755 return 0; /* default */
759 int get_cfg_disable_token_cache(waklog_config
*cfg
)
761 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
762 return 0; /* default */
763 return cfg
->disable_token_cache
;
768 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
772 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
774 memset(cfg
, 0, sizeof(waklog_config
));
775 cfg
->path
= "(server)";
776 cfg
->protect
= WAKLOG_UNSET
;
777 cfg
->usertokens
= WAKLOG_UNSET
;
778 cfg
->disable_token_cache
= WAKLOG_UNSET
;
780 cfg
->principal
= NULL
;
781 cfg
->default_principal
= NULL
;
782 cfg
->default_keytab
= NULL
;
783 cfg
->afs_cell
= NULL
;
784 cfg
->afs_cell_realm
= NULL
;
788 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
789 "mod_waklog: server config created.");
794 /* initialize with host-config information */
797 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
801 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
802 memset(cfg
, 0, sizeof(waklog_config
));
804 cfg
->path
= ap_pstrdup(p
, dir
);
805 cfg
->protect
= WAKLOG_UNSET
;
806 cfg
->usertokens
= WAKLOG_UNSET
;
807 cfg
->disable_token_cache
= WAKLOG_UNSET
;
809 cfg
->principal
= NULL
;
810 cfg
->default_principal
= NULL
;
811 cfg
->default_keytab
= NULL
;
812 cfg
->afs_cell
= NULL
;
813 cfg
->afs_cell_realm
= NULL
;
820 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
822 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
823 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
824 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
826 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
828 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
830 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
832 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
834 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
836 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
838 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
840 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
842 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
844 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
846 return (void *) merged
;
850 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
852 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
853 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
854 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
856 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
858 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
860 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
862 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
863 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
865 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
866 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
868 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
869 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
871 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
872 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
874 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
875 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
877 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
878 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
881 return (void *) merged
;
886 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
888 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
889 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
893 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
894 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
899 /* this adds a principal/keytab pair to get their tokens renewed by the
900 child process every few centons. */
902 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
906 if ( renewcount
>= SHARED_TABLE_SIZE
) {
907 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
908 decrease your tokens.");
912 /* check to see if it's already there */
914 for ( i
= 0; i
< renewcount
; i
++ ) {
915 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
920 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
921 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
922 renewtable
[renewcount
].lastrenewed
= 0;
928 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
930 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
931 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
933 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
934 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
936 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
937 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
939 add_to_renewtable(params
->pool
, keytab
, principal
);
947 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
949 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
950 waklog_config
*waklog_srvconfig
=
951 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
953 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
954 "mod_waklog: will use afs_cell: %s", file
);
956 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
957 waklog_srvconfig
->cell_in_principal
= 1;
959 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
960 waklog_srvconfig
->configured
= 1;
962 if (waklog_mconfig
!= NULL
) {
963 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
964 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
965 waklog_mconfig
->configured
= 1;
971 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
973 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
974 waklog_config
*waklog_srvconfig
=
975 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
977 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
978 "mod_waklog: will use afs_cell_realm: %s", file
);
980 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
982 if (waklog_mconfig
!= NULL
) {
983 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
989 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
991 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
992 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
994 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
996 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
997 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
999 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1000 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1002 /* this also gets set at the server level */
1003 if ( mconfig
&& ( ! cfg
->path
) ) {
1004 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1005 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1007 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
1008 return "Unable to set DefaultPrincipal outside of top level config!";
1011 add_to_renewtable( params
->pool
, keytab
, principal
);
1013 cfg
->configured
= 1;
1019 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1021 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1022 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1024 cfg
->usertokens
= flag
;
1026 cfg
->configured
= 1;
1028 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1029 "mod_waklog: waklog_use_user_tokens set");
1035 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1037 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1038 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1040 cfg
->disable_token_cache
= flag
;
1042 cfg
->configured
= 1;
1044 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1045 "mod_waklog: waklog_disable_token_cache set");
1051 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1053 apr_status_t
waklog_child_exit( void *sr
) {
1055 server_rec
*s
= (server_rec
*) sr
;
1058 if ( child
.ccache
) {
1059 krb5_cc_close(child
.kcontext
, child
.ccache
);
1062 if ( child
.kcontext
) {
1063 krb5_free_context(child
.kcontext
);
1066 /* forget our tokens */
1068 ktc_ForgetAllTokens ();
1070 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1071 "mod_waklog: waklog_child_exit complete");
1081 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1083 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1087 krb5_error_code code
;
1092 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1094 if ( !sharedspace
) {
1095 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1099 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1101 memset (&child
, 0, sizeof(child
));
1103 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1104 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1107 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1108 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1111 if ( pag_for_children
) {
1115 getModConfig (cfg
, s
);
1117 if ( cfg
->default_principal
!= NULL
) {
1118 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1119 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1122 cell
= strdup(cfg
->afs_cell
);
1123 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1126 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1129 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1130 "mod_waklog: child_init returned");
1135 command_rec waklog_cmds
[] = {
1137 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1138 "Use the supplied AFS cell (required)"),
1140 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1141 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1143 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1144 "enable waklog on a server, location, or directory basis"),
1146 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1147 "Set the default principal that the server runs as"),
1149 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1150 "Set the principal on a <Location>-specific basis"),
1152 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1153 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1155 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1156 "Use the requesting user tokens (from webauth)"),
1162 /* not currently using this */
1165 token_cleanup (void *data
)
1167 request_rec
*r
= (request_rec
*) data
;
1169 if (child
.token
.ticketLen
)
1171 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1173 ktc_ForgetAllTokens ();
1175 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1176 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1182 /* This function doesn't return anything but is passed to ap_bspawn_child on
1183 * Apache 1 which expects it to return a pid as an int. For want of better
1184 * understanding, err on the side of not changing Apache 1 code while fixing
1185 * the compile warning on Apache 2. */
1191 waklog_child_routine (void *data
, child_info
* pinfo
)
1194 server_rec
*s
= (server_rec
*) data
;
1195 krb5_error_code code
;
1197 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1202 getModConfig( cfg
, s
);
1204 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1206 memset (&child
, 0, sizeof(child
));
1208 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1209 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1212 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1213 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1216 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1218 /* need to do this so we can make PTS calls */
1219 cell
= strdup(cfg
->afs_cell
); /* stupid */
1220 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1222 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1226 for ( i
= 0; i
< renewcount
; ++i
) {
1227 renewtable
[i
].lastrenewed
= time(0);
1228 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1229 renewtable
[i
].keytab
);
1231 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1233 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1234 things that it needs to read */
1236 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1237 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1238 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1243 sharedspace
->renewcount
++;
1252 left
-= ( time(0) - when
);
1263 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1264 apr_pool_t
* ptemp
, server_rec
* s
)
1267 extern char *version
;
1272 int use_existing
= 1;
1274 char cache_file
[MAXNAMELEN
];
1276 pthread_rwlockattr_t rwlock_attr
;
1280 getModConfig (cfg
, s
);
1282 /* initialize_module() will be called twice, and if it's a DSO
1283 * then all static data from the first call will be lost. Only
1284 * set up our static data on the second call.
1285 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1286 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1289 if (cfg
->afs_cell
==NULL
) {
1290 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1291 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1292 /** clobber apache */
1298 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1299 apr_pool_cleanup_null
, s
->process
->pool
);
1303 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1304 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1306 if ( sharedspace
) {
1307 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1310 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1312 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1314 if ( errno
== ENOENT
) {
1316 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1318 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1319 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1323 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1327 if ( use_existing
== 0 ) {
1328 struct sharedspace_s bob
;
1329 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1330 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1331 if ( write(fd
, &bob
, sizeof(struct sharedspace_s
)) != sizeof(struct sharedspace_s
) ) {
1332 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: failed to write to our cache file %s (%d)", cache_file
, errno
);
1335 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1338 /* mmap the region */
1340 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1342 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1343 err
= unlink(cache_file
);
1345 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1347 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1350 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1356 #define locktype pthread_rwlock_t
1358 #define locktype rwlock_t
1361 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) != NULL
) {
1362 #ifndef use_pthreads
1363 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1365 pthread_rwlockattr_init(&rwlock_attr
);
1366 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1367 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1370 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1375 /* set our default tokens */
1377 oldrenewcount
= sharedspace
->renewcount
;
1379 pag_for_children
= 0;
1381 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1383 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1385 if (rv
== APR_INCHILD
)
1387 waklog_child_routine (s
, NULL
);
1391 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1393 /* parent and child */
1394 cfg
->forked
= proc
->pid
;
1395 pag_for_children
= 1;
1397 if ( use_existing
== 0 ) {
1398 /* wait here until our child process has gone and done it's renewing thing. */
1399 while( sharedspace
->renewcount
== oldrenewcount
) {
1400 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1405 if ( cfg
->default_principal
) {
1406 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1413 waklog_init (server_rec
* s
, MK_POOL
* p
)
1415 extern char *version
;
1419 int use_existing
= 1;
1421 char cache_file
[MAXNAMELEN
];
1423 pthread_rwlockattr_t rwlock_attr
;
1426 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1427 "mod_waklog: version %s initialized.", version
);
1429 if ( sharedspace
) {
1430 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1433 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1435 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1437 if ( errno
== ENOENT
) {
1439 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1441 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1442 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1446 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1451 if ( use_existing
== 0 ) {
1452 struct sharedspace_s bob
;
1453 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1454 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1455 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1456 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1459 /* mmap the region */
1461 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1462 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1465 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1471 #define locktype pthread_rwlock_t
1473 #define locktype rwlock_t
1476 /* mmap our shared space for our lock */
1477 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1478 #ifndef use_pthreads
1479 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1481 pthread_rwlockattr_init(&rwlock_attr
);
1482 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1483 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1486 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1491 /* set our default tokens */
1493 getModConfig (cfg
, s
);
1495 oldrenewcount
= sharedspace
->renewcount
;
1497 pag_for_children
= 0;
1499 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1502 pag_for_children
= 1;
1504 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1505 "mod_waklog: ap_bspawn_child: %d.", pid
);
1507 if ( use_existing
== 0 ) {
1508 /* wait here until our child process has gone and done it's renewing thing. */
1509 while( sharedspace
->renewcount
== oldrenewcount
) {
1510 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1515 if ( cfg
->default_principal
) {
1516 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1523 waklog_phase0 (request_rec
* r
)
1527 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1528 "mod_waklog: phase0 called");
1530 cfg
= retrieve_config(r
);
1532 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1533 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1534 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1535 } else if ( cfg
->default_principal
) {
1536 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1537 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1540 if (child
.token
.ticketLen
) {
1541 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1542 ktc_ForgetAllTokens();
1545 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1552 waklog_phase1 (request_rec
* r
)
1556 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1557 "mod_waklog: phase1 called");
1559 cfg
= retrieve_config(r
);
1561 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1562 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1563 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1564 } else if ( cfg
->default_principal
) {
1565 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1566 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1568 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1575 waklog_phase3 (request_rec
* r
)
1579 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1580 "mod_waklog: phase 3 called");
1582 cfg
= retrieve_config(r
);
1584 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1585 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1586 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1587 } else if ( cfg
->default_principal
) {
1588 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1589 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1591 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1598 waklog_phase6 (request_rec
* r
)
1602 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1603 "mod_waklog: phase6 called");
1605 cfg
= retrieve_config(r
);
1607 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1608 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1609 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1610 } else if ( cfg
->default_principal
) {
1611 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1612 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1614 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1621 waklog_phase7 (request_rec
* r
)
1626 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1627 "mod_waklog: phase7 called");
1629 cfg
= retrieve_config (r
);
1631 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1632 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1633 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1634 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1635 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1636 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1637 } else if ( cfg
->default_principal
) {
1638 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1639 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1641 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1642 if (child
.token
.ticketLen
) {
1643 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1644 ktc_ForgetAllTokens();
1656 waklog_phase9 (request_rec
* r
)
1660 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1661 "mod_waklog: phase9 called");
1663 getModConfig (cfg
, r
->server
);
1665 if ( cfg
->default_principal
) {
1666 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1667 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1680 waklog_new_connection (conn_rec
* c
1689 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1690 "mod_waklog: new_connection called: pid: %d", getpid ());
1692 getModConfig(cfg
, c
->base_server
);
1694 if ( cfg
->default_principal
) {
1695 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1696 cfg
->default_principal
);
1697 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1710 ** Here's a quick explaination for phase0 and phase2:
1711 ** Apache does a stat() on the path between phase0 and
1712 ** phase2, and must by ACLed rl to succeed. So, at
1713 ** phase0 we acquire credentials for umweb:servers from
1714 ** a keytab, and at phase2 we must ensure we remove them.
1716 ** Failure to "unlog" would be a security risk.
1719 waklog_phase2 (request_rec
* r
)
1722 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1723 "mod_waklog: phase2 called");
1725 if (child
.token
.ticketLen
)
1727 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1729 ktc_ForgetAllTokens ();
1731 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1732 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1736 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1737 "mod_waklog: phase2 returning");
1743 module MODULE_VAR_EXPORT waklog_module
= {
1744 STANDARD_MODULE_STUFF
,
1745 waklog_init
, /* module initializer */
1746 waklog_create_dir_config
, /* create per-dir config structures */
1747 waklog_merge_dir_config
, /* merge per-dir config structures */
1748 waklog_create_server_config
, /* create per-server config structures */
1749 waklog_merge_dir_config
, /* merge per-server config structures */
1750 waklog_cmds
, /* table of config file commands */
1751 NULL
, /* [#8] MIME-typed-dispatched handlers */
1752 waklog_phase1
, /* [#1] URI to filename translation */
1753 NULL
, /* [#4] validate user id from request */
1754 NULL
, /* [#5] check if the user is ok _here_ */
1755 waklog_phase3
, /* [#3] check access by host address */
1756 waklog_phase6
, /* [#6] determine MIME type */
1757 waklog_phase7
, /* [#7] pre-run fixups */
1758 waklog_phase9
, /* [#9] log a transaction */
1759 waklog_phase2
, /* [#2] header parser */
1760 waklog_child_init
, /* child_init */
1761 waklog_child_exit
, /* child_exit */
1762 waklog_phase0
/* [#0] post read-request */
1764 , NULL
, /* EAPI: add_module */
1765 NULL
, /* EAPI: remove_module */
1766 NULL
, /* EAPI: rewrite_command */
1767 waklog_new_connection
/* EAPI: new_connection */
1772 waklog_register_hooks (apr_pool_t
* p
)
1774 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1775 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1776 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1777 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1778 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1779 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1780 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1781 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1782 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1783 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1787 module AP_MODULE_DECLARE_DATA waklog_module
= {
1788 STANDARD20_MODULE_STUFF
,
1789 waklog_create_dir_config
, /* create per-dir conf structures */
1790 waklog_merge_dir_config
, /* merge per-dir conf structures */
1791 waklog_create_server_config
, /* create per-server conf structures */
1792 waklog_merge_dir_config
, /* merge per-server conf structures */
1793 waklog_cmds
, /* table of configuration directives */
1794 waklog_register_hooks
/* register hooks */