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