Many cookie fixes:

o Save domains in jars like Mozilla does. It means all domains set in
    Set-Cookie: headers are dot-prefixed.
  o Save and use the 'tailmatch' field in the Mozilla/Netscape cookie jars (the
    second column).
  o Reject cookies using illegal domains in the Set-Cookie: line. Concerns
    both domains with too few dots or domains that are outside the currently
    operating server host's domain.
  o Set the path part by default to the one used in the request, if none was
    set in the Set-Cookie line.
This commit is contained in:
Daniel Stenberg 2003-04-30 17:03:43 +00:00
parent 836aaa1647
commit efd836d971
2 changed files with 138 additions and 59 deletions

View File

@ -111,6 +111,17 @@ free_cookiemess(struct Cookie *co)
free(co); free(co);
} }
static bool tailmatch(const char *little, const char *bigone)
{
unsigned int littlelen = strlen(little);
unsigned int biglen = strlen(bigone);
if(littlelen > biglen)
return FALSE;
return strequal(little, bigone+biglen-littlelen);
}
/**************************************************************************** /****************************************************************************
* *
* Curl_cookie_add() * Curl_cookie_add()
@ -123,7 +134,10 @@ struct Cookie *
Curl_cookie_add(struct CookieInfo *c, Curl_cookie_add(struct CookieInfo *c,
bool httpheader, /* TRUE if HTTP header-style line */ bool httpheader, /* TRUE if HTTP header-style line */
char *lineptr, /* first character of the line */ char *lineptr, /* first character of the line */
char *domain) /* default domain */ char *domain, /* default domain */
char *path) /* full path used when this cookie is set,
used to get default path for the cookie
unless set */
{ {
struct Cookie *clist; struct Cookie *clist;
char what[MAX_COOKIE_LINE]; char what[MAX_COOKIE_LINE];
@ -134,6 +148,7 @@ Curl_cookie_add(struct CookieInfo *c,
struct Cookie *lastc=NULL; struct Cookie *lastc=NULL;
time_t now = time(NULL); time_t now = time(NULL);
bool replace_old = FALSE; bool replace_old = FALSE;
bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
/* First, alloc and init a new struct for it */ /* First, alloc and init a new struct for it */
co = (struct Cookie *)malloc(sizeof(struct Cookie)); co = (struct Cookie *)malloc(sizeof(struct Cookie));
@ -186,8 +201,58 @@ Curl_cookie_add(struct CookieInfo *c,
co->path=strdup(whatptr); co->path=strdup(whatptr);
} }
else if(strequal("domain", name)) { else if(strequal("domain", name)) {
/* note that this name may or may not have a preceeding dot, but
we don't care about that, we treat the names the same anyway */
char *ptr=whatptr;
int dotcount=1;
unsigned int i;
static const char *seventhree[]= {
"com", "edu", "net", "org", "gov", "mil", "int"
};
/* Count the dots, we need to make sure that there are THREE dots
in the normal domains, or TWO in the seventhree-domains. */
if('.' == whatptr[0])
/* don't count the initial dot, assume it */
ptr++;
do {
ptr = strchr(ptr, '.');
if(ptr) {
ptr++;
dotcount++;
}
} while(ptr);
for(i=0;
i<sizeof(seventhree)/sizeof(seventhree[0]); i++) {
if(tailmatch(seventhree[i], whatptr)) {
dotcount++; /* we allow one dot less for these */
break;
}
}
if(dotcount < 3)
/* Received and skipped a cookie with a domain using too few
dots. */
badcookie=TRUE; /* mark this as a bad cookie */
else {
/* Now, we make sure that our host is within the given domain,
or the given domain is not valid and thus cannot be set. */
if(!domain || tailmatch(whatptr, domain)) {
co->domain=strdup(whatptr); co->domain=strdup(whatptr);
co->field1= (whatptr[0]=='.')?2:1; co->tailmatch=TRUE; /* we always do that if the domain name was
given */
}
else
/* we did not get a tailmatch and then the attempted set domain
is not a domain to which the current host belongs. Mark as
bad. */
badcookie=TRUE;
}
} }
else if(strequal("version", name)) { else if(strequal("version", name)) {
co->version=strdup(whatptr); co->version=strdup(whatptr);
@ -249,8 +314,11 @@ Curl_cookie_add(struct CookieInfo *c,
semiptr=strchr(ptr, '\0'); semiptr=strchr(ptr, '\0');
} while(semiptr); } while(semiptr);
if(NULL == co->name) { if(badcookie || (NULL == co->name)) {
/* we didn't get a cookie name, this is an illegal line, bail out */ /* we didn't get a cookie name or a bad one,
this is an illegal line, bail out */
if(co->expirestr)
free(co->expirestr);
if(co->domain) if(co->domain)
free(co->domain); free(co->domain);
if(co->path) if(co->path)
@ -264,8 +332,20 @@ Curl_cookie_add(struct CookieInfo *c,
} }
if(NULL == co->domain) if(NULL == co->domain)
/* no domain given in the header line, set the default now */ /* no domain was given in the header line, set the default now */
co->domain=domain?strdup(domain):NULL; co->domain=domain?strdup(domain):NULL;
if((NULL == co->path) && path) {
/* no path was given in the header line, set the default now */
char *endslash = strrchr(path, '/');
if(endslash) {
int pathlen = endslash-path+1; /* include the ending slash */
co->path=malloc(pathlen+1); /* one extra for the zero byte */
if(co->path) {
memcpy(co->path, path, pathlen);
co->path[pathlen]=0; /* zero terminate */
}
}
}
} }
else { else {
/* This line is NOT a HTTP header style line, we do offer support for /* This line is NOT a HTTP header style line, we do offer support for
@ -297,7 +377,8 @@ Curl_cookie_add(struct CookieInfo *c,
/* Now loop through the fields and init the struct we already have /* Now loop through the fields and init the struct we already have
allocated */ allocated */
for(ptr=firstptr, fields=0; ptr; ptr=strtok_r(NULL, "\t", &tok_buf), fields++) { for(ptr=firstptr, fields=0; ptr;
ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
switch(fields) { switch(fields) {
case 0: case 0:
co->domain = strdup(ptr); co->domain = strdup(ptr);
@ -312,10 +393,8 @@ Curl_cookie_add(struct CookieInfo *c,
As far as I can see, it is set to true when the cookie says As far as I can see, it is set to true when the cookie says
.domain.com and to false when the domain is complete www.domain.com .domain.com and to false when the domain is complete www.domain.com
We don't currently take advantage of this knowledge.
*/ */
co->field1=strequal(ptr, "TRUE")+1; /* store information */ co->tailmatch=strequal(ptr, "TRUE"); /* store information */
break; break;
case 2: case 2:
/* It turns out, that sometimes the file format allows the path /* It turns out, that sometimes the file format allows the path
@ -375,10 +454,11 @@ Curl_cookie_add(struct CookieInfo *c,
if(clist->domain && co->domain) { if(clist->domain && co->domain) {
if(strequal(clist->domain, co->domain) || if(strequal(clist->domain, co->domain) ||
(clist->domain[0]=='.' && (co->tailmatch && /* only do the dot magic if tailmatching is OK */
((clist->domain[0]=='.' &&
strequal(&(clist->domain[1]), co->domain)) || strequal(&(clist->domain[1]), co->domain)) ||
(co->domain[0]=='.' && (co->domain[0]=='.' &&
strequal(clist->domain, &(co->domain[1]))) ) strequal(clist->domain, &(co->domain[1]))))) )
/* The domains are identical, or at least identical if you skip the /* The domains are identical, or at least identical if you skip the
preceeding dot */ preceeding dot */
replace_old=TRUE; replace_old=TRUE;
@ -532,7 +612,7 @@ struct CookieInfo *Curl_cookie_init(char *file,
while(*lineptr && isspace((int)*lineptr)) while(*lineptr && isspace((int)*lineptr))
lineptr++; lineptr++;
Curl_cookie_add(c, headerline, lineptr, NULL); Curl_cookie_add(c, headerline, lineptr, NULL, NULL);
} }
if(fromfile) if(fromfile)
fclose(fp); fclose(fp);
@ -561,9 +641,6 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
struct Cookie *newco; struct Cookie *newco;
struct Cookie *co; struct Cookie *co;
time_t now = time(NULL); time_t now = time(NULL);
int hostlen=strlen(host);
int domlen;
struct Cookie *mainco=NULL; struct Cookie *mainco=NULL;
if(!c || !c->cookies) if(!c || !c->cookies)
@ -579,10 +656,9 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
(co->secure?secure:TRUE) ) { (co->secure?secure:TRUE) ) {
/* now check if the domain is correct */ /* now check if the domain is correct */
domlen=co->domain?strlen(co->domain):0;
if(!co->domain || if(!co->domain ||
((domlen<=hostlen) && (co->tailmatch && tailmatch(co->domain, host)) ||
strequal(host+(hostlen-domlen), co->domain)) ) { (!co->tailmatch && strequal(host, co->domain)) ) {
/* the right part of the host matches the domain stuff in the /* the right part of the host matches the domain stuff in the
cookie data */ cookie data */
@ -716,15 +792,19 @@ int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
while(co) { while(co) {
fprintf(out, fprintf(out,
"%s\t" /* domain */ "%s%s\t" /* domain */
"%s\t" /* field1 */ "%s\t" /* tailmatch */
"%s\t" /* path */ "%s\t" /* path */
"%s\t" /* secure */ "%s\t" /* secure */
"%u\t" /* expires */ "%u\t" /* expires */
"%s\t" /* name */ "%s\t" /* name */
"%s\n", /* value */ "%s\n", /* value */
/* Make sure all domains are prefixed with a dot if they allow
tailmatching. This is Mozilla-style. */
(co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
co->domain?co->domain:"unknown", co->domain?co->domain:"unknown",
co->field1==2?"TRUE":"FALSE", co->tailmatch?"TRUE":"FALSE",
co->path?co->path:"/", co->path?co->path:"/",
co->secure?"TRUE":"FALSE", co->secure?"TRUE":"FALSE",
(unsigned int)co->expires, (unsigned int)co->expires,

View File

@ -40,8 +40,7 @@ struct Cookie {
char *domain; /* domain = <this> */ char *domain; /* domain = <this> */
long expires; /* expires = <this> */ long expires; /* expires = <this> */
char *expirestr; /* the plain text version */ char *expirestr; /* the plain text version */
bool tailmatch; /* weather we do tail-matchning of the domain name */
char field1; /* read from a cookie file, 1 => FALSE, 2=> TRUE */
/* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */ /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */
char *version; /* Version = <value> */ char *version; /* Version = <value> */
@ -70,11 +69,11 @@ struct CookieInfo {
#define MAX_NAME_TXT "255" #define MAX_NAME_TXT "255"
/* /*
* Add a cookie to the internal list of cookies. The domain argument is only * Add a cookie to the internal list of cookies. The domain and path arguments
* used if the header boolean is TRUE. * are only used if the header boolean is TRUE.
*/ */
struct Cookie *Curl_cookie_add(struct CookieInfo *, bool header, char *line, struct Cookie *Curl_cookie_add(struct CookieInfo *, bool header, char *line,
char *domain); char *domain, char *path);
struct CookieInfo *Curl_cookie_init(char *, struct CookieInfo *, bool); struct CookieInfo *Curl_cookie_init(char *, struct CookieInfo *, bool);
struct Cookie *Curl_cookie_getlist(struct CookieInfo *, char *, char *, bool); struct Cookie *Curl_cookie_getlist(struct CookieInfo *, char *, char *, bool);