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