From 0681965308946ef9736a04542c4f9d3b7ea86c5b Mon Sep 17 00:00:00 2001 Message-Id: <0681965308946ef9736a04542c4f9d3b7ea86c5b.1714704799.git.mdw@distorted.org.uk> From: Mark Wooding Date: Sat, 12 Jan 2008 12:40:17 +0000 Subject: [PATCH] Accept unquoted cookie paths, even though they are formally illegal. This makes Netsurf work, and also means that we're not being stricter in what we accept than what we send! Organization: Straylight/Edgeware From: rjk@greenend.org.uk <> --- lib/mime.c | 38 ++++++++++++++++++++++++++++++++++---- server/cgimain.c | 3 ++- server/dcgi.c | 6 ++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/lib/mime.c b/lib/mime.c index d79cc2a..880fe12 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -1,6 +1,6 @@ /* * This file is part of DisOrder - * Copyright (C) 2005, 2007 Richard Kettlewell + * Copyright (C) 2005, 2007, 2008 Richard Kettlewell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -503,6 +503,30 @@ char *mime_qp(const char *s) { return d.vec; } +/** @brief Match cookie separator characters + * + * This is a subset of the RFC2616 specials, and technically is in breach of + * the specification. However rejecting (in particular) slashes is + * unreasonably strict and has broken at least one (admittedly somewhat + * obscure) browser, so we're more forgiving. + */ +static int cookie_separator(int c) { + switch(c) { + case '(': + case ')': + case ',': + case ';': + case '=': + case ' ': + case '"': + case '\t': + return 1; + + default: + return 0; + } +} + /** @brief Parse a RFC2109 Cookie: header * @param s Header field value * @param cd Where to store result @@ -523,14 +547,20 @@ int parse_cookie(const char *s, s = skipwhite(s, 0); continue; } - if(!(s = parsetoken(s, &n, mime_http_separator))) + if(!(s = parsetoken(s, &n, cookie_separator))) { + error(0, "parse_cookie: cannot parse attribute name"); return -1; + } s = skipwhite(s, 0); - if(*s++ != '=') + if(*s++ != '=') { + error(0, "parse_cookie: did not find expected '='"); return -1; + } s = skipwhite(s, 0); - if(!(s = mime_parse_word(s, &v, mime_http_separator))) + if(!(s = mime_parse_word(s, &v, cookie_separator))) { + error(0, "parse_cookie: cannot parse value for '%s'", n); return -1; + } if(n[0] == '$') { /* Some bit of meta-information */ if(!strcmp(n, "$Version")) diff --git a/server/cgimain.c b/server/cgimain.c index 674e9c7..5a79bb5 100644 --- a/server/cgimain.c +++ b/server/cgimain.c @@ -117,7 +117,8 @@ int main(int argc, char **argv) { } if(best_cookie != -1) login_cookie = cd.cookies[best_cookie].value; - } + } else + error(0, "could not parse cookie field '%s'", cookie_env); } disorder_cgi_login(&s, &output); disorder_cgi(&output, &s); diff --git a/server/dcgi.c b/server/dcgi.c index b7a8508..19e25e0 100644 --- a/server/dcgi.c +++ b/server/dcgi.c @@ -133,6 +133,12 @@ static void header_cookie(struct sink *output) { * cause the browser to expose the cookie to other CGI programs on the same * web server. */ dynstr_append_string(d, ";Version=1;Path="); + /* Formally we are supposed to quote the path, since it invariably has a + * slash in it. However Safari does not parse quoted paths correctly, so + * this won't work. Fortunately nothing else seems to care about proper + * quoting of paths, so in practice we get with it. (See also + * parse_cookie() where we are liberal about cookie paths on the way back + * in.) */ dynstr_append_string(d, u.path); } dynstr_terminate(d); -- [mdw]