1 /* Internal cookies implementation */
10 #include <sys/types.h>
11 #include <sys/stat.h> /* OS/2 needs this after sys/types.h */
22 #include "bfu/dialog.h"
23 #include "cookies/cookies.h"
24 #include "cookies/dialogs.h"
25 #include "cookies/parser.h"
26 #include "config/home.h"
27 #include "config/kbdbind.h"
28 #include "config/options.h"
29 #include "intl/gettext/libintl.h"
30 #include "main/module.h"
31 #include "main/object.h"
32 #include "main/select.h"
33 #include "protocol/date.h"
34 #include "protocol/header.h"
35 #include "protocol/protocol.h"
36 #include "protocol/uri.h"
37 #include "session/session.h"
38 #include "terminal/terminal.h"
39 #include "util/conv.h"
41 #include "util/error.h"
43 #include "util/file.h"
44 #include "util/memory.h"
45 #include "util/secsave.h"
46 #include "util/string.h"
47 #include "util/time.h"
49 #define COOKIES_FILENAME "cookies"
52 static int cookies_nosave
= 0;
54 static INIT_LIST_OF(struct cookie
, cookies
);
57 LIST_HEAD(struct c_domain
);
59 unsigned char domain
[1]; /* Must be at end of struct. */
62 /* List of domains for which there may be cookies. This supposedly
63 * speeds up @send_cookies for other domains. Each element is a
64 * struct c_domain. No other data structures have pointers to these
65 * objects. Currently the domains remain in the list until
66 * @done_cookies clears the whole list. */
67 static INIT_LIST_OF(struct c_domain
, c_domains
);
69 /* List of servers for which there are cookies. */
70 static INIT_LIST_OF(struct cookie_server
, cookie_servers
);
72 /* Only @set_cookies_dirty may make this nonzero. */
73 static int cookies_dirty
= 0;
78 COOKIES_ACCEPT_POLICY
,
80 COOKIES_PARANOID_SECURITY
,
87 static struct option_info cookies_options
[] = {
88 INIT_OPT_TREE("", N_("Cookies"),
90 N_("Cookies options.")),
92 INIT_OPT_INT("cookies", N_("Accept policy"),
94 COOKIES_ACCEPT_NONE
, COOKIES_ACCEPT_ALL
, COOKIES_ACCEPT_ALL
,
95 N_("Cookies accepting policy:\n"
96 "0 is accept no cookies\n"
97 "1 is ask for confirmation before accepting cookie\n"
98 "2 is accept all cookies")),
100 INIT_OPT_INT("cookies", N_("Maximum age"),
101 "max_age", 0, -1, 10000, -1,
102 N_("Cookie maximum age (in days):\n"
103 "-1 is use cookie's expiration date if any\n"
104 "0 is force expiration at the end of session, ignoring cookie's\n"
106 "1+ is use cookie's expiration date, but limit age to the given\n"
109 INIT_OPT_BOOL("cookies", N_("Paranoid security"),
110 "paranoid_security", 0, 0,
111 N_("When enabled, we'll require three dots in cookies domain for all\n"
112 "non-international domains (instead of just two dots). Some countries\n"
113 "have generic second level domains (eg. .com.pl, .co.uk) and allowing\n"
114 "sites to set cookies for these generic domains could potentially be\n"
115 "very bad. Note, it is off by default as it breaks a lot of sites.")),
117 INIT_OPT_BOOL("cookies", N_("Saving"),
119 N_("Whether cookies should be loaded from and save to disk.")),
121 INIT_OPT_BOOL("cookies", N_("Resaving"),
123 N_("Save cookies after each change in cookies list? No effect when\n"
124 "cookie saving (cookies.save) is off.")),
129 #define get_opt_cookies(which) cookies_options[(which)].option.value
130 #define get_cookies_accept_policy() get_opt_cookies(COOKIES_ACCEPT_POLICY).number
131 #define get_cookies_max_age() get_opt_cookies(COOKIES_MAX_AGE).number
132 #define get_cookies_paranoid_security() get_opt_cookies(COOKIES_PARANOID_SECURITY).number
133 #define get_cookies_save() get_opt_cookies(COOKIES_SAVE).number
134 #define get_cookies_resave() get_opt_cookies(COOKIES_RESAVE).number
136 struct cookie_server
*
137 get_cookie_server(unsigned char *host
, int hostlen
)
139 struct cookie_server
*sort_spot
= NULL
;
140 struct cookie_server
*cs
;
142 foreach (cs
, cookie_servers
) {
143 /* XXX: We must count with cases like "x.co" vs "x.co.uk"
145 int cslen
= strlen(cs
->host
);
146 int cmp
= strncasecmp(cs
->host
, host
, hostlen
);
148 if (!sort_spot
&& (cmp
> 0 || (cmp
== 0 && cslen
> hostlen
))) {
149 /* This is the first @cs with name greater than @host,
150 * our dream sort spot! */
151 sort_spot
= cs
->prev
;
154 if (cmp
|| cslen
!= hostlen
)
161 cs
= mem_calloc(1, sizeof(*cs
) + hostlen
);
162 if (!cs
) return NULL
;
164 memcpy(cs
->host
, host
, hostlen
);
165 object_nolock(cs
, "cookie_server");
167 cs
->box_item
= add_listbox_folder(&cookie_browser
, NULL
, cs
);
172 /* No sort spot found, therefore this sorts at the end. */
173 add_to_list_end(cookie_servers
, cs
);
174 del_from_list(cs
->box_item
);
175 add_to_list_end(cookie_browser
.root
.child
, cs
->box_item
);
177 /* Sort spot found, sort after it. */
178 add_at_pos(sort_spot
, cs
);
179 if (sort_spot
!= (struct cookie_server
*) &cookie_servers
) {
180 del_from_list(cs
->box_item
);
181 add_at_pos(sort_spot
->box_item
, cs
->box_item
);
182 } /* else we are already at the top anyway. */
189 done_cookie_server(struct cookie_server
*cs
)
192 if (is_object_used(cs
)) return;
194 if (cs
->box_item
) done_listbox_item(&cookie_browser
, cs
->box_item
);
200 done_cookie(struct cookie
*c
)
202 if (c
->box_item
) done_listbox_item(&cookie_browser
, c
->box_item
);
203 if (c
->server
) done_cookie_server(c
->server
);
204 mem_free_if(c
->name
);
205 mem_free_if(c
->value
);
206 mem_free_if(c
->path
);
207 mem_free_if(c
->domain
);
211 /* The cookie @c can be either in @cookies or in @cookie_queries.
212 * Because changes in @cookie_queries should not affect the cookie
213 * file, this function does not set @cookies_dirty. Instead, the
214 * caller must do that if appropriate. */
216 delete_cookie(struct cookie
*c
)
223 /* Check whether cookie's domain matches server.
224 * It returns 1 if ok, 0 else. */
226 is_domain_security_ok(unsigned char *domain
, unsigned char *server
, int server_len
)
232 if (domain
[0] == '.') domain
++;
233 domain_len
= strlen(domain
);
235 /* Match domain and server.. */
237 /* XXX: Hmm, can't we use strlcasecmp() here? --pasky */
239 if (domain_len
> server_len
) return 0;
241 /* Ensure that the domain is atleast a substring of the server before
243 if (strncasecmp(domain
, server
+ server_len
- domain_len
, domain_len
))
246 /* Allow domains which are same as servers. --<rono@sentuny.com.au> */
247 /* Mozilla does it as well ;))) and I can't figure out any security
249 if (server_len
== domain_len
)
252 /* Check whether the server is an IP address, and require an exact host
253 * match for the cookie, so any chance of IP address funkiness is
254 * eliminated (e.g. the alias 127.1 domain-matching 99.54.127.1). Idea
255 * from mozilla. (bug 562) */
256 if (is_ip_address(server
, server_len
))
259 /* Also test if domain is secure en ugh.. */
263 if (get_cookies_paranoid_security()) {
264 /* This is somehow controversial attempt (by the way violating
265 * RFC) to increase cookies security in national domains, done
266 * by Mikulas. As it breaks a lot of sites, I decided to make
267 * this optional and off by default. I also don't think this
268 * improves security considerably, as it's SITE'S fault and
269 * also no other browser probably does it. --pasky */
270 /* Mikulas' comment: Some countries have generic 2-nd level
271 * domains (like .com.pl, .co.uk ...) and it would be very bad
272 * if someone set cookies for these generic domains. Imagine
273 * for example that server http://brutalporn.com.pl sets cookie
274 * Set-Cookie: user_is=perverse_pig; domain=.com.pl -- then
275 * this cookie would be sent to all commercial servers in
279 if (domain_len
> 0) {
280 int pos
= end_with_known_tld(domain
, domain_len
);
282 if (pos
>= 1 && domain
[pos
- 1] == '.')
287 for (i
= 0; domain
[i
]; i
++)
288 if (domain
[i
] == '.' && !--need_dots
)
291 if (need_dots
> 0) return 0;
295 /* Allocate a struct cookie and initialize it with the specified
296 * values (rather than copies). Returns NULL on error. On success,
297 * the cookie is basically safe for @done_cookie or @accept_cookie,
298 * although you may also want to set the remaining members and check
299 * @get_cookies_accept_policy and @is_domain_security_ok.
301 * The unsigned char * arguments must be allocated with @mem_alloc or
302 * equivalent, because @done_cookie will @mem_free them. Likewise,
303 * the caller must already have locked @server. If @init_cookie
304 * fails, then it frees the strings itself, and unlocks @server.
306 * If any parameter is NULL, then @init_cookie fails and does not
307 * consider that a bug. This means callers can use e.g. @stracpy
308 * and let @init_cookie check whether the call ran out of memory. */
310 init_cookie(unsigned char *name
, unsigned char *value
,
311 unsigned char *path
, unsigned char *domain
,
312 struct cookie_server
*server
)
314 struct cookie
*cookie
= mem_calloc(1, sizeof(*cookie
));
315 if (!cookie
|| !name
|| !value
|| !path
|| !domain
|| !server
) {
321 done_cookie_server(server
);
324 object_nolock(cookie
, "cookie"); /* Debugging purpose. */
327 cookie
->value
= value
;
328 cookie
->domain
= domain
;
330 cookie
->server
= server
; /* the caller already locked it for us */
336 set_cookie(struct uri
*uri
, unsigned char *str
)
338 unsigned char *path
, *domain
;
339 struct cookie
*cookie
;
340 struct cookie_str cstr
;
343 if (get_cookies_accept_policy() == COOKIES_ACCEPT_NONE
)
347 DBG("set_cookie -> (%s) %s", struri(uri
), str
);
350 if (!parse_cookie_str(&cstr
, str
)) return;
352 switch (parse_header_param(str
, "path", &path
)) {
353 unsigned char *path_end
;
355 case HEADER_PARAM_FOUND
:
357 || path
[strlen(path
) - 1] != '/')
358 add_to_strn(&path
, "/");
360 if (path
[0] != '/') {
361 add_to_strn(&path
, "x");
362 memmove(path
+ 1, path
, strlen(path
) - 1);
367 case HEADER_PARAM_NOT_FOUND
:
368 path
= get_uri_string(uri
, URI_PATH
);
372 path_end
= strrchr(path
, '/');
381 if (parse_header_param(str
, "domain", &domain
) == HEADER_PARAM_NOT_FOUND
)
382 domain
= memacpy(uri
->host
, uri
->hostlen
);
383 if (domain
&& domain
[0] == '.')
384 memmove(domain
, domain
+ 1, strlen(domain
));
386 cookie
= init_cookie(memacpy(str
, cstr
.nam_end
- str
),
387 memacpy(cstr
.val_start
, cstr
.val_end
- cstr
.val_start
),
390 get_cookie_server(uri
->host
, uri
->hostlen
));
392 /* @cookie now owns @path and @domain. */
395 /* We don't actually set ->accept at the moment. But I have kept it
396 * since it will maybe help to fix bug 77 - Support for more
397 * finegrained control upon accepting of cookies. */
398 if (!cookie
->server
->accept
) {
407 /* Set cookie expiration if needed.
408 * Cookie expires at end of session by default,
409 * set to 0 by calloc().
412 * -1 is use cookie's expiration date if any
413 * 0 is force expiration at the end of session,
414 * ignoring cookie's expiration date
415 * 1+ is use cookie's expiration date,
416 * but limit age to the given number of days.
419 max_age
= get_cookies_max_age();
424 switch (parse_header_param(str
, "expires", &date
)) {
425 case HEADER_PARAM_FOUND
:
426 expires
= parse_date(&date
, NULL
, 0, 1); /* Convert date to seconds. */
432 time_t seconds
= ((time_t) max_age
)*24*3600;
433 time_t deadline
= time(NULL
) + seconds
;
435 if (expires
> deadline
) /* Over-aged cookie ? */
439 cookie
->expires
= expires
;
443 case HEADER_PARAM_NOT_FOUND
:
452 cookie
->secure
= (parse_header_param(str
, "secure", NULL
)
453 == HEADER_PARAM_FOUND
);
457 DBG("Got cookie %s = %s from %s, domain %s, "
458 "expires at %"TIME_PRINT_FORMAT
", secure %d", cookie
->name
,
459 cookie
->value
, cookie
->server
->host
, cookie
->domain
,
460 (time_print_T
) cookie
->expires
, cookie
->secure
);
464 if (!is_domain_security_ok(cookie
->domain
, uri
->host
, uri
->hostlen
)) {
466 DBG("Domain security violated: %s vs %.*s", cookie
->domain
,
467 uri
->hostlen
, uri
->host
);
469 mem_free(cookie
->domain
);
470 cookie
->domain
= memacpy(uri
->host
, uri
->hostlen
);
473 /* We have already check COOKIES_ACCEPT_NONE */
474 if (get_cookies_accept_policy() == COOKIES_ACCEPT_ASK
) {
475 add_to_list(cookie_queries
, cookie
);
476 add_questions_entry(accept_cookie_dialog
, cookie
);
480 accept_cookie(cookie
);
484 accept_cookie(struct cookie
*cookie
)
487 struct listbox_item
*root
= cookie
->server
->box_item
;
491 cookie
->box_item
= add_listbox_leaf(&cookie_browser
, root
, cookie
);
493 /* Do not weed out duplicates when loading the cookie file. It doesn't
494 * scale at all, being O(N^2) and taking about 2s with my 500 cookies
495 * (so if you don't notice that 100ms with your 100 cookies, that's
496 * not an argument). --pasky */
497 if (!cookies_nosave
) {
498 struct cookie
*c
, *next
;
500 foreachsafe (c
, next
, cookies
) {
501 if (strcasecmp(c
->name
, cookie
->name
)
502 || strcasecmp(c
->domain
, cookie
->domain
))
506 /* @set_cookies_dirty will be called below. */
510 add_to_list(cookies
, cookie
);
513 /* XXX: This crunches CPU too. --pasky */
514 foreach (cd
, c_domains
)
515 if (!strcasecmp(cd
->domain
, cookie
->domain
))
518 domain_len
= strlen(cookie
->domain
);
519 /* One byte is reserved for domain in struct c_domain. */
520 cd
= mem_alloc(sizeof(*cd
) + domain_len
);
523 memcpy(cd
->domain
, cookie
->domain
, domain_len
+ 1);
524 add_to_list(c_domains
, cd
);
528 static unsigned int cookie_id
= 0;
531 delete_cookie(struct cookie
*c
)
537 if (!strcasecmp(d
->domain
, c
->domain
))
540 foreach (cd
, c_domains
) {
541 if (!strcasecmp(cd
->domain
, c
->domain
)) {
555 cookie
*find_cookie_id(void *idp
)
569 reject_cookie(void *idp
)
571 struct cookie
*c
= find_cookie_id(idp
);
576 set_cookies_dirty(); /* @find_cookie_id doesn't use @cookie_queries */
581 cookie_default(void *idp
, int a
)
583 struct cookie
*c
= find_cookie_id(idp
);
585 if (c
) c
->server
->accept
= a
;
590 accept_cookie_always(void *idp
)
592 cookie_default(idp
, 1);
597 accept_cookie_never(void *idp
)
599 cookie_default(idp
, 0);
604 /* Check whether domain is matching server
606 * example.com matches www.example.com/
607 * example.com doesn't match www.example.com.org/
608 * example.com doesn't match www.example.comm/
609 * example.com doesn't match example.co
612 is_in_domain(unsigned char *domain
, unsigned char *server
, int server_len
)
614 int domain_len
= strlen(domain
);
617 if (domain_len
> server_len
)
620 if (domain_len
== server_len
)
621 return !strncasecmp(domain
, server
, server_len
);
623 len
= server_len
- domain_len
;
624 if (server
[len
- 1] != '.')
627 return !strncasecmp(domain
, server
+ len
, domain_len
);
632 is_path_prefix(unsigned char *d
, unsigned char *s
)
636 /* TODO: strlcmp()? --pasky */
638 if (dl
> strlen(s
)) return 0;
640 return !memcmp(d
, s
, dl
);
645 send_cookies(struct uri
*uri
)
648 struct cookie
*c
, *next
;
649 unsigned char *path
= NULL
;
650 static struct string header
;
653 if (!uri
->host
|| !uri
->data
)
656 foreach (cd
, c_domains
)
657 if (is_in_domain(cd
->domain
, uri
->host
, uri
->hostlen
)) {
658 path
= get_uri_string(uri
, URI_PATH
);
662 if (!path
) return NULL
;
664 init_string(&header
);
667 foreachsafe (c
, next
, cookies
) {
668 if (!is_in_domain(c
->domain
, uri
->host
, uri
->hostlen
)
669 || !is_path_prefix(c
->path
, path
))
672 if (c
->expires
&& c
->expires
<= now
) {
674 DBG("Cookie %s=%s (exp %"TIME_PRINT_FORMAT
") expired.",
675 c
->name
, c
->value
, (time_print_T
) c
->expires
);
683 /* Not sure if this is 100% right..? --pasky */
684 if (c
->secure
&& uri
->protocol
!= PROTOCOL_HTTPS
)
688 add_to_string(&header
, "; ");
690 add_to_string(&header
, c
->name
);
691 add_char_to_string(&header
, '=');
692 add_to_string(&header
, c
->value
);
694 DBG("Cookie: %s=%s", c
->name
, c
->value
);
700 if (!header
.length
) {
701 done_string(&header
);
708 static void done_cookies(struct module
*module
);
713 /* Buffer size is set to be enough to read long lines that
714 * save_cookies may write. 6 is choosen after the fprintf(..) call
715 * in save_cookies(). --Zas */
716 unsigned char in_buffer
[6 * MAX_STR_LEN
];
717 unsigned char *cookfile
= COOKIES_FILENAME
;
722 cookfile
= straconcat(elinks_home
, cookfile
,
723 (unsigned char *) NULL
);
724 if (!cookfile
) return;
727 /* Do it here, as we will delete whole cookies list if the file was
730 done_cookies(&cookies_module
);
733 fp
= fopen(cookfile
, "rb");
734 if (elinks_home
) mem_free(cookfile
);
737 /* XXX: We don't want to overwrite the cookies file
738 * periodically to our death. */
742 while (fgets(in_buffer
, 6 * MAX_STR_LEN
, fp
)) {
743 struct cookie
*cookie
;
744 unsigned char *p
, *q
= in_buffer
;
745 enum { NAME
= 0, VALUE
, SERVER
, PATH
, DOMAIN
, EXPIRES
, SECURE
, MEMBERS
} member
;
752 /* First find all members. */
753 for (member
= NAME
; member
< MEMBERS
; member
++, q
= ++p
) {
756 if (member
+ 1 != MEMBERS
) break; /* last field ? */
761 members
[member
].pos
= q
;
762 members
[member
].len
= p
- q
;
765 if (member
!= MEMBERS
) continue; /* Invalid line. */
767 /* Skip expired cookies if any. */
768 expires
= str_to_time_t(members
[EXPIRES
].pos
);
769 if (!expires
|| expires
<= now
) {
774 /* Prepare cookie if all members and fields was read. */
775 cookie
= mem_calloc(1, sizeof(*cookie
));
776 if (!cookie
) continue;
778 cookie
->server
= get_cookie_server(members
[SERVER
].pos
, members
[SERVER
].len
);
779 cookie
->name
= memacpy(members
[NAME
].pos
, members
[NAME
].len
);
780 cookie
->value
= memacpy(members
[VALUE
].pos
, members
[VALUE
].len
);
781 cookie
->path
= memacpy(members
[PATH
].pos
, members
[PATH
].len
);
782 cookie
->domain
= memacpy(members
[DOMAIN
].pos
, members
[DOMAIN
].len
);
784 /* Check whether all fields were correctly allocated. */
785 if (!cookie
->server
|| !cookie
->name
|| !cookie
->value
786 || !cookie
->path
|| !cookie
->domain
) {
791 cookie
->expires
= expires
;
792 cookie
->secure
= !!atoi(members
[SECURE
].pos
);
794 accept_cookie(cookie
);
802 resave_cookies_bottom_half(void *always_null
)
804 if (get_cookies_save() && get_cookies_resave())
805 save_cookies(NULL
); /* checks cookies_dirty */
808 /* Note that the cookies have been modified, and register a bottom
809 * half for saving them if appropriate. We use a bottom half so that
810 * if something makes multiple changes and calls this for each change,
811 * the cookies get saved only once at the end. */
813 set_cookies_dirty(void)
815 /* Do not check @cookies_dirty here. If the previous attempt
816 * to save cookies failed, @cookies_dirty can still be nonzero
817 * even though @resave_cookies_bottom_half is no longer in the
820 /* If @resave_cookies_bottom_half is already in the queue,
821 * @register_bottom_half does nothing. */
822 register_bottom_half(resave_cookies_bottom_half
, NULL
);
825 /* @term is non-NULL if the user told ELinks to save cookies, or NULL
826 * if ELinks decided that on its own. In the former case, this
827 * function reports errors to @term, unless CONFIG_SMALL is defined.
828 * In the latter case, this function does not save the cookies if it
829 * thinks the file is already up to date. */
831 save_cookies(struct terminal
*term
) {
833 unsigned char *cookfile
;
834 struct secure_save_info
*ssi
;
838 # define CANNOT_SAVE_COOKIES(flags, message)
840 # define CANNOT_SAVE_COOKIES(flags, message) \
843 info_box(term, flags, N_("Cannot save cookies"),\
844 ALIGN_LEFT, message); \
848 if (cookies_nosave
) {
849 assert(term
== NULL
);
854 CANNOT_SAVE_COOKIES(0, N_("ELinks was started without a home directory."));
857 if (!cookies_dirty
&& !term
)
859 if (get_cmd_opt_bool("anonymous")) {
860 CANNOT_SAVE_COOKIES(0, N_("ELinks was started with the -anonymous option."));
864 cookfile
= straconcat(elinks_home
, COOKIES_FILENAME
,
865 (unsigned char *) NULL
);
867 CANNOT_SAVE_COOKIES(0, N_("Out of memory"));
871 ssi
= secure_open(cookfile
);
874 CANNOT_SAVE_COOKIES(MSGBOX_NO_TEXT_INTL
,
875 secsave_strerror(secsave_errno
, term
));
880 foreach (c
, cookies
) {
881 if (!c
->expires
|| c
->expires
<= now
) continue;
882 if (secure_fprintf(ssi
, "%s\t%s\t%s\t%s\t%s\t%"TIME_PRINT_FORMAT
"\t%d\n",
885 empty_string_or_(c
->path
),
886 empty_string_or_(c
->domain
),
887 (time_print_T
) c
->expires
, c
->secure
) < 0)
891 secsave_errno
= SS_ERR_OTHER
; /* @secure_close doesn't always set it */
892 if (!secure_close(ssi
)) cookies_dirty
= 0;
894 CANNOT_SAVE_COOKIES(MSGBOX_NO_TEXT_INTL
,
895 secsave_strerror(secsave_errno
, term
));
897 #undef CANNOT_SAVE_COOKIES
901 init_cookies(struct module
*module
)
903 if (get_cookies_save())
907 /* Like @delete_cookie, this function does not set @cookies_dirty.
908 * The caller must do that if appropriate. */
910 free_cookies_list(LIST_OF(struct cookie
) *list
)
912 while (!list_empty(*list
)) {
913 struct cookie
*cookie
= list
->next
;
915 delete_cookie(cookie
);
920 done_cookies(struct module
*module
)
922 free_list(c_domains
);
924 if (!cookies_nosave
&& get_cookies_save())
927 free_cookies_list(&cookies
);
928 free_cookies_list(&cookie_queries
);
929 /* If @save_cookies failed above, @cookies_dirty can still be
930 * nonzero. Now if @resave_cookies_bottom_half were in the
931 * queue, it could save the empty @cookies list to the file.
936 struct module cookies_module
= struct_module(
937 /* name: */ N_("Cookies"),
938 /* options: */ cookies_options
,
940 /* submodules: */ NULL
,
942 /* init: */ init_cookies
,
943 /* done: */ done_cookies