Commit efd836d9 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Many cookie fixes:

  o Save domains in jars like Mozilla does. It means all domains set in
    Set-Cookie: headers are dot-prefixed.
  o Save and use the 'tailmatch' field in the Mozilla/Netscape cookie jars (the
    second column).
  o Reject cookies using illegal domains in the Set-Cookie: line. Concerns
    both domains with too few dots or domains that are outside the currently
    operating server host's domain.
  o Set the path part by default to the one used in the request, if none was
    set in the Set-Cookie line.
parent 836aaa16
Loading
Loading
Loading
Loading
+136 −56
Original line number Diff line number Diff line
@@ -111,6 +111,17 @@ free_cookiemess(struct Cookie *co)
  free(co);
}

static bool tailmatch(const char *little, const char *bigone)
{
  unsigned int littlelen = strlen(little);
  unsigned int biglen = strlen(bigone);

  if(littlelen > biglen)
    return FALSE;

  return strequal(little, bigone+biglen-littlelen);
}

/****************************************************************************
 *
 * Curl_cookie_add()
@@ -123,7 +134,10 @@ struct Cookie *
Curl_cookie_add(struct CookieInfo *c,
                bool httpheader, /* TRUE if HTTP header-style line */
                char *lineptr,   /* first character of the line */
                char *domain)    /* default domain */
                char *domain,    /* default domain */
                char *path)      /* full path used when this cookie is set,
                                    used to get default path for the cookie
                                    unless set */
{
  struct Cookie *clist;
  char what[MAX_COOKIE_LINE];
@@ -134,6 +148,7 @@ Curl_cookie_add(struct CookieInfo *c,
  struct Cookie *lastc=NULL;
  time_t now = time(NULL);
  bool replace_old = FALSE;
  bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */

  /* First, alloc and init a new struct for it */
  co = (struct Cookie *)malloc(sizeof(struct Cookie));
@@ -186,8 +201,58 @@ Curl_cookie_add(struct CookieInfo *c,
            co->path=strdup(whatptr);
          }
          else if(strequal("domain", name)) {
            /* note that this name may or may not have a preceeding dot, but
               we don't care about that, we treat the names the same anyway */

            char *ptr=whatptr;
            int dotcount=1;
            unsigned int i;

            static const char *seventhree[]= {
              "com", "edu", "net", "org", "gov", "mil", "int"
            };

            /* Count the dots, we need to make sure that there are THREE dots
               in the normal domains, or TWO in the seventhree-domains. */

            if('.' == whatptr[0])
              /* don't count the initial dot, assume it */
              ptr++;

            do {
              ptr = strchr(ptr, '.');
              if(ptr) {
                ptr++;
                dotcount++;
              }
            } while(ptr);

            for(i=0;
                i<sizeof(seventhree)/sizeof(seventhree[0]); i++) {
              if(tailmatch(seventhree[i], whatptr)) {
                dotcount++; /* we allow one dot less for these */
                break;
              }
            }
            if(dotcount < 3)
              /* Received and skipped a cookie with a domain using too few
                 dots. */
              badcookie=TRUE; /* mark this as a bad cookie */
            else {
              /* 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(!domain || tailmatch(whatptr, domain)) {
                co->domain=strdup(whatptr);
            co->field1= (whatptr[0]=='.')?2:1;
                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
                   is not a domain to which the current host belongs. Mark as
                   bad. */
                badcookie=TRUE;
            }
          }
          else if(strequal("version", name)) {
            co->version=strdup(whatptr);
@@ -249,8 +314,11 @@ Curl_cookie_add(struct CookieInfo *c,
        semiptr=strchr(ptr, '\0');
    } while(semiptr);

    if(NULL == co->name) {
      /* we didn't get a cookie name, this is an illegal line, bail out */
    if(badcookie || (NULL == co->name)) {
      /* we didn't get a cookie name or a bad one,
         this is an illegal line, bail out */
      if(co->expirestr)
        free(co->expirestr);
      if(co->domain)
        free(co->domain);
      if(co->path)
@@ -264,8 +332,20 @@ Curl_cookie_add(struct CookieInfo *c,
    }

    if(NULL == co->domain)
      /* no domain given in the header line, set the default now */
      /* no domain was given in the header line, set the default now */
      co->domain=domain?strdup(domain):NULL;
    if((NULL == co->path) && path) {
      /* no path was given in the header line, set the default now */
      char *endslash = strrchr(path, '/');
      if(endslash) {
        int pathlen = endslash-path+1; /* include the ending slash */
        co->path=malloc(pathlen+1); /* one extra for the zero byte */
        if(co->path) {
          memcpy(co->path, path, pathlen);
          co->path[pathlen]=0; /* zero terminate */
        }
      }
    }
  }
  else {
    /* This line is NOT a HTTP header style line, we do offer support for
@@ -297,7 +377,8 @@ Curl_cookie_add(struct CookieInfo *c,

    /* Now loop through the fields and init the struct we already have
       allocated */
    for(ptr=firstptr, fields=0; ptr; ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
    for(ptr=firstptr, fields=0; ptr;
        ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
      switch(fields) {
      case 0:
        co->domain = strdup(ptr);
@@ -312,10 +393,8 @@ Curl_cookie_add(struct CookieInfo *c,

           As far as I can see, it is set to true when the cookie says
           .domain.com and to false when the domain is complete www.domain.com

           We don't currently take advantage of this knowledge.
        */
        co->field1=strequal(ptr, "TRUE")+1; /* store information */
        co->tailmatch=strequal(ptr, "TRUE"); /* store information */
        break;
      case 2:
        /* It turns out, that sometimes the file format allows the path
@@ -375,10 +454,11 @@ Curl_cookie_add(struct CookieInfo *c,

      if(clist->domain && co->domain) {
        if(strequal(clist->domain, co->domain) ||
           (clist->domain[0]=='.' &&
           (co->tailmatch && /* only do the dot magic if tailmatching is OK */
            ((clist->domain[0]=='.' &&
              strequal(&(clist->domain[1]), co->domain)) ||
             (co->domain[0]=='.' &&
            strequal(clist->domain, &(co->domain[1]))) )
              strequal(clist->domain, &(co->domain[1]))))) )
          /* The domains are identical, or at least identical if you skip the
             preceeding dot */
          replace_old=TRUE;
@@ -532,7 +612,7 @@ struct CookieInfo *Curl_cookie_init(char *file,
      while(*lineptr && isspace((int)*lineptr))
        lineptr++;

      Curl_cookie_add(c, headerline, lineptr, NULL);
      Curl_cookie_add(c, headerline, lineptr, NULL, NULL);
    }
    if(fromfile)
      fclose(fp);
@@ -561,9 +641,6 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
   struct Cookie *newco;
   struct Cookie *co;
   time_t now = time(NULL);
   int hostlen=strlen(host);
   int domlen;

   struct Cookie *mainco=NULL;

   if(!c || !c->cookies)
@@ -579,10 +656,9 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
         (co->secure?secure:TRUE) ) {
       
       /* now check if the domain is correct */
	 domlen=co->domain?strlen(co->domain):0;
       if(!co->domain ||
	    ((domlen<=hostlen) &&
	     strequal(host+(hostlen-domlen), co->domain)) ) {
          (co->tailmatch && tailmatch(co->domain, host)) ||
          (!co->tailmatch && strequal(host, co->domain)) ) {
         /* the right part of the host matches the domain stuff in the
            cookie data */
         
@@ -716,15 +792,19 @@ int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
     
    while(co) {
      fprintf(out,
              "%s\t" /* domain */
              "%s\t" /* field1 */
              "%s%s\t" /* domain */
              "%s\t" /* tailmatch */
              "%s\t" /* path */
              "%s\t" /* secure */
              "%u\t" /* expires */
              "%s\t" /* name */
              "%s\n", /* value */

              /* Make sure all domains are prefixed with a dot if they allow
                 tailmatching. This is Mozilla-style. */
              (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
              co->domain?co->domain:"unknown",
              co->field1==2?"TRUE":"FALSE",
              co->tailmatch?"TRUE":"FALSE",
              co->path?co->path:"/",
              co->secure?"TRUE":"FALSE",
              (unsigned int)co->expires,
+4 −5
Original line number Diff line number Diff line
@@ -40,8 +40,7 @@ struct Cookie {
  char *domain;      /* domain = <this> */
  long expires;    /* expires = <this> */
  char *expirestr;   /* the plain text version */

  char field1;       /* read from a cookie file, 1 => FALSE, 2=> TRUE */
  bool tailmatch;    /* weather we do tail-matchning of the domain name */
  
  /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */
  char *version;     /* Version = <value> */
@@ -70,11 +69,11 @@ struct CookieInfo {
#define MAX_NAME_TXT "255"

/*
 * Add a cookie to the internal list of cookies. The domain argument is only
 * used if the header boolean is TRUE.
 * Add a cookie to the internal list of cookies. The domain and path arguments
 * are only used if the header boolean is TRUE.
 */
struct Cookie *Curl_cookie_add(struct CookieInfo *, bool header, char *line,
                               char *domain);
                               char *domain, char *path);

struct CookieInfo *Curl_cookie_init(char *, struct CookieInfo *, bool);
struct Cookie *Curl_cookie_getlist(struct CookieInfo *, char *, char *, bool);