--- src/sgDiv.c.orig 2009-02-12 07:31:57.000000000 -0600 +++ src/sgDiv.c 2008-06-13 11:52:17.000000000 -0500 @@ -94,6 +94,9 @@ { char *p, *d = NULL, *a = NULL, *e = NULL, *o, *field; int i = 0; + int report_once = 1; + int trailingdot = 0; + size_t strsz; char c; int ndx = 0; @@ -126,22 +129,38 @@ */ /* Fix for multiple slash vulnerability (bug1). */ /* Check if there are still two or more slashes in sequence which must not happen */ - int report_once = 1; + strsz = strlen(p); - /* loop thru the string 'p' until the char '?' is hit */ + /* loop thru the string 'p' until the char '?' is hit or the "end" is hit */ while('?' != p[ndx] && '\0' != p[ndx]) { - /* if this char and the next char are slashes, - then shift the rest of the string left one char */ - if('/' == p[ndx] && '/' == p[ndx+1]) - { - size_t sz = strlen(p+ndx+1); - strncpy(p+ndx,p+ndx+1, sz); - p[ndx+sz] = '\0'; - if(1 == report_once) { - sgLogError("Warning: Possible bypass attempt. Found multiple slashes where only one is expected: %s", s->orig); - report_once--; + /* in case this is a '://' skip over it, but try to not read past EOS */ + if(3 <= strsz-ndx) { + if(':' == p[ndx] && '/' == p[ndx+1] && '/' == p[ndx+2]) { + ndx+=3; /* 3 == strlen("://"); */ + } } + + /* if this char and the next char are slashes, + * then shift the rest of the string left one char */ + if('/' == p[ndx] && '/' == p[ndx+1]) { + size_t sz = strlen(p+ndx+1); + strncpy(p+ndx,p+ndx+1, sz); + p[ndx+sz] = '\0'; + if(1 == report_once) { + sgLogError("Warning: Possible bypass attempt. Found multiple slashes where only one is expected: %s", s->orig); + report_once--; + } + } + else if ('.' == p[ndx] && '/' == p[ndx+1] && trailingdot == 0) { + /* If the domain has trailing dot, remove (problem found with squid 3.0 stable1-5) the trailing dot (fixes bug 38). */ + /* if this char is a dot and the next char is a slash, then shift the rest of the string left one char */ + /* We do this only the first time it is encountered. */ + trailingdot++; + size_t sz = strlen(p+ndx+1); + strncpy(p+ndx,p+ndx+1, sz); + p[ndx+sz] = '\0'; + sgLogError("Warning: Possible bypass attempt. Found a trailing dot in the domain name: %s", s->orig); } else { @@ -537,13 +556,13 @@ #endif { struct sgRegExp *re; - regmatch_t pm[10]; + regmatch_t pm; static char newstring[MAX_BUF]; char *result = NULL, *p; int substlen; *newstring='\0'; for(re = regexp; re != NULL; re = re->next){ - if (regexec (re->compiled, pattern, sizeof(pm) / sizeof(pm[0]), pm, 0) != 0){ + if (regexec (re->compiled, pattern, 1, &pm, 0) != 0){ result = NULL; } else { substlen = strlen(re->substitute); @@ -553,65 +572,14 @@ *newstring = '\0'; p = newstring; do { - if((p - newstring)+ pm[0].rm_so >= MAX_BUF) + if((p - newstring)+ pm.rm_so >= MAX_BUF) break; - p = strncat(newstring,pattern,pm[0].rm_so); - { - char *p_cur; - char *p_next; - - for (p_next = p_cur = re->substitute; - p_next < (re->substitute + substlen); - p_next++) - { - if (*p_next == '\\') - { - if (p_cur < p_next) - { - if (((p - newstring) + (p_next - p_cur)) >= MAX_BUF) - goto err; - p = strncat(newstring, p_cur, p_next - p_cur); - } - p_next++; - if (p_next < (re->substitute + substlen) - && '0' <= *p_next && *p_next <= '9') - { - int i = *p_next - '0'; - if ((p - newstring) + (pm[i].rm_eo - pm[i].rm_so) >= MAX_BUF) - goto err; - p = strncat(newstring, pattern + pm[i].rm_so, pm[i].rm_eo - pm[i].rm_so); - } - else - { - if ((p - newstring + 1) >= MAX_BUF) - goto err; - p = strncat(newstring, p_next, 1); - } - p_cur = p_next + 1; - } - else if (*p_next == '&') - { - if (p_cur < p_next) - { - if (((p - newstring) + (p_next - p_cur)) >= MAX_BUF) - goto err; - p = strncat(newstring, p_cur, p_next - p_cur); - } - if (((p - newstring) + (pm[0].rm_eo - pm[0].rm_so)) >= MAX_BUF) - goto err; - p = strncat(newstring, pattern + pm[0].rm_so, pm[0].rm_eo - pm[0].rm_so); - p_cur = p_next + 1; - } - } - if (p_cur < p_next) - { - if (((p - newstring) + (p_next - p_cur)) >= MAX_BUF) - goto err; - p = strncat(newstring, p_cur, p_next - p_cur); - } - } - pattern = pattern + pm[0].rm_eo; - } while(regexec (re->compiled, pattern, sizeof(pm) / sizeof(pm[0]), pm, REG_NOTBOL)== 0 && + p = strncat(newstring,pattern,pm.rm_so); + if((p - newstring)+ substlen >= MAX_BUF) + break; + p = strcat(newstring,re->substitute); + pattern = pattern + pm.rm_eo; + } while(regexec (re->compiled, pattern, 1, &pm, REG_NOTBOL)== 0 && re->global); if((p - newstring)+ strlen(pattern) <= MAX_BUF) p = strcat(newstring,pattern); @@ -619,7 +587,6 @@ break; } } -err: return result; }