00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 #include "setup.h"
00082
00083 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
00084
00085 #include <stdlib.h>
00086 #include <string.h>
00087
00088 #define _MPRINTF_REPLACE
00089 #include <curl/mprintf.h>
00090
00091 #include "urldata.h"
00092 #include "cookie.h"
00093 #include "strequal.h"
00094 #include "strtok.h"
00095 #include "sendf.h"
00096 #include "memory.h"
00097 #include "share.h"
00098 #include "strtoofft.h"
00099
00100
00101 #ifdef CURLDEBUG
00102 #include "memdebug.h"
00103 #endif
00104
00105
00106 static void freecookie(struct Cookie *co)
00107 {
00108 if(co->expirestr)
00109 free(co->expirestr);
00110 if(co->domain)
00111 free(co->domain);
00112 if(co->path)
00113 free(co->path);
00114 if(co->name)
00115 free(co->name);
00116 if(co->value)
00117 free(co->value);
00118 if(co->maxage)
00119 free(co->maxage);
00120 if(co->version)
00121 free(co->version);
00122
00123 free(co);
00124 }
00125
00126 static bool tailmatch(const char *little, const char *bigone)
00127 {
00128 size_t littlelen = strlen(little);
00129 size_t biglen = strlen(bigone);
00130
00131 if(littlelen > biglen)
00132 return FALSE;
00133
00134 return (bool)strequal(little, bigone+biglen-littlelen);
00135 }
00136
00137
00138
00139
00140 void Curl_cookie_loadfiles(struct SessionHandle *data)
00141 {
00142 struct curl_slist *list = data->change.cookielist;
00143 if(list) {
00144 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
00145 while(list) {
00146 data->cookies = Curl_cookie_init(data,
00147 list->data,
00148 data->cookies,
00149 data->set.cookiesession);
00150 list = list->next;
00151 }
00152 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
00153 curl_slist_free_all(data->change.cookielist);
00154 data->change.cookielist = NULL;
00155 }
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 struct Cookie *
00167 Curl_cookie_add(struct SessionHandle *data,
00168
00169
00170
00171
00172 struct CookieInfo *c,
00173 bool httpheader,
00174 char *lineptr,
00175 char *domain,
00176 char *path)
00177
00178
00179 {
00180 struct Cookie *clist;
00181 char *what;
00182 char name[MAX_NAME];
00183 char *ptr;
00184 char *semiptr;
00185 struct Cookie *co;
00186 struct Cookie *lastc=NULL;
00187 time_t now = time(NULL);
00188 bool replace_old = FALSE;
00189 bool badcookie = FALSE;
00190
00191 #ifdef CURL_DISABLE_VERBOSE_STRINGS
00192 (void)data;
00193 #endif
00194
00195
00196 co = (struct Cookie *)calloc(sizeof(struct Cookie), 1);
00197 if(!co)
00198 return NULL;
00199
00200 if(httpheader) {
00201
00202 char *sep;
00203
00204 what = malloc(MAX_COOKIE_LINE);
00205 if(!what) {
00206 free(co);
00207 return NULL;
00208 }
00209
00210 semiptr=strchr(lineptr, ';');
00211
00212 while(*lineptr && ISBLANK(*lineptr))
00213 lineptr++;
00214
00215 ptr = lineptr;
00216 do {
00217
00218 sep = strchr(ptr, '=');
00219 if(sep && (!semiptr || (semiptr>sep)) ) {
00220
00221
00222
00223
00224
00225 name[0]=what[0]=0;
00226 if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
00227 MAX_COOKIE_LINE_TXT "[^;\r\n]",
00228 name, what)) {
00229
00230
00231 char *whatptr;
00232
00233
00234 size_t len=strlen(what);
00235 while(len && ISBLANK(what[len-1])) {
00236 what[len-1]=0;
00237 len--;
00238 }
00239
00240
00241 whatptr=what;
00242 while(*whatptr && ISBLANK(*whatptr)) {
00243 whatptr++;
00244 }
00245
00246 if(strequal("path", name)) {
00247 co->path=strdup(whatptr);
00248 if(!co->path) {
00249 badcookie = TRUE;
00250 break;
00251 }
00252 }
00253 else if(strequal("domain", name)) {
00254
00255
00256
00257 const char *domptr=whatptr;
00258 int dotcount=1;
00259
00260
00261
00262
00263 if('.' == whatptr[0])
00264
00265 domptr++;
00266
00267 do {
00268 domptr = strchr(domptr, '.');
00269 if(domptr) {
00270 domptr++;
00271 dotcount++;
00272 }
00273 } while(domptr);
00274
00275
00276
00277
00278
00279
00280
00281 if(dotcount < 2) {
00282
00283
00284 badcookie=TRUE;
00285 infof(data, "skipped cookie with illegal dotcount domain: %s\n",
00286 whatptr);
00287 }
00288 else {
00289
00290
00291
00292 if('.' == whatptr[0])
00293 whatptr++;
00294
00295 if(!domain || tailmatch(whatptr, domain)) {
00296 const char *tailptr=whatptr;
00297 if(tailptr[0] == '.')
00298 tailptr++;
00299 co->domain=strdup(tailptr);
00300
00301 if(!co->domain) {
00302 badcookie = TRUE;
00303 break;
00304 }
00305 co->tailmatch=TRUE;
00306
00307 }
00308 else {
00309
00310
00311
00312 badcookie=TRUE;
00313 infof(data, "skipped cookie with bad tailmatch domain: %s\n",
00314 whatptr);
00315 }
00316 }
00317 }
00318 else if(strequal("version", name)) {
00319 co->version=strdup(whatptr);
00320 if(!co->version) {
00321 badcookie = TRUE;
00322 break;
00323 }
00324 }
00325 else if(strequal("max-age", name)) {
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 co->maxage = strdup(whatptr);
00336 if(!co->maxage) {
00337 badcookie = TRUE;
00338 break;
00339 }
00340 co->expires =
00341 atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + (long)now;
00342 }
00343 else if(strequal("expires", name)) {
00344 co->expirestr=strdup(whatptr);
00345 if(!co->expirestr) {
00346 badcookie = TRUE;
00347 break;
00348 }
00349 co->expires = curl_getdate(what, &now);
00350 }
00351 else if(!co->name) {
00352 co->name = strdup(name);
00353 co->value = strdup(whatptr);
00354 if(!co->name || !co->value) {
00355 badcookie = TRUE;
00356 break;
00357 }
00358 }
00359
00360
00361
00362 }
00363 else {
00364
00365 }
00366 }
00367 else {
00368 if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
00369 what)) {
00370 if(strequal("secure", what))
00371 co->secure = TRUE;
00372
00373
00374
00375 }
00376 }
00377 if(!semiptr || !*semiptr) {
00378
00379 semiptr = NULL;
00380 continue;
00381 }
00382
00383 ptr=semiptr+1;
00384 while(ptr && *ptr && ISBLANK(*ptr))
00385 ptr++;
00386 semiptr=strchr(ptr, ';');
00387
00388 if(!semiptr && *ptr)
00389
00390
00391 semiptr=strchr(ptr, '\0');
00392 } while(semiptr);
00393
00394 if(!badcookie && !co->domain) {
00395 if(domain) {
00396
00397 co->domain=strdup(domain);
00398 if(!co->domain)
00399 badcookie = TRUE;
00400 }
00401 }
00402
00403 if(!badcookie && !co->path && path) {
00404
00405 char *endslash = strrchr(path, '/');
00406 if(endslash) {
00407 size_t pathlen = endslash-path+1;
00408 co->path=malloc(pathlen+1);
00409 if(co->path) {
00410 memcpy(co->path, path, pathlen);
00411 co->path[pathlen]=0;
00412 }
00413 else
00414 badcookie = TRUE;
00415 }
00416 }
00417
00418 free(what);
00419
00420 if(badcookie || !co->name) {
00421
00422
00423 freecookie(co);
00424 return NULL;
00425 }
00426
00427 }
00428 else {
00429
00430
00431 char *firstptr;
00432 char *tok_buf;
00433 int fields;
00434
00435 if(lineptr[0]=='#') {
00436
00437 free(co);
00438 return NULL;
00439 }
00440
00441 ptr=strchr(lineptr, '\r');
00442 if(ptr)
00443 *ptr=0;
00444 ptr=strchr(lineptr, '\n');
00445 if(ptr)
00446 *ptr=0;
00447
00448 firstptr=strtok_r(lineptr, "\t", &tok_buf);
00449
00450
00451 if(!firstptr || strchr(firstptr, ':')) {
00452 free(co);
00453 return NULL;
00454 }
00455
00456
00457
00458 for(ptr=firstptr, fields=0; ptr && !badcookie;
00459 ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
00460 switch(fields) {
00461 case 0:
00462 if(ptr[0]=='.')
00463 ptr++;
00464 co->domain = strdup(ptr);
00465 if(!co->domain)
00466 badcookie = TRUE;
00467 break;
00468 case 1:
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 co->tailmatch=(bool)strequal(ptr, "TRUE");
00480 break;
00481 case 2:
00482
00483
00484
00485 if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
00486
00487 co->path = strdup(ptr);
00488 if(!co->path)
00489 badcookie = TRUE;
00490 break;
00491 }
00492
00493 co->path = strdup("/");
00494 if(!co->path)
00495 badcookie = TRUE;
00496 fields++;
00497
00498 case 3:
00499 co->secure = (bool)strequal(ptr, "TRUE");
00500 break;
00501 case 4:
00502 co->expires = curlx_strtoofft(ptr, NULL, 10);
00503 break;
00504 case 5:
00505 co->name = strdup(ptr);
00506 if(!co->name)
00507 badcookie = TRUE;
00508 break;
00509 case 6:
00510 co->value = strdup(ptr);
00511 if(!co->value)
00512 badcookie = TRUE;
00513 break;
00514 }
00515 }
00516 if(6 == fields) {
00517
00518 co->value = strdup("");
00519 if(!co->value)
00520 badcookie = TRUE;
00521 else
00522 fields++;
00523 }
00524
00525 if(!badcookie && (7 != fields))
00526
00527 badcookie = TRUE;
00528
00529 if(badcookie) {
00530 freecookie(co);
00531 return NULL;
00532 }
00533
00534 }
00535
00536 if(!c->running &&
00537 c->newsession &&
00538 !co->expires) {
00539 freecookie(co);
00540 return NULL;
00541 }
00542
00543 co->livecookie = c->running;
00544
00545
00546
00547
00548
00549 clist = c->cookies;
00550 replace_old = FALSE;
00551 while(clist) {
00552 if(strequal(clist->name, co->name)) {
00553
00554
00555 if(clist->domain && co->domain) {
00556 if(strequal(clist->domain, co->domain))
00557
00558 replace_old=TRUE;
00559 }
00560 else if(!clist->domain && !co->domain)
00561 replace_old = TRUE;
00562
00563 if(replace_old) {
00564
00565
00566 if(clist->path && co->path) {
00567 if(strequal(clist->path, co->path)) {
00568 replace_old = TRUE;
00569 }
00570 else
00571 replace_old = FALSE;
00572 }
00573 else if(!clist->path && !co->path)
00574 replace_old = TRUE;
00575 else
00576 replace_old = FALSE;
00577
00578 }
00579
00580 if(replace_old && !co->livecookie && clist->livecookie) {
00581
00582
00583
00584
00585
00586
00587 freecookie(co);
00588 return NULL;
00589 }
00590
00591 if(replace_old) {
00592 co->next = clist->next;
00593
00594
00595 if(clist->name)
00596 free(clist->name);
00597 if(clist->value)
00598 free(clist->value);
00599 if(clist->domain)
00600 free(clist->domain);
00601 if(clist->path)
00602 free(clist->path);
00603 if(clist->expirestr)
00604 free(clist->expirestr);
00605
00606 if(clist->version)
00607 free(clist->version);
00608 if(clist->maxage)
00609 free(clist->maxage);
00610
00611 *clist = *co;
00612
00613 free(co);
00614 co = clist;
00615
00616
00617
00618 do {
00619 lastc = clist;
00620 clist = clist->next;
00621 } while(clist);
00622 break;
00623 }
00624 }
00625 lastc = clist;
00626 clist = clist->next;
00627 }
00628
00629 if(c->running)
00630
00631 infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
00632 replace_old?"Replaced":"Added", co->name, co->value,
00633 co->domain, co->path, co->expires);
00634
00635 if(!replace_old) {
00636
00637 if(lastc)
00638 lastc->next = co;
00639 else
00640 c->cookies = co;
00641 }
00642
00643 c->numcookies++;
00644 return co;
00645 }
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
00658 char *file,
00659 struct CookieInfo *inc,
00660 bool newsession)
00661 {
00662 struct CookieInfo *c;
00663 FILE *fp;
00664 bool fromfile=TRUE;
00665
00666 if(NULL == inc) {
00667
00668 c = (struct CookieInfo *)calloc(1, sizeof(struct CookieInfo));
00669 if(!c)
00670 return NULL;
00671 c->filename = strdup(file?file:"none");
00672 }
00673 else {
00674
00675 c = inc;
00676 }
00677 c->running = FALSE;
00678
00679 if(file && strequal(file, "-")) {
00680 fp = stdin;
00681 fromfile=FALSE;
00682 }
00683 else if(file && !*file) {
00684
00685 fp = NULL;
00686 }
00687 else
00688 fp = file?fopen(file, "r"):NULL;
00689
00690 c->newsession = newsession;
00691
00692 if(fp) {
00693 char *lineptr;
00694 bool headerline;
00695
00696 char *line = (char *)malloc(MAX_COOKIE_LINE);
00697 if(line) {
00698 while(fgets(line, MAX_COOKIE_LINE, fp)) {
00699 if(checkprefix("Set-Cookie:", line)) {
00700
00701 lineptr=&line[11];
00702 headerline=TRUE;
00703 }
00704 else {
00705 lineptr=line;
00706 headerline=FALSE;
00707 }
00708 while(*lineptr && ISBLANK(*lineptr))
00709 lineptr++;
00710
00711 Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
00712 }
00713 free(line);
00714 }
00715 if(fromfile)
00716 fclose(fp);
00717 }
00718
00719 c->running = TRUE;
00720
00721 return c;
00722 }
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
00737 char *host, char *path, bool secure)
00738 {
00739 struct Cookie *newco;
00740 struct Cookie *co;
00741 time_t now = time(NULL);
00742 struct Cookie *mainco=NULL;
00743
00744 if(!c || !c->cookies)
00745 return NULL;
00746
00747 co = c->cookies;
00748
00749 while(co) {
00750
00751
00752
00753 if( (co->expires<=0 || (co->expires> now)) &&
00754 (co->secure?secure:TRUE) ) {
00755
00756
00757 if(!co->domain ||
00758 (co->tailmatch && tailmatch(co->domain, host)) ||
00759 (!co->tailmatch && strequal(host, co->domain)) ) {
00760
00761
00762
00763
00764
00765 if(!co->path ||
00766
00767
00768 !strncmp(co->path, path, strlen(co->path)) ) {
00769
00770
00771
00772
00773 newco = (struct Cookie *)malloc(sizeof(struct Cookie));
00774 if(newco) {
00775
00776 memcpy(newco, co, sizeof(struct Cookie));
00777
00778
00779 newco->next = mainco;
00780
00781
00782 mainco = newco;
00783 }
00784 else {
00785
00786 while(mainco) {
00787 co = mainco->next;
00788 free(mainco);
00789 mainco = co;
00790 }
00791
00792 return NULL;
00793 }
00794 }
00795 }
00796 }
00797 co = co->next;
00798 }
00799
00800 return mainco;
00801 }
00802
00803
00804
00805
00806
00807
00808
00809
00810 void Curl_cookie_clearall(struct CookieInfo *cookies)
00811 {
00812 if(cookies) {
00813 Curl_cookie_freelist(cookies->cookies);
00814 cookies->cookies = NULL;
00815 cookies->numcookies = 0;
00816 }
00817 }
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 void Curl_cookie_freelist(struct Cookie *co)
00828 {
00829 struct Cookie *next;
00830 if(co) {
00831 while(co) {
00832 next = co->next;
00833 free(co);
00834
00835 co = next;
00836 }
00837 }
00838 }
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848 void Curl_cookie_clearsess(struct CookieInfo *cookies)
00849 {
00850 struct Cookie *first, *curr, *next, *prev = NULL;
00851
00852 if(!cookies->cookies)
00853 return;
00854
00855 first = curr = prev = cookies->cookies;
00856
00857 for(; curr; curr = next) {
00858 next = curr->next;
00859 if(!curr->expires) {
00860 if(first == curr)
00861 first = next;
00862
00863 if(prev == curr)
00864 prev = next;
00865 else
00866 prev->next = next;
00867
00868 free(curr);
00869 cookies->numcookies--;
00870 }
00871 else
00872 prev = curr;
00873 }
00874
00875 cookies->cookies = first;
00876 }
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886 void Curl_cookie_cleanup(struct CookieInfo *c)
00887 {
00888 struct Cookie *co;
00889 struct Cookie *next;
00890 if(c) {
00891 if(c->filename)
00892 free(c->filename);
00893 co = c->cookies;
00894
00895 while(co) {
00896 next = co->next;
00897 freecookie(co);
00898 co = next;
00899 }
00900 free(c);
00901 }
00902 }
00903
00904
00905
00906
00907
00908
00909
00910 static char *get_netscape_format(const struct Cookie *co)
00911 {
00912 return aprintf(
00913 "%s%s\t"
00914 "%s\t"
00915 "%s\t"
00916 "%s\t"
00917 "%" FORMAT_OFF_T "\t"
00918 "%s\t"
00919 "%s",
00920
00921
00922 (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
00923 co->domain?co->domain:"unknown",
00924 co->tailmatch?"TRUE":"FALSE",
00925 co->path?co->path:"/",
00926 co->secure?"TRUE":"FALSE",
00927 co->expires,
00928 co->name,
00929 co->value?co->value:"");
00930 }
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940 int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
00941 {
00942 struct Cookie *co;
00943 FILE *out;
00944 bool use_stdout=FALSE;
00945
00946 if((NULL == c) || (0 == c->numcookies))
00947
00948
00949 return 0;
00950
00951 if(strequal("-", dumphere)) {
00952
00953 out = stdout;
00954 use_stdout=TRUE;
00955 }
00956 else {
00957 out = fopen(dumphere, "w");
00958 if(!out)
00959 return 1;
00960 }
00961
00962 if(c) {
00963 char *format_ptr;
00964
00965 fputs("# Netscape HTTP Cookie File\n"
00966 "# http://curlm.haxx.se/rfc/cookie_spec.html\n"
00967 "# This file was generated by libcurl! Edit at your own risk.\n\n",
00968 out);
00969 co = c->cookies;
00970
00971 while(co) {
00972 format_ptr = get_netscape_format(co);
00973 if (format_ptr == NULL) {
00974 fprintf(out, "#\n# Fatal libcurl error\n");
00975 fclose(out);
00976 return 1;
00977 }
00978 fprintf(out, "%s\n", format_ptr);
00979 free(format_ptr);
00980 co=co->next;
00981 }
00982 }
00983
00984 if(!use_stdout)
00985 fclose(out);
00986
00987 return 0;
00988 }
00989
00990 struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
00991 {
00992 struct curl_slist *list = NULL;
00993 struct curl_slist *beg;
00994 struct Cookie *c;
00995 char *line;
00996
00997 if ((data->cookies == NULL) ||
00998 (data->cookies->numcookies == 0))
00999 return NULL;
01000
01001 c = data->cookies->cookies;
01002
01003 beg = list;
01004 while (c) {
01005
01006 line = get_netscape_format(c);
01007 if (line == NULL) {
01008 curl_slist_free_all(beg);
01009 return NULL;
01010 }
01011 list = curl_slist_append(list, line);
01012 free(line);
01013 if (list == NULL) {
01014 curl_slist_free_all(beg);
01015 return NULL;
01016 }
01017 else if (beg == NULL) {
01018 beg = list;
01019 }
01020 c = c->next;
01021 }
01022
01023 return list;
01024 }
01025
01026 #endif