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