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