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 <[EMAIL PROTECTED]>] 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);
}