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