1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23/***
24
25
26RECEIVING COOKIE INFORMATION
27============================
28
29struct CookieInfo *cookie_init(char *file);
30
31        Inits a cookie struct to store data in a local file. This is always
32        called before any cookies are set.
33
34int cookies_set(struct CookieInfo *cookie, char *cookie_line);
35
36        The 'cookie_line' parameter is a full "Set-cookie:" line as
37        received from a server.
38
39        The function need to replace previously stored lines that this new
40        line superceeds.
41
42        It may remove lines that are expired.
43
44        It should return an indication of success/error.
45
46
47SENDING COOKIE INFORMATION
48==========================
49
50struct Cookies *cookie_getlist(struct CookieInfo *cookie,
51                               char *host, char *path, bool secure);
52
53        For a given host and path, return a linked list of cookies that
54        the client should send to the server if used now. The secure
55        boolean informs the cookie if a secure connection is achieved or
56        not.
57
58        It shall only return cookies that haven't expired.
59
60
61Example set of cookies:
62
63    Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
64    Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
65    domain=.fidelity.com; path=/ftgw; secure
66    Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
67    domain=.fidelity.com; path=/; secure
68    Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
69    domain=.fidelity.com; path=/; secure
70    Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
71    domain=.fidelity.com; path=/; secure
72    Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
73    domain=.fidelity.com; path=/; secure
74    Set-cookie:
75    Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
76    13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
77****/
78
79
80#include "curl_setup.h"
81
82#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
83
84#define _MPRINTF_REPLACE
85#include <curl/mprintf.h>
86
87#include "urldata.h"
88#include "cookie.h"
89#include "strequal.h"
90#include "strtok.h"
91#include "sendf.h"
92#include "curl_memory.h"
93#include "share.h"
94#include "strtoofft.h"
95#include "rawstr.h"
96#include "curl_memrchr.h"
97
98/* The last #include file should be: */
99#include "memdebug.h"
100
101static void freecookie(struct Cookie *co)
102{
103  if(co->expirestr)
104    free(co->expirestr);
105  if(co->domain)
106    free(co->domain);
107  if(co->path)
108    free(co->path);
109  if(co->name)
110    free(co->name);
111  if(co->value)
112    free(co->value);
113  if(co->maxage)
114    free(co->maxage);
115  if(co->version)
116    free(co->version);
117
118  free(co);
119}
120
121static bool tailmatch(const char *cooke_domain, const char *hostname)
122{
123  size_t cookie_domain_len = strlen(cooke_domain);
124  size_t hostname_len = strlen(hostname);
125
126  if(hostname_len < cookie_domain_len)
127    return FALSE;
128
129  if(!Curl_raw_equal(cooke_domain, hostname+hostname_len-cookie_domain_len))
130    return FALSE;
131
132  /* A lead char of cookie_domain is not '.'.
133     RFC6265 4.1.2.3. The Domain Attribute says:
134       For example, if the value of the Domain attribute is
135       "example.com", the user agent will include the cookie in the Cookie
136       header when making HTTP requests to example.com, www.example.com, and
137       www.corp.example.com.
138   */
139  if(hostname_len == cookie_domain_len)
140    return TRUE;
141  if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
142    return TRUE;
143  return FALSE;
144}
145
146/*
147 * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
148 */
149void Curl_cookie_loadfiles(struct SessionHandle *data)
150{
151  struct curl_slist *list = data->change.cookielist;
152  if(list) {
153    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
154    while(list) {
155      data->cookies = Curl_cookie_init(data,
156                                       list->data,
157                                       data->cookies,
158                                       data->set.cookiesession);
159      list = list->next;
160    }
161    curl_slist_free_all(data->change.cookielist); /* clean up list */
162    data->change.cookielist = NULL; /* don't do this again! */
163    Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
164  }
165}
166
167/*
168 * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL
169 * that will be freed before the allocated string is stored there.
170 *
171 * It is meant to easily replace strdup()
172 */
173static void strstore(char **str, const char *newstr)
174{
175  if(*str)
176    free(*str);
177  *str = strdup(newstr);
178}
179
180
181/****************************************************************************
182 *
183 * Curl_cookie_add()
184 *
185 * Add a single cookie line to the cookie keeping object.
186 *
187 ***************************************************************************/
188
189struct Cookie *
190Curl_cookie_add(struct SessionHandle *data,
191                /* The 'data' pointer here may be NULL at times, and thus
192                   must only be used very carefully for things that can deal
193                   with data being NULL. Such as infof() and similar */
194
195                struct CookieInfo *c,
196                bool httpheader, /* TRUE if HTTP header-style line */
197                char *lineptr,   /* first character of the line */
198                const char *domain, /* default domain */
199                const char *path)   /* full path used when this cookie is set,
200                                       used to get default path for the cookie
201                                       unless set */
202{
203  struct Cookie *clist;
204  char name[MAX_NAME];
205  struct Cookie *co;
206  struct Cookie *lastc=NULL;
207  time_t now = time(NULL);
208  bool replace_old = FALSE;
209  bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
210
211#ifdef CURL_DISABLE_VERBOSE_STRINGS
212  (void)data;
213#endif
214
215  /* First, alloc and init a new struct for it */
216  co = calloc(1, sizeof(struct Cookie));
217  if(!co)
218    return NULL; /* bail out if we're this low on memory */
219
220  if(httpheader) {
221    /* This line was read off a HTTP-header */
222    const char *ptr;
223    const char *semiptr;
224    char *what;
225
226    what = malloc(MAX_COOKIE_LINE);
227    if(!what) {
228      free(co);
229      return NULL;
230    }
231
232    semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
233
234    while(*lineptr && ISBLANK(*lineptr))
235      lineptr++;
236
237    ptr = lineptr;
238    do {
239      /* we have a <what>=<this> pair or a stand-alone word here */
240      name[0]=what[0]=0; /* init the buffers */
241      if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n =]=%"
242                     MAX_COOKIE_LINE_TXT "[^;\r\n]",
243                     name, what)) {
244        /* Use strstore() below to properly deal with received cookie
245           headers that have the same string property set more than once,
246           and then we use the last one. */
247        const char *whatptr;
248        bool done = FALSE;
249        bool sep;
250        size_t len=strlen(what);
251        const char *endofn = &ptr[ strlen(name) ];
252
253        /* skip trailing spaces in name */
254        while(*endofn && ISBLANK(*endofn))
255          endofn++;
256
257        /* name ends with a '=' ? */
258        sep = (*endofn == '=')?TRUE:FALSE;
259
260        /* Strip off trailing whitespace from the 'what' */
261        while(len && ISBLANK(what[len-1])) {
262          what[len-1]=0;
263          len--;
264        }
265
266        /* Skip leading whitespace from the 'what' */
267        whatptr=what;
268        while(*whatptr && ISBLANK(*whatptr))
269          whatptr++;
270
271        if(!len) {
272          /* this was a "<name>=" with no content, and we must allow
273             'secure' and 'httponly' specified this weirdly */
274          done = TRUE;
275          if(Curl_raw_equal("secure", name))
276            co->secure = TRUE;
277          else if(Curl_raw_equal("httponly", name))
278            co->httponly = TRUE;
279          else if(sep)
280            /* there was a '=' so we're not done parsing this field */
281            done = FALSE;
282        }
283        if(done)
284          ;
285        else if(Curl_raw_equal("path", name)) {
286          strstore(&co->path, whatptr);
287          if(!co->path) {
288            badcookie = TRUE; /* out of memory bad */
289            break;
290          }
291        }
292        else if(Curl_raw_equal("domain", name)) {
293          /* note that this name may or may not have a preceding dot, but
294             we don't care about that, we treat the names the same anyway */
295
296          const char *domptr=whatptr;
297          const char *nextptr;
298          int dotcount=1;
299
300          /* Count the dots, we need to make sure that there are enough
301             of them. */
302
303          if('.' == whatptr[0])
304            /* don't count the initial dot, assume it */
305            domptr++;
306
307          do {
308            nextptr = strchr(domptr, '.');
309            if(nextptr) {
310              if(domptr != nextptr)
311                dotcount++;
312              domptr = nextptr+1;
313            }
314          } while(nextptr);
315
316          /* The original Netscape cookie spec defined that this domain name
317             MUST have three dots (or two if one of the seven holy TLDs),
318             but it seems that these kinds of cookies are in use "out there"
319             so we cannot be that strict. I've therefore lowered the check
320             to not allow less than two dots. */
321
322          if(dotcount < 2) {
323            /* Received and skipped a cookie with a domain using too few
324               dots. */
325            badcookie=TRUE; /* mark this as a bad cookie */
326            infof(data, "skipped cookie with illegal dotcount domain: %s\n",
327                  whatptr);
328          }
329          else {
330            /* Now, we make sure that our host is within the given domain,
331               or the given domain is not valid and thus cannot be set. */
332
333            if('.' == whatptr[0])
334              whatptr++; /* ignore preceding dot */
335
336            if(!domain || tailmatch(whatptr, domain)) {
337              const char *tailptr=whatptr;
338              if(tailptr[0] == '.')
339                tailptr++;
340              strstore(&co->domain, tailptr); /* don't prefix w/dots
341                                                 internally */
342              if(!co->domain) {
343                badcookie = TRUE;
344                break;
345              }
346              co->tailmatch=TRUE; /* we always do that if the domain name was
347                                     given */
348            }
349            else {
350              /* we did not get a tailmatch and then the attempted set domain
351                 is not a domain to which the current host belongs. Mark as
352                 bad. */
353              badcookie=TRUE;
354              infof(data, "skipped cookie with bad tailmatch domain: %s\n",
355                    whatptr);
356            }
357          }
358        }
359        else if(Curl_raw_equal("version", name)) {
360          strstore(&co->version, whatptr);
361          if(!co->version) {
362            badcookie = TRUE;
363            break;
364          }
365        }
366        else if(Curl_raw_equal("max-age", name)) {
367          /* Defined in RFC2109:
368
369             Optional.  The Max-Age attribute defines the lifetime of the
370             cookie, in seconds.  The delta-seconds value is a decimal non-
371             negative integer.  After delta-seconds seconds elapse, the
372             client should discard the cookie.  A value of zero means the
373             cookie should be discarded immediately.
374
375          */
376          strstore(&co->maxage, whatptr);
377          if(!co->maxage) {
378            badcookie = TRUE;
379            break;
380          }
381          co->expires =
382            strtol((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0],NULL,10)
383            + (long)now;
384        }
385        else if(Curl_raw_equal("expires", name)) {
386          strstore(&co->expirestr, whatptr);
387          if(!co->expirestr) {
388            badcookie = TRUE;
389            break;
390          }
391          /* Note that if the date couldn't get parsed for whatever reason,
392             the cookie will be treated as a session cookie */
393          co->expires = curl_getdate(what, &now);
394
395          /* Session cookies have expires set to 0 so if we get that back
396             from the date parser let's add a second to make it a
397             non-session cookie */
398          if(co->expires == 0)
399            co->expires = 1;
400          else if(co->expires < 0)
401            co->expires = 0;
402        }
403        else if(!co->name) {
404          co->name = strdup(name);
405          co->value = strdup(whatptr);
406          if(!co->name || !co->value) {
407            badcookie = TRUE;
408            break;
409          }
410        }
411        /*
412          else this is the second (or more) name we don't know
413          about! */
414      }
415      else {
416        /* this is an "illegal" <what>=<this> pair */
417      }
418
419      if(!semiptr || !*semiptr) {
420        /* we already know there are no more cookies */
421        semiptr = NULL;
422        continue;
423      }
424
425      ptr=semiptr+1;
426      while(*ptr && ISBLANK(*ptr))
427        ptr++;
428      semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
429
430      if(!semiptr && *ptr)
431        /* There are no more semicolons, but there's a final name=value pair
432           coming up */
433        semiptr=strchr(ptr, '\0');
434    } while(semiptr);
435
436    if(!badcookie && !co->domain) {
437      if(domain) {
438        /* no domain was given in the header line, set the default */
439        co->domain=strdup(domain);
440        if(!co->domain)
441          badcookie = TRUE;
442      }
443    }
444
445    if(!badcookie && !co->path && path) {
446      /* No path was given in the header line, set the default.
447         Note that the passed-in path to this function MAY have a '?' and
448         following part that MUST not be stored as part of the path. */
449      char *queryp = strchr(path, '?');
450
451      /* queryp is where the interesting part of the path ends, so now we
452         want to the find the last */
453      char *endslash;
454      if(!queryp)
455        endslash = strrchr(path, '/');
456      else
457        endslash = memrchr(path, '/', (size_t)(queryp - path));
458      if(endslash) {
459        size_t pathlen = (size_t)(endslash-path+1); /* include ending slash */
460        co->path=malloc(pathlen+1); /* one extra for the zero byte */
461        if(co->path) {
462          memcpy(co->path, path, pathlen);
463          co->path[pathlen]=0; /* zero terminate */
464        }
465        else
466          badcookie = TRUE;
467      }
468    }
469
470    free(what);
471
472    if(badcookie || !co->name) {
473      /* we didn't get a cookie name or a bad one,
474         this is an illegal line, bail out */
475      freecookie(co);
476      return NULL;
477    }
478
479  }
480  else {
481    /* This line is NOT a HTTP header style line, we do offer support for
482       reading the odd netscape cookies-file format here */
483    char *ptr;
484    char *firstptr;
485    char *tok_buf=NULL;
486    int fields;
487
488    /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
489       marked with httpOnly after the domain name are not accessible
490       from javascripts, but since curl does not operate at javascript
491       level, we include them anyway. In Firefox's cookie files, these
492       lines are preceded with #HttpOnly_ and then everything is
493       as usual, so we skip 10 characters of the line..
494    */
495    if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
496      lineptr += 10;
497      co->httponly = TRUE;
498    }
499
500    if(lineptr[0]=='#') {
501      /* don't even try the comments */
502      free(co);
503      return NULL;
504    }
505    /* strip off the possible end-of-line characters */
506    ptr=strchr(lineptr, '\r');
507    if(ptr)
508      *ptr=0; /* clear it */
509    ptr=strchr(lineptr, '\n');
510    if(ptr)
511      *ptr=0; /* clear it */
512
513    firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
514
515    /* Here's a quick check to eliminate normal HTTP-headers from this */
516    if(!firstptr || strchr(firstptr, ':')) {
517      free(co);
518      return NULL;
519    }
520
521    /* Now loop through the fields and init the struct we already have
522       allocated */
523    for(ptr=firstptr, fields=0; ptr && !badcookie;
524        ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
525      switch(fields) {
526      case 0:
527        if(ptr[0]=='.') /* skip preceding dots */
528          ptr++;
529        co->domain = strdup(ptr);
530        if(!co->domain)
531          badcookie = TRUE;
532        break;
533      case 1:
534        /* This field got its explanation on the 23rd of May 2001 by
535           Andr�s Garc�a:
536
537           flag: A TRUE/FALSE value indicating if all machines within a given
538           domain can access the variable. This value is set automatically by
539           the browser, depending on the value you set for the domain.
540
541           As far as I can see, it is set to true when the cookie says
542           .domain.com and to false when the domain is complete www.domain.com
543        */
544        co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE;
545        break;
546      case 2:
547        /* It turns out, that sometimes the file format allows the path
548           field to remain not filled in, we try to detect this and work
549           around it! Andr�s Garc�a made us aware of this... */
550        if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
551          /* only if the path doesn't look like a boolean option! */
552          co->path = strdup(ptr);
553          if(!co->path)
554            badcookie = TRUE;
555          break;
556        }
557        /* this doesn't look like a path, make one up! */
558        co->path = strdup("/");
559        if(!co->path)
560          badcookie = TRUE;
561        fields++; /* add a field and fall down to secure */
562        /* FALLTHROUGH */
563      case 3:
564        co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE;
565        break;
566      case 4:
567        co->expires = curlx_strtoofft(ptr, NULL, 10);
568        break;
569      case 5:
570        co->name = strdup(ptr);
571        if(!co->name)
572          badcookie = TRUE;
573        break;
574      case 6:
575        co->value = strdup(ptr);
576        if(!co->value)
577          badcookie = TRUE;
578        break;
579      }
580    }
581    if(6 == fields) {
582      /* we got a cookie with blank contents, fix it */
583      co->value = strdup("");
584      if(!co->value)
585        badcookie = TRUE;
586      else
587        fields++;
588    }
589
590    if(!badcookie && (7 != fields))
591      /* we did not find the sufficient number of fields */
592      badcookie = TRUE;
593
594    if(badcookie) {
595      freecookie(co);
596      return NULL;
597    }
598
599  }
600
601  if(!c->running &&    /* read from a file */
602     c->newsession &&  /* clean session cookies */
603     !co->expires) {   /* this is a session cookie since it doesn't expire! */
604    freecookie(co);
605    return NULL;
606  }
607
608  co->livecookie = c->running;
609
610  /* now, we have parsed the incoming line, we must now check if this
611     superceeds an already existing cookie, which it may if the previous have
612     the same domain and path as this */
613
614  clist = c->cookies;
615  replace_old = FALSE;
616  while(clist) {
617    if(Curl_raw_equal(clist->name, co->name)) {
618      /* the names are identical */
619
620      if(clist->domain && co->domain) {
621        if(Curl_raw_equal(clist->domain, co->domain))
622          /* The domains are identical */
623          replace_old=TRUE;
624      }
625      else if(!clist->domain && !co->domain)
626        replace_old = TRUE;
627
628      if(replace_old) {
629        /* the domains were identical */
630
631        if(clist->path && co->path) {
632          if(Curl_raw_equal(clist->path, co->path)) {
633            replace_old = TRUE;
634          }
635          else
636            replace_old = FALSE;
637        }
638        else if(!clist->path && !co->path)
639          replace_old = TRUE;
640        else
641          replace_old = FALSE;
642
643      }
644
645      if(replace_old && !co->livecookie && clist->livecookie) {
646        /* Both cookies matched fine, except that the already present
647           cookie is "live", which means it was set from a header, while
648           the new one isn't "live" and thus only read from a file. We let
649           live cookies stay alive */
650
651        /* Free the newcomer and get out of here! */
652        freecookie(co);
653        return NULL;
654      }
655
656      if(replace_old) {
657        co->next = clist->next; /* get the next-pointer first */
658
659        /* then free all the old pointers */
660        free(clist->name);
661        if(clist->value)
662          free(clist->value);
663        if(clist->domain)
664          free(clist->domain);
665        if(clist->path)
666          free(clist->path);
667        if(clist->expirestr)
668          free(clist->expirestr);
669
670        if(clist->version)
671          free(clist->version);
672        if(clist->maxage)
673          free(clist->maxage);
674
675        *clist = *co;  /* then store all the new data */
676
677        free(co);   /* free the newly alloced memory */
678        co = clist; /* point to the previous struct instead */
679
680        /* We have replaced a cookie, now skip the rest of the list but
681           make sure the 'lastc' pointer is properly set */
682        do {
683          lastc = clist;
684          clist = clist->next;
685        } while(clist);
686        break;
687      }
688    }
689    lastc = clist;
690    clist = clist->next;
691  }
692
693  if(c->running)
694    /* Only show this when NOT reading the cookies from a file */
695    infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
696          "expire %" FORMAT_OFF_T "\n",
697          replace_old?"Replaced":"Added", co->name, co->value,
698          co->domain, co->path, co->expires);
699
700  if(!replace_old) {
701    /* then make the last item point on this new one */
702    if(lastc)
703      lastc->next = co;
704    else
705      c->cookies = co;
706    c->numcookies++; /* one more cookie in the jar */
707  }
708
709  return co;
710}
711
712/*****************************************************************************
713 *
714 * Curl_cookie_init()
715 *
716 * Inits a cookie struct to read data from a local file. This is always
717 * called before any cookies are set. File may be NULL.
718 *
719 * If 'newsession' is TRUE, discard all "session cookies" on read from file.
720 *
721 ****************************************************************************/
722struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
723                                    const char *file,
724                                    struct CookieInfo *inc,
725                                    bool newsession)
726{
727  struct CookieInfo *c;
728  FILE *fp;
729  bool fromfile=TRUE;
730
731  if(NULL == inc) {
732    /* we didn't get a struct, create one */
733    c = calloc(1, sizeof(struct CookieInfo));
734    if(!c)
735      return NULL; /* failed to get memory */
736    c->filename = strdup(file?file:"none"); /* copy the name just in case */
737  }
738  else {
739    /* we got an already existing one, use that */
740    c = inc;
741  }
742  c->running = FALSE; /* this is not running, this is init */
743
744  if(file && strequal(file, "-")) {
745    fp = stdin;
746    fromfile=FALSE;
747  }
748  else if(file && !*file) {
749    /* points to a "" string */
750    fp = NULL;
751  }
752  else
753    fp = file?fopen(file, "r"):NULL;
754
755  c->newsession = newsession; /* new session? */
756
757  if(fp) {
758    char *lineptr;
759    bool headerline;
760
761    char *line = malloc(MAX_COOKIE_LINE);
762    if(line) {
763      while(fgets(line, MAX_COOKIE_LINE, fp)) {
764        if(checkprefix("Set-Cookie:", line)) {
765          /* This is a cookie line, get it! */
766          lineptr=&line[11];
767          headerline=TRUE;
768        }
769        else {
770          lineptr=line;
771          headerline=FALSE;
772        }
773        while(*lineptr && ISBLANK(*lineptr))
774          lineptr++;
775
776        Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
777      }
778      free(line); /* free the line buffer */
779    }
780    if(fromfile)
781      fclose(fp);
782  }
783
784  c->running = TRUE;          /* now, we're running */
785
786  return c;
787}
788
789/* sort this so that the longest path gets before the shorter path */
790static int cookie_sort(const void *p1, const void *p2)
791{
792  struct Cookie *c1 = *(struct Cookie **)p1;
793  struct Cookie *c2 = *(struct Cookie **)p2;
794  size_t l1, l2;
795
796  /* 1 - compare cookie path lengths */
797  l1 = c1->path ? strlen(c1->path) : 0;
798  l2 = c2->path ? strlen(c2->path) : 0;
799
800  if(l1 != l2)
801    return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
802
803  /* 2 - compare cookie domain lengths */
804  l1 = c1->domain ? strlen(c1->domain) : 0;
805  l2 = c2->domain ? strlen(c2->domain) : 0;
806
807  if(l1 != l2)
808    return (l2 > l1) ? 1 : -1 ;  /* avoid size_t <=> int conversions */
809
810  /* 3 - compare cookie names */
811  if(c1->name && c2->name)
812    return strcmp(c1->name, c2->name);
813
814  /* sorry, can't be more deterministic */
815  return 0;
816}
817
818/*****************************************************************************
819 *
820 * Curl_cookie_getlist()
821 *
822 * For a given host and path, return a linked list of cookies that the
823 * client should send to the server if used now. The secure boolean informs
824 * the cookie if a secure connection is achieved or not.
825 *
826 * It shall only return cookies that haven't expired.
827 *
828 ****************************************************************************/
829
830struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
831                                   const char *host, const char *path,
832                                   bool secure)
833{
834  struct Cookie *newco;
835  struct Cookie *co;
836  time_t now = time(NULL);
837  struct Cookie *mainco=NULL;
838  size_t matches = 0;
839
840  if(!c || !c->cookies)
841    return NULL; /* no cookie struct or no cookies in the struct */
842
843  co = c->cookies;
844
845  while(co) {
846    /* only process this cookie if it is not expired or had no expire
847       date AND that if the cookie requires we're secure we must only
848       continue if we are! */
849    if((!co->expires || (co->expires > now)) &&
850       (co->secure?secure:TRUE)) {
851
852      /* now check if the domain is correct */
853      if(!co->domain ||
854         (co->tailmatch && tailmatch(co->domain, host)) ||
855         (!co->tailmatch && Curl_raw_equal(host, co->domain)) ) {
856        /* the right part of the host matches the domain stuff in the
857           cookie data */
858
859        /* now check the left part of the path with the cookies path
860           requirement */
861        if(!co->path ||
862           /* not using checkprefix() because matching should be
863              case-sensitive */
864           !strncmp(co->path, path, strlen(co->path)) ) {
865
866          /* and now, we know this is a match and we should create an
867             entry for the return-linked-list */
868
869          newco = malloc(sizeof(struct Cookie));
870          if(newco) {
871            /* first, copy the whole source cookie: */
872            memcpy(newco, co, sizeof(struct Cookie));
873
874            /* then modify our next */
875            newco->next = mainco;
876
877            /* point the main to us */
878            mainco = newco;
879
880            matches++;
881          }
882          else {
883            fail:
884            /* failure, clear up the allocated chain and return NULL */
885            while(mainco) {
886              co = mainco->next;
887              free(mainco);
888              mainco = co;
889            }
890
891            return NULL;
892          }
893        }
894      }
895    }
896    co = co->next;
897  }
898
899  if(matches) {
900    /* Now we need to make sure that if there is a name appearing more than
901       once, the longest specified path version comes first. To make this
902       the swiftest way, we just sort them all based on path length. */
903    struct Cookie **array;
904    size_t i;
905
906    /* alloc an array and store all cookie pointers */
907    array = malloc(sizeof(struct Cookie *) * matches);
908    if(!array)
909      goto fail;
910
911    co = mainco;
912
913    for(i=0; co; co = co->next)
914      array[i++] = co;
915
916    /* now sort the cookie pointers in path length order */
917    qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
918
919    /* remake the linked list order according to the new order */
920
921    mainco = array[0]; /* start here */
922    for(i=0; i<matches-1; i++)
923      array[i]->next = array[i+1];
924    array[matches-1]->next = NULL; /* terminate the list */
925
926    free(array); /* remove the temporary data again */
927  }
928
929  return mainco; /* return the new list */
930}
931
932/*****************************************************************************
933 *
934 * Curl_cookie_clearall()
935 *
936 * Clear all existing cookies and reset the counter.
937 *
938 ****************************************************************************/
939void Curl_cookie_clearall(struct CookieInfo *cookies)
940{
941  if(cookies) {
942    Curl_cookie_freelist(cookies->cookies, TRUE);
943    cookies->cookies = NULL;
944    cookies->numcookies = 0;
945  }
946}
947
948/*****************************************************************************
949 *
950 * Curl_cookie_freelist()
951 *
952 * Free a list of cookies previously returned by Curl_cookie_getlist();
953 *
954 * The 'cookiestoo' argument tells this function whether to just free the
955 * list or actually also free all cookies within the list as well.
956 *
957 ****************************************************************************/
958
959void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo)
960{
961  struct Cookie *next;
962  if(co) {
963    while(co) {
964      next = co->next;
965      if(cookiestoo)
966        freecookie(co);
967      else
968        free(co); /* we only free the struct since the "members" are all just
969                     pointed out in the main cookie list! */
970      co = next;
971    }
972  }
973}
974
975
976/*****************************************************************************
977 *
978 * Curl_cookie_clearsess()
979 *
980 * Free all session cookies in the cookies list.
981 *
982 ****************************************************************************/
983void Curl_cookie_clearsess(struct CookieInfo *cookies)
984{
985  struct Cookie *first, *curr, *next, *prev = NULL;
986
987  if(!cookies || !cookies->cookies)
988    return;
989
990  first = curr = prev = cookies->cookies;
991
992  for(; curr; curr = next) {
993    next = curr->next;
994    if(!curr->expires) {
995      if(first == curr)
996        first = next;
997
998      if(prev == curr)
999        prev = next;
1000      else
1001        prev->next = next;
1002
1003      freecookie(curr);
1004      cookies->numcookies--;
1005    }
1006    else
1007      prev = curr;
1008  }
1009
1010  cookies->cookies = first;
1011}
1012
1013
1014/*****************************************************************************
1015 *
1016 * Curl_cookie_cleanup()
1017 *
1018 * Free a "cookie object" previous created with cookie_init().
1019 *
1020 ****************************************************************************/
1021void Curl_cookie_cleanup(struct CookieInfo *c)
1022{
1023  struct Cookie *co;
1024  struct Cookie *next;
1025  if(c) {
1026    if(c->filename)
1027      free(c->filename);
1028    co = c->cookies;
1029
1030    while(co) {
1031      next = co->next;
1032      freecookie(co);
1033      co = next;
1034    }
1035    free(c); /* free the base struct as well */
1036  }
1037}
1038
1039/* get_netscape_format()
1040 *
1041 * Formats a string for Netscape output file, w/o a newline at the end.
1042 *
1043 * Function returns a char * to a formatted line. Has to be free()d
1044*/
1045static char *get_netscape_format(const struct Cookie *co)
1046{
1047  return aprintf(
1048    "%s"     /* httponly preamble */
1049    "%s%s\t" /* domain */
1050    "%s\t"   /* tailmatch */
1051    "%s\t"   /* path */
1052    "%s\t"   /* secure */
1053    "%" FORMAT_OFF_T "\t"   /* expires */
1054    "%s\t"   /* name */
1055    "%s",    /* value */
1056    co->httponly?"#HttpOnly_":"",
1057    /* Make sure all domains are prefixed with a dot if they allow
1058       tailmatching. This is Mozilla-style. */
1059    (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
1060    co->domain?co->domain:"unknown",
1061    co->tailmatch?"TRUE":"FALSE",
1062    co->path?co->path:"/",
1063    co->secure?"TRUE":"FALSE",
1064    co->expires,
1065    co->name,
1066    co->value?co->value:"");
1067}
1068
1069/*
1070 * cookie_output()
1071 *
1072 * Writes all internally known cookies to the specified file. Specify
1073 * "-" as file name to write to stdout.
1074 *
1075 * The function returns non-zero on write failure.
1076 */
1077static int cookie_output(struct CookieInfo *c, const char *dumphere)
1078{
1079  struct Cookie *co;
1080  FILE *out;
1081  bool use_stdout=FALSE;
1082
1083  if((NULL == c) || (0 == c->numcookies))
1084    /* If there are no known cookies, we don't write or even create any
1085       destination file */
1086    return 0;
1087
1088  if(strequal("-", dumphere)) {
1089    /* use stdout */
1090    out = stdout;
1091    use_stdout=TRUE;
1092  }
1093  else {
1094    out = fopen(dumphere, "w");
1095    if(!out)
1096      return 1; /* failure */
1097  }
1098
1099  if(c) {
1100    char *format_ptr;
1101
1102    fputs("# Netscape HTTP Cookie File\n"
1103          "# http://curl.haxx.se/docs/http-cookies.html\n"
1104          "# This file was generated by libcurl! Edit at your own risk.\n\n",
1105          out);
1106    co = c->cookies;
1107
1108    while(co) {
1109      format_ptr = get_netscape_format(co);
1110      if(format_ptr == NULL) {
1111        fprintf(out, "#\n# Fatal libcurl error\n");
1112        if(!use_stdout)
1113          fclose(out);
1114        return 1;
1115      }
1116      fprintf(out, "%s\n", format_ptr);
1117      free(format_ptr);
1118      co=co->next;
1119    }
1120  }
1121
1122  if(!use_stdout)
1123    fclose(out);
1124
1125  return 0;
1126}
1127
1128struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
1129{
1130  struct curl_slist *list = NULL;
1131  struct curl_slist *beg;
1132  struct Cookie *c;
1133  char *line;
1134
1135  if((data->cookies == NULL) ||
1136      (data->cookies->numcookies == 0))
1137    return NULL;
1138
1139  c = data->cookies->cookies;
1140
1141  while(c) {
1142    /* fill the list with _all_ the cookies we know */
1143    line = get_netscape_format(c);
1144    if(!line) {
1145      curl_slist_free_all(list);
1146      return NULL;
1147    }
1148    beg = curl_slist_append(list, line);
1149    free(line);
1150    if(!beg) {
1151      curl_slist_free_all(list);
1152      return NULL;
1153    }
1154    list = beg;
1155    c = c->next;
1156  }
1157
1158  return list;
1159}
1160
1161void Curl_flush_cookies(struct SessionHandle *data, int cleanup)
1162{
1163  if(data->set.str[STRING_COOKIEJAR]) {
1164    if(data->change.cookielist) {
1165      /* If there is a list of cookie files to read, do it first so that
1166         we have all the told files read before we write the new jar.
1167         Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
1168      Curl_cookie_loadfiles(data);
1169    }
1170
1171    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1172
1173    /* if we have a destination file for all the cookies to get dumped to */
1174    if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
1175      infof(data, "WARNING: failed to save cookies in %s\n",
1176            data->set.str[STRING_COOKIEJAR]);
1177  }
1178  else {
1179    if(cleanup && data->change.cookielist) {
1180      /* since nothing is written, we can just free the list of cookie file
1181         names */
1182      curl_slist_free_all(data->change.cookielist); /* clean up list */
1183      data->change.cookielist = NULL;
1184    }
1185    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1186  }
1187
1188  if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
1189    Curl_cookie_cleanup(data->cookies);
1190  }
1191  Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
1192}
1193
1194#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
1195