Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2019, 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 https://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 Curl_easy *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 Curl_easy *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 supersedes.
     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 
     83 #include "curl_setup.h"
     84 
     85 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
     86 
     87 #include "urldata.h"
     88 #include "cookie.h"
     89 #include "psl.h"
     90 #include "strtok.h"
     91 #include "sendf.h"
     92 #include "slist.h"
     93 #include "share.h"
     94 #include "strtoofft.h"
     95 #include "strcase.h"
     96 #include "curl_memrchr.h"
     97 #include "inet_pton.h"
     98 
     99 /* The last 3 #include files should be in this order */
    100 #include "curl_printf.h"
    101 #include "curl_memory.h"
    102 #include "memdebug.h"
    103 
    104 static void freecookie(struct Cookie *co)
    105 {
    106   free(co->expirestr);
    107   free(co->domain);
    108   free(co->path);
    109   free(co->spath);
    110   free(co->name);
    111   free(co->value);
    112   free(co->maxage);
    113   free(co->version);
    114   free(co);
    115 }
    116 
    117 static bool tailmatch(const char *cooke_domain, const char *hostname)
    118 {
    119   size_t cookie_domain_len = strlen(cooke_domain);
    120   size_t hostname_len = strlen(hostname);
    121 
    122   if(hostname_len < cookie_domain_len)
    123     return FALSE;
    124 
    125   if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len))
    126     return FALSE;
    127 
    128   /* A lead char of cookie_domain is not '.'.
    129      RFC6265 4.1.2.3. The Domain Attribute says:
    130        For example, if the value of the Domain attribute is
    131        "example.com", the user agent will include the cookie in the Cookie
    132        header when making HTTP requests to example.com, www.example.com, and
    133        www.corp.example.com.
    134    */
    135   if(hostname_len == cookie_domain_len)
    136     return TRUE;
    137   if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
    138     return TRUE;
    139   return FALSE;
    140 }
    141 
    142 /*
    143  * Return true if the given string is an IP(v4|v6) address.
    144  */
    145 static bool isip(const char *domain)
    146 {
    147   struct in_addr addr;
    148 #ifdef ENABLE_IPV6
    149   struct in6_addr addr6;
    150 #endif
    151 
    152   if(Curl_inet_pton(AF_INET, domain, &addr)
    153 #ifdef ENABLE_IPV6
    154      || Curl_inet_pton(AF_INET6, domain, &addr6)
    155 #endif
    156     ) {
    157     /* domain name given as IP address */
    158     return TRUE;
    159   }
    160 
    161   return FALSE;
    162 }
    163 
    164 /*
    165  * matching cookie path and url path
    166  * RFC6265 5.1.4 Paths and Path-Match
    167  */
    168 static bool pathmatch(const char *cookie_path, const char *request_uri)
    169 {
    170   size_t cookie_path_len;
    171   size_t uri_path_len;
    172   char *uri_path = NULL;
    173   char *pos;
    174   bool ret = FALSE;
    175 
    176   /* cookie_path must not have last '/' separator. ex: /sample */
    177   cookie_path_len = strlen(cookie_path);
    178   if(1 == cookie_path_len) {
    179     /* cookie_path must be '/' */
    180     return TRUE;
    181   }
    182 
    183   uri_path = strdup(request_uri);
    184   if(!uri_path)
    185     return FALSE;
    186   pos = strchr(uri_path, '?');
    187   if(pos)
    188     *pos = 0x0;
    189 
    190   /* #-fragments are already cut off! */
    191   if(0 == strlen(uri_path) || uri_path[0] != '/') {
    192     free(uri_path);
    193     uri_path = strdup("/");
    194     if(!uri_path)
    195       return FALSE;
    196   }
    197 
    198   /* here, RFC6265 5.1.4 says
    199      4. Output the characters of the uri-path from the first character up
    200         to, but not including, the right-most %x2F ("/").
    201      but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
    202      without redirect.
    203      Ignore this algorithm because /hoge is uri path for this case
    204      (uri path is not /).
    205    */
    206 
    207   uri_path_len = strlen(uri_path);
    208 
    209   if(uri_path_len < cookie_path_len) {
    210     ret = FALSE;
    211     goto pathmatched;
    212   }
    213 
    214   /* not using checkprefix() because matching should be case-sensitive */
    215   if(strncmp(cookie_path, uri_path, cookie_path_len)) {
    216     ret = FALSE;
    217     goto pathmatched;
    218   }
    219 
    220   /* The cookie-path and the uri-path are identical. */
    221   if(cookie_path_len == uri_path_len) {
    222     ret = TRUE;
    223     goto pathmatched;
    224   }
    225 
    226   /* here, cookie_path_len < uri_path_len */
    227   if(uri_path[cookie_path_len] == '/') {
    228     ret = TRUE;
    229     goto pathmatched;
    230   }
    231 
    232   ret = FALSE;
    233 
    234 pathmatched:
    235   free(uri_path);
    236   return ret;
    237 }
    238 
    239 /*
    240  * Return the top-level domain, for optimal hashing.
    241  */
    242 static const char *get_top_domain(const char * const domain, size_t *outlen)
    243 {
    244   size_t len;
    245   const char *first = NULL, *last;
    246 
    247   if(!domain)
    248     return NULL;
    249 
    250   len = strlen(domain);
    251   last = memrchr(domain, '.', len);
    252   if(last) {
    253     first = memrchr(domain, '.', (last - domain));
    254     if(first)
    255       len -= (++first - domain);
    256   }
    257 
    258   if(outlen)
    259     *outlen = len;
    260 
    261   return first? first: domain;
    262 }
    263 
    264 /*
    265  * A case-insensitive hash for the cookie domains.
    266  */
    267 static size_t cookie_hash_domain(const char *domain, const size_t len)
    268 {
    269   const char *end = domain + len;
    270   size_t h = 5381;
    271 
    272   while(domain < end) {
    273     h += h << 5;
    274     h ^= Curl_raw_toupper(*domain++);
    275   }
    276 
    277   return (h % COOKIE_HASH_SIZE);
    278 }
    279 
    280 /*
    281  * Hash this domain.
    282  */
    283 static size_t cookiehash(const char * const domain)
    284 {
    285   const char *top;
    286   size_t len;
    287 
    288   if(!domain || isip(domain))
    289     return 0;
    290 
    291   top = get_top_domain(domain, &len);
    292   return cookie_hash_domain(top, len);
    293 }
    294 
    295 /*
    296  * cookie path sanitize
    297  */
    298 static char *sanitize_cookie_path(const char *cookie_path)
    299 {
    300   size_t len;
    301   char *new_path = strdup(cookie_path);
    302   if(!new_path)
    303     return NULL;
    304 
    305   /* some stupid site sends path attribute with '"'. */
    306   len = strlen(new_path);
    307   if(new_path[0] == '\"') {
    308     memmove((void *)new_path, (const void *)(new_path + 1), len);
    309     len--;
    310   }
    311   if(len && (new_path[len - 1] == '\"')) {
    312     new_path[len - 1] = 0x0;
    313     len--;
    314   }
    315 
    316   /* RFC6265 5.2.4 The Path Attribute */
    317   if(new_path[0] != '/') {
    318     /* Let cookie-path be the default-path. */
    319     free(new_path);
    320     new_path = strdup("/");
    321     return new_path;
    322   }
    323 
    324   /* convert /hoge/ to /hoge */
    325   if(len && new_path[len - 1] == '/') {
    326     new_path[len - 1] = 0x0;
    327   }
    328 
    329   return new_path;
    330 }
    331 
    332 /*
    333  * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
    334  *
    335  * NOTE: OOM or cookie parsing failures are ignored.
    336  */
    337 void Curl_cookie_loadfiles(struct Curl_easy *data)
    338 {
    339   struct curl_slist *list = data->change.cookielist;
    340   if(list) {
    341     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
    342     while(list) {
    343       struct CookieInfo *newcookies = Curl_cookie_init(data,
    344                                         list->data,
    345                                         data->cookies,
    346                                         data->set.cookiesession);
    347       if(!newcookies)
    348         /* Failure may be due to OOM or a bad cookie; both are ignored
    349          * but only the first should be
    350          */
    351         infof(data, "ignoring failed cookie_init for %s\n", list->data);
    352       else
    353         data->cookies = newcookies;
    354       list = list->next;
    355     }
    356     curl_slist_free_all(data->change.cookielist); /* clean up list */
    357     data->change.cookielist = NULL; /* don't do this again! */
    358     Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
    359   }
    360 }
    361 
    362 /*
    363  * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL
    364  * that will be freed before the allocated string is stored there.
    365  *
    366  * It is meant to easily replace strdup()
    367  */
    368 static void strstore(char **str, const char *newstr)
    369 {
    370   free(*str);
    371   *str = strdup(newstr);
    372 }
    373 
    374 /*
    375  * remove_expired() removes expired cookies.
    376  */
    377 static void remove_expired(struct CookieInfo *cookies)
    378 {
    379   struct Cookie *co, *nx;
    380   curl_off_t now = (curl_off_t)time(NULL);
    381   unsigned int i;
    382 
    383   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
    384     struct Cookie *pv = NULL;
    385     co = cookies->cookies[i];
    386     while(co) {
    387       nx = co->next;
    388       if(co->expires && co->expires < now) {
    389         if(!pv) {
    390           cookies->cookies[i] = co->next;
    391         }
    392         else {
    393           pv->next = co->next;
    394         }
    395         cookies->numcookies--;
    396         freecookie(co);
    397       }
    398       else {
    399         pv = co;
    400       }
    401       co = nx;
    402     }
    403   }
    404 }
    405 
    406 /* Make sure domain contains a dot or is localhost. */
    407 static bool bad_domain(const char *domain)
    408 {
    409   return !strchr(domain, '.') && !strcasecompare(domain, "localhost");
    410 }
    411 
    412 /****************************************************************************
    413  *
    414  * Curl_cookie_add()
    415  *
    416  * Add a single cookie line to the cookie keeping object.
    417  *
    418  * Be aware that sometimes we get an IP-only host name, and that might also be
    419  * a numerical IPv6 address.
    420  *
    421  * Returns NULL on out of memory or invalid cookie. This is suboptimal,
    422  * as they should be treated separately.
    423  ***************************************************************************/
    424 
    425 struct Cookie *
    426 Curl_cookie_add(struct Curl_easy *data,
    427                 /* The 'data' pointer here may be NULL at times, and thus
    428                    must only be used very carefully for things that can deal
    429                    with data being NULL. Such as infof() and similar */
    430 
    431                 struct CookieInfo *c,
    432                 bool httpheader, /* TRUE if HTTP header-style line */
    433                 bool noexpire, /* if TRUE, skip remove_expired() */
    434                 char *lineptr,   /* first character of the line */
    435                 const char *domain, /* default domain */
    436                 const char *path,   /* full path used when this cookie is set,
    437                                        used to get default path for the cookie
    438                                        unless set */
    439                 bool secure)  /* TRUE if connection is over secure origin */
    440 {
    441   struct Cookie *clist;
    442   struct Cookie *co;
    443   struct Cookie *lastc = NULL;
    444   time_t now = time(NULL);
    445   bool replace_old = FALSE;
    446   bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
    447   size_t myhash;
    448 
    449 #ifdef CURL_DISABLE_VERBOSE_STRINGS
    450   (void)data;
    451 #endif
    452 
    453   /* First, alloc and init a new struct for it */
    454   co = calloc(1, sizeof(struct Cookie));
    455   if(!co)
    456     return NULL; /* bail out if we're this low on memory */
    457 
    458   if(httpheader) {
    459     /* This line was read off a HTTP-header */
    460     char name[MAX_NAME];
    461     char what[MAX_NAME];
    462     const char *ptr;
    463     const char *semiptr;
    464 
    465     size_t linelength = strlen(lineptr);
    466     if(linelength > MAX_COOKIE_LINE) {
    467       /* discard overly long lines at once */
    468       free(co);
    469       return NULL;
    470     }
    471 
    472     semiptr = strchr(lineptr, ';'); /* first, find a semicolon */
    473 
    474     while(*lineptr && ISBLANK(*lineptr))
    475       lineptr++;
    476 
    477     ptr = lineptr;
    478     do {
    479       /* we have a <what>=<this> pair or a stand-alone word here */
    480       name[0] = what[0] = 0; /* init the buffers */
    481       if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%"
    482                      MAX_NAME_TXT "[^;\r\n]",
    483                      name, what)) {
    484         /* Use strstore() below to properly deal with received cookie
    485            headers that have the same string property set more than once,
    486            and then we use the last one. */
    487         const char *whatptr;
    488         bool done = FALSE;
    489         bool sep;
    490         size_t len = strlen(what);
    491         size_t nlen = strlen(name);
    492         const char *endofn = &ptr[ nlen ];
    493 
    494         if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
    495            ((nlen + len) > MAX_NAME)) {
    496           /* too long individual name or contents, or too long combination of
    497              name + contents. Chrome and Firefox support 4095 or 4096 bytes
    498              combo. */
    499           freecookie(co);
    500           infof(data, "oversized cookie dropped, name/val %zu + %zu bytes\n",
    501                 nlen, len);
    502           return NULL;
    503         }
    504 
    505         /* name ends with a '=' ? */
    506         sep = (*endofn == '=')?TRUE:FALSE;
    507 
    508         if(nlen) {
    509           endofn--; /* move to the last character */
    510           if(ISBLANK(*endofn)) {
    511             /* skip trailing spaces in name */
    512             while(*endofn && ISBLANK(*endofn) && nlen) {
    513               endofn--;
    514               nlen--;
    515             }
    516             name[nlen] = 0; /* new end of name */
    517           }
    518         }
    519 
    520         /* Strip off trailing whitespace from the 'what' */
    521         while(len && ISBLANK(what[len-1])) {
    522           what[len-1] = 0;
    523           len--;
    524         }
    525 
    526         /* Skip leading whitespace from the 'what' */
    527         whatptr = what;
    528         while(*whatptr && ISBLANK(*whatptr))
    529           whatptr++;
    530 
    531         /*
    532          * Check if we have a reserved prefix set before anything else, as we
    533          * otherwise have to test for the prefix in both the cookie name and
    534          * "the rest". Prefixes must start with '__' and end with a '-', so
    535          * only test for names where that can possibly be true.
    536          */
    537         if(nlen > 3 && name[0] == '_' && name[1] == '_') {
    538           if(strncasecompare("__Secure-", name, 9))
    539             co->prefix |= COOKIE_PREFIX__SECURE;
    540           else if(strncasecompare("__Host-", name, 7))
    541             co->prefix |= COOKIE_PREFIX__HOST;
    542         }
    543 
    544         if(!co->name) {
    545           /* The very first name/value pair is the actual cookie name */
    546           if(!sep) {
    547             /* Bad name/value pair. */
    548             badcookie = TRUE;
    549             break;
    550           }
    551           co->name = strdup(name);
    552           co->value = strdup(whatptr);
    553           done = TRUE;
    554           if(!co->name || !co->value) {
    555             badcookie = TRUE;
    556             break;
    557           }
    558         }
    559         else if(!len) {
    560           /* this was a "<name>=" with no content, and we must allow
    561              'secure' and 'httponly' specified this weirdly */
    562           done = TRUE;
    563           /*
    564            * secure cookies are only allowed to be set when the connection is
    565            * using a secure protocol, or when the cookie is being set by
    566            * reading from file
    567            */
    568           if(strcasecompare("secure", name)) {
    569             if(secure || !c->running) {
    570               co->secure = TRUE;
    571             }
    572             else {
    573               badcookie = TRUE;
    574               break;
    575             }
    576           }
    577           else if(strcasecompare("httponly", name))
    578             co->httponly = TRUE;
    579           else if(sep)
    580             /* there was a '=' so we're not done parsing this field */
    581             done = FALSE;
    582         }
    583         if(done)
    584           ;
    585         else if(strcasecompare("path", name)) {
    586           strstore(&co->path, whatptr);
    587           if(!co->path) {
    588             badcookie = TRUE; /* out of memory bad */
    589             break;
    590           }
    591           free(co->spath); /* if this is set again */
    592           co->spath = sanitize_cookie_path(co->path);
    593           if(!co->spath) {
    594             badcookie = TRUE; /* out of memory bad */
    595             break;
    596           }
    597         }
    598         else if(strcasecompare("domain", name)) {
    599           bool is_ip;
    600 
    601           /* Now, we make sure that our host is within the given domain,
    602              or the given domain is not valid and thus cannot be set. */
    603 
    604           if('.' == whatptr[0])
    605             whatptr++; /* ignore preceding dot */
    606 
    607 #ifndef USE_LIBPSL
    608           /*
    609            * Without PSL we don't know when the incoming cookie is set on a
    610            * TLD or otherwise "protected" suffix. To reduce risk, we require a
    611            * dot OR the exact host name being "localhost".
    612            */
    613           if(bad_domain(whatptr))
    614             domain = ":";
    615 #endif
    616 
    617           is_ip = isip(domain ? domain : whatptr);
    618 
    619           if(!domain
    620              || (is_ip && !strcmp(whatptr, domain))
    621              || (!is_ip && tailmatch(whatptr, domain))) {
    622             strstore(&co->domain, whatptr);
    623             if(!co->domain) {
    624               badcookie = TRUE;
    625               break;
    626             }
    627             if(!is_ip)
    628               co->tailmatch = TRUE; /* we always do that if the domain name was
    629                                        given */
    630           }
    631           else {
    632             /* we did not get a tailmatch and then the attempted set domain
    633                is not a domain to which the current host belongs. Mark as
    634                bad. */
    635             badcookie = TRUE;
    636             infof(data, "skipped cookie with bad tailmatch domain: %s\n",
    637                   whatptr);
    638           }
    639         }
    640         else if(strcasecompare("version", name)) {
    641           strstore(&co->version, whatptr);
    642           if(!co->version) {
    643             badcookie = TRUE;
    644             break;
    645           }
    646         }
    647         else if(strcasecompare("max-age", name)) {
    648           /* Defined in RFC2109:
    649 
    650              Optional.  The Max-Age attribute defines the lifetime of the
    651              cookie, in seconds.  The delta-seconds value is a decimal non-
    652              negative integer.  After delta-seconds seconds elapse, the
    653              client should discard the cookie.  A value of zero means the
    654              cookie should be discarded immediately.
    655 
    656           */
    657           strstore(&co->maxage, whatptr);
    658           if(!co->maxage) {
    659             badcookie = TRUE;
    660             break;
    661           }
    662         }
    663         else if(strcasecompare("expires", name)) {
    664           strstore(&co->expirestr, whatptr);
    665           if(!co->expirestr) {
    666             badcookie = TRUE;
    667             break;
    668           }
    669         }
    670         /*
    671           else this is the second (or more) name we don't know
    672           about! */
    673       }
    674       else {
    675         /* this is an "illegal" <what>=<this> pair */
    676       }
    677 
    678       if(!semiptr || !*semiptr) {
    679         /* we already know there are no more cookies */
    680         semiptr = NULL;
    681         continue;
    682       }
    683 
    684       ptr = semiptr + 1;
    685       while(*ptr && ISBLANK(*ptr))
    686         ptr++;
    687       semiptr = strchr(ptr, ';'); /* now, find the next semicolon */
    688 
    689       if(!semiptr && *ptr)
    690         /* There are no more semicolons, but there's a final name=value pair
    691            coming up */
    692         semiptr = strchr(ptr, '\0');
    693     } while(semiptr);
    694 
    695     if(co->maxage) {
    696       CURLofft offt;
    697       offt = curlx_strtoofft((*co->maxage == '\"')?
    698                              &co->maxage[1]:&co->maxage[0], NULL, 10,
    699                              &co->expires);
    700       if(offt == CURL_OFFT_FLOW)
    701         /* overflow, used max value */
    702         co->expires = CURL_OFF_T_MAX;
    703       else if(!offt) {
    704         if(!co->expires)
    705           /* already expired */
    706           co->expires = 1;
    707         else if(CURL_OFF_T_MAX - now < co->expires)
    708           /* would overflow */
    709           co->expires = CURL_OFF_T_MAX;
    710         else
    711           co->expires += now;
    712       }
    713     }
    714     else if(co->expirestr) {
    715       /* Note that if the date couldn't get parsed for whatever reason,
    716          the cookie will be treated as a session cookie */
    717       co->expires = curl_getdate(co->expirestr, NULL);
    718 
    719       /* Session cookies have expires set to 0 so if we get that back
    720          from the date parser let's add a second to make it a
    721          non-session cookie */
    722       if(co->expires == 0)
    723         co->expires = 1;
    724       else if(co->expires < 0)
    725         co->expires = 0;
    726     }
    727 
    728     if(!badcookie && !co->domain) {
    729       if(domain) {
    730         /* no domain was given in the header line, set the default */
    731         co->domain = strdup(domain);
    732         if(!co->domain)
    733           badcookie = TRUE;
    734       }
    735     }
    736 
    737     if(!badcookie && !co->path && path) {
    738       /* No path was given in the header line, set the default.
    739          Note that the passed-in path to this function MAY have a '?' and
    740          following part that MUST not be stored as part of the path. */
    741       char *queryp = strchr(path, '?');
    742 
    743       /* queryp is where the interesting part of the path ends, so now we
    744          want to the find the last */
    745       char *endslash;
    746       if(!queryp)
    747         endslash = strrchr(path, '/');
    748       else
    749         endslash = memrchr(path, '/', (queryp - path));
    750       if(endslash) {
    751         size_t pathlen = (endslash-path + 1); /* include end slash */
    752         co->path = malloc(pathlen + 1); /* one extra for the zero byte */
    753         if(co->path) {
    754           memcpy(co->path, path, pathlen);
    755           co->path[pathlen] = 0; /* zero terminate */
    756           co->spath = sanitize_cookie_path(co->path);
    757           if(!co->spath)
    758             badcookie = TRUE; /* out of memory bad */
    759         }
    760         else
    761           badcookie = TRUE;
    762       }
    763     }
    764 
    765     if(badcookie || !co->name) {
    766       /* we didn't get a cookie name or a bad one,
    767          this is an illegal line, bail out */
    768       freecookie(co);
    769       return NULL;
    770     }
    771 
    772   }
    773   else {
    774     /* This line is NOT a HTTP header style line, we do offer support for
    775        reading the odd netscape cookies-file format here */
    776     char *ptr;
    777     char *firstptr;
    778     char *tok_buf = NULL;
    779     int fields;
    780 
    781     /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
    782        marked with httpOnly after the domain name are not accessible
    783        from javascripts, but since curl does not operate at javascript
    784        level, we include them anyway. In Firefox's cookie files, these
    785        lines are preceded with #HttpOnly_ and then everything is
    786        as usual, so we skip 10 characters of the line..
    787     */
    788     if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
    789       lineptr += 10;
    790       co->httponly = TRUE;
    791     }
    792 
    793     if(lineptr[0]=='#') {
    794       /* don't even try the comments */
    795       free(co);
    796       return NULL;
    797     }
    798     /* strip off the possible end-of-line characters */
    799     ptr = strchr(lineptr, '\r');
    800     if(ptr)
    801       *ptr = 0; /* clear it */
    802     ptr = strchr(lineptr, '\n');
    803     if(ptr)
    804       *ptr = 0; /* clear it */
    805 
    806     firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
    807 
    808     /* Now loop through the fields and init the struct we already have
    809        allocated */
    810     for(ptr = firstptr, fields = 0; ptr && !badcookie;
    811         ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
    812       switch(fields) {
    813       case 0:
    814         if(ptr[0]=='.') /* skip preceding dots */
    815           ptr++;
    816         co->domain = strdup(ptr);
    817         if(!co->domain)
    818           badcookie = TRUE;
    819         break;
    820       case 1:
    821         /* This field got its explanation on the 23rd of May 2001 by
    822            Andrs Garca:
    823 
    824            flag: A TRUE/FALSE value indicating if all machines within a given
    825            domain can access the variable. This value is set automatically by
    826            the browser, depending on the value you set for the domain.
    827 
    828            As far as I can see, it is set to true when the cookie says
    829            .domain.com and to false when the domain is complete www.domain.com
    830         */
    831         co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
    832         break;
    833       case 2:
    834         /* It turns out, that sometimes the file format allows the path
    835            field to remain not filled in, we try to detect this and work
    836            around it! Andrs Garca made us aware of this... */
    837         if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
    838           /* only if the path doesn't look like a boolean option! */
    839           co->path = strdup(ptr);
    840           if(!co->path)
    841             badcookie = TRUE;
    842           else {
    843             co->spath = sanitize_cookie_path(co->path);
    844             if(!co->spath) {
    845               badcookie = TRUE; /* out of memory bad */
    846             }
    847           }
    848           break;
    849         }
    850         /* this doesn't look like a path, make one up! */
    851         co->path = strdup("/");
    852         if(!co->path)
    853           badcookie = TRUE;
    854         co->spath = strdup("/");
    855         if(!co->spath)
    856           badcookie = TRUE;
    857         fields++; /* add a field and fall down to secure */
    858         /* FALLTHROUGH */
    859       case 3:
    860         co->secure = FALSE;
    861         if(strcasecompare(ptr, "TRUE")) {
    862           if(secure || c->running)
    863             co->secure = TRUE;
    864           else
    865             badcookie = TRUE;
    866         }
    867         break;
    868       case 4:
    869         if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
    870           badcookie = TRUE;
    871         break;
    872       case 5:
    873         co->name = strdup(ptr);
    874         if(!co->name)
    875           badcookie = TRUE;
    876         /* For Netscape file format cookies we check prefix on the name */
    877         if(strncasecompare("__Secure-", co->name, 9))
    878           co->prefix |= COOKIE_PREFIX__SECURE;
    879         else if(strncasecompare("__Host-", co->name, 7))
    880           co->prefix |= COOKIE_PREFIX__HOST;
    881         break;
    882       case 6:
    883         co->value = strdup(ptr);
    884         if(!co->value)
    885           badcookie = TRUE;
    886         break;
    887       }
    888     }
    889     if(6 == fields) {
    890       /* we got a cookie with blank contents, fix it */
    891       co->value = strdup("");
    892       if(!co->value)
    893         badcookie = TRUE;
    894       else
    895         fields++;
    896     }
    897 
    898     if(!badcookie && (7 != fields))
    899       /* we did not find the sufficient number of fields */
    900       badcookie = TRUE;
    901 
    902     if(badcookie) {
    903       freecookie(co);
    904       return NULL;
    905     }
    906 
    907   }
    908 
    909   if(co->prefix & COOKIE_PREFIX__SECURE) {
    910     /* The __Secure- prefix only requires that the cookie be set secure */
    911     if(!co->secure) {
    912       freecookie(co);
    913       return NULL;
    914     }
    915   }
    916   if(co->prefix & COOKIE_PREFIX__HOST) {
    917     /*
    918      * The __Host- prefix requires the cookie to be secure, have a "/" path
    919      * and not have a domain set.
    920      */
    921     if(co->secure && co->path && strcmp(co->path, "/") == 0 && !co->tailmatch)
    922       ;
    923     else {
    924       freecookie(co);
    925       return NULL;
    926     }
    927   }
    928 
    929   if(!c->running &&    /* read from a file */
    930      c->newsession &&  /* clean session cookies */
    931      !co->expires) {   /* this is a session cookie since it doesn't expire! */
    932     freecookie(co);
    933     return NULL;
    934   }
    935 
    936   co->livecookie = c->running;
    937   co->creationtime = ++c->lastct;
    938 
    939   /* now, we have parsed the incoming line, we must now check if this
    940      supersedes an already existing cookie, which it may if the previous have
    941      the same domain and path as this */
    942 
    943   /* at first, remove expired cookies */
    944   if(!noexpire)
    945     remove_expired(c);
    946 
    947 #ifdef USE_LIBPSL
    948   /* Check if the domain is a Public Suffix and if yes, ignore the cookie. */
    949   if(domain && co->domain && !isip(co->domain)) {
    950     const psl_ctx_t *psl = Curl_psl_use(data);
    951     int acceptable;
    952 
    953     if(psl) {
    954       acceptable = psl_is_cookie_domain_acceptable(psl, domain, co->domain);
    955       Curl_psl_release(data);
    956     }
    957     else
    958       acceptable = !bad_domain(domain);
    959 
    960     if(!acceptable) {
    961       infof(data, "cookie '%s' dropped, domain '%s' must not "
    962                   "set cookies for '%s'\n", co->name, domain, co->domain);
    963       freecookie(co);
    964       return NULL;
    965     }
    966   }
    967 #endif
    968 
    969   myhash = cookiehash(co->domain);
    970   clist = c->cookies[myhash];
    971   replace_old = FALSE;
    972   while(clist) {
    973     if(strcasecompare(clist->name, co->name)) {
    974       /* the names are identical */
    975 
    976       if(clist->domain && co->domain) {
    977         if(strcasecompare(clist->domain, co->domain) &&
    978           (clist->tailmatch == co->tailmatch))
    979           /* The domains are identical */
    980           replace_old = TRUE;
    981       }
    982       else if(!clist->domain && !co->domain)
    983         replace_old = TRUE;
    984 
    985       if(replace_old) {
    986         /* the domains were identical */
    987 
    988         if(clist->spath && co->spath) {
    989           if(clist->secure && !co->secure && !secure) {
    990             size_t cllen;
    991             const char *sep;
    992 
    993             /*
    994              * A non-secure cookie may not overlay an existing secure cookie.
    995              * For an existing cookie "a" with path "/login", refuse a new
    996              * cookie "a" with for example path "/login/en", while the path
    997              * "/loginhelper" is ok.
    998              */
    999 
   1000             sep = strchr(clist->spath + 1, '/');
   1001 
   1002             if(sep)
   1003               cllen = sep - clist->spath;
   1004             else
   1005               cllen = strlen(clist->spath);
   1006 
   1007             if(strncasecompare(clist->spath, co->spath, cllen)) {
   1008               freecookie(co);
   1009               return NULL;
   1010             }
   1011           }
   1012           else if(strcasecompare(clist->spath, co->spath))
   1013             replace_old = TRUE;
   1014           else
   1015             replace_old = FALSE;
   1016         }
   1017         else if(!clist->spath && !co->spath)
   1018           replace_old = TRUE;
   1019         else
   1020           replace_old = FALSE;
   1021 
   1022       }
   1023 
   1024       if(replace_old && !co->livecookie && clist->livecookie) {
   1025         /* Both cookies matched fine, except that the already present
   1026            cookie is "live", which means it was set from a header, while
   1027            the new one isn't "live" and thus only read from a file. We let
   1028            live cookies stay alive */
   1029 
   1030         /* Free the newcomer and get out of here! */
   1031         freecookie(co);
   1032         return NULL;
   1033       }
   1034 
   1035       if(replace_old) {
   1036         co->next = clist->next; /* get the next-pointer first */
   1037 
   1038         /* when replacing, creationtime is kept from old */
   1039         co->creationtime = clist->creationtime;
   1040 
   1041         /* then free all the old pointers */
   1042         free(clist->name);
   1043         free(clist->value);
   1044         free(clist->domain);
   1045         free(clist->path);
   1046         free(clist->spath);
   1047         free(clist->expirestr);
   1048         free(clist->version);
   1049         free(clist->maxage);
   1050 
   1051         *clist = *co;  /* then store all the new data */
   1052 
   1053         free(co);   /* free the newly alloced memory */
   1054         co = clist; /* point to the previous struct instead */
   1055 
   1056         /* We have replaced a cookie, now skip the rest of the list but
   1057            make sure the 'lastc' pointer is properly set */
   1058         do {
   1059           lastc = clist;
   1060           clist = clist->next;
   1061         } while(clist);
   1062         break;
   1063       }
   1064     }
   1065     lastc = clist;
   1066     clist = clist->next;
   1067   }
   1068 
   1069   if(c->running)
   1070     /* Only show this when NOT reading the cookies from a file */
   1071     infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
   1072           "expire %" CURL_FORMAT_CURL_OFF_T "\n",
   1073           replace_old?"Replaced":"Added", co->name, co->value,
   1074           co->domain, co->path, co->expires);
   1075 
   1076   if(!replace_old) {
   1077     /* then make the last item point on this new one */
   1078     if(lastc)
   1079       lastc->next = co;
   1080     else
   1081       c->cookies[myhash] = co;
   1082     c->numcookies++; /* one more cookie in the jar */
   1083   }
   1084 
   1085   return co;
   1086 }
   1087 
   1088 /*
   1089  * get_line() makes sure to only return complete whole lines that fit in 'len'
   1090  * bytes and end with a newline.
   1091  */
   1092 char *Curl_get_line(char *buf, int len, FILE *input)
   1093 {
   1094   bool partial = FALSE;
   1095   while(1) {
   1096     char *b = fgets(buf, len, input);
   1097     if(b) {
   1098       size_t rlen = strlen(b);
   1099       if(rlen && (b[rlen-1] == '\n')) {
   1100         if(partial) {
   1101           partial = FALSE;
   1102           continue;
   1103         }
   1104         return b;
   1105       }
   1106       /* read a partial, discard the next piece that ends with newline */
   1107       partial = TRUE;
   1108     }
   1109     else
   1110       break;
   1111   }
   1112   return NULL;
   1113 }
   1114 
   1115 
   1116 /*****************************************************************************
   1117  *
   1118  * Curl_cookie_init()
   1119  *
   1120  * Inits a cookie struct to read data from a local file. This is always
   1121  * called before any cookies are set. File may be NULL.
   1122  *
   1123  * If 'newsession' is TRUE, discard all "session cookies" on read from file.
   1124  *
   1125  * Returns NULL on out of memory. Invalid cookies are ignored.
   1126  ****************************************************************************/
   1127 struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
   1128                                     const char *file,
   1129                                     struct CookieInfo *inc,
   1130                                     bool newsession)
   1131 {
   1132   struct CookieInfo *c;
   1133   FILE *fp = NULL;
   1134   bool fromfile = TRUE;
   1135   char *line = NULL;
   1136 
   1137   if(NULL == inc) {
   1138     /* we didn't get a struct, create one */
   1139     c = calloc(1, sizeof(struct CookieInfo));
   1140     if(!c)
   1141       return NULL; /* failed to get memory */
   1142     c->filename = strdup(file?file:"none"); /* copy the name just in case */
   1143     if(!c->filename)
   1144       goto fail; /* failed to get memory */
   1145   }
   1146   else {
   1147     /* we got an already existing one, use that */
   1148     c = inc;
   1149   }
   1150   c->running = FALSE; /* this is not running, this is init */
   1151 
   1152   if(file && !strcmp(file, "-")) {
   1153     fp = stdin;
   1154     fromfile = FALSE;
   1155   }
   1156   else if(file && !*file) {
   1157     /* points to a "" string */
   1158     fp = NULL;
   1159   }
   1160   else
   1161     fp = file?fopen(file, FOPEN_READTEXT):NULL;
   1162 
   1163   c->newsession = newsession; /* new session? */
   1164 
   1165   if(fp) {
   1166     char *lineptr;
   1167     bool headerline;
   1168 
   1169     line = malloc(MAX_COOKIE_LINE);
   1170     if(!line)
   1171       goto fail;
   1172     while(Curl_get_line(line, MAX_COOKIE_LINE, fp)) {
   1173       if(checkprefix("Set-Cookie:", line)) {
   1174         /* This is a cookie line, get it! */
   1175         lineptr = &line[11];
   1176         headerline = TRUE;
   1177       }
   1178       else {
   1179         lineptr = line;
   1180         headerline = FALSE;
   1181       }
   1182       while(*lineptr && ISBLANK(*lineptr))
   1183         lineptr++;
   1184 
   1185       Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
   1186     }
   1187     free(line); /* free the line buffer */
   1188     remove_expired(c); /* run this once, not on every cookie */
   1189 
   1190     if(fromfile)
   1191       fclose(fp);
   1192   }
   1193 
   1194   c->running = TRUE;          /* now, we're running */
   1195 
   1196   return c;
   1197 
   1198 fail:
   1199   free(line);
   1200   if(!inc)
   1201     /* Only clean up if we allocated it here, as the original could still be in
   1202      * use by a share handle */
   1203     Curl_cookie_cleanup(c);
   1204   if(fromfile && fp)
   1205     fclose(fp);
   1206   return NULL; /* out of memory */
   1207 }
   1208 
   1209 /* sort this so that the longest path gets before the shorter path */
   1210 static int cookie_sort(const void *p1, const void *p2)
   1211 {
   1212   struct Cookie *c1 = *(struct Cookie **)p1;
   1213   struct Cookie *c2 = *(struct Cookie **)p2;
   1214   size_t l1, l2;
   1215 
   1216   /* 1 - compare cookie path lengths */
   1217   l1 = c1->path ? strlen(c1->path) : 0;
   1218   l2 = c2->path ? strlen(c2->path) : 0;
   1219 
   1220   if(l1 != l2)
   1221     return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
   1222 
   1223   /* 2 - compare cookie domain lengths */
   1224   l1 = c1->domain ? strlen(c1->domain) : 0;
   1225   l2 = c2->domain ? strlen(c2->domain) : 0;
   1226 
   1227   if(l1 != l2)
   1228     return (l2 > l1) ? 1 : -1 ;  /* avoid size_t <=> int conversions */
   1229 
   1230   /* 3 - compare cookie name lengths */
   1231   l1 = c1->name ? strlen(c1->name) : 0;
   1232   l2 = c2->name ? strlen(c2->name) : 0;
   1233 
   1234   if(l1 != l2)
   1235     return (l2 > l1) ? 1 : -1;
   1236 
   1237   /* 4 - compare cookie creation time */
   1238   return (c2->creationtime > c1->creationtime) ? 1 : -1;
   1239 }
   1240 
   1241 /* sort cookies only according to creation time */
   1242 static int cookie_sort_ct(const void *p1, const void *p2)
   1243 {
   1244   struct Cookie *c1 = *(struct Cookie **)p1;
   1245   struct Cookie *c2 = *(struct Cookie **)p2;
   1246 
   1247   return (c2->creationtime > c1->creationtime) ? 1 : -1;
   1248 }
   1249 
   1250 #define CLONE(field)                     \
   1251   do {                                   \
   1252     if(src->field) {                     \
   1253       d->field = strdup(src->field);     \
   1254       if(!d->field)                      \
   1255         goto fail;                       \
   1256     }                                    \
   1257   } while(0)
   1258 
   1259 static struct Cookie *dup_cookie(struct Cookie *src)
   1260 {
   1261   struct Cookie *d = calloc(sizeof(struct Cookie), 1);
   1262   if(d) {
   1263     CLONE(expirestr);
   1264     CLONE(domain);
   1265     CLONE(path);
   1266     CLONE(spath);
   1267     CLONE(name);
   1268     CLONE(value);
   1269     CLONE(maxage);
   1270     CLONE(version);
   1271     d->expires = src->expires;
   1272     d->tailmatch = src->tailmatch;
   1273     d->secure = src->secure;
   1274     d->livecookie = src->livecookie;
   1275     d->httponly = src->httponly;
   1276     d->creationtime = src->creationtime;
   1277   }
   1278   return d;
   1279 
   1280   fail:
   1281   freecookie(d);
   1282   return NULL;
   1283 }
   1284 
   1285 /*****************************************************************************
   1286  *
   1287  * Curl_cookie_getlist()
   1288  *
   1289  * For a given host and path, return a linked list of cookies that the
   1290  * client should send to the server if used now. The secure boolean informs
   1291  * the cookie if a secure connection is achieved or not.
   1292  *
   1293  * It shall only return cookies that haven't expired.
   1294  *
   1295  ****************************************************************************/
   1296 
   1297 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
   1298                                    const char *host, const char *path,
   1299                                    bool secure)
   1300 {
   1301   struct Cookie *newco;
   1302   struct Cookie *co;
   1303   struct Cookie *mainco = NULL;
   1304   size_t matches = 0;
   1305   bool is_ip;
   1306   const size_t myhash = cookiehash(host);
   1307 
   1308   if(!c || !c->cookies[myhash])
   1309     return NULL; /* no cookie struct or no cookies in the struct */
   1310 
   1311   /* at first, remove expired cookies */
   1312   remove_expired(c);
   1313 
   1314   /* check if host is an IP(v4|v6) address */
   1315   is_ip = isip(host);
   1316 
   1317   co = c->cookies[myhash];
   1318 
   1319   while(co) {
   1320     /* if the cookie requires we're secure we must only continue if we are! */
   1321     if(co->secure?secure:TRUE) {
   1322 
   1323       /* now check if the domain is correct */
   1324       if(!co->domain ||
   1325          (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
   1326          ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
   1327         /* the right part of the host matches the domain stuff in the
   1328            cookie data */
   1329 
   1330         /* now check the left part of the path with the cookies path
   1331            requirement */
   1332         if(!co->spath || pathmatch(co->spath, path) ) {
   1333 
   1334           /* and now, we know this is a match and we should create an
   1335              entry for the return-linked-list */
   1336 
   1337           newco = dup_cookie(co);
   1338           if(newco) {
   1339             /* then modify our next */
   1340             newco->next = mainco;
   1341 
   1342             /* point the main to us */
   1343             mainco = newco;
   1344 
   1345             matches++;
   1346           }
   1347           else
   1348             goto fail;
   1349         }
   1350       }
   1351     }
   1352     co = co->next;
   1353   }
   1354 
   1355   if(matches) {
   1356     /* Now we need to make sure that if there is a name appearing more than
   1357        once, the longest specified path version comes first. To make this
   1358        the swiftest way, we just sort them all based on path length. */
   1359     struct Cookie **array;
   1360     size_t i;
   1361 
   1362     /* alloc an array and store all cookie pointers */
   1363     array = malloc(sizeof(struct Cookie *) * matches);
   1364     if(!array)
   1365       goto fail;
   1366 
   1367     co = mainco;
   1368 
   1369     for(i = 0; co; co = co->next)
   1370       array[i++] = co;
   1371 
   1372     /* now sort the cookie pointers in path length order */
   1373     qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
   1374 
   1375     /* remake the linked list order according to the new order */
   1376 
   1377     mainco = array[0]; /* start here */
   1378     for(i = 0; i<matches-1; i++)
   1379       array[i]->next = array[i + 1];
   1380     array[matches-1]->next = NULL; /* terminate the list */
   1381 
   1382     free(array); /* remove the temporary data again */
   1383   }
   1384 
   1385   return mainco; /* return the new list */
   1386 
   1387 fail:
   1388   /* failure, clear up the allocated chain and return NULL */
   1389   Curl_cookie_freelist(mainco);
   1390   return NULL;
   1391 }
   1392 
   1393 /*****************************************************************************
   1394  *
   1395  * Curl_cookie_clearall()
   1396  *
   1397  * Clear all existing cookies and reset the counter.
   1398  *
   1399  ****************************************************************************/
   1400 void Curl_cookie_clearall(struct CookieInfo *cookies)
   1401 {
   1402   if(cookies) {
   1403     unsigned int i;
   1404     for(i = 0; i < COOKIE_HASH_SIZE; i++) {
   1405       Curl_cookie_freelist(cookies->cookies[i]);
   1406       cookies->cookies[i] = NULL;
   1407     }
   1408     cookies->numcookies = 0;
   1409   }
   1410 }
   1411 
   1412 /*****************************************************************************
   1413  *
   1414  * Curl_cookie_freelist()
   1415  *
   1416  * Free a list of cookies previously returned by Curl_cookie_getlist();
   1417  *
   1418  ****************************************************************************/
   1419 
   1420 void Curl_cookie_freelist(struct Cookie *co)
   1421 {
   1422   struct Cookie *next;
   1423   while(co) {
   1424     next = co->next;
   1425     freecookie(co);
   1426     co = next;
   1427   }
   1428 }
   1429 
   1430 
   1431 /*****************************************************************************
   1432  *
   1433  * Curl_cookie_clearsess()
   1434  *
   1435  * Free all session cookies in the cookies list.
   1436  *
   1437  ****************************************************************************/
   1438 void Curl_cookie_clearsess(struct CookieInfo *cookies)
   1439 {
   1440   struct Cookie *first, *curr, *next, *prev = NULL;
   1441   unsigned int i;
   1442 
   1443   if(!cookies)
   1444     return;
   1445 
   1446   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
   1447     if(!cookies->cookies[i])
   1448       continue;
   1449 
   1450     first = curr = prev = cookies->cookies[i];
   1451 
   1452     for(; curr; curr = next) {
   1453       next = curr->next;
   1454       if(!curr->expires) {
   1455         if(first == curr)
   1456           first = next;
   1457 
   1458         if(prev == curr)
   1459           prev = next;
   1460         else
   1461           prev->next = next;
   1462 
   1463         freecookie(curr);
   1464         cookies->numcookies--;
   1465       }
   1466       else
   1467         prev = curr;
   1468     }
   1469 
   1470     cookies->cookies[i] = first;
   1471   }
   1472 }
   1473 
   1474 
   1475 /*****************************************************************************
   1476  *
   1477  * Curl_cookie_cleanup()
   1478  *
   1479  * Free a "cookie object" previous created with Curl_cookie_init().
   1480  *
   1481  ****************************************************************************/
   1482 void Curl_cookie_cleanup(struct CookieInfo *c)
   1483 {
   1484   if(c) {
   1485     unsigned int i;
   1486     free(c->filename);
   1487     for(i = 0; i < COOKIE_HASH_SIZE; i++)
   1488       Curl_cookie_freelist(c->cookies[i]);
   1489     free(c); /* free the base struct as well */
   1490   }
   1491 }
   1492 
   1493 /* get_netscape_format()
   1494  *
   1495  * Formats a string for Netscape output file, w/o a newline at the end.
   1496  *
   1497  * Function returns a char * to a formatted line. Has to be free()d
   1498 */
   1499 static char *get_netscape_format(const struct Cookie *co)
   1500 {
   1501   return aprintf(
   1502     "%s"     /* httponly preamble */
   1503     "%s%s\t" /* domain */
   1504     "%s\t"   /* tailmatch */
   1505     "%s\t"   /* path */
   1506     "%s\t"   /* secure */
   1507     "%" CURL_FORMAT_CURL_OFF_T "\t"   /* expires */
   1508     "%s\t"   /* name */
   1509     "%s",    /* value */
   1510     co->httponly?"#HttpOnly_":"",
   1511     /* Make sure all domains are prefixed with a dot if they allow
   1512        tailmatching. This is Mozilla-style. */
   1513     (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
   1514     co->domain?co->domain:"unknown",
   1515     co->tailmatch?"TRUE":"FALSE",
   1516     co->path?co->path:"/",
   1517     co->secure?"TRUE":"FALSE",
   1518     co->expires,
   1519     co->name,
   1520     co->value?co->value:"");
   1521 }
   1522 
   1523 /*
   1524  * cookie_output()
   1525  *
   1526  * Writes all internally known cookies to the specified file. Specify
   1527  * "-" as file name to write to stdout.
   1528  *
   1529  * The function returns non-zero on write failure.
   1530  */
   1531 static int cookie_output(struct CookieInfo *c, const char *dumphere)
   1532 {
   1533   struct Cookie *co;
   1534   FILE *out;
   1535   bool use_stdout = FALSE;
   1536   char *format_ptr;
   1537   unsigned int i;
   1538   unsigned int j;
   1539   struct Cookie **array;
   1540 
   1541   if(!c)
   1542     /* no cookie engine alive */
   1543     return 0;
   1544 
   1545   /* at first, remove expired cookies */
   1546   remove_expired(c);
   1547 
   1548   if(!strcmp("-", dumphere)) {
   1549     /* use stdout */
   1550     out = stdout;
   1551     use_stdout = TRUE;
   1552   }
   1553   else {
   1554     out = fopen(dumphere, FOPEN_WRITETEXT);
   1555     if(!out) {
   1556       return 1; /* failure */
   1557     }
   1558   }
   1559 
   1560   fputs("# Netscape HTTP Cookie File\n"
   1561         "# https://curl.haxx.se/docs/http-cookies.html\n"
   1562         "# This file was generated by libcurl! Edit at your own risk.\n\n",
   1563         out);
   1564 
   1565   if(c->numcookies) {
   1566     array = malloc(sizeof(struct Cookie *) * c->numcookies);
   1567     if(!array) {
   1568       if(!use_stdout)
   1569         fclose(out);
   1570       return 1;
   1571     }
   1572 
   1573     j = 0;
   1574     for(i = 0; i < COOKIE_HASH_SIZE; i++) {
   1575       for(co = c->cookies[i]; co; co = co->next) {
   1576         if(!co->domain)
   1577           continue;
   1578         array[j++] = co;
   1579       }
   1580     }
   1581 
   1582     qsort(array, c->numcookies, sizeof(struct Cookie *), cookie_sort_ct);
   1583 
   1584     for(i = 0; i < j; i++) {
   1585       format_ptr = get_netscape_format(array[i]);
   1586       if(format_ptr == NULL) {
   1587         fprintf(out, "#\n# Fatal libcurl error\n");
   1588         free(array);
   1589         if(!use_stdout)
   1590           fclose(out);
   1591         return 1;
   1592       }
   1593       fprintf(out, "%s\n", format_ptr);
   1594       free(format_ptr);
   1595     }
   1596 
   1597     free(array);
   1598   }
   1599   if(!use_stdout)
   1600     fclose(out);
   1601 
   1602   return 0;
   1603 }
   1604 
   1605 static struct curl_slist *cookie_list(struct Curl_easy *data)
   1606 {
   1607   struct curl_slist *list = NULL;
   1608   struct curl_slist *beg;
   1609   struct Cookie *c;
   1610   char *line;
   1611   unsigned int i;
   1612 
   1613   if((data->cookies == NULL) ||
   1614       (data->cookies->numcookies == 0))
   1615     return NULL;
   1616 
   1617   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
   1618     for(c = data->cookies->cookies[i]; c; c = c->next) {
   1619       if(!c->domain)
   1620         continue;
   1621       line = get_netscape_format(c);
   1622       if(!line) {
   1623         curl_slist_free_all(list);
   1624         return NULL;
   1625       }
   1626       beg = Curl_slist_append_nodup(list, line);
   1627       if(!beg) {
   1628         free(line);
   1629         curl_slist_free_all(list);
   1630         return NULL;
   1631       }
   1632       list = beg;
   1633     }
   1634   }
   1635 
   1636   return list;
   1637 }
   1638 
   1639 struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
   1640 {
   1641   struct curl_slist *list;
   1642   Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
   1643   list = cookie_list(data);
   1644   Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
   1645   return list;
   1646 }
   1647 
   1648 void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
   1649 {
   1650   if(data->set.str[STRING_COOKIEJAR]) {
   1651     if(data->change.cookielist) {
   1652       /* If there is a list of cookie files to read, do it first so that
   1653          we have all the told files read before we write the new jar.
   1654          Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
   1655       Curl_cookie_loadfiles(data);
   1656     }
   1657 
   1658     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
   1659 
   1660     /* if we have a destination file for all the cookies to get dumped to */
   1661     if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
   1662       infof(data, "WARNING: failed to save cookies in %s\n",
   1663             data->set.str[STRING_COOKIEJAR]);
   1664   }
   1665   else {
   1666     if(cleanup && data->change.cookielist) {
   1667       /* since nothing is written, we can just free the list of cookie file
   1668          names */
   1669       curl_slist_free_all(data->change.cookielist); /* clean up list */
   1670       data->change.cookielist = NULL;
   1671     }
   1672     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
   1673   }
   1674 
   1675   if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
   1676     Curl_cookie_cleanup(data->cookies);
   1677   }
   1678   Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
   1679 }
   1680 
   1681 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
   1682