Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at http://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 
     23 /***
     24 
     25 
     26 RECEIVING COOKIE INFORMATION
     27 ============================
     28 
     29 struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
     30                     const char *file, struct CookieInfo *inc, bool newsession);
     31 
     32         Inits a cookie struct to store data in a local file. This is always
     33         called before any cookies are set.
     34 
     35 struct Cookie *Curl_cookie_add(struct SessionHandle *data,
     36                  struct CookieInfo *c, bool httpheader, char *lineptr,
     37                  const char *domain, const char *path);
     38 
     39         The 'lineptr' parameter is a full "Set-cookie:" line as
     40         received from a server.
     41 
     42         The function need to replace previously stored lines that this new
     43         line superceeds.
     44 
     45         It may remove lines that are expired.
     46 
     47         It should return an indication of success/error.
     48 
     49 
     50 SENDING COOKIE INFORMATION
     51 ==========================
     52 
     53 struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie,
     54                                     char *host, char *path, bool secure);
     55 
     56         For a given host and path, return a linked list of cookies that
     57         the client should send to the server if used now. The secure
     58         boolean informs the cookie if a secure connection is achieved or
     59         not.
     60 
     61         It shall only return cookies that haven't expired.
     62 
     63 
     64 Example set of cookies:
     65 
     66     Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
     67     Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
     68     domain=.fidelity.com; path=/ftgw; secure
     69     Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
     70     domain=.fidelity.com; path=/; secure
     71     Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
     72     domain=.fidelity.com; path=/; secure
     73     Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
     74     domain=.fidelity.com; path=/; secure
     75     Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
     76     domain=.fidelity.com; path=/; secure
     77     Set-cookie:
     78     Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
     79     13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
     80 ****/
     81 
     82 #include "curl_setup.h"
     83 
     84 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
     85 
     86 #include "curl_printf.h"
     87 #include "urldata.h"
     88 #include "cookie.h"
     89 #include "strequal.h"
     90 #include "strtok.h"
     91 #include "sendf.h"
     92 #include "slist.h"
     93 #include "share.h"
     94 #include "strtoofft.h"
     95 #include "rawstr.h"
     96 #include "curl_memrchr.h"
     97 #include "inet_pton.h"
     98 
     99 /* The last #include files should be: */
    100 #include "curl_memory.h"
    101 #include "memdebug.h"
    102 
    103 static void freecookie(struct Cookie *co)
    104 {
    105   free(co->expirestr);
    106   free(co->domain);
    107   free(co->path);
    108   free(co->spath);
    109   free(co->name);
    110   free(co->value);
    111   free(co->maxage);
    112   free(co->version);
    113   free(co);
    114 }
    115 
    116 static bool tailmatch(const char *cooke_domain, const char *hostname)
    117 {
    118   size_t cookie_domain_len = strlen(cooke_domain);
    119   size_t hostname_len = strlen(hostname);
    120 
    121   if(hostname_len < cookie_domain_len)
    122     return FALSE;
    123 
    124   if(!Curl_raw_equal(cooke_domain, hostname+hostname_len-cookie_domain_len))
    125     return FALSE;
    126 
    127   /* A lead char of cookie_domain is not '.'.
    128      RFC6265 4.1.2.3. The Domain Attribute says:
    129        For example, if the value of the Domain attribute is
    130        "example.com", the user agent will include the cookie in the Cookie
    131        header when making HTTP requests to example.com, www.example.com, and
    132        www.corp.example.com.
    133    */
    134   if(hostname_len == cookie_domain_len)
    135     return TRUE;
    136   if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
    137     return TRUE;
    138   return FALSE;
    139 }
    140 
    141 /*
    142  * matching cookie path and url path
    143  * RFC6265 5.1.4 Paths and Path-Match
    144  */
    145 static bool pathmatch(const char* cookie_path, const char* request_uri)
    146 {
    147   size_t cookie_path_len;
    148   size_t uri_path_len;
    149   char* uri_path = NULL;
    150   char* pos;
    151   bool ret = FALSE;
    152 
    153   /* cookie_path must not have last '/' separator. ex: /sample */
    154   cookie_path_len = strlen(cookie_path);
    155   if(1 == cookie_path_len) {
    156     /* cookie_path must be '/' */
    157     return TRUE;
    158   }
    159 
    160   uri_path = strdup(request_uri);
    161   if(!uri_path)
    162     return FALSE;
    163   pos = strchr(uri_path, '?');
    164   if(pos)
    165     *pos = 0x0;
    166 
    167   /* #-fragments are already cut off! */
    168   if(0 == strlen(uri_path) || uri_path[0] != '/') {
    169     free(uri_path);
    170     uri_path = strdup("/");
    171     if(!uri_path)
    172       return FALSE;
    173   }
    174 
    175   /* here, RFC6265 5.1.4 says
    176      4. Output the characters of the uri-path from the first character up
    177         to, but not including, the right-most %x2F ("/").
    178      but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
    179      without redirect.
    180      Ignore this algorithm because /hoge is uri path for this case
    181      (uri path is not /).
    182    */
    183 
    184   uri_path_len = strlen(uri_path);
    185 
    186   if(uri_path_len < cookie_path_len) {
    187     ret = FALSE;
    188     goto pathmatched;
    189   }
    190 
    191   /* not using checkprefix() because matching should be case-sensitive */
    192   if(strncmp(cookie_path, uri_path, cookie_path_len)) {
    193     ret = FALSE;
    194     goto pathmatched;
    195   }
    196 
    197   /* The cookie-path and the uri-path are identical. */
    198   if(cookie_path_len == uri_path_len) {
    199     ret = TRUE;
    200     goto pathmatched;
    201   }
    202 
    203   /* here, cookie_path_len < url_path_len */
    204   if(uri_path[cookie_path_len] == '/') {
    205     ret = TRUE;
    206     goto pathmatched;
    207   }
    208 
    209   ret = FALSE;
    210 
    211 pathmatched:
    212   free(uri_path);
    213   return ret;
    214 }
    215 
    216 /*
    217  * cookie path sanitize
    218  */
    219 static char *sanitize_cookie_path(const char *cookie_path)
    220 {
    221   size_t len;
    222   char *new_path = strdup(cookie_path);
    223   if(!new_path)
    224     return NULL;
    225 
    226   /* some stupid site sends path attribute with '"'. */
    227   len = strlen(new_path);
    228   if(new_path[0] == '\"') {
    229     memmove((void *)new_path, (const void *)(new_path + 1), len);
    230     len--;
    231   }
    232   if(len && (new_path[len - 1] == '\"')) {
    233     new_path[len - 1] = 0x0;
    234     len--;
    235   }
    236 
    237   /* RFC6265 5.2.4 The Path Attribute */
    238   if(new_path[0] != '/') {
    239     /* Let cookie-path be the default-path. */
    240     free(new_path);
    241     new_path = strdup("/");
    242     return new_path;
    243   }
    244 
    245   /* convert /hoge/ to /hoge */
    246   if(len && new_path[len - 1] == '/') {
    247     new_path[len - 1] = 0x0;
    248   }
    249 
    250   return new_path;
    251 }
    252 
    253 /*
    254  * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
    255  *
    256  * NOTE: OOM or cookie parsing failures are ignored.
    257  */
    258 void Curl_cookie_loadfiles(struct SessionHandle *data)
    259 {
    260   struct curl_slist *list = data->change.cookielist;
    261   if(list) {
    262     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
    263     while(list) {
    264       struct CookieInfo *newcookies = Curl_cookie_init(data,
    265                                         list->data,
    266                                         data->cookies,
    267                                         data->set.cookiesession);
    268       if(!newcookies)
    269         /* Failure may be due to OOM or a bad cookie; both are ignored
    270          * but only the first should be
    271          */
    272         infof(data, "ignoring failed cookie_init for %s\n", list->data);
    273       else
    274         data->cookies = newcookies;
    275       list = list->next;
    276     }
    277     curl_slist_free_all(data->change.cookielist); /* clean up list */
    278     data->change.cookielist = NULL; /* don't do this again! */
    279     Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
    280   }
    281 }
    282 
    283 /*
    284  * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL
    285  * that will be freed before the allocated string is stored there.
    286  *
    287  * It is meant to easily replace strdup()
    288  */
    289 static void strstore(char **str, const char *newstr)
    290 {
    291   free(*str);
    292   *str = strdup(newstr);
    293 }
    294 
    295 /*
    296  * remove_expired() removes expired cookies.
    297  */
    298 static void remove_expired(struct CookieInfo *cookies)
    299 {
    300   struct Cookie *co, *nx, *pv;
    301   curl_off_t now = (curl_off_t)time(NULL);
    302 
    303   co = cookies->cookies;
    304   pv = NULL;
    305   while(co) {
    306     nx = co->next;
    307     if((co->expirestr || co->maxage) && co->expires < now) {
    308       if(co == cookies->cookies) {
    309         cookies->cookies = co->next;
    310       }
    311       else {
    312         pv->next = co->next;
    313       }
    314       cookies->numcookies--;
    315       freecookie(co);
    316     }
    317     else {
    318       pv = co;
    319     }
    320     co = nx;
    321   }
    322 }
    323 
    324 /*
    325  * Return true if the given string is an IP(v4|v6) address.
    326  */
    327 static bool isip(const char *domain)
    328 {
    329   struct in_addr addr;
    330 #ifdef ENABLE_IPV6
    331   struct in6_addr addr6;
    332 #endif
    333 
    334   if(Curl_inet_pton(AF_INET, domain, &addr)
    335 #ifdef ENABLE_IPV6
    336      || Curl_inet_pton(AF_INET6, domain, &addr6)
    337 #endif
    338     ) {
    339     /* domain name given as IP address */
    340     return TRUE;
    341   }
    342 
    343   return FALSE;
    344 }
    345 
    346 /****************************************************************************
    347  *
    348  * Curl_cookie_add()
    349  *
    350  * Add a single cookie line to the cookie keeping object.
    351  *
    352  * Be aware that sometimes we get an IP-only host name, and that might also be
    353  * a numerical IPv6 address.
    354  *
    355  * Returns NULL on out of memory or invalid cookie. This is suboptimal,
    356  * as they should be treated separately.
    357  ***************************************************************************/
    358 
    359 struct Cookie *
    360 Curl_cookie_add(struct SessionHandle *data,
    361                 /* The 'data' pointer here may be NULL at times, and thus
    362                    must only be used very carefully for things that can deal
    363                    with data being NULL. Such as infof() and similar */
    364 
    365                 struct CookieInfo *c,
    366                 bool httpheader, /* TRUE if HTTP header-style line */
    367                 char *lineptr,   /* first character of the line */
    368                 const char *domain, /* default domain */
    369                 const char *path)   /* full path used when this cookie is set,
    370                                        used to get default path for the cookie
    371                                        unless set */
    372 {
    373   struct Cookie *clist;
    374   char name[MAX_NAME];
    375   struct Cookie *co;
    376   struct Cookie *lastc=NULL;
    377   time_t now = time(NULL);
    378   bool replace_old = FALSE;
    379   bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
    380 
    381 #ifdef CURL_DISABLE_VERBOSE_STRINGS
    382   (void)data;
    383 #endif
    384 
    385   /* First, alloc and init a new struct for it */
    386   co = calloc(1, sizeof(struct Cookie));
    387   if(!co)
    388     return NULL; /* bail out if we're this low on memory */
    389 
    390   if(httpheader) {
    391     /* This line was read off a HTTP-header */
    392     const char *ptr;
    393     const char *semiptr;
    394     char *what;
    395 
    396     what = malloc(MAX_COOKIE_LINE);
    397     if(!what) {
    398       free(co);
    399       return NULL;
    400     }
    401 
    402     semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
    403 
    404     while(*lineptr && ISBLANK(*lineptr))
    405       lineptr++;
    406 
    407     ptr = lineptr;
    408     do {
    409       /* we have a <what>=<this> pair or a stand-alone word here */
    410       name[0]=what[0]=0; /* init the buffers */
    411       if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n =] =%"
    412                      MAX_COOKIE_LINE_TXT "[^;\r\n]",
    413                      name, what)) {
    414         /* Use strstore() below to properly deal with received cookie
    415            headers that have the same string property set more than once,
    416            and then we use the last one. */
    417         const char *whatptr;
    418         bool done = FALSE;
    419         bool sep;
    420         size_t len=strlen(what);
    421         const char *endofn = &ptr[ strlen(name) ];
    422 
    423         /* skip trailing spaces in name */
    424         while(*endofn && ISBLANK(*endofn))
    425           endofn++;
    426 
    427         /* name ends with a '=' ? */
    428         sep = (*endofn == '=')?TRUE:FALSE;
    429 
    430         /* Strip off trailing whitespace from the 'what' */
    431         while(len && ISBLANK(what[len-1])) {
    432           what[len-1]=0;
    433           len--;
    434         }
    435 
    436         /* Skip leading whitespace from the 'what' */
    437         whatptr=what;
    438         while(*whatptr && ISBLANK(*whatptr))
    439           whatptr++;
    440 
    441         if(!len) {
    442           /* this was a "<name>=" with no content, and we must allow
    443              'secure' and 'httponly' specified this weirdly */
    444           done = TRUE;
    445           if(Curl_raw_equal("secure", name))
    446             co->secure = TRUE;
    447           else if(Curl_raw_equal("httponly", name))
    448             co->httponly = TRUE;
    449           else if(sep)
    450             /* there was a '=' so we're not done parsing this field */
    451             done = FALSE;
    452         }
    453         if(done)
    454           ;
    455         else if(Curl_raw_equal("path", name)) {
    456           strstore(&co->path, whatptr);
    457           if(!co->path) {
    458             badcookie = TRUE; /* out of memory bad */
    459             break;
    460           }
    461           co->spath = sanitize_cookie_path(co->path);
    462           if(!co->spath) {
    463             badcookie = TRUE; /* out of memory bad */
    464             break;
    465           }
    466         }
    467         else if(Curl_raw_equal("domain", name)) {
    468           bool is_ip;
    469           const char *dotp;
    470 
    471           /* Now, we make sure that our host is within the given domain,
    472              or the given domain is not valid and thus cannot be set. */
    473 
    474           if('.' == whatptr[0])
    475             whatptr++; /* ignore preceding dot */
    476 
    477           is_ip = isip(domain ? domain : whatptr);
    478 
    479           /* check for more dots */
    480           dotp = strchr(whatptr, '.');
    481           if(!dotp)
    482             domain=":";
    483 
    484           if(!domain
    485              || (is_ip && !strcmp(whatptr, domain))
    486              || (!is_ip && tailmatch(whatptr, domain))) {
    487             strstore(&co->domain, whatptr);
    488             if(!co->domain) {
    489               badcookie = TRUE;
    490               break;
    491             }
    492             if(!is_ip)
    493               co->tailmatch=TRUE; /* we always do that if the domain name was
    494                                      given */
    495           }
    496           else {
    497             /* we did not get a tailmatch and then the attempted set domain
    498                is not a domain to which the current host belongs. Mark as
    499                bad. */
    500             badcookie=TRUE;
    501             infof(data, "skipped cookie with bad tailmatch domain: %s\n",
    502                   whatptr);
    503           }
    504         }
    505         else if(Curl_raw_equal("version", name)) {
    506           strstore(&co->version, whatptr);
    507           if(!co->version) {
    508             badcookie = TRUE;
    509             break;
    510           }
    511         }
    512         else if(Curl_raw_equal("max-age", name)) {
    513           /* Defined in RFC2109:
    514 
    515              Optional.  The Max-Age attribute defines the lifetime of the
    516              cookie, in seconds.  The delta-seconds value is a decimal non-
    517              negative integer.  After delta-seconds seconds elapse, the
    518              client should discard the cookie.  A value of zero means the
    519              cookie should be discarded immediately.
    520 
    521           */
    522           strstore(&co->maxage, whatptr);
    523           if(!co->maxage) {
    524             badcookie = TRUE;
    525             break;
    526           }
    527         }
    528         else if(Curl_raw_equal("expires", name)) {
    529           strstore(&co->expirestr, whatptr);
    530           if(!co->expirestr) {
    531             badcookie = TRUE;
    532             break;
    533           }
    534         }
    535         else if(!co->name) {
    536           co->name = strdup(name);
    537           co->value = strdup(whatptr);
    538           if(!co->name || !co->value) {
    539             badcookie = TRUE;
    540             break;
    541           }
    542         }
    543         /*
    544           else this is the second (or more) name we don't know
    545           about! */
    546       }
    547       else {
    548         /* this is an "illegal" <what>=<this> pair */
    549       }
    550 
    551       if(!semiptr || !*semiptr) {
    552         /* we already know there are no more cookies */
    553         semiptr = NULL;
    554         continue;
    555       }
    556 
    557       ptr=semiptr+1;
    558       while(*ptr && ISBLANK(*ptr))
    559         ptr++;
    560       semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
    561 
    562       if(!semiptr && *ptr)
    563         /* There are no more semicolons, but there's a final name=value pair
    564            coming up */
    565         semiptr=strchr(ptr, '\0');
    566     } while(semiptr);
    567 
    568     if(co->maxage) {
    569       co->expires =
    570         curlx_strtoofft((*co->maxage=='\"')?
    571                         &co->maxage[1]:&co->maxage[0], NULL, 10);
    572       if(CURL_OFF_T_MAX - now < co->expires)
    573         /* avoid overflow */
    574         co->expires = CURL_OFF_T_MAX;
    575       else
    576         co->expires += now;
    577     }
    578     else if(co->expirestr) {
    579       /* Note that if the date couldn't get parsed for whatever reason,
    580          the cookie will be treated as a session cookie */
    581       co->expires = curl_getdate(co->expirestr, NULL);
    582 
    583       /* Session cookies have expires set to 0 so if we get that back
    584          from the date parser let's add a second to make it a
    585          non-session cookie */
    586       if(co->expires == 0)
    587         co->expires = 1;
    588       else if(co->expires < 0)
    589         co->expires = 0;
    590     }
    591 
    592     if(!badcookie && !co->domain) {
    593       if(domain) {
    594         /* no domain was given in the header line, set the default */
    595         co->domain=strdup(domain);
    596         if(!co->domain)
    597           badcookie = TRUE;
    598       }
    599     }
    600 
    601     if(!badcookie && !co->path && path) {
    602       /* No path was given in the header line, set the default.
    603          Note that the passed-in path to this function MAY have a '?' and
    604          following part that MUST not be stored as part of the path. */
    605       char *queryp = strchr(path, '?');
    606 
    607       /* queryp is where the interesting part of the path ends, so now we
    608          want to the find the last */
    609       char *endslash;
    610       if(!queryp)
    611         endslash = strrchr(path, '/');
    612       else
    613         endslash = memrchr(path, '/', (size_t)(queryp - path));
    614       if(endslash) {
    615         size_t pathlen = (size_t)(endslash-path+1); /* include ending slash */
    616         co->path=malloc(pathlen+1); /* one extra for the zero byte */
    617         if(co->path) {
    618           memcpy(co->path, path, pathlen);
    619           co->path[pathlen]=0; /* zero terminate */
    620           co->spath = sanitize_cookie_path(co->path);
    621           if(!co->spath)
    622             badcookie = TRUE; /* out of memory bad */
    623         }
    624         else
    625           badcookie = TRUE;
    626       }
    627     }
    628 
    629     free(what);
    630 
    631     if(badcookie || !co->name) {
    632       /* we didn't get a cookie name or a bad one,
    633          this is an illegal line, bail out */
    634       freecookie(co);
    635       return NULL;
    636     }
    637 
    638   }
    639   else {
    640     /* This line is NOT a HTTP header style line, we do offer support for
    641        reading the odd netscape cookies-file format here */
    642     char *ptr;
    643     char *firstptr;
    644     char *tok_buf=NULL;
    645     int fields;
    646 
    647     /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
    648        marked with httpOnly after the domain name are not accessible
    649        from javascripts, but since curl does not operate at javascript
    650        level, we include them anyway. In Firefox's cookie files, these
    651        lines are preceded with #HttpOnly_ and then everything is
    652        as usual, so we skip 10 characters of the line..
    653     */
    654     if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
    655       lineptr += 10;
    656       co->httponly = TRUE;
    657     }
    658 
    659     if(lineptr[0]=='#') {
    660       /* don't even try the comments */
    661       free(co);
    662       return NULL;
    663     }
    664     /* strip off the possible end-of-line characters */
    665     ptr=strchr(lineptr, '\r');
    666     if(ptr)
    667       *ptr=0; /* clear it */
    668     ptr=strchr(lineptr, '\n');
    669     if(ptr)
    670       *ptr=0; /* clear it */
    671 
    672     firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
    673 
    674     /* Now loop through the fields and init the struct we already have
    675        allocated */
    676     for(ptr=firstptr, fields=0; ptr && !badcookie;
    677         ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
    678       switch(fields) {
    679       case 0:
    680         if(ptr[0]=='.') /* skip preceding dots */
    681           ptr++;
    682         co->domain = strdup(ptr);
    683         if(!co->domain)
    684           badcookie = TRUE;
    685         break;
    686       case 1:
    687         /* This field got its explanation on the 23rd of May 2001 by
    688            Andrs Garca:
    689 
    690            flag: A TRUE/FALSE value indicating if all machines within a given
    691            domain can access the variable. This value is set automatically by
    692            the browser, depending on the value you set for the domain.
    693 
    694            As far as I can see, it is set to true when the cookie says
    695            .domain.com and to false when the domain is complete www.domain.com
    696         */
    697         co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE;
    698         break;
    699       case 2:
    700         /* It turns out, that sometimes the file format allows the path
    701            field to remain not filled in, we try to detect this and work
    702            around it! Andrs Garca made us aware of this... */
    703         if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
    704           /* only if the path doesn't look like a boolean option! */
    705           co->path = strdup(ptr);
    706           if(!co->path)
    707             badcookie = TRUE;
    708           else {
    709             co->spath = sanitize_cookie_path(co->path);
    710             if(!co->spath) {
    711               badcookie = TRUE; /* out of memory bad */
    712             }
    713           }
    714           break;
    715         }
    716         /* this doesn't look like a path, make one up! */
    717         co->path = strdup("/");
    718         if(!co->path)
    719           badcookie = TRUE;
    720         co->spath = strdup("/");
    721         if(!co->spath)
    722           badcookie = TRUE;
    723         fields++; /* add a field and fall down to secure */
    724         /* FALLTHROUGH */
    725       case 3:
    726         co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE;
    727         break;
    728       case 4:
    729         co->expires = curlx_strtoofft(ptr, NULL, 10);
    730         break;
    731       case 5:
    732         co->name = strdup(ptr);
    733         if(!co->name)
    734           badcookie = TRUE;
    735         break;
    736       case 6:
    737         co->value = strdup(ptr);
    738         if(!co->value)
    739           badcookie = TRUE;
    740         break;
    741       }
    742     }
    743     if(6 == fields) {
    744       /* we got a cookie with blank contents, fix it */
    745       co->value = strdup("");
    746       if(!co->value)
    747         badcookie = TRUE;
    748       else
    749         fields++;
    750     }
    751 
    752     if(!badcookie && (7 != fields))
    753       /* we did not find the sufficient number of fields */
    754       badcookie = TRUE;
    755 
    756     if(badcookie) {
    757       freecookie(co);
    758       return NULL;
    759     }
    760 
    761   }
    762 
    763   if(!c->running &&    /* read from a file */
    764      c->newsession &&  /* clean session cookies */
    765      !co->expires) {   /* this is a session cookie since it doesn't expire! */
    766     freecookie(co);
    767     return NULL;
    768   }
    769 
    770   co->livecookie = c->running;
    771 
    772   /* now, we have parsed the incoming line, we must now check if this
    773      superceeds an already existing cookie, which it may if the previous have
    774      the same domain and path as this */
    775 
    776   /* at first, remove expired cookies */
    777   remove_expired(c);
    778 
    779   clist = c->cookies;
    780   replace_old = FALSE;
    781   while(clist) {
    782     if(Curl_raw_equal(clist->name, co->name)) {
    783       /* the names are identical */
    784 
    785       if(clist->domain && co->domain) {
    786         if(Curl_raw_equal(clist->domain, co->domain))
    787           /* The domains are identical */
    788           replace_old=TRUE;
    789       }
    790       else if(!clist->domain && !co->domain)
    791         replace_old = TRUE;
    792 
    793       if(replace_old) {
    794         /* the domains were identical */
    795 
    796         if(clist->spath && co->spath) {
    797           if(Curl_raw_equal(clist->spath, co->spath)) {
    798             replace_old = TRUE;
    799           }
    800           else
    801             replace_old = FALSE;
    802         }
    803         else if(!clist->spath && !co->spath)
    804           replace_old = TRUE;
    805         else
    806           replace_old = FALSE;
    807 
    808       }
    809 
    810       if(replace_old && !co->livecookie && clist->livecookie) {
    811         /* Both cookies matched fine, except that the already present
    812            cookie is "live", which means it was set from a header, while
    813            the new one isn't "live" and thus only read from a file. We let
    814            live cookies stay alive */
    815 
    816         /* Free the newcomer and get out of here! */
    817         freecookie(co);
    818         return NULL;
    819       }
    820 
    821       if(replace_old) {
    822         co->next = clist->next; /* get the next-pointer first */
    823 
    824         /* then free all the old pointers */
    825         free(clist->name);
    826         free(clist->value);
    827         free(clist->domain);
    828         free(clist->path);
    829         free(clist->spath);
    830         free(clist->expirestr);
    831         free(clist->version);
    832         free(clist->maxage);
    833 
    834         *clist = *co;  /* then store all the new data */
    835 
    836         free(co);   /* free the newly alloced memory */
    837         co = clist; /* point to the previous struct instead */
    838 
    839         /* We have replaced a cookie, now skip the rest of the list but
    840            make sure the 'lastc' pointer is properly set */
    841         do {
    842           lastc = clist;
    843           clist = clist->next;
    844         } while(clist);
    845         break;
    846       }
    847     }
    848     lastc = clist;
    849     clist = clist->next;
    850   }
    851 
    852   if(c->running)
    853     /* Only show this when NOT reading the cookies from a file */
    854     infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
    855           "expire %" CURL_FORMAT_CURL_OFF_T "\n",
    856           replace_old?"Replaced":"Added", co->name, co->value,
    857           co->domain, co->path, co->expires);
    858 
    859   if(!replace_old) {
    860     /* then make the last item point on this new one */
    861     if(lastc)
    862       lastc->next = co;
    863     else
    864       c->cookies = co;
    865     c->numcookies++; /* one more cookie in the jar */
    866   }
    867 
    868   return co;
    869 }
    870 
    871 /*****************************************************************************
    872  *
    873  * Curl_cookie_init()
    874  *
    875  * Inits a cookie struct to read data from a local file. This is always
    876  * called before any cookies are set. File may be NULL.
    877  *
    878  * If 'newsession' is TRUE, discard all "session cookies" on read from file.
    879  *
    880  * Returns NULL on out of memory. Invalid cookies are ignored.
    881  ****************************************************************************/
    882 struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
    883                                     const char *file,
    884                                     struct CookieInfo *inc,
    885                                     bool newsession)
    886 {
    887   struct CookieInfo *c;
    888   FILE *fp = NULL;
    889   bool fromfile=TRUE;
    890   char *line = NULL;
    891 
    892   if(NULL == inc) {
    893     /* we didn't get a struct, create one */
    894     c = calloc(1, sizeof(struct CookieInfo));
    895     if(!c)
    896       return NULL; /* failed to get memory */
    897     c->filename = strdup(file?file:"none"); /* copy the name just in case */
    898     if(!c->filename)
    899       goto fail; /* failed to get memory */
    900   }
    901   else {
    902     /* we got an already existing one, use that */
    903     c = inc;
    904   }
    905   c->running = FALSE; /* this is not running, this is init */
    906 
    907   if(file && strequal(file, "-")) {
    908     fp = stdin;
    909     fromfile=FALSE;
    910   }
    911   else if(file && !*file) {
    912     /* points to a "" string */
    913     fp = NULL;
    914   }
    915   else
    916     fp = file?fopen(file, FOPEN_READTEXT):NULL;
    917 
    918   c->newsession = newsession; /* new session? */
    919 
    920   if(fp) {
    921     char *lineptr;
    922     bool headerline;
    923 
    924     line = malloc(MAX_COOKIE_LINE);
    925     if(!line)
    926       goto fail;
    927     while(fgets(line, MAX_COOKIE_LINE, fp)) {
    928       if(checkprefix("Set-Cookie:", line)) {
    929         /* This is a cookie line, get it! */
    930         lineptr=&line[11];
    931         headerline=TRUE;
    932       }
    933       else {
    934         lineptr=line;
    935         headerline=FALSE;
    936       }
    937       while(*lineptr && ISBLANK(*lineptr))
    938         lineptr++;
    939 
    940       Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
    941     }
    942     free(line); /* free the line buffer */
    943 
    944     if(fromfile)
    945       fclose(fp);
    946   }
    947 
    948   c->running = TRUE;          /* now, we're running */
    949 
    950   return c;
    951 
    952 fail:
    953   free(line);
    954   if(!inc)
    955     /* Only clean up if we allocated it here, as the original could still be in
    956      * use by a share handle */
    957     Curl_cookie_cleanup(c);
    958   if(fromfile && fp)
    959     fclose(fp);
    960   return NULL; /* out of memory */
    961 }
    962 
    963 /* sort this so that the longest path gets before the shorter path */
    964 static int cookie_sort(const void *p1, const void *p2)
    965 {
    966   struct Cookie *c1 = *(struct Cookie **)p1;
    967   struct Cookie *c2 = *(struct Cookie **)p2;
    968   size_t l1, l2;
    969 
    970   /* 1 - compare cookie path lengths */
    971   l1 = c1->path ? strlen(c1->path) : 0;
    972   l2 = c2->path ? strlen(c2->path) : 0;
    973 
    974   if(l1 != l2)
    975     return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
    976 
    977   /* 2 - compare cookie domain lengths */
    978   l1 = c1->domain ? strlen(c1->domain) : 0;
    979   l2 = c2->domain ? strlen(c2->domain) : 0;
    980 
    981   if(l1 != l2)
    982     return (l2 > l1) ? 1 : -1 ;  /* avoid size_t <=> int conversions */
    983 
    984   /* 3 - compare cookie names */
    985   if(c1->name && c2->name)
    986     return strcmp(c1->name, c2->name);
    987 
    988   /* sorry, can't be more deterministic */
    989   return 0;
    990 }
    991 
    992 /*****************************************************************************
    993  *
    994  * Curl_cookie_getlist()
    995  *
    996  * For a given host and path, return a linked list of cookies that the
    997  * client should send to the server if used now. The secure boolean informs
    998  * the cookie if a secure connection is achieved or not.
    999  *
   1000  * It shall only return cookies that haven't expired.
   1001  *
   1002  ****************************************************************************/
   1003 
   1004 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
   1005                                    const char *host, const char *path,
   1006                                    bool secure)
   1007 {
   1008   struct Cookie *newco;
   1009   struct Cookie *co;
   1010   time_t now = time(NULL);
   1011   struct Cookie *mainco=NULL;
   1012   size_t matches = 0;
   1013   bool is_ip;
   1014 
   1015   if(!c || !c->cookies)
   1016     return NULL; /* no cookie struct or no cookies in the struct */
   1017 
   1018   /* at first, remove expired cookies */
   1019   remove_expired(c);
   1020 
   1021   /* check if host is an IP(v4|v6) address */
   1022   is_ip = isip(host);
   1023 
   1024   co = c->cookies;
   1025 
   1026   while(co) {
   1027     /* only process this cookie if it is not expired or had no expire
   1028        date AND that if the cookie requires we're secure we must only
   1029        continue if we are! */
   1030     if((!co->expires || (co->expires > now)) &&
   1031        (co->secure?secure:TRUE)) {
   1032 
   1033       /* now check if the domain is correct */
   1034       if(!co->domain ||
   1035          (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
   1036          ((!co->tailmatch || is_ip) && Curl_raw_equal(host, co->domain)) ) {
   1037         /* the right part of the host matches the domain stuff in the
   1038            cookie data */
   1039 
   1040         /* now check the left part of the path with the cookies path
   1041            requirement */
   1042         if(!co->spath || pathmatch(co->spath, path) ) {
   1043 
   1044           /* and now, we know this is a match and we should create an
   1045              entry for the return-linked-list */
   1046 
   1047           newco = malloc(sizeof(struct Cookie));
   1048           if(newco) {
   1049             /* first, copy the whole source cookie: */
   1050             memcpy(newco, co, sizeof(struct Cookie));
   1051 
   1052             /* then modify our next */
   1053             newco->next = mainco;
   1054 
   1055             /* point the main to us */
   1056             mainco = newco;
   1057 
   1058             matches++;
   1059           }
   1060           else {
   1061             fail:
   1062             /* failure, clear up the allocated chain and return NULL */
   1063             while(mainco) {
   1064               co = mainco->next;
   1065               free(mainco);
   1066               mainco = co;
   1067             }
   1068 
   1069             return NULL;
   1070           }
   1071         }
   1072       }
   1073     }
   1074     co = co->next;
   1075   }
   1076 
   1077   if(matches) {
   1078     /* Now we need to make sure that if there is a name appearing more than
   1079        once, the longest specified path version comes first. To make this
   1080        the swiftest way, we just sort them all based on path length. */
   1081     struct Cookie **array;
   1082     size_t i;
   1083 
   1084     /* alloc an array and store all cookie pointers */
   1085     array = malloc(sizeof(struct Cookie *) * matches);
   1086     if(!array)
   1087       goto fail;
   1088 
   1089     co = mainco;
   1090 
   1091     for(i=0; co; co = co->next)
   1092       array[i++] = co;
   1093 
   1094     /* now sort the cookie pointers in path length order */
   1095     qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
   1096 
   1097     /* remake the linked list order according to the new order */
   1098 
   1099     mainco = array[0]; /* start here */
   1100     for(i=0; i<matches-1; i++)
   1101       array[i]->next = array[i+1];
   1102     array[matches-1]->next = NULL; /* terminate the list */
   1103 
   1104     free(array); /* remove the temporary data again */
   1105   }
   1106 
   1107   return mainco; /* return the new list */
   1108 }
   1109 
   1110 /*****************************************************************************
   1111  *
   1112  * Curl_cookie_clearall()
   1113  *
   1114  * Clear all existing cookies and reset the counter.
   1115  *
   1116  ****************************************************************************/
   1117 void Curl_cookie_clearall(struct CookieInfo *cookies)
   1118 {
   1119   if(cookies) {
   1120     Curl_cookie_freelist(cookies->cookies, TRUE);
   1121     cookies->cookies = NULL;
   1122     cookies->numcookies = 0;
   1123   }
   1124 }
   1125 
   1126 /*****************************************************************************
   1127  *
   1128  * Curl_cookie_freelist()
   1129  *
   1130  * Free a list of cookies previously returned by Curl_cookie_getlist();
   1131  *
   1132  * The 'cookiestoo' argument tells this function whether to just free the
   1133  * list or actually also free all cookies within the list as well.
   1134  *
   1135  ****************************************************************************/
   1136 
   1137 void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo)
   1138 {
   1139   struct Cookie *next;
   1140   while(co) {
   1141     next = co->next;
   1142     if(cookiestoo)
   1143       freecookie(co);
   1144     else
   1145       free(co); /* we only free the struct since the "members" are all just
   1146                    pointed out in the main cookie list! */
   1147     co = next;
   1148   }
   1149 }
   1150 
   1151 
   1152 /*****************************************************************************
   1153  *
   1154  * Curl_cookie_clearsess()
   1155  *
   1156  * Free all session cookies in the cookies list.
   1157  *
   1158  ****************************************************************************/
   1159 void Curl_cookie_clearsess(struct CookieInfo *cookies)
   1160 {
   1161   struct Cookie *first, *curr, *next, *prev = NULL;
   1162 
   1163   if(!cookies || !cookies->cookies)
   1164     return;
   1165 
   1166   first = curr = prev = cookies->cookies;
   1167 
   1168   for(; curr; curr = next) {
   1169     next = curr->next;
   1170     if(!curr->expires) {
   1171       if(first == curr)
   1172         first = next;
   1173 
   1174       if(prev == curr)
   1175         prev = next;
   1176       else
   1177         prev->next = next;
   1178 
   1179       freecookie(curr);
   1180       cookies->numcookies--;
   1181     }
   1182     else
   1183       prev = curr;
   1184   }
   1185 
   1186   cookies->cookies = first;
   1187 }
   1188 
   1189 
   1190 /*****************************************************************************
   1191  *
   1192  * Curl_cookie_cleanup()
   1193  *
   1194  * Free a "cookie object" previous created with Curl_cookie_init().
   1195  *
   1196  ****************************************************************************/
   1197 void Curl_cookie_cleanup(struct CookieInfo *c)
   1198 {
   1199   if(c) {
   1200     free(c->filename);
   1201     Curl_cookie_freelist(c->cookies, TRUE);
   1202     free(c); /* free the base struct as well */
   1203   }
   1204 }
   1205 
   1206 /* get_netscape_format()
   1207  *
   1208  * Formats a string for Netscape output file, w/o a newline at the end.
   1209  *
   1210  * Function returns a char * to a formatted line. Has to be free()d
   1211 */
   1212 static char *get_netscape_format(const struct Cookie *co)
   1213 {
   1214   return aprintf(
   1215     "%s"     /* httponly preamble */
   1216     "%s%s\t" /* domain */
   1217     "%s\t"   /* tailmatch */
   1218     "%s\t"   /* path */
   1219     "%s\t"   /* secure */
   1220     "%" CURL_FORMAT_CURL_OFF_T "\t"   /* expires */
   1221     "%s\t"   /* name */
   1222     "%s",    /* value */
   1223     co->httponly?"#HttpOnly_":"",
   1224     /* Make sure all domains are prefixed with a dot if they allow
   1225        tailmatching. This is Mozilla-style. */
   1226     (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
   1227     co->domain?co->domain:"unknown",
   1228     co->tailmatch?"TRUE":"FALSE",
   1229     co->path?co->path:"/",
   1230     co->secure?"TRUE":"FALSE",
   1231     co->expires,
   1232     co->name,
   1233     co->value?co->value:"");
   1234 }
   1235 
   1236 /*
   1237  * cookie_output()
   1238  *
   1239  * Writes all internally known cookies to the specified file. Specify
   1240  * "-" as file name to write to stdout.
   1241  *
   1242  * The function returns non-zero on write failure.
   1243  */
   1244 static int cookie_output(struct CookieInfo *c, const char *dumphere)
   1245 {
   1246   struct Cookie *co;
   1247   FILE *out;
   1248   bool use_stdout=FALSE;
   1249 
   1250   if((NULL == c) || (0 == c->numcookies))
   1251     /* If there are no known cookies, we don't write or even create any
   1252        destination file */
   1253     return 0;
   1254 
   1255   /* at first, remove expired cookies */
   1256   remove_expired(c);
   1257 
   1258   if(strequal("-", dumphere)) {
   1259     /* use stdout */
   1260     out = stdout;
   1261     use_stdout=TRUE;
   1262   }
   1263   else {
   1264     out = fopen(dumphere, FOPEN_WRITETEXT);
   1265     if(!out)
   1266       return 1; /* failure */
   1267   }
   1268 
   1269   if(c) {
   1270     char *format_ptr;
   1271 
   1272     fputs("# Netscape HTTP Cookie File\n"
   1273           "# http://curl.haxx.se/docs/http-cookies.html\n"
   1274           "# This file was generated by libcurl! Edit at your own risk.\n\n",
   1275           out);
   1276     co = c->cookies;
   1277 
   1278     while(co) {
   1279       if(!co->domain)
   1280         continue;
   1281       format_ptr = get_netscape_format(co);
   1282       if(format_ptr == NULL) {
   1283         fprintf(out, "#\n# Fatal libcurl error\n");
   1284         if(!use_stdout)
   1285           fclose(out);
   1286         return 1;
   1287       }
   1288       fprintf(out, "%s\n", format_ptr);
   1289       free(format_ptr);
   1290       co=co->next;
   1291     }
   1292   }
   1293 
   1294   if(!use_stdout)
   1295     fclose(out);
   1296 
   1297   return 0;
   1298 }
   1299 
   1300 struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
   1301 {
   1302   struct curl_slist *list = NULL;
   1303   struct curl_slist *beg;
   1304   struct Cookie *c;
   1305   char *line;
   1306 
   1307   if((data->cookies == NULL) ||
   1308       (data->cookies->numcookies == 0))
   1309     return NULL;
   1310 
   1311   c = data->cookies->cookies;
   1312 
   1313   while(c) {
   1314     if(!c->domain)
   1315       continue;
   1316     line = get_netscape_format(c);
   1317     if(!line) {
   1318       curl_slist_free_all(list);
   1319       return NULL;
   1320     }
   1321     beg = Curl_slist_append_nodup(list, line);
   1322     if(!beg) {
   1323       free(line);
   1324       curl_slist_free_all(list);
   1325       return NULL;
   1326     }
   1327     list = beg;
   1328     c = c->next;
   1329   }
   1330 
   1331   return list;
   1332 }
   1333 
   1334 void Curl_flush_cookies(struct SessionHandle *data, int cleanup)
   1335 {
   1336   if(data->set.str[STRING_COOKIEJAR]) {
   1337     if(data->change.cookielist) {
   1338       /* If there is a list of cookie files to read, do it first so that
   1339          we have all the told files read before we write the new jar.
   1340          Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
   1341       Curl_cookie_loadfiles(data);
   1342     }
   1343 
   1344     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
   1345 
   1346     /* if we have a destination file for all the cookies to get dumped to */
   1347     if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
   1348       infof(data, "WARNING: failed to save cookies in %s\n",
   1349             data->set.str[STRING_COOKIEJAR]);
   1350   }
   1351   else {
   1352     if(cleanup && data->change.cookielist) {
   1353       /* since nothing is written, we can just free the list of cookie file
   1354          names */
   1355       curl_slist_free_all(data->change.cookielist); /* clean up list */
   1356       data->change.cookielist = NULL;
   1357     }
   1358     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
   1359   }
   1360 
   1361   if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
   1362     Curl_cookie_cleanup(data->cookies);
   1363   }
   1364   Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
   1365 }
   1366 
   1367 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
   1368