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