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