1 #define _LARGEFILE64_SOURCE
5 #include "http_config.h"
7 #include "http_protocol.h"
8 #include "http_request.h"
16 #include <sys/types.h>
20 #error "make sure you include the right stuff here"
24 #define MAXNAMELEN 1024
27 #ifdef STANDARD20_MODULE_STUFF
31 /********************* APACHE1 ******************************************************************************/
33 #include "ap_config.h"
35 #include <sys/ioccom.h>
37 #include <http_conf_globals.h>
39 #define MK_TABLE_GET ap_table_get
40 #define MK_TABLE_SET ap_table_set
41 #define command(name, func, var, type, usage) \
44 RSRC_CONF | ACCESS_CONF , type, usage }
47 /********************* APACHE2 ******************************************************************************/
49 #include <apr_strings.h>
50 #include <apr_base64.h>
51 #define ap_pcalloc apr_pcalloc
52 #define ap_pdupstr apr_pdupstr
53 #define ap_pstrdup apr_pstrdup
54 #define MK_POOL apr_pool_t
55 #define MK_TABLE_GET apr_table_get
56 #define MK_TABLE_SET apr_table_set
58 extern unixd_config_rec unixd_config
;
59 #define ap_user_id unixd_config.user_id
60 #define ap_group_id unixd_config.group_id
61 #define ap_user_name unixd_config.user_name
62 #define command(name, func, var, type, usage) \
63 AP_INIT_ ## type (name, (void*) func, \
65 RSRC_CONF | ACCESS_CONF, usage)
66 module AP_MODULE_DECLARE_DATA waklog_module
;
67 typedef struct { int dummy
; } child_info
;
68 const char *userdata_key
= "waklog_init";
71 /**************************************************************************************************/
75 #include <afs/venus.h>
77 #include <afs/dirpath.h>
78 #include <afs/ptuser.h>
81 #define TKT_LIFE ( 12 * 60 * 60 )
82 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
86 #define WAKLOG_UNSET 0
90 #define APLOG_DEBUG APLOG_ERR
93 /* this is used to turn off pag generation for the backround worker child during startup */
94 int pag_for_children
= 1;
102 int cell_in_principal
;
103 int disable_token_cache
;
106 char *default_principal
;
107 char *default_keytab
;
109 char *afs_cell_realm
;
117 struct ktc_token token
;
118 char clientprincipal
[MAXNAMELEN
];
119 krb5_context kcontext
;
121 struct ktc_principal server
;
122 struct ktc_principal client
;
124 } waklog_child_config
;
126 waklog_child_config child
;
128 struct tokencache_ent
{
129 char clientprincipal
[MAXNAMELEN
];
130 struct ktc_token token
;
131 struct ktc_principal client
;
132 struct ktc_principal server
;
137 #define SHARED_TABLE_SIZE 512
139 struct sharedspace_s
{
141 struct tokencache_ent sharedtokens
[SHARED_TABLE_SIZE
];
144 struct sharedspace_s
*sharedspace
= NULL
;
153 pthread_rwlock_t
*sharedlock
= NULL
;
155 rwlock_t
*sharedlock
= NULL
;
158 struct renew_ent renewtable
[SHARED_TABLE_SIZE
];
164 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
169 #include <sys/ioccom.h>
172 #include <afs/venus.h>
173 #include <afs/auth.h>
174 #include <afs/dirpath.h>
175 #include <afs/ptuser.h>
176 #include <rx/rxkad.h>
180 log_error (const char *file
, int line
, int level
, int status
,
181 const server_rec
* s
, const char *fmt
, ...)
187 vsnprintf (errstr
, 1024, fmt
, ap
);
191 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
==NULL
));
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
? k5user
: "NULL");
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... */
419 if (( ! usecached
) && ( k5user
)) {
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
!= WAKLOG_UNSET
) {
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
;
749 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
753 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
755 memset(cfg
, 0, sizeof(waklog_config
));
756 cfg
->path
= "(server)";
757 cfg
->protect
= WAKLOG_UNSET
;
758 cfg
->usertokens
= WAKLOG_UNSET
;
759 cfg
->disable_token_cache
= WAKLOG_UNSET
;
760 cfg
->keytab
= WAKLOG_UNSET
;
761 cfg
->principal
= WAKLOG_UNSET
;
762 cfg
->default_principal
= WAKLOG_UNSET
;
763 cfg
->default_keytab
= WAKLOG_UNSET
;
764 cfg
->afs_cell
= WAKLOG_UNSET
;
765 cfg
->afs_cell_realm
= WAKLOG_UNSET
;
769 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
770 "mod_waklog: server config created.");
775 /* initialize with host-config information */
778 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
782 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
783 memset(cfg
, 0, sizeof(waklog_config
));
785 cfg
->path
= ap_pstrdup(p
, dir
);
786 cfg
->protect
= WAKLOG_UNSET
;
787 cfg
->usertokens
= WAKLOG_UNSET
;
788 cfg
->disable_token_cache
= WAKLOG_UNSET
;
789 cfg
->keytab
= WAKLOG_UNSET
;
790 cfg
->principal
= WAKLOG_UNSET
;
791 cfg
->default_principal
= WAKLOG_UNSET
;
792 cfg
->default_keytab
= WAKLOG_UNSET
;
793 cfg
->afs_cell
= WAKLOG_UNSET
;
794 cfg
->afs_cell_realm
= WAKLOG_UNSET
;
801 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
803 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
804 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
805 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
807 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
809 merged
->path
= child
->path
!= WAKLOG_UNSET
? child
->path
: parent
->path
;
811 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
813 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
815 merged
->principal
= child
->principal
!= WAKLOG_UNSET
? child
->principal
: parent
->principal
;
817 merged
->keytab
= child
->keytab
!= WAKLOG_UNSET
? child
->keytab
: parent
->keytab
;
819 merged
->default_keytab
= child
->default_keytab
!= WAKLOG_UNSET
? child
->default_keytab
: parent
->default_keytab
;
821 merged
->default_principal
= child
->default_principal
!= WAKLOG_UNSET
? child
->default_principal
: parent
->default_principal
;
823 merged
->afs_cell
= child
->afs_cell
!= WAKLOG_UNSET
? child
->afs_cell
: parent
->afs_cell
;
825 merged
->afs_cell_realm
= child
->afs_cell_realm
!= WAKLOG_UNSET
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
827 return (void *) merged
;
831 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
833 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
834 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
835 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
837 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
839 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
841 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
843 merged
->keytab
= nconf
->keytab
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->keytab
) :
844 ( nconf
->keytab
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->keytab
) );
846 merged
->principal
= nconf
->principal
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->principal
) :
847 ( nconf
->principal
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->principal
) );
849 merged
->afs_cell
= nconf
->afs_cell
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->afs_cell
) :
850 ( nconf
->afs_cell
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->afs_cell
) );
852 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
853 ( nconf
->afs_cell_realm
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->afs_cell_realm
) );
855 merged
->default_keytab
= nconf
->default_keytab
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->default_keytab
) :
856 ( nconf
->default_keytab
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->default_keytab
) );
858 merged
->default_principal
= nconf
->default_principal
== WAKLOG_UNSET
? ap_pstrdup(p
, pconf
->default_principal
) :
859 ( nconf
->default_principal
== WAKLOG_UNSET
? WAKLOG_UNSET
: ap_pstrdup(p
, pconf
->default_principal
) );
862 return (void *) merged
;
867 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
869 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
870 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
874 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
875 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
880 /* this adds a principal/keytab pair to get their tokens renewed by the
881 child process every few centons. */
883 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
887 if ( renewcount
>= SHARED_TABLE_SIZE
) {
888 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
889 decrease your tokens.");
893 /* check to see if it's already there */
895 for ( i
= 0; i
< renewcount
; i
++ ) {
896 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
901 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
902 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
903 renewtable
[renewcount
].lastrenewed
= 0;
909 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
911 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
912 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
914 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
915 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
917 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
918 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
920 add_to_renewtable(params
->pool
, keytab
, principal
);
928 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
930 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
931 waklog_config
*waklog_srvconfig
=
932 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
934 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
935 "mod_waklog: will use afs_cell: %s", file
);
937 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
938 waklog_srvconfig
->cell_in_principal
= 1;
940 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
941 waklog_srvconfig
->configured
= 1;
943 if (waklog_mconfig
!= NULL
) {
944 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
945 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
946 waklog_mconfig
->configured
= 1;
952 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
954 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
955 waklog_config
*waklog_srvconfig
=
956 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
958 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
959 "mod_waklog: will use afs_cell_realm: %s", file
);
961 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
963 if (waklog_mconfig
!= NULL
) {
964 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
970 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
972 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
973 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
975 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
977 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
978 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
980 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
981 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
983 /* this also gets set at the server level */
984 if ( mconfig
&& ( ! cfg
->path
) ) {
985 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
986 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
988 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
989 return "Unable to set DefaultPrincipal outside of top level config!";
992 add_to_renewtable( params
->pool
, keytab
, principal
);
1000 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1002 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1003 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1005 cfg
->usertokens
= flag
;
1007 cfg
->configured
= 1;
1009 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1010 "mod_waklog: waklog_use_user_tokens set");
1016 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1018 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1019 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1021 cfg
->disable_token_cache
= flag
;
1023 cfg
->configured
= 1;
1025 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1026 "mod_waklog: waklog_disable_token_cache set");
1032 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1034 apr_status_t
waklog_child_exit( void *sr
) {
1036 server_rec
*s
= (server_rec
*) sr
;
1039 if ( child
.ccache
) {
1040 krb5_cc_close(child
.kcontext
, child
.ccache
);
1043 if ( child
.kcontext
) {
1044 krb5_free_context(child
.kcontext
);
1047 /* forget our tokens */
1049 ktc_ForgetAllTokens ();
1051 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1052 "mod_waklog: waklog_child_exit complete");
1062 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1064 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1068 krb5_error_code code
;
1073 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1075 if ( !sharedspace
) {
1076 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1080 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1082 memset (&child
, 0, sizeof(child
));
1084 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1085 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1088 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1089 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1092 if ( pag_for_children
) {
1096 getModConfig (cfg
, s
);
1098 if ( cfg
->default_principal
!= WAKLOG_UNSET
) {
1099 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1100 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1103 cell
= strdup(cfg
->afs_cell
);
1104 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1107 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1110 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1111 "mod_waklog: child_init returned");
1116 command_rec waklog_cmds
[] = {
1118 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1119 "Use the supplied AFS cell (required)"),
1121 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1122 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1124 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1125 "enable waklog on a server, location, or directory basis"),
1127 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1128 "Set the default principal that the server runs as"),
1130 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1131 "Set the principal on a <Location>-specific basis"),
1133 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1134 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1136 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1137 "Use the requesting user tokens (from webauth)"),
1143 /* not currently using this */
1146 token_cleanup (void *data
)
1148 request_rec
*r
= (request_rec
*) data
;
1150 if (child
.token
.ticketLen
)
1152 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1154 ktc_ForgetAllTokens ();
1156 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1157 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1164 waklog_child_routine (void *data
, child_info
* pinfo
)
1167 server_rec
*s
= (server_rec
*) data
;
1168 krb5_error_code code
;
1170 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1175 getModConfig( cfg
, s
);
1177 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1179 memset (&child
, 0, sizeof(child
));
1181 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1182 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1185 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1186 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1189 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1191 /* need to do this so we can make PTS calls */
1192 cell
= strdup(cfg
->afs_cell
); /* stupid */
1193 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1195 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1199 for ( i
= 0; i
< renewcount
; ++i
) {
1200 renewtable
[i
].lastrenewed
= time(0);
1201 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1202 renewtable
[i
].keytab
);
1204 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1206 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1207 things that it needs to read */
1209 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1210 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1211 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1216 sharedspace
->renewcount
++;
1225 left
-= ( time(0) - when
);
1236 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1237 apr_pool_t
* ptemp
, server_rec
* s
)
1240 extern char *version
;
1245 int use_existing
= 1;
1247 char cache_file
[MAXNAMELEN
];
1249 pthread_rwlockattr_t rwlock_attr
;
1253 getModConfig (cfg
, s
);
1255 /* initialize_module() will be called twice, and if it's a DSO
1256 * then all static data from the first call will be lost. Only
1257 * set up our static data on the second call.
1258 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1259 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1262 if (cfg
->afs_cell
==NULL
) {
1263 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1264 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1265 /** clobber apache */
1271 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1272 apr_pool_cleanup_null
, s
->process
->pool
);
1276 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1277 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1279 if ( sharedspace
) {
1280 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1283 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1285 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1287 if ( errno
== ENOENT
) {
1289 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1291 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1292 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1296 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1300 if ( use_existing
== 0 ) {
1301 struct sharedspace_s bob
;
1302 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1303 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1304 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1305 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1308 /* mmap the region */
1310 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1311 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1314 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1320 #define locktype pthread_rwlock_t
1322 #define locktype rwlock_t
1325 if ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) {
1326 #ifndef use_pthreads
1327 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1329 pthread_rwlockattr_init(&rwlock_attr
);
1330 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1331 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1334 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1339 /* set our default tokens */
1341 oldrenewcount
= sharedspace
->renewcount
;
1343 pag_for_children
= 0;
1345 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1347 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1349 if (rv
== APR_INCHILD
)
1351 waklog_child_routine (s
, NULL
);
1355 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1357 /* parent and child */
1358 cfg
->forked
= proc
->pid
;
1359 pag_for_children
= 1;
1361 if ( use_existing
== 0 ) {
1362 /* wait here until our child process has gone and done it's renewing thing. */
1363 while( sharedspace
->renewcount
== oldrenewcount
) {
1364 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1369 if ( cfg
->default_principal
) {
1370 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1377 waklog_init (server_rec
* s
, MK_POOL
* p
)
1379 extern char *version
;
1383 int use_existing
= 1;
1385 char cache_file
[MAXNAMELEN
];
1387 pthread_rwlockattr_t rwlock_attr
;
1390 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1391 "mod_waklog: version %s initialized.", version
);
1393 if ( sharedspace
) {
1394 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1397 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1399 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1401 if ( errno
== ENOENT
) {
1403 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1405 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1406 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1410 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1415 if ( use_existing
== 0 ) {
1416 struct sharedspace_s bob
;
1417 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1418 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1419 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1420 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1423 /* mmap the region */
1425 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1426 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1429 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1435 #define locktype pthread_rwlock_t
1437 #define locktype rwlock_t
1440 /* mmap our shared space for our lock */
1441 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1442 #ifndef use_pthreads
1443 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1445 pthread_rwlockattr_init(&rwlock_attr
);
1446 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1447 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1450 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1455 /* set our default tokens */
1457 getModConfig (cfg
, s
);
1459 oldrenewcount
= sharedspace
->renewcount
;
1461 pag_for_children
= 0;
1463 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1466 pag_for_children
= 1;
1468 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1469 "mod_waklog: ap_bspawn_child: %d.", pid
);
1471 if ( use_existing
== 0 ) {
1472 /* wait here until our child process has gone and done it's renewing thing. */
1473 while( sharedspace
->renewcount
== oldrenewcount
) {
1474 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1479 if ( cfg
->default_principal
) {
1480 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1487 waklog_phase0 (request_rec
* r
)
1491 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1492 "mod_waklog: phase0 called");
1494 cfg
= retrieve_config(r
);
1496 if ( cfg
->protect
&& cfg
->principal
) {
1497 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1498 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1499 } else if ( cfg
->default_principal
) {
1500 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1501 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1504 if (child
.token
.ticketLen
) {
1505 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1506 ktc_ForgetAllTokens();
1509 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1516 waklog_phase1 (request_rec
* r
)
1520 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1521 "mod_waklog: phase1 called");
1523 cfg
= retrieve_config(r
);
1525 if ( cfg
->protect
&& cfg
->principal
) {
1526 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1527 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1528 } else if ( cfg
->default_principal
) {
1529 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1530 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1532 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1539 waklog_phase3 (request_rec
* r
)
1543 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1544 "mod_waklog: phase 3 called");
1546 cfg
= retrieve_config(r
);
1548 if ( cfg
->protect
&& cfg
->principal
) {
1549 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1550 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1551 } else if ( cfg
->default_principal
) {
1552 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1553 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1555 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1562 waklog_phase6 (request_rec
* r
)
1566 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1567 "mod_waklog: phase6 called");
1569 cfg
= retrieve_config(r
);
1571 if ( cfg
->protect
&& cfg
->principal
) {
1572 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1573 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1574 } else if ( cfg
->default_principal
) {
1575 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1576 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1578 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1585 waklog_phase7 (request_rec
* r
)
1590 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1591 "mod_waklog: phase7 called");
1593 cfg
= retrieve_config (r
);
1595 if ( cfg
->protect
&& cfg
->usertokens
) {
1596 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1597 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1598 } else if ( cfg
->protect
&& cfg
->principal
) {
1599 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1600 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1601 } else if ( cfg
->default_principal
) {
1602 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1603 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1605 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1606 if (child
.token
.ticketLen
) {
1607 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1608 ktc_ForgetAllTokens();
1620 waklog_phase9 (request_rec
* r
)
1624 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1625 "mod_waklog: phase9 called");
1627 getModConfig (cfg
, r
->server
);
1629 if ( cfg
->default_principal
) {
1630 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1631 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1644 waklog_new_connection (conn_rec
* c
1653 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1654 "mod_waklog: new_connection called: pid: %d", getpid ());
1656 getModConfig(cfg
, c
->base_server
);
1658 if ( cfg
->default_principal
) {
1659 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1660 cfg
->default_principal
);
1661 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1674 ** Here's a quick explaination for phase0 and phase2:
1675 ** Apache does a stat() on the path between phase0 and
1676 ** phase2, and must by ACLed rl to succeed. So, at
1677 ** phase0 we acquire credentials for umweb:servers from
1678 ** a keytab, and at phase2 we must ensure we remove them.
1680 ** Failure to "unlog" would be a security risk.
1683 waklog_phase2 (request_rec
* r
)
1686 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1687 "mod_waklog: phase2 called");
1689 if (child
.token
.ticketLen
)
1691 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1693 ktc_ForgetAllTokens ();
1695 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1696 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1700 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1701 "mod_waklog: phase2 returning");
1707 module MODULE_VAR_EXPORT waklog_module
= {
1708 STANDARD_MODULE_STUFF
,
1709 waklog_init
, /* module initializer */
1710 waklog_create_dir_config
, /* create per-dir config structures */
1711 waklog_merge_dir_config
, /* merge per-dir config structures */
1712 waklog_create_server_config
, /* create per-server config structures */
1713 waklog_merge_dir_config
, /* merge per-server config structures */
1714 waklog_cmds
, /* table of config file commands */
1715 NULL
, /* [#8] MIME-typed-dispatched handlers */
1716 waklog_phase1
, /* [#1] URI to filename translation */
1717 NULL
, /* [#4] validate user id from request */
1718 NULL
, /* [#5] check if the user is ok _here_ */
1719 waklog_phase3
, /* [#3] check access by host address */
1720 waklog_phase6
, /* [#6] determine MIME type */
1721 waklog_phase7
, /* [#7] pre-run fixups */
1722 waklog_phase9
, /* [#9] log a transaction */
1723 waklog_phase2
, /* [#2] header parser */
1724 waklog_child_init
, /* child_init */
1725 waklog_child_exit
, /* child_exit */
1726 waklog_phase0
/* [#0] post read-request */
1728 , NULL
, /* EAPI: add_module */
1729 NULL
, /* EAPI: remove_module */
1730 NULL
, /* EAPI: rewrite_command */
1731 waklog_new_connection
/* EAPI: new_connection */
1736 waklog_register_hooks (apr_pool_t
* p
)
1738 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1739 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1740 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1741 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1742 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1743 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1744 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1745 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1746 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1747 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1751 module AP_MODULE_DECLARE_DATA waklog_module
= {
1752 STANDARD20_MODULE_STUFF
,
1753 waklog_create_dir_config
, /* create per-dir conf structures */
1754 waklog_merge_dir_config
, /* merge per-dir conf structures */
1755 waklog_create_server_config
, /* create per-server conf structures */
1756 waklog_merge_dir_config
, /* merge per-server conf structures */
1757 waklog_cmds
, /* table of configuration directives */
1758 waklog_register_hooks
/* register hooks */