Annotation of embedaddon/curl/lib/cookie.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>