]> sjero.net Git - wget/blob - src/cookies.c
Maintain the cookie value quoted if it was in the server response.
[wget] / src / cookies.c
1 /* Support for cookies.
2    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
3    2010, 2011 Free Software Foundation, Inc.
4
5 This file is part of GNU Wget.
6
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or (at
10 your option) any later version.
11
12 GNU Wget is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Wget.  If not, see <http://www.gnu.org/licenses/>.
19
20 Additional permission under GNU GPL version 3 section 7
21
22 If you modify this program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a
24 modified version of that library), containing parts covered by the
25 terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
26 grants you additional permission to convey the resulting work.
27 Corresponding Source for a non-source form of such a combination
28 shall include the source code for the parts of OpenSSL used as well
29 as that of the covered work.  */
30
31 /* Written by Hrvoje Niksic.  Parts are loosely inspired by the
32    cookie patch submitted by Tomasz Wegrzanowski.
33
34    This implements the client-side cookie support, as specified
35    (loosely) by Netscape's "preliminary specification", currently
36    available at:
37
38        http://wp.netscape.com/newsref/std/cookie_spec.html
39
40    rfc2109 is not supported because of its incompatibilities with the
41    above widely-used specification.  rfc2965 is entirely ignored,
42    since popular client software doesn't implement it, and even the
43    sites that do send Set-Cookie2 also emit Set-Cookie for
44    compatibility.  */
45
46 #include "wget.h"
47
48 #include <stdio.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include <assert.h>
52 #include <errno.h>
53 #include <time.h>
54 #include "utils.h"
55 #include "hash.h"
56 #include "cookies.h"
57 #include "http.h"               /* for http_atotm */
58 \f
59 /* Declarations of `struct cookie' and the most basic functions. */
60
61 /* Cookie jar serves as cookie storage and a means of retrieving
62    cookies efficiently.  All cookies with the same domain are stored
63    in a linked list called "chain".  A cookie chain can be reached by
64    looking up the domain in the cookie jar's chains_by_domain table.
65
66    For example, to reach all the cookies under google.com, one must
67    execute hash_table_get(jar->chains_by_domain, "google.com").  Of
68    course, when sending a cookie to `www.google.com', one must search
69    for cookies that belong to either `www.google.com' or `google.com'
70    -- but the point is that the code doesn't need to go through *all*
71    the cookies.  */
72
73 struct cookie_jar {
74   /* Cookie chains indexed by domain.  */
75   struct hash_table *chains;
76
77   int cookie_count;             /* number of cookies in the jar. */
78 };
79
80 /* Value set by entry point functions, so that the low-level
81    routines don't need to call time() all the time.  */
82 static time_t cookies_now;
83
84 struct cookie_jar *
85 cookie_jar_new (void)
86 {
87   struct cookie_jar *jar = xnew (struct cookie_jar);
88   jar->chains = make_nocase_string_hash_table (0);
89   jar->cookie_count = 0;
90   return jar;
91 }
92
93 struct cookie {
94   char *domain;                 /* domain of the cookie */
95   int port;                     /* port number */
96   char *path;                   /* path prefix of the cookie */
97
98   unsigned discard_requested :1; /* whether cookie was created to
99                                    request discarding another
100                                    cookie. */
101
102   unsigned secure :1;           /* whether cookie should be
103                                    transmitted over non-https
104                                    connections. */
105   unsigned domain_exact :1;     /* whether DOMAIN must match as a
106                                    whole. */
107
108   unsigned permanent :1;        /* whether the cookie should outlive
109                                    the session. */
110   time_t expiry_time;           /* time when the cookie expires, 0
111                                    means undetermined. */
112
113   char *attr;                   /* cookie attribute name */
114   char *value;                  /* cookie attribute value */
115
116   struct cookie *next;          /* used for chaining of cookies in the
117                                    same domain. */
118 };
119
120 #define PORT_ANY (-1)
121
122 /* Allocate and return a new, empty cookie structure. */
123
124 static struct cookie *
125 cookie_new (void)
126 {
127   struct cookie *cookie = xnew0 (struct cookie);
128
129   /* Both cookie->permanent and cookie->expiry_time are now 0.  This
130      means that the cookie doesn't expire, but is only valid for this
131      session (i.e. not written out to disk).  */
132
133   cookie->port = PORT_ANY;
134   return cookie;
135 }
136
137 /* Non-zero if the cookie has expired.  Assumes cookies_now has been
138    set by one of the entry point functions.  */
139
140 static bool
141 cookie_expired_p (const struct cookie *c)
142 {
143   return c->expiry_time != 0 && c->expiry_time < cookies_now;
144 }
145
146 /* Deallocate COOKIE and its components. */
147
148 static void
149 delete_cookie (struct cookie *cookie)
150 {
151   xfree_null (cookie->domain);
152   xfree_null (cookie->path);
153   xfree_null (cookie->attr);
154   xfree_null (cookie->value);
155   xfree (cookie);
156 }
157 \f
158 /* Functions for storing cookies.
159
160    All cookies can be reached beginning with jar->chains.  The key in
161    that table is the domain name, and the value is a linked list of
162    all cookies from that domain.  Every new cookie is placed on the
163    head of the list.  */
164
165 /* Find and return a cookie in JAR whose domain, path, and attribute
166    name correspond to COOKIE.  If found, PREVPTR will point to the
167    location of the cookie previous in chain, or NULL if the found
168    cookie is the head of a chain.
169
170    If no matching cookie is found, return NULL. */
171
172 static struct cookie *
173 find_matching_cookie (struct cookie_jar *jar, struct cookie *cookie,
174                       struct cookie **prevptr)
175 {
176   struct cookie *chain, *prev;
177
178   chain = hash_table_get (jar->chains, cookie->domain);
179   if (!chain)
180     goto nomatch;
181
182   prev = NULL;
183   for (; chain; prev = chain, chain = chain->next)
184     if (0 == strcmp (cookie->path, chain->path)
185         && 0 == strcmp (cookie->attr, chain->attr)
186         && cookie->port == chain->port)
187       {
188         *prevptr = prev;
189         return chain;
190       }
191
192  nomatch:
193   *prevptr = NULL;
194   return NULL;
195 }
196
197 /* Store COOKIE to the jar.
198
199    This is done by placing COOKIE at the head of its chain.  However,
200    if COOKIE matches a cookie already in memory, as determined by
201    find_matching_cookie, the old cookie is unlinked and destroyed.
202
203    The key of each chain's hash table entry is allocated only the
204    first time; next hash_table_put's reuse the same key.  */
205
206 static void
207 store_cookie (struct cookie_jar *jar, struct cookie *cookie)
208 {
209   struct cookie *chain_head;
210   char *chain_key;
211
212   if (hash_table_get_pair (jar->chains, cookie->domain,
213                            &chain_key, &chain_head))
214     {
215       /* A chain of cookies in this domain already exists.  Check for
216          duplicates -- if an extant cookie exactly matches our domain,
217          port, path, and name, replace it.  */
218       struct cookie *prev;
219       struct cookie *victim = find_matching_cookie (jar, cookie, &prev);
220
221       if (victim)
222         {
223           /* Remove VICTIM from the chain.  COOKIE will be placed at
224              the head. */
225           if (prev)
226             {
227               prev->next = victim->next;
228               cookie->next = chain_head;
229             }
230           else
231             {
232               /* prev is NULL; apparently VICTIM was at the head of
233                  the chain.  This place will be taken by COOKIE, so
234                  all we need to do is:  */
235               cookie->next = victim->next;
236             }
237           delete_cookie (victim);
238           --jar->cookie_count;
239           DEBUGP (("Deleted old cookie (to be replaced.)\n"));
240         }
241       else
242         cookie->next = chain_head;
243     }
244   else
245     {
246       /* We are now creating the chain.  Use a copy of cookie->domain
247          as the key for the life-time of the chain.  Using
248          cookie->domain would be unsafe because the life-time of the
249          chain may exceed the life-time of the cookie.  (Cookies may
250          be deleted from the chain by this very function.)  */
251       cookie->next = NULL;
252       chain_key = xstrdup (cookie->domain);
253     }
254
255   hash_table_put (jar->chains, chain_key, cookie);
256   ++jar->cookie_count;
257
258   IF_DEBUG
259     {
260       time_t exptime = cookie->expiry_time;
261       DEBUGP (("\nStored cookie %s %d%s %s <%s> <%s> [expiry %s] %s %s\n",
262                cookie->domain, cookie->port,
263                cookie->port == PORT_ANY ? " (ANY)" : "",
264                cookie->path,
265                cookie->permanent ? "permanent" : "session",
266                cookie->secure ? "secure" : "insecure",
267                cookie->expiry_time ? datetime_str (exptime) : "none",
268                cookie->attr, cookie->value));
269     }
270 }
271
272 /* Discard a cookie matching COOKIE's domain, port, path, and
273    attribute name.  This gets called when we encounter a cookie whose
274    expiry date is in the past, or whose max-age is set to 0.  The
275    former corresponds to netscape cookie spec, while the latter is
276    specified by rfc2109.  */
277
278 static void
279 discard_matching_cookie (struct cookie_jar *jar, struct cookie *cookie)
280 {
281   struct cookie *prev, *victim;
282
283   if (!hash_table_count (jar->chains))
284     /* No elements == nothing to discard. */
285     return;
286
287   victim = find_matching_cookie (jar, cookie, &prev);
288   if (victim)
289     {
290       if (prev)
291         /* Simply unchain the victim. */
292         prev->next = victim->next;
293       else
294         {
295           /* VICTIM was head of its chain.  We need to place a new
296              cookie at the head.  */
297           char *chain_key = NULL;
298           int res;
299
300           res = hash_table_get_pair (jar->chains, victim->domain,
301                                      &chain_key, NULL);
302           assert (res != 0);
303           if (!victim->next)
304             {
305               /* VICTIM was the only cookie in the chain.  Destroy the
306                  chain and deallocate the chain key.  */
307               hash_table_remove (jar->chains, victim->domain);
308               xfree (chain_key);
309             }
310           else
311             hash_table_put (jar->chains, chain_key, victim->next);
312         }
313       delete_cookie (victim);
314       DEBUGP (("Discarded old cookie.\n"));
315     }
316 }
317 \f
318 /* Functions for parsing the `Set-Cookie' header, and creating new
319    cookies from the wire.  */
320
321 #define TOKEN_IS(token, string_literal)                         \
322   BOUNDED_EQUAL_NO_CASE (token.b, token.e, string_literal)
323
324 #define TOKEN_NON_EMPTY(token) (token.b != NULL && token.b != token.e)
325
326 /* Parse the contents of the `Set-Cookie' header.  The header looks
327    like this:
328
329    name1=value1; name2=value2; ...
330
331    Trailing semicolon is optional; spaces are allowed between all
332    tokens.  Additionally, values may be quoted.
333
334    A new cookie is returned upon success, NULL otherwise.
335
336    The first name-value pair will be used to set the cookie's
337    attribute name and value.  Subsequent parameters will be checked
338    against field names such as `domain', `path', etc.  Recognized
339    fields will be parsed and the corresponding members of COOKIE
340    filled.  */
341
342 static struct cookie *
343 parse_set_cookie (const char *set_cookie, bool silent)
344 {
345   const char *ptr = set_cookie;
346   struct cookie *cookie = cookie_new ();
347   param_token name, value;
348
349   if (!extract_param (&ptr, &name, &value, ';'))
350     goto error;
351   if (!value.b)
352     goto error;
353
354   /* If the value is quoted, do not modify it.  */
355   if (*(value.b - 1) == '"')
356     value.b--;
357   if (*value.e == '"')
358     value.e++;
359
360   cookie->attr = strdupdelim (name.b, name.e);
361   cookie->value = strdupdelim (value.b, value.e);
362
363   while (extract_param (&ptr, &name, &value, ';'))
364     {
365       if (TOKEN_IS (name, "domain"))
366         {
367           if (!TOKEN_NON_EMPTY (value))
368             goto error;
369           xfree_null (cookie->domain);
370           /* Strictly speaking, we should set cookie->domain_exact if the
371              domain doesn't begin with a dot.  But many sites set the
372              domain to "foo.com" and expect "subhost.foo.com" to get the
373              cookie, and it apparently works in browsers.  */
374           if (*value.b == '.')
375             ++value.b;
376           cookie->domain = strdupdelim (value.b, value.e);
377         }
378       else if (TOKEN_IS (name, "path"))
379         {
380           if (!TOKEN_NON_EMPTY (value))
381             goto error;
382           xfree_null (cookie->path);
383           cookie->path = strdupdelim (value.b, value.e);
384         }
385       else if (TOKEN_IS (name, "expires"))
386         {
387           char *value_copy;
388           time_t expires;
389
390           if (!TOKEN_NON_EMPTY (value))
391             goto error;
392           BOUNDED_TO_ALLOCA (value.b, value.e, value_copy);
393
394           expires = http_atotm (value_copy);
395           if (expires != (time_t) -1)
396             {
397               cookie->permanent = 1;
398               cookie->expiry_time = expires;
399               /* According to netscape's specification, expiry time in
400                  the past means that discarding of a matching cookie
401                  is requested.  */
402               if (cookie->expiry_time < cookies_now)
403                 cookie->discard_requested = 1;
404             }
405           else
406             /* Error in expiration spec.  Assume default (cookie doesn't
407                expire, but valid only for this session.)  */
408             ;
409         }
410       else if (TOKEN_IS (name, "max-age"))
411         {
412           double maxage = -1;
413           char *value_copy;
414
415           if (!TOKEN_NON_EMPTY (value))
416             goto error;
417           BOUNDED_TO_ALLOCA (value.b, value.e, value_copy);
418
419           sscanf (value_copy, "%lf", &maxage);
420           if (maxage == -1)
421             /* something went wrong. */
422             goto error;
423           cookie->permanent = 1;
424           cookie->expiry_time = cookies_now + maxage;
425
426           /* According to rfc2109, a cookie with max-age of 0 means that
427              discarding of a matching cookie is requested.  */
428           if (maxage == 0)
429             cookie->discard_requested = 1;
430         }
431       else if (TOKEN_IS (name, "secure"))
432         {
433           /* ignore value completely */
434           cookie->secure = 1;
435         }
436       else
437         /* Ignore unrecognized attribute. */
438         ;
439     }
440   if (*ptr)
441     /* extract_param has encountered a syntax error */
442     goto error;
443
444   /* The cookie has been successfully constructed; return it. */
445   return cookie;
446
447  error:
448   if (!silent)
449     logprintf (LOG_NOTQUIET,
450                _("Syntax error in Set-Cookie: %s at position %d.\n"),
451                quotearg_style (escape_quoting_style, set_cookie),
452                (int) (ptr - set_cookie));
453   delete_cookie (cookie);
454   return NULL;
455 }
456
457 #undef TOKEN_IS
458 #undef TOKEN_NON_EMPTY
459 \f
460 /* Sanity checks.  These are important, otherwise it is possible for
461    mailcious attackers to destroy important cookie information and/or
462    violate your privacy.  */
463
464
465 #define REQUIRE_DIGITS(p) do {                  \
466   if (!c_isdigit (*p))                            \
467     return false;                               \
468   for (++p; c_isdigit (*p); p++)                  \
469     ;                                           \
470 } while (0)
471
472 #define REQUIRE_DOT(p) do {                     \
473   if (*p++ != '.')                              \
474     return false;                               \
475 } while (0)
476
477 /* Check whether ADDR matches <digits>.<digits>.<digits>.<digits>.
478
479    We don't want to call network functions like inet_addr() because
480    all we need is a check, preferrably one that is small, fast, and
481    well-defined.  */
482
483 static bool
484 numeric_address_p (const char *addr)
485 {
486   const char *p = addr;
487
488   REQUIRE_DIGITS (p);           /* A */
489   REQUIRE_DOT (p);              /* . */
490   REQUIRE_DIGITS (p);           /* B */
491   REQUIRE_DOT (p);              /* . */
492   REQUIRE_DIGITS (p);           /* C */
493   REQUIRE_DOT (p);              /* . */
494   REQUIRE_DIGITS (p);           /* D */
495
496   if (*p != '\0')
497     return false;
498   return true;
499 }
500
501 /* Check whether COOKIE_DOMAIN is an appropriate domain for HOST.
502    Originally I tried to make the check compliant with rfc2109, but
503    the sites deviated too often, so I had to fall back to "tail
504    matching", as defined by the original Netscape's cookie spec.  */
505
506 static bool
507 check_domain_match (const char *cookie_domain, const char *host)
508 {
509   DEBUGP (("cdm: 1"));
510
511   /* Numeric address requires exact match.  It also requires HOST to
512      be an IP address.  */
513   if (numeric_address_p (cookie_domain))
514     return 0 == strcmp (cookie_domain, host);
515
516   DEBUGP ((" 2"));
517
518   /* For the sake of efficiency, check for exact match first. */
519   if (0 == strcasecmp (cookie_domain, host))
520     return true;
521
522   DEBUGP ((" 3"));
523
524   /* HOST must match the tail of cookie_domain. */
525   if (!match_tail (host, cookie_domain, true))
526     return false;
527
528   /* We know that COOKIE_DOMAIN is a subset of HOST; however, we must
529      make sure that somebody is not trying to set the cookie for a
530      subdomain shared by many entities.  For example, "company.co.uk"
531      must not be allowed to set a cookie for ".co.uk".  On the other
532      hand, "sso.redhat.de" should be able to set a cookie for
533      ".redhat.de".
534
535      The only marginally sane way to handle this I can think of is to
536      reject on the basis of the length of the second-level domain name
537      (but when the top-level domain is unknown), with the assumption
538      that those of three or less characters could be reserved.  For
539      example:
540
541           .co.org -> works because the TLD is known
542            .co.uk -> doesn't work because "co" is only two chars long
543           .com.au -> doesn't work because "com" is only 3 chars long
544           .cnn.uk -> doesn't work because "cnn" is also only 3 chars long (ugh)
545           .cnn.de -> doesn't work for the same reason (ugh!!)
546          .abcd.de -> works because "abcd" is 4 chars long
547       .img.cnn.de -> works because it's not trying to set the 2nd level domain
548        .cnn.co.uk -> works for the same reason
549
550     That should prevent misuse, while allowing reasonable usage.  If
551     someone knows of a better way to handle this, please let me
552     know.  */
553   {
554     const char *p = cookie_domain;
555     int dccount = 1;            /* number of domain components */
556     int ldcl  = 0;              /* last domain component length */
557     int nldcl = 0;              /* next to last domain component length */
558     int out;
559     if (*p == '.')
560       /* Ignore leading period in this calculation. */
561       ++p;
562     DEBUGP ((" 4"));
563     for (out = 0; !out; p++)
564       switch (*p)
565         {
566         case '\0':
567           out = 1;
568           break;
569         case '.':
570           if (ldcl == 0)
571             /* Empty domain component found -- the domain is invalid. */
572             return false;
573           if (*(p + 1) == '\0')
574             {
575               /* Tolerate trailing '.' by not treating the domain as
576                  one ending with an empty domain component.  */
577               out = 1;
578               break;
579             }
580           nldcl = ldcl;
581           ldcl  = 0;
582           ++dccount;
583           break;
584         default:
585           ++ldcl;
586         }
587
588     DEBUGP ((" 5"));
589
590     if (dccount < 2)
591       return false;
592
593     DEBUGP ((" 6"));
594
595     if (dccount == 2)
596       {
597         size_t i;
598         int known_toplevel = false;
599         static const char *known_toplevel_domains[] = {
600           ".com", ".edu", ".net", ".org", ".gov", ".mil", ".int"
601         };
602         for (i = 0; i < countof (known_toplevel_domains); i++)
603           if (match_tail (cookie_domain, known_toplevel_domains[i], true))
604             {
605               known_toplevel = true;
606               break;
607             }
608         if (!known_toplevel && nldcl <= 3)
609           return false;
610       }
611   }
612
613   DEBUGP ((" 7"));
614
615   /* Don't allow the host "foobar.com" to set a cookie for domain
616      "bar.com".  */
617   if (*cookie_domain != '.')
618     {
619       int dlen = strlen (cookie_domain);
620       int hlen = strlen (host);
621       /* cookie host:    hostname.foobar.com */
622       /* desired domain:             bar.com */
623       /* '.' must be here in host-> ^        */
624       if (hlen > dlen && host[hlen - dlen - 1] != '.')
625         return false;
626     }
627
628   DEBUGP ((" 8"));
629
630   return true;
631 }
632
633 static int path_matches (const char *, const char *);
634
635 /* Check whether PATH begins with COOKIE_PATH. */
636
637 static bool
638 check_path_match (const char *cookie_path, const char *path)
639 {
640   return path_matches (path, cookie_path) != 0;
641 }
642
643 /* Prepend '/' to string S.  S is copied to fresh stack-allocated
644    space and its value is modified to point to the new location.  */
645
646 #define PREPEND_SLASH(s) do {                                   \
647   char *PS_newstr = (char *) alloca (1 + strlen (s) + 1);       \
648   *PS_newstr = '/';                                             \
649   strcpy (PS_newstr + 1, s);                                    \
650   s = PS_newstr;                                                \
651 } while (0)
652
653 \f
654 /* Process the HTTP `Set-Cookie' header.  This results in storing the
655    cookie or discarding a matching one, or ignoring it completely, all
656    depending on the contents.  */
657
658 void
659 cookie_handle_set_cookie (struct cookie_jar *jar,
660                           const char *host, int port,
661                           const char *path, const char *set_cookie)
662 {
663   struct cookie *cookie;
664   cookies_now = time (NULL);
665
666   /* Wget's paths don't begin with '/' (blame rfc1808), but cookie
667      usage assumes /-prefixed paths.  Until the rest of Wget is fixed,
668      simply prepend slash to PATH.  */
669   PREPEND_SLASH (path);
670
671   cookie = parse_set_cookie (set_cookie, false);
672   if (!cookie)
673     goto out;
674
675   /* Sanitize parts of cookie. */
676
677   if (!cookie->domain)
678     {
679     copy_domain:
680       /* If the domain was not provided, we use the one we're talking
681          to, and set exact match.  */
682       cookie->domain = xstrdup (host);
683       cookie->domain_exact = 1;
684       /* Set the port, but only if it's non-default. */
685       if (port != 80 && port != 443)
686         cookie->port = port;
687     }
688   else
689     {
690       if (!check_domain_match (cookie->domain, host))
691         {
692           logprintf (LOG_NOTQUIET,
693                      _("Cookie coming from %s attempted to set domain to %s\n"),
694                      quotearg_style (escape_quoting_style, host),
695                      quotearg_style (escape_quoting_style, cookie->domain));
696           xfree (cookie->domain);
697           goto copy_domain;
698         }
699     }
700
701   if (!cookie->path)
702     {
703       /* The cookie doesn't set path: set it to the URL path, sans the
704          file part ("/dir/file" truncated to "/dir/").  */
705       char *trailing_slash = strrchr (path, '/');
706       if (trailing_slash)
707         cookie->path = strdupdelim (path, trailing_slash + 1);
708       else
709         /* no slash in the string -- can this even happen? */
710         cookie->path = xstrdup (path);
711     }
712   else
713     {
714       /* The cookie sets its own path; verify that it is legal. */
715       if (!check_path_match (cookie->path, path))
716         {
717           DEBUGP (("Attempt to fake the path: %s, %s\n",
718                    cookie->path, path));
719           goto out;
720         }
721     }
722
723   /* Now store the cookie, or discard an existing cookie, if
724      discarding was requested.  */
725
726   if (cookie->discard_requested)
727     {
728       discard_matching_cookie (jar, cookie);
729       goto out;
730     }
731
732   store_cookie (jar, cookie);
733   return;
734
735  out:
736   if (cookie)
737     delete_cookie (cookie);
738 }
739 \f
740 /* Support for sending out cookies in HTTP requests, based on
741    previously stored cookies.  Entry point is
742    `build_cookies_request'.  */
743
744 /* Return a count of how many times CHR occurs in STRING. */
745
746 static int
747 count_char (const char *string, char chr)
748 {
749   const char *p;
750   int count = 0;
751   for (p = string; *p; p++)
752     if (*p == chr)
753       ++count;
754   return count;
755 }
756
757 /* Find the cookie chains whose domains match HOST and store them to
758    DEST.
759
760    A cookie chain is the head of a list of cookies that belong to a
761    host/domain.  Given HOST "img.search.xemacs.org", this function
762    will return the chains for "img.search.xemacs.org",
763    "search.xemacs.org", and "xemacs.org" -- those of them that exist
764    (if any), that is.
765
766    DEST should be large enough to accept (in the worst case) as many
767    elements as there are domain components of HOST.  */
768
769 static int
770 find_chains_of_host (struct cookie_jar *jar, const char *host,
771                      struct cookie *dest[])
772 {
773   int dest_count = 0;
774   int passes, passcnt;
775
776   /* Bail out quickly if there are no cookies in the jar.  */
777   if (!hash_table_count (jar->chains))
778     return 0;
779
780   if (numeric_address_p (host))
781     /* If host is an IP address, only check for the exact match. */
782     passes = 1;
783   else
784     /* Otherwise, check all the subdomains except the top-level (last)
785        one.  As a domain with N components has N-1 dots, the number of
786        passes equals the number of dots.  */
787     passes = count_char (host, '.');
788
789   passcnt = 0;
790
791   /* Find chains that match HOST, starting with exact match and
792      progressing to less specific domains.  For instance, given HOST
793      fly.srk.fer.hr, first look for fly.srk.fer.hr's chain, then
794      srk.fer.hr's, then fer.hr's.  */
795   while (1)
796     {
797       struct cookie *chain = hash_table_get (jar->chains, host);
798       if (chain)
799         dest[dest_count++] = chain;
800       if (++passcnt >= passes)
801         break;
802       host = strchr (host, '.') + 1;
803     }
804
805   return dest_count;
806 }
807
808 /* If FULL_PATH begins with PREFIX, return the length of PREFIX, zero
809    otherwise.  */
810
811 static int
812 path_matches (const char *full_path, const char *prefix)
813 {
814   int len = strlen (prefix);
815
816   if (0 != strncmp (full_path, prefix, len))
817     /* FULL_PATH doesn't begin with PREFIX. */
818     return 0;
819
820   /* Length of PREFIX determines the quality of the match. */
821   return len + 1;
822 }
823
824 /* Return true iff COOKIE matches the provided parameters of the URL
825    being downloaded: HOST, PORT, PATH, and SECFLAG.
826
827    If PATH_GOODNESS is non-NULL, store the "path goodness" value
828    there.  That value is a measure of how closely COOKIE matches PATH,
829    used for ordering cookies.  */
830
831 static bool
832 cookie_matches_url (const struct cookie *cookie,
833                     const char *host, int port, const char *path,
834                     bool secflag, int *path_goodness)
835 {
836   int pg;
837
838   if (cookie_expired_p (cookie))
839     /* Ignore stale cookies.  Don't bother unchaining the cookie at
840        this point -- Wget is a relatively short-lived application, and
841        stale cookies will not be saved by `save_cookies'.  On the
842        other hand, this function should be as efficient as
843        possible.  */
844     return false;
845
846   if (cookie->secure && !secflag)
847     /* Don't transmit secure cookies over insecure connections.  */
848     return false;
849   if (cookie->port != PORT_ANY && cookie->port != port)
850     return false;
851
852   /* If exact domain match is required, verify that cookie's domain is
853      equal to HOST.  If not, assume success on the grounds of the
854      cookie's chain having been found by find_chains_of_host.  */
855   if (cookie->domain_exact
856       && 0 != strcasecmp (host, cookie->domain))
857     return false;
858
859   pg = path_matches (path, cookie->path);
860   if (pg == 0)
861     return false;
862
863   if (path_goodness)
864     /* If the caller requested path_goodness, we return it.  This is
865        an optimization, so that the caller doesn't need to call
866        path_matches() again.  */
867     *path_goodness = pg;
868   return true;
869 }
870
871 /* A structure that points to a cookie, along with the additional
872    information about the cookie's "goodness".  This allows us to sort
873    the cookies when returning them to the server, as required by the
874    spec.  */
875
876 struct weighed_cookie {
877   struct cookie *cookie;
878   int domain_goodness;
879   int path_goodness;
880 };
881
882 /* Comparator used for uniquifying the list. */
883
884 static int
885 equality_comparator (const void *p1, const void *p2)
886 {
887   struct weighed_cookie *wc1 = (struct weighed_cookie *)p1;
888   struct weighed_cookie *wc2 = (struct weighed_cookie *)p2;
889
890   int namecmp  = strcmp (wc1->cookie->attr, wc2->cookie->attr);
891   int valuecmp = strcmp (wc1->cookie->value, wc2->cookie->value);
892
893   /* We only really care whether both name and value are equal.  We
894      return them in this order only for consistency...  */
895   return namecmp ? namecmp : valuecmp;
896 }
897
898 /* Eliminate duplicate cookies.  "Duplicate cookies" are any two
899    cookies with the same attr name and value.  Whenever a duplicate
900    pair is found, one of the cookies is removed.  */
901
902 static int
903 eliminate_dups (struct weighed_cookie *outgoing, int count)
904 {
905   struct weighed_cookie *h;     /* hare */
906   struct weighed_cookie *t;     /* tortoise */
907   struct weighed_cookie *end = outgoing + count;
908
909   /* We deploy a simple uniquify algorithm: first sort the array
910      according to our sort criteria, then copy it to itself, comparing
911      each cookie to its neighbor and ignoring the duplicates.  */
912
913   qsort (outgoing, count, sizeof (struct weighed_cookie), equality_comparator);
914
915   /* "Hare" runs through all the entries in the array, followed by
916      "tortoise".  If a duplicate is found, the hare skips it.
917      Non-duplicate entries are copied to the tortoise ptr.  */
918
919   for (h = t = outgoing; h < end; h++)
920     {
921       if (h != end - 1)
922         {
923           struct cookie *c0 = h[0].cookie;
924           struct cookie *c1 = h[1].cookie;
925           if (!strcmp (c0->attr, c1->attr) && !strcmp (c0->value, c1->value))
926             continue;           /* ignore the duplicate */
927         }
928
929       /* If the hare has advanced past the tortoise (because of
930          previous dups), make sure the values get copied.  Otherwise,
931          no copying is necessary.  */
932       if (h != t)
933         *t++ = *h;
934       else
935         t++;
936     }
937   return t - outgoing;
938 }
939
940 /* Comparator used for sorting by quality. */
941
942 static int
943 goodness_comparator (const void *p1, const void *p2)
944 {
945   struct weighed_cookie *wc1 = (struct weighed_cookie *)p1;
946   struct weighed_cookie *wc2 = (struct weighed_cookie *)p2;
947
948   /* Subtractions take `wc2' as the first argument becauase we want a
949      sort in *decreasing* order of goodness.  */
950   int dgdiff = wc2->domain_goodness - wc1->domain_goodness;
951   int pgdiff = wc2->path_goodness - wc1->path_goodness;
952
953   /* Sort by domain goodness; if these are the same, sort by path
954      goodness.  (The sorting order isn't really specified; maybe it
955      should be the other way around.)  */
956   return dgdiff ? dgdiff : pgdiff;
957 }
958
959 /* Generate a `Cookie' header for a request that goes to HOST:PORT and
960    requests PATH from the server.  The resulting string is allocated
961    with `malloc', and the caller is responsible for freeing it.  If no
962    cookies pertain to this request, i.e. no cookie header should be
963    generated, NULL is returned.  */
964
965 char *
966 cookie_header (struct cookie_jar *jar, const char *host,
967                int port, const char *path, bool secflag)
968 {
969   struct cookie **chains;
970   int chain_count;
971
972   struct cookie *cookie;
973   struct weighed_cookie *outgoing;
974   int count, i, ocnt;
975   char *result;
976   int result_size, pos;
977   PREPEND_SLASH (path);         /* see cookie_handle_set_cookie */
978
979   /* First, find the cookie chains whose domains match HOST. */
980
981   /* Allocate room for find_chains_of_host to write to.  The number of
982      chains can at most equal the number of subdomains, hence
983      1+<number of dots>.  */
984   chains = alloca_array (struct cookie *, 1 + count_char (host, '.'));
985   chain_count = find_chains_of_host (jar, host, chains);
986
987   /* No cookies for this host. */
988   if (!chain_count)
989     return NULL;
990
991   cookies_now = time (NULL);
992
993   /* Now extract from the chains those cookies that match our host
994      (for domain_exact cookies), port (for cookies with port other
995      than PORT_ANY), etc.  See matching_cookie for details.  */
996
997   /* Count the number of matching cookies. */
998   count = 0;
999   for (i = 0; i < chain_count; i++)
1000     for (cookie = chains[i]; cookie; cookie = cookie->next)
1001       if (cookie_matches_url (cookie, host, port, path, secflag, NULL))
1002         ++count;
1003   if (!count)
1004     return NULL;                /* no cookies matched */
1005
1006   /* Allocate the array. */
1007   outgoing = alloca_array (struct weighed_cookie, count);
1008
1009   /* Fill the array with all the matching cookies from the chains that
1010      match HOST. */
1011   ocnt = 0;
1012   for (i = 0; i < chain_count; i++)
1013     for (cookie = chains[i]; cookie; cookie = cookie->next)
1014       {
1015         int pg;
1016         if (!cookie_matches_url (cookie, host, port, path, secflag, &pg))
1017           continue;
1018         outgoing[ocnt].cookie = cookie;
1019         outgoing[ocnt].domain_goodness = strlen (cookie->domain);
1020         outgoing[ocnt].path_goodness   = pg;
1021         ++ocnt;
1022       }
1023   assert (ocnt == count);
1024
1025   /* Eliminate duplicate cookies; that is, those whose name and value
1026      are the same.  */
1027   count = eliminate_dups (outgoing, count);
1028
1029   /* Sort the array so that best-matching domains come first, and
1030      that, within one domain, best-matching paths come first. */
1031   qsort (outgoing, count, sizeof (struct weighed_cookie), goodness_comparator);
1032
1033   /* Count the space the name=value pairs will take. */
1034   result_size = 0;
1035   for (i = 0; i < count; i++)
1036     {
1037       struct cookie *c = outgoing[i].cookie;
1038       /* name=value */
1039       result_size += strlen (c->attr) + 1 + strlen (c->value);
1040     }
1041
1042   /* Allocate output buffer:
1043      name=value pairs -- result_size
1044      "; " separators  -- (count - 1) * 2
1045      \0 terminator    -- 1 */
1046   result_size = result_size + (count - 1) * 2 + 1;
1047   result = xmalloc (result_size);
1048   pos = 0;
1049   for (i = 0; i < count; i++)
1050     {
1051       struct cookie *c = outgoing[i].cookie;
1052       int namlen = strlen (c->attr);
1053       int vallen = strlen (c->value);
1054
1055       memcpy (result + pos, c->attr, namlen);
1056       pos += namlen;
1057       result[pos++] = '=';
1058       memcpy (result + pos, c->value, vallen);
1059       pos += vallen;
1060       if (i < count - 1)
1061         {
1062           result[pos++] = ';';
1063           result[pos++] = ' ';
1064         }
1065     }
1066   result[pos++] = '\0';
1067   assert (pos == result_size);
1068   return result;
1069 }
1070 \f
1071 /* Support for loading and saving cookies.  The format used for
1072    loading and saving should be the format of the `cookies.txt' file
1073    used by Netscape and Mozilla, at least the Unix versions.
1074    (Apparently IE can export cookies in that format as well.)  The
1075    format goes like this:
1076
1077        DOMAIN DOMAIN-FLAG PATH SECURE-FLAG TIMESTAMP ATTR-NAME ATTR-VALUE
1078
1079      DOMAIN      -- cookie domain, optionally followed by :PORT
1080      DOMAIN-FLAG -- whether all hosts in the domain match
1081      PATH        -- cookie path
1082      SECURE-FLAG -- whether cookie requires secure connection
1083      TIMESTAMP   -- expiry timestamp, number of seconds since epoch
1084      ATTR-NAME   -- name of the cookie attribute
1085      ATTR-VALUE  -- value of the cookie attribute (empty if absent)
1086
1087    The fields are separated by TABs.  All fields are mandatory, except
1088    for ATTR-VALUE.  The `-FLAG' fields are boolean, their legal values
1089    being "TRUE" and "FALSE'.  Empty lines, lines consisting of
1090    whitespace only, and comment lines (beginning with # optionally
1091    preceded by whitespace) are ignored.
1092
1093    Example line from cookies.txt (split in two lines for readability):
1094
1095        .google.com      TRUE    /       FALSE   2147368447      \
1096        PREF     ID=34bb47565bbcd47b:LD=en:NR=20:TM=985172580:LM=985739012
1097
1098 */
1099
1100 /* If the region [B, E) ends with :<digits>, parse the number, return
1101    it, and store new boundary (location of the `:') to DOMAIN_E_PTR.
1102    If port is not specified, return 0.  */
1103
1104 static int
1105 domain_port (const char *domain_b, const char *domain_e,
1106              const char **domain_e_ptr)
1107 {
1108   int port = 0;
1109   const char *p;
1110   const char *colon = memchr (domain_b, ':', domain_e - domain_b);
1111   if (!colon)
1112     return 0;
1113   for (p = colon + 1; p < domain_e && c_isdigit (*p); p++)
1114     port = 10 * port + (*p - '0');
1115   if (p < domain_e)
1116     /* Garbage following port number. */
1117     return 0;
1118   *domain_e_ptr = colon;
1119   return port;
1120 }
1121
1122 #define GET_WORD(p, b, e) do {                  \
1123   b = p;                                        \
1124   while (*p && *p != '\t')                      \
1125     ++p;                                        \
1126   e = p;                                        \
1127   if (b == e || !*p)                            \
1128     goto next;                                  \
1129   ++p;                                          \
1130 } while (0)
1131
1132 /* Load cookies from FILE.  */
1133
1134 void
1135 cookie_jar_load (struct cookie_jar *jar, const char *file)
1136 {
1137   char *line;
1138   FILE *fp = fopen (file, "r");
1139   if (!fp)
1140     {
1141       logprintf (LOG_NOTQUIET, _("Cannot open cookies file %s: %s\n"),
1142                  quote (file), strerror (errno));
1143       return;
1144     }
1145   cookies_now = time (NULL);
1146
1147   for (; ((line = read_whole_line (fp)) != NULL); xfree (line))
1148     {
1149       struct cookie *cookie;
1150       char *p = line;
1151
1152       double expiry;
1153       int port;
1154
1155       char *domain_b  = NULL, *domain_e  = NULL;
1156       char *domflag_b = NULL, *domflag_e = NULL;
1157       char *path_b    = NULL, *path_e    = NULL;
1158       char *secure_b  = NULL, *secure_e  = NULL;
1159       char *expires_b = NULL, *expires_e = NULL;
1160       char *name_b    = NULL, *name_e    = NULL;
1161       char *value_b   = NULL, *value_e   = NULL;
1162
1163       /* Skip leading white-space. */
1164       while (*p && c_isspace (*p))
1165         ++p;
1166       /* Ignore empty lines.  */
1167       if (!*p || *p == '#')
1168         continue;
1169
1170       GET_WORD (p, domain_b,  domain_e);
1171       GET_WORD (p, domflag_b, domflag_e);
1172       GET_WORD (p, path_b,    path_e);
1173       GET_WORD (p, secure_b,  secure_e);
1174       GET_WORD (p, expires_b, expires_e);
1175       GET_WORD (p, name_b,    name_e);
1176
1177       /* Don't use GET_WORD for value because it ends with newline,
1178          not TAB.  */
1179       value_b = p;
1180       value_e = p + strlen (p);
1181       if (value_e > value_b && value_e[-1] == '\n')
1182         --value_e;
1183       if (value_e > value_b && value_e[-1] == '\r')
1184         --value_e;
1185       /* Empty values are legal (I think), so don't bother checking. */
1186
1187       cookie = cookie_new ();
1188
1189       cookie->attr    = strdupdelim (name_b, name_e);
1190       cookie->value   = strdupdelim (value_b, value_e);
1191       cookie->path    = strdupdelim (path_b, path_e);
1192       cookie->secure  = BOUNDED_EQUAL (secure_b, secure_e, "TRUE");
1193
1194       /* Curl source says, quoting Andre Garcia: "flag: A TRUE/FALSE
1195          value indicating if all machines within a given domain can
1196          access the variable.  This value is set automatically by the
1197          browser, depending on the value set for the domain."  */
1198       cookie->domain_exact = !BOUNDED_EQUAL (domflag_b, domflag_e, "TRUE");
1199
1200       /* DOMAIN needs special treatment because we might need to
1201          extract the port.  */
1202       port = domain_port (domain_b, domain_e, (const char **)&domain_e);
1203       if (port)
1204         cookie->port = port;
1205
1206       if (*domain_b == '.')
1207         ++domain_b;             /* remove leading dot internally */
1208       cookie->domain  = strdupdelim (domain_b, domain_e);
1209
1210       /* safe default in case EXPIRES field is garbled. */
1211       expiry = (double)cookies_now - 1;
1212
1213       /* I don't like changing the line, but it's safe here.  (line is
1214          malloced.)  */
1215       *expires_e = '\0';
1216       sscanf (expires_b, "%lf", &expiry);
1217
1218       if (expiry == 0)
1219         {
1220           /* EXPIRY can be 0 for session cookies saved because the
1221              user specified `--keep-session-cookies' in the past.
1222              They remain session cookies, and will be saved only if
1223              the user has specified `keep-session-cookies' again.  */
1224         }
1225       else
1226         {
1227           if (expiry < cookies_now)
1228             goto abort_cookie;  /* ignore stale cookie. */
1229           cookie->expiry_time = expiry;
1230           cookie->permanent = 1;
1231         }
1232
1233       store_cookie (jar, cookie);
1234
1235     next:
1236       continue;
1237
1238     abort_cookie:
1239       delete_cookie (cookie);
1240     }
1241   fclose (fp);
1242 }
1243
1244 /* Save cookies, in format described above, to FILE. */
1245
1246 void
1247 cookie_jar_save (struct cookie_jar *jar, const char *file)
1248 {
1249   FILE *fp;
1250   hash_table_iterator iter;
1251
1252   DEBUGP (("Saving cookies to %s.\n", file));
1253
1254   cookies_now = time (NULL);
1255
1256   fp = fopen (file, "w");
1257   if (!fp)
1258     {
1259       logprintf (LOG_NOTQUIET, _("Cannot open cookies file %s: %s\n"),
1260                  quote (file), strerror (errno));
1261       return;
1262     }
1263
1264   fputs ("# HTTP cookie file.\n", fp);
1265   fprintf (fp, "# Generated by Wget on %s.\n", datetime_str (cookies_now));
1266   fputs ("# Edit at your own risk.\n\n", fp);
1267
1268   for (hash_table_iterate (jar->chains, &iter);
1269        hash_table_iter_next (&iter);
1270        )
1271     {
1272       const char *domain = iter.key;
1273       struct cookie *cookie = iter.value;
1274       for (; cookie; cookie = cookie->next)
1275         {
1276           if (!cookie->permanent && !opt.keep_session_cookies)
1277             continue;
1278           if (cookie_expired_p (cookie))
1279             continue;
1280           if (!cookie->domain_exact)
1281             fputc ('.', fp);
1282           fputs (domain, fp);
1283           if (cookie->port != PORT_ANY)
1284             fprintf (fp, ":%d", cookie->port);
1285           fprintf (fp, "\t%s\t%s\t%s\t%.0f\t%s\t%s\n",
1286                    cookie->domain_exact ? "FALSE" : "TRUE",
1287                    cookie->path, cookie->secure ? "TRUE" : "FALSE",
1288                    (double)cookie->expiry_time,
1289                    cookie->attr, cookie->value);
1290           if (ferror (fp))
1291             goto out;
1292         }
1293     }
1294  out:
1295   if (ferror (fp))
1296     logprintf (LOG_NOTQUIET, _("Error writing to %s: %s\n"),
1297                quote (file), strerror (errno));
1298   if (fclose (fp) < 0)
1299     logprintf (LOG_NOTQUIET, _("Error closing %s: %s\n"),
1300                quote (file), strerror (errno));
1301
1302   DEBUGP (("Done saving cookies.\n"));
1303 }
1304 \f
1305 /* Clean up cookie-related data. */
1306
1307 void
1308 cookie_jar_delete (struct cookie_jar *jar)
1309 {
1310   /* Iterate over chains (indexed by domain) and free them. */
1311   hash_table_iterator iter;
1312   for (hash_table_iterate (jar->chains, &iter); hash_table_iter_next (&iter); )
1313     {
1314       struct cookie *chain = iter.value;
1315       xfree (iter.key);
1316       /* Then all cookies in this chain. */
1317       while (chain)
1318         {
1319           struct cookie *next = chain->next;
1320           delete_cookie (chain);
1321           chain = next;
1322         }
1323     }
1324   hash_table_destroy (jar->chains);
1325   xfree (jar);
1326 }
1327 \f
1328 /* Test cases.  Currently this is only tests parse_set_cookies.  To
1329    use, recompile Wget with -DTEST_COOKIES and call test_cookies()
1330    from main.  */
1331
1332 #ifdef TEST_COOKIES
1333 void
1334 test_cookies (void)
1335 {
1336   /* Tests expected to succeed: */
1337   static struct {
1338     const char *data;
1339     const char *results[10];
1340   } tests_succ[] = {
1341     { "arg=value", {"arg", "value", NULL} },
1342     { "arg1=value1;arg2=value2", {"arg1", "value1", "arg2", "value2", NULL} },
1343     { "arg1=value1; arg2=value2", {"arg1", "value1", "arg2", "value2", NULL} },
1344     { "arg1=value1;  arg2=value2;", {"arg1", "value1", "arg2", "value2", NULL} },
1345     { "arg1=value1;  arg2=value2;  ", {"arg1", "value1", "arg2", "value2", NULL} },
1346     { "arg1=\"value1\"; arg2=\"\"", {"arg1", "value1", "arg2", "", NULL} },
1347     { "arg=", {"arg", "", NULL} },
1348     { "arg1=; arg2=", {"arg1", "", "arg2", "", NULL} },
1349     { "arg1 = ; arg2= ", {"arg1", "", "arg2", "", NULL} },
1350   };
1351
1352   /* Tests expected to fail: */
1353   static char *tests_fail[] = {
1354     ";",
1355     "arg=\"unterminated",
1356     "=empty-name",
1357     "arg1=;=another-empty-name",
1358   };
1359   int i;
1360
1361   for (i = 0; i < countof (tests_succ); i++)
1362     {
1363       int ind;
1364       const char *data = tests_succ[i].data;
1365       const char **expected = tests_succ[i].results;
1366       struct cookie *c;
1367
1368       c = parse_set_cookie (data, true);
1369       if (!c)
1370         {
1371           printf ("NULL cookie returned for valid data: %s\n", data);
1372           continue;
1373         }
1374
1375       /* Test whether extract_param handles these cases correctly. */
1376       {
1377         param_token name, value;
1378         const char *ptr = data;
1379         int j = 0;
1380         while (extract_param (&ptr, &name, &value, ';'))
1381           {
1382             char *n = strdupdelim (name.b, name.e);
1383             char *v = strdupdelim (value.b, value.e);
1384             if (!expected[j])
1385               {
1386                 printf ("Too many parameters for '%s'\n", data);
1387                 break;
1388               }
1389             if (0 != strcmp (expected[j], n))
1390               printf ("Invalid name %d for '%s' (expected '%s', got '%s')\n",
1391                       j / 2 + 1, data, expected[j], n);
1392             if (0 != strcmp (expected[j + 1], v))
1393               printf ("Invalid value %d for '%s' (expected '%s', got '%s')\n",
1394                       j / 2 + 1, data, expected[j + 1], v);
1395             j += 2;
1396             free (n);
1397             free (v);
1398           }
1399         if (expected[j])
1400           printf ("Too few parameters for '%s'\n", data);
1401       }
1402     }
1403
1404   for (i = 0; i < countof (tests_fail); i++)
1405     {
1406       struct cookie *c;
1407       char *data = tests_fail[i];
1408       c = parse_set_cookie (data, true);
1409       if (c)
1410         printf ("Failed to report error on invalid data: %s\n", data);
1411     }
1412 }
1413 #endif /* TEST_COOKIES */