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