2 * Copyright (C) 2005 QSDN,Inc. All rights reserved.
3 * Copyright (C) 2005 Atsushi Konno All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include "chxj_cookie.h"
21 #include "chxj_url_encode.h"
22 #include "chxj_apply_convrule.h"
28 #include "apr_base64.h"
30 static char* s_get_hostname_from_url(request_rec* r, char* value);
31 static char* s_cut_until_end_hostname(request_rec*, char* value);
37 chxj_save_cookie(request_rec* r)
40 apr_array_header_t* headers;
41 apr_table_entry_t* hentryp;
48 unsigned char* md5_value;
51 mod_chxj_config* dconf;
52 chxjconvrule_entry* entryp;
54 apr_table_t* new_cookie_table;
60 DBG(r, "start chxj_save_cookie()");
62 cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
63 cookie->cookie_id = NULL;
67 dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
68 entryp = chxj_apply_convrule(r, dconf->convrules);
70 DBG(r, "end chxj_save_cookie() no pattern");
73 if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
74 DBG(r, "end chxj_save_cookie() CookieOff");
79 headers = (apr_array_header_t*)apr_table_elts(r->headers_out);
80 hentryp = (apr_table_entry_t*)headers->elts;
83 new_cookie_table = apr_table_make(r->pool, 0);
85 for (ii=0; ii<headers->nelts; ii++) {
86 if (strcasecmp(hentryp[ii].key, "Set-Cookie") == 0) {
87 DBG(r, "=====================================");
88 DBG2(r, "cookie=[%s:%s]", hentryp[ii].key, hentryp[ii].val);
94 buff = apr_pstrdup(r->pool, hentryp[ii].val);
95 val = strchr(buff, '=');
99 apr_table_add(new_cookie_table, key, val);
103 DBG(r, "=====================================");
108 * check input parameters
110 old_cookie_id = (char*)apr_table_get(r->headers_in, "CHXJ_COOKIE_ID");
112 old_cookie = chxj_load_cookie(r, old_cookie_id);
113 if (old_cookie && old_cookie->cookie_headers) {
114 hentryp = (apr_table_entry_t*)old_cookie->cookie_headers->elts;
115 for (ii=0; ii<old_cookie->cookie_headers->nelts; ii++) {
116 if (hentryp[ii].key && apr_table_get(new_cookie_table, hentryp[ii].key) == NULL) {
117 apr_table_setn(new_cookie_table, hentryp[ii].key, hentryp[ii].val);
121 chxj_delete_cookie(r, old_cookie_id);
122 chxj_delete_cookie_expire(r, old_cookie_id);
131 file = chxj_cookie_db_lock(r);
133 ERR(r, "mod_chxj: Can't lock cookie db");
139 retval = apr_dbm_open_ex(&f,
141 chxj_cookie_db_name_create(r, dconf->cookie_db_dir),
145 if (retval != APR_SUCCESS) {
146 ERR2(r, "could not open dbm (type %s) auth file: %s",
148 chxj_cookie_db_name_create(r,dconf->cookie_db_dir));
149 chxj_cookie_db_unlock(r, file);
154 uuid_string = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
155 memset(uuid_string, 0, APR_UUID_FORMATTED_LENGTH + 1);
156 apr_uuid_format(uuid_string, &uuid);;
158 md5_value = (unsigned char*)apr_palloc(r->pool, APR_MD5_DIGESTSIZE + 1);
159 memset(md5_value, 0, APR_MD5_DIGESTSIZE + 1);
161 retval = apr_md5(md5_value,
162 (const char*)uuid_string,
163 (apr_size_t)APR_UUID_FORMATTED_LENGTH);
164 if (retval != APR_SUCCESS) {
165 ERR(r, "md5 failed.");
169 cookie->cookie_id = apr_palloc(r->pool, apr_base64_encode_len(APR_MD5_DIGESTSIZE)+1);
170 memset(cookie->cookie_id, 0, APR_MD5_DIGESTSIZE+1);
171 apr_base64_encode(cookie->cookie_id, (char*)md5_value, APR_MD5_DIGESTSIZE);
173 DBG1(r, "cookie->cookie_id=[%s]", cookie->cookie_id);
175 cookie->cookie_id = chxj_url_encode(r,cookie->cookie_id);
177 DBG1(r, "cookie->cookie_id=[%s]", cookie->cookie_id);
183 dbmkey.dptr = cookie->cookie_id;
184 dbmkey.dsize = strlen(cookie->cookie_id);
189 cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(new_cookie_table);
190 store_string = apr_palloc(r->pool, 1);
192 hentryp = (apr_table_entry_t*)cookie->cookie_headers->elts;
194 for (ii=0; ii<cookie->cookie_headers->nelts; ii++) {
195 if (ii) store_string = apr_pstrcat(r->pool,
200 store_string = apr_pstrcat(r->pool,
207 dbmval.dptr = store_string;
208 dbmval.dsize = strlen(store_string);
213 retval = apr_dbm_store(f, dbmkey, dbmval);
214 if (retval != APR_SUCCESS) {
215 ERR1(r, "Cannot store Cookie data to DBM file `%s'",
216 chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
220 chxj_save_cookie_expire(r, cookie);
225 chxj_cookie_db_unlock(r, file);
227 DBG(r, "end chxj_save_cookie()");
234 * @return loaded data.
237 chxj_load_cookie(request_rec* r, char* cookie_id)
243 mod_chxj_config* dconf;
244 chxjconvrule_entry* entryp;
247 apr_table_t* load_cookie_table;
254 DBG1(r, "start chxj_load_cookie() cookie_id=[%s]", cookie_id);
255 chxj_cookie_expire_gc(r);
257 cookie = (cookie_t*)apr_palloc(r->pool, sizeof(cookie_t));
258 cookie->cookie_headers = NULL;
259 cookie->cookie_id = apr_pstrdup(r->pool, cookie_id);
261 dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
262 entryp = chxj_apply_convrule(r, dconf->convrules);
264 DBG(r, "end chxj_load_cookie() no pattern");
267 if (! (entryp->action & CONVRULE_COOKIE_ON_BIT)) {
268 DBG(r, "end chxj_load_cookie() CookieOff");
273 file = chxj_cookie_db_lock(r);
275 ERR(r, "mod_chxj: Can't lock cookie db");
279 retval = apr_dbm_open_ex(&f,
281 chxj_cookie_db_name_create(r, dconf->cookie_db_dir),
285 if (retval != APR_SUCCESS) {
287 "could not open dbm (type %s) auth file: %s",
289 chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
296 dbmkey.dptr = apr_pstrdup(r->pool, cookie->cookie_id);
297 dbmkey.dsize = strlen(dbmkey.dptr);
298 if (apr_dbm_exists(f, dbmkey)) {
300 retval = apr_dbm_fetch(f, dbmkey, &dbmval);
301 if (retval != APR_SUCCESS) {
303 "could not fetch dbm (type %s) auth file: %s", "default",
304 chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
307 load_cookie_table = apr_table_make(r->pool, 0);
308 load_string = apr_palloc(r->pool, dbmval.dsize+1);
310 memset(load_string, 0, dbmval.dsize+1);
311 memcpy(load_string, dbmval.dptr, dbmval.dsize);
314 pair = apr_strtok(load_string, "\n", &pstat);
318 DBG1(r, "Cookie:[%s]", pair);
321 tmp_pair = apr_pstrdup(r->pool, pair);
322 val = strchr(tmp_pair, '=');
326 apr_table_add(load_cookie_table, key, val);
328 tmp_sem = strchr(pair, ';');
332 apr_table_setn(r->headers_in, "Cookie", pair);
335 cookie->cookie_headers = (apr_array_header_t*)apr_table_elts(load_cookie_table);
338 * save cookie_id to request header.
340 apr_table_setn(r->headers_in, "CHXJ_COOKIE_ID", cookie->cookie_id);
343 chxj_cookie_db_unlock(r, file);
344 DBG(r, "end chxj_load_cookie()");
353 chxj_cookie_db_unlock(r, file);
357 DBG(r, "end chxj_load_cookie()");
363 chxj_add_cookie_parameter(request_rec* r, char* value, cookie_t* cookie)
368 DBG1(r, "start chxj_add_cookie_parameter() cookie_id=[%s]", (cookie) ? cookie->cookie_id : NULL);
375 if (!cookie->cookie_id)
378 if (chxj_cookie_check_host(r, value) != 0) {
379 DBG(r, "end chxj_add_cookie_parameter()(check host)");
384 qs = strchr(dst, '?');
386 dst = apr_psprintf(r->pool, "%s&%s=%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id);
389 dst = apr_psprintf(r->pool, "%s?%s=%s", dst, CHXJ_COOKIE_PARAM, cookie->cookie_id);
392 DBG1(r, "end chxj_add_cookie_parameter() dst=[%s]", dst);
397 DBG(r, "end chxj_add_cookie_parameter() (on_error)");
403 chxj_cookie_check_host(request_rec* r, char* value)
407 DBG1(r, "hostname=[%s]", r->hostname);
409 hostnm = s_get_hostname_from_url(r, value);
411 if (strcasecmp(hostnm, r->hostname) == 0)
421 s_get_hostname_from_url(request_rec* r, char* value)
426 if (strncasecmp(value, "http://", 7) == 0 )
427 return s_cut_until_end_hostname(r, &value[7]);
429 if (strncasecmp(value, "https://", 8) == 0)
430 return s_cut_until_end_hostname(r, &value[8]);
437 s_cut_until_end_hostname(request_rec* r, char* value)
442 hostnm = sp = apr_pstrdup(r->pool, value);
444 if (*sp == '/'|| *sp == '?') {
454 chxj_cookie_db_lock(request_rec* r)
458 mod_chxj_config* dconf;
460 dconf = (mod_chxj_config*)ap_get_module_config(r->per_dir_config, &chxj_module);
462 rv = apr_file_open(&file,
463 chxj_cookie_db_lock_name_create(r, dconf->cookie_db_dir),
464 APR_CREATE|APR_WRITE,
467 if (rv != APR_SUCCESS) {
468 ERR(r, "cookie lock file open failed.");
472 rv = apr_file_lock(file,APR_FLOCK_EXCLUSIVE);
473 if (rv != APR_SUCCESS) {
474 ERR(r, "cookie lock file open failed.");
475 apr_file_close(file);
484 chxj_cookie_db_unlock(request_rec* r, apr_file_t* file)
488 rv = apr_file_unlock(file);
489 if (rv != APR_SUCCESS) {
490 ERR(r, "cookie lock file open failed.");
494 apr_file_close(file);
499 chxj_delete_cookie(request_rec* r, char* cookie_id)
505 mod_chxj_config* dconf;
507 DBG(r, "start chxj_delete_cookie()");
509 file = chxj_cookie_db_lock(r);
511 ERR(r, "mod_chxj: Can't lock cookie db");
514 dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
516 retval = apr_dbm_open_ex(&f,
518 chxj_cookie_db_name_create(r, dconf->cookie_db_dir),
522 if (retval != APR_SUCCESS) {
524 "could not open dbm (type %s) auth file: %s",
526 chxj_cookie_db_name_create(r,dconf->cookie_db_dir));
533 dbmkey.dptr = apr_pstrdup(r->pool, cookie_id);
534 dbmkey.dsize = strlen(dbmkey.dptr);
535 if (apr_dbm_exists(f, dbmkey)) {
536 apr_dbm_delete(f, dbmkey);
539 chxj_cookie_db_unlock(r, file);
541 DBG(r, "end chxj_delete_cookie()");
546 chxj_cookie_db_unlock(r, file);
555 chxj_cookie_db_name_create(request_rec* r, const char* dir)
560 dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
563 dst = apr_pstrdup(r->pool, dir);
566 if (dst[strlen(dst)-1] != '/') {
567 dst = apr_pstrcat(r->pool, dst, "/", COOKIE_DB_NAME, NULL);
570 dst = apr_pstrcat(r->pool, dst, COOKIE_DB_NAME, NULL);
578 chxj_cookie_db_lock_name_create(request_rec* r, const char* dir)
581 DBG(r, "start chxj_cookie_db_lock_name_create()");
585 dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
589 DBG1(r, " dir=[%x]", (unsigned int)dir);
590 dst = apr_pstrdup(r->pool, dir);
593 DBG1(r, "dst[strlen(dst)-1]=[%c]", dst[strlen(dst)-1]);
594 if (dst[strlen(dst)-1] != '/') {
595 dst = apr_pstrcat(r->pool, dst, "/", COOKIE_DB_LOCK_NAME, NULL);
598 dst = apr_pstrcat(r->pool, dst, COOKIE_DB_LOCK_NAME, NULL);
600 DBG(r, "end chxj_cookie_db_lock_name_create()");
607 chxj_save_cookie_expire(request_rec* r, cookie_t* cookie)
614 mod_chxj_config* dconf;
617 DBG(r, "start chxj_save_cookie_expire()");
619 DBG(r, "cookie is NULL");
623 dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
625 DBG(r, "dconf is NULL");
629 file = chxj_cookie_expire_db_lock(r);
631 ERR(r, "mod_chxj: Can't lock cookie db");
637 retval = apr_dbm_open_ex(&f,
639 chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir),
643 if (retval != APR_SUCCESS) {
644 ERR2(r, "could not open dbm (type %s) auth file: %s",
646 chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
647 chxj_cookie_expire_db_unlock(r, file);
654 dbmkey.dptr = cookie->cookie_id;
655 dbmkey.dsize = strlen(cookie->cookie_id);
661 store_string = apr_psprintf(r->pool, "%d", (int)time(NULL));
662 dbmval.dptr = store_string;
663 dbmval.dsize = strlen(store_string);
668 retval = apr_dbm_store(f, dbmkey, dbmval);
669 if (retval != APR_SUCCESS) {
670 ERR1(r, "Cannot store Cookie data to DBM file `%s'",
671 chxj_cookie_db_name_create(r, dconf->cookie_db_dir));
676 chxj_cookie_expire_db_unlock(r, file);
678 DBG(r, "end chxj_save_cookie_expire()");
683 chxj_cookie_expire_db_name_create(request_rec* r, const char* dir)
688 dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
691 dst = apr_pstrdup(r->pool, dir);
694 if (dst[strlen(dst)-1] != '/') {
695 dst = apr_pstrcat(r->pool, dst, "/", COOKIE_EXPIRE_DB_NAME, NULL);
698 dst = apr_pstrcat(r->pool, dst, COOKIE_EXPIRE_DB_NAME, NULL);
706 chxj_cookie_expire_db_lock_name_create(request_rec* r, const char* dir)
711 dst = apr_pstrdup(r->pool, DEFAULT_COOKIE_DB_DIR);
714 dst = apr_pstrdup(r->pool, dir);
716 if (dst[strlen(dst)-1] != '/') {
717 dst = apr_pstrcat(r->pool, dst, "/", COOKIE_EXPIRE_DB_LOCK_NAME, NULL);
720 dst = apr_pstrcat(r->pool, dst, COOKIE_EXPIRE_DB_LOCK_NAME, NULL);
728 chxj_cookie_expire_db_lock(request_rec* r)
732 mod_chxj_config* dconf;
734 dconf = (mod_chxj_config*)ap_get_module_config(r->per_dir_config, &chxj_module);
736 rv = apr_file_open(&file,
737 chxj_cookie_expire_db_lock_name_create(r, dconf->cookie_db_dir),
738 APR_CREATE|APR_WRITE,
741 if (rv != APR_SUCCESS) {
742 ERR(r, "cookie lock file open failed.");
746 rv = apr_file_lock(file,APR_FLOCK_EXCLUSIVE);
747 if (rv != APR_SUCCESS) {
748 ERR(r, "cookie lock file open failed.");
749 apr_file_close(file);
758 chxj_cookie_expire_db_unlock(request_rec* r, apr_file_t* file)
762 rv = apr_file_unlock(file);
763 if (rv != APR_SUCCESS) {
764 ERR(r, "cookie lock file open failed.");
768 apr_file_close(file);
772 chxj_delete_cookie_expire(request_rec* r, char* cookie_id)
778 mod_chxj_config* dconf;
780 DBG(r, "start chxj_delete_cookie_expire()");
782 file = chxj_cookie_expire_db_lock(r);
784 ERR(r, "mod_chxj: Can't lock cookie db");
787 dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
789 retval = apr_dbm_open_ex(&f,
791 chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir),
795 if (retval != APR_SUCCESS) {
797 "could not open dbm (type %s) auth file: %s",
799 chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
806 dbmkey.dptr = apr_pstrdup(r->pool, cookie_id);
807 dbmkey.dsize = strlen(dbmkey.dptr);
808 if (apr_dbm_exists(f, dbmkey)) {
809 apr_dbm_delete(f, dbmkey);
812 chxj_cookie_expire_db_unlock(r, file);
814 DBG(r, "end chxj_delete_cookie_expire()");
819 chxj_cookie_expire_db_unlock(r, file);
828 chxj_cookie_expire_gc(request_rec* r)
835 mod_chxj_config* dconf;
838 DBG(r, "start chxj_cookie_expire_gc()");
840 file = chxj_cookie_expire_db_lock(r);
842 ERR(r, "mod_chxj: Can't lock cookie db");
845 dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
847 retval = apr_dbm_open_ex(&f,
849 chxj_cookie_expire_db_name_create(r, dconf->cookie_db_dir),
853 if (retval != APR_SUCCESS) {
855 "could not open dbm (type %s) auth file: %s",
857 chxj_cookie_expire_db_name_create(r,dconf->cookie_db_dir));
864 memset(&dbmkey, 0, sizeof(apr_datum_t));
866 now_time = time(NULL);
868 retval = apr_dbm_firstkey(f, &dbmkey);
869 if (retval == APR_SUCCESS) {
876 retval = apr_dbm_fetch(f, dbmkey, &dbmval);
877 if (retval != APR_SUCCESS) {
880 tmp = apr_palloc(r->pool, dbmval.dsize+1);
881 memset(tmp, 0, dbmval.dsize+1);
882 memcpy(tmp, dbmval.dptr, dbmval.dsize);
885 val_time = atoi(tmp);
887 if (dconf->cookie_timeout == 0)
888 cmp_time = now_time - DEFAULT_COOKIE_TIMEOUT;
890 cmp_time = now_time - dconf->cookie_timeout;
892 if (cmp_time >= val_time) {
893 apr_dbm_delete(f, dbmkey);
895 old_cookie_id = apr_palloc(r->pool, dbmkey.dsize+1);
896 memset(old_cookie_id, 0, dbmkey.dsize+1);
897 memcpy(old_cookie_id, dbmkey.dptr, dbmkey.dsize);
899 chxj_delete_cookie(r,old_cookie_id);
902 retval = apr_dbm_nextkey(f, &dbmkey);
903 } while(retval == APR_SUCCESS);
907 chxj_cookie_expire_db_unlock(r, file);
909 DBG(r, "end chxj_cookie_expire_gc()");
914 chxj_cookie_expire_db_unlock(r, file);