]> sjero.net Git - wget/blobdiff - src/cookies.c
[svn] Match hosts against domains per Netscape cookie "specification".
[wget] / src / cookies.c
index 766896c2e5e70741497219e1a68c85d879a182b3..a0937e348cc67e2e3c6aae64df7c0106f7da50c1 100644 (file)
@@ -670,96 +670,70 @@ numeric_address_p (const char *addr)
 }
 
 /* Check whether COOKIE_DOMAIN is an appropriate domain for HOST.
-   This check is compliant with rfc2109.  */
+   Originally I tried to make the check compliant with rfc2109, but
+   the sites deviated too often, so I had to fall back to "tail
+   matching", as defined by the original Netscape's cookie spec.  */
 
 static int
 check_domain_match (const char *cookie_domain, const char *host)
 {
-  int headlen;
-  const char *tail;
+  static char *special_toplevel_domains[] = {
+    ".com", ".edu", ".net", ".org", ".gov", ".mil", ".int"
+  };
+  int i, required_dots;
 
   DEBUGP (("cdm: 1"));
 
   /* Numeric address requires exact match.  It also requires HOST to
-     be an IP address.  I suppose we *could* resolve HOST with
-     store_hostaddress (it would hit the hash table), but rfc2109
-     doesn't require it, and it doesn't seem very useful, so we
-     don't.  */
+     be an IP address.  */
   if (numeric_address_p (cookie_domain))
-    return !strcmp (cookie_domain, host);
+    return 0 == strcmp (cookie_domain, host);
 
   DEBUGP ((" 2"));
 
-  /* The domain must contain at least one embedded dot. */
-  {
-    const char *rest = cookie_domain;
-    int len = strlen (rest);
-    if (*rest == '.')
-      ++rest, --len;           /* ignore first dot */
-    if (len <= 0)
-      return 0;
-    if (rest[len - 1] == '.')
-      --len;                   /* ignore last dot */
-
-    if (!memchr (rest, '.', len))
-      /* No dots. */
-      return 0;
-  }
-
-  DEBUGP ((" 3"));
-
   /* For the sake of efficiency, check for exact match first. */
   if (!strcasecmp (cookie_domain, host))
     return 1;
 
-  DEBUGP ((" 4"));
-
-  /* In rfc2109 terminology, HOST needs domain-match COOKIE_DOMAIN.
-     This means that COOKIE_DOMAIN needs to start with `.' and be an
-     FQDN, and that HOST must end with COOKIE_DOMAIN.  */
-  if (*cookie_domain != '.')
-    return 0;
-
-  DEBUGP ((" 5"));
-
-  /* Two proceed, we need to examine two parts of HOST: its head and
-     its tail.  Head and tail are defined in terms of the length of
-     the domain, like this:
-
-       HHHHTTTTTTTTTTTTTTT  <- host
-           DDDDDDDDDDDDDDD  <- domain
-
-     That is, "head" is the part of the host before (dlen - hlen), and
-     "tail" is what follows.
-
-     For the domain to match, two conditions need to be true:
+  DEBUGP ((" 3"));
 
-     1. Tail must equal DOMAIN.
-     2. Head must not contain an embedded dot.  */
+  required_dots = 3;
+  for (i = 0; i < ARRAY_SIZE (special_toplevel_domains); i++)
+    if (match_tail (cookie_domain, special_toplevel_domains[i]))
+      {
+       required_dots = 2;
+       break;
+      }
 
-  headlen = strlen (host) - strlen (cookie_domain);
+  /* If the domain does not start with '.', require one less dot.
+     This is so that domains like "altavista.com" (which should be
+     ".altavista.com") are accepted.  */
+  if (*cookie_domain != '.')
+    --required_dots;
 
-  if (headlen <= 0)
-    /* DOMAIN must be a proper subset of HOST. */
+  if (count_char (cookie_domain, '.') < required_dots)
     return 0;
-  tail = host + headlen;
 
-  DEBUGP ((" 6"));
+  DEBUGP ((" 4"));
 
-  /* (1) */
-  if (strcasecmp (tail, cookie_domain))
+  if (!match_tail (host, cookie_domain))
     return 0;
 
-  DEBUGP ((" 7"));
-
-  /* Test (2) is not part of the "domain-match" itself, but is
-     recommended by rfc2109 for reasons of privacy.  */
+  DEBUGP ((" 5"));
 
-  /* (2) */
-  if (memchr (host, '.', headlen))
-    return 0;
+  /* Don't allow domain "bar.com" to match host "foobar.com".  */
+  if (*cookie_domain != '.')
+    {
+      int dlen = strlen (cookie_domain);
+      int hlen = strlen (host);
+      /* hostname.foobar.com                   */
+      /*             bar.com                   */
+      /*            ^ <-- must be '.' for host */
+      if (hlen > dlen && host[hlen - dlen - 1] != '.')
+       return 0;
+    }
 
-  DEBUGP ((" 8"));
+  DEBUGP ((" 6"));
 
   return 1;
 }
@@ -836,20 +810,6 @@ set_cookie_header_cb (const char *hdr, void *closure)
    previously stored cookies.  Entry point is
    `build_cookies_request'.  */
 
-
-/* Count how many times CHR occurs in STRING. */
-
-static int
-count_char (const char *string, char chr)
-{
-  const char *p;
-  int count = 0;
-  for (p = string; *p; p++)
-    if (*p == chr)
-      ++count;
-  return count;
-}
-
 /* Store CHAIN to STORE if there is room in STORE.  If not, inrecement
    COUNT anyway, so that when the function is done, we end up with the
    exact count of how much place we actually need.  */