blob: 29f627fd4c29a9c36ce471df85afb0438fca6364 [file] [log] [blame]
Kristian Monsen5ab50182010-05-14 18:53:44 +01001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Elliott Hughescac39802018-04-27 16:19:43 -07008 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
Kristian Monsen5ab50182010-05-14 18:53:44 +01009 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
Alex Deymod15eaac2016-06-28 14:49:26 -070012 * are also available at https://curl.haxx.se/docs/copyright.html.
Kristian Monsen5ab50182010-05-14 18:53:44 +010013 *
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
Alex Deymoe3149cc2016-10-05 11:18:42 -070029struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070030 const char *file, struct CookieInfo *inc, bool newsession);
Kristian Monsen5ab50182010-05-14 18:53:44 +010031
32 Inits a cookie struct to store data in a local file. This is always
33 called before any cookies are set.
34
Alex Deymoe3149cc2016-10-05 11:18:42 -070035struct Cookie *Curl_cookie_add(struct Curl_easy *data,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070036 struct CookieInfo *c, bool httpheader, char *lineptr,
37 const char *domain, const char *path);
Kristian Monsen5ab50182010-05-14 18:53:44 +010038
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070039 The 'lineptr' parameter is a full "Set-cookie:" line as
Kristian Monsen5ab50182010-05-14 18:53:44 +010040 received from a server.
41
42 The function need to replace previously stored lines that this new
43 line superceeds.
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
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070053struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie,
54 char *host, char *path, bool secure);
Kristian Monsen5ab50182010-05-14 18:53:44 +010055
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
Elliott Hughes82be86d2017-09-20 17:00:17 -070082
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070083#include "curl_setup.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010084
85#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
86
Alex Deymod15eaac2016-06-28 14:49:26 -070087#ifdef USE_LIBPSL
88# include <libpsl.h>
89#endif
90
Kristian Monsen5ab50182010-05-14 18:53:44 +010091#include "urldata.h"
92#include "cookie.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010093#include "strtok.h"
94#include "sendf.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070095#include "slist.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010096#include "share.h"
97#include "strtoofft.h"
Elliott Hughescee03382017-06-23 12:17:18 -070098#include "strcase.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +010099#include "curl_memrchr.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700100#include "inet_pton.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +0100101
Alex Deymod15eaac2016-06-28 14:49:26 -0700102/* The last 3 #include files should be in this order */
103#include "curl_printf.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700104#include "curl_memory.h"
Kristian Monsen5ab50182010-05-14 18:53:44 +0100105#include "memdebug.h"
106
Kristian Monsen5ab50182010-05-14 18:53:44 +0100107static void freecookie(struct Cookie *co)
108{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700109 free(co->expirestr);
110 free(co->domain);
111 free(co->path);
112 free(co->spath);
113 free(co->name);
114 free(co->value);
115 free(co->maxage);
116 free(co->version);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100117 free(co);
118}
119
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700120static bool tailmatch(const char *cooke_domain, const char *hostname)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100121{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700122 size_t cookie_domain_len = strlen(cooke_domain);
123 size_t hostname_len = strlen(hostname);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100124
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700125 if(hostname_len < cookie_domain_len)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100126 return FALSE;
127
Alex Deymo486467e2017-12-19 19:04:07 +0100128 if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len))
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700129 return FALSE;
130
131 /* A lead char of cookie_domain is not '.'.
132 RFC6265 4.1.2.3. The Domain Attribute says:
133 For example, if the value of the Domain attribute is
134 "example.com", the user agent will include the cookie in the Cookie
135 header when making HTTP requests to example.com, www.example.com, and
136 www.corp.example.com.
137 */
138 if(hostname_len == cookie_domain_len)
139 return TRUE;
140 if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
141 return TRUE;
142 return FALSE;
143}
144
145/*
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700146 * Return true if the given string is an IP(v4|v6) address.
147 */
148static bool isip(const char *domain)
149{
150 struct in_addr addr;
151#ifdef ENABLE_IPV6
152 struct in6_addr addr6;
153#endif
154
155 if(Curl_inet_pton(AF_INET, domain, &addr)
156#ifdef ENABLE_IPV6
157 || Curl_inet_pton(AF_INET6, domain, &addr6)
158#endif
159 ) {
160 /* domain name given as IP address */
161 return TRUE;
162 }
163
164 return FALSE;
165}
166
167/*
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700168 * matching cookie path and url path
169 * RFC6265 5.1.4 Paths and Path-Match
170 */
Elliott Hughescee03382017-06-23 12:17:18 -0700171static bool pathmatch(const char *cookie_path, const char *request_uri)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700172{
173 size_t cookie_path_len;
174 size_t uri_path_len;
Elliott Hughescee03382017-06-23 12:17:18 -0700175 char *uri_path = NULL;
176 char *pos;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700177 bool ret = FALSE;
178
179 /* cookie_path must not have last '/' separator. ex: /sample */
180 cookie_path_len = strlen(cookie_path);
181 if(1 == cookie_path_len) {
182 /* cookie_path must be '/' */
183 return TRUE;
184 }
185
186 uri_path = strdup(request_uri);
187 if(!uri_path)
188 return FALSE;
189 pos = strchr(uri_path, '?');
190 if(pos)
191 *pos = 0x0;
192
193 /* #-fragments are already cut off! */
194 if(0 == strlen(uri_path) || uri_path[0] != '/') {
195 free(uri_path);
196 uri_path = strdup("/");
197 if(!uri_path)
198 return FALSE;
199 }
200
201 /* here, RFC6265 5.1.4 says
202 4. Output the characters of the uri-path from the first character up
203 to, but not including, the right-most %x2F ("/").
204 but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
205 without redirect.
206 Ignore this algorithm because /hoge is uri path for this case
207 (uri path is not /).
208 */
209
210 uri_path_len = strlen(uri_path);
211
212 if(uri_path_len < cookie_path_len) {
213 ret = FALSE;
214 goto pathmatched;
215 }
216
217 /* not using checkprefix() because matching should be case-sensitive */
218 if(strncmp(cookie_path, uri_path, cookie_path_len)) {
219 ret = FALSE;
220 goto pathmatched;
221 }
222
223 /* The cookie-path and the uri-path are identical. */
224 if(cookie_path_len == uri_path_len) {
225 ret = TRUE;
226 goto pathmatched;
227 }
228
229 /* here, cookie_path_len < url_path_len */
230 if(uri_path[cookie_path_len] == '/') {
231 ret = TRUE;
232 goto pathmatched;
233 }
234
235 ret = FALSE;
236
237pathmatched:
238 free(uri_path);
239 return ret;
240}
241
242/*
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700243 * Return the top-level domain, for optimal hashing.
244 */
245static const char *get_top_domain(const char * const domain, size_t *outlen)
246{
247 size_t len;
248 const char *first = NULL, *last;
249
250 if(!domain)
251 return NULL;
252
253 len = strlen(domain);
254 last = memrchr(domain, '.', len);
255 if(last) {
256 first = memrchr(domain, '.', (size_t) (last - domain));
257 if(first)
258 len -= (size_t) (++first - domain);
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 */
270static 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 */
286static 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/*
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700299 * cookie path sanitize
300 */
301static 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;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100333}
334
335/*
336 * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700337 *
338 * NOTE: OOM or cookie parsing failures are ignored.
Kristian Monsen5ab50182010-05-14 18:53:44 +0100339 */
Alex Deymoe3149cc2016-10-05 11:18:42 -0700340void Curl_cookie_loadfiles(struct Curl_easy *data)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100341{
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) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700346 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;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100357 list = list->next;
358 }
Kristian Monsen5ab50182010-05-14 18:53:44 +0100359 curl_slist_free_all(data->change.cookielist); /* clean up list */
360 data->change.cookielist = NULL; /* don't do this again! */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700361 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100362 }
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 */
371static void strstore(char **str, const char *newstr)
372{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700373 free(*str);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100374 *str = strdup(newstr);
375}
376
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700377/*
378 * remove_expired() removes expired cookies.
379 */
380static void remove_expired(struct CookieInfo *cookies)
381{
382 struct Cookie *co, *nx, *pv;
383 curl_off_t now = (curl_off_t)time(NULL);
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700384 unsigned int i;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700385
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700386 for(i = 0; i < COOKIE_HASH_SIZE; i++) {
387 co = cookies->cookies[i];
388 pv = NULL;
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);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700400 }
401 else {
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700402 pv = co;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700403 }
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700404 co = nx;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700405 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700406 }
407}
408
Kristian Monsen5ab50182010-05-14 18:53:44 +0100409/****************************************************************************
410 *
411 * Curl_cookie_add()
412 *
413 * Add a single cookie line to the cookie keeping object.
414 *
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700415 * Be aware that sometimes we get an IP-only host name, and that might also be
416 * a numerical IPv6 address.
417 *
418 * Returns NULL on out of memory or invalid cookie. This is suboptimal,
419 * as they should be treated separately.
Kristian Monsen5ab50182010-05-14 18:53:44 +0100420 ***************************************************************************/
421
422struct Cookie *
Alex Deymoe3149cc2016-10-05 11:18:42 -0700423Curl_cookie_add(struct Curl_easy *data,
Kristian Monsen5ab50182010-05-14 18:53:44 +0100424 /* The 'data' pointer here may be NULL at times, and thus
425 must only be used very carefully for things that can deal
426 with data being NULL. Such as infof() and similar */
427
428 struct CookieInfo *c,
429 bool httpheader, /* TRUE if HTTP header-style line */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700430 bool noexpire, /* if TRUE, skip remove_expired() */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100431 char *lineptr, /* first character of the line */
432 const char *domain, /* default domain */
433 const char *path) /* full path used when this cookie is set,
434 used to get default path for the cookie
435 unless set */
436{
437 struct Cookie *clist;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100438 struct Cookie *co;
Alex Deymo486467e2017-12-19 19:04:07 +0100439 struct Cookie *lastc = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100440 time_t now = time(NULL);
441 bool replace_old = FALSE;
442 bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700443 size_t myhash;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100444
Alex Deymod15eaac2016-06-28 14:49:26 -0700445#ifdef USE_LIBPSL
446 const psl_ctx_t *psl;
447#endif
448
Kristian Monsen5ab50182010-05-14 18:53:44 +0100449#ifdef CURL_DISABLE_VERBOSE_STRINGS
450 (void)data;
451#endif
452
453 /* First, alloc and init a new struct for it */
454 co = calloc(1, sizeof(struct Cookie));
455 if(!co)
456 return NULL; /* bail out if we're this low on memory */
457
458 if(httpheader) {
459 /* This line was read off a HTTP-header */
Alex Deymo486467e2017-12-19 19:04:07 +0100460 char name[MAX_NAME];
461 char what[MAX_NAME];
Kristian Monsen5ab50182010-05-14 18:53:44 +0100462 const char *ptr;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100463 const char *semiptr;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100464
Alex Deymo486467e2017-12-19 19:04:07 +0100465 size_t linelength = strlen(lineptr);
466 if(linelength > MAX_COOKIE_LINE) {
467 /* discard overly long lines at once */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100468 free(co);
469 return NULL;
470 }
471
Alex Deymo486467e2017-12-19 19:04:07 +0100472 semiptr = strchr(lineptr, ';'); /* first, find a semicolon */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100473
474 while(*lineptr && ISBLANK(*lineptr))
475 lineptr++;
476
477 ptr = lineptr;
478 do {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700479 /* we have a <what>=<this> pair or a stand-alone word here */
Alex Deymo486467e2017-12-19 19:04:07 +0100480 name[0] = what[0] = 0; /* init the buffers */
Alex Deymod15eaac2016-06-28 14:49:26 -0700481 if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%"
Alex Deymo486467e2017-12-19 19:04:07 +0100482 MAX_NAME_TXT "[^;\r\n]",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700483 name, what)) {
484 /* Use strstore() below to properly deal with received cookie
485 headers that have the same string property set more than once,
486 and then we use the last one. */
487 const char *whatptr;
488 bool done = FALSE;
489 bool sep;
Alex Deymo486467e2017-12-19 19:04:07 +0100490 size_t len = strlen(what);
Alex Deymod15eaac2016-06-28 14:49:26 -0700491 size_t nlen = strlen(name);
492 const char *endofn = &ptr[ nlen ];
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700493
Alex Deymo486467e2017-12-19 19:04:07 +0100494 if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
495 ((nlen + len) > MAX_NAME)) {
496 /* too long individual name or contents, or too long combination of
497 name + contents. Chrome and Firefox support 4095 or 4096 bytes
498 combo. */
499 freecookie(co);
500 infof(data, "oversized cookie dropped, name/val %d + %d bytes\n",
501 nlen, len);
502 return NULL;
503 }
504
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700505 /* name ends with a '=' ? */
506 sep = (*endofn == '=')?TRUE:FALSE;
507
Alex Deymod15eaac2016-06-28 14:49:26 -0700508 if(nlen) {
509 endofn--; /* move to the last character */
510 if(ISBLANK(*endofn)) {
511 /* skip trailing spaces in name */
512 while(*endofn && ISBLANK(*endofn) && nlen) {
513 endofn--;
514 nlen--;
515 }
Alex Deymo486467e2017-12-19 19:04:07 +0100516 name[nlen] = 0; /* new end of name */
Alex Deymod15eaac2016-06-28 14:49:26 -0700517 }
518 }
519
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700520 /* Strip off trailing whitespace from the 'what' */
521 while(len && ISBLANK(what[len-1])) {
Alex Deymo486467e2017-12-19 19:04:07 +0100522 what[len-1] = 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700523 len--;
524 }
525
526 /* Skip leading whitespace from the 'what' */
Alex Deymo486467e2017-12-19 19:04:07 +0100527 whatptr = what;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700528 while(*whatptr && ISBLANK(*whatptr))
529 whatptr++;
530
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700531 if(!co->name) {
Alex Deymod15eaac2016-06-28 14:49:26 -0700532 /* The very first name/value pair is the actual cookie name */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700533 if(!sep) {
534 /* Bad name/value pair. */
535 badcookie = TRUE;
536 break;
537 }
Alex Deymod15eaac2016-06-28 14:49:26 -0700538 co->name = strdup(name);
539 co->value = strdup(whatptr);
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700540 done = TRUE;
Alex Deymod15eaac2016-06-28 14:49:26 -0700541 if(!co->name || !co->value) {
542 badcookie = TRUE;
543 break;
544 }
545 }
546 else if(!len) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700547 /* this was a "<name>=" with no content, and we must allow
548 'secure' and 'httponly' specified this weirdly */
549 done = TRUE;
Elliott Hughescee03382017-06-23 12:17:18 -0700550 if(strcasecompare("secure", name))
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700551 co->secure = TRUE;
Elliott Hughescee03382017-06-23 12:17:18 -0700552 else if(strcasecompare("httponly", name))
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700553 co->httponly = TRUE;
554 else if(sep)
555 /* there was a '=' so we're not done parsing this field */
556 done = FALSE;
557 }
558 if(done)
559 ;
Elliott Hughescee03382017-06-23 12:17:18 -0700560 else if(strcasecompare("path", name)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700561 strstore(&co->path, whatptr);
562 if(!co->path) {
563 badcookie = TRUE; /* out of memory bad */
564 break;
565 }
Alex Deymo486467e2017-12-19 19:04:07 +0100566 free(co->spath); /* if this is set again */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700567 co->spath = sanitize_cookie_path(co->path);
568 if(!co->spath) {
569 badcookie = TRUE; /* out of memory bad */
570 break;
571 }
572 }
Elliott Hughescee03382017-06-23 12:17:18 -0700573 else if(strcasecompare("domain", name)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700574 bool is_ip;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700575
576 /* Now, we make sure that our host is within the given domain,
577 or the given domain is not valid and thus cannot be set. */
578
579 if('.' == whatptr[0])
580 whatptr++; /* ignore preceding dot */
581
Elliott Hughes82be86d2017-09-20 17:00:17 -0700582#ifndef USE_LIBPSL
583 /*
584 * Without PSL we don't know when the incoming cookie is set on a
585 * TLD or otherwise "protected" suffix. To reduce risk, we require a
586 * dot OR the exact host name being "localhost".
587 */
588 {
589 const char *dotp;
590 /* check for more dots */
591 dotp = strchr(whatptr, '.');
592 if(!dotp && !strcasecompare("localhost", whatptr))
Alex Deymo486467e2017-12-19 19:04:07 +0100593 domain = ":";
Elliott Hughes82be86d2017-09-20 17:00:17 -0700594 }
595#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700596
Elliott Hughes82be86d2017-09-20 17:00:17 -0700597 is_ip = isip(domain ? domain : whatptr);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700598
599 if(!domain
600 || (is_ip && !strcmp(whatptr, domain))
601 || (!is_ip && tailmatch(whatptr, domain))) {
602 strstore(&co->domain, whatptr);
603 if(!co->domain) {
604 badcookie = TRUE;
605 break;
606 }
607 if(!is_ip)
Alex Deymo486467e2017-12-19 19:04:07 +0100608 co->tailmatch = TRUE; /* we always do that if the domain name was
609 given */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700610 }
611 else {
612 /* we did not get a tailmatch and then the attempted set domain
613 is not a domain to which the current host belongs. Mark as
614 bad. */
Alex Deymo486467e2017-12-19 19:04:07 +0100615 badcookie = TRUE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700616 infof(data, "skipped cookie with bad tailmatch domain: %s\n",
617 whatptr);
618 }
619 }
Elliott Hughescee03382017-06-23 12:17:18 -0700620 else if(strcasecompare("version", name)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700621 strstore(&co->version, whatptr);
622 if(!co->version) {
623 badcookie = TRUE;
624 break;
625 }
626 }
Elliott Hughescee03382017-06-23 12:17:18 -0700627 else if(strcasecompare("max-age", name)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700628 /* Defined in RFC2109:
629
630 Optional. The Max-Age attribute defines the lifetime of the
631 cookie, in seconds. The delta-seconds value is a decimal non-
632 negative integer. After delta-seconds seconds elapse, the
633 client should discard the cookie. A value of zero means the
634 cookie should be discarded immediately.
635
636 */
637 strstore(&co->maxage, whatptr);
638 if(!co->maxage) {
639 badcookie = TRUE;
640 break;
641 }
642 }
Elliott Hughescee03382017-06-23 12:17:18 -0700643 else if(strcasecompare("expires", name)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700644 strstore(&co->expirestr, whatptr);
645 if(!co->expirestr) {
646 badcookie = TRUE;
647 break;
648 }
649 }
Kristian Monsen5ab50182010-05-14 18:53:44 +0100650 /*
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700651 else this is the second (or more) name we don't know
652 about! */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100653 }
654 else {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700655 /* this is an "illegal" <what>=<this> pair */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100656 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700657
Kristian Monsen5ab50182010-05-14 18:53:44 +0100658 if(!semiptr || !*semiptr) {
659 /* we already know there are no more cookies */
660 semiptr = NULL;
661 continue;
662 }
663
Alex Deymo486467e2017-12-19 19:04:07 +0100664 ptr = semiptr + 1;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100665 while(*ptr && ISBLANK(*ptr))
666 ptr++;
Alex Deymo486467e2017-12-19 19:04:07 +0100667 semiptr = strchr(ptr, ';'); /* now, find the next semicolon */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100668
669 if(!semiptr && *ptr)
670 /* There are no more semicolons, but there's a final name=value pair
671 coming up */
Alex Deymo486467e2017-12-19 19:04:07 +0100672 semiptr = strchr(ptr, '\0');
Kristian Monsen5ab50182010-05-14 18:53:44 +0100673 } while(semiptr);
674
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700675 if(co->maxage) {
Alex Deymo486467e2017-12-19 19:04:07 +0100676 CURLofft offt;
677 offt = curlx_strtoofft((*co->maxage == '\"')?
678 &co->maxage[1]:&co->maxage[0], NULL, 10,
679 &co->expires);
680 if(offt == CURL_OFFT_FLOW)
681 /* overflow, used max value */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700682 co->expires = CURL_OFF_T_MAX;
Alex Deymo486467e2017-12-19 19:04:07 +0100683 else if(!offt) {
684 if(CURL_OFF_T_MAX - now < co->expires)
685 /* would overflow */
686 co->expires = CURL_OFF_T_MAX;
687 else
688 co->expires += now;
689 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700690 }
691 else if(co->expirestr) {
692 /* Note that if the date couldn't get parsed for whatever reason,
693 the cookie will be treated as a session cookie */
694 co->expires = curl_getdate(co->expirestr, NULL);
695
696 /* Session cookies have expires set to 0 so if we get that back
697 from the date parser let's add a second to make it a
698 non-session cookie */
699 if(co->expires == 0)
700 co->expires = 1;
701 else if(co->expires < 0)
702 co->expires = 0;
703 }
704
Kristian Monsen5ab50182010-05-14 18:53:44 +0100705 if(!badcookie && !co->domain) {
706 if(domain) {
707 /* no domain was given in the header line, set the default */
Alex Deymo486467e2017-12-19 19:04:07 +0100708 co->domain = strdup(domain);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100709 if(!co->domain)
710 badcookie = TRUE;
711 }
712 }
713
714 if(!badcookie && !co->path && path) {
715 /* No path was given in the header line, set the default.
716 Note that the passed-in path to this function MAY have a '?' and
717 following part that MUST not be stored as part of the path. */
718 char *queryp = strchr(path, '?');
719
720 /* queryp is where the interesting part of the path ends, so now we
721 want to the find the last */
722 char *endslash;
723 if(!queryp)
724 endslash = strrchr(path, '/');
725 else
726 endslash = memrchr(path, '/', (size_t)(queryp - path));
727 if(endslash) {
Alex Deymo486467e2017-12-19 19:04:07 +0100728 size_t pathlen = (size_t)(endslash-path + 1); /* include end slash */
729 co->path = malloc(pathlen + 1); /* one extra for the zero byte */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100730 if(co->path) {
731 memcpy(co->path, path, pathlen);
Alex Deymo486467e2017-12-19 19:04:07 +0100732 co->path[pathlen] = 0; /* zero terminate */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700733 co->spath = sanitize_cookie_path(co->path);
734 if(!co->spath)
735 badcookie = TRUE; /* out of memory bad */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100736 }
737 else
738 badcookie = TRUE;
739 }
740 }
741
Kristian Monsen5ab50182010-05-14 18:53:44 +0100742 if(badcookie || !co->name) {
743 /* we didn't get a cookie name or a bad one,
744 this is an illegal line, bail out */
745 freecookie(co);
746 return NULL;
747 }
748
749 }
750 else {
751 /* This line is NOT a HTTP header style line, we do offer support for
752 reading the odd netscape cookies-file format here */
753 char *ptr;
754 char *firstptr;
Alex Deymo486467e2017-12-19 19:04:07 +0100755 char *tok_buf = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100756 int fields;
757
758 /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
759 marked with httpOnly after the domain name are not accessible
760 from javascripts, but since curl does not operate at javascript
761 level, we include them anyway. In Firefox's cookie files, these
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700762 lines are preceded with #HttpOnly_ and then everything is
Kristian Monsen5ab50182010-05-14 18:53:44 +0100763 as usual, so we skip 10 characters of the line..
764 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700765 if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100766 lineptr += 10;
767 co->httponly = TRUE;
768 }
769
770 if(lineptr[0]=='#') {
771 /* don't even try the comments */
772 free(co);
773 return NULL;
774 }
775 /* strip off the possible end-of-line characters */
Alex Deymo486467e2017-12-19 19:04:07 +0100776 ptr = strchr(lineptr, '\r');
Kristian Monsen5ab50182010-05-14 18:53:44 +0100777 if(ptr)
Alex Deymo486467e2017-12-19 19:04:07 +0100778 *ptr = 0; /* clear it */
779 ptr = strchr(lineptr, '\n');
Kristian Monsen5ab50182010-05-14 18:53:44 +0100780 if(ptr)
Alex Deymo486467e2017-12-19 19:04:07 +0100781 *ptr = 0; /* clear it */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100782
Alex Deymo486467e2017-12-19 19:04:07 +0100783 firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100784
Kristian Monsen5ab50182010-05-14 18:53:44 +0100785 /* Now loop through the fields and init the struct we already have
786 allocated */
Alex Deymo486467e2017-12-19 19:04:07 +0100787 for(ptr = firstptr, fields = 0; ptr && !badcookie;
788 ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100789 switch(fields) {
790 case 0:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700791 if(ptr[0]=='.') /* skip preceding dots */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100792 ptr++;
793 co->domain = strdup(ptr);
794 if(!co->domain)
795 badcookie = TRUE;
796 break;
797 case 1:
798 /* This field got its explanation on the 23rd of May 2001 by
799 Andrés García:
800
801 flag: A TRUE/FALSE value indicating if all machines within a given
802 domain can access the variable. This value is set automatically by
803 the browser, depending on the value you set for the domain.
804
805 As far as I can see, it is set to true when the cookie says
806 .domain.com and to false when the domain is complete www.domain.com
807 */
Elliott Hughescee03382017-06-23 12:17:18 -0700808 co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100809 break;
810 case 2:
811 /* It turns out, that sometimes the file format allows the path
812 field to remain not filled in, we try to detect this and work
813 around it! Andrés García made us aware of this... */
814 if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
815 /* only if the path doesn't look like a boolean option! */
816 co->path = strdup(ptr);
817 if(!co->path)
818 badcookie = TRUE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700819 else {
820 co->spath = sanitize_cookie_path(co->path);
821 if(!co->spath) {
822 badcookie = TRUE; /* out of memory bad */
823 }
824 }
Kristian Monsen5ab50182010-05-14 18:53:44 +0100825 break;
826 }
827 /* this doesn't look like a path, make one up! */
828 co->path = strdup("/");
829 if(!co->path)
830 badcookie = TRUE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700831 co->spath = strdup("/");
832 if(!co->spath)
833 badcookie = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100834 fields++; /* add a field and fall down to secure */
835 /* FALLTHROUGH */
836 case 3:
Elliott Hughescee03382017-06-23 12:17:18 -0700837 co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100838 break;
839 case 4:
Alex Deymo486467e2017-12-19 19:04:07 +0100840 if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
841 badcookie = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100842 break;
843 case 5:
844 co->name = strdup(ptr);
845 if(!co->name)
846 badcookie = TRUE;
847 break;
848 case 6:
849 co->value = strdup(ptr);
850 if(!co->value)
851 badcookie = TRUE;
852 break;
853 }
854 }
855 if(6 == fields) {
856 /* we got a cookie with blank contents, fix it */
857 co->value = strdup("");
858 if(!co->value)
859 badcookie = TRUE;
860 else
861 fields++;
862 }
863
864 if(!badcookie && (7 != fields))
865 /* we did not find the sufficient number of fields */
866 badcookie = TRUE;
867
868 if(badcookie) {
869 freecookie(co);
870 return NULL;
871 }
872
873 }
874
875 if(!c->running && /* read from a file */
876 c->newsession && /* clean session cookies */
877 !co->expires) { /* this is a session cookie since it doesn't expire! */
878 freecookie(co);
879 return NULL;
880 }
881
882 co->livecookie = c->running;
883
884 /* now, we have parsed the incoming line, we must now check if this
885 superceeds an already existing cookie, which it may if the previous have
886 the same domain and path as this */
887
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700888 /* at first, remove expired cookies */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700889 if(!noexpire)
890 remove_expired(c);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700891
Alex Deymod15eaac2016-06-28 14:49:26 -0700892#ifdef USE_LIBPSL
893 /* Check if the domain is a Public Suffix and if yes, ignore the cookie.
894 This needs a libpsl compiled with builtin data. */
895 if(domain && co->domain && !isip(co->domain)) {
Elliott Hughes82be86d2017-09-20 17:00:17 -0700896 psl = psl_builtin();
897 if(psl && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) {
Alex Deymod15eaac2016-06-28 14:49:26 -0700898 infof(data,
899 "cookie '%s' dropped, domain '%s' must not set cookies for '%s'\n",
900 co->name, domain, co->domain);
901 freecookie(co);
902 return NULL;
903 }
904 }
905#endif
906
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700907 myhash = cookiehash(co->domain);
908 clist = c->cookies[myhash];
Kristian Monsen5ab50182010-05-14 18:53:44 +0100909 replace_old = FALSE;
910 while(clist) {
Elliott Hughescee03382017-06-23 12:17:18 -0700911 if(strcasecompare(clist->name, co->name)) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100912 /* the names are identical */
913
914 if(clist->domain && co->domain) {
Elliott Hughescee03382017-06-23 12:17:18 -0700915 if(strcasecompare(clist->domain, co->domain) &&
916 (clist->tailmatch == co->tailmatch))
Kristian Monsen5ab50182010-05-14 18:53:44 +0100917 /* The domains are identical */
Alex Deymo486467e2017-12-19 19:04:07 +0100918 replace_old = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +0100919 }
920 else if(!clist->domain && !co->domain)
921 replace_old = TRUE;
922
923 if(replace_old) {
924 /* the domains were identical */
925
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700926 if(clist->spath && co->spath) {
Elliott Hughescee03382017-06-23 12:17:18 -0700927 if(strcasecompare(clist->spath, co->spath)) {
Kristian Monsen5ab50182010-05-14 18:53:44 +0100928 replace_old = TRUE;
929 }
930 else
931 replace_old = FALSE;
932 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700933 else if(!clist->spath && !co->spath)
Kristian Monsen5ab50182010-05-14 18:53:44 +0100934 replace_old = TRUE;
935 else
936 replace_old = FALSE;
937
938 }
939
940 if(replace_old && !co->livecookie && clist->livecookie) {
941 /* Both cookies matched fine, except that the already present
942 cookie is "live", which means it was set from a header, while
943 the new one isn't "live" and thus only read from a file. We let
944 live cookies stay alive */
945
946 /* Free the newcomer and get out of here! */
947 freecookie(co);
948 return NULL;
949 }
950
951 if(replace_old) {
952 co->next = clist->next; /* get the next-pointer first */
953
954 /* then free all the old pointers */
955 free(clist->name);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700956 free(clist->value);
957 free(clist->domain);
958 free(clist->path);
959 free(clist->spath);
960 free(clist->expirestr);
961 free(clist->version);
962 free(clist->maxage);
Kristian Monsen5ab50182010-05-14 18:53:44 +0100963
964 *clist = *co; /* then store all the new data */
965
966 free(co); /* free the newly alloced memory */
967 co = clist; /* point to the previous struct instead */
968
969 /* We have replaced a cookie, now skip the rest of the list but
970 make sure the 'lastc' pointer is properly set */
971 do {
972 lastc = clist;
973 clist = clist->next;
974 } while(clist);
975 break;
976 }
977 }
978 lastc = clist;
979 clist = clist->next;
980 }
981
982 if(c->running)
983 /* Only show this when NOT reading the cookies from a file */
984 infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700985 "expire %" CURL_FORMAT_CURL_OFF_T "\n",
Kristian Monsen5ab50182010-05-14 18:53:44 +0100986 replace_old?"Replaced":"Added", co->name, co->value,
987 co->domain, co->path, co->expires);
988
989 if(!replace_old) {
990 /* then make the last item point on this new one */
991 if(lastc)
992 lastc->next = co;
993 else
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700994 c->cookies[myhash] = co;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700995 c->numcookies++; /* one more cookie in the jar */
Kristian Monsen5ab50182010-05-14 18:53:44 +0100996 }
997
Kristian Monsen5ab50182010-05-14 18:53:44 +0100998 return co;
999}
1000
Elliott Hughescee03382017-06-23 12:17:18 -07001001/*
1002 * get_line() makes sure to only return complete whole lines that fit in 'len'
1003 * bytes and end with a newline.
1004 */
1005static char *get_line(char *buf, int len, FILE *input)
1006{
1007 bool partial = FALSE;
1008 while(1) {
1009 char *b = fgets(buf, len, input);
1010 if(b) {
1011 size_t rlen = strlen(b);
1012 if(rlen && (b[rlen-1] == '\n')) {
1013 if(partial) {
1014 partial = FALSE;
1015 continue;
1016 }
1017 return b;
1018 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07001019 /* read a partial, discard the next piece that ends with newline */
1020 partial = TRUE;
Elliott Hughescee03382017-06-23 12:17:18 -07001021 }
1022 else
1023 break;
1024 }
1025 return NULL;
1026}
1027
1028
Kristian Monsen5ab50182010-05-14 18:53:44 +01001029/*****************************************************************************
1030 *
1031 * Curl_cookie_init()
1032 *
1033 * Inits a cookie struct to read data from a local file. This is always
1034 * called before any cookies are set. File may be NULL.
1035 *
1036 * If 'newsession' is TRUE, discard all "session cookies" on read from file.
1037 *
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001038 * Returns NULL on out of memory. Invalid cookies are ignored.
Kristian Monsen5ab50182010-05-14 18:53:44 +01001039 ****************************************************************************/
Alex Deymoe3149cc2016-10-05 11:18:42 -07001040struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
Kristian Monsen5ab50182010-05-14 18:53:44 +01001041 const char *file,
1042 struct CookieInfo *inc,
1043 bool newsession)
1044{
1045 struct CookieInfo *c;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001046 FILE *fp = NULL;
Alex Deymo486467e2017-12-19 19:04:07 +01001047 bool fromfile = TRUE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001048 char *line = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001049
1050 if(NULL == inc) {
1051 /* we didn't get a struct, create one */
1052 c = calloc(1, sizeof(struct CookieInfo));
1053 if(!c)
1054 return NULL; /* failed to get memory */
1055 c->filename = strdup(file?file:"none"); /* copy the name just in case */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001056 if(!c->filename)
1057 goto fail; /* failed to get memory */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001058 }
1059 else {
1060 /* we got an already existing one, use that */
1061 c = inc;
1062 }
1063 c->running = FALSE; /* this is not running, this is init */
1064
Elliott Hughescee03382017-06-23 12:17:18 -07001065 if(file && !strcmp(file, "-")) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001066 fp = stdin;
Alex Deymo486467e2017-12-19 19:04:07 +01001067 fromfile = FALSE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001068 }
1069 else if(file && !*file) {
1070 /* points to a "" string */
1071 fp = NULL;
1072 }
1073 else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001074 fp = file?fopen(file, FOPEN_READTEXT):NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001075
1076 c->newsession = newsession; /* new session? */
1077
1078 if(fp) {
1079 char *lineptr;
1080 bool headerline;
1081
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001082 line = malloc(MAX_COOKIE_LINE);
1083 if(!line)
1084 goto fail;
Elliott Hughescee03382017-06-23 12:17:18 -07001085 while(get_line(line, MAX_COOKIE_LINE, fp)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001086 if(checkprefix("Set-Cookie:", line)) {
1087 /* This is a cookie line, get it! */
Alex Deymo486467e2017-12-19 19:04:07 +01001088 lineptr = &line[11];
1089 headerline = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001090 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001091 else {
Alex Deymo486467e2017-12-19 19:04:07 +01001092 lineptr = line;
1093 headerline = FALSE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001094 }
1095 while(*lineptr && ISBLANK(*lineptr))
1096 lineptr++;
1097
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001098 Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001099 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001100 free(line); /* free the line buffer */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001101 remove_expired(c); /* run this once, not on every cookie */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001102
Kristian Monsen5ab50182010-05-14 18:53:44 +01001103 if(fromfile)
1104 fclose(fp);
1105 }
1106
1107 c->running = TRUE; /* now, we're running */
1108
1109 return c;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001110
1111fail:
1112 free(line);
1113 if(!inc)
1114 /* Only clean up if we allocated it here, as the original could still be in
1115 * use by a share handle */
1116 Curl_cookie_cleanup(c);
1117 if(fromfile && fp)
1118 fclose(fp);
1119 return NULL; /* out of memory */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001120}
1121
1122/* sort this so that the longest path gets before the shorter path */
1123static int cookie_sort(const void *p1, const void *p2)
1124{
1125 struct Cookie *c1 = *(struct Cookie **)p1;
1126 struct Cookie *c2 = *(struct Cookie **)p2;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001127 size_t l1, l2;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001128
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001129 /* 1 - compare cookie path lengths */
1130 l1 = c1->path ? strlen(c1->path) : 0;
1131 l2 = c2->path ? strlen(c2->path) : 0;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001132
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001133 if(l1 != l2)
1134 return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
1135
1136 /* 2 - compare cookie domain lengths */
1137 l1 = c1->domain ? strlen(c1->domain) : 0;
1138 l2 = c2->domain ? strlen(c2->domain) : 0;
1139
1140 if(l1 != l2)
1141 return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
1142
1143 /* 3 - compare cookie names */
1144 if(c1->name && c2->name)
1145 return strcmp(c1->name, c2->name);
1146
1147 /* sorry, can't be more deterministic */
1148 return 0;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001149}
1150
Elliott Hughescee03382017-06-23 12:17:18 -07001151#define CLONE(field) \
1152 do { \
1153 if(src->field) { \
Elliott Hughes82be86d2017-09-20 17:00:17 -07001154 d->field = strdup(src->field); \
1155 if(!d->field) \
Elliott Hughescee03382017-06-23 12:17:18 -07001156 goto fail; \
1157 } \
1158 } while(0)
1159
1160static struct Cookie *dup_cookie(struct Cookie *src)
1161{
Elliott Hughes82be86d2017-09-20 17:00:17 -07001162 struct Cookie *d = calloc(sizeof(struct Cookie), 1);
1163 if(d) {
Elliott Hughescee03382017-06-23 12:17:18 -07001164 CLONE(expirestr);
1165 CLONE(domain);
1166 CLONE(path);
1167 CLONE(spath);
1168 CLONE(name);
1169 CLONE(value);
1170 CLONE(maxage);
1171 CLONE(version);
Elliott Hughes82be86d2017-09-20 17:00:17 -07001172 d->expires = src->expires;
1173 d->tailmatch = src->tailmatch;
1174 d->secure = src->secure;
1175 d->livecookie = src->livecookie;
1176 d->httponly = src->httponly;
Elliott Hughescee03382017-06-23 12:17:18 -07001177 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07001178 return d;
Elliott Hughescee03382017-06-23 12:17:18 -07001179
1180 fail:
Elliott Hughes82be86d2017-09-20 17:00:17 -07001181 freecookie(d);
Elliott Hughescee03382017-06-23 12:17:18 -07001182 return NULL;
1183}
1184
Kristian Monsen5ab50182010-05-14 18:53:44 +01001185/*****************************************************************************
1186 *
1187 * Curl_cookie_getlist()
1188 *
1189 * For a given host and path, return a linked list of cookies that the
1190 * client should send to the server if used now. The secure boolean informs
1191 * the cookie if a secure connection is achieved or not.
1192 *
1193 * It shall only return cookies that haven't expired.
1194 *
1195 ****************************************************************************/
1196
1197struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
1198 const char *host, const char *path,
1199 bool secure)
1200{
1201 struct Cookie *newco;
1202 struct Cookie *co;
1203 time_t now = time(NULL);
Alex Deymo486467e2017-12-19 19:04:07 +01001204 struct Cookie *mainco = NULL;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001205 size_t matches = 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001206 bool is_ip;
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001207 const size_t myhash = cookiehash(host);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001208
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001209 if(!c || !c->cookies[myhash])
Kristian Monsen5ab50182010-05-14 18:53:44 +01001210 return NULL; /* no cookie struct or no cookies in the struct */
1211
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001212 /* at first, remove expired cookies */
1213 remove_expired(c);
1214
1215 /* check if host is an IP(v4|v6) address */
1216 is_ip = isip(host);
1217
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001218 co = c->cookies[myhash];
Kristian Monsen5ab50182010-05-14 18:53:44 +01001219
1220 while(co) {
1221 /* only process this cookie if it is not expired or had no expire
1222 date AND that if the cookie requires we're secure we must only
1223 continue if we are! */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001224 if((!co->expires || (co->expires > now)) &&
1225 (co->secure?secure:TRUE)) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001226
1227 /* now check if the domain is correct */
1228 if(!co->domain ||
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001229 (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
Elliott Hughescee03382017-06-23 12:17:18 -07001230 ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001231 /* the right part of the host matches the domain stuff in the
1232 cookie data */
1233
1234 /* now check the left part of the path with the cookies path
1235 requirement */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001236 if(!co->spath || pathmatch(co->spath, path) ) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001237
1238 /* and now, we know this is a match and we should create an
1239 entry for the return-linked-list */
1240
Elliott Hughescee03382017-06-23 12:17:18 -07001241 newco = dup_cookie(co);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001242 if(newco) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001243 /* then modify our next */
1244 newco->next = mainco;
1245
1246 /* point the main to us */
1247 mainco = newco;
1248
1249 matches++;
1250 }
1251 else {
1252 fail:
1253 /* failure, clear up the allocated chain and return NULL */
Elliott Hughescee03382017-06-23 12:17:18 -07001254 Curl_cookie_freelist(mainco);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001255 return NULL;
1256 }
1257 }
1258 }
1259 }
1260 co = co->next;
1261 }
1262
1263 if(matches) {
1264 /* Now we need to make sure that if there is a name appearing more than
1265 once, the longest specified path version comes first. To make this
1266 the swiftest way, we just sort them all based on path length. */
1267 struct Cookie **array;
1268 size_t i;
1269
1270 /* alloc an array and store all cookie pointers */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001271 array = malloc(sizeof(struct Cookie *) * matches);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001272 if(!array)
1273 goto fail;
1274
1275 co = mainco;
1276
Alex Deymo486467e2017-12-19 19:04:07 +01001277 for(i = 0; co; co = co->next)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001278 array[i++] = co;
1279
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001280 /* now sort the cookie pointers in path length order */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001281 qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
1282
1283 /* remake the linked list order according to the new order */
1284
1285 mainco = array[0]; /* start here */
Alex Deymo486467e2017-12-19 19:04:07 +01001286 for(i = 0; i<matches-1; i++)
1287 array[i]->next = array[i + 1];
Kristian Monsen5ab50182010-05-14 18:53:44 +01001288 array[matches-1]->next = NULL; /* terminate the list */
1289
1290 free(array); /* remove the temporary data again */
1291 }
1292
1293 return mainco; /* return the new list */
1294}
1295
1296/*****************************************************************************
1297 *
1298 * Curl_cookie_clearall()
1299 *
1300 * Clear all existing cookies and reset the counter.
1301 *
1302 ****************************************************************************/
1303void Curl_cookie_clearall(struct CookieInfo *cookies)
1304{
1305 if(cookies) {
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001306 unsigned int i;
1307 for(i = 0; i < COOKIE_HASH_SIZE; i++) {
1308 Curl_cookie_freelist(cookies->cookies[i]);
1309 cookies->cookies[i] = NULL;
1310 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001311 cookies->numcookies = 0;
1312 }
1313}
1314
1315/*****************************************************************************
1316 *
1317 * Curl_cookie_freelist()
1318 *
1319 * Free a list of cookies previously returned by Curl_cookie_getlist();
1320 *
Kristian Monsen5ab50182010-05-14 18:53:44 +01001321 ****************************************************************************/
1322
Elliott Hughescee03382017-06-23 12:17:18 -07001323void Curl_cookie_freelist(struct Cookie *co)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001324{
1325 struct Cookie *next;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001326 while(co) {
1327 next = co->next;
Elliott Hughescee03382017-06-23 12:17:18 -07001328 freecookie(co);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001329 co = next;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001330 }
1331}
1332
1333
1334/*****************************************************************************
1335 *
1336 * Curl_cookie_clearsess()
1337 *
1338 * Free all session cookies in the cookies list.
1339 *
1340 ****************************************************************************/
1341void Curl_cookie_clearsess(struct CookieInfo *cookies)
1342{
1343 struct Cookie *first, *curr, *next, *prev = NULL;
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001344 unsigned int i;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001345
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001346 if(!cookies)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001347 return;
1348
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001349 for(i = 0; i < COOKIE_HASH_SIZE; i++) {
1350 if(!cookies->cookies[i])
1351 continue;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001352
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001353 first = curr = prev = cookies->cookies[i];
Kristian Monsen5ab50182010-05-14 18:53:44 +01001354
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001355 for(; curr; curr = next) {
1356 next = curr->next;
1357 if(!curr->expires) {
1358 if(first == curr)
1359 first = next;
1360
1361 if(prev == curr)
1362 prev = next;
1363 else
1364 prev->next = next;
1365
1366 freecookie(curr);
1367 cookies->numcookies--;
1368 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001369 else
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001370 prev = curr;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001371 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001372
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001373 cookies->cookies[i] = first;
1374 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001375}
1376
1377
1378/*****************************************************************************
1379 *
1380 * Curl_cookie_cleanup()
1381 *
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001382 * Free a "cookie object" previous created with Curl_cookie_init().
Kristian Monsen5ab50182010-05-14 18:53:44 +01001383 *
1384 ****************************************************************************/
1385void Curl_cookie_cleanup(struct CookieInfo *c)
1386{
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001387 unsigned int i;
1388
Kristian Monsen5ab50182010-05-14 18:53:44 +01001389 if(c) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001390 free(c->filename);
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001391 for(i = 0; i < COOKIE_HASH_SIZE; i++)
1392 Curl_cookie_freelist(c->cookies[i]);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001393 free(c); /* free the base struct as well */
1394 }
1395}
1396
1397/* get_netscape_format()
1398 *
1399 * Formats a string for Netscape output file, w/o a newline at the end.
1400 *
1401 * Function returns a char * to a formatted line. Has to be free()d
1402*/
1403static char *get_netscape_format(const struct Cookie *co)
1404{
1405 return aprintf(
1406 "%s" /* httponly preamble */
1407 "%s%s\t" /* domain */
1408 "%s\t" /* tailmatch */
1409 "%s\t" /* path */
1410 "%s\t" /* secure */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001411 "%" CURL_FORMAT_CURL_OFF_T "\t" /* expires */
Kristian Monsen5ab50182010-05-14 18:53:44 +01001412 "%s\t" /* name */
1413 "%s", /* value */
1414 co->httponly?"#HttpOnly_":"",
1415 /* Make sure all domains are prefixed with a dot if they allow
1416 tailmatching. This is Mozilla-style. */
1417 (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
1418 co->domain?co->domain:"unknown",
1419 co->tailmatch?"TRUE":"FALSE",
1420 co->path?co->path:"/",
1421 co->secure?"TRUE":"FALSE",
1422 co->expires,
1423 co->name,
1424 co->value?co->value:"");
1425}
1426
1427/*
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001428 * cookie_output()
Kristian Monsen5ab50182010-05-14 18:53:44 +01001429 *
1430 * Writes all internally known cookies to the specified file. Specify
1431 * "-" as file name to write to stdout.
1432 *
1433 * The function returns non-zero on write failure.
1434 */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001435static int cookie_output(struct CookieInfo *c, const char *dumphere)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001436{
1437 struct Cookie *co;
1438 FILE *out;
Alex Deymo486467e2017-12-19 19:04:07 +01001439 bool use_stdout = FALSE;
Alex Deymod15eaac2016-06-28 14:49:26 -07001440 char *format_ptr;
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001441 unsigned int i;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001442
1443 if((NULL == c) || (0 == c->numcookies))
1444 /* If there are no known cookies, we don't write or even create any
1445 destination file */
1446 return 0;
1447
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001448 /* at first, remove expired cookies */
1449 remove_expired(c);
1450
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001451 /* make sure we still have cookies after expiration */
1452 if(0 == c->numcookies)
1453 return 0;
1454
Elliott Hughescee03382017-06-23 12:17:18 -07001455 if(!strcmp("-", dumphere)) {
Kristian Monsen5ab50182010-05-14 18:53:44 +01001456 /* use stdout */
1457 out = stdout;
Alex Deymo486467e2017-12-19 19:04:07 +01001458 use_stdout = TRUE;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001459 }
1460 else {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001461 out = fopen(dumphere, FOPEN_WRITETEXT);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001462 if(!out)
1463 return 1; /* failure */
1464 }
1465
Alex Deymod15eaac2016-06-28 14:49:26 -07001466 fputs("# Netscape HTTP Cookie File\n"
1467 "# https://curl.haxx.se/docs/http-cookies.html\n"
1468 "# This file was generated by libcurl! Edit at your own risk.\n\n",
1469 out);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001470
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001471 for(i = 0; i < COOKIE_HASH_SIZE; i++) {
1472 for(co = c->cookies[i]; co; co = co->next) {
1473 if(!co->domain)
1474 continue;
1475 format_ptr = get_netscape_format(co);
1476 if(format_ptr == NULL) {
1477 fprintf(out, "#\n# Fatal libcurl error\n");
1478 if(!use_stdout)
1479 fclose(out);
1480 return 1;
1481 }
1482 fprintf(out, "%s\n", format_ptr);
1483 free(format_ptr);
Kristian Monsen5ab50182010-05-14 18:53:44 +01001484 }
1485 }
1486
1487 if(!use_stdout)
1488 fclose(out);
1489
1490 return 0;
1491}
1492
Alex Deymo486467e2017-12-19 19:04:07 +01001493static struct curl_slist *cookie_list(struct Curl_easy *data)
Kristian Monsen5ab50182010-05-14 18:53:44 +01001494{
1495 struct curl_slist *list = NULL;
1496 struct curl_slist *beg;
1497 struct Cookie *c;
1498 char *line;
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001499 unsigned int i;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001500
1501 if((data->cookies == NULL) ||
1502 (data->cookies->numcookies == 0))
1503 return NULL;
1504
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001505 for(i = 0; i < COOKIE_HASH_SIZE; i++) {
1506 for(c = data->cookies->cookies[i]; c; c = c->next) {
1507 if(!c->domain)
1508 continue;
1509 line = get_netscape_format(c);
1510 if(!line) {
1511 curl_slist_free_all(list);
1512 return NULL;
1513 }
1514 beg = Curl_slist_append_nodup(list, line);
1515 if(!beg) {
1516 free(line);
1517 curl_slist_free_all(list);
1518 return NULL;
1519 }
1520 list = beg;
Kristian Monsen5ab50182010-05-14 18:53:44 +01001521 }
Kristian Monsen5ab50182010-05-14 18:53:44 +01001522 }
1523
1524 return list;
1525}
1526
Alex Deymo486467e2017-12-19 19:04:07 +01001527struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
1528{
1529 struct curl_slist *list;
1530 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1531 list = cookie_list(data);
1532 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
1533 return list;
1534}
1535
Alex Deymoe3149cc2016-10-05 11:18:42 -07001536void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001537{
1538 if(data->set.str[STRING_COOKIEJAR]) {
1539 if(data->change.cookielist) {
1540 /* If there is a list of cookie files to read, do it first so that
1541 we have all the told files read before we write the new jar.
1542 Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
1543 Curl_cookie_loadfiles(data);
1544 }
1545
1546 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1547
1548 /* if we have a destination file for all the cookies to get dumped to */
1549 if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
1550 infof(data, "WARNING: failed to save cookies in %s\n",
1551 data->set.str[STRING_COOKIEJAR]);
1552 }
1553 else {
1554 if(cleanup && data->change.cookielist) {
1555 /* since nothing is written, we can just free the list of cookie file
1556 names */
1557 curl_slist_free_all(data->change.cookielist); /* clean up list */
1558 data->change.cookielist = NULL;
1559 }
1560 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1561 }
1562
1563 if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
1564 Curl_cookie_cleanup(data->cookies);
1565 }
1566 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
1567}
1568
Kristian Monsen5ab50182010-05-14 18:53:44 +01001569#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */