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