OSDN Git Service

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