openssl: guard against OOM on context creation
[platform/upstream/curl.git] / lib / cookie.c
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; /* null-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 */