1 #define _LARGEFILE64_SOURCE
5 #include "http_config.h"
7 #include "http_protocol.h"
8 #include "http_request.h"
14 #include <sys/ioccom.h>
18 #include <sys/types.h>
22 #error "make sure you include the right stuff here"
26 #define MAXNAMELEN 1024
29 #ifdef STANDARD20_MODULE_STUFF
33 /********************* APACHE1 ******************************************************************************/
35 #include "ap_config.h"
36 #include <http_conf_globals.h>
38 #define MK_TABLE_GET ap_table_get
39 #define MK_TABLE_SET ap_table_set
40 #define command(name, func, var, type, usage) \
43 RSRC_CONF | ACCESS_CONF , type, usage }
46 /********************* APACHE2 ******************************************************************************/
48 #include "http_connection.h"
49 #include <apr_strings.h>
50 #include <apr_base64.h>
51 #define ap_pcalloc apr_pcalloc
52 #define ap_pdupstr apr_pdupstr
53 #define ap_pstrdup apr_pstrdup
54 #define MK_POOL apr_pool_t
55 #define MK_TABLE_GET apr_table_get
56 #define MK_TABLE_SET apr_table_set
57 #define command(name, func, var, type, usage) \
58 AP_INIT_ ## type (name, (void*) func, \
60 RSRC_CONF | ACCESS_CONF, usage)
61 module AP_MODULE_DECLARE_DATA waklog_module
;
62 typedef struct { int dummy
; } child_info
;
63 const char *userdata_key
= "waklog_init";
66 #ifdef APLOG_USE_MODULE
67 APLOG_USE_MODULE(waklog
);
71 /**************************************************************************************************/
76 #include <afs/param.h>
78 #include <afs/venus.h>
80 #include <afs/dirpath.h>
81 #include <afs/ptuser.h>
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 );
168 #ifdef APLOG_USE_MODULE
170 log_error (const char *file
, int line
, int module_index
, int level
, int status
,
171 const server_rec
* s
, const char *fmt
, ...)
174 log_error (const char *file
, int line
, int level
, int status
,
175 const server_rec
* s
, const char *fmt
, ...)
182 vsnprintf (errstr
, 1024, fmt
, ap
);
186 #ifdef APLOG_USE_MODULE
188 ap_log_error (file
, line
, module_index
, level
| APLOG_NOERRNO
, status
, s
, "%s", errstr
);
190 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
193 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
198 waklog_config
*retrieve_config(request_rec
*r
) {
203 if ( r
&& r
->main
) {
211 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
214 getModConfig (cfg
, r
->server
);
221 /* set_auth -- sets the tokens of the current process to this user.
222 if "self" is set, it divines the user from the current requests' environment.
223 otherwise, it's gettng it from principal/keytab */
226 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
230 krb5_error_code kerror
= 0;
231 krb5_principal kprinc
= NULL
;
232 krb5_get_init_creds_opt kopts
;
235 krb5_ccache clientccache
;
236 struct ktc_principal server
= { "afs", "", "" };
237 struct ktc_principal client
;
238 struct ktc_token token
;
239 krb5_creds
*v5credsp
= NULL
;
240 krb5_keytab krb5kt
= NULL
;
241 char buf
[MAXNAMELEN
];
245 time_t oldest_time
= 0;
250 int cell_in_principal
;
252 int use_client_credentials
= 0;
254 char k5user
[MAXNAMELEN
] = "";
255 char *k5secret
= NULL
;
259 memset((char *) &increds
, 0, sizeof(increds
));
260 /* init some stuff if it ain't already */
261 /* XXX - In what situation will these not be initialized? */
263 if ( ! child
.kcontext
) {
264 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
265 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
271 if ( !child
.ccache
) {
272 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
273 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
279 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
280 self
, principal
? principal
: "NULL",
281 keytab
? keytab
: "NULL",
283 k5path
? k5path
: "NULL",
285 (r
&& r
->user
) ? r
->user
: "NULL"
287 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
291 /* pull the server config record that we care about... */
294 cfg
= retrieve_config(r
);
296 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
297 "mod_waklog: set_auth using no config" );
298 getModConfig (cfg
, s
);
302 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
307 /* pull out our principal name and stuff from the environment -- webauth better have sent
311 if ( ! ( r
&& r
->connection
&& r
->user
)) {
312 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
313 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
));
317 strncpy(k5user
, r
->user
, sizeof(k5user
));
319 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
320 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
324 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
326 /* if they've supplied a credentials cache */
327 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
329 /* the other thing we need is someone's password */
330 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
332 /* we'll pick this up later after we've checked the cache and current state */
336 strncpy(k5user
, principal
, sizeof(k5user
));
340 strncpy(k5user
, r
->user
, sizeof(k5user
));
343 if (r
&& r
->connection
&& r
->connection
->user
) {
344 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
348 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
);
351 /* see if we should just go ahead and ignore this call, since we already should be set to these
357 pthread_rwlock_rdlock( sharedlock
);
359 rw_rdlock( sharedlock
);
362 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
364 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
366 if ( ( !strcmp( k5user
,
367 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
368 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
370 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
376 /* copy the token out of the cache and into the child object */
378 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
379 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
380 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
381 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
383 /* set our last used time thing */
384 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
394 /* release the lock on the token cache */
396 pthread_rwlock_unlock( sharedlock
);
398 rw_unlock( sharedlock
);
402 /* release the lock on the token cache */
403 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
404 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
408 /* if this is something that was in the cache, and it's the same as the token we already have stored,
409 and we weren't calling this just to renew it... */
411 if ( usecached
&& indentical
) {
412 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
418 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
421 /* clear out the creds structure */
422 memset((void *) &v5creds
, 0, sizeof(v5creds
));
424 /* create a principal out of our k5user string */
426 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
427 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror
) );
431 /* create the credentials options */
433 krb5_get_init_creds_opt_init ( &kopts
);
434 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
435 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
436 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
437 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
439 if ( keytab
|| k5secret
) {
442 /* if we've been passed a keytab, we're going to be getting our credentials from it */
444 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
446 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
447 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
448 "mod_waklog: krb5_kt_resolve %s", error_message(kerror
) );
452 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
453 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
454 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
455 error_message(kerror
) );
458 } else if (k5secret
) {
460 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
462 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
463 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
464 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
465 error_message(kerror
) );
466 /* nuke the password so it doesn't end up in core files */
467 memset(k5secret
, 0, sizeof(k5secret
));
471 memset(k5secret
, 0, sizeof(k5secret
));
474 /* initialize the credentials cache and store the stuff we just got */
475 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
476 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
477 error_message(kerror
));
481 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
482 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
483 error_message(kerror
));
487 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
490 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", error_message(kerror
));
494 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
497 /* If we've got a path to a credentials cache, then try and use that. We can't just
498 * replace child.creds, because we want to ensure that only this request gets access to
501 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
502 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
503 "mod_waklog: can't open provided credentials cache %s err=%d",
508 use_client_credentials
= 1;
511 /* now, to the 'aklog' portion of our program. */
513 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
514 for(attempt
= 0; attempt
<= 1; attempt
++) {
515 strncpy( buf
, "afs", sizeof(buf
) - 1 );
516 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
518 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
519 if (cell_in_principal
) {
520 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
521 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
523 if (cfg
->afs_cell_realm
!= NULL
) {
524 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
525 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
528 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
530 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
531 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", error_message(kerror
));
535 if (!use_client_credentials
) {
536 clientccache
= child
.ccache
;
539 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
540 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", error_message(kerror
), clientccache
);
544 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
546 increds
.times
.endtime
= 0;
548 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
550 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
551 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
553 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
554 error_message(kerror
));
560 cfg
->cell_in_principal
= cell_in_principal
;
564 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
566 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
567 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
568 v5credsp
->ticket
.length
);
572 memset(&token
, 0, sizeof(struct ktc_token
));
574 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
575 token
.endTime
= v5credsp
->times
.endtime
;
577 memmove( &token
.sessionKey
, v5credsp
->keyblock
.contents
, v5credsp
->keyblock
.length
);
578 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
579 token
.ticketLen
= v5credsp
->ticket
.length
;
580 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
584 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
586 buf
[v5credsp
->client
->data
[0].length
] = '\0';
587 if ( v5credsp
->client
->length
> 1 ) {
588 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
589 buflen
= strlen(buf
);
590 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
591 min(v5credsp
->client
->data
[1].length
,
592 MAXKTCNAMELEN
- strlen(buf
) - 1));
593 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
596 /* assemble the client */
597 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
598 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
599 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
601 buf
[v5credsp
->client
->realm
.length
] = '\0';
602 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
604 /* assemble the server's cell */
605 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
607 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
609 /* fill out the AFS ID in the client name */
610 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
611 * strange things seem to happen. */
614 afs_int32 viceId
= 0;
616 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
618 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
619 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
621 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
624 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
628 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
629 server
.name
, server
.instance
, server
.cell
);
631 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
632 client
.name
, client
.instance
, client
.cell
);
634 /* copy the resulting stuff into the child structure */
636 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
637 memcpy(&child
.token
, &token
, sizeof(child
.token
));
638 memcpy(&child
.server
, &server
, sizeof(child
.server
));
639 memcpy(&child
.client
, &client
, sizeof(child
.client
));
641 /* stuff the resulting token-related stuff into our shared token cache */
642 /* note, that anything that was set from a keytab is "persistant", and is immune
643 * from LRU-aging. This is because nothing but the process that's running as root
644 * can update these, and it's running every hour or so and renewing these tokens.
645 * and we don't want them aged out.
648 mytime
= oldest_time
= time(0);
650 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
653 pthread_rwlock_wrlock(sharedlock
);
655 rw_wrlock(sharedlock
);
658 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
659 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
660 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
662 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
664 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
665 child
.clientprincipal
) ) {
666 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
667 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
668 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
669 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
670 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
676 if ( stored
== -1 ) {
677 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
678 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
679 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
680 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
681 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
682 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
687 pthread_rwlock_unlock(sharedlock
);
689 rw_unlock(sharedlock
);
692 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
693 child
.clientprincipal
);
695 } else if ( ! usecached
) {
696 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
705 /* don't ask. Something about AIX. We're leaving it here.*/
706 /* write(2, "", 0); */
708 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
710 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
711 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
712 error_message(rc
), k5user
);
713 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
714 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
715 error_message(rc
), k5user
);
721 if (use_client_credentials
)
722 krb5_cc_close(child
.kcontext
, clientccache
);
724 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
725 if ( increds
.client
)
726 krb5_free_principal (child
.kcontext
, increds
.client
);
727 if ( increds
.server
)
728 krb5_free_principal (child
.kcontext
, increds
.server
);
730 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
732 krb5_free_principal (child
.kcontext
, kprinc
);
735 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
736 } else if ( kerror
) {
737 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, error_message(kerror
));
739 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
742 return kerror
? (int) kerror
: (int) rc
;
747 int get_cfg_usertokens(waklog_config
*cfg
)
749 if (cfg
->usertokens
==WAKLOG_UNSET
)
750 return 0; /* default */
751 return cfg
->usertokens
;
754 int get_cfg_protect(waklog_config
*cfg
)
756 if (cfg
->protect
==WAKLOG_UNSET
)
757 return 0; /* default */
761 int get_cfg_disable_token_cache(waklog_config
*cfg
)
763 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
764 return 0; /* default */
765 return cfg
->disable_token_cache
;
770 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
774 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
776 memset(cfg
, 0, sizeof(waklog_config
));
777 cfg
->path
= "(server)";
778 cfg
->protect
= WAKLOG_UNSET
;
779 cfg
->usertokens
= WAKLOG_UNSET
;
780 cfg
->disable_token_cache
= WAKLOG_UNSET
;
782 cfg
->principal
= NULL
;
783 cfg
->default_principal
= NULL
;
784 cfg
->default_keytab
= NULL
;
785 cfg
->afs_cell
= NULL
;
786 cfg
->afs_cell_realm
= NULL
;
790 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
791 "mod_waklog: server config created.");
796 /* initialize with host-config information */
799 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
803 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
804 memset(cfg
, 0, sizeof(waklog_config
));
806 cfg
->path
= ap_pstrdup(p
, dir
);
807 cfg
->protect
= WAKLOG_UNSET
;
808 cfg
->usertokens
= WAKLOG_UNSET
;
809 cfg
->disable_token_cache
= WAKLOG_UNSET
;
811 cfg
->principal
= NULL
;
812 cfg
->default_principal
= NULL
;
813 cfg
->default_keytab
= NULL
;
814 cfg
->afs_cell
= NULL
;
815 cfg
->afs_cell_realm
= NULL
;
822 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
824 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
825 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
826 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
828 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
830 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
832 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
834 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
836 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
838 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
840 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
842 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
844 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
846 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
848 return (void *) merged
;
852 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
854 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
855 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
856 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
858 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
860 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
862 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
864 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
865 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
867 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
868 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
870 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
871 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
873 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
874 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
876 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
877 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
879 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
880 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
883 return (void *) merged
;
888 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
890 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
891 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
895 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
896 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
901 /* this adds a principal/keytab pair to get their tokens renewed by the
902 child process every few centons. */
904 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
908 if ( renewcount
>= SHARED_TABLE_SIZE
) {
909 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
910 decrease your tokens.");
914 /* check to see if it's already there */
916 for ( i
= 0; i
< renewcount
; i
++ ) {
917 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
922 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
923 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
924 renewtable
[renewcount
].lastrenewed
= 0;
930 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
932 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
933 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
935 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
936 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
938 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
939 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
941 add_to_renewtable(params
->pool
, keytab
, principal
);
949 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
951 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
952 waklog_config
*waklog_srvconfig
=
953 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
955 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
956 "mod_waklog: will use afs_cell: %s", file
);
958 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
959 waklog_srvconfig
->cell_in_principal
= 1;
961 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
962 waklog_srvconfig
->configured
= 1;
964 if (waklog_mconfig
!= NULL
) {
965 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
966 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
967 waklog_mconfig
->configured
= 1;
973 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
975 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
976 waklog_config
*waklog_srvconfig
=
977 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
979 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
980 "mod_waklog: will use afs_cell_realm: %s", file
);
982 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
984 if (waklog_mconfig
!= NULL
) {
985 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
991 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
993 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
994 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
996 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
998 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
999 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
1001 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1002 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1004 /* this also gets set at the server level */
1005 if ( mconfig
&& ( ! cfg
->path
) ) {
1006 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1007 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1009 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
1010 return "Unable to set DefaultPrincipal outside of top level config!";
1013 add_to_renewtable( params
->pool
, keytab
, principal
);
1015 cfg
->configured
= 1;
1021 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1023 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1024 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1026 cfg
->usertokens
= flag
;
1028 cfg
->configured
= 1;
1030 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1031 "mod_waklog: waklog_use_user_tokens set");
1037 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1039 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1040 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1042 cfg
->disable_token_cache
= flag
;
1044 cfg
->configured
= 1;
1046 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1047 "mod_waklog: waklog_disable_token_cache set");
1053 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1055 apr_status_t
waklog_child_exit( void *sr
) {
1057 server_rec
*s
= (server_rec
*) sr
;
1060 if ( child
.ccache
) {
1061 krb5_cc_close(child
.kcontext
, child
.ccache
);
1064 if ( child
.kcontext
) {
1065 krb5_free_context(child
.kcontext
);
1068 /* forget our tokens */
1070 ktc_ForgetAllTokens ();
1072 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1073 "mod_waklog: waklog_child_exit complete");
1083 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1085 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1089 krb5_error_code code
;
1094 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1096 if ( !sharedspace
) {
1097 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1101 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1103 memset (&child
, 0, sizeof(child
));
1105 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1106 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1109 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1110 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1113 if ( pag_for_children
) {
1117 getModConfig (cfg
, s
);
1119 if ( cfg
->default_principal
!= NULL
) {
1120 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1121 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1124 cell
= strdup(cfg
->afs_cell
);
1125 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1128 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1131 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1132 "mod_waklog: child_init returned");
1137 command_rec waklog_cmds
[] = {
1139 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1140 "Use the supplied AFS cell (required)"),
1142 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1143 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1145 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1146 "enable waklog on a server, location, or directory basis"),
1148 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1149 "Set the default principal that the server runs as"),
1151 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1152 "Set the principal on a <Location>-specific basis"),
1154 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1155 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1157 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1158 "Use the requesting user tokens (from webauth)"),
1164 /* not currently using this */
1167 token_cleanup (void *data
)
1169 request_rec
*r
= (request_rec
*) data
;
1171 if (child
.token
.ticketLen
)
1173 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1175 ktc_ForgetAllTokens ();
1177 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1178 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1184 /* This function doesn't return anything but is passed to ap_bspawn_child on
1185 * Apache 1 which expects it to return a pid as an int. For want of better
1186 * understanding, err on the side of not changing Apache 1 code while fixing
1187 * the compile warning on Apache 2. */
1193 waklog_child_routine (void *data
, child_info
* pinfo
)
1196 server_rec
*s
= (server_rec
*) data
;
1197 krb5_error_code code
;
1199 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1204 getModConfig( cfg
, s
);
1206 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1208 memset (&child
, 0, sizeof(child
));
1210 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1211 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1214 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1215 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1218 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1220 /* need to do this so we can make PTS calls */
1221 cell
= strdup(cfg
->afs_cell
); /* stupid */
1222 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1224 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1228 for ( i
= 0; i
< renewcount
; ++i
) {
1229 renewtable
[i
].lastrenewed
= time(0);
1230 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1231 renewtable
[i
].keytab
);
1233 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1235 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1236 things that it needs to read */
1238 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1239 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1240 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1245 sharedspace
->renewcount
++;
1254 left
-= ( time(0) - when
);
1265 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1266 apr_pool_t
* ptemp
, server_rec
* s
)
1269 extern char *version
;
1274 int use_existing
= 1;
1276 char cache_file
[MAXNAMELEN
];
1278 pthread_rwlockattr_t rwlock_attr
;
1282 getModConfig (cfg
, s
);
1284 /* initialize_module() will be called twice, and if it's a DSO
1285 * then all static data from the first call will be lost. Only
1286 * set up our static data on the second call.
1287 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1288 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1291 if (cfg
->afs_cell
==NULL
) {
1292 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1293 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1294 /** clobber apache */
1300 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1301 apr_pool_cleanup_null
, s
->process
->pool
);
1305 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1306 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1308 if ( sharedspace
) {
1309 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1312 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1314 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1316 if ( errno
== ENOENT
) {
1318 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1320 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1321 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1325 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1329 if ( use_existing
== 0 ) {
1330 struct sharedspace_s bob
;
1331 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1332 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1333 if ( write(fd
, &bob
, sizeof(struct sharedspace_s
)) != sizeof(struct sharedspace_s
) ) {
1334 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: failed to write to our cache file %s (%d)", cache_file
, errno
);
1337 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1340 /* mmap the region */
1342 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1344 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1345 err
= unlink(cache_file
);
1347 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1349 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1352 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1358 #define locktype pthread_rwlock_t
1360 #define locktype rwlock_t
1363 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) != NULL
) {
1364 #ifndef use_pthreads
1365 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1367 pthread_rwlockattr_init(&rwlock_attr
);
1368 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1369 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1372 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1377 /* set our default tokens */
1379 oldrenewcount
= sharedspace
->renewcount
;
1381 pag_for_children
= 0;
1383 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1385 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1387 if (rv
== APR_INCHILD
)
1389 waklog_child_routine (s
, NULL
);
1393 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1395 /* parent and child */
1396 cfg
->forked
= proc
->pid
;
1397 pag_for_children
= 1;
1399 if ( use_existing
== 0 ) {
1400 /* wait here until our child process has gone and done it's renewing thing. */
1401 while( sharedspace
->renewcount
== oldrenewcount
) {
1402 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1407 if ( cfg
->default_principal
) {
1408 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1415 waklog_init (server_rec
* s
, MK_POOL
* p
)
1417 extern char *version
;
1421 int use_existing
= 1;
1423 char cache_file
[MAXNAMELEN
];
1425 pthread_rwlockattr_t rwlock_attr
;
1428 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1429 "mod_waklog: version %s initialized.", version
);
1431 if ( sharedspace
) {
1432 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1435 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1437 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1439 if ( errno
== ENOENT
) {
1441 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1443 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1444 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1448 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1453 if ( use_existing
== 0 ) {
1454 struct sharedspace_s bob
;
1455 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1456 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1457 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1458 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1461 /* mmap the region */
1463 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1464 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1467 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1473 #define locktype pthread_rwlock_t
1475 #define locktype rwlock_t
1478 /* mmap our shared space for our lock */
1479 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1480 #ifndef use_pthreads
1481 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1483 pthread_rwlockattr_init(&rwlock_attr
);
1484 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1485 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1488 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1493 /* set our default tokens */
1495 getModConfig (cfg
, s
);
1497 oldrenewcount
= sharedspace
->renewcount
;
1499 pag_for_children
= 0;
1501 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1504 pag_for_children
= 1;
1506 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1507 "mod_waklog: ap_bspawn_child: %d.", pid
);
1509 if ( use_existing
== 0 ) {
1510 /* wait here until our child process has gone and done it's renewing thing. */
1511 while( sharedspace
->renewcount
== oldrenewcount
) {
1512 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1517 if ( cfg
->default_principal
) {
1518 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1525 waklog_phase0 (request_rec
* r
)
1529 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1530 "mod_waklog: phase0 called");
1532 cfg
= retrieve_config(r
);
1534 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1535 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1536 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1537 } else if ( cfg
->default_principal
) {
1538 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1539 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1542 if (child
.token
.ticketLen
) {
1543 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1544 ktc_ForgetAllTokens();
1547 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1554 waklog_phase1 (request_rec
* r
)
1558 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1559 "mod_waklog: phase1 called");
1561 cfg
= retrieve_config(r
);
1563 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1564 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1565 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1566 } else if ( cfg
->default_principal
) {
1567 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1568 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1570 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1577 waklog_phase3 (request_rec
* r
)
1581 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1582 "mod_waklog: phase 3 called");
1584 cfg
= retrieve_config(r
);
1586 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1587 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1588 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1589 } else if ( cfg
->default_principal
) {
1590 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1591 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1593 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1600 waklog_phase6 (request_rec
* r
)
1604 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1605 "mod_waklog: phase6 called");
1607 cfg
= retrieve_config(r
);
1609 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1610 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1611 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1612 } else if ( cfg
->default_principal
) {
1613 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1614 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1616 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1623 waklog_phase7 (request_rec
* r
)
1628 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1629 "mod_waklog: phase7 called");
1631 cfg
= retrieve_config (r
);
1633 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1634 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1635 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1636 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1637 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1638 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1639 } else if ( cfg
->default_principal
) {
1640 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1641 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1643 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1644 if (child
.token
.ticketLen
) {
1645 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1646 ktc_ForgetAllTokens();
1658 waklog_phase9 (request_rec
* r
)
1662 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1663 "mod_waklog: phase9 called");
1665 getModConfig (cfg
, r
->server
);
1667 if ( cfg
->default_principal
) {
1668 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1669 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1682 waklog_new_connection (conn_rec
* c
1691 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1692 "mod_waklog: new_connection called: pid: %d", getpid ());
1694 getModConfig(cfg
, c
->base_server
);
1696 if ( cfg
->default_principal
) {
1697 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1698 cfg
->default_principal
);
1699 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1712 ** Here's a quick explaination for phase0 and phase2:
1713 ** Apache does a stat() on the path between phase0 and
1714 ** phase2, and must by ACLed rl to succeed. So, at
1715 ** phase0 we acquire credentials for umweb:servers from
1716 ** a keytab, and at phase2 we must ensure we remove them.
1718 ** Failure to "unlog" would be a security risk.
1721 waklog_phase2 (request_rec
* r
)
1724 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1725 "mod_waklog: phase2 called");
1727 if (child
.token
.ticketLen
)
1729 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1731 ktc_ForgetAllTokens ();
1733 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1734 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1738 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1739 "mod_waklog: phase2 returning");
1745 module MODULE_VAR_EXPORT waklog_module
= {
1746 STANDARD_MODULE_STUFF
,
1747 waklog_init
, /* module initializer */
1748 waklog_create_dir_config
, /* create per-dir config structures */
1749 waklog_merge_dir_config
, /* merge per-dir config structures */
1750 waklog_create_server_config
, /* create per-server config structures */
1751 waklog_merge_dir_config
, /* merge per-server config structures */
1752 waklog_cmds
, /* table of config file commands */
1753 NULL
, /* [#8] MIME-typed-dispatched handlers */
1754 waklog_phase1
, /* [#1] URI to filename translation */
1755 NULL
, /* [#4] validate user id from request */
1756 NULL
, /* [#5] check if the user is ok _here_ */
1757 waklog_phase3
, /* [#3] check access by host address */
1758 waklog_phase6
, /* [#6] determine MIME type */
1759 waklog_phase7
, /* [#7] pre-run fixups */
1760 waklog_phase9
, /* [#9] log a transaction */
1761 waklog_phase2
, /* [#2] header parser */
1762 waklog_child_init
, /* child_init */
1763 waklog_child_exit
, /* child_exit */
1764 waklog_phase0
/* [#0] post read-request */
1766 , NULL
, /* EAPI: add_module */
1767 NULL
, /* EAPI: remove_module */
1768 NULL
, /* EAPI: rewrite_command */
1769 waklog_new_connection
/* EAPI: new_connection */
1774 waklog_register_hooks (apr_pool_t
* p
)
1776 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1777 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1778 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1779 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1780 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1781 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1782 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1783 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1784 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1785 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1789 module AP_MODULE_DECLARE_DATA waklog_module
= {
1790 STANDARD20_MODULE_STUFF
,
1791 waklog_create_dir_config
, /* create per-dir conf structures */
1792 waklog_merge_dir_config
, /* merge per-dir conf structures */
1793 waklog_create_server_config
, /* create per-server conf structures */
1794 waklog_merge_dir_config
, /* merge per-server conf structures */
1795 waklog_cmds
, /* table of configuration directives */
1796 waklog_register_hooks
/* register hooks */