Return-Path: Delivered-To: apache-cvs-archive@hyperreal.org Received: (qmail 19297 invoked by uid 6000); 27 Jun 1998 17:24:15 -0000 Received: (qmail 19287 invoked by alias); 27 Jun 1998 17:24:13 -0000 Delivered-To: apache-1.3-cvs@hyperreal.org Received: (qmail 19271 invoked by uid 124); 27 Jun 1998 17:24:13 -0000 Date: 27 Jun 1998 17:24:13 -0000 Message-ID: <19980627172413.19270.qmail@hyperreal.org> From: ben@hyperreal.org To: apache-1.3-cvs@hyperreal.org Subject: cvs commit: apache-1.3/src/os/win32 util_win32.c Sender: apache-cvs-owner@apache.org Precedence: bulk Reply-To: new-httpd@apache.org ben 98/06/27 10:24:12 Modified: src CHANGES src/os/win32 util_win32.c Log: Eliminate problems with mutiple and trailing slashes. Also deal with trailing .s. Revision Changes Path 1.934 +7 -0 apache-1.3/src/CHANGES Index: CHANGES =================================================================== RCS file: /export/home/cvs/apache-1.3/src/CHANGES,v retrieving revision 1.933 retrieving revision 1.934 diff -u -r1.933 -r1.934 --- CHANGES 1998/06/25 21:06:01 1.933 +++ CHANGES 1998/06/27 17:24:06 1.934 @@ -1,5 +1,12 @@ Changes with Apache 1.3.1 + *) Win32: Don't collapse multiple slashes in PATH_INFO. + [Ben Laurie, Bill Stoddard ] PR#2274 + + *) Win32 (security): Eliminate trailing "."s in path components. These are + ignored by the Windows filesystem, and so can be used to bypass security. + [Ben Laurie, Alexei Kosut]. + *) We now attempt to dump core when we get SIGILL. [Jim Jagielski] *) PORT: remove broken test for MAP_FILE in http_main.c. 1.18 +36 -19 apache-1.3/src/os/win32/util_win32.c Index: util_win32.c =================================================================== RCS file: /export/home/cvs/apache-1.3/src/os/win32/util_win32.c,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- util_win32.c 1998/06/23 19:53:31 1.17 +++ util_win32.c 1998/06/27 17:24:11 1.18 @@ -4,14 +4,21 @@ #include "httpd.h" -static void sub_canonical_filename(char *szCanon, unsigned nCanon, const char *szFile) +/* Returns TRUE if the path is real, FALSE if it is PATH_INFO */ +static BOOL sub_canonical_filename(char *szCanon, unsigned nCanon, const char *szFile) { char buf[HUGE_STRING_LEN]; int n; char *szFilePart; + char *s; + int nSlashes; WIN32_FIND_DATA d; HANDLE h; + s=strrchr(szFile,'\\'); + for(nSlashes=0 ; s > szFile && s[-1] == '\\' ; ++nSlashes,--s) + ; + n = GetFullPathName(szFile, sizeof buf, buf, &szFilePart); ap_assert(n); ap_assert(n < sizeof buf); @@ -68,13 +75,17 @@ szCanon[3] = '\0'; } if (h == INVALID_HANDLE_VALUE) { - ap_assert(strlen(szCanon)+strlen(szFilePart) < nCanon); + ap_assert(strlen(szCanon)+strlen(szFilePart)+nSlashes < nCanon); + for(n=0 ; n < nSlashes ; ++n) + strcat(szCanon, "/"); strcat(szCanon, szFilePart); + return FALSE; } else { ap_assert(strlen(szCanon)+strlen(d.cFileName) < nCanon); strlwr(d.cFileName); strcat(szCanon, d.cFileName); + return TRUE; } } @@ -86,35 +97,41 @@ { char buf[HUGE_STRING_LEN]; char b2[HUGE_STRING_LEN]; - char *s,*d; + const char *s; + char *d; + int nSlashes; ap_assert(strlen(szFile) < sizeof b2); - strcpy(b2,szFile); - for(s=b2 ; *s ; ++s) - if(*s == '/') - *s='\\'; /* Eliminate directories consisting of three or more dots. These act like ".." but are not detected by other machinery. + Also get rid of trailing .s on any path component, which are ignored by the filesystem. + Simultaneously, rewrite / to \. This is a bit of a kludge - Ben. */ - for(d=s=b2 ; (*d=*s) ; ++d,++s) - if(!strncmp(s,"\\...",3)) - { - int n=strspn(s+1,"."); - if(s[n+1] != '\\') - continue; - s+=n; - --d; + for(s=szFile,d=b2 ; (*d=*s) ; ++d,++s) { + if(*s == '/') + *d='\\'; + if(*s == '.' && (s[1] == '/' || s[1] == '\\' || !s[1])) { + while(*d == '.') + --d; + if(*d == '\\') + --d; } + } + // Finally, a trailing slash(es) screws thing, so blow them away + for(nSlashes=0 ; d > b2 && d[-1] == '\\' ; --d,++nSlashes) + ; + *d='\0'; + + if(sub_canonical_filename(buf, sizeof buf, b2) && nSlashes) + nSlashes=1; - sub_canonical_filename(buf, sizeof buf, b2); buf[0]=tolower(buf[0]); - if (*szFile && szFile[strlen(szFile)-1] == '/' && buf[strlen(buf)-1] != '/') { - ap_assert(strlen(buf)+1 < sizeof buf); + ap_assert(strlen(buf)+nSlashes < sizeof buf); + while(nSlashes--) strcat(buf, "/"); - } return ap_pstrdup(pPool, buf); }