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 <apr_strings.h>
49 #include <apr_base64.h>
50 #define ap_pcalloc apr_pcalloc
51 #define ap_pdupstr apr_pdupstr
52 #define ap_pstrdup apr_pstrdup
53 #define MK_POOL apr_pool_t
54 #define MK_TABLE_GET apr_table_get
55 #define MK_TABLE_SET apr_table_set
57 extern unixd_config_rec unixd_config
;
58 #define ap_user_id unixd_config.user_id
59 #define ap_group_id unixd_config.group_id
60 #define ap_user_name unixd_config.user_name
61 #define command(name, func, var, type, usage) \
62 AP_INIT_ ## type (name, (void*) func, \
64 RSRC_CONF | ACCESS_CONF, usage)
65 module AP_MODULE_DECLARE_DATA waklog_module
;
66 typedef struct { int dummy
; } child_info
;
67 const char *userdata_key
= "waklog_init";
70 /**************************************************************************************************/
75 #include <afs/param.h>
77 #include <afs/venus.h>
79 #include <afs/dirpath.h>
80 #include <afs/ptuser.h>
83 #define TKT_LIFE ( 12 * 60 * 60 )
84 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
86 #define WAKLOG_UNSET -1
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 );
168 log_error (const char *file
, int line
, int level
, int status
,
169 const server_rec
* s
, const char *fmt
, ...)
175 vsnprintf (errstr
, 1024, fmt
, ap
);
179 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, status
, s
, "(%d) %s", getpid(), errstr
);
181 ap_log_error (file
, line
, level
| APLOG_NOERRNO
, s
, "(%d) %s", getpid(), errstr
);
186 waklog_config
*retrieve_config(request_rec
*r
) {
191 if ( r
&& r
->main
) {
199 if ( my
&& ( cfg
= (waklog_config
*) ap_get_module_config(my
->per_dir_config
, &waklog_module
) ) ) {
202 getModConfig (cfg
, r
->server
);
209 /* set_auth -- sets the tokens of the current process to this user.
210 if "self" is set, it divines the user from the current requests' environment.
211 otherwise, it's gettng it from principal/keytab */
214 set_auth ( server_rec
*s
, request_rec
*r
, int self
, char *principal
, char *keytab
, int storeonly
) {
218 krb5_error_code kerror
= 0;
219 krb5_principal kprinc
= NULL
;
220 krb5_get_init_creds_opt kopts
;
223 krb5_ccache clientccache
;
224 struct ktc_principal server
= { "afs", "", "" };
225 struct ktc_principal client
;
226 struct ktc_token token
;
227 krb5_creds
*v5credsp
= NULL
;
228 krb5_keytab krb5kt
= NULL
;
229 char buf
[MAXNAMELEN
];
233 time_t oldest_time
= 0;
238 int cell_in_principal
;
240 int use_client_credentials
= 0;
242 char k5user
[MAXNAMELEN
] = "";
243 char *k5secret
= NULL
;
247 memset((char *) &increds
, 0, sizeof(increds
));
248 /* init some stuff if it ain't already */
249 /* XXX - In what situation will these not be initialized? */
251 if ( ! child
.kcontext
) {
252 if ((kerror
= krb5_init_context(&child
.kcontext
))) {
253 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize Kerberos context err=%d",
259 if ( !child
.ccache
) {
260 if ((kerror
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
))) {
261 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize credentials cache %s err=%d",
267 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
268 self
, principal
? principal
: "NULL",
269 keytab
? keytab
: "NULL",
271 k5path
? k5path
: "NULL",
273 (r
&& r
->user
) ? r
->user
: "NULL"
275 (r
&& r
->connection
&& r
->connection
->user
) ? r
->connection
->user
: "NULL"
279 /* pull the server config record that we care about... */
282 cfg
= retrieve_config(r
);
284 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
285 "mod_waklog: set_auth using no config" );
286 getModConfig (cfg
, s
);
290 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cfg is %d", cfg
);
295 /* pull out our principal name and stuff from the environment -- webauth better have sent
299 if ( ! ( r
&& r
->connection
&& r
->user
)) {
300 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no data available");
301 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: r->user=%s", (r
->user
==NULL
? "null" : r
->user
));
305 strncpy(k5user
, r
->user
, sizeof(k5user
));
307 if ( ! (r
&& r
->connection
&& r
->connection
->user
)) {
308 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: self authentication selected, but no username available");
312 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
314 /* if they've supplied a credentials cache */
315 k5path
= (char *) MK_TABLE_GET( r
->subprocess_env
, "KRB5CCNAME" );
317 /* the other thing we need is someone's password */
318 k5secret
= (char *) MK_TABLE_GET( r
->notes
, "ATTR_PASSWORD" );
320 /* we'll pick this up later after we've checked the cache and current state */
324 strncpy(k5user
, principal
, sizeof(k5user
));
328 strncpy(k5user
, r
->user
, sizeof(k5user
));
331 if (r
&& r
->connection
&& r
->connection
->user
) {
332 strncpy(k5user
, r
->connection
->user
, sizeof(k5user
));
336 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth: k5user=%s", k5user
);
339 /* see if we should just go ahead and ignore this call, since we already should be set to these
345 pthread_rwlock_rdlock( sharedlock
);
347 rw_rdlock( sharedlock
);
350 for ( i
= 0; i
< SHARED_TABLE_SIZE
; ++i
) {
352 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
354 if ( ( !strcmp( k5user
,
355 sharedspace
->sharedtokens
[i
].clientprincipal
) ) &&
356 ( sharedspace
->sharedtokens
[i
].token
.endTime
> mytime
) ) {
358 if ( ! memcmp(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
) ) ) {
364 /* copy the token out of the cache and into the child object */
366 strcpy(child
.clientprincipal
, sharedspace
->sharedtokens
[i
].clientprincipal
);
367 memcpy(&child
.token
, &sharedspace
->sharedtokens
[i
].token
, sizeof(child
.token
));
368 memcpy(&child
.server
, &sharedspace
->sharedtokens
[i
].server
, sizeof(child
.server
));
369 memcpy(&child
.client
, &sharedspace
->sharedtokens
[i
].client
, sizeof(child
.client
));
371 /* set our last used time thing */
372 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
382 /* release the lock on the token cache */
384 pthread_rwlock_unlock( sharedlock
);
386 rw_unlock( sharedlock
);
390 /* release the lock on the token cache */
391 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
,
392 "mod_waklog: set_auth using shared token %d for %s", i
, k5user
);
396 /* if this is something that was in the cache, and it's the same as the token we already have stored,
397 and we weren't calling this just to renew it... */
399 if ( usecached
&& indentical
) {
400 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: token is identical for %s", k5user
);
406 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
409 /* clear out the creds structure */
410 memset((void *) &v5creds
, 0, sizeof(v5creds
));
412 /* create a principal out of our k5user string */
414 if ( ( kerror
= krb5_parse_name (child
.kcontext
, k5user
, &kprinc
) ) ) {
415 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror
) );
419 /* create the credentials options */
421 krb5_get_init_creds_opt_init ( &kopts
);
422 krb5_get_init_creds_opt_set_tkt_life ( &kopts
, TKT_LIFE
);
423 krb5_get_init_creds_opt_set_renew_life ( &kopts
, 0 );
424 krb5_get_init_creds_opt_set_forwardable ( &kopts
, 0 );
425 krb5_get_init_creds_opt_set_proxiable ( &kopts
, 0 );
427 if ( keytab
|| k5secret
) {
430 /* if we've been passed a keytab, we're going to be getting our credentials from it */
432 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using keytab %s", keytab
);
434 if ( ( kerror
= krb5_kt_resolve(child
.kcontext
, keytab
, &krb5kt
) ) ) {
435 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
,
436 "mod_waklog: krb5_kt_resolve %s", error_message(kerror
) );
440 if ((kerror
= krb5_get_init_creds_keytab (child
.kcontext
, &v5creds
,
441 kprinc
, krb5kt
, 0, NULL
, &kopts
) ) ) {
442 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_keytab %s",
443 error_message(kerror
) );
446 } else if (k5secret
) {
448 /* If the WebSSO is lame enough to provide a secret, then try and use that to get a token */
450 if ((kerror
= krb5_get_init_creds_password ( child
.kcontext
, &v5creds
,
451 kprinc
, k5secret
, NULL
, NULL
, 0, NULL
, &kopts
) ) ) {
452 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_get_init_creds_password %s",
453 error_message(kerror
) );
454 /* nuke the password so it doesn't end up in core files */
455 memset(k5secret
, 0, sizeof(k5secret
));
459 memset(k5secret
, 0, sizeof(k5secret
));
462 /* initialize the credentials cache and store the stuff we just got */
463 if ( ( kerror
= krb5_cc_initialize (child
.kcontext
, child
.ccache
, kprinc
) ) ) {
464 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: init credentials cache %s",
465 error_message(kerror
));
469 if ( ( kerror
= krb5_cc_store_cred(child
.kcontext
, child
.ccache
, &v5creds
) ) ) {
470 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot store credentials %s",
471 error_message(kerror
));
475 krb5_free_cred_contents(child
.kcontext
, &v5creds
);
478 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: store cred %s", error_message(kerror
));
482 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: kinit ok for %s", k5user
);
485 /* If we've got a path to a credentials cache, then try and use that. We can't just
486 * replace child.creds, because we want to ensure that only this request gets access to
489 if ( ( kerror
= krb5_cc_resolve(child
.kcontext
, k5path
, &clientccache
) ) ) {
490 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
,
491 "mod_waklog: can't open provided credentials cache %s err=%d",
496 use_client_credentials
= 1;
499 /* now, to the 'aklog' portion of our program. */
501 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
502 for(attempt
= 0; attempt
<= 1; attempt
++) {
503 strncpy( buf
, "afs", sizeof(buf
) - 1 );
504 cell_in_principal
= (cfg
->cell_in_principal
+ attempt
) % 2;
506 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: cell_in_principal=%d", cell_in_principal
);
507 if (cell_in_principal
) {
508 strncat(buf
, "/", sizeof(buf
) - strlen(buf
) - 1);
509 strncat(buf
, cfg
->afs_cell
, sizeof(buf
) - strlen(buf
) - 1);
511 if (cfg
->afs_cell_realm
!= NULL
) {
512 strncat(buf
, "@", sizeof(buf
) - strlen(buf
) - 1);
513 strncat(buf
, cfg
->afs_cell_realm
, sizeof(buf
) - strlen(buf
) - 1);
516 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: using AFS principal: %s", buf
);
518 if ((kerror
= krb5_parse_name (child
.kcontext
, buf
, &increds
.server
))) {
519 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_parse name %s", error_message(kerror
));
523 if (!use_client_credentials
) {
524 clientccache
= child
.ccache
;
527 if ((kerror
= krb5_cc_get_principal(child
.kcontext
, clientccache
, &increds
.client
))) {
528 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: krb5_cc_get_princ %s %p", error_message(kerror
), clientccache
);
532 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: retrieved data from ccache for %s", k5user
);
534 increds
.times
.endtime
= 0;
536 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
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 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 memmove( &token
.sessionKey
, v5credsp
->keyblock
.contents
, v5credsp
->keyblock
.length
);
566 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
567 token
.ticketLen
= v5credsp
->ticket
.length
;
568 memmove( token
.ticket
, v5credsp
->ticket
.data
, token
.ticketLen
);
572 memmove( buf
, v5credsp
->client
->data
[0].data
, min(v5credsp
->client
->data
[0].length
,
574 buf
[v5credsp
->client
->data
[0].length
] = '\0';
575 if ( v5credsp
->client
->length
> 1 ) {
576 strncat(buf
, ".", sizeof(buf
) - strlen(buf
) - 1);
577 buflen
= strlen(buf
);
578 memmove(buf
+ buflen
, v5credsp
->client
->data
[1].data
,
579 min(v5credsp
->client
->data
[1].length
,
580 MAXKTCNAMELEN
- strlen(buf
) - 1));
581 buf
[buflen
+ v5credsp
->client
->data
[1].length
] = '\0';
584 /* assemble the client */
585 strncpy(client
.name
, buf
, sizeof(client
.name
) - 1 );
586 strncpy(client
.instance
, "", sizeof(client
.instance
) - 1 );
587 memmove(buf
, v5credsp
->client
->realm
.data
, min(v5credsp
->client
->realm
.length
,
589 buf
[v5credsp
->client
->realm
.length
] = '\0';
590 strncpy(client
.cell
, buf
, sizeof(client
.cell
));
592 /* assemble the server's cell */
593 strncpy(server
.cell
, cfg
->afs_cell
, sizeof(server
.cell
) - 1);
595 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: preparing to init PTS connection for %s", server
.cell
);
597 /* fill out the AFS ID in the client name */
598 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
599 * strange things seem to happen. */
602 afs_int32 viceId
= 0;
604 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: making PTS call to look up %s", client
.name
);
606 if ( ( rc
= pr_SNameToId( client
.name
, &viceId
) ) == 0 ) {
607 snprintf( client
.name
, sizeof(client
.name
), "AFS ID %d", viceId
);
609 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned error %d ", rc
);
612 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: PTS call returned %s ", client
.name
);
616 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: server: name %s, instance %s, cell %s",
617 server
.name
, server
.instance
, server
.cell
);
619 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: client: name %s, instance %s, cell %s",
620 client
.name
, client
.instance
, client
.cell
);
622 /* copy the resulting stuff into the child structure */
624 strncpy(child
.clientprincipal
, k5user
, sizeof(child
.clientprincipal
));
625 memcpy(&child
.token
, &token
, sizeof(child
.token
));
626 memcpy(&child
.server
, &server
, sizeof(child
.server
));
627 memcpy(&child
.client
, &client
, sizeof(child
.client
));
629 /* stuff the resulting token-related stuff into our shared token cache */
630 /* note, that anything that was set from a keytab is "persistant", and is immune
631 * from LRU-aging. This is because nothing but the process that's running as root
632 * can update these, and it's running every hour or so and renewing these tokens.
633 * and we don't want them aged out.
636 mytime
= oldest_time
= time(0);
638 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waiting for shared space for %s ", k5user
);
641 pthread_rwlock_wrlock(sharedlock
);
643 rw_wrlock(sharedlock
);
646 for( i
= ( SHARED_TABLE_SIZE
- 1 ); i
>= 0; i
-- ) {
647 if ( ( sharedspace
->sharedtokens
[i
].lastused
<= oldest_time
) &&
648 ( sharedspace
->sharedtokens
[i
].persist
== 0 ) ) {
650 oldest_time
= sharedspace
->sharedtokens
[i
].lastused
;
652 if ( ! strcmp ( sharedspace
->sharedtokens
[i
].clientprincipal
,
653 child
.clientprincipal
) ) {
654 memcpy(&sharedspace
->sharedtokens
[i
].token
, &child
.token
, sizeof(child
.token
) );
655 memcpy(&sharedspace
->sharedtokens
[i
].client
, &child
.client
, sizeof(child
.client
) );
656 memcpy(&sharedspace
->sharedtokens
[i
].server
, &child
.server
, sizeof(child
.server
) );
657 sharedspace
->sharedtokens
[i
].lastused
= mytime
;
658 sharedspace
->sharedtokens
[i
].persist
= keytab
? 1 : 0;
664 if ( stored
== -1 ) {
665 memcpy(&sharedspace
->sharedtokens
[oldest
].token
, &child
.token
, sizeof(child
.token
) );
666 memcpy(&sharedspace
->sharedtokens
[oldest
].client
, &child
.client
, sizeof(child
.client
) );
667 memcpy(&sharedspace
->sharedtokens
[oldest
].server
, &child
.server
, sizeof(child
.server
) );
668 strcpy(sharedspace
->sharedtokens
[oldest
].clientprincipal
, child
.clientprincipal
);
669 sharedspace
->sharedtokens
[oldest
].lastused
= mytime
;
670 sharedspace
->sharedtokens
[oldest
].persist
= keytab
? 1 : 0;
675 pthread_rwlock_unlock(sharedlock
);
677 rw_unlock(sharedlock
);
680 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: token stored in slot %d for %s", stored
,
681 child
.clientprincipal
);
683 } else if ( ! usecached
) {
684 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth divergent case");
693 /* don't ask. Something about AIX. We're leaving it here.*/
694 /* write(2, "", 0); */
696 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
698 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
699 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: settoken returned %s for %s -- trying again",
700 error_message(rc
), k5user
);
701 if ((rc
= ktc_SetToken(&child
.server
, &child
.token
, &child
.client
, 0))) {
702 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: settoken2 returned %s for %s",
703 error_message(rc
), k5user
);
709 if (use_client_credentials
)
710 krb5_cc_close(child
.kcontext
, clientccache
);
712 krb5_free_cred_contents(child
.kcontext
, v5credsp
);
713 if ( increds
.client
)
714 krb5_free_principal (child
.kcontext
, increds
.client
);
715 if ( increds
.server
)
716 krb5_free_principal (child
.kcontext
, increds
.server
);
718 (void) krb5_kt_close(child
.kcontext
, krb5kt
);
720 krb5_free_principal (child
.kcontext
, kprinc
);
723 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with %d", rc
);
724 } else if ( kerror
) {
725 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror
, error_message(kerror
));
727 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: set_auth ending ok");
730 return kerror
? (int) kerror
: (int) rc
;
735 int get_cfg_usertokens(waklog_config
*cfg
)
737 if (cfg
->usertokens
==WAKLOG_UNSET
)
738 return 0; /* default */
739 return cfg
->usertokens
;
742 int get_cfg_protect(waklog_config
*cfg
)
744 if (cfg
->protect
==WAKLOG_UNSET
)
745 return 0; /* default */
749 int get_cfg_disable_token_cache(waklog_config
*cfg
)
751 if (cfg
->disable_token_cache
==WAKLOG_UNSET
)
752 return 0; /* default */
753 return cfg
->disable_token_cache
;
758 waklog_create_server_config (MK_POOL
* p
, server_rec
* s
)
762 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
764 memset(cfg
, 0, sizeof(waklog_config
));
765 cfg
->path
= "(server)";
766 cfg
->protect
= WAKLOG_UNSET
;
767 cfg
->usertokens
= WAKLOG_UNSET
;
768 cfg
->disable_token_cache
= WAKLOG_UNSET
;
770 cfg
->principal
= NULL
;
771 cfg
->default_principal
= NULL
;
772 cfg
->default_keytab
= NULL
;
773 cfg
->afs_cell
= NULL
;
774 cfg
->afs_cell_realm
= NULL
;
778 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
779 "mod_waklog: server config created.");
784 /* initialize with host-config information */
787 waklog_create_dir_config (MK_POOL
* p
, char *dir
)
791 cfg
= (waklog_config
*) ap_pcalloc (p
, sizeof (waklog_config
));
792 memset(cfg
, 0, sizeof(waklog_config
));
794 cfg
->path
= ap_pstrdup(p
, dir
);
795 cfg
->protect
= WAKLOG_UNSET
;
796 cfg
->usertokens
= WAKLOG_UNSET
;
797 cfg
->disable_token_cache
= WAKLOG_UNSET
;
799 cfg
->principal
= NULL
;
800 cfg
->default_principal
= NULL
;
801 cfg
->default_keytab
= NULL
;
802 cfg
->afs_cell
= NULL
;
803 cfg
->afs_cell_realm
= NULL
;
810 static void *waklog_merge_dir_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
812 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
813 waklog_config
*parent
= ( waklog_config
* ) parent_conf
;
814 waklog_config
*child
= ( waklog_config
* ) newloc_conf
;
816 merged
->protect
= child
->protect
!= WAKLOG_UNSET
? child
->protect
: parent
->protect
;
818 merged
->path
= child
->path
!= NULL
? child
->path
: parent
->path
;
820 merged
->usertokens
= child
->usertokens
!= WAKLOG_UNSET
? child
->usertokens
: parent
->usertokens
;
822 merged
->disable_token_cache
= child
->disable_token_cache
!= WAKLOG_UNSET
? child
->disable_token_cache
: parent
->disable_token_cache
;
824 merged
->principal
= child
->principal
!= NULL
? child
->principal
: parent
->principal
;
826 merged
->keytab
= child
->keytab
!= NULL
? child
->keytab
: parent
->keytab
;
828 merged
->default_keytab
= child
->default_keytab
!= NULL
? child
->default_keytab
: parent
->default_keytab
;
830 merged
->default_principal
= child
->default_principal
!= NULL
? child
->default_principal
: parent
->default_principal
;
832 merged
->afs_cell
= child
->afs_cell
!= NULL
? child
->afs_cell
: parent
->afs_cell
;
834 merged
->afs_cell_realm
= child
->afs_cell_realm
!= NULL
? child
->afs_cell_realm
: parent
->afs_cell_realm
;
836 return (void *) merged
;
840 static void *waklog_merge_server_config(MK_POOL
*p
, void *parent_conf
, void *newloc_conf
) {
842 waklog_config
*merged
= ( waklog_config
* ) ap_pcalloc(p
, sizeof(waklog_config
) );
843 waklog_config
*pconf
= ( waklog_config
* ) parent_conf
;
844 waklog_config
*nconf
= ( waklog_config
* ) newloc_conf
;
846 merged
->protect
= nconf
->protect
== WAKLOG_UNSET
? pconf
->protect
: nconf
->protect
;
848 merged
->usertokens
= nconf
->usertokens
== WAKLOG_UNSET
? pconf
->usertokens
: nconf
->usertokens
;
850 merged
->disable_token_cache
= nconf
->disable_token_cache
== WAKLOG_UNSET
? pconf
->disable_token_cache
: nconf
->disable_token_cache
;
852 merged
->keytab
= nconf
->keytab
== NULL
? ap_pstrdup(p
, pconf
->keytab
) :
853 ( nconf
->keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->keytab
) );
855 merged
->principal
= nconf
->principal
== NULL
? ap_pstrdup(p
, pconf
->principal
) :
856 ( nconf
->principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->principal
) );
858 merged
->afs_cell
= nconf
->afs_cell
== NULL
? ap_pstrdup(p
, pconf
->afs_cell
) :
859 ( nconf
->afs_cell
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell
) );
861 merged
->afs_cell_realm
= nconf
->afs_cell_realm
== NULL
? ap_pstrdup(p
, pconf
->afs_cell_realm
) :
862 ( nconf
->afs_cell_realm
== NULL
? NULL
: ap_pstrdup(p
, nconf
->afs_cell_realm
) );
864 merged
->default_keytab
= nconf
->default_keytab
== NULL
? ap_pstrdup(p
, pconf
->default_keytab
) :
865 ( nconf
->default_keytab
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_keytab
) );
867 merged
->default_principal
= nconf
->default_principal
== NULL
? ap_pstrdup(p
, pconf
->default_principal
) :
868 ( nconf
->default_principal
== NULL
? NULL
: ap_pstrdup(p
, nconf
->default_principal
) );
871 return (void *) merged
;
876 set_waklog_enabled (cmd_parms
* params
, void *mconfig
, int flag
)
878 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
879 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
883 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
884 "mod_waklog: waklog_enabled set on %s", cfg
->path
? cfg
->path
: "NULL");
889 /* this adds a principal/keytab pair to get their tokens renewed by the
890 child process every few centons. */
892 void add_to_renewtable(MK_POOL
*p
, char *keytab
, char *principal
) {
896 if ( renewcount
>= SHARED_TABLE_SIZE
) {
897 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, NULL
, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
898 decrease your tokens.");
902 /* check to see if it's already there */
904 for ( i
= 0; i
< renewcount
; i
++ ) {
905 if ( ! strcmp(renewtable
[i
].principal
, principal
) ) {
910 renewtable
[renewcount
].keytab
= ap_pstrdup(p
, keytab
);
911 renewtable
[renewcount
].principal
= ap_pstrdup(p
, principal
);
912 renewtable
[renewcount
].lastrenewed
= 0;
918 set_waklog_location_principal (cmd_parms
*params
, void *mconfig
, char *principal
, char *keytab
)
920 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
921 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
923 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
924 "mod_waklog: configuring principal: %s, keytab: %s", principal
, keytab
);
926 cfg
->principal
= ap_pstrdup(params
->pool
, principal
);
927 cfg
->keytab
= ap_pstrdup (params
->pool
, keytab
);
929 add_to_renewtable(params
->pool
, keytab
, principal
);
937 set_waklog_afs_cell (cmd_parms
* params
, void *mconfig
, char *file
)
939 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
940 waklog_config
*waklog_srvconfig
=
941 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
943 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
944 "mod_waklog: will use afs_cell: %s", file
);
946 // Prefer afs/cell@REALM over afs@REALM, just like the OpenAFS tools
947 waklog_srvconfig
->cell_in_principal
= 1;
949 waklog_srvconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
950 waklog_srvconfig
->configured
= 1;
952 if (waklog_mconfig
!= NULL
) {
953 waklog_mconfig
->cell_in_principal
= waklog_srvconfig
->cell_in_principal
;
954 waklog_mconfig
->afs_cell
= ap_pstrdup (params
->pool
, file
);
955 waklog_mconfig
->configured
= 1;
961 set_waklog_afs_cell_realm (cmd_parms
* params
, void *mconfig
, char *file
)
963 waklog_config
*waklog_mconfig
= ( waklog_config
* ) mconfig
;
964 waklog_config
*waklog_srvconfig
=
965 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
967 log_error (APLOG_MARK
, APLOG_INFO
, 0, params
->server
,
968 "mod_waklog: will use afs_cell_realm: %s", file
);
970 waklog_srvconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
972 if (waklog_mconfig
!= NULL
) {
973 waklog_mconfig
->afs_cell_realm
= ap_pstrdup (params
->pool
, file
);
979 set_waklog_default_principal (cmd_parms
* params
, void *mconfig
, char *principal
, char *keytab
)
981 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
982 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
984 waklog_config
*srvcfg
= ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
986 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
987 "mod_waklog: set default princ/keytab: %s, %s for %s", principal
, keytab
, cfg
->path
? cfg
->path
: "NULL");
989 cfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
990 cfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
992 /* this also gets set at the server level */
993 if ( mconfig
&& ( ! cfg
->path
) ) {
994 srvcfg
->default_principal
= ap_pstrdup (params
->pool
, principal
);
995 srvcfg
->default_keytab
= ap_pstrdup(params
->pool
, keytab
);
997 log_error(APLOG_MARK
, APLOG_ERR
, 0, params
->server
, "only able to set default principal on a global level!");
998 return "Unable to set DefaultPrincipal outside of top level config!";
1001 add_to_renewtable( params
->pool
, keytab
, principal
);
1003 cfg
->configured
= 1;
1009 set_waklog_use_usertokens (cmd_parms
* params
, void *mconfig
, int flag
)
1011 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1012 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1014 cfg
->usertokens
= flag
;
1016 cfg
->configured
= 1;
1018 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1019 "mod_waklog: waklog_use_user_tokens set");
1025 set_waklog_disable_token_cache (cmd_parms
* params
, void *mconfig
, int flag
)
1027 waklog_config
*cfg
= mconfig
? ( waklog_config
* ) mconfig
:
1028 ( waklog_config
* ) ap_get_module_config(params
->server
->module_config
, &waklog_module
);
1030 cfg
->disable_token_cache
= flag
;
1032 cfg
->configured
= 1;
1034 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, params
->server
,
1035 "mod_waklog: waklog_disable_token_cache set");
1041 static void waklog_child_exit( server_rec
*s
, MK_POOL
*p
) {
1043 apr_status_t
waklog_child_exit( void *sr
) {
1045 server_rec
*s
= (server_rec
*) sr
;
1048 if ( child
.ccache
) {
1049 krb5_cc_close(child
.kcontext
, child
.ccache
);
1052 if ( child
.kcontext
) {
1053 krb5_free_context(child
.kcontext
);
1056 /* forget our tokens */
1058 ktc_ForgetAllTokens ();
1060 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1061 "mod_waklog: waklog_child_exit complete");
1071 waklog_child_init (MK_POOL
* p
, server_rec
* s
)
1073 waklog_child_init (server_rec
* s
, MK_POOL
* p
)
1077 krb5_error_code code
;
1082 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1084 if ( !sharedspace
) {
1085 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: child_init called without shared space? %d", getpid());
1089 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init called for pid %d", getpid());
1091 memset (&child
, 0, sizeof(child
));
1093 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1094 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1097 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1098 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1101 if ( pag_for_children
) {
1105 getModConfig (cfg
, s
);
1107 if ( cfg
->default_principal
!= NULL
) {
1108 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: child_init setting default user %s, %s", cfg
->default_principal
, cfg
->default_keytab
);
1109 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1112 cell
= strdup(cfg
->afs_cell
);
1113 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1116 apr_pool_cleanup_register(p
, s
, waklog_child_exit
, apr_pool_cleanup_null
);
1119 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1120 "mod_waklog: child_init returned");
1125 command_rec waklog_cmds
[] = {
1127 command ("WaklogAFSCell", set_waklog_afs_cell
, 0, TAKE1
,
1128 "Use the supplied AFS cell (required)"),
1130 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm
, 0, TAKE1
,
1131 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1133 command ("WaklogEnabled", set_waklog_enabled
, 0, FLAG
,
1134 "enable waklog on a server, location, or directory basis"),
1136 command ("WaklogDefaultPrincipal", set_waklog_default_principal
, 0, TAKE2
,
1137 "Set the default principal that the server runs as"),
1139 command ("WaklogLocationPrincipal", set_waklog_location_principal
, 0, TAKE2
,
1140 "Set the principal on a <Location>-specific basis"),
1142 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache
, 0, FLAG
,
1143 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1145 command ("WaklogUseUserTokens", set_waklog_use_usertokens
, 0, FLAG
,
1146 "Use the requesting user tokens (from webauth)"),
1152 /* not currently using this */
1155 token_cleanup (void *data
)
1157 request_rec
*r
= (request_rec
*) data
;
1159 if (child
.token
.ticketLen
)
1161 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1163 ktc_ForgetAllTokens ();
1165 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1166 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1173 waklog_child_routine (void *data
, child_info
* pinfo
)
1176 server_rec
*s
= (server_rec
*) data
;
1177 krb5_error_code code
;
1179 time_t sleep_time
= ( TKT_LIFE
/ 2 ) ;
1184 getModConfig( cfg
, s
);
1186 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1188 memset (&child
, 0, sizeof(child
));
1190 if ( ( code
= krb5_init_context(&child
.kcontext
) ) ) {
1191 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't init kerberos context %d", code
);
1194 if ( ( code
= krb5_cc_resolve(child
.kcontext
, "MEMORY:tmpcache", &child
.ccache
) ) ) {
1195 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: can't initialize in-memory credentials cache %d", code
);
1198 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: about to pr_Initialize");
1200 /* need to do this so we can make PTS calls */
1201 cell
= strdup(cfg
->afs_cell
); /* stupid */
1202 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR
, cell
);
1204 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: still here");
1208 for ( i
= 0; i
< renewcount
; ++i
) {
1209 renewtable
[i
].lastrenewed
= time(0);
1210 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable
[i
].principal
,
1211 renewtable
[i
].keytab
);
1213 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 1 );
1215 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1216 things that it needs to read */
1218 if ( cfg
&& cfg
->default_principal
&& ( ! strcmp(cfg
->default_principal
, renewtable
[i
].principal
) ) ) {
1219 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: renewing/setting default tokens" );
1220 set_auth( s
, NULL
, 0, renewtable
[i
].principal
, renewtable
[i
].keytab
, 0 );
1225 sharedspace
->renewcount
++;
1234 left
-= ( time(0) - when
);
1245 waklog_init_handler (apr_pool_t
* p
, apr_pool_t
* plog
,
1246 apr_pool_t
* ptemp
, server_rec
* s
)
1249 extern char *version
;
1254 int use_existing
= 1;
1256 char cache_file
[MAXNAMELEN
];
1258 pthread_rwlockattr_t rwlock_attr
;
1262 getModConfig (cfg
, s
);
1264 /* initialize_module() will be called twice, and if it's a DSO
1265 * then all static data from the first call will be lost. Only
1266 * set up our static data on the second call.
1267 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1268 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1271 if (cfg
->afs_cell
==NULL
) {
1272 log_error (APLOG_MARK
, APLOG_ERR
, 0, s
,
1273 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1274 /** clobber apache */
1280 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1281 apr_pool_cleanup_null
, s
->process
->pool
);
1285 log_error (APLOG_MARK
, APLOG_INFO
, 0, s
,
1286 "mod_waklog: version %s initialized for cell %s", version
, cfg
->afs_cell
);
1288 if ( sharedspace
) {
1289 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1292 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1294 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1296 if ( errno
== ENOENT
) {
1298 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1300 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1301 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1305 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1309 if ( use_existing
== 0 ) {
1310 struct sharedspace_s bob
;
1311 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1312 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1313 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1314 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1317 /* mmap the region */
1319 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != MAP_FAILED
) {
1321 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1322 err
= unlink(cache_file
);
1324 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: unable to delete %s due to %d", cache_file
, errno
);
1326 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared cache unlinked (will be deleted when Apache quits)");
1329 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1335 #define locktype pthread_rwlock_t
1337 #define locktype rwlock_t
1340 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) != NULL
) {
1341 #ifndef use_pthreads
1342 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1344 pthread_rwlockattr_init(&rwlock_attr
);
1345 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1346 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1349 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1354 /* set our default tokens */
1356 oldrenewcount
= sharedspace
->renewcount
;
1358 pag_for_children
= 0;
1360 proc
= (apr_proc_t
*) ap_pcalloc (s
->process
->pool
, sizeof (apr_proc_t
));
1362 rv
= apr_proc_fork (proc
, s
->process
->pool
);
1364 if (rv
== APR_INCHILD
)
1366 waklog_child_routine (s
, NULL
);
1370 apr_pool_note_subprocess (s
->process
->pool
, proc
, APR_KILL_ALWAYS
);
1372 /* parent and child */
1373 cfg
->forked
= proc
->pid
;
1374 pag_for_children
= 1;
1376 if ( use_existing
== 0 ) {
1377 /* wait here until our child process has gone and done it's renewing thing. */
1378 while( sharedspace
->renewcount
== oldrenewcount
) {
1379 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1384 if ( cfg
->default_principal
) {
1385 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1392 waklog_init (server_rec
* s
, MK_POOL
* p
)
1394 extern char *version
;
1398 int use_existing
= 1;
1400 char cache_file
[MAXNAMELEN
];
1402 pthread_rwlockattr_t rwlock_attr
;
1405 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1406 "mod_waklog: version %s initialized.", version
);
1408 if ( sharedspace
) {
1409 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: shared memory already allocated." );
1412 snprintf( cache_file
, MAXNAMELEN
, "/tmp/waklog_cache.%d", getpid() );
1414 if ( ( fd
= open( cache_file
, O_RDWR
, 0600 ) ) == -1 ) {
1416 if ( errno
== ENOENT
) {
1418 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: creating shared token cache file %s", cache_file
);
1420 if ( ( fd
= open( cache_file
, O_RDWR
|O_CREAT
|O_TRUNC
, 0600 ) ) == -1 ) {
1421 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file
, errno
);
1425 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file
, errno
);
1430 if ( use_existing
== 0 ) {
1431 struct sharedspace_s bob
;
1432 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: sizing our cache file %d to %d", fd
, sizeof(struct sharedspace_s
) );
1433 memset( &bob
, 0, sizeof(struct sharedspace_s
));
1434 write(fd
, &bob
, sizeof(struct sharedspace_s
));
1435 log_error(APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s
) );
1438 /* mmap the region */
1440 if ( ( sharedspace
= (struct sharedspace_s
*) mmap ( NULL
, sizeof(struct sharedspace_s
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0 ) ) != (void *) -1 ) {
1441 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: shared mmap region ok %d", sharedspace
);
1444 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: mmap failed %d", errno
);
1450 #define locktype pthread_rwlock_t
1452 #define locktype rwlock_t
1455 /* mmap our shared space for our lock */
1456 if ( ( sharedlock
= ( locktype
* ) mmap ( NULL
, sizeof(locktype
), PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANON
, -1, 0 ) ) ) {
1457 #ifndef use_pthreads
1458 rwlock_init(sharedlock
, USYNC_PROCESS
, NULL
);
1460 pthread_rwlockattr_init(&rwlock_attr
);
1461 pthread_rwlockattr_setpshared(&rwlock_attr
, PTHREAD_PROCESS_SHARED
);
1462 pthread_rwlock_init(sharedlock
, &rwlock_attr
);
1465 log_error( APLOG_MARK
, APLOG_DEBUG
, 0, s
, "mod_waklog: rwlock mmap failed %d", errno
);
1470 /* set our default tokens */
1472 getModConfig (cfg
, s
);
1474 oldrenewcount
= sharedspace
->renewcount
;
1476 pag_for_children
= 0;
1478 pid
= ap_bspawn_child (p
, waklog_child_routine
, s
, kill_always
,
1481 pag_for_children
= 1;
1483 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, s
,
1484 "mod_waklog: ap_bspawn_child: %d.", pid
);
1486 if ( use_existing
== 0 ) {
1487 /* wait here until our child process has gone and done it's renewing thing. */
1488 while( sharedspace
->renewcount
== oldrenewcount
) {
1489 log_error( APLOG_MARK
, APLOG_ERR
, 0, s
, "mod_waklog: waiting for tokens..." );
1494 if ( cfg
->default_principal
) {
1495 set_auth( s
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1502 waklog_phase0 (request_rec
* r
)
1506 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1507 "mod_waklog: phase0 called");
1509 cfg
= retrieve_config(r
);
1511 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1512 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using user %s", cfg
->principal
);
1513 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1514 } else if ( cfg
->default_principal
) {
1515 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 using default user %s", cfg
->default_principal
);
1516 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1519 if (child
.token
.ticketLen
) {
1520 memset( &child
.token
, 0, sizeof (struct ktc_token
) );
1521 ktc_ForgetAllTokens();
1524 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase0 not doing nothin.");
1531 waklog_phase1 (request_rec
* r
)
1535 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1536 "mod_waklog: phase1 called");
1538 cfg
= retrieve_config(r
);
1540 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1541 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using user %s", cfg
->principal
);
1542 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1543 } else if ( cfg
->default_principal
) {
1544 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 using default user %s", cfg
->default_principal
);
1545 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1547 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase1 not doing nothin.");
1554 waklog_phase3 (request_rec
* r
)
1558 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1559 "mod_waklog: phase 3 called");
1561 cfg
= retrieve_config(r
);
1563 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1564 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using user %s", cfg
->principal
);
1565 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1566 } else if ( cfg
->default_principal
) {
1567 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 using default user %s", cfg
->default_principal
);
1568 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1570 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase3 not doing nothin.");
1577 waklog_phase6 (request_rec
* r
)
1581 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1582 "mod_waklog: phase6 called");
1584 cfg
= retrieve_config(r
);
1586 if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1587 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using user %s", cfg
->principal
);
1588 set_auth(r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1589 } else if ( cfg
->default_principal
) {
1590 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 using default user %s", cfg
->default_principal
);
1591 set_auth(r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1593 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase6 not doing nothin.");
1600 waklog_phase7 (request_rec
* r
)
1605 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1606 "mod_waklog: phase7 called");
1608 cfg
= retrieve_config (r
);
1610 if ( get_cfg_protect(cfg
) && get_cfg_usertokens(cfg
) ) {
1611 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using usertokens");
1612 rc
= set_auth( r
->server
, r
, 1, NULL
, NULL
, 0);
1613 } else if ( get_cfg_protect(cfg
) && cfg
->principal
) {
1614 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using user %s", cfg
->principal
);
1615 rc
= set_auth( r
->server
, r
, 0, cfg
->principal
, cfg
->keytab
, 0);
1616 } else if ( cfg
->default_principal
) {
1617 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase7 using default user %s", cfg
->default_principal
);
1618 rc
= set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1620 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: no tokens");
1621 if (child
.token
.ticketLen
) {
1622 memset(&child
.token
, 0, sizeof(struct ktc_token
));
1623 ktc_ForgetAllTokens();
1635 waklog_phase9 (request_rec
* r
)
1639 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1640 "mod_waklog: phase9 called");
1642 getModConfig (cfg
, r
->server
);
1644 if ( cfg
->default_principal
) {
1645 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
, "mod_waklog: phase9 using default user %s", cfg
->default_principal
);
1646 set_auth( r
->server
, r
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1659 waklog_new_connection (conn_rec
* c
1668 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
,
1669 "mod_waklog: new_connection called: pid: %d", getpid ());
1671 getModConfig(cfg
, c
->base_server
);
1673 if ( cfg
->default_principal
) {
1674 log_error(APLOG_MARK
, APLOG_DEBUG
, 0, c
->base_server
, "mod_waklog: new conn setting default user %s",
1675 cfg
->default_principal
);
1676 set_auth( c
->base_server
, NULL
, 0, cfg
->default_principal
, cfg
->default_keytab
, 0);
1689 ** Here's a quick explaination for phase0 and phase2:
1690 ** Apache does a stat() on the path between phase0 and
1691 ** phase2, and must by ACLed rl to succeed. So, at
1692 ** phase0 we acquire credentials for umweb:servers from
1693 ** a keytab, and at phase2 we must ensure we remove them.
1695 ** Failure to "unlog" would be a security risk.
1698 waklog_phase2 (request_rec
* r
)
1701 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1702 "mod_waklog: phase2 called");
1704 if (child
.token
.ticketLen
)
1706 memset (&child
.token
, 0, sizeof (struct ktc_token
));
1708 ktc_ForgetAllTokens ();
1710 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1711 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1715 log_error (APLOG_MARK
, APLOG_DEBUG
, 0, r
->server
,
1716 "mod_waklog: phase2 returning");
1722 module MODULE_VAR_EXPORT waklog_module
= {
1723 STANDARD_MODULE_STUFF
,
1724 waklog_init
, /* module initializer */
1725 waklog_create_dir_config
, /* create per-dir config structures */
1726 waklog_merge_dir_config
, /* merge per-dir config structures */
1727 waklog_create_server_config
, /* create per-server config structures */
1728 waklog_merge_dir_config
, /* merge per-server config structures */
1729 waklog_cmds
, /* table of config file commands */
1730 NULL
, /* [#8] MIME-typed-dispatched handlers */
1731 waklog_phase1
, /* [#1] URI to filename translation */
1732 NULL
, /* [#4] validate user id from request */
1733 NULL
, /* [#5] check if the user is ok _here_ */
1734 waklog_phase3
, /* [#3] check access by host address */
1735 waklog_phase6
, /* [#6] determine MIME type */
1736 waklog_phase7
, /* [#7] pre-run fixups */
1737 waklog_phase9
, /* [#9] log a transaction */
1738 waklog_phase2
, /* [#2] header parser */
1739 waklog_child_init
, /* child_init */
1740 waklog_child_exit
, /* child_exit */
1741 waklog_phase0
/* [#0] post read-request */
1743 , NULL
, /* EAPI: add_module */
1744 NULL
, /* EAPI: remove_module */
1745 NULL
, /* EAPI: rewrite_command */
1746 waklog_new_connection
/* EAPI: new_connection */
1751 waklog_register_hooks (apr_pool_t
* p
)
1753 ap_hook_translate_name (waklog_phase1
, NULL
, NULL
, APR_HOOK_FIRST
);
1754 ap_hook_header_parser (waklog_phase2
, NULL
, NULL
, APR_HOOK_FIRST
);
1755 ap_hook_access_checker (waklog_phase3
, NULL
, NULL
, APR_HOOK_FIRST
);
1756 ap_hook_type_checker (waklog_phase6
, NULL
, NULL
, APR_HOOK_FIRST
);
1757 ap_hook_fixups (waklog_phase7
, NULL
, NULL
, APR_HOOK_FIRST
);
1758 ap_hook_log_transaction (waklog_phase9
, NULL
, NULL
, APR_HOOK_FIRST
);
1759 ap_hook_child_init (waklog_child_init
, NULL
, NULL
, APR_HOOK_FIRST
);
1760 ap_hook_post_read_request (waklog_phase0
, NULL
, NULL
, APR_HOOK_FIRST
);
1761 ap_hook_pre_connection (waklog_new_connection
, NULL
, NULL
, APR_HOOK_FIRST
);
1762 ap_hook_post_config (waklog_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1766 module AP_MODULE_DECLARE_DATA waklog_module
= {
1767 STANDARD20_MODULE_STUFF
,
1768 waklog_create_dir_config
, /* create per-dir conf structures */
1769 waklog_merge_dir_config
, /* merge per-dir conf structures */
1770 waklog_create_server_config
, /* create per-server conf structures */
1771 waklog_merge_dir_config
, /* merge per-server conf structures */
1772 waklog_cmds
, /* table of configuration directives */
1773 waklog_register_hooks
/* register hooks */