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