Revert "Update to 7.40.1"
[platform/upstream/curl.git] / lib / cookie.c
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
26 RECEIVING COOKIE INFORMATION
27 ============================
28
29 struct 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
34 int 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
47 SENDING COOKIE INFORMATION
48 ==========================
49
50 struct 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
61 Example 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
102 static 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
124 static 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  */
153 static 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
219 pathmatched:
220   free(uri_path);
221   return ret;
222 }
223
224 /*
225  * cookie path sanitize
226  */
227 static 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  */
262 void 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  */
286 static 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  */
296 static 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
333 struct Cookie *
334 Curl_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  ****************************************************************************/
854 struct 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 */
922 static 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
962 struct 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  ****************************************************************************/
1071 void 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
1091 void 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  ****************************************************************************/
1115 void 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  ****************************************************************************/
1153 void 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 */
1177 static 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  */
1209 static 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
1263 struct 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
1296 void 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 */