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