OSDN Git Service

*** empty log message ***
[modchxj/mod_chxj.git] / src / chxj_cookie.c
1 /*
2  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
3  * Copyright (C) 2005 Atsushi Konno All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <time.h>
18
19 #include "mod_chxj.h"
20 #include "chxj_cookie.h"
21 #include "chxj_url_encode.h"
22 #include "chxj_apply_convrule.h"
23
24 #include "apu.h"
25 #include "apr_dbm.h"
26 #include "apr_uuid.h"
27 #include "apr_md5.h"
28 #include "apr_base64.h"
29 #include "apr_uri.h"
30
31 static char* s_get_hostname_from_url(request_rec* r, char* value);
32 static char* s_cut_until_end_hostname(request_rec*, char* value);
33
34 /*
35  *
36  */
37 cookie_t*
38 chxj_save_cookie(request_rec* r)
39 {
40   int                 ii;
41   apr_array_header_t* headers;
42   apr_table_entry_t*  hentryp;
43   apr_status_t        retval;
44   apr_datum_t         dbmkey;
45   apr_datum_t         dbmval;
46   apr_dbm_t*          f;
47   apr_uuid_t          uuid;
48   char*               uuid_string;
49   unsigned char*      md5_value;
50   char*               old_cookie_id;
51   char*               store_string;
52   mod_chxj_config*    dconf;
53   chxjconvrule_entry* entryp;
54   apr_file_t*         file;
55   apr_table_t*        new_cookie_table;
56   int                 has_cookie = 0;
57   cookie_t*           cookie;
58   cookie_t*           old_cookie;
59   char*               refer_string;
60
61
62   DBG(r, "start chxj_save_cookie()");
63
64   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
65   cookie->cookie_id = NULL;
66
67   has_cookie = 0;
68
69   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
70   entryp = chxj_apply_convrule(r, dconf->convrules);
71   if (! entryp) {
72     DBG(r, "end chxj_save_cookie() no pattern");
73     return NULL;
74   }
75   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
76     DBG(r, "end chxj_save_cookie() CookieOff");
77     return NULL;
78   }
79
80   refer_string = apr_psprintf(r->pool, 
81                               "CHXJ_REFER=%s", 
82                               apr_uri_unparse(r->pool,
83                                               &r->parsed_uri,
84                                               APR_URI_UNP_OMITQUERY));
85   apr_table_setn(r->headers_out, "Set-Cookie", refer_string);
86
87
88   headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
89   hentryp = (apr_table_entry_t*)headers->elts;
90
91
92   new_cookie_table = apr_table_make(r->pool, 0);
93
94   for (ii=0; ii<headers->nelts; ii++) {
95     if (strcasecmp(hentryp[ii].key, "Set-Cookie") == 0) {
96       DBG(r, "=====================================");
97       DBG2(r, "cookie=[%s:%s]", hentryp[ii].key, hentryp[ii].val);
98
99       char* key;
100       char* val;
101       char* buff;
102
103       buff = apr_pstrdup(r->pool, hentryp[ii].val);
104       val = strchr(buff, '=');
105       if (val) {
106         key = buff;
107         *val++ = 0;
108         apr_table_add(new_cookie_table, key, val);
109       }
110
111       has_cookie = 1;
112       DBG(r, "=====================================");
113     }
114   }
115   apr_table_unset(r->headers_out, "Set-Cookie");
116
117   /*
118    * check input parameters
119    */
120   old_cookie_id = (char*)apr_table_get(r->headers_in, "CHXJ_COOKIE_ID");
121   if (old_cookie_id) {
122     old_cookie = chxj_load_cookie(r, old_cookie_id); 
123     if (old_cookie && old_cookie->cookie_headers) {
124       hentryp = (apr_table_entry_t*)old_cookie->cookie_headers->elts;
125       for (ii=0; ii<old_cookie->cookie_headers->nelts; ii++) {
126         if (hentryp[ii].key && apr_table_get(new_cookie_table, hentryp[ii].key) == NULL) {
127           apr_table_setn(new_cookie_table, hentryp[ii].key, hentryp[ii].val);
128           has_cookie = 1;
129         }
130       }
131       chxj_delete_cookie(r,        old_cookie_id);
132       chxj_delete_cookie_expire(r, old_cookie_id);
133     }
134   }
135
136   if (! has_cookie) {
137     DBG(r, "no cookie");
138     return NULL;
139   }
140
141   file = chxj_cookie_db_lock(r);
142   if (! file) {
143     ERR(r, "mod_chxj: Can't lock cookie db");
144     return NULL;
145   }
146
147   DBG(r, " ");
148
149   retval = apr_dbm_open_ex(&f, 
150                            "default", 
151                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir), 
152                            APR_DBM_RWCREATE, 
153                            APR_OS_DEFAULT, 
154                            r->pool);
155   if (retval != APR_SUCCESS) {
156     ERR2(r, "could not open dbm (type %s) auth file: %s", 
157             "default", 
158             chxj_cookie_db_name_create(r,dconf->cookie_db_dir));
159     chxj_cookie_db_unlock(r, file);
160     return NULL;
161   }
162
163   apr_uuid_get(&uuid);
164   uuid_string = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
165   memset(uuid_string, 0, APR_UUID_FORMATTED_LENGTH + 1);
166   apr_uuid_format(uuid_string, &uuid);;
167
168   md5_value = (unsigned char*)apr_palloc(r->pool, APR_MD5_DIGESTSIZE + 1);
169   memset(md5_value, 0, APR_MD5_DIGESTSIZE + 1);
170
171   retval = apr_md5(md5_value, 
172                    (const char*)uuid_string, 
173                    (apr_size_t)APR_UUID_FORMATTED_LENGTH);
174   if (retval != APR_SUCCESS) {
175     ERR(r, "md5 failed.");
176     goto on_error;
177   }
178
179   cookie->cookie_id = apr_palloc(r->pool, apr_base64_encode_len(APR_MD5_DIGESTSIZE)+1);
180   memset(cookie->cookie_id, 0, APR_MD5_DIGESTSIZE+1);
181   apr_base64_encode(cookie->cookie_id, (char*)md5_value, APR_MD5_DIGESTSIZE);
182
183   DBG1(r, "cookie->cookie_id=[%s]", cookie->cookie_id);
184
185   cookie->cookie_id = chxj_url_encode(r,cookie->cookie_id);
186
187   DBG1(r, "cookie->cookie_id=[%s]", cookie->cookie_id);
188
189   /*
190    * create key
191    */
192
193   dbmkey.dptr  = cookie->cookie_id;
194   dbmkey.dsize = strlen(cookie->cookie_id);
195
196   /*
197    * create val
198    */
199   cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(new_cookie_table);
200   store_string = apr_palloc(r->pool, 1);
201   store_string[0] = 0;
202   hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
203
204   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
205     if (ii) store_string = apr_pstrcat(r->pool,
206                                store_string, 
207                                "\n",
208                                NULL);
209
210     store_string = apr_pstrcat(r->pool, 
211                                store_string, 
212                                hentryp[ii].key, 
213                                "=",
214                                hentryp[ii].val, 
215                                NULL);
216   }
217   dbmval.dptr  = store_string;
218   dbmval.dsize = strlen(store_string);
219
220   /*
221    * store to db
222    */
223   retval = apr_dbm_store(f, dbmkey, dbmval);
224   if (retval != APR_SUCCESS) {
225     ERR1(r, "Cannot store Cookie data to DBM file `%s'",
226             chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
227     goto on_error;
228   }
229
230   chxj_save_cookie_expire(r, cookie);
231
232
233 on_error:
234   apr_dbm_close(f);
235   chxj_cookie_db_unlock(r, file);
236
237   DBG(r, "end   chxj_save_cookie()");
238   return cookie;
239 }
240
241 /*
242  *
243  */
244 cookie_t*
245 chxj_update_cookie(request_rec* r, cookie_t* old_cookie)
246 {
247   int                 ii;
248   apr_array_header_t* headers;
249   apr_table_entry_t*  hentryp;
250   apr_status_t        retval;
251   apr_datum_t         dbmkey;
252   apr_datum_t         dbmval;
253   apr_dbm_t*          f;
254   apr_uuid_t          uuid;
255   char*               uuid_string;
256   unsigned char*      md5_value;
257   char*               store_string;
258   mod_chxj_config*    dconf;
259   chxjconvrule_entry* entryp;
260   apr_file_t*         file;
261   cookie_t*           cookie;
262
263
264   DBG(r, "start chxj_update_cookie()");
265   if (!old_cookie || ! old_cookie->cookie_headers || ! old_cookie->cookie_id) {
266     DBG(r, "end chxj_update_cookie() (old_cookie is null)");
267     return  NULL;
268   }
269
270   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
271   cookie->cookie_id = NULL;
272
273
274   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
275   entryp = chxj_apply_convrule(r, dconf->convrules);
276   if (! entryp) {
277     DBG(r, "end chxj_update_cookie() no pattern");
278     return NULL;
279   }
280   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
281     DBG(r, "end chxj_update_cookie() CookieOff");
282     return NULL;
283   }
284
285
286   headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
287   hentryp = (apr_table_entry_t*)headers->elts;
288
289
290   chxj_delete_cookie(r,        old_cookie->cookie_id);
291   chxj_delete_cookie_expire(r, old_cookie->cookie_id);
292
293   file = chxj_cookie_db_lock(r);
294   if (! file) {
295     ERR(r, "mod_chxj: Can't lock cookie db");
296     return NULL;
297   }
298
299   DBG(r, " ");
300
301   retval = apr_dbm_open_ex(&f, 
302                            "default", 
303                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir), 
304                            APR_DBM_RWCREATE, 
305                            APR_OS_DEFAULT, 
306                            r->pool);
307   if (retval != APR_SUCCESS) {
308     ERR2(r, "could not open dbm (type %s) auth file: %s", 
309             "default", 
310             chxj_cookie_db_name_create(r,dconf->cookie_db_dir));
311     chxj_cookie_db_unlock(r, file);
312     return NULL;
313   }
314   DBG(r, " ");
315
316   apr_uuid_get(&uuid);
317   uuid_string = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
318   memset(uuid_string, 0, APR_UUID_FORMATTED_LENGTH + 1);
319   apr_uuid_format(uuid_string, &uuid);;
320
321   md5_value = (unsigned char*)apr_palloc(r->pool, APR_MD5_DIGESTSIZE + 1);
322   memset(md5_value, 0, APR_MD5_DIGESTSIZE + 1);
323
324   retval = apr_md5(md5_value, 
325                    (const char*)uuid_string, 
326                    (apr_size_t)APR_UUID_FORMATTED_LENGTH);
327   if (retval != APR_SUCCESS) {
328     ERR(r, "md5 failed.");
329     goto on_error;
330   }
331   DBG(r, " ");
332
333   cookie->cookie_id = apr_palloc(r->pool, apr_base64_encode_len(APR_MD5_DIGESTSIZE)+1);
334   memset(cookie->cookie_id, 0, APR_MD5_DIGESTSIZE+1);
335   apr_base64_encode(cookie->cookie_id, (char*)md5_value, APR_MD5_DIGESTSIZE);
336
337   cookie->cookie_id = chxj_url_encode(r,cookie->cookie_id);
338
339   DBG(r, " ");
340
341   /*
342    * create key
343    */
344
345   dbmkey.dptr  = cookie->cookie_id;
346   dbmkey.dsize = strlen(cookie->cookie_id);
347
348   /*
349    * create val
350    */
351   cookie->cookie_headers = old_cookie->cookie_headers;
352   store_string = apr_palloc(r->pool, 1);
353   store_string[0] = 0;
354   hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
355
356   for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
357     if (ii) store_string = apr_pstrcat(r->pool,
358                                store_string, 
359                                "\n",
360                                NULL);
361
362     DBG2(r, "OLD COOKIE VALUE=[%s][%s]", hentryp[ii].key, hentryp[ii].val);
363     store_string = apr_pstrcat(r->pool, 
364                                store_string, 
365                                hentryp[ii].key, 
366                                "=",
367                                hentryp[ii].val, 
368                                NULL);
369   }
370   dbmval.dptr  = store_string;
371   dbmval.dsize = strlen(store_string);
372
373   /*
374    * store to db
375    */
376   retval = apr_dbm_store(f, dbmkey, dbmval);
377   if (retval != APR_SUCCESS) {
378     ERR1(r, "Cannot store Cookie data to DBM file `%s'",
379             chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
380     goto on_error;
381   }
382
383   chxj_save_cookie_expire(r, cookie);
384
385   apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
386
387
388 on_error:
389   apr_dbm_close(f);
390   chxj_cookie_db_unlock(r, file);
391
392   DBG(r, "end   chxj_update_cookie()");
393   return cookie;
394 }
395
396
397 /*
398  *
399  * @return loaded data.
400  */
401 cookie_t*
402 chxj_load_cookie(request_rec* r, char* cookie_id)
403 {
404   apr_status_t            retval;
405   apr_datum_t             dbmkey;
406   apr_datum_t             dbmval;
407   apr_dbm_t*              f;
408   mod_chxj_config*        dconf;
409   chxjconvrule_entry*     entryp;
410   apr_file_t*             file;
411   cookie_t*               cookie;
412   apr_table_t*            load_cookie_table;
413   char*                   load_string;
414   char*                   pstat;
415   char*                   key;
416   char*                   val;
417   char*                   pair;
418
419   DBG(r, "========================================================");
420   DBG(r, "========================================================");
421   DBG(r, "========================================================");
422   DBG(r, "========================================================");
423   DBG1(r, "start chxj_load_cookie() cookie_id=[%s]", cookie_id);
424   chxj_cookie_expire_gc(r);
425
426   cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
427   cookie->cookie_headers = NULL;
428   cookie->cookie_id = apr_pstrdup(r->pool, cookie_id);
429
430   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
431   entryp = chxj_apply_convrule(r, dconf->convrules);
432   if (! entryp) {
433     DBG(r, "end chxj_load_cookie() no pattern");
434     goto on_error0;
435   }
436   if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
437     DBG(r, "end chxj_load_cookie() CookieOff");
438     goto on_error0;
439   }
440
441
442   file = chxj_cookie_db_lock(r);
443   if (! file) {
444     ERR(r, "mod_chxj: Can't lock cookie db");
445     goto on_error0;
446   }
447
448   retval = apr_dbm_open_ex(&f, 
449                            "default", 
450                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir),
451                            APR_DBM_RWCREATE, 
452                            APR_OS_DEFAULT, 
453                            r->pool);
454   if (retval != APR_SUCCESS) {
455     ERR2(r, 
456          "could not open dbm (type %s) auth file: %s", 
457          "default", 
458          chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
459     goto on_error1;
460   }
461
462   /*
463    * create key
464    */
465   dbmkey.dptr  = apr_pstrdup(r->pool, cookie->cookie_id);
466   dbmkey.dsize = strlen(dbmkey.dptr);
467   if (apr_dbm_exists(f, dbmkey)) {
468   
469     retval = apr_dbm_fetch(f, dbmkey, &dbmval);
470     if (retval != APR_SUCCESS) {
471       ERR2(r, 
472            "could not fetch dbm (type %s) auth file: %s", "default", 
473            chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
474       goto on_error2;
475     }
476     load_cookie_table = apr_table_make(r->pool, 0);
477     load_string = apr_palloc(r->pool, dbmval.dsize+1);
478
479     memset(load_string, 0, dbmval.dsize+1);
480     memcpy(load_string, dbmval.dptr, dbmval.dsize);
481     for (;;) {
482       char* tmp_sem;
483       pair = apr_strtok(load_string, "\n", &pstat);  
484       load_string = NULL;
485       if (!pair) break;
486
487       DBG1(r, "Cookie:[%s]", pair);
488       char* tmp_pair;
489
490       tmp_pair = apr_pstrdup(r->pool, pair);
491       val = strchr(tmp_pair, '=');
492       if (val) {
493         key = tmp_pair;
494         *val++ = 0;
495         apr_table_add(load_cookie_table, key, val);
496       }
497       tmp_sem = strchr(pair, ';'); 
498       if (tmp_sem)
499         *tmp_sem = '\0';
500
501       apr_table_setn(r->headers_in, "Cookie", pair);
502     }
503   
504     cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(load_cookie_table);
505   
506     /*
507      * save cookie_id to request header.
508      */
509     apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
510   }
511   apr_dbm_close(f);
512   chxj_cookie_db_unlock(r, file);
513   DBG(r, "end   chxj_load_cookie()");
514   DBG(r, "========================================================");
515   DBG(r, "========================================================");
516   DBG(r, "========================================================");
517   DBG(r, "========================================================");
518
519   return cookie;
520
521
522 on_error2:
523   apr_dbm_close(f);
524
525 on_error1:
526   chxj_cookie_db_unlock(r, file);
527
528 on_error0:
529
530   DBG(r, "end   chxj_load_cookie()");
531   DBG(r, "========================================================");
532   DBG(r, "========================================================");
533   DBG(r, "========================================================");
534   DBG(r, "========================================================");
535   return NULL;
536 }
537
538
539 char*
540 chxj_add_cookie_parameter(request_rec* r, char* value, cookie_t* cookie)
541 {
542   char* qs;
543   char* dst;
544
545   DBG1(r, "start chxj_add_cookie_parameter() cookie_id=[%s]", (cookie) ? cookie->cookie_id : NULL);
546
547   dst = apr_pstrdup(r->pool, value);
548
549   if (!cookie)
550     goto on_error;
551
552   if (!cookie->cookie_id)
553     goto on_error;
554
555   if (chxj_cookie_check_host(r, value) != 0) {
556     DBG(r, "end chxj_add_cookie_parameter()(check host)");
557     goto on_error;
558   }
559
560   qs = strchr(dst, '?');
561   if (qs) {
562     dst = apr_psprintf(r->pool, "%s&%s=%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id);
563   }
564   else {
565     dst = apr_psprintf(r->pool, "%s?%s=%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id);
566   }
567
568   DBG1(r, "end   chxj_add_cookie_parameter() dst=[%s]", dst);
569
570   return dst;
571
572 on_error:
573   DBG(r, "end   chxj_add_cookie_parameter() (on_error)");
574   return dst;
575 }
576
577
578 int
579 chxj_cookie_check_host(request_rec* r, char* value) 
580 {
581   char* hostnm;
582
583   DBG1(r, "hostname=[%s]", r->hostname);
584
585   hostnm = s_get_hostname_from_url(r, value);
586   if (hostnm) {
587     if (strcasecmp(hostnm, r->hostname) == 0)
588       return 0;
589     else
590       return 1;
591   }
592   return 0;
593 }
594
595
596 static char*
597 s_get_hostname_from_url(request_rec* r, char* value)
598 {
599   if (!value) 
600     return NULL; 
601
602   if (strncasecmp(value, "http://",  7) == 0 )
603     return s_cut_until_end_hostname(r, &value[7]);
604
605   if (strncasecmp(value, "https://", 8) == 0)
606     return s_cut_until_end_hostname(r, &value[8]);
607
608   return NULL;
609 }
610
611
612 static char* 
613 s_cut_until_end_hostname(request_rec* r, char* value)
614 {
615   char* sp;
616   char* hostnm;
617
618   hostnm = sp = apr_pstrdup(r->pool, value);
619   for (;*sp; sp++) {
620     if (*sp == '/'|| *sp == '?') {
621       *sp = '\0';
622       break;
623     }
624   }
625   return hostnm;
626 }
627
628
629 apr_file_t*
630 chxj_cookie_db_lock(request_rec* r)
631 {
632   apr_file_t*      file;
633   apr_status_t     rv;
634   mod_chxj_config* dconf;
635
636   dconf = (mod_chxj_config*)ap_get_module_config(r->per_dir_config, &chxj_module);
637
638   rv = apr_file_open(&file, 
639                      chxj_cookie_db_lock_name_create(r, dconf->cookie_db_dir),
640                      APR_CREATE|APR_WRITE, 
641                      APR_OS_DEFAULT, 
642                      r->pool);
643   if (rv != APR_SUCCESS) {
644     ERR(r, "cookie lock file open failed.");
645     return NULL;
646   }
647
648   rv = apr_file_lock(file,APR_FLOCK_EXCLUSIVE);
649   if (rv != APR_SUCCESS) {
650     ERR(r, "cookie lock file open failed.");
651     apr_file_close(file);
652     return NULL;
653   }
654
655   return file;
656 }
657
658
659 void
660 chxj_cookie_db_unlock(request_rec* r, apr_file_t* file)
661 {
662   apr_status_t rv;
663
664   rv = apr_file_unlock(file);
665   if (rv != APR_SUCCESS) {
666     ERR(r, "cookie lock file open failed.");
667     return;
668   }
669
670   apr_file_close(file);
671 }
672
673
674 void
675 chxj_delete_cookie(request_rec* r, char* cookie_id)
676 {
677   apr_status_t      retval;
678   apr_datum_t       dbmkey;
679   apr_dbm_t*        f;
680   apr_file_t*       file;
681   mod_chxj_config*  dconf;
682
683   DBG(r, "start chxj_delete_cookie()");
684
685   file = chxj_cookie_db_lock(r);
686   if (! file) {
687     ERR(r, "mod_chxj: Can't lock cookie db");
688     goto on_error0;
689   }
690   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
691
692   retval = apr_dbm_open_ex(&f,
693                            "default",
694                            chxj_cookie_db_name_create(r, dconf->cookie_db_dir),
695                            APR_DBM_RWCREATE,
696                            APR_OS_DEFAULT,
697                            r->pool);
698   if (retval != APR_SUCCESS) {
699     ERR2(r, 
700          "could not open dbm (type %s) auth file: %s", 
701          "default", 
702          chxj_cookie_db_name_create(r,dconf->cookie_db_dir));
703     goto on_error1;
704   }
705
706   /*
707    * create key
708    */
709   dbmkey.dptr  = apr_pstrdup(r->pool, cookie_id);
710   dbmkey.dsize = strlen(dbmkey.dptr);
711   if (apr_dbm_exists(f, dbmkey)) {
712     apr_dbm_delete(f, dbmkey);
713   }
714   apr_dbm_close(f);
715   chxj_cookie_db_unlock(r, file);
716
717   DBG(r, "end   chxj_delete_cookie()");
718
719   return;
720
721 on_error1:
722   chxj_cookie_db_unlock(r, file);
723
724 on_error0:
725   return;
726
727 }
728
729
730 char*
731 chxj_cookie_db_name_create(request_rec* r, const char* dir)
732 {
733   char* dst;
734
735   if (!dir) {
736     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
737   }
738   else {
739     dst = apr_pstrdup(r->pool, dir);
740   }
741
742   if (dst[strlen(dst)-1] != '/') {
743     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_DB_NAME, NULL);
744   }
745   else {
746     dst = apr_pstrcat(r->pool, dst, COOKIE_DB_NAME, NULL);
747   }
748
749   return dst;
750 }
751
752
753 char*
754 chxj_cookie_db_lock_name_create(request_rec* r, const char* dir)
755 {
756   char* dst;
757   DBG(r, "start  chxj_cookie_db_lock_name_create()");
758
759   if (!dir) {
760 DBG(r, " ");
761     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
762 DBG(r, " ");
763   }
764   else {
765 DBG1(r, " dir=[%x]", (unsigned int)dir);
766     dst = apr_pstrdup(r->pool, dir);
767 DBG(r, " ");
768   }
769 DBG1(r, "dst[strlen(dst)-1]=[%c]", dst[strlen(dst)-1]);
770   if (dst[strlen(dst)-1] != '/') {
771     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_DB_LOCK_NAME, NULL);
772   }
773   else {
774     dst = apr_pstrcat(r->pool, dst, COOKIE_DB_LOCK_NAME, NULL);
775   }
776   DBG(r, "end  chxj_cookie_db_lock_name_create()");
777   return dst;
778 }
779 /*
780  *
781  */
782 void
783 chxj_save_cookie_expire(request_rec* r, cookie_t* cookie)
784 {
785   apr_status_t            retval;
786   apr_datum_t             dbmkey;
787   apr_datum_t             dbmval;
788   apr_dbm_t*              f;
789   apr_file_t*             file;
790   mod_chxj_config*        dconf;
791   char*                   store_string;
792
793   DBG(r, "start chxj_save_cookie_expire()");
794   if (!cookie) {
795     DBG(r, "cookie is NULL");
796     return;
797   }
798
799   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
800   if (!dconf) {
801     DBG(r, "dconf is NULL");
802     return;
803   }
804
805   file = chxj_cookie_expire_db_lock(r);
806   if (! file) {
807     ERR(r, "mod_chxj: Can't lock cookie db");
808     return;
809   }
810
811   DBG(r, " ");
812
813   retval = apr_dbm_open_ex(&f, 
814                            "default", 
815                            chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir), 
816                            APR_DBM_RWCREATE, 
817                            APR_OS_DEFAULT, 
818                            r->pool);
819   if (retval != APR_SUCCESS) {
820     ERR2(r, "could not open dbm (type %s) auth file: %s", 
821             "default", 
822             chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
823     chxj_cookie_expire_db_unlock(r, file);
824     return;
825   }
826   /*
827    * create key
828    */
829
830   dbmkey.dptr  = cookie->cookie_id;
831   dbmkey.dsize = strlen(cookie->cookie_id);
832
833   /*
834    * create val
835    */
836   
837   store_string = apr_psprintf(r->pool, "%d", (int)time(NULL));
838   dbmval.dptr  = store_string;
839   dbmval.dsize = strlen(store_string);
840
841   /*
842    * store to db
843    */
844   retval = apr_dbm_store(f, dbmkey, dbmval);
845   if (retval != APR_SUCCESS) {
846     ERR1(r, "Cannot store Cookie data to DBM file `%s'",
847             chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
848   }
849
850
851   apr_dbm_close(f);
852   chxj_cookie_expire_db_unlock(r, file);
853
854   DBG(r, "end   chxj_save_cookie_expire()");
855 }
856
857
858 char*
859 chxj_cookie_expire_db_name_create(request_rec* r, const char* dir)
860 {
861   char* dst;
862
863   if (!dir) {
864     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
865   }
866   else {
867     dst = apr_pstrdup(r->pool, dir);
868   }
869
870   if (dst[strlen(dst)-1] != '/') {
871     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_EXPIRE_DB_NAME, NULL);
872   }
873   else {
874     dst = apr_pstrcat(r->pool, dst, COOKIE_EXPIRE_DB_NAME, NULL);
875   }
876
877   return dst;
878 }
879
880
881 char*
882 chxj_cookie_expire_db_lock_name_create(request_rec* r, const char* dir)
883 {
884   char* dst;
885
886   if (!dir) {
887     dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
888   }
889   else {
890     dst = apr_pstrdup(r->pool, dir);
891   }
892   if (dst[strlen(dst)-1] != '/') {
893     dst = apr_pstrcat(r->pool, dst, "/", COOKIE_EXPIRE_DB_LOCK_NAME, NULL);
894   }
895   else {
896     dst = apr_pstrcat(r->pool, dst, COOKIE_EXPIRE_DB_LOCK_NAME, NULL);
897   }
898
899   return dst;
900 }
901
902
903 apr_file_t*
904 chxj_cookie_expire_db_lock(request_rec* r)
905 {
906   apr_file_t*      file;
907   apr_status_t     rv;
908   mod_chxj_config* dconf;
909
910   dconf = (mod_chxj_config*)ap_get_module_config(r->per_dir_config, &chxj_module);
911
912   rv = apr_file_open(&file, 
913                      chxj_cookie_expire_db_lock_name_create(r, dconf->cookie_db_dir),
914                      APR_CREATE|APR_WRITE, 
915                      APR_OS_DEFAULT, 
916                      r->pool);
917   if (rv != APR_SUCCESS) {
918     ERR(r, "cookie lock file open failed.");
919     return NULL;
920   }
921
922   rv = apr_file_lock(file,APR_FLOCK_EXCLUSIVE);
923   if (rv != APR_SUCCESS) {
924     ERR(r, "cookie lock file open failed.");
925     apr_file_close(file);
926     return NULL;
927   }
928
929   return file;
930 }
931
932
933 void
934 chxj_cookie_expire_db_unlock(request_rec* r, apr_file_t* file)
935 {
936   apr_status_t rv;
937
938   rv = apr_file_unlock(file);
939   if (rv != APR_SUCCESS) {
940     ERR(r, "cookie lock file open failed.");
941     return;
942   }
943
944   apr_file_close(file);
945 }
946
947 void
948 chxj_delete_cookie_expire(request_rec* r, char* cookie_id)
949 {
950   apr_status_t      retval;
951   apr_datum_t       dbmkey;
952   apr_dbm_t*        f;
953   apr_file_t*       file;
954   mod_chxj_config*  dconf;
955
956   DBG(r, "start chxj_delete_cookie_expire()");
957
958   file = chxj_cookie_expire_db_lock(r);
959   if (! file) {
960     ERR(r, "mod_chxj: Can't lock cookie db");
961     goto on_error0;
962   }
963   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
964
965   retval = apr_dbm_open_ex(&f,
966                            "default",
967                            chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir),
968                            APR_DBM_RWCREATE,
969                            APR_OS_DEFAULT,
970                            r->pool);
971   if (retval != APR_SUCCESS) {
972     ERR2(r, 
973          "could not open dbm (type %s) auth file: %s", 
974          "default", 
975          chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
976     goto on_error1;
977   }
978
979   /*
980    * create key
981    */
982   dbmkey.dptr  = apr_pstrdup(r->pool, cookie_id);
983   dbmkey.dsize = strlen(dbmkey.dptr);
984   if (apr_dbm_exists(f, dbmkey)) {
985     apr_dbm_delete(f, dbmkey);
986   }
987   apr_dbm_close(f);
988   chxj_cookie_expire_db_unlock(r, file);
989
990   DBG(r, "end   chxj_delete_cookie_expire()");
991
992   return;
993
994 on_error1:
995   chxj_cookie_expire_db_unlock(r, file);
996
997 on_error0:
998   return;
999
1000 }
1001
1002
1003 void
1004 chxj_cookie_expire_gc(request_rec* r)
1005 {
1006   apr_status_t      retval;
1007   apr_datum_t       dbmkey;
1008   apr_datum_t       dbmval;
1009   apr_dbm_t*        f;
1010   apr_file_t*       file;
1011   mod_chxj_config*  dconf;
1012   time_t            now_time;
1013
1014   DBG(r, "start chxj_cookie_expire_gc()");
1015
1016   file = chxj_cookie_expire_db_lock(r);
1017   if (! file) {
1018     ERR(r, "mod_chxj: Can't lock cookie db");
1019     goto on_error0;
1020   }
1021   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
1022
1023   retval = apr_dbm_open_ex(&f,
1024                            "default",
1025                            chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir),
1026                            APR_DBM_RWCREATE,
1027                            APR_OS_DEFAULT,
1028                            r->pool);
1029   if (retval != APR_SUCCESS) {
1030     ERR2(r, 
1031          "could not open dbm (type %s) auth file: %s", 
1032          "default", 
1033          chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
1034     goto on_error1;
1035   }
1036
1037   /*
1038    * create key
1039    */
1040   memset(&dbmkey, 0, sizeof(apr_datum_t));
1041
1042   now_time = time(NULL);
1043
1044   retval = apr_dbm_firstkey(f, &dbmkey);
1045   if (retval == APR_SUCCESS) {
1046     DBG2(r, "firstkey=[%.*s]", dbmkey.dsize, dbmkey.dptr);
1047     do {
1048       char* tmp;
1049       char* old_cookie_id;
1050       int   val_time;
1051       int   cmp_time;
1052
1053       retval = apr_dbm_fetch(f, dbmkey, &dbmval);
1054       if (retval != APR_SUCCESS) {
1055         break;
1056       }
1057       tmp = apr_palloc(r->pool, dbmval.dsize+1);
1058       memset(tmp, 0, dbmval.dsize+1);
1059       memcpy(tmp, dbmval.dptr, dbmval.dsize);
1060
1061
1062       val_time = atoi(tmp);
1063
1064       if (dconf->cookie_timeout == 0)
1065         cmp_time = now_time - DEFAULT_COOKIE_TIMEOUT;
1066       else
1067         cmp_time = now_time - dconf->cookie_timeout;
1068
1069       DBG2(r, "key=[%.*s]", dbmkey.dsize, dbmkey.dptr);
1070       if (cmp_time >= val_time) {
1071         apr_dbm_delete(f, dbmkey);
1072
1073         old_cookie_id = apr_palloc(r->pool, dbmkey.dsize+1);
1074         memset(old_cookie_id, 0, dbmkey.dsize+1);
1075         memcpy(old_cookie_id, dbmkey.dptr, dbmkey.dsize);
1076
1077         chxj_delete_cookie(r,old_cookie_id);
1078         DBG1(r, "detect timeout cookie [%s]", old_cookie_id);
1079       }
1080
1081       retval = apr_dbm_nextkey(f, &dbmkey);
1082     } while(retval == APR_SUCCESS && dbmkey.dptr != NULL);
1083   }
1084
1085   apr_dbm_close(f);
1086   chxj_cookie_expire_db_unlock(r, file);
1087
1088   DBG(r, "end   chxj_cookie_expire_gc()");
1089
1090   return;
1091
1092 on_error1:
1093   chxj_cookie_expire_db_unlock(r, file);
1094
1095 on_error0:
1096   return;
1097
1098 }
1099 /*
1100  * vim:ts=2 et
1101  */