xref: /aosp_15_r20/external/curl/lib/cookie.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker 
25*6236dae4SAndroid Build Coastguard Worker /***
26*6236dae4SAndroid Build Coastguard Worker 
27*6236dae4SAndroid Build Coastguard Worker 
28*6236dae4SAndroid Build Coastguard Worker RECEIVING COOKIE INFORMATION
29*6236dae4SAndroid Build Coastguard Worker ============================
30*6236dae4SAndroid Build Coastguard Worker 
31*6236dae4SAndroid Build Coastguard Worker Curl_cookie_init()
32*6236dae4SAndroid Build Coastguard Worker 
33*6236dae4SAndroid Build Coastguard Worker         Inits a cookie struct to store data in a local file. This is always
34*6236dae4SAndroid Build Coastguard Worker         called before any cookies are set.
35*6236dae4SAndroid Build Coastguard Worker 
36*6236dae4SAndroid Build Coastguard Worker Curl_cookie_add()
37*6236dae4SAndroid Build Coastguard Worker 
38*6236dae4SAndroid Build Coastguard Worker         Adds a cookie to the in-memory cookie jar.
39*6236dae4SAndroid Build Coastguard Worker 
40*6236dae4SAndroid Build Coastguard Worker 
41*6236dae4SAndroid Build Coastguard Worker SENDING COOKIE INFORMATION
42*6236dae4SAndroid Build Coastguard Worker ==========================
43*6236dae4SAndroid Build Coastguard Worker 
44*6236dae4SAndroid Build Coastguard Worker Curl_cookie_getlist()
45*6236dae4SAndroid Build Coastguard Worker 
46*6236dae4SAndroid Build Coastguard Worker         For a given host and path, return a linked list of cookies that
47*6236dae4SAndroid Build Coastguard Worker         the client should send to the server if used now. The secure
48*6236dae4SAndroid Build Coastguard Worker         boolean informs the cookie if a secure connection is achieved or
49*6236dae4SAndroid Build Coastguard Worker         not.
50*6236dae4SAndroid Build Coastguard Worker 
51*6236dae4SAndroid Build Coastguard Worker         It shall only return cookies that have not expired.
52*6236dae4SAndroid Build Coastguard Worker 
53*6236dae4SAndroid Build Coastguard Worker Example set of cookies:
54*6236dae4SAndroid Build Coastguard Worker 
55*6236dae4SAndroid Build Coastguard Worker     Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
56*6236dae4SAndroid Build Coastguard Worker     Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
57*6236dae4SAndroid Build Coastguard Worker     domain=.fidelity.com; path=/ftgw; secure
58*6236dae4SAndroid Build Coastguard Worker     Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
59*6236dae4SAndroid Build Coastguard Worker     domain=.fidelity.com; path=/; secure
60*6236dae4SAndroid Build Coastguard Worker     Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
61*6236dae4SAndroid Build Coastguard Worker     domain=.fidelity.com; path=/; secure
62*6236dae4SAndroid Build Coastguard Worker     Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
63*6236dae4SAndroid Build Coastguard Worker     domain=.fidelity.com; path=/; secure
64*6236dae4SAndroid Build Coastguard Worker     Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
65*6236dae4SAndroid Build Coastguard Worker     domain=.fidelity.com; path=/; secure
66*6236dae4SAndroid Build Coastguard Worker     Set-cookie:
67*6236dae4SAndroid Build Coastguard Worker     Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
68*6236dae4SAndroid Build Coastguard Worker     13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
69*6236dae4SAndroid Build Coastguard Worker ****/
70*6236dae4SAndroid Build Coastguard Worker 
71*6236dae4SAndroid Build Coastguard Worker 
72*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
73*6236dae4SAndroid Build Coastguard Worker 
74*6236dae4SAndroid Build Coastguard Worker #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
75*6236dae4SAndroid Build Coastguard Worker 
76*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
77*6236dae4SAndroid Build Coastguard Worker #include "cookie.h"
78*6236dae4SAndroid Build Coastguard Worker #include "psl.h"
79*6236dae4SAndroid Build Coastguard Worker #include "strtok.h"
80*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
81*6236dae4SAndroid Build Coastguard Worker #include "slist.h"
82*6236dae4SAndroid Build Coastguard Worker #include "share.h"
83*6236dae4SAndroid Build Coastguard Worker #include "strtoofft.h"
84*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
85*6236dae4SAndroid Build Coastguard Worker #include "curl_get_line.h"
86*6236dae4SAndroid Build Coastguard Worker #include "curl_memrchr.h"
87*6236dae4SAndroid Build Coastguard Worker #include "parsedate.h"
88*6236dae4SAndroid Build Coastguard Worker #include "rename.h"
89*6236dae4SAndroid Build Coastguard Worker #include "fopen.h"
90*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
91*6236dae4SAndroid Build Coastguard Worker #include "llist.h"
92*6236dae4SAndroid Build Coastguard Worker 
93*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
94*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
95*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
96*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
97*6236dae4SAndroid Build Coastguard Worker 
98*6236dae4SAndroid Build Coastguard Worker static void strstore(char **str, const char *newstr, size_t len);
99*6236dae4SAndroid Build Coastguard Worker 
freecookie(struct Cookie * co)100*6236dae4SAndroid Build Coastguard Worker static void freecookie(struct Cookie *co)
101*6236dae4SAndroid Build Coastguard Worker {
102*6236dae4SAndroid Build Coastguard Worker   free(co->domain);
103*6236dae4SAndroid Build Coastguard Worker   free(co->path);
104*6236dae4SAndroid Build Coastguard Worker   free(co->spath);
105*6236dae4SAndroid Build Coastguard Worker   free(co->name);
106*6236dae4SAndroid Build Coastguard Worker   free(co->value);
107*6236dae4SAndroid Build Coastguard Worker   free(co);
108*6236dae4SAndroid Build Coastguard Worker }
109*6236dae4SAndroid Build Coastguard Worker 
cookie_tailmatch(const char * cookie_domain,size_t cookie_domain_len,const char * hostname)110*6236dae4SAndroid Build Coastguard Worker static bool cookie_tailmatch(const char *cookie_domain,
111*6236dae4SAndroid Build Coastguard Worker                              size_t cookie_domain_len,
112*6236dae4SAndroid Build Coastguard Worker                              const char *hostname)
113*6236dae4SAndroid Build Coastguard Worker {
114*6236dae4SAndroid Build Coastguard Worker   size_t hostname_len = strlen(hostname);
115*6236dae4SAndroid Build Coastguard Worker 
116*6236dae4SAndroid Build Coastguard Worker   if(hostname_len < cookie_domain_len)
117*6236dae4SAndroid Build Coastguard Worker     return FALSE;
118*6236dae4SAndroid Build Coastguard Worker 
119*6236dae4SAndroid Build Coastguard Worker   if(!strncasecompare(cookie_domain,
120*6236dae4SAndroid Build Coastguard Worker                       hostname + hostname_len-cookie_domain_len,
121*6236dae4SAndroid Build Coastguard Worker                       cookie_domain_len))
122*6236dae4SAndroid Build Coastguard Worker     return FALSE;
123*6236dae4SAndroid Build Coastguard Worker 
124*6236dae4SAndroid Build Coastguard Worker   /*
125*6236dae4SAndroid Build Coastguard Worker    * A lead char of cookie_domain is not '.'.
126*6236dae4SAndroid Build Coastguard Worker    * RFC6265 4.1.2.3. The Domain Attribute says:
127*6236dae4SAndroid Build Coastguard Worker    * For example, if the value of the Domain attribute is
128*6236dae4SAndroid Build Coastguard Worker    * "example.com", the user agent will include the cookie in the Cookie
129*6236dae4SAndroid Build Coastguard Worker    * header when making HTTP requests to example.com, www.example.com, and
130*6236dae4SAndroid Build Coastguard Worker    * www.corp.example.com.
131*6236dae4SAndroid Build Coastguard Worker    */
132*6236dae4SAndroid Build Coastguard Worker   if(hostname_len == cookie_domain_len)
133*6236dae4SAndroid Build Coastguard Worker     return TRUE;
134*6236dae4SAndroid Build Coastguard Worker   if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
135*6236dae4SAndroid Build Coastguard Worker     return TRUE;
136*6236dae4SAndroid Build Coastguard Worker   return FALSE;
137*6236dae4SAndroid Build Coastguard Worker }
138*6236dae4SAndroid Build Coastguard Worker 
139*6236dae4SAndroid Build Coastguard Worker /*
140*6236dae4SAndroid Build Coastguard Worker  * matching cookie path and URL path
141*6236dae4SAndroid Build Coastguard Worker  * RFC6265 5.1.4 Paths and Path-Match
142*6236dae4SAndroid Build Coastguard Worker  */
pathmatch(const char * cookie_path,const char * request_uri)143*6236dae4SAndroid Build Coastguard Worker static bool pathmatch(const char *cookie_path, const char *request_uri)
144*6236dae4SAndroid Build Coastguard Worker {
145*6236dae4SAndroid Build Coastguard Worker   size_t cookie_path_len;
146*6236dae4SAndroid Build Coastguard Worker   size_t uri_path_len;
147*6236dae4SAndroid Build Coastguard Worker   char *uri_path = NULL;
148*6236dae4SAndroid Build Coastguard Worker   char *pos;
149*6236dae4SAndroid Build Coastguard Worker   bool ret = FALSE;
150*6236dae4SAndroid Build Coastguard Worker 
151*6236dae4SAndroid Build Coastguard Worker   /* cookie_path must not have last '/' separator. ex: /sample */
152*6236dae4SAndroid Build Coastguard Worker   cookie_path_len = strlen(cookie_path);
153*6236dae4SAndroid Build Coastguard Worker   if(1 == cookie_path_len) {
154*6236dae4SAndroid Build Coastguard Worker     /* cookie_path must be '/' */
155*6236dae4SAndroid Build Coastguard Worker     return TRUE;
156*6236dae4SAndroid Build Coastguard Worker   }
157*6236dae4SAndroid Build Coastguard Worker 
158*6236dae4SAndroid Build Coastguard Worker   uri_path = strdup(request_uri);
159*6236dae4SAndroid Build Coastguard Worker   if(!uri_path)
160*6236dae4SAndroid Build Coastguard Worker     return FALSE;
161*6236dae4SAndroid Build Coastguard Worker   pos = strchr(uri_path, '?');
162*6236dae4SAndroid Build Coastguard Worker   if(pos)
163*6236dae4SAndroid Build Coastguard Worker     *pos = 0x0;
164*6236dae4SAndroid Build Coastguard Worker 
165*6236dae4SAndroid Build Coastguard Worker   /* #-fragments are already cut off! */
166*6236dae4SAndroid Build Coastguard Worker   if(0 == strlen(uri_path) || uri_path[0] != '/') {
167*6236dae4SAndroid Build Coastguard Worker     strstore(&uri_path, "/", 1);
168*6236dae4SAndroid Build Coastguard Worker     if(!uri_path)
169*6236dae4SAndroid Build Coastguard Worker       return FALSE;
170*6236dae4SAndroid Build Coastguard Worker   }
171*6236dae4SAndroid Build Coastguard Worker 
172*6236dae4SAndroid Build Coastguard Worker   /*
173*6236dae4SAndroid Build Coastguard Worker    * here, RFC6265 5.1.4 says
174*6236dae4SAndroid Build Coastguard Worker    *  4. Output the characters of the uri-path from the first character up
175*6236dae4SAndroid Build Coastguard Worker    *     to, but not including, the right-most %x2F ("/").
176*6236dae4SAndroid Build Coastguard Worker    *  but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
177*6236dae4SAndroid Build Coastguard Worker    *  without redirect.
178*6236dae4SAndroid Build Coastguard Worker    *  Ignore this algorithm because /hoge is uri path for this case
179*6236dae4SAndroid Build Coastguard Worker    *  (uri path is not /).
180*6236dae4SAndroid Build Coastguard Worker    */
181*6236dae4SAndroid Build Coastguard Worker 
182*6236dae4SAndroid Build Coastguard Worker   uri_path_len = strlen(uri_path);
183*6236dae4SAndroid Build Coastguard Worker 
184*6236dae4SAndroid Build Coastguard Worker   if(uri_path_len < cookie_path_len) {
185*6236dae4SAndroid Build Coastguard Worker     ret = FALSE;
186*6236dae4SAndroid Build Coastguard Worker     goto pathmatched;
187*6236dae4SAndroid Build Coastguard Worker   }
188*6236dae4SAndroid Build Coastguard Worker 
189*6236dae4SAndroid Build Coastguard Worker   /* not using checkprefix() because matching should be case-sensitive */
190*6236dae4SAndroid Build Coastguard Worker   if(strncmp(cookie_path, uri_path, cookie_path_len)) {
191*6236dae4SAndroid Build Coastguard Worker     ret = FALSE;
192*6236dae4SAndroid Build Coastguard Worker     goto pathmatched;
193*6236dae4SAndroid Build Coastguard Worker   }
194*6236dae4SAndroid Build Coastguard Worker 
195*6236dae4SAndroid Build Coastguard Worker   /* The cookie-path and the uri-path are identical. */
196*6236dae4SAndroid Build Coastguard Worker   if(cookie_path_len == uri_path_len) {
197*6236dae4SAndroid Build Coastguard Worker     ret = TRUE;
198*6236dae4SAndroid Build Coastguard Worker     goto pathmatched;
199*6236dae4SAndroid Build Coastguard Worker   }
200*6236dae4SAndroid Build Coastguard Worker 
201*6236dae4SAndroid Build Coastguard Worker   /* here, cookie_path_len < uri_path_len */
202*6236dae4SAndroid Build Coastguard Worker   if(uri_path[cookie_path_len] == '/') {
203*6236dae4SAndroid Build Coastguard Worker     ret = TRUE;
204*6236dae4SAndroid Build Coastguard Worker     goto pathmatched;
205*6236dae4SAndroid Build Coastguard Worker   }
206*6236dae4SAndroid Build Coastguard Worker 
207*6236dae4SAndroid Build Coastguard Worker   ret = FALSE;
208*6236dae4SAndroid Build Coastguard Worker 
209*6236dae4SAndroid Build Coastguard Worker pathmatched:
210*6236dae4SAndroid Build Coastguard Worker   free(uri_path);
211*6236dae4SAndroid Build Coastguard Worker   return ret;
212*6236dae4SAndroid Build Coastguard Worker }
213*6236dae4SAndroid Build Coastguard Worker 
214*6236dae4SAndroid Build Coastguard Worker /*
215*6236dae4SAndroid Build Coastguard Worker  * Return the top-level domain, for optimal hashing.
216*6236dae4SAndroid Build Coastguard Worker  */
get_top_domain(const char * const domain,size_t * outlen)217*6236dae4SAndroid Build Coastguard Worker static const char *get_top_domain(const char * const domain, size_t *outlen)
218*6236dae4SAndroid Build Coastguard Worker {
219*6236dae4SAndroid Build Coastguard Worker   size_t len = 0;
220*6236dae4SAndroid Build Coastguard Worker   const char *first = NULL, *last;
221*6236dae4SAndroid Build Coastguard Worker 
222*6236dae4SAndroid Build Coastguard Worker   if(domain) {
223*6236dae4SAndroid Build Coastguard Worker     len = strlen(domain);
224*6236dae4SAndroid Build Coastguard Worker     last = memrchr(domain, '.', len);
225*6236dae4SAndroid Build Coastguard Worker     if(last) {
226*6236dae4SAndroid Build Coastguard Worker       first = memrchr(domain, '.', (last - domain));
227*6236dae4SAndroid Build Coastguard Worker       if(first)
228*6236dae4SAndroid Build Coastguard Worker         len -= (++first - domain);
229*6236dae4SAndroid Build Coastguard Worker     }
230*6236dae4SAndroid Build Coastguard Worker   }
231*6236dae4SAndroid Build Coastguard Worker 
232*6236dae4SAndroid Build Coastguard Worker   if(outlen)
233*6236dae4SAndroid Build Coastguard Worker     *outlen = len;
234*6236dae4SAndroid Build Coastguard Worker 
235*6236dae4SAndroid Build Coastguard Worker   return first ? first : domain;
236*6236dae4SAndroid Build Coastguard Worker }
237*6236dae4SAndroid Build Coastguard Worker 
238*6236dae4SAndroid Build Coastguard Worker /* Avoid C1001, an "internal error" with MSVC14 */
239*6236dae4SAndroid Build Coastguard Worker #if defined(_MSC_VER) && (_MSC_VER == 1900)
240*6236dae4SAndroid Build Coastguard Worker #pragma optimize("", off)
241*6236dae4SAndroid Build Coastguard Worker #endif
242*6236dae4SAndroid Build Coastguard Worker 
243*6236dae4SAndroid Build Coastguard Worker /*
244*6236dae4SAndroid Build Coastguard Worker  * A case-insensitive hash for the cookie domains.
245*6236dae4SAndroid Build Coastguard Worker  */
cookie_hash_domain(const char * domain,const size_t len)246*6236dae4SAndroid Build Coastguard Worker static size_t cookie_hash_domain(const char *domain, const size_t len)
247*6236dae4SAndroid Build Coastguard Worker {
248*6236dae4SAndroid Build Coastguard Worker   const char *end = domain + len;
249*6236dae4SAndroid Build Coastguard Worker   size_t h = 5381;
250*6236dae4SAndroid Build Coastguard Worker 
251*6236dae4SAndroid Build Coastguard Worker   while(domain < end) {
252*6236dae4SAndroid Build Coastguard Worker     size_t j = (size_t)Curl_raw_toupper(*domain++);
253*6236dae4SAndroid Build Coastguard Worker     h += h << 5;
254*6236dae4SAndroid Build Coastguard Worker     h ^= j;
255*6236dae4SAndroid Build Coastguard Worker   }
256*6236dae4SAndroid Build Coastguard Worker 
257*6236dae4SAndroid Build Coastguard Worker   return (h % COOKIE_HASH_SIZE);
258*6236dae4SAndroid Build Coastguard Worker }
259*6236dae4SAndroid Build Coastguard Worker 
260*6236dae4SAndroid Build Coastguard Worker #if defined(_MSC_VER) && (_MSC_VER == 1900)
261*6236dae4SAndroid Build Coastguard Worker #pragma optimize("", on)
262*6236dae4SAndroid Build Coastguard Worker #endif
263*6236dae4SAndroid Build Coastguard Worker 
264*6236dae4SAndroid Build Coastguard Worker /*
265*6236dae4SAndroid Build Coastguard Worker  * Hash this domain.
266*6236dae4SAndroid Build Coastguard Worker  */
cookiehash(const char * const domain)267*6236dae4SAndroid Build Coastguard Worker static size_t cookiehash(const char * const domain)
268*6236dae4SAndroid Build Coastguard Worker {
269*6236dae4SAndroid Build Coastguard Worker   const char *top;
270*6236dae4SAndroid Build Coastguard Worker   size_t len;
271*6236dae4SAndroid Build Coastguard Worker 
272*6236dae4SAndroid Build Coastguard Worker   if(!domain || Curl_host_is_ipnum(domain))
273*6236dae4SAndroid Build Coastguard Worker     return 0;
274*6236dae4SAndroid Build Coastguard Worker 
275*6236dae4SAndroid Build Coastguard Worker   top = get_top_domain(domain, &len);
276*6236dae4SAndroid Build Coastguard Worker   return cookie_hash_domain(top, len);
277*6236dae4SAndroid Build Coastguard Worker }
278*6236dae4SAndroid Build Coastguard Worker 
279*6236dae4SAndroid Build Coastguard Worker /*
280*6236dae4SAndroid Build Coastguard Worker  * cookie path sanitize
281*6236dae4SAndroid Build Coastguard Worker  */
sanitize_cookie_path(const char * cookie_path)282*6236dae4SAndroid Build Coastguard Worker static char *sanitize_cookie_path(const char *cookie_path)
283*6236dae4SAndroid Build Coastguard Worker {
284*6236dae4SAndroid Build Coastguard Worker   size_t len;
285*6236dae4SAndroid Build Coastguard Worker   char *new_path = strdup(cookie_path);
286*6236dae4SAndroid Build Coastguard Worker   if(!new_path)
287*6236dae4SAndroid Build Coastguard Worker     return NULL;
288*6236dae4SAndroid Build Coastguard Worker 
289*6236dae4SAndroid Build Coastguard Worker   /* some stupid site sends path attribute with '"'. */
290*6236dae4SAndroid Build Coastguard Worker   len = strlen(new_path);
291*6236dae4SAndroid Build Coastguard Worker   if(new_path[0] == '\"') {
292*6236dae4SAndroid Build Coastguard Worker     memmove(new_path, new_path + 1, len);
293*6236dae4SAndroid Build Coastguard Worker     len--;
294*6236dae4SAndroid Build Coastguard Worker   }
295*6236dae4SAndroid Build Coastguard Worker   if(len && (new_path[len - 1] == '\"')) {
296*6236dae4SAndroid Build Coastguard Worker     new_path[--len] = 0x0;
297*6236dae4SAndroid Build Coastguard Worker   }
298*6236dae4SAndroid Build Coastguard Worker 
299*6236dae4SAndroid Build Coastguard Worker   /* RFC6265 5.2.4 The Path Attribute */
300*6236dae4SAndroid Build Coastguard Worker   if(new_path[0] != '/') {
301*6236dae4SAndroid Build Coastguard Worker     /* Let cookie-path be the default-path. */
302*6236dae4SAndroid Build Coastguard Worker     strstore(&new_path, "/", 1);
303*6236dae4SAndroid Build Coastguard Worker     return new_path;
304*6236dae4SAndroid Build Coastguard Worker   }
305*6236dae4SAndroid Build Coastguard Worker 
306*6236dae4SAndroid Build Coastguard Worker   /* convert /hoge/ to /hoge */
307*6236dae4SAndroid Build Coastguard Worker   if(len && new_path[len - 1] == '/') {
308*6236dae4SAndroid Build Coastguard Worker     new_path[len - 1] = 0x0;
309*6236dae4SAndroid Build Coastguard Worker   }
310*6236dae4SAndroid Build Coastguard Worker 
311*6236dae4SAndroid Build Coastguard Worker   return new_path;
312*6236dae4SAndroid Build Coastguard Worker }
313*6236dae4SAndroid Build Coastguard Worker 
314*6236dae4SAndroid Build Coastguard Worker /*
315*6236dae4SAndroid Build Coastguard Worker  * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
316*6236dae4SAndroid Build Coastguard Worker  *
317*6236dae4SAndroid Build Coastguard Worker  * NOTE: OOM or cookie parsing failures are ignored.
318*6236dae4SAndroid Build Coastguard Worker  */
Curl_cookie_loadfiles(struct Curl_easy * data)319*6236dae4SAndroid Build Coastguard Worker void Curl_cookie_loadfiles(struct Curl_easy *data)
320*6236dae4SAndroid Build Coastguard Worker {
321*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *list = data->state.cookielist;
322*6236dae4SAndroid Build Coastguard Worker   if(list) {
323*6236dae4SAndroid Build Coastguard Worker     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
324*6236dae4SAndroid Build Coastguard Worker     while(list) {
325*6236dae4SAndroid Build Coastguard Worker       struct CookieInfo *ci =
326*6236dae4SAndroid Build Coastguard Worker         Curl_cookie_init(data, list->data, data->cookies,
327*6236dae4SAndroid Build Coastguard Worker                          data->set.cookiesession);
328*6236dae4SAndroid Build Coastguard Worker       if(!ci)
329*6236dae4SAndroid Build Coastguard Worker         /*
330*6236dae4SAndroid Build Coastguard Worker          * Failure may be due to OOM or a bad cookie; both are ignored
331*6236dae4SAndroid Build Coastguard Worker          * but only the first should be
332*6236dae4SAndroid Build Coastguard Worker          */
333*6236dae4SAndroid Build Coastguard Worker         infof(data, "ignoring failed cookie_init for %s", list->data);
334*6236dae4SAndroid Build Coastguard Worker       else
335*6236dae4SAndroid Build Coastguard Worker         data->cookies = ci;
336*6236dae4SAndroid Build Coastguard Worker       list = list->next;
337*6236dae4SAndroid Build Coastguard Worker     }
338*6236dae4SAndroid Build Coastguard Worker     Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
339*6236dae4SAndroid Build Coastguard Worker   }
340*6236dae4SAndroid Build Coastguard Worker }
341*6236dae4SAndroid Build Coastguard Worker 
342*6236dae4SAndroid Build Coastguard Worker /*
343*6236dae4SAndroid Build Coastguard Worker  * strstore
344*6236dae4SAndroid Build Coastguard Worker  *
345*6236dae4SAndroid Build Coastguard Worker  * A thin wrapper around strdup which ensures that any memory allocated at
346*6236dae4SAndroid Build Coastguard Worker  * *str will be freed before the string allocated by strdup is stored there.
347*6236dae4SAndroid Build Coastguard Worker  * The intended usecase is repeated assignments to the same variable during
348*6236dae4SAndroid Build Coastguard Worker  * parsing in a last-wins scenario. The caller is responsible for checking
349*6236dae4SAndroid Build Coastguard Worker  * for OOM errors.
350*6236dae4SAndroid Build Coastguard Worker  */
strstore(char ** str,const char * newstr,size_t len)351*6236dae4SAndroid Build Coastguard Worker static void strstore(char **str, const char *newstr, size_t len)
352*6236dae4SAndroid Build Coastguard Worker {
353*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(newstr);
354*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(str);
355*6236dae4SAndroid Build Coastguard Worker   free(*str);
356*6236dae4SAndroid Build Coastguard Worker   *str = Curl_memdup0(newstr, len);
357*6236dae4SAndroid Build Coastguard Worker }
358*6236dae4SAndroid Build Coastguard Worker 
359*6236dae4SAndroid Build Coastguard Worker /*
360*6236dae4SAndroid Build Coastguard Worker  * remove_expired
361*6236dae4SAndroid Build Coastguard Worker  *
362*6236dae4SAndroid Build Coastguard Worker  * Remove expired cookies from the hash by inspecting the expires timestamp on
363*6236dae4SAndroid Build Coastguard Worker  * each cookie in the hash, freeing and deleting any where the timestamp is in
364*6236dae4SAndroid Build Coastguard Worker  * the past. If the cookiejar has recorded the next timestamp at which one or
365*6236dae4SAndroid Build Coastguard Worker  * more cookies expire, then processing will exit early in case this timestamp
366*6236dae4SAndroid Build Coastguard Worker  * is in the future.
367*6236dae4SAndroid Build Coastguard Worker  */
remove_expired(struct CookieInfo * ci)368*6236dae4SAndroid Build Coastguard Worker static void remove_expired(struct CookieInfo *ci)
369*6236dae4SAndroid Build Coastguard Worker {
370*6236dae4SAndroid Build Coastguard Worker   struct Cookie *co;
371*6236dae4SAndroid Build Coastguard Worker   curl_off_t now = (curl_off_t)time(NULL);
372*6236dae4SAndroid Build Coastguard Worker   unsigned int i;
373*6236dae4SAndroid Build Coastguard Worker 
374*6236dae4SAndroid Build Coastguard Worker   /*
375*6236dae4SAndroid Build Coastguard Worker    * If the earliest expiration timestamp in the jar is in the future we can
376*6236dae4SAndroid Build Coastguard Worker    * skip scanning the whole jar and instead exit early as there will not be
377*6236dae4SAndroid Build Coastguard Worker    * any cookies to evict. If we need to evict however, reset the
378*6236dae4SAndroid Build Coastguard Worker    * next_expiration counter in order to track the next one. In case the
379*6236dae4SAndroid Build Coastguard Worker    * recorded first expiration is the max offset, then perform the safe
380*6236dae4SAndroid Build Coastguard Worker    * fallback of checking all cookies.
381*6236dae4SAndroid Build Coastguard Worker    */
382*6236dae4SAndroid Build Coastguard Worker   if(now < ci->next_expiration &&
383*6236dae4SAndroid Build Coastguard Worker      ci->next_expiration != CURL_OFF_T_MAX)
384*6236dae4SAndroid Build Coastguard Worker     return;
385*6236dae4SAndroid Build Coastguard Worker   else
386*6236dae4SAndroid Build Coastguard Worker     ci->next_expiration = CURL_OFF_T_MAX;
387*6236dae4SAndroid Build Coastguard Worker 
388*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
389*6236dae4SAndroid Build Coastguard Worker     struct Curl_llist_node *n;
390*6236dae4SAndroid Build Coastguard Worker     struct Curl_llist_node *e = NULL;
391*6236dae4SAndroid Build Coastguard Worker 
392*6236dae4SAndroid Build Coastguard Worker     for(n = Curl_llist_head(&ci->cookielist[i]); n; n = e) {
393*6236dae4SAndroid Build Coastguard Worker       co = Curl_node_elem(n);
394*6236dae4SAndroid Build Coastguard Worker       e = Curl_node_next(n);
395*6236dae4SAndroid Build Coastguard Worker       if(co->expires && co->expires < now) {
396*6236dae4SAndroid Build Coastguard Worker         Curl_node_remove(n);
397*6236dae4SAndroid Build Coastguard Worker         freecookie(co);
398*6236dae4SAndroid Build Coastguard Worker         ci->numcookies--;
399*6236dae4SAndroid Build Coastguard Worker       }
400*6236dae4SAndroid Build Coastguard Worker       else {
401*6236dae4SAndroid Build Coastguard Worker         /*
402*6236dae4SAndroid Build Coastguard Worker          * If this cookie has an expiration timestamp earlier than what we
403*6236dae4SAndroid Build Coastguard Worker          * have seen so far then record it for the next round of expirations.
404*6236dae4SAndroid Build Coastguard Worker          */
405*6236dae4SAndroid Build Coastguard Worker         if(co->expires && co->expires < ci->next_expiration)
406*6236dae4SAndroid Build Coastguard Worker           ci->next_expiration = co->expires;
407*6236dae4SAndroid Build Coastguard Worker       }
408*6236dae4SAndroid Build Coastguard Worker     }
409*6236dae4SAndroid Build Coastguard Worker   }
410*6236dae4SAndroid Build Coastguard Worker }
411*6236dae4SAndroid Build Coastguard Worker 
412*6236dae4SAndroid Build Coastguard Worker #ifndef USE_LIBPSL
413*6236dae4SAndroid Build Coastguard Worker /* Make sure domain contains a dot or is localhost. */
bad_domain(const char * domain,size_t len)414*6236dae4SAndroid Build Coastguard Worker static bool bad_domain(const char *domain, size_t len)
415*6236dae4SAndroid Build Coastguard Worker {
416*6236dae4SAndroid Build Coastguard Worker   if((len == 9) && strncasecompare(domain, "localhost", 9))
417*6236dae4SAndroid Build Coastguard Worker     return FALSE;
418*6236dae4SAndroid Build Coastguard Worker   else {
419*6236dae4SAndroid Build Coastguard Worker     /* there must be a dot present, but that dot must not be a trailing dot */
420*6236dae4SAndroid Build Coastguard Worker     char *dot = memchr(domain, '.', len);
421*6236dae4SAndroid Build Coastguard Worker     if(dot) {
422*6236dae4SAndroid Build Coastguard Worker       size_t i = dot - domain;
423*6236dae4SAndroid Build Coastguard Worker       if((len - i) > 1)
424*6236dae4SAndroid Build Coastguard Worker         /* the dot is not the last byte */
425*6236dae4SAndroid Build Coastguard Worker         return FALSE;
426*6236dae4SAndroid Build Coastguard Worker     }
427*6236dae4SAndroid Build Coastguard Worker   }
428*6236dae4SAndroid Build Coastguard Worker   return TRUE;
429*6236dae4SAndroid Build Coastguard Worker }
430*6236dae4SAndroid Build Coastguard Worker #endif
431*6236dae4SAndroid Build Coastguard Worker 
432*6236dae4SAndroid Build Coastguard Worker /*
433*6236dae4SAndroid Build Coastguard Worker   RFC 6265 section 4.1.1 says a server should accept this range:
434*6236dae4SAndroid Build Coastguard Worker 
435*6236dae4SAndroid Build Coastguard Worker   cookie-octet    = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
436*6236dae4SAndroid Build Coastguard Worker 
437*6236dae4SAndroid Build Coastguard Worker   But Firefox and Chrome as of June 2022 accept space, comma and double-quotes
438*6236dae4SAndroid Build Coastguard Worker   fine. The prime reason for filtering out control bytes is that some HTTP
439*6236dae4SAndroid Build Coastguard Worker   servers return 400 for requests that contain such.
440*6236dae4SAndroid Build Coastguard Worker */
invalid_octets(const char * p)441*6236dae4SAndroid Build Coastguard Worker static int invalid_octets(const char *p)
442*6236dae4SAndroid Build Coastguard Worker {
443*6236dae4SAndroid Build Coastguard Worker   /* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */
444*6236dae4SAndroid Build Coastguard Worker   static const char badoctets[] = {
445*6236dae4SAndroid Build Coastguard Worker     "\x01\x02\x03\x04\x05\x06\x07\x08\x0a"
446*6236dae4SAndroid Build Coastguard Worker     "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
447*6236dae4SAndroid Build Coastguard Worker     "\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f"
448*6236dae4SAndroid Build Coastguard Worker   };
449*6236dae4SAndroid Build Coastguard Worker   size_t len;
450*6236dae4SAndroid Build Coastguard Worker   /* scan for all the octets that are *not* in cookie-octet */
451*6236dae4SAndroid Build Coastguard Worker   len = strcspn(p, badoctets);
452*6236dae4SAndroid Build Coastguard Worker   return (p[len] != '\0');
453*6236dae4SAndroid Build Coastguard Worker }
454*6236dae4SAndroid Build Coastguard Worker 
455*6236dae4SAndroid Build Coastguard Worker #define CERR_OK            0
456*6236dae4SAndroid Build Coastguard Worker #define CERR_TOO_LONG      1 /* input line too long */
457*6236dae4SAndroid Build Coastguard Worker #define CERR_TAB           2 /* in a wrong place */
458*6236dae4SAndroid Build Coastguard Worker #define CERR_TOO_BIG       3 /* name/value too large */
459*6236dae4SAndroid Build Coastguard Worker #define CERR_BAD           4 /* deemed incorrect */
460*6236dae4SAndroid Build Coastguard Worker #define CERR_NO_SEP        5 /* semicolon problem */
461*6236dae4SAndroid Build Coastguard Worker #define CERR_NO_NAME_VALUE 6 /* name or value problem */
462*6236dae4SAndroid Build Coastguard Worker #define CERR_INVALID_OCTET 7 /* bad content */
463*6236dae4SAndroid Build Coastguard Worker #define CERR_BAD_SECURE    8 /* secure in a bad place */
464*6236dae4SAndroid Build Coastguard Worker #define CERR_OUT_OF_MEMORY 9
465*6236dae4SAndroid Build Coastguard Worker #define CERR_NO_TAILMATCH  10
466*6236dae4SAndroid Build Coastguard Worker #define CERR_COMMENT       11 /* a commented line */
467*6236dae4SAndroid Build Coastguard Worker #define CERR_RANGE         12 /* expire range problem */
468*6236dae4SAndroid Build Coastguard Worker #define CERR_FIELDS        13 /* incomplete netscape line */
469*6236dae4SAndroid Build Coastguard Worker #define CERR_PSL           14 /* a public suffix */
470*6236dae4SAndroid Build Coastguard Worker #define CERR_LIVE_WINS     15
471*6236dae4SAndroid Build Coastguard Worker 
472*6236dae4SAndroid Build Coastguard Worker static int
parse_cookie_header(struct Curl_easy * data,struct Cookie * co,struct CookieInfo * ci,const char * ptr,const char * domain,const char * path,bool secure)473*6236dae4SAndroid Build Coastguard Worker parse_cookie_header(struct Curl_easy *data,
474*6236dae4SAndroid Build Coastguard Worker                     struct Cookie *co,
475*6236dae4SAndroid Build Coastguard Worker                     struct CookieInfo *ci,
476*6236dae4SAndroid Build Coastguard Worker                     const char *ptr,
477*6236dae4SAndroid Build Coastguard Worker                     const char *domain, /* default domain */
478*6236dae4SAndroid Build Coastguard Worker                     const char *path,   /* full path used when this cookie is
479*6236dae4SAndroid Build Coastguard Worker                                            set, used to get default path for
480*6236dae4SAndroid Build Coastguard Worker                                            the cookie unless set */
481*6236dae4SAndroid Build Coastguard Worker                     bool secure)  /* TRUE if connection is over secure
482*6236dae4SAndroid Build Coastguard Worker                                      origin */
483*6236dae4SAndroid Build Coastguard Worker {
484*6236dae4SAndroid Build Coastguard Worker   /* This line was read off an HTTP-header */
485*6236dae4SAndroid Build Coastguard Worker   time_t now;
486*6236dae4SAndroid Build Coastguard Worker   size_t linelength = strlen(ptr);
487*6236dae4SAndroid Build Coastguard Worker   if(linelength > MAX_COOKIE_LINE)
488*6236dae4SAndroid Build Coastguard Worker     /* discard overly long lines at once */
489*6236dae4SAndroid Build Coastguard Worker     return CERR_TOO_LONG;
490*6236dae4SAndroid Build Coastguard Worker 
491*6236dae4SAndroid Build Coastguard Worker   now = time(NULL);
492*6236dae4SAndroid Build Coastguard Worker   do {
493*6236dae4SAndroid Build Coastguard Worker     size_t vlen;
494*6236dae4SAndroid Build Coastguard Worker     size_t nlen;
495*6236dae4SAndroid Build Coastguard Worker 
496*6236dae4SAndroid Build Coastguard Worker     while(*ptr && ISBLANK(*ptr))
497*6236dae4SAndroid Build Coastguard Worker       ptr++;
498*6236dae4SAndroid Build Coastguard Worker 
499*6236dae4SAndroid Build Coastguard Worker     /* we have a <name>=<value> pair or a stand-alone word here */
500*6236dae4SAndroid Build Coastguard Worker     nlen = strcspn(ptr, ";\t\r\n=");
501*6236dae4SAndroid Build Coastguard Worker     if(nlen) {
502*6236dae4SAndroid Build Coastguard Worker       bool done = FALSE;
503*6236dae4SAndroid Build Coastguard Worker       bool sep = FALSE;
504*6236dae4SAndroid Build Coastguard Worker       const char *namep = ptr;
505*6236dae4SAndroid Build Coastguard Worker       const char *valuep;
506*6236dae4SAndroid Build Coastguard Worker 
507*6236dae4SAndroid Build Coastguard Worker       ptr += nlen;
508*6236dae4SAndroid Build Coastguard Worker 
509*6236dae4SAndroid Build Coastguard Worker       /* trim trailing spaces and tabs after name */
510*6236dae4SAndroid Build Coastguard Worker       while(nlen && ISBLANK(namep[nlen - 1]))
511*6236dae4SAndroid Build Coastguard Worker         nlen--;
512*6236dae4SAndroid Build Coastguard Worker 
513*6236dae4SAndroid Build Coastguard Worker       if(*ptr == '=') {
514*6236dae4SAndroid Build Coastguard Worker         vlen = strcspn(++ptr, ";\r\n");
515*6236dae4SAndroid Build Coastguard Worker         valuep = ptr;
516*6236dae4SAndroid Build Coastguard Worker         sep = TRUE;
517*6236dae4SAndroid Build Coastguard Worker         ptr = &valuep[vlen];
518*6236dae4SAndroid Build Coastguard Worker 
519*6236dae4SAndroid Build Coastguard Worker         /* Strip off trailing whitespace from the value */
520*6236dae4SAndroid Build Coastguard Worker         while(vlen && ISBLANK(valuep[vlen-1]))
521*6236dae4SAndroid Build Coastguard Worker           vlen--;
522*6236dae4SAndroid Build Coastguard Worker 
523*6236dae4SAndroid Build Coastguard Worker         /* Skip leading whitespace from the value */
524*6236dae4SAndroid Build Coastguard Worker         while(vlen && ISBLANK(*valuep)) {
525*6236dae4SAndroid Build Coastguard Worker           valuep++;
526*6236dae4SAndroid Build Coastguard Worker           vlen--;
527*6236dae4SAndroid Build Coastguard Worker         }
528*6236dae4SAndroid Build Coastguard Worker 
529*6236dae4SAndroid Build Coastguard Worker         /* Reject cookies with a TAB inside the value */
530*6236dae4SAndroid Build Coastguard Worker         if(memchr(valuep, '\t', vlen)) {
531*6236dae4SAndroid Build Coastguard Worker           infof(data, "cookie contains TAB, dropping");
532*6236dae4SAndroid Build Coastguard Worker           return CERR_TAB;
533*6236dae4SAndroid Build Coastguard Worker         }
534*6236dae4SAndroid Build Coastguard Worker       }
535*6236dae4SAndroid Build Coastguard Worker       else {
536*6236dae4SAndroid Build Coastguard Worker         valuep = NULL;
537*6236dae4SAndroid Build Coastguard Worker         vlen = 0;
538*6236dae4SAndroid Build Coastguard Worker       }
539*6236dae4SAndroid Build Coastguard Worker 
540*6236dae4SAndroid Build Coastguard Worker       /*
541*6236dae4SAndroid Build Coastguard Worker        * Check for too long individual name or contents, or too long
542*6236dae4SAndroid Build Coastguard Worker        * combination of name + contents. Chrome and Firefox support 4095 or
543*6236dae4SAndroid Build Coastguard Worker        * 4096 bytes combo
544*6236dae4SAndroid Build Coastguard Worker        */
545*6236dae4SAndroid Build Coastguard Worker       if(nlen >= (MAX_NAME-1) || vlen >= (MAX_NAME-1) ||
546*6236dae4SAndroid Build Coastguard Worker          ((nlen + vlen) > MAX_NAME)) {
547*6236dae4SAndroid Build Coastguard Worker         infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
548*6236dae4SAndroid Build Coastguard Worker               nlen, vlen);
549*6236dae4SAndroid Build Coastguard Worker         return CERR_TOO_BIG;
550*6236dae4SAndroid Build Coastguard Worker       }
551*6236dae4SAndroid Build Coastguard Worker 
552*6236dae4SAndroid Build Coastguard Worker       /*
553*6236dae4SAndroid Build Coastguard Worker        * Check if we have a reserved prefix set before anything else, as we
554*6236dae4SAndroid Build Coastguard Worker        * otherwise have to test for the prefix in both the cookie name and
555*6236dae4SAndroid Build Coastguard Worker        * "the rest". Prefixes must start with '__' and end with a '-', so
556*6236dae4SAndroid Build Coastguard Worker        * only test for names where that can possibly be true.
557*6236dae4SAndroid Build Coastguard Worker        */
558*6236dae4SAndroid Build Coastguard Worker       if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') {
559*6236dae4SAndroid Build Coastguard Worker         if(strncasecompare("__Secure-", namep, 9))
560*6236dae4SAndroid Build Coastguard Worker           co->prefix_secure = TRUE;
561*6236dae4SAndroid Build Coastguard Worker         else if(strncasecompare("__Host-", namep, 7))
562*6236dae4SAndroid Build Coastguard Worker           co->prefix_host = TRUE;
563*6236dae4SAndroid Build Coastguard Worker       }
564*6236dae4SAndroid Build Coastguard Worker 
565*6236dae4SAndroid Build Coastguard Worker       /*
566*6236dae4SAndroid Build Coastguard Worker        * Use strstore() below to properly deal with received cookie
567*6236dae4SAndroid Build Coastguard Worker        * headers that have the same string property set more than once,
568*6236dae4SAndroid Build Coastguard Worker        * and then we use the last one.
569*6236dae4SAndroid Build Coastguard Worker        */
570*6236dae4SAndroid Build Coastguard Worker 
571*6236dae4SAndroid Build Coastguard Worker       if(!co->name) {
572*6236dae4SAndroid Build Coastguard Worker         /* The very first name/value pair is the actual cookie name */
573*6236dae4SAndroid Build Coastguard Worker         if(!sep)
574*6236dae4SAndroid Build Coastguard Worker           /* Bad name/value pair. */
575*6236dae4SAndroid Build Coastguard Worker           return CERR_NO_SEP;
576*6236dae4SAndroid Build Coastguard Worker 
577*6236dae4SAndroid Build Coastguard Worker         strstore(&co->name, namep, nlen);
578*6236dae4SAndroid Build Coastguard Worker         strstore(&co->value, valuep, vlen);
579*6236dae4SAndroid Build Coastguard Worker         done = TRUE;
580*6236dae4SAndroid Build Coastguard Worker         if(!co->name || !co->value)
581*6236dae4SAndroid Build Coastguard Worker           return CERR_NO_NAME_VALUE;
582*6236dae4SAndroid Build Coastguard Worker 
583*6236dae4SAndroid Build Coastguard Worker         if(invalid_octets(co->value) || invalid_octets(co->name)) {
584*6236dae4SAndroid Build Coastguard Worker           infof(data, "invalid octets in name/value, cookie dropped");
585*6236dae4SAndroid Build Coastguard Worker           return CERR_INVALID_OCTET;
586*6236dae4SAndroid Build Coastguard Worker         }
587*6236dae4SAndroid Build Coastguard Worker       }
588*6236dae4SAndroid Build Coastguard Worker       else if(!vlen) {
589*6236dae4SAndroid Build Coastguard Worker         /*
590*6236dae4SAndroid Build Coastguard Worker          * this was a "<name>=" with no content, and we must allow
591*6236dae4SAndroid Build Coastguard Worker          * 'secure' and 'httponly' specified this weirdly
592*6236dae4SAndroid Build Coastguard Worker          */
593*6236dae4SAndroid Build Coastguard Worker         done = TRUE;
594*6236dae4SAndroid Build Coastguard Worker         /*
595*6236dae4SAndroid Build Coastguard Worker          * secure cookies are only allowed to be set when the connection is
596*6236dae4SAndroid Build Coastguard Worker          * using a secure protocol, or when the cookie is being set by
597*6236dae4SAndroid Build Coastguard Worker          * reading from file
598*6236dae4SAndroid Build Coastguard Worker          */
599*6236dae4SAndroid Build Coastguard Worker         if((nlen == 6) && strncasecompare("secure", namep, 6)) {
600*6236dae4SAndroid Build Coastguard Worker           if(secure || !ci->running) {
601*6236dae4SAndroid Build Coastguard Worker             co->secure = TRUE;
602*6236dae4SAndroid Build Coastguard Worker           }
603*6236dae4SAndroid Build Coastguard Worker           else {
604*6236dae4SAndroid Build Coastguard Worker             return CERR_BAD_SECURE;
605*6236dae4SAndroid Build Coastguard Worker           }
606*6236dae4SAndroid Build Coastguard Worker         }
607*6236dae4SAndroid Build Coastguard Worker         else if((nlen == 8) && strncasecompare("httponly", namep, 8))
608*6236dae4SAndroid Build Coastguard Worker           co->httponly = TRUE;
609*6236dae4SAndroid Build Coastguard Worker         else if(sep)
610*6236dae4SAndroid Build Coastguard Worker           /* there was a '=' so we are not done parsing this field */
611*6236dae4SAndroid Build Coastguard Worker           done = FALSE;
612*6236dae4SAndroid Build Coastguard Worker       }
613*6236dae4SAndroid Build Coastguard Worker       if(done)
614*6236dae4SAndroid Build Coastguard Worker         ;
615*6236dae4SAndroid Build Coastguard Worker       else if((nlen == 4) && strncasecompare("path", namep, 4)) {
616*6236dae4SAndroid Build Coastguard Worker         strstore(&co->path, valuep, vlen);
617*6236dae4SAndroid Build Coastguard Worker         if(!co->path)
618*6236dae4SAndroid Build Coastguard Worker           return CERR_OUT_OF_MEMORY;
619*6236dae4SAndroid Build Coastguard Worker         free(co->spath); /* if this is set again */
620*6236dae4SAndroid Build Coastguard Worker         co->spath = sanitize_cookie_path(co->path);
621*6236dae4SAndroid Build Coastguard Worker         if(!co->spath)
622*6236dae4SAndroid Build Coastguard Worker           return CERR_OUT_OF_MEMORY;
623*6236dae4SAndroid Build Coastguard Worker       }
624*6236dae4SAndroid Build Coastguard Worker       else if((nlen == 6) &&
625*6236dae4SAndroid Build Coastguard Worker               strncasecompare("domain", namep, 6) && vlen) {
626*6236dae4SAndroid Build Coastguard Worker         bool is_ip;
627*6236dae4SAndroid Build Coastguard Worker 
628*6236dae4SAndroid Build Coastguard Worker         /*
629*6236dae4SAndroid Build Coastguard Worker          * Now, we make sure that our host is within the given domain, or
630*6236dae4SAndroid Build Coastguard Worker          * the given domain is not valid and thus cannot be set.
631*6236dae4SAndroid Build Coastguard Worker          */
632*6236dae4SAndroid Build Coastguard Worker 
633*6236dae4SAndroid Build Coastguard Worker         if('.' == valuep[0]) {
634*6236dae4SAndroid Build Coastguard Worker           valuep++; /* ignore preceding dot */
635*6236dae4SAndroid Build Coastguard Worker           vlen--;
636*6236dae4SAndroid Build Coastguard Worker         }
637*6236dae4SAndroid Build Coastguard Worker 
638*6236dae4SAndroid Build Coastguard Worker #ifndef USE_LIBPSL
639*6236dae4SAndroid Build Coastguard Worker         /*
640*6236dae4SAndroid Build Coastguard Worker          * Without PSL we do not know when the incoming cookie is set on a
641*6236dae4SAndroid Build Coastguard Worker          * TLD or otherwise "protected" suffix. To reduce risk, we require a
642*6236dae4SAndroid Build Coastguard Worker          * dot OR the exact hostname being "localhost".
643*6236dae4SAndroid Build Coastguard Worker          */
644*6236dae4SAndroid Build Coastguard Worker         if(bad_domain(valuep, vlen))
645*6236dae4SAndroid Build Coastguard Worker           domain = ":";
646*6236dae4SAndroid Build Coastguard Worker #endif
647*6236dae4SAndroid Build Coastguard Worker 
648*6236dae4SAndroid Build Coastguard Worker         is_ip = Curl_host_is_ipnum(domain ? domain : valuep);
649*6236dae4SAndroid Build Coastguard Worker 
650*6236dae4SAndroid Build Coastguard Worker         if(!domain
651*6236dae4SAndroid Build Coastguard Worker            || (is_ip && !strncmp(valuep, domain, vlen) &&
652*6236dae4SAndroid Build Coastguard Worker                (vlen == strlen(domain)))
653*6236dae4SAndroid Build Coastguard Worker            || (!is_ip && cookie_tailmatch(valuep, vlen, domain))) {
654*6236dae4SAndroid Build Coastguard Worker           strstore(&co->domain, valuep, vlen);
655*6236dae4SAndroid Build Coastguard Worker           if(!co->domain)
656*6236dae4SAndroid Build Coastguard Worker             return CERR_OUT_OF_MEMORY;
657*6236dae4SAndroid Build Coastguard Worker 
658*6236dae4SAndroid Build Coastguard Worker           if(!is_ip)
659*6236dae4SAndroid Build Coastguard Worker             co->tailmatch = TRUE; /* we always do that if the domain name was
660*6236dae4SAndroid Build Coastguard Worker                                      given */
661*6236dae4SAndroid Build Coastguard Worker         }
662*6236dae4SAndroid Build Coastguard Worker         else {
663*6236dae4SAndroid Build Coastguard Worker           /*
664*6236dae4SAndroid Build Coastguard Worker            * We did not get a tailmatch and then the attempted set domain is
665*6236dae4SAndroid Build Coastguard Worker            * not a domain to which the current host belongs. Mark as bad.
666*6236dae4SAndroid Build Coastguard Worker            */
667*6236dae4SAndroid Build Coastguard Worker           infof(data, "skipped cookie with bad tailmatch domain: %s",
668*6236dae4SAndroid Build Coastguard Worker                 valuep);
669*6236dae4SAndroid Build Coastguard Worker           return CERR_NO_TAILMATCH;
670*6236dae4SAndroid Build Coastguard Worker         }
671*6236dae4SAndroid Build Coastguard Worker       }
672*6236dae4SAndroid Build Coastguard Worker       else if((nlen == 7) && strncasecompare("version", namep, 7)) {
673*6236dae4SAndroid Build Coastguard Worker         /* just ignore */
674*6236dae4SAndroid Build Coastguard Worker       }
675*6236dae4SAndroid Build Coastguard Worker       else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
676*6236dae4SAndroid Build Coastguard Worker         /*
677*6236dae4SAndroid Build Coastguard Worker          * Defined in RFC2109:
678*6236dae4SAndroid Build Coastguard Worker          *
679*6236dae4SAndroid Build Coastguard Worker          * Optional. The Max-Age attribute defines the lifetime of the
680*6236dae4SAndroid Build Coastguard Worker          * cookie, in seconds. The delta-seconds value is a decimal non-
681*6236dae4SAndroid Build Coastguard Worker          * negative integer. After delta-seconds seconds elapse, the
682*6236dae4SAndroid Build Coastguard Worker          * client should discard the cookie. A value of zero means the
683*6236dae4SAndroid Build Coastguard Worker          * cookie should be discarded immediately.
684*6236dae4SAndroid Build Coastguard Worker          */
685*6236dae4SAndroid Build Coastguard Worker         CURLofft offt;
686*6236dae4SAndroid Build Coastguard Worker         const char *maxage = valuep;
687*6236dae4SAndroid Build Coastguard Worker         offt = curlx_strtoofft((*maxage == '\"') ?
688*6236dae4SAndroid Build Coastguard Worker                                &maxage[1] : &maxage[0], NULL, 10,
689*6236dae4SAndroid Build Coastguard Worker                                &co->expires);
690*6236dae4SAndroid Build Coastguard Worker         switch(offt) {
691*6236dae4SAndroid Build Coastguard Worker         case CURL_OFFT_FLOW:
692*6236dae4SAndroid Build Coastguard Worker           /* overflow, used max value */
693*6236dae4SAndroid Build Coastguard Worker           co->expires = CURL_OFF_T_MAX;
694*6236dae4SAndroid Build Coastguard Worker           break;
695*6236dae4SAndroid Build Coastguard Worker         case CURL_OFFT_INVAL:
696*6236dae4SAndroid Build Coastguard Worker           /* negative or otherwise bad, expire */
697*6236dae4SAndroid Build Coastguard Worker           co->expires = 1;
698*6236dae4SAndroid Build Coastguard Worker           break;
699*6236dae4SAndroid Build Coastguard Worker         case CURL_OFFT_OK:
700*6236dae4SAndroid Build Coastguard Worker           if(!co->expires)
701*6236dae4SAndroid Build Coastguard Worker             /* already expired */
702*6236dae4SAndroid Build Coastguard Worker             co->expires = 1;
703*6236dae4SAndroid Build Coastguard Worker           else if(CURL_OFF_T_MAX - now < co->expires)
704*6236dae4SAndroid Build Coastguard Worker             /* would overflow */
705*6236dae4SAndroid Build Coastguard Worker             co->expires = CURL_OFF_T_MAX;
706*6236dae4SAndroid Build Coastguard Worker           else
707*6236dae4SAndroid Build Coastguard Worker             co->expires += now;
708*6236dae4SAndroid Build Coastguard Worker           break;
709*6236dae4SAndroid Build Coastguard Worker         }
710*6236dae4SAndroid Build Coastguard Worker       }
711*6236dae4SAndroid Build Coastguard Worker       else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
712*6236dae4SAndroid Build Coastguard Worker         if(!co->expires) {
713*6236dae4SAndroid Build Coastguard Worker           /*
714*6236dae4SAndroid Build Coastguard Worker            * Let max-age have priority.
715*6236dae4SAndroid Build Coastguard Worker            *
716*6236dae4SAndroid Build Coastguard Worker            * If the date cannot get parsed for whatever reason, the cookie
717*6236dae4SAndroid Build Coastguard Worker            * will be treated as a session cookie
718*6236dae4SAndroid Build Coastguard Worker            */
719*6236dae4SAndroid Build Coastguard Worker           co->expires = Curl_getdate_capped(valuep);
720*6236dae4SAndroid Build Coastguard Worker 
721*6236dae4SAndroid Build Coastguard Worker           /*
722*6236dae4SAndroid Build Coastguard Worker            * Session cookies have expires set to 0 so if we get that back
723*6236dae4SAndroid Build Coastguard Worker            * from the date parser let's add a second to make it a
724*6236dae4SAndroid Build Coastguard Worker            * non-session cookie
725*6236dae4SAndroid Build Coastguard Worker            */
726*6236dae4SAndroid Build Coastguard Worker           if(co->expires == 0)
727*6236dae4SAndroid Build Coastguard Worker             co->expires = 1;
728*6236dae4SAndroid Build Coastguard Worker           else if(co->expires < 0)
729*6236dae4SAndroid Build Coastguard Worker             co->expires = 0;
730*6236dae4SAndroid Build Coastguard Worker         }
731*6236dae4SAndroid Build Coastguard Worker       }
732*6236dae4SAndroid Build Coastguard Worker 
733*6236dae4SAndroid Build Coastguard Worker       /*
734*6236dae4SAndroid Build Coastguard Worker        * Else, this is the second (or more) name we do not know about!
735*6236dae4SAndroid Build Coastguard Worker        */
736*6236dae4SAndroid Build Coastguard Worker     }
737*6236dae4SAndroid Build Coastguard Worker     else {
738*6236dae4SAndroid Build Coastguard Worker       /* this is an "illegal" <what>=<this> pair */
739*6236dae4SAndroid Build Coastguard Worker     }
740*6236dae4SAndroid Build Coastguard Worker 
741*6236dae4SAndroid Build Coastguard Worker     while(*ptr && ISBLANK(*ptr))
742*6236dae4SAndroid Build Coastguard Worker       ptr++;
743*6236dae4SAndroid Build Coastguard Worker     if(*ptr == ';')
744*6236dae4SAndroid Build Coastguard Worker       ptr++;
745*6236dae4SAndroid Build Coastguard Worker     else
746*6236dae4SAndroid Build Coastguard Worker       break;
747*6236dae4SAndroid Build Coastguard Worker   } while(1);
748*6236dae4SAndroid Build Coastguard Worker 
749*6236dae4SAndroid Build Coastguard Worker   if(!co->domain && domain) {
750*6236dae4SAndroid Build Coastguard Worker     /* no domain was given in the header line, set the default */
751*6236dae4SAndroid Build Coastguard Worker     co->domain = strdup(domain);
752*6236dae4SAndroid Build Coastguard Worker     if(!co->domain)
753*6236dae4SAndroid Build Coastguard Worker       return CERR_OUT_OF_MEMORY;
754*6236dae4SAndroid Build Coastguard Worker   }
755*6236dae4SAndroid Build Coastguard Worker 
756*6236dae4SAndroid Build Coastguard Worker   if(!co->path && path) {
757*6236dae4SAndroid Build Coastguard Worker     /*
758*6236dae4SAndroid Build Coastguard Worker      * No path was given in the header line, set the default. Note that the
759*6236dae4SAndroid Build Coastguard Worker      * passed-in path to this function MAY have a '?' and following part that
760*6236dae4SAndroid Build Coastguard Worker      * MUST NOT be stored as part of the path.
761*6236dae4SAndroid Build Coastguard Worker      */
762*6236dae4SAndroid Build Coastguard Worker     char *queryp = strchr(path, '?');
763*6236dae4SAndroid Build Coastguard Worker 
764*6236dae4SAndroid Build Coastguard Worker     /*
765*6236dae4SAndroid Build Coastguard Worker      * queryp is where the interesting part of the path ends, so now we
766*6236dae4SAndroid Build Coastguard Worker      * want to the find the last
767*6236dae4SAndroid Build Coastguard Worker      */
768*6236dae4SAndroid Build Coastguard Worker     char *endslash;
769*6236dae4SAndroid Build Coastguard Worker     if(!queryp)
770*6236dae4SAndroid Build Coastguard Worker       endslash = strrchr(path, '/');
771*6236dae4SAndroid Build Coastguard Worker     else
772*6236dae4SAndroid Build Coastguard Worker       endslash = memrchr(path, '/', (queryp - path));
773*6236dae4SAndroid Build Coastguard Worker     if(endslash) {
774*6236dae4SAndroid Build Coastguard Worker       size_t pathlen = (endslash-path + 1); /* include end slash */
775*6236dae4SAndroid Build Coastguard Worker       co->path = Curl_memdup0(path, pathlen);
776*6236dae4SAndroid Build Coastguard Worker       if(co->path) {
777*6236dae4SAndroid Build Coastguard Worker         co->spath = sanitize_cookie_path(co->path);
778*6236dae4SAndroid Build Coastguard Worker         if(!co->spath)
779*6236dae4SAndroid Build Coastguard Worker           return CERR_OUT_OF_MEMORY;
780*6236dae4SAndroid Build Coastguard Worker       }
781*6236dae4SAndroid Build Coastguard Worker       else
782*6236dae4SAndroid Build Coastguard Worker         return CERR_OUT_OF_MEMORY;
783*6236dae4SAndroid Build Coastguard Worker     }
784*6236dae4SAndroid Build Coastguard Worker   }
785*6236dae4SAndroid Build Coastguard Worker 
786*6236dae4SAndroid Build Coastguard Worker   /*
787*6236dae4SAndroid Build Coastguard Worker    * If we did not get a cookie name, or a bad one, the this is an illegal
788*6236dae4SAndroid Build Coastguard Worker    * line so bail out.
789*6236dae4SAndroid Build Coastguard Worker    */
790*6236dae4SAndroid Build Coastguard Worker   if(!co->name)
791*6236dae4SAndroid Build Coastguard Worker     return CERR_BAD;
792*6236dae4SAndroid Build Coastguard Worker 
793*6236dae4SAndroid Build Coastguard Worker   data->req.setcookies++;
794*6236dae4SAndroid Build Coastguard Worker   return CERR_OK;
795*6236dae4SAndroid Build Coastguard Worker }
796*6236dae4SAndroid Build Coastguard Worker 
797*6236dae4SAndroid Build Coastguard Worker static int
parse_netscape(struct Cookie * co,struct CookieInfo * ci,const char * lineptr,bool secure)798*6236dae4SAndroid Build Coastguard Worker parse_netscape(struct Cookie *co,
799*6236dae4SAndroid Build Coastguard Worker                struct CookieInfo *ci,
800*6236dae4SAndroid Build Coastguard Worker                const char *lineptr,
801*6236dae4SAndroid Build Coastguard Worker                bool secure)  /* TRUE if connection is over secure
802*6236dae4SAndroid Build Coastguard Worker                                 origin */
803*6236dae4SAndroid Build Coastguard Worker {
804*6236dae4SAndroid Build Coastguard Worker   /*
805*6236dae4SAndroid Build Coastguard Worker    * This line is NOT an HTTP header style line, we do offer support for
806*6236dae4SAndroid Build Coastguard Worker    * reading the odd netscape cookies-file format here
807*6236dae4SAndroid Build Coastguard Worker    */
808*6236dae4SAndroid Build Coastguard Worker   char *ptr;
809*6236dae4SAndroid Build Coastguard Worker   char *firstptr;
810*6236dae4SAndroid Build Coastguard Worker   char *tok_buf = NULL;
811*6236dae4SAndroid Build Coastguard Worker   int fields;
812*6236dae4SAndroid Build Coastguard Worker 
813*6236dae4SAndroid Build Coastguard Worker   /*
814*6236dae4SAndroid Build Coastguard Worker    * In 2008, Internet Explorer introduced HTTP-only cookies to prevent XSS
815*6236dae4SAndroid Build Coastguard Worker    * attacks. Cookies marked httpOnly are not accessible to JavaScript. In
816*6236dae4SAndroid Build Coastguard Worker    * Firefox's cookie files, they are prefixed #HttpOnly_ and the rest
817*6236dae4SAndroid Build Coastguard Worker    * remains as usual, so we skip 10 characters of the line.
818*6236dae4SAndroid Build Coastguard Worker    */
819*6236dae4SAndroid Build Coastguard Worker   if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
820*6236dae4SAndroid Build Coastguard Worker     lineptr += 10;
821*6236dae4SAndroid Build Coastguard Worker     co->httponly = TRUE;
822*6236dae4SAndroid Build Coastguard Worker   }
823*6236dae4SAndroid Build Coastguard Worker 
824*6236dae4SAndroid Build Coastguard Worker   if(lineptr[0]=='#')
825*6236dae4SAndroid Build Coastguard Worker     /* do not even try the comments */
826*6236dae4SAndroid Build Coastguard Worker     return CERR_COMMENT;
827*6236dae4SAndroid Build Coastguard Worker 
828*6236dae4SAndroid Build Coastguard Worker   /* strip off the possible end-of-line characters */
829*6236dae4SAndroid Build Coastguard Worker   ptr = strchr(lineptr, '\r');
830*6236dae4SAndroid Build Coastguard Worker   if(ptr)
831*6236dae4SAndroid Build Coastguard Worker     *ptr = 0; /* clear it */
832*6236dae4SAndroid Build Coastguard Worker   ptr = strchr(lineptr, '\n');
833*6236dae4SAndroid Build Coastguard Worker   if(ptr)
834*6236dae4SAndroid Build Coastguard Worker     *ptr = 0; /* clear it */
835*6236dae4SAndroid Build Coastguard Worker 
836*6236dae4SAndroid Build Coastguard Worker   firstptr = strtok_r((char *)lineptr, "\t", &tok_buf); /* tokenize on TAB */
837*6236dae4SAndroid Build Coastguard Worker 
838*6236dae4SAndroid Build Coastguard Worker   /*
839*6236dae4SAndroid Build Coastguard Worker    * Now loop through the fields and init the struct we already have
840*6236dae4SAndroid Build Coastguard Worker    * allocated
841*6236dae4SAndroid Build Coastguard Worker    */
842*6236dae4SAndroid Build Coastguard Worker   fields = 0;
843*6236dae4SAndroid Build Coastguard Worker   for(ptr = firstptr; ptr; ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
844*6236dae4SAndroid Build Coastguard Worker     switch(fields) {
845*6236dae4SAndroid Build Coastguard Worker     case 0:
846*6236dae4SAndroid Build Coastguard Worker       if(ptr[0]=='.') /* skip preceding dots */
847*6236dae4SAndroid Build Coastguard Worker         ptr++;
848*6236dae4SAndroid Build Coastguard Worker       co->domain = strdup(ptr);
849*6236dae4SAndroid Build Coastguard Worker       if(!co->domain)
850*6236dae4SAndroid Build Coastguard Worker         return CERR_OUT_OF_MEMORY;
851*6236dae4SAndroid Build Coastguard Worker       break;
852*6236dae4SAndroid Build Coastguard Worker     case 1:
853*6236dae4SAndroid Build Coastguard Worker       /*
854*6236dae4SAndroid Build Coastguard Worker        * flag: A TRUE/FALSE value indicating if all machines within a given
855*6236dae4SAndroid Build Coastguard Worker        * domain can access the variable. Set TRUE when the cookie says
856*6236dae4SAndroid Build Coastguard Worker        * .domain.com and to false when the domain is complete www.domain.com
857*6236dae4SAndroid Build Coastguard Worker        */
858*6236dae4SAndroid Build Coastguard Worker       co->tailmatch = !!strcasecompare(ptr, "TRUE");
859*6236dae4SAndroid Build Coastguard Worker       break;
860*6236dae4SAndroid Build Coastguard Worker     case 2:
861*6236dae4SAndroid Build Coastguard Worker       /* The file format allows the path field to remain not filled in */
862*6236dae4SAndroid Build Coastguard Worker       if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
863*6236dae4SAndroid Build Coastguard Worker         /* only if the path does not look like a boolean option! */
864*6236dae4SAndroid Build Coastguard Worker         co->path = strdup(ptr);
865*6236dae4SAndroid Build Coastguard Worker         if(!co->path)
866*6236dae4SAndroid Build Coastguard Worker           return CERR_OUT_OF_MEMORY;
867*6236dae4SAndroid Build Coastguard Worker         else {
868*6236dae4SAndroid Build Coastguard Worker           co->spath = sanitize_cookie_path(co->path);
869*6236dae4SAndroid Build Coastguard Worker           if(!co->spath)
870*6236dae4SAndroid Build Coastguard Worker             return CERR_OUT_OF_MEMORY;
871*6236dae4SAndroid Build Coastguard Worker         }
872*6236dae4SAndroid Build Coastguard Worker         break;
873*6236dae4SAndroid Build Coastguard Worker       }
874*6236dae4SAndroid Build Coastguard Worker       /* this does not look like a path, make one up! */
875*6236dae4SAndroid Build Coastguard Worker       co->path = strdup("/");
876*6236dae4SAndroid Build Coastguard Worker       if(!co->path)
877*6236dae4SAndroid Build Coastguard Worker         return CERR_OUT_OF_MEMORY;
878*6236dae4SAndroid Build Coastguard Worker       co->spath = strdup("/");
879*6236dae4SAndroid Build Coastguard Worker       if(!co->spath)
880*6236dae4SAndroid Build Coastguard Worker         return CERR_OUT_OF_MEMORY;
881*6236dae4SAndroid Build Coastguard Worker       fields++; /* add a field and fall down to secure */
882*6236dae4SAndroid Build Coastguard Worker       FALLTHROUGH();
883*6236dae4SAndroid Build Coastguard Worker     case 3:
884*6236dae4SAndroid Build Coastguard Worker       co->secure = FALSE;
885*6236dae4SAndroid Build Coastguard Worker       if(strcasecompare(ptr, "TRUE")) {
886*6236dae4SAndroid Build Coastguard Worker         if(secure || ci->running)
887*6236dae4SAndroid Build Coastguard Worker           co->secure = TRUE;
888*6236dae4SAndroid Build Coastguard Worker         else
889*6236dae4SAndroid Build Coastguard Worker           return CERR_BAD_SECURE;
890*6236dae4SAndroid Build Coastguard Worker       }
891*6236dae4SAndroid Build Coastguard Worker       break;
892*6236dae4SAndroid Build Coastguard Worker     case 4:
893*6236dae4SAndroid Build Coastguard Worker       if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
894*6236dae4SAndroid Build Coastguard Worker         return CERR_RANGE;
895*6236dae4SAndroid Build Coastguard Worker       break;
896*6236dae4SAndroid Build Coastguard Worker     case 5:
897*6236dae4SAndroid Build Coastguard Worker       co->name = strdup(ptr);
898*6236dae4SAndroid Build Coastguard Worker       if(!co->name)
899*6236dae4SAndroid Build Coastguard Worker         return CERR_OUT_OF_MEMORY;
900*6236dae4SAndroid Build Coastguard Worker       else {
901*6236dae4SAndroid Build Coastguard Worker         /* For Netscape file format cookies we check prefix on the name */
902*6236dae4SAndroid Build Coastguard Worker         if(strncasecompare("__Secure-", co->name, 9))
903*6236dae4SAndroid Build Coastguard Worker           co->prefix_secure = TRUE;
904*6236dae4SAndroid Build Coastguard Worker         else if(strncasecompare("__Host-", co->name, 7))
905*6236dae4SAndroid Build Coastguard Worker           co->prefix_host = TRUE;
906*6236dae4SAndroid Build Coastguard Worker       }
907*6236dae4SAndroid Build Coastguard Worker       break;
908*6236dae4SAndroid Build Coastguard Worker     case 6:
909*6236dae4SAndroid Build Coastguard Worker       co->value = strdup(ptr);
910*6236dae4SAndroid Build Coastguard Worker       if(!co->value)
911*6236dae4SAndroid Build Coastguard Worker         return CERR_OUT_OF_MEMORY;
912*6236dae4SAndroid Build Coastguard Worker       break;
913*6236dae4SAndroid Build Coastguard Worker     }
914*6236dae4SAndroid Build Coastguard Worker   }
915*6236dae4SAndroid Build Coastguard Worker   if(6 == fields) {
916*6236dae4SAndroid Build Coastguard Worker     /* we got a cookie with blank contents, fix it */
917*6236dae4SAndroid Build Coastguard Worker     co->value = strdup("");
918*6236dae4SAndroid Build Coastguard Worker     if(!co->value)
919*6236dae4SAndroid Build Coastguard Worker       return CERR_OUT_OF_MEMORY;
920*6236dae4SAndroid Build Coastguard Worker     else
921*6236dae4SAndroid Build Coastguard Worker       fields++;
922*6236dae4SAndroid Build Coastguard Worker   }
923*6236dae4SAndroid Build Coastguard Worker 
924*6236dae4SAndroid Build Coastguard Worker   if(7 != fields)
925*6236dae4SAndroid Build Coastguard Worker     /* we did not find the sufficient number of fields */
926*6236dae4SAndroid Build Coastguard Worker     return CERR_FIELDS;
927*6236dae4SAndroid Build Coastguard Worker 
928*6236dae4SAndroid Build Coastguard Worker   return CERR_OK;
929*6236dae4SAndroid Build Coastguard Worker }
930*6236dae4SAndroid Build Coastguard Worker 
931*6236dae4SAndroid Build Coastguard Worker static int
is_public_suffix(struct Curl_easy * data,struct Cookie * co,const char * domain)932*6236dae4SAndroid Build Coastguard Worker is_public_suffix(struct Curl_easy *data,
933*6236dae4SAndroid Build Coastguard Worker                  struct Cookie *co,
934*6236dae4SAndroid Build Coastguard Worker                  const char *domain)
935*6236dae4SAndroid Build Coastguard Worker {
936*6236dae4SAndroid Build Coastguard Worker #ifdef USE_LIBPSL
937*6236dae4SAndroid Build Coastguard Worker   /*
938*6236dae4SAndroid Build Coastguard Worker    * Check if the domain is a Public Suffix and if yes, ignore the cookie. We
939*6236dae4SAndroid Build Coastguard Worker    * must also check that the data handle is not NULL since the psl code will
940*6236dae4SAndroid Build Coastguard Worker    * dereference it.
941*6236dae4SAndroid Build Coastguard Worker    */
942*6236dae4SAndroid Build Coastguard Worker   DEBUGF(infof(data, "PSL check set-cookie '%s' for domain=%s in %s",
943*6236dae4SAndroid Build Coastguard Worker          co->name, co->domain, domain));
944*6236dae4SAndroid Build Coastguard Worker   if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
945*6236dae4SAndroid Build Coastguard Worker     bool acceptable = FALSE;
946*6236dae4SAndroid Build Coastguard Worker     char lcase[256];
947*6236dae4SAndroid Build Coastguard Worker     char lcookie[256];
948*6236dae4SAndroid Build Coastguard Worker     size_t dlen = strlen(domain);
949*6236dae4SAndroid Build Coastguard Worker     size_t clen = strlen(co->domain);
950*6236dae4SAndroid Build Coastguard Worker     if((dlen < sizeof(lcase)) && (clen < sizeof(lcookie))) {
951*6236dae4SAndroid Build Coastguard Worker       const psl_ctx_t *psl = Curl_psl_use(data);
952*6236dae4SAndroid Build Coastguard Worker       if(psl) {
953*6236dae4SAndroid Build Coastguard Worker         /* the PSL check requires lowercase domain name and pattern */
954*6236dae4SAndroid Build Coastguard Worker         Curl_strntolower(lcase, domain, dlen + 1);
955*6236dae4SAndroid Build Coastguard Worker         Curl_strntolower(lcookie, co->domain, clen + 1);
956*6236dae4SAndroid Build Coastguard Worker         acceptable = psl_is_cookie_domain_acceptable(psl, lcase, lcookie);
957*6236dae4SAndroid Build Coastguard Worker         Curl_psl_release(data);
958*6236dae4SAndroid Build Coastguard Worker       }
959*6236dae4SAndroid Build Coastguard Worker       else
960*6236dae4SAndroid Build Coastguard Worker         infof(data, "libpsl problem, rejecting cookie for satety");
961*6236dae4SAndroid Build Coastguard Worker     }
962*6236dae4SAndroid Build Coastguard Worker 
963*6236dae4SAndroid Build Coastguard Worker     if(!acceptable) {
964*6236dae4SAndroid Build Coastguard Worker       infof(data, "cookie '%s' dropped, domain '%s' must not "
965*6236dae4SAndroid Build Coastguard Worker             "set cookies for '%s'", co->name, domain, co->domain);
966*6236dae4SAndroid Build Coastguard Worker       return CERR_PSL;
967*6236dae4SAndroid Build Coastguard Worker     }
968*6236dae4SAndroid Build Coastguard Worker   }
969*6236dae4SAndroid Build Coastguard Worker #else
970*6236dae4SAndroid Build Coastguard Worker   (void)data;
971*6236dae4SAndroid Build Coastguard Worker   (void)co;
972*6236dae4SAndroid Build Coastguard Worker   (void)domain;
973*6236dae4SAndroid Build Coastguard Worker   DEBUGF(infof(data, "NO PSL to check set-cookie '%s' for domain=%s in %s",
974*6236dae4SAndroid Build Coastguard Worker          co->name, co->domain, domain));
975*6236dae4SAndroid Build Coastguard Worker #endif
976*6236dae4SAndroid Build Coastguard Worker   return CERR_OK;
977*6236dae4SAndroid Build Coastguard Worker }
978*6236dae4SAndroid Build Coastguard Worker 
979*6236dae4SAndroid Build Coastguard Worker static int
replace_existing(struct Curl_easy * data,struct Cookie * co,struct CookieInfo * ci,bool secure,bool * replacep)980*6236dae4SAndroid Build Coastguard Worker replace_existing(struct Curl_easy *data,
981*6236dae4SAndroid Build Coastguard Worker                  struct Cookie *co,
982*6236dae4SAndroid Build Coastguard Worker                  struct CookieInfo *ci,
983*6236dae4SAndroid Build Coastguard Worker                  bool secure,
984*6236dae4SAndroid Build Coastguard Worker                  bool *replacep)
985*6236dae4SAndroid Build Coastguard Worker {
986*6236dae4SAndroid Build Coastguard Worker   bool replace_old = FALSE;
987*6236dae4SAndroid Build Coastguard Worker   struct Curl_llist_node *replace_n = NULL;
988*6236dae4SAndroid Build Coastguard Worker   struct Curl_llist_node *n;
989*6236dae4SAndroid Build Coastguard Worker   size_t myhash = cookiehash(co->domain);
990*6236dae4SAndroid Build Coastguard Worker   for(n = Curl_llist_head(&ci->cookielist[myhash]); n; n = Curl_node_next(n)) {
991*6236dae4SAndroid Build Coastguard Worker     struct Cookie *clist = Curl_node_elem(n);
992*6236dae4SAndroid Build Coastguard Worker     if(strcasecompare(clist->name, co->name)) {
993*6236dae4SAndroid Build Coastguard Worker       /* the names are identical */
994*6236dae4SAndroid Build Coastguard Worker       bool matching_domains = FALSE;
995*6236dae4SAndroid Build Coastguard Worker 
996*6236dae4SAndroid Build Coastguard Worker       if(clist->domain && co->domain) {
997*6236dae4SAndroid Build Coastguard Worker         if(strcasecompare(clist->domain, co->domain))
998*6236dae4SAndroid Build Coastguard Worker           /* The domains are identical */
999*6236dae4SAndroid Build Coastguard Worker           matching_domains = TRUE;
1000*6236dae4SAndroid Build Coastguard Worker       }
1001*6236dae4SAndroid Build Coastguard Worker       else if(!clist->domain && !co->domain)
1002*6236dae4SAndroid Build Coastguard Worker         matching_domains = TRUE;
1003*6236dae4SAndroid Build Coastguard Worker 
1004*6236dae4SAndroid Build Coastguard Worker       if(matching_domains && /* the domains were identical */
1005*6236dae4SAndroid Build Coastguard Worker          clist->spath && co->spath && /* both have paths */
1006*6236dae4SAndroid Build Coastguard Worker          clist->secure && !co->secure && !secure) {
1007*6236dae4SAndroid Build Coastguard Worker         size_t cllen;
1008*6236dae4SAndroid Build Coastguard Worker         const char *sep;
1009*6236dae4SAndroid Build Coastguard Worker 
1010*6236dae4SAndroid Build Coastguard Worker         /*
1011*6236dae4SAndroid Build Coastguard Worker          * A non-secure cookie may not overlay an existing secure cookie.
1012*6236dae4SAndroid Build Coastguard Worker          * For an existing cookie "a" with path "/login", refuse a new
1013*6236dae4SAndroid Build Coastguard Worker          * cookie "a" with for example path "/login/en", while the path
1014*6236dae4SAndroid Build Coastguard Worker          * "/loginhelper" is ok.
1015*6236dae4SAndroid Build Coastguard Worker          */
1016*6236dae4SAndroid Build Coastguard Worker 
1017*6236dae4SAndroid Build Coastguard Worker         sep = strchr(clist->spath + 1, '/');
1018*6236dae4SAndroid Build Coastguard Worker 
1019*6236dae4SAndroid Build Coastguard Worker         if(sep)
1020*6236dae4SAndroid Build Coastguard Worker           cllen = sep - clist->spath;
1021*6236dae4SAndroid Build Coastguard Worker         else
1022*6236dae4SAndroid Build Coastguard Worker           cllen = strlen(clist->spath);
1023*6236dae4SAndroid Build Coastguard Worker 
1024*6236dae4SAndroid Build Coastguard Worker         if(strncasecompare(clist->spath, co->spath, cllen)) {
1025*6236dae4SAndroid Build Coastguard Worker           infof(data, "cookie '%s' for domain '%s' dropped, would "
1026*6236dae4SAndroid Build Coastguard Worker                 "overlay an existing cookie", co->name, co->domain);
1027*6236dae4SAndroid Build Coastguard Worker           return CERR_BAD_SECURE;
1028*6236dae4SAndroid Build Coastguard Worker         }
1029*6236dae4SAndroid Build Coastguard Worker       }
1030*6236dae4SAndroid Build Coastguard Worker     }
1031*6236dae4SAndroid Build Coastguard Worker 
1032*6236dae4SAndroid Build Coastguard Worker     if(!replace_n && strcasecompare(clist->name, co->name)) {
1033*6236dae4SAndroid Build Coastguard Worker       /* the names are identical */
1034*6236dae4SAndroid Build Coastguard Worker 
1035*6236dae4SAndroid Build Coastguard Worker       if(clist->domain && co->domain) {
1036*6236dae4SAndroid Build Coastguard Worker         if(strcasecompare(clist->domain, co->domain) &&
1037*6236dae4SAndroid Build Coastguard Worker           (clist->tailmatch == co->tailmatch))
1038*6236dae4SAndroid Build Coastguard Worker           /* The domains are identical */
1039*6236dae4SAndroid Build Coastguard Worker           replace_old = TRUE;
1040*6236dae4SAndroid Build Coastguard Worker       }
1041*6236dae4SAndroid Build Coastguard Worker       else if(!clist->domain && !co->domain)
1042*6236dae4SAndroid Build Coastguard Worker         replace_old = TRUE;
1043*6236dae4SAndroid Build Coastguard Worker 
1044*6236dae4SAndroid Build Coastguard Worker       if(replace_old) {
1045*6236dae4SAndroid Build Coastguard Worker         /* the domains were identical */
1046*6236dae4SAndroid Build Coastguard Worker 
1047*6236dae4SAndroid Build Coastguard Worker         if(clist->spath && co->spath &&
1048*6236dae4SAndroid Build Coastguard Worker            !strcasecompare(clist->spath, co->spath))
1049*6236dae4SAndroid Build Coastguard Worker           replace_old = FALSE;
1050*6236dae4SAndroid Build Coastguard Worker         else if(!clist->spath != !co->spath)
1051*6236dae4SAndroid Build Coastguard Worker           replace_old = FALSE;
1052*6236dae4SAndroid Build Coastguard Worker       }
1053*6236dae4SAndroid Build Coastguard Worker 
1054*6236dae4SAndroid Build Coastguard Worker       if(replace_old && !co->livecookie && clist->livecookie) {
1055*6236dae4SAndroid Build Coastguard Worker         /*
1056*6236dae4SAndroid Build Coastguard Worker          * Both cookies matched fine, except that the already present cookie
1057*6236dae4SAndroid Build Coastguard Worker          * is "live", which means it was set from a header, while the new one
1058*6236dae4SAndroid Build Coastguard Worker          * was read from a file and thus is not "live". "live" cookies are
1059*6236dae4SAndroid Build Coastguard Worker          * preferred so the new cookie is freed.
1060*6236dae4SAndroid Build Coastguard Worker          */
1061*6236dae4SAndroid Build Coastguard Worker         return CERR_LIVE_WINS;
1062*6236dae4SAndroid Build Coastguard Worker       }
1063*6236dae4SAndroid Build Coastguard Worker       if(replace_old)
1064*6236dae4SAndroid Build Coastguard Worker         replace_n = n;
1065*6236dae4SAndroid Build Coastguard Worker     }
1066*6236dae4SAndroid Build Coastguard Worker   }
1067*6236dae4SAndroid Build Coastguard Worker   if(replace_n) {
1068*6236dae4SAndroid Build Coastguard Worker     struct Cookie *repl = Curl_node_elem(replace_n);
1069*6236dae4SAndroid Build Coastguard Worker 
1070*6236dae4SAndroid Build Coastguard Worker     /* when replacing, creationtime is kept from old */
1071*6236dae4SAndroid Build Coastguard Worker     co->creationtime = repl->creationtime;
1072*6236dae4SAndroid Build Coastguard Worker 
1073*6236dae4SAndroid Build Coastguard Worker     /* unlink the old */
1074*6236dae4SAndroid Build Coastguard Worker     Curl_node_remove(replace_n);
1075*6236dae4SAndroid Build Coastguard Worker 
1076*6236dae4SAndroid Build Coastguard Worker     /* free the old cookie */
1077*6236dae4SAndroid Build Coastguard Worker     freecookie(repl);
1078*6236dae4SAndroid Build Coastguard Worker   }
1079*6236dae4SAndroid Build Coastguard Worker   *replacep = replace_old;
1080*6236dae4SAndroid Build Coastguard Worker   return CERR_OK;
1081*6236dae4SAndroid Build Coastguard Worker }
1082*6236dae4SAndroid Build Coastguard Worker 
1083*6236dae4SAndroid Build Coastguard Worker /*
1084*6236dae4SAndroid Build Coastguard Worker  * Curl_cookie_add
1085*6236dae4SAndroid Build Coastguard Worker  *
1086*6236dae4SAndroid Build Coastguard Worker  * Add a single cookie line to the cookie keeping object. Be aware that
1087*6236dae4SAndroid Build Coastguard Worker  * sometimes we get an IP-only hostname, and that might also be a numerical
1088*6236dae4SAndroid Build Coastguard Worker  * IPv6 address.
1089*6236dae4SAndroid Build Coastguard Worker  *
1090*6236dae4SAndroid Build Coastguard Worker  * Returns NULL on out of memory or invalid cookie. This is suboptimal,
1091*6236dae4SAndroid Build Coastguard Worker  * as they should be treated separately.
1092*6236dae4SAndroid Build Coastguard Worker  */
1093*6236dae4SAndroid Build Coastguard Worker struct Cookie *
Curl_cookie_add(struct Curl_easy * data,struct CookieInfo * ci,bool httpheader,bool noexpire,const char * lineptr,const char * domain,const char * path,bool secure)1094*6236dae4SAndroid Build Coastguard Worker Curl_cookie_add(struct Curl_easy *data,
1095*6236dae4SAndroid Build Coastguard Worker                 struct CookieInfo *ci,
1096*6236dae4SAndroid Build Coastguard Worker                 bool httpheader, /* TRUE if HTTP header-style line */
1097*6236dae4SAndroid Build Coastguard Worker                 bool noexpire, /* if TRUE, skip remove_expired() */
1098*6236dae4SAndroid Build Coastguard Worker                 const char *lineptr,   /* first character of the line */
1099*6236dae4SAndroid Build Coastguard Worker                 const char *domain, /* default domain */
1100*6236dae4SAndroid Build Coastguard Worker                 const char *path,   /* full path used when this cookie is set,
1101*6236dae4SAndroid Build Coastguard Worker                                        used to get default path for the cookie
1102*6236dae4SAndroid Build Coastguard Worker                                        unless set */
1103*6236dae4SAndroid Build Coastguard Worker                 bool secure)  /* TRUE if connection is over secure origin */
1104*6236dae4SAndroid Build Coastguard Worker {
1105*6236dae4SAndroid Build Coastguard Worker   struct Cookie *co;
1106*6236dae4SAndroid Build Coastguard Worker   size_t myhash;
1107*6236dae4SAndroid Build Coastguard Worker   int rc;
1108*6236dae4SAndroid Build Coastguard Worker   bool replaces = FALSE;
1109*6236dae4SAndroid Build Coastguard Worker 
1110*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(data);
1111*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(MAX_SET_COOKIE_AMOUNT <= 255); /* counter is an unsigned char */
1112*6236dae4SAndroid Build Coastguard Worker   if(data->req.setcookies >= MAX_SET_COOKIE_AMOUNT)
1113*6236dae4SAndroid Build Coastguard Worker     return NULL;
1114*6236dae4SAndroid Build Coastguard Worker 
1115*6236dae4SAndroid Build Coastguard Worker   /* First, alloc and init a new struct for it */
1116*6236dae4SAndroid Build Coastguard Worker   co = calloc(1, sizeof(struct Cookie));
1117*6236dae4SAndroid Build Coastguard Worker   if(!co)
1118*6236dae4SAndroid Build Coastguard Worker     return NULL; /* bail out if we are this low on memory */
1119*6236dae4SAndroid Build Coastguard Worker 
1120*6236dae4SAndroid Build Coastguard Worker   if(httpheader)
1121*6236dae4SAndroid Build Coastguard Worker     rc = parse_cookie_header(data, co, ci, lineptr, domain, path, secure);
1122*6236dae4SAndroid Build Coastguard Worker   else
1123*6236dae4SAndroid Build Coastguard Worker     rc = parse_netscape(co, ci, lineptr, secure);
1124*6236dae4SAndroid Build Coastguard Worker 
1125*6236dae4SAndroid Build Coastguard Worker   if(rc)
1126*6236dae4SAndroid Build Coastguard Worker     goto fail;
1127*6236dae4SAndroid Build Coastguard Worker 
1128*6236dae4SAndroid Build Coastguard Worker   if(co->prefix_secure && !co->secure)
1129*6236dae4SAndroid Build Coastguard Worker     /* The __Secure- prefix only requires that the cookie be set secure */
1130*6236dae4SAndroid Build Coastguard Worker     goto fail;
1131*6236dae4SAndroid Build Coastguard Worker 
1132*6236dae4SAndroid Build Coastguard Worker   if(co->prefix_host) {
1133*6236dae4SAndroid Build Coastguard Worker     /*
1134*6236dae4SAndroid Build Coastguard Worker      * The __Host- prefix requires the cookie to be secure, have a "/" path
1135*6236dae4SAndroid Build Coastguard Worker      * and not have a domain set.
1136*6236dae4SAndroid Build Coastguard Worker      */
1137*6236dae4SAndroid Build Coastguard Worker     if(co->secure && co->path && strcmp(co->path, "/") == 0 && !co->tailmatch)
1138*6236dae4SAndroid Build Coastguard Worker       ;
1139*6236dae4SAndroid Build Coastguard Worker     else
1140*6236dae4SAndroid Build Coastguard Worker       goto fail;
1141*6236dae4SAndroid Build Coastguard Worker   }
1142*6236dae4SAndroid Build Coastguard Worker 
1143*6236dae4SAndroid Build Coastguard Worker   if(!ci->running &&    /* read from a file */
1144*6236dae4SAndroid Build Coastguard Worker      ci->newsession &&  /* clean session cookies */
1145*6236dae4SAndroid Build Coastguard Worker      !co->expires)      /* this is a session cookie since it does not expire */
1146*6236dae4SAndroid Build Coastguard Worker     goto fail;
1147*6236dae4SAndroid Build Coastguard Worker 
1148*6236dae4SAndroid Build Coastguard Worker   co->livecookie = ci->running;
1149*6236dae4SAndroid Build Coastguard Worker   co->creationtime = ++ci->lastct;
1150*6236dae4SAndroid Build Coastguard Worker 
1151*6236dae4SAndroid Build Coastguard Worker   /*
1152*6236dae4SAndroid Build Coastguard Worker    * Now we have parsed the incoming line, we must now check if this supersedes
1153*6236dae4SAndroid Build Coastguard Worker    * an already existing cookie, which it may if the previous have the same
1154*6236dae4SAndroid Build Coastguard Worker    * domain and path as this.
1155*6236dae4SAndroid Build Coastguard Worker    */
1156*6236dae4SAndroid Build Coastguard Worker 
1157*6236dae4SAndroid Build Coastguard Worker   /* remove expired cookies */
1158*6236dae4SAndroid Build Coastguard Worker   if(!noexpire)
1159*6236dae4SAndroid Build Coastguard Worker     remove_expired(ci);
1160*6236dae4SAndroid Build Coastguard Worker 
1161*6236dae4SAndroid Build Coastguard Worker   if(is_public_suffix(data, co, domain))
1162*6236dae4SAndroid Build Coastguard Worker     goto fail;
1163*6236dae4SAndroid Build Coastguard Worker 
1164*6236dae4SAndroid Build Coastguard Worker   if(replace_existing(data, co, ci, secure, &replaces))
1165*6236dae4SAndroid Build Coastguard Worker     goto fail;
1166*6236dae4SAndroid Build Coastguard Worker 
1167*6236dae4SAndroid Build Coastguard Worker   /* add this cookie to the list */
1168*6236dae4SAndroid Build Coastguard Worker   myhash = cookiehash(co->domain);
1169*6236dae4SAndroid Build Coastguard Worker   Curl_llist_append(&ci->cookielist[myhash], co, &co->node);
1170*6236dae4SAndroid Build Coastguard Worker 
1171*6236dae4SAndroid Build Coastguard Worker   if(ci->running)
1172*6236dae4SAndroid Build Coastguard Worker     /* Only show this when NOT reading the cookies from a file */
1173*6236dae4SAndroid Build Coastguard Worker     infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
1174*6236dae4SAndroid Build Coastguard Worker           "expire %" FMT_OFF_T,
1175*6236dae4SAndroid Build Coastguard Worker           replaces ? "Replaced":"Added", co->name, co->value,
1176*6236dae4SAndroid Build Coastguard Worker           co->domain, co->path, co->expires);
1177*6236dae4SAndroid Build Coastguard Worker 
1178*6236dae4SAndroid Build Coastguard Worker   if(!replaces)
1179*6236dae4SAndroid Build Coastguard Worker     ci->numcookies++; /* one more cookie in the jar */
1180*6236dae4SAndroid Build Coastguard Worker 
1181*6236dae4SAndroid Build Coastguard Worker   /*
1182*6236dae4SAndroid Build Coastguard Worker    * Now that we have added a new cookie to the jar, update the expiration
1183*6236dae4SAndroid Build Coastguard Worker    * tracker in case it is the next one to expire.
1184*6236dae4SAndroid Build Coastguard Worker    */
1185*6236dae4SAndroid Build Coastguard Worker   if(co->expires && (co->expires < ci->next_expiration))
1186*6236dae4SAndroid Build Coastguard Worker     ci->next_expiration = co->expires;
1187*6236dae4SAndroid Build Coastguard Worker 
1188*6236dae4SAndroid Build Coastguard Worker   return co;
1189*6236dae4SAndroid Build Coastguard Worker fail:
1190*6236dae4SAndroid Build Coastguard Worker   freecookie(co);
1191*6236dae4SAndroid Build Coastguard Worker   return NULL;
1192*6236dae4SAndroid Build Coastguard Worker }
1193*6236dae4SAndroid Build Coastguard Worker 
1194*6236dae4SAndroid Build Coastguard Worker 
1195*6236dae4SAndroid Build Coastguard Worker /*
1196*6236dae4SAndroid Build Coastguard Worker  * Curl_cookie_init()
1197*6236dae4SAndroid Build Coastguard Worker  *
1198*6236dae4SAndroid Build Coastguard Worker  * Inits a cookie struct to read data from a local file. This is always
1199*6236dae4SAndroid Build Coastguard Worker  * called before any cookies are set. File may be NULL in which case only the
1200*6236dae4SAndroid Build Coastguard Worker  * struct is initialized. Is file is "-" then STDIN is read.
1201*6236dae4SAndroid Build Coastguard Worker  *
1202*6236dae4SAndroid Build Coastguard Worker  * If 'newsession' is TRUE, discard all "session cookies" on read from file.
1203*6236dae4SAndroid Build Coastguard Worker  *
1204*6236dae4SAndroid Build Coastguard Worker  * Note that 'data' might be called as NULL pointer. If data is NULL, 'file'
1205*6236dae4SAndroid Build Coastguard Worker  * will be ignored.
1206*6236dae4SAndroid Build Coastguard Worker  *
1207*6236dae4SAndroid Build Coastguard Worker  * Returns NULL on out of memory. Invalid cookies are ignored.
1208*6236dae4SAndroid Build Coastguard Worker  */
Curl_cookie_init(struct Curl_easy * data,const char * file,struct CookieInfo * ci,bool newsession)1209*6236dae4SAndroid Build Coastguard Worker struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
1210*6236dae4SAndroid Build Coastguard Worker                                     const char *file,
1211*6236dae4SAndroid Build Coastguard Worker                                     struct CookieInfo *ci,
1212*6236dae4SAndroid Build Coastguard Worker                                     bool newsession)
1213*6236dae4SAndroid Build Coastguard Worker {
1214*6236dae4SAndroid Build Coastguard Worker   FILE *handle = NULL;
1215*6236dae4SAndroid Build Coastguard Worker 
1216*6236dae4SAndroid Build Coastguard Worker   if(!ci) {
1217*6236dae4SAndroid Build Coastguard Worker     int i;
1218*6236dae4SAndroid Build Coastguard Worker 
1219*6236dae4SAndroid Build Coastguard Worker     /* we did not get a struct, create one */
1220*6236dae4SAndroid Build Coastguard Worker     ci = calloc(1, sizeof(struct CookieInfo));
1221*6236dae4SAndroid Build Coastguard Worker     if(!ci)
1222*6236dae4SAndroid Build Coastguard Worker       return NULL; /* failed to get memory */
1223*6236dae4SAndroid Build Coastguard Worker 
1224*6236dae4SAndroid Build Coastguard Worker     /* This does not use the destructor callback since we want to add
1225*6236dae4SAndroid Build Coastguard Worker        and remove to lists while keeping the cookie struct intact */
1226*6236dae4SAndroid Build Coastguard Worker     for(i = 0; i < COOKIE_HASH_SIZE; i++)
1227*6236dae4SAndroid Build Coastguard Worker       Curl_llist_init(&ci->cookielist[i], NULL);
1228*6236dae4SAndroid Build Coastguard Worker     /*
1229*6236dae4SAndroid Build Coastguard Worker      * Initialize the next_expiration time to signal that we do not have enough
1230*6236dae4SAndroid Build Coastguard Worker      * information yet.
1231*6236dae4SAndroid Build Coastguard Worker      */
1232*6236dae4SAndroid Build Coastguard Worker     ci->next_expiration = CURL_OFF_T_MAX;
1233*6236dae4SAndroid Build Coastguard Worker   }
1234*6236dae4SAndroid Build Coastguard Worker   ci->newsession = newsession; /* new session? */
1235*6236dae4SAndroid Build Coastguard Worker 
1236*6236dae4SAndroid Build Coastguard Worker   if(data) {
1237*6236dae4SAndroid Build Coastguard Worker     FILE *fp = NULL;
1238*6236dae4SAndroid Build Coastguard Worker     if(file && *file) {
1239*6236dae4SAndroid Build Coastguard Worker       if(!strcmp(file, "-"))
1240*6236dae4SAndroid Build Coastguard Worker         fp = stdin;
1241*6236dae4SAndroid Build Coastguard Worker       else {
1242*6236dae4SAndroid Build Coastguard Worker         fp = fopen(file, "rb");
1243*6236dae4SAndroid Build Coastguard Worker         if(!fp)
1244*6236dae4SAndroid Build Coastguard Worker           infof(data, "WARNING: failed to open cookie file \"%s\"", file);
1245*6236dae4SAndroid Build Coastguard Worker         else
1246*6236dae4SAndroid Build Coastguard Worker           handle = fp;
1247*6236dae4SAndroid Build Coastguard Worker       }
1248*6236dae4SAndroid Build Coastguard Worker     }
1249*6236dae4SAndroid Build Coastguard Worker 
1250*6236dae4SAndroid Build Coastguard Worker     ci->running = FALSE; /* this is not running, this is init */
1251*6236dae4SAndroid Build Coastguard Worker     if(fp) {
1252*6236dae4SAndroid Build Coastguard Worker       struct dynbuf buf;
1253*6236dae4SAndroid Build Coastguard Worker       Curl_dyn_init(&buf, MAX_COOKIE_LINE);
1254*6236dae4SAndroid Build Coastguard Worker       while(Curl_get_line(&buf, fp)) {
1255*6236dae4SAndroid Build Coastguard Worker         char *lineptr = Curl_dyn_ptr(&buf);
1256*6236dae4SAndroid Build Coastguard Worker         bool headerline = FALSE;
1257*6236dae4SAndroid Build Coastguard Worker         if(checkprefix("Set-Cookie:", lineptr)) {
1258*6236dae4SAndroid Build Coastguard Worker           /* This is a cookie line, get it! */
1259*6236dae4SAndroid Build Coastguard Worker           lineptr += 11;
1260*6236dae4SAndroid Build Coastguard Worker           headerline = TRUE;
1261*6236dae4SAndroid Build Coastguard Worker           while(*lineptr && ISBLANK(*lineptr))
1262*6236dae4SAndroid Build Coastguard Worker             lineptr++;
1263*6236dae4SAndroid Build Coastguard Worker         }
1264*6236dae4SAndroid Build Coastguard Worker 
1265*6236dae4SAndroid Build Coastguard Worker         Curl_cookie_add(data, ci, headerline, TRUE, lineptr, NULL, NULL, TRUE);
1266*6236dae4SAndroid Build Coastguard Worker       }
1267*6236dae4SAndroid Build Coastguard Worker       Curl_dyn_free(&buf); /* free the line buffer */
1268*6236dae4SAndroid Build Coastguard Worker 
1269*6236dae4SAndroid Build Coastguard Worker       /*
1270*6236dae4SAndroid Build Coastguard Worker        * Remove expired cookies from the hash. We must make sure to run this
1271*6236dae4SAndroid Build Coastguard Worker        * after reading the file, and not on every cookie.
1272*6236dae4SAndroid Build Coastguard Worker        */
1273*6236dae4SAndroid Build Coastguard Worker       remove_expired(ci);
1274*6236dae4SAndroid Build Coastguard Worker 
1275*6236dae4SAndroid Build Coastguard Worker       if(handle)
1276*6236dae4SAndroid Build Coastguard Worker         fclose(handle);
1277*6236dae4SAndroid Build Coastguard Worker     }
1278*6236dae4SAndroid Build Coastguard Worker     data->state.cookie_engine = TRUE;
1279*6236dae4SAndroid Build Coastguard Worker   }
1280*6236dae4SAndroid Build Coastguard Worker   ci->running = TRUE;          /* now, we are running */
1281*6236dae4SAndroid Build Coastguard Worker 
1282*6236dae4SAndroid Build Coastguard Worker   return ci;
1283*6236dae4SAndroid Build Coastguard Worker }
1284*6236dae4SAndroid Build Coastguard Worker 
1285*6236dae4SAndroid Build Coastguard Worker /*
1286*6236dae4SAndroid Build Coastguard Worker  * cookie_sort
1287*6236dae4SAndroid Build Coastguard Worker  *
1288*6236dae4SAndroid Build Coastguard Worker  * Helper function to sort cookies such that the longest path gets before the
1289*6236dae4SAndroid Build Coastguard Worker  * shorter path. Path, domain and name lengths are considered in that order,
1290*6236dae4SAndroid Build Coastguard Worker  * with the creationtime as the tiebreaker. The creationtime is guaranteed to
1291*6236dae4SAndroid Build Coastguard Worker  * be unique per cookie, so we know we will get an ordering at that point.
1292*6236dae4SAndroid Build Coastguard Worker  */
cookie_sort(const void * p1,const void * p2)1293*6236dae4SAndroid Build Coastguard Worker static int cookie_sort(const void *p1, const void *p2)
1294*6236dae4SAndroid Build Coastguard Worker {
1295*6236dae4SAndroid Build Coastguard Worker   struct Cookie *c1 = *(struct Cookie **)p1;
1296*6236dae4SAndroid Build Coastguard Worker   struct Cookie *c2 = *(struct Cookie **)p2;
1297*6236dae4SAndroid Build Coastguard Worker   size_t l1, l2;
1298*6236dae4SAndroid Build Coastguard Worker 
1299*6236dae4SAndroid Build Coastguard Worker   /* 1 - compare cookie path lengths */
1300*6236dae4SAndroid Build Coastguard Worker   l1 = c1->path ? strlen(c1->path) : 0;
1301*6236dae4SAndroid Build Coastguard Worker   l2 = c2->path ? strlen(c2->path) : 0;
1302*6236dae4SAndroid Build Coastguard Worker 
1303*6236dae4SAndroid Build Coastguard Worker   if(l1 != l2)
1304*6236dae4SAndroid Build Coastguard Worker     return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
1305*6236dae4SAndroid Build Coastguard Worker 
1306*6236dae4SAndroid Build Coastguard Worker   /* 2 - compare cookie domain lengths */
1307*6236dae4SAndroid Build Coastguard Worker   l1 = c1->domain ? strlen(c1->domain) : 0;
1308*6236dae4SAndroid Build Coastguard Worker   l2 = c2->domain ? strlen(c2->domain) : 0;
1309*6236dae4SAndroid Build Coastguard Worker 
1310*6236dae4SAndroid Build Coastguard Worker   if(l1 != l2)
1311*6236dae4SAndroid Build Coastguard Worker     return (l2 > l1) ? 1 : -1 ;  /* avoid size_t <=> int conversions */
1312*6236dae4SAndroid Build Coastguard Worker 
1313*6236dae4SAndroid Build Coastguard Worker   /* 3 - compare cookie name lengths */
1314*6236dae4SAndroid Build Coastguard Worker   l1 = c1->name ? strlen(c1->name) : 0;
1315*6236dae4SAndroid Build Coastguard Worker   l2 = c2->name ? strlen(c2->name) : 0;
1316*6236dae4SAndroid Build Coastguard Worker 
1317*6236dae4SAndroid Build Coastguard Worker   if(l1 != l2)
1318*6236dae4SAndroid Build Coastguard Worker     return (l2 > l1) ? 1 : -1;
1319*6236dae4SAndroid Build Coastguard Worker 
1320*6236dae4SAndroid Build Coastguard Worker   /* 4 - compare cookie creation time */
1321*6236dae4SAndroid Build Coastguard Worker   return (c2->creationtime > c1->creationtime) ? 1 : -1;
1322*6236dae4SAndroid Build Coastguard Worker }
1323*6236dae4SAndroid Build Coastguard Worker 
1324*6236dae4SAndroid Build Coastguard Worker /*
1325*6236dae4SAndroid Build Coastguard Worker  * cookie_sort_ct
1326*6236dae4SAndroid Build Coastguard Worker  *
1327*6236dae4SAndroid Build Coastguard Worker  * Helper function to sort cookies according to creation time.
1328*6236dae4SAndroid Build Coastguard Worker  */
cookie_sort_ct(const void * p1,const void * p2)1329*6236dae4SAndroid Build Coastguard Worker static int cookie_sort_ct(const void *p1, const void *p2)
1330*6236dae4SAndroid Build Coastguard Worker {
1331*6236dae4SAndroid Build Coastguard Worker   struct Cookie *c1 = *(struct Cookie **)p1;
1332*6236dae4SAndroid Build Coastguard Worker   struct Cookie *c2 = *(struct Cookie **)p2;
1333*6236dae4SAndroid Build Coastguard Worker 
1334*6236dae4SAndroid Build Coastguard Worker   return (c2->creationtime > c1->creationtime) ? 1 : -1;
1335*6236dae4SAndroid Build Coastguard Worker }
1336*6236dae4SAndroid Build Coastguard Worker 
1337*6236dae4SAndroid Build Coastguard Worker /*
1338*6236dae4SAndroid Build Coastguard Worker  * Curl_cookie_getlist
1339*6236dae4SAndroid Build Coastguard Worker  *
1340*6236dae4SAndroid Build Coastguard Worker  * For a given host and path, return a linked list of cookies that the client
1341*6236dae4SAndroid Build Coastguard Worker  * should send to the server if used now. The secure boolean informs the cookie
1342*6236dae4SAndroid Build Coastguard Worker  * if a secure connection is achieved or not.
1343*6236dae4SAndroid Build Coastguard Worker  *
1344*6236dae4SAndroid Build Coastguard Worker  * It shall only return cookies that have not expired.
1345*6236dae4SAndroid Build Coastguard Worker  *
1346*6236dae4SAndroid Build Coastguard Worker  * Returns 0 when there is a list returned. Otherwise non-zero.
1347*6236dae4SAndroid Build Coastguard Worker  */
Curl_cookie_getlist(struct Curl_easy * data,struct CookieInfo * ci,const char * host,const char * path,bool secure,struct Curl_llist * list)1348*6236dae4SAndroid Build Coastguard Worker int Curl_cookie_getlist(struct Curl_easy *data,
1349*6236dae4SAndroid Build Coastguard Worker                         struct CookieInfo *ci,
1350*6236dae4SAndroid Build Coastguard Worker                         const char *host, const char *path,
1351*6236dae4SAndroid Build Coastguard Worker                         bool secure,
1352*6236dae4SAndroid Build Coastguard Worker                         struct Curl_llist *list)
1353*6236dae4SAndroid Build Coastguard Worker {
1354*6236dae4SAndroid Build Coastguard Worker   size_t matches = 0;
1355*6236dae4SAndroid Build Coastguard Worker   bool is_ip;
1356*6236dae4SAndroid Build Coastguard Worker   const size_t myhash = cookiehash(host);
1357*6236dae4SAndroid Build Coastguard Worker   struct Curl_llist_node *n;
1358*6236dae4SAndroid Build Coastguard Worker 
1359*6236dae4SAndroid Build Coastguard Worker   Curl_llist_init(list, NULL);
1360*6236dae4SAndroid Build Coastguard Worker 
1361*6236dae4SAndroid Build Coastguard Worker   if(!ci || !Curl_llist_count(&ci->cookielist[myhash]))
1362*6236dae4SAndroid Build Coastguard Worker     return 1; /* no cookie struct or no cookies in the struct */
1363*6236dae4SAndroid Build Coastguard Worker 
1364*6236dae4SAndroid Build Coastguard Worker   /* at first, remove expired cookies */
1365*6236dae4SAndroid Build Coastguard Worker   remove_expired(ci);
1366*6236dae4SAndroid Build Coastguard Worker 
1367*6236dae4SAndroid Build Coastguard Worker   /* check if host is an IP(v4|v6) address */
1368*6236dae4SAndroid Build Coastguard Worker   is_ip = Curl_host_is_ipnum(host);
1369*6236dae4SAndroid Build Coastguard Worker 
1370*6236dae4SAndroid Build Coastguard Worker   for(n = Curl_llist_head(&ci->cookielist[myhash]);
1371*6236dae4SAndroid Build Coastguard Worker       n; n = Curl_node_next(n)) {
1372*6236dae4SAndroid Build Coastguard Worker     struct Cookie *co = Curl_node_elem(n);
1373*6236dae4SAndroid Build Coastguard Worker 
1374*6236dae4SAndroid Build Coastguard Worker     /* if the cookie requires we are secure we must only continue if we are! */
1375*6236dae4SAndroid Build Coastguard Worker     if(co->secure ? secure : TRUE) {
1376*6236dae4SAndroid Build Coastguard Worker 
1377*6236dae4SAndroid Build Coastguard Worker       /* now check if the domain is correct */
1378*6236dae4SAndroid Build Coastguard Worker       if(!co->domain ||
1379*6236dae4SAndroid Build Coastguard Worker          (co->tailmatch && !is_ip &&
1380*6236dae4SAndroid Build Coastguard Worker           cookie_tailmatch(co->domain, strlen(co->domain), host)) ||
1381*6236dae4SAndroid Build Coastguard Worker          ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
1382*6236dae4SAndroid Build Coastguard Worker         /*
1383*6236dae4SAndroid Build Coastguard Worker          * the right part of the host matches the domain stuff in the
1384*6236dae4SAndroid Build Coastguard Worker          * cookie data
1385*6236dae4SAndroid Build Coastguard Worker          */
1386*6236dae4SAndroid Build Coastguard Worker 
1387*6236dae4SAndroid Build Coastguard Worker         /*
1388*6236dae4SAndroid Build Coastguard Worker          * now check the left part of the path with the cookies path
1389*6236dae4SAndroid Build Coastguard Worker          * requirement
1390*6236dae4SAndroid Build Coastguard Worker          */
1391*6236dae4SAndroid Build Coastguard Worker         if(!co->spath || pathmatch(co->spath, path) ) {
1392*6236dae4SAndroid Build Coastguard Worker 
1393*6236dae4SAndroid Build Coastguard Worker           /*
1394*6236dae4SAndroid Build Coastguard Worker            * This is a match and we add it to the return-linked-list
1395*6236dae4SAndroid Build Coastguard Worker            */
1396*6236dae4SAndroid Build Coastguard Worker           Curl_llist_append(list, co, &co->getnode);
1397*6236dae4SAndroid Build Coastguard Worker           matches++;
1398*6236dae4SAndroid Build Coastguard Worker           if(matches >= MAX_COOKIE_SEND_AMOUNT) {
1399*6236dae4SAndroid Build Coastguard Worker             infof(data, "Included max number of cookies (%zu) in request!",
1400*6236dae4SAndroid Build Coastguard Worker                   matches);
1401*6236dae4SAndroid Build Coastguard Worker             break;
1402*6236dae4SAndroid Build Coastguard Worker           }
1403*6236dae4SAndroid Build Coastguard Worker         }
1404*6236dae4SAndroid Build Coastguard Worker       }
1405*6236dae4SAndroid Build Coastguard Worker     }
1406*6236dae4SAndroid Build Coastguard Worker   }
1407*6236dae4SAndroid Build Coastguard Worker 
1408*6236dae4SAndroid Build Coastguard Worker   if(matches) {
1409*6236dae4SAndroid Build Coastguard Worker     /*
1410*6236dae4SAndroid Build Coastguard Worker      * Now we need to make sure that if there is a name appearing more than
1411*6236dae4SAndroid Build Coastguard Worker      * once, the longest specified path version comes first. To make this
1412*6236dae4SAndroid Build Coastguard Worker      * the swiftest way, we just sort them all based on path length.
1413*6236dae4SAndroid Build Coastguard Worker      */
1414*6236dae4SAndroid Build Coastguard Worker     struct Cookie **array;
1415*6236dae4SAndroid Build Coastguard Worker     size_t i;
1416*6236dae4SAndroid Build Coastguard Worker 
1417*6236dae4SAndroid Build Coastguard Worker     /* alloc an array and store all cookie pointers */
1418*6236dae4SAndroid Build Coastguard Worker     array = malloc(sizeof(struct Cookie *) * matches);
1419*6236dae4SAndroid Build Coastguard Worker     if(!array)
1420*6236dae4SAndroid Build Coastguard Worker       goto fail;
1421*6236dae4SAndroid Build Coastguard Worker 
1422*6236dae4SAndroid Build Coastguard Worker     n = Curl_llist_head(list);
1423*6236dae4SAndroid Build Coastguard Worker 
1424*6236dae4SAndroid Build Coastguard Worker     for(i = 0; n; n = Curl_node_next(n))
1425*6236dae4SAndroid Build Coastguard Worker       array[i++] = Curl_node_elem(n);
1426*6236dae4SAndroid Build Coastguard Worker 
1427*6236dae4SAndroid Build Coastguard Worker     /* now sort the cookie pointers in path length order */
1428*6236dae4SAndroid Build Coastguard Worker     qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
1429*6236dae4SAndroid Build Coastguard Worker 
1430*6236dae4SAndroid Build Coastguard Worker     /* remake the linked list order according to the new order */
1431*6236dae4SAndroid Build Coastguard Worker     Curl_llist_destroy(list, NULL);
1432*6236dae4SAndroid Build Coastguard Worker 
1433*6236dae4SAndroid Build Coastguard Worker     for(i = 0; i < matches; i++)
1434*6236dae4SAndroid Build Coastguard Worker       Curl_llist_append(list, array[i], &array[i]->getnode);
1435*6236dae4SAndroid Build Coastguard Worker 
1436*6236dae4SAndroid Build Coastguard Worker     free(array); /* remove the temporary data again */
1437*6236dae4SAndroid Build Coastguard Worker   }
1438*6236dae4SAndroid Build Coastguard Worker 
1439*6236dae4SAndroid Build Coastguard Worker   return 0; /* success */
1440*6236dae4SAndroid Build Coastguard Worker 
1441*6236dae4SAndroid Build Coastguard Worker fail:
1442*6236dae4SAndroid Build Coastguard Worker   /* failure, clear up the allocated chain and return NULL */
1443*6236dae4SAndroid Build Coastguard Worker   Curl_llist_destroy(list, NULL);
1444*6236dae4SAndroid Build Coastguard Worker   return 2; /* error */
1445*6236dae4SAndroid Build Coastguard Worker }
1446*6236dae4SAndroid Build Coastguard Worker 
1447*6236dae4SAndroid Build Coastguard Worker /*
1448*6236dae4SAndroid Build Coastguard Worker  * Curl_cookie_clearall
1449*6236dae4SAndroid Build Coastguard Worker  *
1450*6236dae4SAndroid Build Coastguard Worker  * Clear all existing cookies and reset the counter.
1451*6236dae4SAndroid Build Coastguard Worker  */
Curl_cookie_clearall(struct CookieInfo * ci)1452*6236dae4SAndroid Build Coastguard Worker void Curl_cookie_clearall(struct CookieInfo *ci)
1453*6236dae4SAndroid Build Coastguard Worker {
1454*6236dae4SAndroid Build Coastguard Worker   if(ci) {
1455*6236dae4SAndroid Build Coastguard Worker     unsigned int i;
1456*6236dae4SAndroid Build Coastguard Worker     for(i = 0; i < COOKIE_HASH_SIZE; i++) {
1457*6236dae4SAndroid Build Coastguard Worker       struct Curl_llist_node *n;
1458*6236dae4SAndroid Build Coastguard Worker       for(n = Curl_llist_head(&ci->cookielist[i]); n;) {
1459*6236dae4SAndroid Build Coastguard Worker         struct Cookie *c = Curl_node_elem(n);
1460*6236dae4SAndroid Build Coastguard Worker         struct Curl_llist_node *e = Curl_node_next(n);
1461*6236dae4SAndroid Build Coastguard Worker         Curl_node_remove(n);
1462*6236dae4SAndroid Build Coastguard Worker         freecookie(c);
1463*6236dae4SAndroid Build Coastguard Worker         n = e;
1464*6236dae4SAndroid Build Coastguard Worker       }
1465*6236dae4SAndroid Build Coastguard Worker     }
1466*6236dae4SAndroid Build Coastguard Worker     ci->numcookies = 0;
1467*6236dae4SAndroid Build Coastguard Worker   }
1468*6236dae4SAndroid Build Coastguard Worker }
1469*6236dae4SAndroid Build Coastguard Worker 
1470*6236dae4SAndroid Build Coastguard Worker /*
1471*6236dae4SAndroid Build Coastguard Worker  * Curl_cookie_clearsess
1472*6236dae4SAndroid Build Coastguard Worker  *
1473*6236dae4SAndroid Build Coastguard Worker  * Free all session cookies in the cookies list.
1474*6236dae4SAndroid Build Coastguard Worker  */
Curl_cookie_clearsess(struct CookieInfo * ci)1475*6236dae4SAndroid Build Coastguard Worker void Curl_cookie_clearsess(struct CookieInfo *ci)
1476*6236dae4SAndroid Build Coastguard Worker {
1477*6236dae4SAndroid Build Coastguard Worker   unsigned int i;
1478*6236dae4SAndroid Build Coastguard Worker 
1479*6236dae4SAndroid Build Coastguard Worker   if(!ci)
1480*6236dae4SAndroid Build Coastguard Worker     return;
1481*6236dae4SAndroid Build Coastguard Worker 
1482*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
1483*6236dae4SAndroid Build Coastguard Worker     struct Curl_llist_node *n = Curl_llist_head(&ci->cookielist[i]);
1484*6236dae4SAndroid Build Coastguard Worker     struct Curl_llist_node *e = NULL;
1485*6236dae4SAndroid Build Coastguard Worker 
1486*6236dae4SAndroid Build Coastguard Worker     for(; n; n = e) {
1487*6236dae4SAndroid Build Coastguard Worker       struct Cookie *curr = Curl_node_elem(n);
1488*6236dae4SAndroid Build Coastguard Worker       e = Curl_node_next(n); /* in case the node is removed, get it early */
1489*6236dae4SAndroid Build Coastguard Worker       if(!curr->expires) {
1490*6236dae4SAndroid Build Coastguard Worker         Curl_node_remove(n);
1491*6236dae4SAndroid Build Coastguard Worker         freecookie(curr);
1492*6236dae4SAndroid Build Coastguard Worker         ci->numcookies--;
1493*6236dae4SAndroid Build Coastguard Worker       }
1494*6236dae4SAndroid Build Coastguard Worker     }
1495*6236dae4SAndroid Build Coastguard Worker   }
1496*6236dae4SAndroid Build Coastguard Worker }
1497*6236dae4SAndroid Build Coastguard Worker 
1498*6236dae4SAndroid Build Coastguard Worker /*
1499*6236dae4SAndroid Build Coastguard Worker  * Curl_cookie_cleanup()
1500*6236dae4SAndroid Build Coastguard Worker  *
1501*6236dae4SAndroid Build Coastguard Worker  * Free a "cookie object" previous created with Curl_cookie_init().
1502*6236dae4SAndroid Build Coastguard Worker  */
Curl_cookie_cleanup(struct CookieInfo * ci)1503*6236dae4SAndroid Build Coastguard Worker void Curl_cookie_cleanup(struct CookieInfo *ci)
1504*6236dae4SAndroid Build Coastguard Worker {
1505*6236dae4SAndroid Build Coastguard Worker   if(ci) {
1506*6236dae4SAndroid Build Coastguard Worker     Curl_cookie_clearall(ci);
1507*6236dae4SAndroid Build Coastguard Worker     free(ci); /* free the base struct as well */
1508*6236dae4SAndroid Build Coastguard Worker   }
1509*6236dae4SAndroid Build Coastguard Worker }
1510*6236dae4SAndroid Build Coastguard Worker 
1511*6236dae4SAndroid Build Coastguard Worker /*
1512*6236dae4SAndroid Build Coastguard Worker  * get_netscape_format()
1513*6236dae4SAndroid Build Coastguard Worker  *
1514*6236dae4SAndroid Build Coastguard Worker  * Formats a string for Netscape output file, w/o a newline at the end.
1515*6236dae4SAndroid Build Coastguard Worker  * Function returns a char * to a formatted line. The caller is responsible
1516*6236dae4SAndroid Build Coastguard Worker  * for freeing the returned pointer.
1517*6236dae4SAndroid Build Coastguard Worker  */
get_netscape_format(const struct Cookie * co)1518*6236dae4SAndroid Build Coastguard Worker static char *get_netscape_format(const struct Cookie *co)
1519*6236dae4SAndroid Build Coastguard Worker {
1520*6236dae4SAndroid Build Coastguard Worker   return aprintf(
1521*6236dae4SAndroid Build Coastguard Worker     "%s"     /* httponly preamble */
1522*6236dae4SAndroid Build Coastguard Worker     "%s%s\t" /* domain */
1523*6236dae4SAndroid Build Coastguard Worker     "%s\t"   /* tailmatch */
1524*6236dae4SAndroid Build Coastguard Worker     "%s\t"   /* path */
1525*6236dae4SAndroid Build Coastguard Worker     "%s\t"   /* secure */
1526*6236dae4SAndroid Build Coastguard Worker     "%" FMT_OFF_T "\t"   /* expires */
1527*6236dae4SAndroid Build Coastguard Worker     "%s\t"   /* name */
1528*6236dae4SAndroid Build Coastguard Worker     "%s",    /* value */
1529*6236dae4SAndroid Build Coastguard Worker     co->httponly ? "#HttpOnly_" : "",
1530*6236dae4SAndroid Build Coastguard Worker     /*
1531*6236dae4SAndroid Build Coastguard Worker      * Make sure all domains are prefixed with a dot if they allow
1532*6236dae4SAndroid Build Coastguard Worker      * tailmatching. This is Mozilla-style.
1533*6236dae4SAndroid Build Coastguard Worker      */
1534*6236dae4SAndroid Build Coastguard Worker     (co->tailmatch && co->domain && co->domain[0] != '.') ? "." : "",
1535*6236dae4SAndroid Build Coastguard Worker     co->domain ? co->domain : "unknown",
1536*6236dae4SAndroid Build Coastguard Worker     co->tailmatch ? "TRUE" : "FALSE",
1537*6236dae4SAndroid Build Coastguard Worker     co->path ? co->path : "/",
1538*6236dae4SAndroid Build Coastguard Worker     co->secure ? "TRUE" : "FALSE",
1539*6236dae4SAndroid Build Coastguard Worker     co->expires,
1540*6236dae4SAndroid Build Coastguard Worker     co->name,
1541*6236dae4SAndroid Build Coastguard Worker     co->value ? co->value : "");
1542*6236dae4SAndroid Build Coastguard Worker }
1543*6236dae4SAndroid Build Coastguard Worker 
1544*6236dae4SAndroid Build Coastguard Worker /*
1545*6236dae4SAndroid Build Coastguard Worker  * cookie_output()
1546*6236dae4SAndroid Build Coastguard Worker  *
1547*6236dae4SAndroid Build Coastguard Worker  * Writes all internally known cookies to the specified file. Specify
1548*6236dae4SAndroid Build Coastguard Worker  * "-" as filename to write to stdout.
1549*6236dae4SAndroid Build Coastguard Worker  *
1550*6236dae4SAndroid Build Coastguard Worker  * The function returns non-zero on write failure.
1551*6236dae4SAndroid Build Coastguard Worker  */
cookie_output(struct Curl_easy * data,struct CookieInfo * ci,const char * filename)1552*6236dae4SAndroid Build Coastguard Worker static CURLcode cookie_output(struct Curl_easy *data,
1553*6236dae4SAndroid Build Coastguard Worker                               struct CookieInfo *ci,
1554*6236dae4SAndroid Build Coastguard Worker                               const char *filename)
1555*6236dae4SAndroid Build Coastguard Worker {
1556*6236dae4SAndroid Build Coastguard Worker   FILE *out = NULL;
1557*6236dae4SAndroid Build Coastguard Worker   bool use_stdout = FALSE;
1558*6236dae4SAndroid Build Coastguard Worker   char *tempstore = NULL;
1559*6236dae4SAndroid Build Coastguard Worker   CURLcode error = CURLE_OK;
1560*6236dae4SAndroid Build Coastguard Worker 
1561*6236dae4SAndroid Build Coastguard Worker   if(!ci)
1562*6236dae4SAndroid Build Coastguard Worker     /* no cookie engine alive */
1563*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
1564*6236dae4SAndroid Build Coastguard Worker 
1565*6236dae4SAndroid Build Coastguard Worker   /* at first, remove expired cookies */
1566*6236dae4SAndroid Build Coastguard Worker   remove_expired(ci);
1567*6236dae4SAndroid Build Coastguard Worker 
1568*6236dae4SAndroid Build Coastguard Worker   if(!strcmp("-", filename)) {
1569*6236dae4SAndroid Build Coastguard Worker     /* use stdout */
1570*6236dae4SAndroid Build Coastguard Worker     out = stdout;
1571*6236dae4SAndroid Build Coastguard Worker     use_stdout = TRUE;
1572*6236dae4SAndroid Build Coastguard Worker   }
1573*6236dae4SAndroid Build Coastguard Worker   else {
1574*6236dae4SAndroid Build Coastguard Worker     error = Curl_fopen(data, filename, &out, &tempstore);
1575*6236dae4SAndroid Build Coastguard Worker     if(error)
1576*6236dae4SAndroid Build Coastguard Worker       goto error;
1577*6236dae4SAndroid Build Coastguard Worker   }
1578*6236dae4SAndroid Build Coastguard Worker 
1579*6236dae4SAndroid Build Coastguard Worker   fputs("# Netscape HTTP Cookie File\n"
1580*6236dae4SAndroid Build Coastguard Worker         "# https://curl.se/docs/http-cookies.html\n"
1581*6236dae4SAndroid Build Coastguard Worker         "# This file was generated by libcurl! Edit at your own risk.\n\n",
1582*6236dae4SAndroid Build Coastguard Worker         out);
1583*6236dae4SAndroid Build Coastguard Worker 
1584*6236dae4SAndroid Build Coastguard Worker   if(ci->numcookies) {
1585*6236dae4SAndroid Build Coastguard Worker     unsigned int i;
1586*6236dae4SAndroid Build Coastguard Worker     size_t nvalid = 0;
1587*6236dae4SAndroid Build Coastguard Worker     struct Cookie **array;
1588*6236dae4SAndroid Build Coastguard Worker     struct Curl_llist_node *n;
1589*6236dae4SAndroid Build Coastguard Worker 
1590*6236dae4SAndroid Build Coastguard Worker     array = calloc(1, sizeof(struct Cookie *) * ci->numcookies);
1591*6236dae4SAndroid Build Coastguard Worker     if(!array) {
1592*6236dae4SAndroid Build Coastguard Worker       error = CURLE_OUT_OF_MEMORY;
1593*6236dae4SAndroid Build Coastguard Worker       goto error;
1594*6236dae4SAndroid Build Coastguard Worker     }
1595*6236dae4SAndroid Build Coastguard Worker 
1596*6236dae4SAndroid Build Coastguard Worker     /* only sort the cookies with a domain property */
1597*6236dae4SAndroid Build Coastguard Worker     for(i = 0; i < COOKIE_HASH_SIZE; i++) {
1598*6236dae4SAndroid Build Coastguard Worker       for(n = Curl_llist_head(&ci->cookielist[i]); n;
1599*6236dae4SAndroid Build Coastguard Worker           n = Curl_node_next(n)) {
1600*6236dae4SAndroid Build Coastguard Worker         struct Cookie *co = Curl_node_elem(n);
1601*6236dae4SAndroid Build Coastguard Worker         if(!co->domain)
1602*6236dae4SAndroid Build Coastguard Worker           continue;
1603*6236dae4SAndroid Build Coastguard Worker         array[nvalid++] = co;
1604*6236dae4SAndroid Build Coastguard Worker       }
1605*6236dae4SAndroid Build Coastguard Worker     }
1606*6236dae4SAndroid Build Coastguard Worker 
1607*6236dae4SAndroid Build Coastguard Worker     qsort(array, nvalid, sizeof(struct Cookie *), cookie_sort_ct);
1608*6236dae4SAndroid Build Coastguard Worker 
1609*6236dae4SAndroid Build Coastguard Worker     for(i = 0; i < nvalid; i++) {
1610*6236dae4SAndroid Build Coastguard Worker       char *format_ptr = get_netscape_format(array[i]);
1611*6236dae4SAndroid Build Coastguard Worker       if(!format_ptr) {
1612*6236dae4SAndroid Build Coastguard Worker         free(array);
1613*6236dae4SAndroid Build Coastguard Worker         error = CURLE_OUT_OF_MEMORY;
1614*6236dae4SAndroid Build Coastguard Worker         goto error;
1615*6236dae4SAndroid Build Coastguard Worker       }
1616*6236dae4SAndroid Build Coastguard Worker       fprintf(out, "%s\n", format_ptr);
1617*6236dae4SAndroid Build Coastguard Worker       free(format_ptr);
1618*6236dae4SAndroid Build Coastguard Worker     }
1619*6236dae4SAndroid Build Coastguard Worker 
1620*6236dae4SAndroid Build Coastguard Worker     free(array);
1621*6236dae4SAndroid Build Coastguard Worker   }
1622*6236dae4SAndroid Build Coastguard Worker 
1623*6236dae4SAndroid Build Coastguard Worker   if(!use_stdout) {
1624*6236dae4SAndroid Build Coastguard Worker     fclose(out);
1625*6236dae4SAndroid Build Coastguard Worker     out = NULL;
1626*6236dae4SAndroid Build Coastguard Worker     if(tempstore && Curl_rename(tempstore, filename)) {
1627*6236dae4SAndroid Build Coastguard Worker       unlink(tempstore);
1628*6236dae4SAndroid Build Coastguard Worker       error = CURLE_WRITE_ERROR;
1629*6236dae4SAndroid Build Coastguard Worker       goto error;
1630*6236dae4SAndroid Build Coastguard Worker     }
1631*6236dae4SAndroid Build Coastguard Worker   }
1632*6236dae4SAndroid Build Coastguard Worker 
1633*6236dae4SAndroid Build Coastguard Worker   /*
1634*6236dae4SAndroid Build Coastguard Worker    * If we reach here we have successfully written a cookie file so there is
1635*6236dae4SAndroid Build Coastguard Worker    * no need to inspect the error, any error case should have jumped into the
1636*6236dae4SAndroid Build Coastguard Worker    * error block below.
1637*6236dae4SAndroid Build Coastguard Worker    */
1638*6236dae4SAndroid Build Coastguard Worker   free(tempstore);
1639*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1640*6236dae4SAndroid Build Coastguard Worker 
1641*6236dae4SAndroid Build Coastguard Worker error:
1642*6236dae4SAndroid Build Coastguard Worker   if(out && !use_stdout)
1643*6236dae4SAndroid Build Coastguard Worker     fclose(out);
1644*6236dae4SAndroid Build Coastguard Worker   free(tempstore);
1645*6236dae4SAndroid Build Coastguard Worker   return error;
1646*6236dae4SAndroid Build Coastguard Worker }
1647*6236dae4SAndroid Build Coastguard Worker 
cookie_list(struct Curl_easy * data)1648*6236dae4SAndroid Build Coastguard Worker static struct curl_slist *cookie_list(struct Curl_easy *data)
1649*6236dae4SAndroid Build Coastguard Worker {
1650*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *list = NULL;
1651*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *beg;
1652*6236dae4SAndroid Build Coastguard Worker   unsigned int i;
1653*6236dae4SAndroid Build Coastguard Worker   struct Curl_llist_node *n;
1654*6236dae4SAndroid Build Coastguard Worker 
1655*6236dae4SAndroid Build Coastguard Worker   if(!data->cookies || (data->cookies->numcookies == 0))
1656*6236dae4SAndroid Build Coastguard Worker     return NULL;
1657*6236dae4SAndroid Build Coastguard Worker 
1658*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
1659*6236dae4SAndroid Build Coastguard Worker     for(n = Curl_llist_head(&data->cookies->cookielist[i]); n;
1660*6236dae4SAndroid Build Coastguard Worker         n = Curl_node_next(n)) {
1661*6236dae4SAndroid Build Coastguard Worker       struct Cookie *c = Curl_node_elem(n);
1662*6236dae4SAndroid Build Coastguard Worker       char *line;
1663*6236dae4SAndroid Build Coastguard Worker       if(!c->domain)
1664*6236dae4SAndroid Build Coastguard Worker         continue;
1665*6236dae4SAndroid Build Coastguard Worker       line = get_netscape_format(c);
1666*6236dae4SAndroid Build Coastguard Worker       if(!line) {
1667*6236dae4SAndroid Build Coastguard Worker         curl_slist_free_all(list);
1668*6236dae4SAndroid Build Coastguard Worker         return NULL;
1669*6236dae4SAndroid Build Coastguard Worker       }
1670*6236dae4SAndroid Build Coastguard Worker       beg = Curl_slist_append_nodup(list, line);
1671*6236dae4SAndroid Build Coastguard Worker       if(!beg) {
1672*6236dae4SAndroid Build Coastguard Worker         free(line);
1673*6236dae4SAndroid Build Coastguard Worker         curl_slist_free_all(list);
1674*6236dae4SAndroid Build Coastguard Worker         return NULL;
1675*6236dae4SAndroid Build Coastguard Worker       }
1676*6236dae4SAndroid Build Coastguard Worker       list = beg;
1677*6236dae4SAndroid Build Coastguard Worker     }
1678*6236dae4SAndroid Build Coastguard Worker   }
1679*6236dae4SAndroid Build Coastguard Worker 
1680*6236dae4SAndroid Build Coastguard Worker   return list;
1681*6236dae4SAndroid Build Coastguard Worker }
1682*6236dae4SAndroid Build Coastguard Worker 
Curl_cookie_list(struct Curl_easy * data)1683*6236dae4SAndroid Build Coastguard Worker struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
1684*6236dae4SAndroid Build Coastguard Worker {
1685*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *list;
1686*6236dae4SAndroid Build Coastguard Worker   Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1687*6236dae4SAndroid Build Coastguard Worker   list = cookie_list(data);
1688*6236dae4SAndroid Build Coastguard Worker   Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
1689*6236dae4SAndroid Build Coastguard Worker   return list;
1690*6236dae4SAndroid Build Coastguard Worker }
1691*6236dae4SAndroid Build Coastguard Worker 
Curl_flush_cookies(struct Curl_easy * data,bool cleanup)1692*6236dae4SAndroid Build Coastguard Worker void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
1693*6236dae4SAndroid Build Coastguard Worker {
1694*6236dae4SAndroid Build Coastguard Worker   CURLcode res;
1695*6236dae4SAndroid Build Coastguard Worker 
1696*6236dae4SAndroid Build Coastguard Worker   if(data->set.str[STRING_COOKIEJAR]) {
1697*6236dae4SAndroid Build Coastguard Worker     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1698*6236dae4SAndroid Build Coastguard Worker 
1699*6236dae4SAndroid Build Coastguard Worker     /* if we have a destination file for all the cookies to get dumped to */
1700*6236dae4SAndroid Build Coastguard Worker     res = cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]);
1701*6236dae4SAndroid Build Coastguard Worker     if(res)
1702*6236dae4SAndroid Build Coastguard Worker       infof(data, "WARNING: failed to save cookies in %s: %s",
1703*6236dae4SAndroid Build Coastguard Worker             data->set.str[STRING_COOKIEJAR], curl_easy_strerror(res));
1704*6236dae4SAndroid Build Coastguard Worker   }
1705*6236dae4SAndroid Build Coastguard Worker   else {
1706*6236dae4SAndroid Build Coastguard Worker     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
1707*6236dae4SAndroid Build Coastguard Worker   }
1708*6236dae4SAndroid Build Coastguard Worker 
1709*6236dae4SAndroid Build Coastguard Worker   if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
1710*6236dae4SAndroid Build Coastguard Worker     Curl_cookie_cleanup(data->cookies);
1711*6236dae4SAndroid Build Coastguard Worker     data->cookies = NULL;
1712*6236dae4SAndroid Build Coastguard Worker   }
1713*6236dae4SAndroid Build Coastguard Worker   Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
1714*6236dae4SAndroid Build Coastguard Worker }
1715*6236dae4SAndroid Build Coastguard Worker 
1716*6236dae4SAndroid Build Coastguard Worker #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
1717