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