swap order of AFS_LIBS and KRB5_LIBS to get the correct libcom_err.a
[hcoop/zz_old/modwaklog.git] / mod_waklog.c
1 #define _LARGEFILE64_SOURCE
2 #define _GNU_SOURCE
3
4 #include "httpd.h"
5 #include "http_config.h"
6 #include "http_log.h"
7 #include "http_protocol.h"
8 #include "http_request.h"
9 #include "http_core.h"
10
11 #ifdef sun
12 #include <synch.h>
13 #elif linux
14 #define use_pthreads
15 #include <features.h>
16 #include <sys/types.h>
17 #include <sys/mman.h>
18 #include <pthread.h>
19 #else
20 #error "make sure you include the right stuff here"
21 #endif
22
23 #ifndef MAXNAMELEN
24 #define MAXNAMELEN 1024
25 #endif
26
27 #ifdef STANDARD20_MODULE_STUFF
28 #define APACHE2
29 #endif
30
31 /********************* APACHE1 ******************************************************************************/
32 #ifndef APACHE2
33 #include "ap_config.h"
34 #if defined(sun)
35 #include <sys/ioccom.h>
36 #endif /* sun */
37 #include <http_conf_globals.h>
38 #define MK_POOL pool
39 #define MK_TABLE_GET ap_table_get
40 #define MK_TABLE_SET ap_table_set
41 #define command(name, func, var, type, usage) \
42 { name, func, \
43 NULL , \
44 RSRC_CONF | ACCESS_CONF , type, usage }
45 module waklog_module;
46
47 /********************* APACHE2 ******************************************************************************/
48 #else
49 #include <apr_strings.h>
50 #include <apr_base64.h>
51 #define ap_pcalloc apr_pcalloc
52 #define ap_pdupstr apr_pdupstr
53 #define ap_pstrdup apr_pstrdup
54 #define MK_POOL apr_pool_t
55 #define MK_TABLE_GET apr_table_get
56 #define MK_TABLE_SET apr_table_set
57 #include "unixd.h"
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, \
64 NULL, \
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";
69
70 #endif /* APACHE2 */
71 /**************************************************************************************************/
72
73 #include <krb5.h>
74 #include <stropts.h>
75 #include <afs/venus.h>
76 #include <afs/auth.h>
77 #include <afs/dirpath.h>
78 #include <afs/ptuser.h>
79 #include <rx/rxkad.h>
80
81 #define TKT_LIFE ( 12 * 60 * 60 )
82 #define SLEEP_TIME ( TKT_LIFE - 5*60 )
83
84 #define WAKLOG_ON 1
85 #define WAKLOG_OFF 2
86 #define WAKLOG_UNSET 0
87
88 #ifdef WAKLOG_DEBUG
89 #undef APLOG_DEBUG
90 #define APLOG_DEBUG APLOG_ERR
91 #endif
92
93 /* this is used to turn off pag generation for the backround worker child during startup */
94 int pag_for_children = 1;
95
96 typedef struct
97 {
98 int forked;
99 int configured;
100 int protect;
101 int usertokens;
102 int cell_in_principal;
103 int disable_token_cache;
104 char *keytab;
105 char *principal;
106 char *default_principal;
107 char *default_keytab;
108 char *afs_cell;
109 char *afs_cell_realm;
110 char *path;
111 MK_POOL *p;
112 }
113 waklog_config;
114
115 typedef struct
116 {
117 struct ktc_token token;
118 char clientprincipal[MAXNAMELEN];
119 krb5_context kcontext;
120 krb5_ccache ccache;
121 struct ktc_principal server;
122 struct ktc_principal client;
123 int pr_init;
124 } waklog_child_config;
125
126 waklog_child_config child;
127
128 struct tokencache_ent {
129 char clientprincipal[MAXNAMELEN];
130 struct ktc_token token;
131 struct ktc_principal client;
132 struct ktc_principal server;
133 time_t lastused;
134 int persist;
135 };
136
137 #define SHARED_TABLE_SIZE 512
138
139 struct sharedspace_s {
140 int renewcount;
141 struct tokencache_ent sharedtokens[SHARED_TABLE_SIZE];
142 };
143
144 struct sharedspace_s *sharedspace = NULL;
145
146 struct renew_ent {
147 char *keytab;
148 char *principal;
149 int lastrenewed;
150 };
151
152 #ifdef use_pthreads
153 pthread_rwlock_t *sharedlock = NULL;
154 #else
155 rwlock_t *sharedlock = NULL;
156 #endif
157
158 struct renew_ent renewtable[SHARED_TABLE_SIZE];
159
160 int renewcount = 0;
161
162
163
164 #define getModConfig(P, X) P = (waklog_config *) ap_get_module_config( (X)->module_config, &waklog_module );
165
166 #include <krb5.h>
167
168 #if defined(sun)
169 #include <sys/ioccom.h>
170 #endif /* sun */
171 #include <stropts.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>
177
178
179 static void
180 log_error (const char *file, int line, int level, int status,
181 const server_rec * s, const char *fmt, ...)
182 {
183 char errstr[4096];
184 va_list ap;
185
186 va_start (ap, fmt);
187 vsnprintf (errstr, 1024, fmt, ap);
188 va_end (ap);
189
190 #ifdef APACHE2
191 ap_log_error (file, line, level | APLOG_NOERRNO, status, s, "(%d) %s", getpid(), errstr);
192 #else
193 ap_log_error (file, line, level | APLOG_NOERRNO, s, "(%d) %s", getpid(), errstr);
194 #endif
195
196 }
197
198 waklog_config *retrieve_config(request_rec *r) {
199
200 request_rec *my;
201 waklog_config *cfg;
202
203 if ( r && r->main ) {
204 my = r->main;
205 } else if (r) {
206 my = r;
207 } else {
208 return NULL;
209 }
210
211 if ( my && ( cfg = (waklog_config *) ap_get_module_config(my->per_dir_config, &waklog_module ) ) ) {
212 return cfg;
213 } else {
214 getModConfig (cfg, r->server);
215 }
216
217 return cfg;
218
219 }
220
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 */
224
225 int
226 set_auth ( server_rec *s, request_rec *r, int self, char *principal, char *keytab, int storeonly ) {
227
228 int i;
229 int usecached = 0;
230 krb5_error_code kerror = 0;
231 krb5_principal kprinc = NULL;
232 krb5_get_init_creds_opt kopts;
233 krb5_creds v5creds;
234 krb5_creds increds;
235 struct ktc_principal server = { "afs", "", "" };
236 struct ktc_principal client;
237 struct ktc_token token;
238 krb5_creds *v5credsp = NULL;
239 krb5_keytab krb5kt = NULL;
240 char buf[MAXNAMELEN];
241 waklog_config *cfg;
242 int rc = 0;
243 int buflen = 0;
244 time_t oldest_time = 0;
245 int oldest;
246 int stored = -1;
247 time_t mytime;
248 int indentical;
249 int cell_in_principal;
250 int attempt;
251 int use_client_credentials = 0;
252
253 char k5user[MAXNAMELEN];
254 char *k5secret;
255 char *k5path = NULL;
256
257 k5path = !r ? NULL : MK_TABLE_GET( r->subprocess_env, "KRB5CCNAME" );
258
259 memset((char *) &increds, 0, sizeof(increds));
260 /* init some stuff if it ain't already */
261
262 if ( ! child.kcontext ) {
263 kerror = krb5_init_context(&child.kcontext);
264 }
265
266 if (!k5path || !*k5path) {
267 k5path = "MEMORY:tmpcache";
268 }
269 if ( ( ! child.ccache ) && ( kerror = krb5_cc_resolve(child.kcontext, k5path, &child.ccache) ) ) {
270 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize credentials cache %s err=%d",
271 k5path, kerror );
272 }
273
274 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth: %d, %s, %s, %d, KRB5CC=%s user=%s",
275 self, principal ? principal : "NULL",
276 keytab ? keytab : "NULL",
277 storeonly,
278 k5path ? k5path : "NULL",
279 #ifdef APACHE2
280 (r && r->user) ? r->user : "NULL"
281 #else
282 "NULL"
283 #endif
284 );
285
286 /* pull the server config record that we care about... */
287
288 if ( r ) {
289 cfg = retrieve_config(r);
290 } else {
291 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
292 "mod_waklog: set_auth using no config" );
293 getModConfig (cfg, s);
294 }
295
296 if ( ! cfg ) {
297 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: cfg is %d", cfg );
298 }
299
300 #ifdef APACHE2
301 if ( self ) {
302 /* pull out our principal name and stuff from the environment -- webauth better have sent
303 through. This here is also where you'd suck stuff out of KRB5CCNAME if we were
304 using something like Cosign */
305
306 if ( ! ( r && r->connection && r->user )) {
307 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: self authentication selected, but no data available");
308 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: r->user=%s", (r->user==NULL ? "null" : r->user==NULL));
309 return -1;
310 }
311
312 strncpy(k5user, r->user, sizeof(k5user));
313
314 /* the other thing we need is someone's password */
315 if ( ! ( k5secret = (char *) MK_TABLE_GET( r->notes, "ATTR_PASSWORD" ) ) ) {
316 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cant do self auth without a secret");
317 return -1;
318 }
319
320 /* we'll pick this up later after we've checked the cache and current state */
321
322 } else
323 if (r && r->user && !principal) {
324 strncpy(k5user, r->user, sizeof(k5user));
325 keytab = NULL;
326 } else
327 #endif
328 if ( principal ) {
329 strncpy( k5user, principal, sizeof(k5user));
330 }
331
332 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth: k5user=%s", k5user ? k5user : "NULL");
333 mytime = time(0);
334
335 /* see if we should just go ahead and ignore this call, since we already should be set to these
336 credentials */
337
338 if ( ! storeonly ) {
339
340 #ifdef use_pthreads
341 pthread_rwlock_rdlock( sharedlock );
342 #else
343 rw_rdlock( sharedlock );
344 #endif
345
346 for ( i = 0; i < SHARED_TABLE_SIZE; ++i ) {
347
348 /* if it's a token for the principal we're looking for, and it hasn't expired yet */
349
350 if ( ( !strcmp( k5user,
351 sharedspace->sharedtokens[i].clientprincipal ) ) &&
352 ( sharedspace->sharedtokens[i].token.endTime > mytime ) ) {
353
354 if ( ! memcmp(&child.token, &sharedspace->sharedtokens[i].token, sizeof(child.token) ) ) {
355 indentical = 1;
356 } else {
357 indentical = 0;
358 }
359
360 /* copy the token out of the cache and into the child object */
361
362 strcpy(child.clientprincipal, sharedspace->sharedtokens[i].clientprincipal );
363 memcpy(&child.token, &sharedspace->sharedtokens[i].token, sizeof(child.token));
364 memcpy(&child.server, &sharedspace->sharedtokens[i].server, sizeof(child.server));
365 memcpy(&child.client, &sharedspace->sharedtokens[i].client, sizeof(child.client));
366
367 /* set our last used time thing */
368 sharedspace->sharedtokens[i].lastused = mytime;
369
370 usecached = 1;
371
372 break;
373
374 }
375
376 }
377
378 /* release the lock on the token cache */
379 #ifdef use_pthreads
380 pthread_rwlock_unlock( sharedlock );
381 #else
382 rw_unlock( sharedlock );
383 #endif
384
385 if ( usecached ) {
386 /* release the lock on the token cache */
387 log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
388 "mod_waklog: set_auth using shared token %d for %s", i, k5user );
389
390 }
391
392 /* if this is something that was in the cache, and it's the same as the token we already have stored,
393 and we weren't calling this just to renew it... */
394
395 if ( usecached && indentical ) {
396 log_error (APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: token is identical for %s", k5user );
397 return 0;
398 }
399
400 }
401
402 /* if 'usecached' isn't set, we've got to get our tokens from somewhere... */
403 if (( ! usecached ) && ( k5user )) {
404
405 /* clear out the creds structure */
406 memset((void *) &v5creds, 0, sizeof(v5creds));
407
408 /* create a principal out of our k5user string */
409
410 if ( kerror = krb5_parse_name (child.kcontext, k5user, &kprinc ) ) {
411 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_parse_name %s", (char *) error_message(kerror) );
412 goto cleanup;
413 }
414
415 /* create the credentials options */
416
417 krb5_get_init_creds_opt_init ( &kopts );
418 krb5_get_init_creds_opt_set_tkt_life ( &kopts, TKT_LIFE );
419 krb5_get_init_creds_opt_set_renew_life ( &kopts, 0 );
420 krb5_get_init_creds_opt_set_forwardable ( &kopts, 0 );
421 krb5_get_init_creds_opt_set_proxiable ( &kopts, 0 );
422
423 if ( keytab ) {
424
425 /* if we've been passed a keytab, we're going to be getting our credentials from it */
426
427 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: using keytab %s", keytab);
428
429 if ( kerror = krb5_kt_resolve(child.kcontext, keytab, &krb5kt ) ) {
430 log_error( APLOG_MARK, APLOG_ERR, 0, s,
431 "mod_waklog: krb5_kt_resolve %s", error_message(kerror) );
432 goto cleanup;
433 }
434
435 if ((kerror = krb5_get_init_creds_keytab (child.kcontext, &v5creds,
436 kprinc, krb5kt, 0, NULL, &kopts ) ) ) {
437 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_init_creds_keytab %s",
438 error_message(kerror) );
439 goto cleanup;
440 }
441
442 } else if ( self ) {
443
444 /* if 'self' is set, we're going to use the credentials provided in the credential information */
445 /* if you're using CoSign, you'd actually just set the ccache to the KRB5CCNAME credentials */
446 /* and skip ahead... Our WebSSO is lame, but has a way for us to snarf the password out of */
447 /* the encrypted token for proxy-authentication stuff. We only hand out keys that allow this */
448 /* functionality to VERY special people. */
449
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));
456 goto cleanup;
457 }
458
459 memset(k5secret, 0, sizeof(k5secret));
460
461 } else {
462 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: no keytab, no self; assuming mod_auth_kerb or similar");
463 use_client_credentials = 1;
464 }
465
466 /* initialize the credentials cache and store the stuff we just got */
467 if (!use_client_credentials) {
468 if ( kerror = krb5_cc_initialize (child.kcontext, child.ccache, kprinc)) {
469 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: init credentials cache %s",
470 error_message(kerror));
471 goto cleanup;
472 }
473
474 if ( kerror = krb5_cc_store_cred(child.kcontext, child.ccache, &v5creds) ) {
475 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot store credentials %s",
476 error_message(kerror));
477 goto cleanup;
478 }
479 }
480
481 krb5_free_cred_contents(child.kcontext, &v5creds);
482
483 if ( kerror ) {
484 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: store cred %s", error_message(kerror));
485 goto cleanup;
486 }
487
488 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: kinit ok for %s", k5user );
489
490 /* now, to the 'aklog' portion of our program. */
491
492 /** we make two attempts here, one for afs@REALM and one for afs/cell@REALM */
493 for(attempt = 0; attempt <= 1; attempt++) {
494 strncpy( buf, "afs", sizeof(buf) - 1 );
495 cell_in_principal = (cfg->cell_in_principal + attempt) % 2;
496
497 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: cell_in_principal=%d", cell_in_principal );
498 if (cell_in_principal) {
499 strncat(buf, "/", sizeof(buf) - strlen(buf) - 1);
500 strncat(buf, cfg->afs_cell, sizeof(buf) - strlen(buf) - 1);
501 }
502 if (cfg->afs_cell_realm != WAKLOG_UNSET) {
503 strncat(buf, "@", sizeof(buf) - strlen(buf) - 1);
504 strncat(buf, cfg->afs_cell_realm, sizeof(buf) - strlen(buf) - 1);
505 }
506
507 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: using AFS principal: %s", buf);
508
509 if ((kerror = krb5_parse_name (child.kcontext, buf, &increds.server))) {
510 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_parse name %s", error_message(kerror));
511 goto cleanup;
512 }
513
514 if (use_client_credentials) {
515 if (( kerror = krb5_cc_resolve( child.kcontext, k5path, &child.ccache)) != 0 ) {
516 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_cc_resolve %s", error_message(kerror));
517 goto cleanup;
518 }
519 }
520
521 if ((kerror = krb5_cc_get_principal(child.kcontext, child.ccache, &increds.client))) {
522 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_cc_get_princ %s", error_message(kerror));
523 goto cleanup;
524 }
525
526 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: retrieved data from ccache for %s", k5user);
527
528 increds.times.endtime = 0;
529
530 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
531
532 if (kerror = krb5_get_credentials (child.kcontext, 0, child.ccache, &increds, &v5credsp )) {
533 /* only complain once we've tried both afs@REALM and afs/cell@REALM */
534 if (attempt>=1) {
535 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: krb5_get_credentials: %s",
536 error_message(kerror));
537 goto cleanup;
538 } else {
539 continue;
540 }
541 }
542 cfg->cell_in_principal = cell_in_principal;
543 break;
544 }
545
546 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: get_credentials passed for %s", k5user);
547
548 if ( v5credsp->ticket.length >= MAXKTCTICKETLEN ) {
549 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: ticket size (%d) too big to fake",
550 v5credsp->ticket.length);
551 goto cleanup;
552 }
553
554 memset(&token, 0, sizeof(struct ktc_token));
555
556 token.startTime = v5credsp->times.starttime ? v5credsp->times.starttime : v5credsp->times.authtime;
557 token.endTime = v5credsp->times.endtime;
558
559 memmove( &token.sessionKey, v5credsp->keyblock.contents, v5credsp->keyblock.length);
560 token.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
561 token.ticketLen = v5credsp->ticket.length;
562 memmove( token.ticket, v5credsp->ticket.data, token.ticketLen);
563
564 /* build the name */
565
566 memmove( buf, v5credsp->client->data[0].data, min(v5credsp->client->data[0].length,
567 MAXKTCNAMELEN -1 ));
568 buf[v5credsp->client->data[0].length] = '\0';
569 if ( v5credsp->client->length > 1 ) {
570 strncat(buf, ".", sizeof(buf) - strlen(buf) - 1);
571 buflen = strlen(buf);
572 memmove(buf + buflen, v5credsp->client->data[1].data,
573 min(v5credsp->client->data[1].length,
574 MAXKTCNAMELEN - strlen(buf) - 1));
575 buf[buflen + v5credsp->client->data[1].length] = '\0';
576 }
577
578 /* assemble the client */
579 strncpy(client.name, buf, sizeof(client.name) - 1 );
580 strncpy(client.instance, "", sizeof(client.instance) - 1 );
581 memmove(buf, v5credsp->client->realm.data, min(v5credsp->client->realm.length,
582 MAXKTCNAMELEN - 1));
583 buf[v5credsp->client->realm.length] = '\0';
584 strncpy(client.cell, buf, sizeof(client.cell));
585
586 /* assemble the server's cell */
587 strncpy(server.cell, cfg->afs_cell, sizeof(server.cell) - 1);
588
589 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: preparing to init PTS connection for %s", server.cell);
590
591 /* fill out the AFS ID in the client name */
592 /* we've done a pr_Initialize in the child_init -- once, per process. If you try to do it more
593 * strange things seem to happen. */
594
595 {
596 afs_int32 viceId = 0;
597
598 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: making PTS call to look up %s", client.name);
599
600 if ( ( rc = pr_SNameToId( client.name, &viceId ) ) == 0 ) {
601 snprintf( client.name, sizeof(client.name), "AFS ID %d", viceId );
602 } else {
603 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: PTS call returned error %d ", rc);
604 }
605
606 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: PTS call returned %s ", client.name);
607
608 }
609
610 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: server: name %s, instance %s, cell %s",
611 server.name, server.instance, server.cell );
612
613 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: client: name %s, instance %s, cell %s",
614 client.name, client.instance, client.cell );
615
616 /* copy the resulting stuff into the child structure */
617
618 strncpy(child.clientprincipal, k5user, sizeof(child.clientprincipal));
619 memcpy(&child.token, &token, sizeof(child.token));
620 memcpy(&child.server, &server, sizeof(child.server));
621 memcpy(&child.client, &client, sizeof(child.client));
622
623 /* stuff the resulting token-related stuff into our shared token cache */
624 /* note, that anything that was set from a keytab is "persistant", and is immune
625 * from LRU-aging. This is because nothing but the process that's running as root
626 * can update these, and it's running every hour or so and renewing these tokens.
627 * and we don't want them aged out.
628 */
629
630 mytime = oldest_time = time(0);
631
632 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: waiting for shared space for %s ", k5user);
633
634 #ifdef use_pthreads
635 pthread_rwlock_wrlock(sharedlock);
636 #else
637 rw_wrlock(sharedlock);
638 #endif
639
640 for( i = ( SHARED_TABLE_SIZE - 1 ); i >= 0; i-- ) {
641 if ( ( sharedspace->sharedtokens[i].lastused <= oldest_time) &&
642 ( sharedspace->sharedtokens[i].persist == 0 ) ) {
643 oldest = i;
644 oldest_time = sharedspace->sharedtokens[i].lastused;
645 }
646 if ( ! strcmp ( sharedspace->sharedtokens[i].clientprincipal,
647 child.clientprincipal ) ) {
648 memcpy(&sharedspace->sharedtokens[i].token, &child.token, sizeof(child.token) );
649 memcpy(&sharedspace->sharedtokens[i].client, &child.client, sizeof(child.client) );
650 memcpy(&sharedspace->sharedtokens[i].server, &child.server, sizeof(child.server) );
651 sharedspace->sharedtokens[i].lastused = mytime;
652 sharedspace->sharedtokens[i].persist = keytab ? 1 : 0;
653 stored = i;
654 break;
655 }
656 }
657
658 if ( stored == -1 ) {
659 memcpy(&sharedspace->sharedtokens[oldest].token, &child.token, sizeof(child.token) );
660 memcpy(&sharedspace->sharedtokens[oldest].client, &child.client, sizeof(child.client) );
661 memcpy(&sharedspace->sharedtokens[oldest].server, &child.server, sizeof(child.server) );
662 strcpy(sharedspace->sharedtokens[oldest].clientprincipal, child.clientprincipal );
663 sharedspace->sharedtokens[oldest].lastused = mytime;
664 sharedspace->sharedtokens[oldest].persist = keytab ? 1 : 0;
665 stored = oldest;
666 }
667
668 #ifdef use_pthreads
669 pthread_rwlock_unlock(sharedlock);
670 #else
671 rw_unlock(sharedlock);
672 #endif
673
674 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: token stored in slot %d for %s", stored,
675 child.clientprincipal );
676
677 } else if ( ! usecached ) {
678 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth divergent case");
679 }
680
681 if ( storeonly ) {
682 goto cleanup;
683 }
684
685 usecachedtoken:
686
687 /* don't ask. Something about AIX. We're leaving it here.*/
688 /* write(2, "", 0); */
689
690 /* we try twice, because sometimes the first one fails. Dunno why, but it always works the second time */
691
692 if ((rc = ktc_SetToken(&child.server, &child.token, &child.client, 0))) {
693 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: settoken returned %s for %s -- trying again",
694 error_message(rc), k5user);
695 if ((rc = ktc_SetToken(&child.server, &child.token, &child.client, 0))) {
696 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: settoken2 returned %s for %s",
697 error_message(rc), k5user);
698 goto cleanup;
699 }
700 }
701
702 cleanup:
703 if ( v5credsp )
704 krb5_free_cred_contents(child.kcontext, v5credsp);
705 if ( increds.client )
706 krb5_free_principal (child.kcontext, increds.client);
707 if ( increds.server )
708 krb5_free_principal (child.kcontext, increds.server);
709 if ( krb5kt )
710 (void) krb5_kt_close(child.kcontext, krb5kt);
711 if ( kprinc )
712 krb5_free_principal (child.kcontext, kprinc);
713
714 if ( rc ) {
715 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with %d", rc );
716 } else if ( kerror ) {
717 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: set_auth ending with krb5 error %d, %s", kerror, error_message(kerror));
718 } else {
719 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: set_auth ending ok");
720 }
721
722 return kerror ? (int) kerror : (int) rc;
723
724 }
725
726
727
728 static void *
729 waklog_create_server_config (MK_POOL * p, server_rec * s)
730 {
731 waklog_config *cfg;
732
733 cfg = (waklog_config *) ap_pcalloc (p, sizeof (waklog_config));
734 cfg->p = p;
735 memset(cfg, 0, sizeof(waklog_config));
736 cfg->path = "(server)";
737 cfg->protect = WAKLOG_UNSET;
738 cfg->usertokens = WAKLOG_UNSET;
739 cfg->disable_token_cache = WAKLOG_UNSET;
740 cfg->keytab = WAKLOG_UNSET;
741 cfg->principal = WAKLOG_UNSET;
742 cfg->default_principal = WAKLOG_UNSET;
743 cfg->default_keytab = WAKLOG_UNSET;
744 cfg->afs_cell = WAKLOG_UNSET;
745 cfg->afs_cell_realm = WAKLOG_UNSET;
746 cfg->forked = 0;
747 cfg->configured = 0;
748
749 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
750 "mod_waklog: server config created.");
751
752 return (cfg);
753 }
754
755 /* initialize with host-config information */
756
757 static void *
758 waklog_create_dir_config (MK_POOL * p, char *dir)
759 {
760 waklog_config *cfg;
761
762 cfg = (waklog_config *) ap_pcalloc (p, sizeof (waklog_config));
763 memset(cfg, 0, sizeof(waklog_config));
764 cfg->p = p;
765 cfg->path = ap_pstrdup(p, dir );
766 cfg->protect = WAKLOG_UNSET;
767 cfg->usertokens = WAKLOG_UNSET;
768 cfg->disable_token_cache = WAKLOG_UNSET;
769 cfg->keytab = WAKLOG_UNSET;
770 cfg->principal = WAKLOG_UNSET;
771 cfg->default_principal = WAKLOG_UNSET;
772 cfg->default_keytab = WAKLOG_UNSET;
773 cfg->afs_cell = WAKLOG_UNSET;
774 cfg->afs_cell_realm = WAKLOG_UNSET;
775 cfg->forked = 0;
776 cfg->configured = 0;
777
778 return (cfg);
779 }
780
781 static void *waklog_merge_dir_config(MK_POOL *p, void *parent_conf, void *newloc_conf) {
782
783 waklog_config *merged = ( waklog_config * ) ap_pcalloc(p, sizeof(waklog_config ) );
784 waklog_config *parent = ( waklog_config * ) parent_conf;
785 waklog_config *child = ( waklog_config * ) newloc_conf;
786
787 merged->protect = child->protect != WAKLOG_UNSET ? child->protect : parent->protect;
788
789 merged->path = child->path != WAKLOG_UNSET ? child->path : parent->path;
790
791 merged->usertokens = child->usertokens != WAKLOG_UNSET ? child->usertokens : parent->usertokens;
792
793 merged->disable_token_cache = child->disable_token_cache != WAKLOG_UNSET ? child->disable_token_cache : parent->disable_token_cache;
794
795 merged->principal = child->principal != WAKLOG_UNSET ? child->principal : parent->principal;
796
797 merged->keytab = child->keytab != WAKLOG_UNSET ? child->keytab : parent->keytab;
798
799 merged->default_keytab = child->default_keytab != WAKLOG_UNSET ? child->default_keytab : parent->default_keytab;
800
801 merged->default_principal = child->default_principal != WAKLOG_UNSET ? child->default_principal : parent->default_principal;
802
803 merged->afs_cell = child->afs_cell != WAKLOG_UNSET ? child->afs_cell : parent->afs_cell;
804
805 merged->afs_cell_realm = child->afs_cell_realm != WAKLOG_UNSET ? child->afs_cell_realm : parent->afs_cell_realm;
806
807 return (void *) merged;
808
809 }
810
811 static void *waklog_merge_server_config(MK_POOL *p, void *parent_conf, void *newloc_conf) {
812
813 waklog_config *merged = ( waklog_config * ) ap_pcalloc(p, sizeof(waklog_config ) );
814 waklog_config *pconf = ( waklog_config * ) parent_conf;
815 waklog_config *nconf = ( waklog_config * ) newloc_conf;
816
817 merged->protect = nconf->protect == WAKLOG_UNSET ? pconf->protect : nconf->protect;
818
819 merged->usertokens = nconf->usertokens == WAKLOG_UNSET ? pconf->usertokens : nconf->usertokens;
820
821 merged->disable_token_cache = nconf->disable_token_cache == WAKLOG_UNSET ? pconf->disable_token_cache : nconf->disable_token_cache;
822
823 merged->keytab = nconf->keytab == WAKLOG_UNSET ? ap_pstrdup(p, pconf->keytab) :
824 ( nconf->keytab == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->keytab) );
825
826 merged->principal = nconf->principal == WAKLOG_UNSET ? ap_pstrdup(p, pconf->principal) :
827 ( nconf->principal == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->principal) );
828
829 merged->afs_cell = nconf->afs_cell == WAKLOG_UNSET ? ap_pstrdup(p, pconf->afs_cell) :
830 ( nconf->afs_cell == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->afs_cell) );
831
832 merged->afs_cell_realm = nconf->afs_cell_realm == WAKLOG_UNSET ? ap_pstrdup(p, pconf->afs_cell_realm) :
833 ( nconf->afs_cell_realm == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->afs_cell_realm) );
834
835 merged->default_keytab = nconf->default_keytab == WAKLOG_UNSET ? ap_pstrdup(p, pconf->default_keytab) :
836 ( nconf->default_keytab == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->default_keytab) );
837
838 merged->default_principal = nconf->default_principal == WAKLOG_UNSET ? ap_pstrdup(p, pconf->default_principal) :
839 ( nconf->default_principal == WAKLOG_UNSET ? WAKLOG_UNSET : ap_pstrdup(p, pconf->default_principal) );
840
841
842 return (void *) merged;
843
844 }
845
846 static const char *
847 set_waklog_enabled (cmd_parms * params, void *mconfig, int flag)
848 {
849 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
850 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
851
852 cfg->protect = flag;
853 cfg->configured = 1;
854 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
855 "mod_waklog: waklog_enabled set on %s", cfg->path ? cfg->path : "NULL");
856 return (NULL);
857 }
858
859
860 /* this adds a principal/keytab pair to get their tokens renewed by the
861 child process every few centons. */
862
863 void add_to_renewtable(MK_POOL *p, char *keytab, char *principal) {
864
865 int i;
866
867 if ( renewcount >= SHARED_TABLE_SIZE ) {
868 log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "mod_waklog: big problem. Increase the SHARED_TABLE_SIZE or \
869 decrease your tokens.");
870 return;
871 }
872
873 /* check to see if it's already there */
874
875 for ( i = 0; i < renewcount; i++ ) {
876 if ( ! strcmp(renewtable[i].principal, principal ) ) {
877 return;
878 }
879 }
880
881 renewtable[renewcount].keytab = ap_pstrdup(p, keytab);
882 renewtable[renewcount].principal = ap_pstrdup(p, principal);
883 renewtable[renewcount].lastrenewed = 0;
884 ++renewcount;
885
886 }
887
888 static const char *
889 set_waklog_location_principal (cmd_parms *params, void *mconfig, char *principal, char *keytab)
890 {
891 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
892 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
893
894 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
895 "mod_waklog: configuring principal: %s, keytab: %s", principal, keytab);
896
897 cfg->principal = ap_pstrdup(params->pool, principal);
898 cfg->keytab = ap_pstrdup (params->pool, keytab);
899
900 add_to_renewtable(params->pool, keytab, principal);
901
902 cfg->configured = 1;
903
904 return (NULL);
905 }
906
907 static const char *
908 set_waklog_afs_cell (cmd_parms * params, void *mconfig, char *file)
909 {
910 waklog_config *waklog_mconfig = ( waklog_config * ) mconfig;
911 waklog_config *waklog_srvconfig =
912 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
913
914 log_error (APLOG_MARK, APLOG_INFO, 0, params->server,
915 "mod_waklog: will use afs_cell: %s", file);
916
917 waklog_srvconfig->cell_in_principal = 0;
918 waklog_srvconfig->afs_cell = ap_pstrdup (params->pool, file);
919 waklog_srvconfig->configured = 1;
920
921 if (waklog_mconfig != NULL) {
922 waklog_mconfig->cell_in_principal = waklog_srvconfig->cell_in_principal;
923 waklog_mconfig->afs_cell = ap_pstrdup (params->pool, file);
924 waklog_mconfig->configured = 1;
925 }
926 return (NULL);
927 }
928
929 static const char *
930 set_waklog_afs_cell_realm (cmd_parms * params, void *mconfig, char *file)
931 {
932 waklog_config *waklog_mconfig = ( waklog_config * ) mconfig;
933 waklog_config *waklog_srvconfig =
934 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
935
936 log_error (APLOG_MARK, APLOG_INFO, 0, params->server,
937 "mod_waklog: will use afs_cell_realm: %s", file);
938
939 waklog_srvconfig->afs_cell_realm = ap_pstrdup (params->pool, file);
940
941 if (waklog_mconfig != NULL) {
942 waklog_mconfig->afs_cell_realm = ap_pstrdup (params->pool, file);
943 }
944 return (NULL);
945 }
946
947 static const char *
948 set_waklog_default_principal (cmd_parms * params, void *mconfig, char *principal, char *keytab)
949 {
950 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
951 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
952
953 waklog_config *srvcfg = ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
954
955 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
956 "mod_waklog: set default princ/keytab: %s, %s for %s", principal, keytab, cfg->path ? cfg->path : "NULL");
957
958 cfg->default_principal = ap_pstrdup (params->pool, principal);
959 cfg->default_keytab = ap_pstrdup(params->pool, keytab );
960
961 /* this also gets set at the server level */
962 if ( mconfig && ( ! cfg->path ) ) {
963 srvcfg->default_principal = ap_pstrdup (params->pool, principal);
964 srvcfg->default_keytab = ap_pstrdup(params->pool, keytab );
965 } else {
966 log_error(APLOG_MARK, APLOG_ERR, 0, params->server, "only able to set default principal on a global level!");
967 return "Unable to set DefaultPrincipal outside of top level config!";
968 }
969
970 add_to_renewtable( params->pool, keytab, principal );
971
972 cfg->configured = 1;
973
974 return (NULL);
975 }
976
977 static const char *
978 set_waklog_use_usertokens (cmd_parms * params, void *mconfig, int flag)
979 {
980 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
981 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
982
983 cfg->usertokens = flag;
984
985 cfg->configured = 1;
986
987 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
988 "mod_waklog: waklog_use_user_tokens set");
989 return (NULL);
990 }
991
992
993 static const char *
994 set_waklog_disable_token_cache (cmd_parms * params, void *mconfig, int flag)
995 {
996 waklog_config *cfg = mconfig ? ( waklog_config * ) mconfig :
997 ( waklog_config * ) ap_get_module_config(params->server->module_config, &waklog_module );
998
999 cfg->disable_token_cache = flag;
1000
1001 cfg->configured = 1;
1002
1003 log_error (APLOG_MARK, APLOG_DEBUG, 0, params->server,
1004 "mod_waklog: waklog_disable_token_cache set");
1005 return (NULL);
1006 }
1007
1008
1009 #ifndef APACHE2
1010 static void waklog_child_exit( server_rec *s, MK_POOL *p ) {
1011 #else
1012 apr_status_t waklog_child_exit( void *sr ) {
1013
1014 server_rec *s = (server_rec *) sr;
1015 #endif
1016
1017 if ( child.ccache ) {
1018 krb5_cc_close(child.kcontext, child.ccache);
1019 }
1020
1021 if ( child.kcontext ) {
1022 krb5_free_context(child.kcontext);
1023 }
1024
1025 /* forget our tokens */
1026
1027 ktc_ForgetAllTokens ();
1028
1029 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
1030 "mod_waklog: waklog_child_exit complete");
1031
1032 #ifdef APACHE2
1033 return APR_SUCCESS;
1034 #endif
1035
1036 }
1037
1038 static void
1039 #ifdef APACHE2
1040 waklog_child_init (MK_POOL * p, server_rec * s)
1041 #else
1042 waklog_child_init (server_rec * s, MK_POOL * p)
1043 #endif
1044 {
1045
1046 krb5_error_code code;
1047 waklog_config *cfg;
1048
1049 char *cell;
1050
1051 log_error (APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init called for pid %d", getpid());
1052
1053 if ( !sharedspace ) {
1054 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: child_init called without shared space? %d", getpid());
1055 return;
1056 }
1057
1058 log_error (APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init called for pid %d", getpid());
1059
1060 memset (&child, 0, sizeof(child));
1061
1062 if ( code = krb5_init_context(&child.kcontext) ) {
1063 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't init kerberos context %d", code );
1064 }
1065
1066 if ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) {
1067 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", code );
1068 }
1069
1070 if ( pag_for_children ) {
1071 setpag ();
1072 }
1073
1074 getModConfig (cfg, s);
1075
1076 if ( cfg->default_principal != WAKLOG_UNSET ) {
1077 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: child_init setting default user %s, %s", cfg->default_principal, cfg->default_keytab);
1078 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1079 }
1080
1081 cell = strdup(cfg->afs_cell);
1082 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR, cell );
1083
1084 #ifdef APACHE2
1085 apr_pool_cleanup_register(p, s, waklog_child_exit, apr_pool_cleanup_null);
1086 #endif
1087
1088 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
1089 "mod_waklog: child_init returned");
1090
1091 return;
1092 }
1093
1094 command_rec waklog_cmds[] = {
1095
1096 command ("WaklogAFSCell", set_waklog_afs_cell, 0, TAKE1,
1097 "Use the supplied AFS cell (required)"),
1098
1099 command ("WaklogAFSCellRealm", set_waklog_afs_cell_realm, 0, TAKE1,
1100 "Assume that the AFS cell belongs to the specified Kerberos realm (optional)"),
1101
1102 command ("WaklogEnabled", set_waklog_enabled, 0, FLAG,
1103 "enable waklog on a server, location, or directory basis"),
1104
1105 command ("WaklogDefaultPrincipal", set_waklog_default_principal, 0, TAKE2,
1106 "Set the default principal that the server runs as"),
1107
1108 command ("WaklogLocationPrincipal", set_waklog_location_principal, 0, TAKE2,
1109 "Set the principal on a <Location>-specific basis"),
1110
1111 command ("WaklogDisableTokenCache", set_waklog_disable_token_cache, 0, FLAG,
1112 "Ignore the token cache (location-specific); useful for scripts that need kerberos tickets."),
1113
1114 command ("WaklogUseUserTokens", set_waklog_use_usertokens, 0, FLAG,
1115 "Use the requesting user tokens (from webauth)"),
1116
1117 {NULL}
1118 };
1119
1120
1121 /* not currently using this */
1122
1123 static int
1124 token_cleanup (void *data)
1125 {
1126 request_rec *r = (request_rec *) data;
1127
1128 if (child.token.ticketLen)
1129 {
1130 memset (&child.token, 0, sizeof (struct ktc_token));
1131
1132 ktc_ForgetAllTokens ();
1133
1134 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1135 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1136 getpid ());
1137 }
1138 return 0;
1139 }
1140
1141 static int
1142 waklog_child_routine (void *data, child_info * pinfo)
1143 {
1144 int i;
1145 server_rec *s = (server_rec *) data;
1146 krb5_error_code code;
1147 char *cell;
1148 time_t sleep_time = ( TKT_LIFE / 2 ) ;
1149 time_t when;
1150 time_t left;
1151 waklog_config *cfg;
1152
1153 getModConfig( cfg, s );
1154
1155 log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: waklog_child_routine started, running as %d", getuid());
1156
1157 memset (&child, 0, sizeof(child));
1158
1159 if ( code = krb5_init_context(&child.kcontext) ) {
1160 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't init kerberos context %d", code );
1161 }
1162
1163 if ( code = krb5_cc_resolve(child.kcontext, "MEMORY:tmpcache", &child.ccache) ) {
1164 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: can't initialize in-memory credentials cache %d", code );
1165 }
1166
1167 /* need to do this so we can make PTS calls */
1168 cell = strdup(cfg->afs_cell); /* stupid */
1169 pr_Initialize( 0, AFSDIR_CLIENT_ETC_DIR, cell );
1170
1171 while(1) {
1172
1173 for ( i = 0; i < renewcount; ++i ) {
1174 renewtable[i].lastrenewed = time(0);
1175 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: (pid %d) renewing %s / %s", getpid(), renewtable[i].principal,
1176 renewtable[i].keytab);
1177
1178 set_auth( s, NULL, 0, renewtable[i].principal, renewtable[i].keytab, 1 );
1179
1180 /* if this is our default token, we want to "stash" it in our current PAG so the parent maintains readability of
1181 things that it needs to read */
1182
1183 if ( cfg && cfg->default_principal && ( ! strcmp(cfg->default_principal, renewtable[i].principal ) ) ) {
1184 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: renewing/setting default tokens" );
1185 set_auth( s, NULL, 0, renewtable[i].principal, renewtable[i].keytab, 0 );
1186 }
1187
1188 }
1189
1190 sharedspace->renewcount++;
1191
1192 left = sleep_time;
1193
1194 while( left > 5 ) {
1195 when = time(0);
1196
1197 sleep(left);
1198
1199 left -= ( time(0) - when );
1200 }
1201
1202 }
1203
1204 pr_End();
1205
1206 }
1207
1208 #ifdef APACHE2
1209 static int
1210 waklog_init_handler (apr_pool_t * p, apr_pool_t * plog,
1211 apr_pool_t * ptemp, server_rec * s)
1212 {
1213 int rv;
1214 extern char *version;
1215 apr_proc_t *proc;
1216 waklog_config *cfg;
1217 void *data;
1218 int fd = -1;
1219 int use_existing = 1;
1220 int oldrenewcount;
1221 char cache_file[MAXNAMELEN];
1222 #ifdef use_pthreads
1223 pthread_rwlockattr_t rwlock_attr;
1224 #endif
1225
1226
1227 getModConfig (cfg, s);
1228
1229 /* initialize_module() will be called twice, and if it's a DSO
1230 * then all static data from the first call will be lost. Only
1231 * set up our static data on the second call.
1232 * see http://issues.apache.org/bugzilla/show_bug.cgi?id=37519 */
1233 apr_pool_userdata_get (&data, userdata_key, s->process->pool);
1234
1235
1236 if (cfg->afs_cell==NULL) {
1237 log_error (APLOG_MARK, APLOG_ERR, 0, s,
1238 "mod_waklog: afs_cell==NULL; please provide the WaklogAFSCell directive");
1239 /** clobber apache */
1240 exit(-1);
1241 }
1242
1243 if (!data)
1244 {
1245 apr_pool_userdata_set ((const void *) 1, userdata_key,
1246 apr_pool_cleanup_null, s->process->pool);
1247 }
1248 else
1249 {
1250 log_error (APLOG_MARK, APLOG_INFO, 0, s,
1251 "mod_waklog: version %s initialized for cell %s", version, cfg->afs_cell);
1252
1253 if ( sharedspace ) {
1254 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: shared memory already allocated." );
1255 } else {
1256
1257 snprintf( cache_file, MAXNAMELEN, "/tmp/waklog_cache.%d", getpid() );
1258
1259 if ( ( fd = open( cache_file, O_RDWR, 0600 ) ) == -1 ) {
1260
1261 if ( errno == ENOENT ) {
1262
1263 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: creating shared token cache file %s", cache_file );
1264 use_existing = 0;
1265 if ( ( fd = open( cache_file, O_RDWR|O_CREAT|O_TRUNC, 0600 ) ) == -1 ) {
1266 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file, errno );
1267 exit(errno);
1268 }
1269 } else {
1270 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file, errno );
1271 }
1272 }
1273
1274 if ( use_existing == 0 ) {
1275 struct sharedspace_s bob;
1276 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: sizing our cache file %d to %d", fd, sizeof(struct sharedspace_s) );
1277 memset( &bob, 0, sizeof(struct sharedspace_s));
1278 write(fd, &bob, sizeof(struct sharedspace_s));
1279 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s) );
1280 }
1281
1282 /* mmap the region */
1283
1284 if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != MAP_FAILED ) {
1285 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared mmap region ok %d", sharedspace );
1286 close(fd);
1287 } else {
1288 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: mmap failed %d", errno );
1289 exit(errno);
1290 }
1291 }
1292
1293 #ifdef use_pthreads
1294 #define locktype pthread_rwlock_t
1295 #else
1296 #define locktype rwlock_t
1297 #endif
1298
1299 if ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) {
1300 #ifndef use_pthreads
1301 rwlock_init(sharedlock, USYNC_PROCESS, NULL );
1302 #else
1303 pthread_rwlockattr_init(&rwlock_attr);
1304 pthread_rwlockattr_setpshared(&rwlock_attr, PTHREAD_PROCESS_SHARED);
1305 pthread_rwlock_init(sharedlock, &rwlock_attr );
1306 #endif
1307 } else {
1308 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: rwlock mmap failed %d", errno );
1309 }
1310
1311 #undef locktype
1312
1313 /* set our default tokens */
1314
1315 oldrenewcount = sharedspace->renewcount;
1316
1317 pag_for_children = 0;
1318
1319 proc = (apr_proc_t *) ap_pcalloc (s->process->pool, sizeof (apr_proc_t));
1320
1321 rv = apr_proc_fork (proc, s->process->pool);
1322
1323 if (rv == APR_INCHILD)
1324 {
1325 waklog_child_routine (s, NULL);
1326 }
1327 else
1328 {
1329 apr_pool_note_subprocess (s->process->pool, proc, APR_KILL_ALWAYS);
1330 }
1331 /* parent and child */
1332 cfg->forked = proc->pid;
1333 pag_for_children = 1;
1334
1335 if ( use_existing == 0 ) {
1336 /* wait here until our child process has gone and done it's renewing thing. */
1337 while( sharedspace->renewcount == oldrenewcount ) {
1338 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: waiting for tokens..." );
1339 sleep(2);
1340 }
1341 }
1342
1343 if ( cfg->default_principal ) {
1344 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1345 }
1346 }
1347 return 0;
1348 }
1349 #else
1350 static void
1351 waklog_init (server_rec * s, MK_POOL * p)
1352 {
1353 extern char *version;
1354 int pid;
1355 waklog_config *cfg;
1356 char *cell;
1357 int fd = -1;
1358 int use_existing = 1;
1359 int oldrenewcount;
1360 char cache_file[MAXNAMELEN];
1361 #ifdef use_pthreads
1362 pthread_rwlockattr_t rwlock_attr;
1363 #endif
1364
1365 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
1366 "mod_waklog: version %s initialized.", version);
1367
1368 if ( sharedspace ) {
1369 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: shared memory already allocated." );
1370 } else {
1371
1372 snprintf( cache_file, MAXNAMELEN, "/tmp/waklog_cache.%d", getpid() );
1373
1374 if ( ( fd = open( cache_file, O_RDWR, 0600 ) ) == -1 ) {
1375
1376 if ( errno == ENOENT ) {
1377
1378 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: creating shared token cache file %s", cache_file );
1379 use_existing = 0;
1380 if ( ( fd = open( cache_file, O_RDWR|O_CREAT|O_TRUNC, 0600 ) ) == -1 ) {
1381 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot create shared token cache file %s (%d)", cache_file, errno );
1382 exit(errno);
1383 }
1384 } else {
1385 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: cannot open existing shared token cache file %s (%d)", cache_file, errno );
1386 }
1387
1388 }
1389
1390 if ( use_existing == 0 ) {
1391 struct sharedspace_s bob;
1392 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: sizing our cache file %d to %d", fd, sizeof(struct sharedspace_s) );
1393 memset( &bob, 0, sizeof(struct sharedspace_s));
1394 write(fd, &bob, sizeof(struct sharedspace_s));
1395 log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: done sizing our cache file to %d", sizeof(struct sharedspace_s) );
1396 }
1397
1398 /* mmap the region */
1399
1400 if ( ( sharedspace = (struct sharedspace_s *) mmap ( NULL, sizeof(struct sharedspace_s), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ) ) != -1 ) {
1401 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: shared mmap region ok %d", sharedspace );
1402 close(fd);
1403 } else {
1404 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: mmap failed %d", errno );
1405 exit(errno);
1406 }
1407 }
1408
1409 #ifdef use_pthreads
1410 #define locktype pthread_rwlock_t
1411 #else
1412 #define locktype rwlock_t
1413 #endif
1414
1415 /* mmap our shared space for our lock */
1416 if ( sharedlock = ( locktype * ) mmap ( NULL, sizeof(locktype), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0 ) ) {
1417 #ifndef use_pthreads
1418 rwlock_init(sharedlock, USYNC_PROCESS, NULL );
1419 #else
1420 pthread_rwlockattr_init(&rwlock_attr);
1421 pthread_rwlockattr_setpshared(&rwlock_attr, PTHREAD_PROCESS_SHARED);
1422 pthread_rwlock_init(sharedlock, &rwlock_attr );
1423 #endif
1424 } else {
1425 log_error( APLOG_MARK, APLOG_DEBUG, 0, s, "mod_waklog: rwlock mmap failed %d", errno );
1426 }
1427
1428 #undef locktype
1429
1430 /* set our default tokens */
1431
1432 getModConfig (cfg, s);
1433
1434 oldrenewcount = sharedspace->renewcount;
1435
1436 pag_for_children = 0;
1437
1438 pid = ap_bspawn_child (p, waklog_child_routine, s, kill_always,
1439 NULL, NULL, NULL);
1440
1441 pag_for_children = 1;
1442
1443 log_error (APLOG_MARK, APLOG_DEBUG, 0, s,
1444 "mod_waklog: ap_bspawn_child: %d.", pid);
1445
1446 if ( use_existing == 0 ) {
1447 /* wait here until our child process has gone and done it's renewing thing. */
1448 while( sharedspace->renewcount == oldrenewcount ) {
1449 log_error( APLOG_MARK, APLOG_ERR, 0, s, "mod_waklog: waiting for tokens..." );
1450 sleep(2);
1451 }
1452 }
1453
1454 if ( cfg->default_principal ) {
1455 set_auth( s, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1456 }
1457
1458 }
1459 #endif
1460
1461 static int
1462 waklog_phase0 (request_rec * r)
1463 {
1464 waklog_config *cfg;
1465
1466 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1467 "mod_waklog: phase0 called");
1468
1469 cfg = retrieve_config(r);
1470
1471 if ( cfg->protect && cfg->principal ) {
1472 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 using user %s", cfg->principal);
1473 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1474 } else if ( cfg->default_principal ) {
1475 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 using default user %s", cfg->default_principal);
1476 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1477 } else {
1478 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase0 not doing nothin.");
1479 }
1480
1481 return DECLINED;
1482 }
1483
1484 static int
1485 waklog_phase1 (request_rec * r)
1486 {
1487 waklog_config *cfg;
1488
1489 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1490 "mod_waklog: phase1 called");
1491
1492 cfg = retrieve_config(r);
1493
1494 if ( cfg->protect && cfg->principal ) {
1495 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 using user %s", cfg->principal);
1496 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1497 } else if ( cfg->default_principal ) {
1498 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 using default user %s", cfg->default_principal);
1499 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1500 } else {
1501 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase1 not doing nothin.");
1502 }
1503
1504 return DECLINED;
1505 }
1506
1507 static int
1508 waklog_phase3 (request_rec * r)
1509 {
1510 waklog_config *cfg;
1511
1512 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1513 "mod_waklog: phase 3 called");
1514
1515 cfg = retrieve_config(r);
1516
1517 if ( cfg->protect && cfg->principal ) {
1518 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 using user %s", cfg->principal);
1519 set_auth(r->server, r, 0, cfg->principal, cfg->keytab, 0);
1520 } else if ( cfg->default_principal ) {
1521 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 using default user %s", cfg->default_principal);
1522 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1523 } else {
1524 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase3 not doing nothin.");
1525 }
1526
1527 return DECLINED;
1528 }
1529
1530 static int
1531 waklog_phase6 (request_rec * r)
1532 {
1533 waklog_config *cfg;
1534
1535 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1536 "mod_waklog: phase6 called");
1537
1538 cfg = retrieve_config(r);
1539
1540 if ( cfg->protect && cfg->principal ) {
1541 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 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: phase6 using default user %s", cfg->default_principal);
1545 set_auth(r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1546 } else {
1547 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase6 not doing nothin.");
1548 }
1549
1550 return DECLINED;
1551 }
1552
1553 static int
1554 waklog_phase7 (request_rec * r)
1555 {
1556 waklog_config *cfg;
1557 int rc = 0;
1558
1559 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1560 "mod_waklog: phase7 called");
1561
1562 cfg = retrieve_config (r);
1563
1564 if ( cfg->protect && cfg->usertokens ) {
1565 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using usertokens");
1566 rc = set_auth( r->server, r, 1, NULL, NULL, 0);
1567 } else if ( cfg->protect && cfg->principal ) {
1568 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using user %s", cfg->principal);
1569 rc = set_auth( r->server, r, 0, cfg->principal, cfg->keytab, 0);
1570 } else if ( cfg->default_principal ) {
1571 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using default user %s", cfg->default_principal);
1572 rc = set_auth( r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1573 } else {
1574 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase7 using no default principal");
1575 set_auth(r->server, r, 0, NULL, NULL, 0);
1576 }
1577
1578 if ( rc ) {
1579 return 400;
1580 }
1581
1582 return DECLINED;
1583 }
1584
1585 static int
1586 waklog_phase9 (request_rec * r)
1587 {
1588 waklog_config *cfg;
1589
1590 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1591 "mod_waklog: phase9 called");
1592
1593 getModConfig (cfg, r->server);
1594
1595 if ( cfg->default_principal ) {
1596 log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "mod_waklog: phase9 using default user %s", cfg->default_principal);
1597 set_auth( r->server, r, 0, cfg->default_principal, cfg->default_keytab, 0);
1598 }
1599
1600 return DECLINED;
1601 }
1602
1603
1604 static
1605 #ifdef APACHE2
1606 int
1607 #else
1608 void
1609 #endif
1610 waklog_new_connection (conn_rec * c
1611 #ifdef APACHE2
1612 , void *dummy
1613 #endif
1614 )
1615 {
1616
1617 waklog_config *cfg;
1618
1619 log_error (APLOG_MARK, APLOG_DEBUG, 0, c->base_server,
1620 "mod_waklog: new_connection called: pid: %d", getpid ());
1621
1622 getModConfig(cfg, c->base_server);
1623
1624 if ( cfg->default_principal ) {
1625 log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "mod_waklog: new conn setting default user %s",
1626 cfg->default_principal);
1627 set_auth( c->base_server, NULL, 0, cfg->default_principal, cfg->default_keytab, 0);
1628 }
1629
1630
1631 return
1632 #ifdef APACHE2
1633 0
1634 #endif
1635 ;
1636 }
1637
1638
1639 /*
1640 ** Here's a quick explaination for phase0 and phase2:
1641 ** Apache does a stat() on the path between phase0 and
1642 ** phase2, and must by ACLed rl to succeed. So, at
1643 ** phase0 we acquire credentials for umweb:servers from
1644 ** a keytab, and at phase2 we must ensure we remove them.
1645 **
1646 ** Failure to "unlog" would be a security risk.
1647 */
1648 static int
1649 waklog_phase2 (request_rec * r)
1650 {
1651
1652 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1653 "mod_waklog: phase2 called");
1654
1655 if (child.token.ticketLen)
1656 {
1657 memset (&child.token, 0, sizeof (struct ktc_token));
1658
1659 ktc_ForgetAllTokens ();
1660
1661 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1662 "mod_waklog: ktc_ForgetAllTokens succeeded: pid: %d",
1663 getpid ());
1664 }
1665
1666 log_error (APLOG_MARK, APLOG_DEBUG, 0, r->server,
1667 "mod_waklog: phase2 returning");
1668
1669 return DECLINED;
1670 }
1671
1672 #ifndef APACHE2
1673 module MODULE_VAR_EXPORT waklog_module = {
1674 STANDARD_MODULE_STUFF,
1675 waklog_init, /* module initializer */
1676 waklog_create_dir_config, /* create per-dir config structures */
1677 waklog_merge_dir_config, /* merge per-dir config structures */
1678 waklog_create_server_config, /* create per-server config structures */
1679 waklog_merge_dir_config, /* merge per-server config structures */
1680 waklog_cmds, /* table of config file commands */
1681 NULL, /* [#8] MIME-typed-dispatched handlers */
1682 waklog_phase1, /* [#1] URI to filename translation */
1683 NULL, /* [#4] validate user id from request */
1684 NULL, /* [#5] check if the user is ok _here_ */
1685 waklog_phase3, /* [#3] check access by host address */
1686 waklog_phase6, /* [#6] determine MIME type */
1687 waklog_phase7, /* [#7] pre-run fixups */
1688 waklog_phase9, /* [#9] log a transaction */
1689 NULL, /* [#2] header parser */
1690 waklog_child_init, /* child_init */
1691 waklog_child_exit, /* child_exit */
1692 waklog_phase0 /* [#0] post read-request */
1693 #ifdef EAPI
1694 , NULL, /* EAPI: add_module */
1695 NULL, /* EAPI: remove_module */
1696 NULL, /* EAPI: rewrite_command */
1697 waklog_new_connection /* EAPI: new_connection */
1698 #endif
1699 };
1700 #else
1701 static void
1702 waklog_register_hooks (apr_pool_t * p)
1703 {
1704 ap_hook_translate_name (waklog_phase1, NULL, NULL, APR_HOOK_FIRST);
1705 ap_hook_header_parser (waklog_phase2, NULL, NULL, APR_HOOK_FIRST);
1706 ap_hook_access_checker (waklog_phase3, NULL, NULL, APR_HOOK_FIRST);
1707 ap_hook_type_checker (waklog_phase6, NULL, NULL, APR_HOOK_FIRST);
1708 ap_hook_fixups (waklog_phase7, NULL, NULL, APR_HOOK_FIRST);
1709 ap_hook_log_transaction (waklog_phase9, NULL, NULL, APR_HOOK_FIRST);
1710 ap_hook_child_init (waklog_child_init, NULL, NULL, APR_HOOK_FIRST);
1711 ap_hook_post_read_request (waklog_phase0, NULL, NULL, APR_HOOK_FIRST);
1712 ap_hook_pre_connection (waklog_new_connection, NULL, NULL, APR_HOOK_FIRST);
1713 ap_hook_post_config (waklog_init_handler, NULL, NULL, APR_HOOK_MIDDLE);
1714 }
1715
1716
1717 module AP_MODULE_DECLARE_DATA waklog_module = {
1718 STANDARD20_MODULE_STUFF,
1719 waklog_create_dir_config, /* create per-dir conf structures */
1720 waklog_merge_dir_config, /* merge per-dir conf structures */
1721 waklog_create_server_config, /* create per-server conf structures */
1722 waklog_merge_dir_config, /* merge per-server conf structures */
1723 waklog_cmds, /* table of configuration directives */
1724 waklog_register_hooks /* register hooks */
1725 };
1726 #endif