From 127e502a012567221fd792e256655006849fada8 Mon Sep 17 00:00:00 2001 From: kush789 Date: Wed, 27 Jan 2016 03:34:31 +0530 Subject: [PATCH] Added recomendations of draft-west-leave-secure-cookies-alone --- src/cookies.c | 198 +++++++++++++++++++++++++++++++++++++--------------------- src/cookies.h | 5 +- src/http.c | 2 +- 3 files changed, 131 insertions(+), 74 deletions(-) diff --git a/src/cookies.c b/src/cookies.c index 81ecfa5..156bd61 100644 --- a/src/cookies.c +++ b/src/cookies.c @@ -350,7 +350,8 @@ discard_matching_cookie (struct cookie_jar *jar, struct cookie *cookie) filled. */ static struct cookie * -parse_set_cookie (const char *set_cookie, bool silent) +parse_set_cookie (const char *set_cookie, enum url_scheme scheme, + bool silent) { const char *ptr = set_cookie; struct cookie *cookie = cookie_new (); @@ -439,8 +440,30 @@ parse_set_cookie (const char *set_cookie, bool silent) } else if (TOKEN_IS (name, "secure")) { - /* ignore value completely */ - cookie->secure = 1; +#ifdef HAVE_SSL + if (scheme == SCHEME_HTTPS) + /* Ignore value completely since secure is a value-less + attribute*/ + cookie->secure = 1; + else + { + /* Deleting cookie since secure only flag is set but connection + is not secure. */ + if (!silent) + logprintf (LOG_NOTQUIET, + _("Trying to create secure only cookie, but connection is not secure.\nSet-Cookie : %s\n"), + quotearg_style (escape_quoting_style, set_cookie)); + delete_cookie (cookie); + return NULL; + } +#else + if (!silent) + logprintf (LOG_NOTQUIET, + _("Trying to create secure only cookie, wget configured with\" --without-ssl.\nSet-Cookie : %s\n"), + quotearg_style (escape_quoting_style, set_cookie)); + delete_cookie (cookie); + return NULL; +#endif } /* else: Ignore unrecognized attribute. */ } @@ -699,17 +722,84 @@ check_path_match (const char *cookie_path, const char *path) s = PS_newstr; \ } while (0) +/* Return a count of how many times CHR occurs in STRING. */ + +static int +count_char (const char *string, char chr) +{ + const char *p; + int count = 0; + for (p = string; *p; p++) + if (*p == chr) + ++count; + return count; +} + +/* Find the cookie chains whose domains match HOST and store them to + DEST. + + A cookie chain is the head of a list of cookies that belong to a + host/domain. Given HOST "img.search.xemacs.org", this function + will return the chains for "img.search.xemacs.org", + "search.xemacs.org", and "xemacs.org" -- those of them that exist + (if any), that is. + + DEST should be large enough to accept (in the worst case) as many + elements as there are domain components of HOST. */ + +static int +find_chains_of_host (struct cookie_jar *jar, const char *host, + struct cookie *dest[]) +{ + int dest_count = 0; + int passes, passcnt; + + /* Bail out quickly if there are no cookies in the jar. */ + if (!hash_table_count (jar->chains)) + return 0; + + if (numeric_address_p (host)) + /* If host is an IP address, only check for the exact match. */ + passes = 1; + else + /* Otherwise, check all the subdomains except the top-level (last) + one. As a domain with N components has N-1 dots, the number of + passes equals the number of dots. */ + passes = count_char (host, '.'); + + passcnt = 0; + + /* Find chains that match HOST, starting with exact match and + progressing to less specific domains. For instance, given HOST + fly.srk.fer.hr, first look for fly.srk.fer.hr's chain, then + srk.fer.hr's, then fer.hr's. */ + while (1) + { + struct cookie *chain = hash_table_get (jar->chains, host); + if (chain) + dest[dest_count++] = chain; + if (++passcnt >= passes) + break; + host = strchr (host, '.') + 1; + } + + return dest_count; +} /* Process the HTTP `Set-Cookie' header. This results in storing the cookie or discarding a matching one, or ignoring it completely, all depending on the contents. */ + void cookie_handle_set_cookie (struct cookie_jar *jar, const char *host, int port, - const char *path, const char *set_cookie) + const char *path, enum url_scheme scheme, + const char *set_cookie) { - struct cookie *cookie; + struct cookie *cookie, *old_cookie; + struct cookie **chains; + int chain_count, i; cookies_now = time (NULL); /* Wget's paths don't begin with '/' (blame rfc1808), but cookie @@ -717,7 +807,7 @@ cookie_handle_set_cookie (struct cookie_jar *jar, simply prepend slash to PATH. */ PREPEND_SLASH (path); - cookie = parse_set_cookie (set_cookie, false); + cookie = parse_set_cookie (set_cookie, scheme, false); if (!cookie) goto out; @@ -767,6 +857,31 @@ cookie_handle_set_cookie (struct cookie_jar *jar, } } +#ifdef HAVE_SSL + if ((cookie->secure == 0) && (scheme != SCHEME_HTTPS)) + { + /* If an old cookie exists such that the all of the following are + true, then discard the new cookie. + + - The "domain" domain-matches the domain of the new cookie + - The "name" matches the "name" of the new cookie + - Secure-only flag of old cookie is set */ + + chains = alloca_array (struct cookie *, 1 + count_char (host, '.')); + chain_count = find_chains_of_host (jar, host, chains); + + for (i = 0; i < chain_count; i++) + for (old_cookie = chains[i]; old_cookie; old_cookie = old_cookie->next) + { + if (!cookie_expired_p(old_cookie) + && !(old_cookie->domain_exact + && 0 != strcasecmp (host, old_cookie->domain)) + && 0 == strcasecmp(old_cookie->attr, cookie->attr) + && 1 == old_cookie->secure) + goto out; + } + } +#endif /* Now store the cookie, or discard an existing cookie, if discarding was requested. */ @@ -788,70 +903,6 @@ cookie_handle_set_cookie (struct cookie_jar *jar, previously stored cookies. Entry point is `build_cookies_request'. */ -/* Return a count of how many times CHR occurs in STRING. */ - -static int -count_char (const char *string, char chr) -{ - const char *p; - int count = 0; - for (p = string; *p; p++) - if (*p == chr) - ++count; - return count; -} - -/* Find the cookie chains whose domains match HOST and store them to - DEST. - - A cookie chain is the head of a list of cookies that belong to a - host/domain. Given HOST "img.search.xemacs.org", this function - will return the chains for "img.search.xemacs.org", - "search.xemacs.org", and "xemacs.org" -- those of them that exist - (if any), that is. - - DEST should be large enough to accept (in the worst case) as many - elements as there are domain components of HOST. */ - -static int -find_chains_of_host (struct cookie_jar *jar, const char *host, - struct cookie *dest[]) -{ - int dest_count = 0; - int passes, passcnt; - - /* Bail out quickly if there are no cookies in the jar. */ - if (!hash_table_count (jar->chains)) - return 0; - - if (numeric_address_p (host)) - /* If host is an IP address, only check for the exact match. */ - passes = 1; - else - /* Otherwise, check all the subdomains except the top-level (last) - one. As a domain with N components has N-1 dots, the number of - passes equals the number of dots. */ - passes = count_char (host, '.'); - - passcnt = 0; - - /* Find chains that match HOST, starting with exact match and - progressing to less specific domains. For instance, given HOST - fly.srk.fer.hr, first look for fly.srk.fer.hr's chain, then - srk.fer.hr's, then fer.hr's. */ - while (1) - { - struct cookie *chain = hash_table_get (jar->chains, host); - if (chain) - dest[dest_count++] = chain; - if (++passcnt >= passes) - break; - host = strchr (host, '.') + 1; - } - - return dest_count; -} - /* If FULL_PATH begins with PREFIX, return the length of PREFIX, zero otherwise. */ @@ -1410,6 +1461,9 @@ test_cookies (void) }; int i; + /* The uri scheme doesn't make a difference in these tests */ + enum url_scheme scheme = SCHEME_HTTP; + for (i = 0; i < countof (tests_succ); i++) { int ind; @@ -1417,7 +1471,7 @@ test_cookies (void) const char **expected = tests_succ[i].results; struct cookie *c; - c = parse_set_cookie (data, true); + c = parse_set_cookie (data, scheme, true); if (!c) { printf ("NULL cookie returned for valid data: %s\n", data); @@ -1457,7 +1511,7 @@ test_cookies (void) { struct cookie *c; char *data = tests_fail[i]; - c = parse_set_cookie (data, true); + c = parse_set_cookie (data, scheme, true); if (c) printf ("Failed to report error on invalid data: %s\n", data); } diff --git a/src/cookies.h b/src/cookies.h index b4281e1..d565b09 100644 --- a/src/cookies.h +++ b/src/cookies.h @@ -31,13 +31,16 @@ as that of the covered work. */ #ifndef COOKIES_H #define COOKIES_H +#include "url.h" + struct cookie_jar; struct cookie_jar *cookie_jar_new (void); void cookie_jar_delete (struct cookie_jar *); void cookie_handle_set_cookie (struct cookie_jar *, const char *, int, - const char *, const char *); + const char *, enum url_scheme, + const char *); char *cookie_header (struct cookie_jar *, const char *, int, const char *, bool); diff --git a/src/http.c b/src/http.c index 8916d2b..f7d42b2 100644 --- a/src/http.c +++ b/src/http.c @@ -3276,7 +3276,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy, { char *set_cookie; BOUNDED_TO_ALLOCA (scbeg, scend, set_cookie); cookie_handle_set_cookie (wget_cookie_jar, u->host, u->port, - u->path, set_cookie); + u->path, u->scheme, set_cookie); } } -- 1.9.1