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