Description: Only use full host matches for hosts used as IP address
Origin: upstream, http://curl.haxx.se/libcurl-cookie-leak.patch
Forwarded: not-needed
Author: Tim Ruehsen <tim.ruehsen@gmx.de>
Last-Update: 2014-09-06

--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -94,6 +94,7 @@
 #include "strtoofft.h"
 #include "rawstr.h"
 #include "curl_memrchr.h"
+#include "inet_pton.h"
 
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -177,6 +178,27 @@
   *str = strdup(newstr);
 }
 
+/*
+ * Return true if the given string is an IP(v4|v6) address.
+ */
+static bool isip(const char *domain)
+{
+  struct in_addr addr;
+#ifdef ENABLE_IPV6
+  struct in6_addr addr6;
+#endif
+
+  if(Curl_inet_pton(AF_INET, domain, &addr)
+#ifdef ENABLE_IPV6
+     || Curl_inet_pton(AF_INET6, domain, &addr6)
+#endif
+    ) {
+    /* domain name given as IP address */
+    return TRUE;
+  }
+
+  return FALSE;
+}
 
 /****************************************************************************
  *
@@ -327,24 +349,27 @@
                   whatptr);
           }
           else {
+            bool is_ip;
+
             /* Now, we make sure that our host is within the given domain,
                or the given domain is not valid and thus cannot be set. */
 
             if('.' == whatptr[0])
               whatptr++; /* ignore preceding dot */
 
-            if(!domain || tailmatch(whatptr, domain)) {
-              const char *tailptr=whatptr;
-              if(tailptr[0] == '.')
-                tailptr++;
-              strstore(&co->domain, tailptr); /* don't prefix w/dots
-                                                 internally */
+            is_ip = isip(domain ? domain : whatptr);
+
+            if(!domain
+               || (is_ip && !strcmp(whatptr, domain))
+               || (!is_ip && tailmatch(whatptr, domain))) {
+              strstore(&co->domain, whatptr);
               if(!co->domain) {
                 badcookie = TRUE;
                 break;
               }
-              co->tailmatch=TRUE; /* we always do that if the domain name was
-                                     given */
+              if(!is_ip)
+                co->tailmatch=TRUE; /* we always do that if the domain name was
+                                       given */
             }
             else {
               /* we did not get a tailmatch and then the attempted set domain
@@ -819,10 +844,14 @@
   time_t now = time(NULL);
   struct Cookie *mainco=NULL;
   size_t matches = 0;
+  bool is_ip;
 
   if(!c || !c->cookies)
     return NULL; /* no cookie struct or no cookies in the struct */
 
+  /* check if host is an IP(v4|v6) address */
+  is_ip = isip(host);
+
   co = c->cookies;
 
   while(co) {
@@ -834,8 +863,8 @@
 
       /* now check if the domain is correct */
       if(!co->domain ||
-         (co->tailmatch && tailmatch(co->domain, host)) ||
-         (!co->tailmatch && Curl_raw_equal(host, co->domain)) ) {
+         (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
+         ((!co->tailmatch || is_ip) && Curl_raw_equal(host, co->domain)) ) {
         /* the right part of the host matches the domain stuff in the
            cookie data */
 
--- a/tests/data/test1105
+++ b/tests/data/test1105
@@ -56,8 +56,7 @@
 # This file was generated by libcurl! Edit at your own risk.
 
 127.0.0.1	FALSE	/we/want/	FALSE	0	foobar	name
-.127.0.0.1	TRUE	"/silly/"	FALSE	0	mismatch	this
-.0.0.1	TRUE	/	FALSE	0	partmatch	present
+127.0.0.1	FALSE	"/silly/"	FALSE	0	mismatch	this
 </file>
 </verify>
 </testcase>
--- a/tests/data/test31
+++ b/tests/data/test31
@@ -49,7 +49,8 @@
 Set-Cookie: test=yes; domain=foo.com; expires=Sat Feb 2 11:56:27 GMT 2030
 Set-Cookie: test2=yes; domain=se; expires=Sat Feb 2 11:56:27 GMT 2030
 Set-Cookie: magic=yessir; path=/silly/; HttpOnly
-Set-Cookie: blexp=yesyes; domain=.0.0.1; domain=.0.0.1; expiry=totally bad;
+Set-Cookie: blexp=yesyes; domain=127.0.0.1; domain=127.0.0.1; expiry=totally bad;
+Set-Cookie: partialip=nono; domain=.0.0.1;
 
 boo
 </data>
@@ -90,33 +91,33 @@
 # http://curl.haxx.se/rfc/cookie_spec.html
 # This file was generated by libcurl! Edit at your own risk.
 
-.127.0.0.1	TRUE	/silly/	FALSE	0	ismatch	this
-.127.0.0.1	TRUE	/secure1/	TRUE	0	sec1value	secure1
-.127.0.0.1	TRUE	/secure2/	TRUE	0	sec2value	secure2
-.127.0.0.1	TRUE	/secure3/	TRUE	0	sec3value	secure3
-.127.0.0.1	TRUE	/secure4/	TRUE	0	sec4value	secure4
-.127.0.0.1	TRUE	/secure5/	TRUE	0	sec5value	secure5
-.127.0.0.1	TRUE	/secure6/	TRUE	0	sec6value	secure6
-.127.0.0.1	TRUE	/secure7/	TRUE	0	sec7value	secure7
-.127.0.0.1	TRUE	/secure8/	TRUE	0	sec8value	secure8
-.127.0.0.1	TRUE	/secure9/	TRUE	0	secure	very1
-#HttpOnly_.127.0.0.1	TRUE	/p1/	FALSE	0	httpo1	value1
-#HttpOnly_.127.0.0.1	TRUE	/p2/	FALSE	0	httpo2	value2
-#HttpOnly_.127.0.0.1	TRUE	/p3/	FALSE	0	httpo3	value3
-#HttpOnly_.127.0.0.1	TRUE	/p4/	FALSE	0	httpo4	value4
-#HttpOnly_.127.0.0.1	TRUE	/p4/	FALSE	0	httponly	myvalue1
-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec	myvalue2
-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec2	myvalue3
-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec3	myvalue4
-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec4	myvalue5
-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec5	myvalue6
-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec6	myvalue7
-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec7	myvalue8
-#HttpOnly_.127.0.0.1	TRUE	/p4/	TRUE	0	httpandsec8	myvalue9
-.127.0.0.1	TRUE	/	FALSE	0	partmatch	present
+127.0.0.1	FALSE	/silly/	FALSE	0	ismatch	this
+127.0.0.1	FALSE	/secure1/	TRUE	0	sec1value	secure1
+127.0.0.1	FALSE	/secure2/	TRUE	0	sec2value	secure2
+127.0.0.1	FALSE	/secure3/	TRUE	0	sec3value	secure3
+127.0.0.1	FALSE	/secure4/	TRUE	0	sec4value	secure4
+127.0.0.1	FALSE	/secure5/	TRUE	0	sec5value	secure5
+127.0.0.1	FALSE	/secure6/	TRUE	0	sec6value	secure6
+127.0.0.1	FALSE	/secure7/	TRUE	0	sec7value	secure7
+127.0.0.1	FALSE	/secure8/	TRUE	0	sec8value	secure8
+127.0.0.1	FALSE	/secure9/	TRUE	0	secure	very1
+#HttpOnly_127.0.0.1	FALSE	/p1/	FALSE	0	httpo1	value1
+#HttpOnly_127.0.0.1	FALSE	/p2/	FALSE	0	httpo2	value2
+#HttpOnly_127.0.0.1	FALSE	/p3/	FALSE	0	httpo3	value3
+#HttpOnly_127.0.0.1	FALSE	/p4/	FALSE	0	httpo4	value4
+#HttpOnly_127.0.0.1	FALSE	/p4/	FALSE	0	httponly	myvalue1
+#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec	myvalue2
+#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec2	myvalue3
+#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec3	myvalue4
+#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec4	myvalue5
+#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec5	myvalue6
+#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec6	myvalue7
+#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec7	myvalue8
+#HttpOnly_127.0.0.1	FALSE	/p4/	TRUE	0	httpandsec8	myvalue9
+127.0.0.1	FALSE	/	FALSE	0	partmatch	present
 127.0.0.1	FALSE	/we/want/	FALSE	2054030187	nodomain	value
 #HttpOnly_127.0.0.1	FALSE	/silly/	FALSE	0	magic	yessir
-.0.0.1	TRUE	/we/want/	FALSE	0	blexp	yesyes
+127.0.0.1	FALSE	/we/want/	FALSE	0	blexp	yesyes
 </file>
 </verify>
 </testcase>
--- a/tests/data/test8
+++ b/tests/data/test8
@@ -42,7 +42,8 @@
 Set-Cookie: cookie=yes; path=/we;
 Set-Cookie: cookie=perhaps; path=/we/want;
 Set-Cookie: nocookie=yes; path=/WE;
-Set-Cookie: blexp=yesyes; domain=.0.0.1; domain=.0.0.1; expiry=totally bad;
+Set-Cookie: blexp=yesyes; domain=%HOSTIP; domain=%HOSTIP; expiry=totally bad;
+Set-Cookie: partialip=nono; domain=.0.0.1;
 
 </file>
 </client>
@@ -56,7 +57,7 @@
 GET /we/want/8 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
-Cookie: cookie=perhaps; cookie=yes; partmatch=present; foobar=name; blexp=yesyes
+Cookie: cookie=perhaps; cookie=yes; foobar=name; blexp=yesyes
 
 </protocol>
 </verify>
