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>
52 #define ap_pcalloc apr_pcalloc
53 #define ap_pdupstr apr_pdupstr
54 #define ap_pstrdup apr_pstrdup
55 #define MK_POOL apr_pool_t
56 #define MK_TABLE_GET apr_table_get
57 #define MK_TABLE_SET apr_table_set
59 extern unixd_config_rec unixd_config
;
60 #define ap_user_id unixd_config.user_id
61 #define ap_group_id unixd_config.group_id
62 #define ap_user_name unixd_config.user_name
63 #define command(name, func, var, type, usage) \
64 AP_INIT_ ## type (name, (void*) func, \
66 RSRC_CONF | ACCESS_CONF, usage)
67 module AP_MODULE_DECLARE_DATA waklog_module
;
68 typedef struct { int dummy
; } child_info
;
69 const char *userdata_key
= "waklog_init";
72 /**************************************************************************************************/
77 #include <afs/param.h>
79 #include <afs/venus.h>
81 #include <afs/dirpath.h>
82 #include <afs/ptuser.h>
85 #define TKT_LIFE ( 12 * 60 * 60 )
86 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
88 #define WAKLOG_UNSET -1
92 #define APLOG_DEBUG APLOG_ERR
95 /* this is used to turn off pag generation for the backround worker child during startup */
96 int pag_for_children
= 1;
104 int cell_in_principal
;
105 int disable_token_cache
;
108 char *default_principal
;
109 char *default_keytab
;
111 char *afs_cell_realm
;
119 struct ktc_token token
;
120 char clientprincipal
[MAXNAMELEN
];
121 krb5_context kcontext
;
123 struct ktc_principal server
;
124 struct ktc_principal client
;
126 } waklog_child_config
;
128 waklog_child_config child
;
130 struct tokencache_ent
{
131 char clientprincipal
[MAXNAMELEN
];
132 struct ktc_token token
;
133 struct ktc_principal client
;
134 struct ktc_principal server
;
139 #define SHARED_TABLE_SIZE 512
141 struct sharedspace_s
{
143 struct tokencache_ent sharedtokens
[SHARED_TABLE_SIZE
];
146 struct sharedspace_s
*sharedspace
= NULL
;
155 pthread_rwlock_t
*sharedlock
= NULL
;
157 rwlock_t
*sharedlock
= NULL
;
160 struct renew_ent renewtable
[SHARED_TABLE_SIZE
];
166 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
170 log_error (const char *file
, int line
, int level
, int status
,
171 const server_rec
* s
, const char *fmt
, ...)
177 vsnprintf (errstr
, 1024, fmt
, ap
);
181 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
183 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
188 waklog_config
*retrieve_config(request_rec
*r
) {
193 if ( r
&& r
->main
) {
201 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
204 getModConfig (cfg
, r
->server
);
211 /* set_auth -- sets the tokens of the current process to this user.
212 if "self" is set, it divines the user from the current requests' environment.
213 otherwise, it's gettng it from principal/keytab */
216 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
220 krb5_error_code kerror
= 0;
221 krb5_principal kprinc
= NULL
;
222 krb5_get_init_creds_opt kopts
;
225 krb5_ccache clientccache
;
226 struct ktc_principal server
= { "afs", "", "" };
227 struct ktc_principal client
;
228 struct ktc_token token
;
229 krb5_creds
*v5credsp
= NULL
;
230 krb5_keytab krb5kt
= NULL
;
231 char buf
[MAXNAMELEN
];
235 time_t oldest_time
= 0;
240 int cell_in_principal
;
242 int use_client_credentials
= 0;
244 char k5user
[MAXNAMELEN
] = "";
245 char *k5secret
= NULL
;
249 memset((char *) &increds
, 0, sizeof(increds
));
250 /* init some stuff if it ain't already */
251 /* XXX - In what situation will these not be initialized? */
253 if ( ! child
.kcontext
) {
254 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
255 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
261 if ( !child
.ccache
) {
262 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
263 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
269 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
270 self
, principal
? principal
: "NULL",
271 keytab
? keytab
: "NULL",
273 k5path
? k5path
: "NULL",
275 (r
&& r
->user
) ? r
->user
: "NULL"
277 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
281 /* pull the server config record that we care about... */
284 cfg
= retrieve_config(r
);
286 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
287 "mod_waklog: set_auth using no config" );
288 getModConfig (cfg
, s
);
292 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
297 /* pull out our principal name and stuff from the environment -- webauth better have sent
301 if ( ! ( r
&& r
->connection
&& r
->user
)) {
302 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
303 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
));
307 strncpy(k5user
, r
->user
, sizeof(k5user
));
309 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
310 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
314 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
316 /* if they've supplied a credentials cache */
317 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
319 /* the other thing we need is someone's password */
320 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
322 /* we'll pick this up later after we've checked the cache and current state */
326 strncpy(k5user
, principal
, sizeof(k5user
));
330 strncpy(k5user
, r
->user
, sizeof(k5user
));
333 if (r
&& r
->connection
&& r
->connection
->user
) {
334 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
338 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
);
341 /* see if we should just go ahead and ignore this call, since we already should be set to these
347 pthread_rwlock_rdlock( sharedlock
);
349 rw_rdlock( sharedlock
);
352 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
354 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
356 if ( ( !strcmp( k5user
,
357 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
358 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
360 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
366 /* copy the token out of the cache and into the child object */
368 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
369 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
370 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
371 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
373 /* set our last used time thing */
374 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
384 /* release the lock on the token cache */
386 pthread_rwlock_unlock( sharedlock
);
388 rw_unlock( sharedlock
);
392 /* release the lock on the token cache */
393 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
394 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
398 /* if this is something that was in the cache, and it's the same as the token we already have stored,
399 and we weren't calling this just to renew it... */
401 if ( usecached
&& indentical
) {
402 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
408 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
411 /* clear out the creds structure */
412 memset((void *) &v5creds
, 0, sizeof(v5creds
));
414 /* create a principal out of our k5user string */
416 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
417 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) afs_error_message(kerror
) );
421 /* create the credentials options */
423 krb5_get_init_creds_opt_init ( &kopts
);
424 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
425 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
426 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
427 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
429 if ( keytab
|| k5secret
) {
432 /* if we've been passed a keytab, we're going to be getting our credentials from it */
434 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
436 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
437 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
438 "mod_waklog: krb5_kt_resolve %s", afs_error_message(kerror
) );
442 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
443 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
444 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
445 afs_error_message(kerror
) );
448 } else if (k5secret
) {
450 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
452 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
453 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
454 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
455 afs_error_message(kerror
) );
456 /* nuke the password so it doesn't end up in core files */
457 memset(k5secret
, 0, sizeof(k5secret
));
461 memset(k5secret
, 0, sizeof(k5secret
));
464 /* initialize the credentials cache and store the stuff we just got */
465 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
466 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
467 afs_error_message(kerror
));
471 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
472 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
473 afs_error_message(kerror
));
477 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
480 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", afs_error_message(kerror
));
484 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
487 /* If we've got a path to a credentials cache, then try and use that. We can't just
488 * replace child.creds, because we want to ensure that only this request gets access to
491 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
492 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
493 "mod_waklog: can't open provided credentials cache %s err=%d",
498 use_client_credentials
= 1;
501 /* now, to the 'aklog' portion of our program. */
503 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
504 for(attempt
= 0; attempt
<= 1; attempt
++) {
505 strncpy( buf
, "afs", sizeof(buf
) - 1 );
506 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
508 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
509 if (cell_in_principal
) {
510 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
511 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
513 if (cfg
->afs_cell_realm
!= NULL
) {
514 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
515 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
518 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
520 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
521 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", afs_error_message(kerror
));
525 if (!use_client_credentials
) {
526 clientccache
= child
.ccache
;
529 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
530 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", afs_error_message(kerror
), clientccache
);
534 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
536 increds
.times
.endtime
= 0;
538 if ( ( kerror
= krb5_get_credentials (child
.kcontext
, 0, clientccache
, &increds
, &v5credsp
) ) ) {
539 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
541 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_credentials: %s",
542 afs_error_message(kerror
));
548 cfg
->cell_in_principal
= cell_in_principal
;
552 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: get_credentials passed for %s", k5user
);
554 if ( v5credsp
->ticket
.length
>= MAXKTCTICKETLEN
) {
555 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: ticket size (%d) too big to fake",
556 v5credsp
->ticket
.length
);
560 memset(&token
, 0, sizeof(struct ktc_token
));
562 token
.startTime
= v5credsp
->times
.starttime
? v5credsp
->times
.starttime
: v5credsp
->times
.authtime
;
563 token
.endTime
= v5credsp
->times
.endtime
;
565 if (tkt_DeriveDesKey(v5credsp
->keyblock
.enctype
, v5credsp
->keyblock
.contents
,
566 v5credsp
->keyblock
.length
, &token
.sessionKey
) != 0) {
567 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: tkt_DeriveDesKey failure (enctype: %d)",
568 v5credsp
->keyblock
.enctype
);
571 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
572 token
.ticketLen
= v5credsp
->ticket
.length
;
573 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
577 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
579 buf
[v5credsp
->client
->data
[0].length
] = '\0';
580 if ( v5credsp
->client
->length
> 1 ) {
581 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
582 buflen
= strlen(buf
);
583 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
584 min(v5credsp
->client
->data
[1].length
,
585 MAXKTCNAMELEN
- strlen(buf
) - 1));
586 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
589 /* assemble the client */
590 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
591 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
592 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
594 buf
[v5credsp
->client
->realm
.length
] = '\0';
595 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
597 /* assemble the server's cell */
598 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
600 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
602 /* fill out the AFS ID in the client name */
603 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
604 * strange things seem to happen. */
607 afs_int32 viceId
= 0;
609 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
611 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
612 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
614 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
617 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
621 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
622 server
.name
, server
.instance
, server
.cell
);
624 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
625 client
.name
, client
.instance
, client
.cell
);
627 /* copy the resulting stuff into the child structure */
629 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
630 memcpy(&child
.token
, &token
, sizeof(child
.token
));
631 memcpy(&child
.server
, &server
, sizeof(child
.server
));
632 memcpy(&child
.client
, &client
, sizeof(child
.client
));
634 /* stuff the resulting token-related stuff into our shared token cache */
635 /* note, that anything that was set from a keytab is "persistant", and is immune
636 * from LRU-aging. This is because nothing but the process that's running as root
637 * can update these, and it's running every hour or so and renewing these tokens.
638 * and we don't want them aged out.
641 mytime
= oldest_time
= time(0);
643 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
646 pthread_rwlock_wrlock(sharedlock
);
648 rw_wrlock(sharedlock
);
651 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
652 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
653 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
655 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
657 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
658 child
.clientprincipal
) ) {
659 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
660 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
661 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
662 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
663 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
669 if ( stored
== -1 ) {
670 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
671 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
672 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
673 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
674 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
675 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
680 pthread_rwlock_unlock(sharedlock
);
682 rw_unlock(sharedlock
);
685 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
686 child
.clientprincipal
);
688 } else if ( ! usecached
) {
689 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
698 /* don't ask. Something about AIX. We're leaving it here.*/
699 /* write(2, "", 0); */
701 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
703 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
704 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
705 afs_error_message(rc
), k5user
);
706 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
707 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
708 afs_error_message(rc
), k5user
);
714 if (use_client_credentials
)
715 krb5_cc_close(child
.kcontext
, clientccache
);
717 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
718 if ( increds
.client
)
719 krb5_free_principal (child
.kcontext
, increds
.client
);
720 if ( increds
.server
)
721 krb5_free_principal (child
.kcontext
, increds
.server
);
723 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
725 krb5_free_principal (child
.kcontext
, kprinc
);
728 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
729 } else if ( kerror
) {
730 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, afs_error_message(kerror
));
732 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
735 return kerror
? (int) kerror
: (int) rc
;
740 int get_cfg_usertokens(waklog_config
*cfg
)
742 if (cfg
->usertokens
==WAKLOG_UNSET
)
743 return 0; /* default */
744 return cfg
->usertokens
;
747 int get_cfg_protect(waklog_config
*cfg
)
749 if (cfg
->protect
==WAKLOG_UNSET
)
750 return 0; /* default */
754 int get_cfg_disable_token_cache(waklog_config
*cfg
)
756 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
757 return 0; /* default */
758 return cfg
->disable_token_cache
;
763 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
767 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
769 memset(cfg
, 0, sizeof(waklog_config
));
770 cfg
->path
= "(server)";
771 cfg
->protect
= WAKLOG_UNSET
;
772 cfg
->usertokens
= WAKLOG_UNSET
;
773 cfg
->disable_token_cache
= WAKLOG_UNSET
;
775 cfg
->principal
= NULL
;
776 cfg
->default_principal
= NULL
;
777 cfg
->default_keytab
= NULL
;
778 cfg
->afs_cell
= NULL
;
779 cfg
->afs_cell_realm
= NULL
;
783 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
784 "mod_waklog: server config created.");
789 /* initialize with host-config information */
792 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
796 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
797 memset(cfg
, 0, sizeof(waklog_config
));
799 cfg
->path
= ap_pstrdup(p
, dir
);
800 cfg
->protect
= WAKLOG_UNSET
;
801 cfg
->usertokens
= WAKLOG_UNSET
;
802 cfg
->disable_token_cache
= WAKLOG_UNSET
;
804 cfg
->principal
= NULL
;
805 cfg
->default_principal
= NULL
;
806 cfg
->default_keytab
= NULL
;
807 cfg
->afs_cell
= NULL
;
808 cfg
->afs_cell_realm
= NULL
;
815 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
817 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
818 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
819 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
821 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
823 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
825 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
827 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
829 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
831 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
833 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
835 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
837 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
839 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
841 return (void *) merged
;
845 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
847 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
848 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
849 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
851 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
853 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
855 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
857 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
858 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
860 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
861 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
863 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
864 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
866 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
867 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
869 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
870 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
872 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
873 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
876 return (void *) merged
;
881 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
883 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
884 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
888 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
889 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
894 /* this adds a principal/keytab pair to get their tokens renewed by the
895 child process every few centons. */
897 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
901 if ( renewcount
>= SHARED_TABLE_SIZE
) {
902 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
903 decrease your tokens.");
907 /* check to see if it's already there */
909 for ( i
= 0; i
< renewcount
; i
++ ) {
910 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
915 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
916 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
917 renewtable
[renewcount
].lastrenewed
= 0;
923 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
925 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
926 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
928 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
929 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
931 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
932 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
934 add_to_renewtable(params
->pool
, keytab
, principal
);
942 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
944 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
945 waklog_config
*waklog_srvconfig
=
946 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
948 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
949 "mod_waklog: will use afs_cell: %s", file
);
951 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
952 waklog_srvconfig
->cell_in_principal
= 1;
954 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
955 waklog_srvconfig
->configured
= 1;
957 if (waklog_mconfig
!= NULL
) {
958 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
959 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
960 waklog_mconfig
->configured
= 1;
966 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
968 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
969 waklog_config
*waklog_srvconfig
=
970 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
972 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
973 "mod_waklog: will use afs_cell_realm: %s", file
);
975 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
977 if (waklog_mconfig
!= NULL
) {
978 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
984 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
986 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
987 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
989 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
991 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
992 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
994 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
995 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
997 /* this also gets set at the server level */
998 if ( mconfig
&& ( ! cfg
->path
) ) {
999 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
1000 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
1002 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
1003 return "Unable to set DefaultPrincipal outside of top level config!";
1006 add_to_renewtable( params
->pool
, keytab
, principal
);
1008 cfg
->configured
= 1;
1014 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1016 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1017 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1019 cfg
->usertokens
= flag
;
1021 cfg
->configured
= 1;
1023 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1024 "mod_waklog: waklog_use_user_tokens set");
1030 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1032 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1033 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1035 cfg
->disable_token_cache
= flag
;
1037 cfg
->configured
= 1;
1039 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1040 "mod_waklog: waklog_disable_token_cache set");
1046 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1048 apr_status_t
waklog_child_exit( void *sr
) {
1050 server_rec
*s
= (server_rec
*) sr
;
1053 if ( child
.ccache
) {
1054 krb5_cc_close(child
.kcontext
, child
.ccache
);
1057 if ( child
.kcontext
) {
1058 krb5_free_context(child
.kcontext
);
1061 /* forget our tokens */
1063 ktc_ForgetAllTokens ();
1065 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1066 "mod_waklog: waklog_child_exit complete");
1076 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1078 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1082 krb5_error_code code
;
1087 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1089 if ( !sharedspace
) {
1090 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1094 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1096 memset (&child
, 0, sizeof(child
));
1098 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1099 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1102 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1103 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1106 if ( pag_for_children
) {
1110 getModConfig (cfg
, s
);
1112 if ( cfg
->default_principal
!= NULL
) {
1113 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1114 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1117 cell
= strdup(cfg
->afs_cell
);
1118 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1121 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1124 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1125 "mod_waklog: child_init returned");
1130 command_rec waklog_cmds
[] = {
1132 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1133 "Use the supplied AFS cell (required)"),
1135 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1136 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1138 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1139 "enable waklog on a server, location, or directory basis"),
1141 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1142 "Set the default principal that the server runs as"),
1144 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1145 "Set the principal on a <Location>-specific basis"),
1147 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1148 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1150 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1151 "Use the requesting user tokens (from webauth)"),
1157 /* not currently using this */
1160 token_cleanup (void *data
)
1162 request_rec
*r
= (request_rec
*) data
;
1164 if (child
.token
.ticketLen
)
1166 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1168 ktc_ForgetAllTokens ();
1170 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1171 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1177 /* This function doesn't return anything but is passed to ap_bspawn_child on
1178 * Apache 1 which expects it to return a pid as an int. For want of better
1179 * understanding, err on the side of not changing Apache 1 code while fixing
1180 * the compile warning on Apache 2. */
1186 waklog_child_routine (void *data
, child_info
* pinfo
)
1189 server_rec
*s
= (server_rec
*) data
;
1190 krb5_error_code code
;
1192 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1197 getModConfig( cfg
, s
);
1199 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1201 memset (&child
, 0, sizeof(child
));
1203 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1204 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1207 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1208 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1211 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1213 /* need to do this so we can make PTS calls */
1214 cell
= strdup(cfg
->afs_cell
); /* stupid */
1215 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1217 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1221 for ( i
= 0; i
< renewcount
; ++i
) {
1222 renewtable
[i
].lastrenewed
= time(0);
1223 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1224 renewtable
[i
].keytab
);
1226 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1228 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1229 things that it needs to read */
1231 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1232 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1233 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1238 sharedspace
->renewcount
++;
1247 left
-= ( time(0) - when
);
1258 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1259 apr_pool_t
* ptemp
, server_rec
* s
)
1262 extern char *version
;
1267 int use_existing
= 1;
1269 char cache_file
[MAXNAMELEN
];
1271 pthread_rwlockattr_t rwlock_attr
;
1275 getModConfig (cfg
, s
);
1277 /* initialize_module() will be called twice, and if it's a DSO
1278 * then all static data from the first call will be lost. Only
1279 * set up our static data on the second call.
1280 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1281 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1284 if (cfg
->afs_cell
==NULL
) {
1285 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1286 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1287 /** clobber apache */
1293 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1294 apr_pool_cleanup_null
, s
->process
->pool
);
1298 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1299 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1301 if ( sharedspace
) {
1302 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1305 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1307 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1309 if ( errno
== ENOENT
) {
1311 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1313 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1314 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1318 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1322 if ( use_existing
== 0 ) {
1323 struct sharedspace_s bob
;
1324 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1325 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1326 if ( write(fd
, &bob
, sizeof(struct sharedspace_s
)) != sizeof(struct sharedspace_s
) ) {
1327 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: failed to write to our cache file %s (%d)", cache_file
, errno
);
1330 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1333 /* mmap the region */
1335 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1337 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1338 err
= unlink(cache_file
);
1340 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1342 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1345 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1351 #define locktype pthread_rwlock_t
1353 #define locktype rwlock_t
1356 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) != NULL
) {
1357 #ifndef use_pthreads
1358 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1360 pthread_rwlockattr_init(&rwlock_attr
);
1361 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1362 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1365 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1370 /* set our default tokens */
1372 oldrenewcount
= sharedspace
->renewcount
;
1374 pag_for_children
= 0;
1376 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1378 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1380 if (rv
== APR_INCHILD
)
1382 waklog_child_routine (s
, NULL
);
1386 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1388 /* parent and child */
1389 cfg
->forked
= proc
->pid
;
1390 pag_for_children
= 1;
1392 if ( use_existing
== 0 ) {
1393 /* wait here until our child process has gone and done it's renewing thing. */
1394 while( sharedspace
->renewcount
== oldrenewcount
) {
1395 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1400 if ( cfg
->default_principal
) {
1401 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1408 waklog_init (server_rec
* s
, MK_POOL
* p
)
1410 extern char *version
;
1414 int use_existing
= 1;
1416 char cache_file
[MAXNAMELEN
];
1418 pthread_rwlockattr_t rwlock_attr
;
1421 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1422 "mod_waklog: version %s initialized.", version
);
1424 if ( sharedspace
) {
1425 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1428 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1430 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1432 if ( errno
== ENOENT
) {
1434 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1436 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1437 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1441 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1446 if ( use_existing
== 0 ) {
1447 struct sharedspace_s bob
;
1448 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1449 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1450 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1451 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1454 /* mmap the region */
1456 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1457 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1460 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1466 #define locktype pthread_rwlock_t
1468 #define locktype rwlock_t
1471 /* mmap our shared space for our lock */
1472 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1473 #ifndef use_pthreads
1474 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1476 pthread_rwlockattr_init(&rwlock_attr
);
1477 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1478 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1481 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1486 /* set our default tokens */
1488 getModConfig (cfg
, s
);
1490 oldrenewcount
= sharedspace
->renewcount
;
1492 pag_for_children
= 0;
1494 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1497 pag_for_children
= 1;
1499 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1500 "mod_waklog: ap_bspawn_child: %d.", pid
);
1502 if ( use_existing
== 0 ) {
1503 /* wait here until our child process has gone and done it's renewing thing. */
1504 while( sharedspace
->renewcount
== oldrenewcount
) {
1505 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1510 if ( cfg
->default_principal
) {
1511 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1518 waklog_phase0 (request_rec
* r
)
1522 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1523 "mod_waklog: phase0 called");
1525 cfg
= retrieve_config(r
);
1527 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1528 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1529 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1530 } else if ( cfg
->default_principal
) {
1531 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1532 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1535 if (child
.token
.ticketLen
) {
1536 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1537 ktc_ForgetAllTokens();
1540 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1547 waklog_phase1 (request_rec
* r
)
1551 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1552 "mod_waklog: phase1 called");
1554 cfg
= retrieve_config(r
);
1556 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1557 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1558 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1559 } else if ( cfg
->default_principal
) {
1560 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1561 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1563 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1570 waklog_phase3 (request_rec
* r
)
1574 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1575 "mod_waklog: phase 3 called");
1577 cfg
= retrieve_config(r
);
1579 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1580 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1581 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1582 } else if ( cfg
->default_principal
) {
1583 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1584 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1586 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1593 waklog_phase6 (request_rec
* r
)
1597 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1598 "mod_waklog: phase6 called");
1600 cfg
= retrieve_config(r
);
1602 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1603 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1604 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1605 } else if ( cfg
->default_principal
) {
1606 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1607 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1609 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1616 waklog_phase7 (request_rec
* r
)
1621 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1622 "mod_waklog: phase7 called");
1624 cfg
= retrieve_config (r
);
1626 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1627 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1628 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1629 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1630 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1631 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1632 } else if ( cfg
->default_principal
) {
1633 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1634 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1636 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1637 if (child
.token
.ticketLen
) {
1638 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1639 ktc_ForgetAllTokens();
1651 waklog_phase9 (request_rec
* r
)
1655 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1656 "mod_waklog: phase9 called");
1658 getModConfig (cfg
, r
->server
);
1660 if ( cfg
->default_principal
) {
1661 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1662 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1675 waklog_new_connection (conn_rec
* c
1684 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1685 "mod_waklog: new_connection called: pid: %d", getpid ());
1687 getModConfig(cfg
, c
->base_server
);
1689 if ( cfg
->default_principal
) {
1690 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1691 cfg
->default_principal
);
1692 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1705 ** Here's a quick explaination for phase0 and phase2:
1706 ** Apache does a stat() on the path between phase0 and
1707 ** phase2, and must by ACLed rl to succeed. So, at
1708 ** phase0 we acquire credentials for umweb:servers from
1709 ** a keytab, and at phase2 we must ensure we remove them.
1711 ** Failure to "unlog" would be a security risk.
1714 waklog_phase2 (request_rec
* r
)
1717 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1718 "mod_waklog: phase2 called");
1720 if (child
.token
.ticketLen
)
1722 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1724 ktc_ForgetAllTokens ();
1726 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1727 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1731 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1732 "mod_waklog: phase2 returning");
1738 module MODULE_VAR_EXPORT waklog_module
= {
1739 STANDARD_MODULE_STUFF
,
1740 waklog_init
, /* module initializer */
1741 waklog_create_dir_config
, /* create per-dir config structures */
1742 waklog_merge_dir_config
, /* merge per-dir config structures */
1743 waklog_create_server_config
, /* create per-server config structures */
1744 waklog_merge_dir_config
, /* merge per-server config structures */
1745 waklog_cmds
, /* table of config file commands */
1746 NULL
, /* [#8] MIME-typed-dispatched handlers */
1747 waklog_phase1
, /* [#1] URI to filename translation */
1748 NULL
, /* [#4] validate user id from request */
1749 NULL
, /* [#5] check if the user is ok _here_ */
1750 waklog_phase3
, /* [#3] check access by host address */
1751 waklog_phase6
, /* [#6] determine MIME type */
1752 waklog_phase7
, /* [#7] pre-run fixups */
1753 waklog_phase9
, /* [#9] log a transaction */
1754 waklog_phase2
, /* [#2] header parser */
1755 waklog_child_init
, /* child_init */
1756 waklog_child_exit
, /* child_exit */
1757 waklog_phase0
/* [#0] post read-request */
1759 , NULL
, /* EAPI: add_module */
1760 NULL
, /* EAPI: remove_module */
1761 NULL
, /* EAPI: rewrite_command */
1762 waklog_new_connection
/* EAPI: new_connection */
1767 waklog_register_hooks (apr_pool_t
* p
)
1769 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1770 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1771 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1772 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1773 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1774 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1775 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1776 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1777 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1778 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1782 module AP_MODULE_DECLARE_DATA waklog_module
= {
1783 STANDARD20_MODULE_STUFF
,
1784 waklog_create_dir_config
, /* create per-dir conf structures */
1785 waklog_merge_dir_config
, /* merge per-dir conf structures */
1786 waklog_create_server_config
, /* create per-server conf structures */
1787 waklog_merge_dir_config
, /* merge per-server conf structures */
1788 waklog_cmds
, /* table of configuration directives */
1789 waklog_register_hooks
/* register hooks */