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)) {
co->domain=strdup(whatptr); /* note that this name may or may not have a preceeding dot, but
co->field1= (whatptr[0]=='.')?2:1; 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->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 */
strequal(&(clist->domain[1]), co->domain)) || ((clist->domain[0]=='.' &&
(co->domain[0]=='.' && strequal(&(clist->domain[1]), co->domain)) ||
strequal(clist->domain, &(co->domain[1]))) ) (co->domain[0]=='.' &&
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)
@ -572,43 +649,42 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
co = c->cookies; co = c->cookies;
while(co) { while(co) {
/* only process this cookie if it is not expired or had no expire /* only process this cookie if it is not expired or had no expire
date AND that if the cookie requires we're secure we must only date AND that if the cookie requires we're secure we must only
continue if we are! */ continue if we are! */
if( (co->expires<=0 || (co->expires> now)) && if( (co->expires<=0 || (co->expires> now)) &&
(co->secure?secure:TRUE) ) { (co->secure?secure:TRUE) ) {
/* now check if the domain is correct */
if(!co->domain ||
(co->tailmatch && tailmatch(co->domain, host)) ||
(!co->tailmatch && strequal(host, co->domain)) ) {
/* the right part of the host matches the domain stuff in the
cookie data */
/* now check the left part of the path with the cookies path
requirement */
if(!co->path ||
checkprefix(co->path, path) ) {
/* now check if the domain is correct */ /* and now, we know this is a match and we should create an
domlen=co->domain?strlen(co->domain):0; entry for the return-linked-list */
if(!co->domain ||
((domlen<=hostlen) && newco = (struct Cookie *)malloc(sizeof(struct Cookie));
strequal(host+(hostlen-domlen), co->domain)) ) { if(newco) {
/* the right part of the host matches the domain stuff in the /* first, copy the whole source cookie: */
cookie data */ memcpy(newco, co, sizeof(struct Cookie));
/* now check the left part of the path with the cookies path /* then modify our next */
requirement */ newco->next = mainco;
if(!co->path ||
checkprefix(co->path, path) ) { /* point the main to us */
mainco = newco;
/* and now, we know this is a match and we should create an }
entry for the return-linked-list */ }
}
newco = (struct Cookie *)malloc(sizeof(struct Cookie)); }
if(newco) { co = co->next;
/* first, copy the whole source cookie: */
memcpy(newco, co, sizeof(struct Cookie));
/* then modify our next */
newco->next = mainco;
/* point the main to us */
mainco = newco;
}
}
}
}
co = co->next;
} }
return mainco; /* return the new list */ return mainco; /* return the new list */
@ -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);