fielding 99/01/05 00:17:38
Modified: . STATUS
src ApacheCore.def CHANGES
src/include ap_mmn.h httpd.h
src/main http_request.c util.c
src/os/win32 util_win32.c
src/support httpd.exp
Log:
ap_os_is_filename_valid() has been added to Win32
to detect and prevent access to special DOS device file names.
Submitted by: Paul Sutton, Ken Parzygnat
Reviewed by: Roy Fielding
Revision Changes Path
1.592 +1 -7 apache-1.3/STATUS
Index: STATUS
===================================================================
RCS file: /home/cvs/apache-1.3/STATUS,v
retrieving revision 1.591
retrieving revision 1.592
diff -u -r1.591 -r1.592
--- STATUS 1999/01/05 07:08:59 1.591
+++ STATUS 1999/01/05 08:17:24 1.592
@@ -1,5 +1,5 @@
1.3 STATUS:
- Last modified at [$Date: 1999/01/05 07:08:59 $]
+ Last modified at [$Date: 1999/01/05 08:17:24 $]
Release:
@@ -16,12 +16,6 @@
RELEASE SHOWSTOPPERS:
- * Paul's [PATCH] Win32 device files
- Message-ID: <[EMAIL PROTECTED]>
- and <[EMAIL PROTECTED]>
- Status: Someone who knows the current status of this thing should
- apply it now, since the rest of us can't test it otherwise.
-
* long pathnames with many components and no AllowOverride None
Status: Marc is looking at it
1.6 +1 -0 apache-1.3/src/ApacheCore.def
Index: ApacheCore.def
===================================================================
RCS file: /home/cvs/apache-1.3/src/ApacheCore.def,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- ApacheCore.def 1999/01/03 12:04:34 1.5
+++ ApacheCore.def 1999/01/05 08:17:25 1.6
@@ -323,4 +323,5 @@
ap_single_module_init @316
ap_make_etag @317
ap_array_pstrcat @318
+ ap_os_is_filename_valid @319
1.1204 +4 -0 apache-1.3/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/apache-1.3/src/CHANGES,v
retrieving revision 1.1203
retrieving revision 1.1204
diff -u -r1.1203 -r1.1204
--- CHANGES 1999/01/05 07:09:01 1.1203
+++ CHANGES 1999/01/05 08:17:25 1.1204
@@ -1,5 +1,9 @@
Changes with Apache 1.3.4
+ *) SECURITY: ap_os_is_filename_valid() has been added to Win32
+ to detect and prevent access to special DOS device file names.
+ [Paul Sutton, Ken Parzygnat]
+
*) WIN32: Created new makefiles Makefile_win32.txt (normal build)
and Makefile_win32_debug.txt (debug build) that work on Win95.
Run each of the following from the src directory:
1.19 +2 -1 apache-1.3/src/include/ap_mmn.h
Index: ap_mmn.h
===================================================================
RCS file: /home/cvs/apache-1.3/src/include/ap_mmn.h,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- ap_mmn.h 1999/01/03 12:04:36 1.18
+++ ap_mmn.h 1999/01/05 08:17:27 1.19
@@ -195,12 +195,13 @@
* 19990101 - renamed macro escape_uri() to ap_escape_uri()
* - added MODULE_MAGIC_COOKIE to identify module
structs
* 19990103 (1.3.4-dev) - added ap_array_pstrcat()
+ * 19990105 (1.3.4-dev) - added ap_os_is_filename_valid() to Win32
*/
#define MODULE_MAGIC_COOKIE 0x41503133UL /* "AP13" */
#ifndef MODULE_MAGIC_NUMBER_MAJOR
-#define MODULE_MAGIC_NUMBER_MAJOR 19990103
+#define MODULE_MAGIC_NUMBER_MAJOR 19990105
#endif
#define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */
#define MODULE_MAGIC_NUMBER MODULE_MAGIC_NUMBER_MAJOR /* backward
compat */
1.258 +1 -0 apache-1.3/src/include/httpd.h
Index: httpd.h
===================================================================
RCS file: /home/cvs/apache-1.3/src/include/httpd.h,v
retrieving revision 1.257
retrieving revision 1.258
diff -u -r1.257 -r1.258
--- httpd.h 1999/01/03 13:35:32 1.257
+++ httpd.h 1999/01/05 08:17:27 1.258
@@ -1025,6 +1025,7 @@
#ifdef WIN32
API_EXPORT(char *) ap_os_case_canonical_filename(pool *pPool, const char
*szFile);
API_EXPORT(char *) ap_os_systemcase_filename(pool *pPool, const char
*szFile);
+API_EXPORT(int) ap_os_is_filename_valid(const char *file);
#else
#define ap_os_case_canonical_filename(p,f) ap_os_canonical_filename(p,f)
#define ap_os_systemcase_filename(p,f) ap_os_canonical_filename(p,f)
1.141 +42 -13 apache-1.3/src/main/http_request.c
Index: http_request.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/main/http_request.c,v
retrieving revision 1.140
retrieving revision 1.141
diff -u -r1.140 -r1.141
--- http_request.c 1999/01/01 19:04:50 1.140
+++ http_request.c 1999/01/05 08:17:29 1.141
@@ -179,7 +179,6 @@
char *last_cp = NULL;
int rv;
#ifdef WIN32
- char buf[5];
BOOL bStripSlash=TRUE;
#endif
@@ -189,16 +188,12 @@
}
#ifdef WIN32
- /* If the path is x:/, then convert it to x:/., coz that's what stat
- * needs to work properly
+ /* If the directory is x:\, then we don't want to strip
+ * the trailing slash since x: is not a valid directory.
*/
- if (strlen(path) == 3 && path[1] == ':') {
- strcpy(buf,path);
- buf[3]='.';
- buf[4]='\0';
- path=buf;
- end=buf+4;
- }
+ if (strlen(path) == 3 && path[1] == ':' && path[2] == '/')
+ bStripSlash = FALSE;
+
/* If UNC name == //machine/share/, do not
* advance over the trailing slash. Any other
@@ -234,8 +229,25 @@
*cp = '\0';
+#ifdef WIN32
+ /* We must not stat() filenames such as "/file/aux" since it can
cause
+ * delays or lockups. So pretend that they do not exist by returning
+ * an ENOENT error. This will force us to drop that part of the path
and
+ * keep looking back for a "real" file that exists, while still
allowing
+ * the "invalid" path parts within the PATH_INFO.
+ */
+ if (!ap_os_is_filename_valid(path)) {
+ errno = ENOENT;
+ rv = -1;
+ }
+ else {
+ errno = 0;
+ rv = stat(path, &r->finfo);
+ }
+#else
errno = 0;
rv = stat(path, &r->finfo);
+#endif
if (cp != end)
*cp = '/';
@@ -315,7 +327,7 @@
char *test_filename;
char *test_dirname;
int res;
- unsigned i, num_dirs;
+ unsigned i, num_dirs, iStart;
int j, test_filename_len;
/*
@@ -395,6 +407,14 @@
ap_no2slash(test_filename);
num_dirs = ap_count_dirs(test_filename);
+#ifdef WIN32
+ if (!ap_os_is_filename_valid(r->filename)) {
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "Filename is not valid: %s", r->filename);
+ return HTTP_FORBIDDEN;
+ }
+#endif
+
if ((res = check_safe_file(r))) {
return res;
}
@@ -415,9 +435,18 @@
*/
test_dirname = ap_palloc(r->pool, test_filename_len + 2);
+ iStart = 1;
+#ifdef WIN32
+ /* If the name is a UNC name, then do not walk through the
+ * machine and share name (e.g. \\machine\share\)
+ */
+ if (num_dirs > 3 && test_filename[0] == '/' && test_filename[1] == '/')
+ iStart = 4;
+#endif
+
/* j keeps track of which section we're on, see core_reorder_directories
*/
j = 0;
- for (i = 1; i <= num_dirs; ++i) {
+ for (i = iStart; i <= num_dirs; ++i) {
int overrides_here;
core_dir_config *core_dir = (core_dir_config *)
ap_get_module_config(per_dir_defaults, &core_module);
@@ -803,7 +832,7 @@
rnew->uri = ap_make_full_path(rnew->pool, udir, new_file);
rnew->filename = ap_make_full_path(rnew->pool, fdir, new_file);
- ap_parse_uri(rnew, rnew->uri); /* fill in parsed_uri values */
+ ap_parse_uri(rnew, rnew->uri); /* fill in parsed_uri values */
if (stat(rnew->filename, &rnew->finfo) < 0) {
rnew->finfo.st_mode = 0;
}
1.144 +10 -0 apache-1.3/src/main/util.c
Index: util.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/main/util.c,v
retrieving revision 1.143
retrieving revision 1.144
diff -u -r1.143 -r1.144
--- util.c 1999/01/01 19:04:53 1.143
+++ util.c 1999/01/05 08:17:30 1.144
@@ -761,6 +761,16 @@
return NULL;
}
+#if defined(WIN32)
+ if (!ap_os_is_filename_valid(name)) {
+ ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL,
+ "Access to config file %s denied: not a valid filename",
+ name);
+ errno = EACCES;
+ return NULL;
+ }
+#endif
+
file = ap_pfopen(p, name, "r");
#ifdef DEBUG
saved_errno = errno;
1.31 +140 -0 apache-1.3/src/os/win32/util_win32.c
Index: util_win32.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/os/win32/util_win32.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -r1.30 -r1.31
--- util_win32.c 1998/11/06 14:25:58 1.30
+++ util_win32.c 1999/01/05 08:17:32 1.31
@@ -534,3 +534,143 @@
}
return return_value;
}
+
+/*
+ * ap_os_is_filename_valid is given a filename, and returns 0 if the filename
+ * is not valid for use on this system. On Windows, this means it fails any
+ * of the tests below. Otherwise returns 1.
+ *
+ * Test for filename validity on Win32. This is of tests come in part from
+ * the MSDN article at "Technical Articles, Windows Platform, Base Services,
+ * Guidelines, Making Room for Long Filenames" although the information
+ * in MSDN about filename testing is incomplete or conflicting. There is a
+ * similar set of tests in "Technical Articles, Windows Platform, Base
Services,
+ * Guidelines, Moving Unix Applications to Windows NT".
+ *
+ * The tests are:
+ *
+ * 1) total path length greater than MAX_PATH
+ *
+ * 2) anything using the octets 0-31 or characters " < > | :
+ * (these are reserved for Windows use in filenames. In addition
+ * each file system has its own additional characters that are
+ * invalid. See KB article Q100108 for more details).
+ *
+ * 3) anything ending in "." (no matter how many)
+ * (filename doc, doc. and doc... all refer to the same file)
+ *
+ * 4) any segment in which the basename (before first period) matches
+ * one of the DOS device names
+ * (the list comes from KB article Q100108 although some people
+ * reports that additional names such as "COM5" are also special
+ * devices).
+ *
+ * If the path fails ANY of these tests, the result must be to deny access.
+ */
+
+API_EXPORT(int) ap_os_is_filename_valid(const char *file)
+{
+ const char *segstart;
+ char seglength;
+ const char *pos;
+ static const char * const invalid_characters = "?\"<>*|:";
+ static const char * const invalid_filenames[] = {
+ "CON", "AUX", "COM1", "COM2", "COM3",
+ "COM4", "LPT1", "LPT2", "LPT3", "PRN", "NUL", NULL
+ };
+
+ /* Test 1 */
+ if (strlen(file) > MAX_PATH) {
+ /* Path too long for Windows. Note that this test is not valid
+ * if the path starts with //?/ or \\?\. */
+ return 0;
+ }
+
+ pos = file;
+
+ /* Skip any leading non-path components. This can be either a
+ * drive letter such as C:, or a UNC path such as \\SERVER\SHARE\.
+ * We continue and check the rest of the path based on the rules above.
+ * This means we could eliminate valid filenames from servers which
+ * are not running NT (such as Samba).
+ */
+
+ if (pos[0] && pos[1] == ':') {
+ /* Skip leading drive letter */
+ pos += 2;
+ }
+ else {
+ if ((pos[0] == '\\' || pos[0] == '/') &&
+ (pos[1] == '\\' || pos[1] == '/')) {
+ /* Is a UNC, so skip the server name and share name */
+ pos += 2;
+ while (*pos && *pos != '/' && *pos != '\\')
+ pos++;
+ if (!*pos) {
+ /* No share name */
+ return 0;
+ }
+ pos++; /* Move to start of share name */
+ while (*pos && *pos != '/' && *pos != '\\')
+ pos++;
+ if (!*pos) {
+ /* No path information */
+ return 0;
+ }
+ }
+ }
+
+ while (*pos) {
+ int idx;
+ int baselength;
+
+ while (*pos == '/' || *pos == '\\') {
+ pos++;
+ }
+ if (*pos == '\0') {
+ break;
+ }
+ segstart = pos; /* start of segment */
+ while (*pos && *pos != '/' && *pos != '\\') {
+ pos++;
+ }
+ seglength = pos - segstart;
+ /*
+ * Now we have a segment of the path, starting at position "segstart"
+ * and length "seglength"
+ */
+
+ /* Test 2 */
+ for (idx = 0; idx < seglength; idx++) {
+ if (segstart[idx] < 32 ||
+ strchr(invalid_characters, segstart[idx])) {
+ return 0;
+ }
+ }
+
+ /* Test 3 */
+ if (segstart[seglength-1] == '.') {
+ return 0;
+ }
+
+ /* Test 4 */
+ for (baselength = 0; baselength < seglength; baselength++) {
+ if (segstart[baselength] == '.') {
+ break;
+ }
+ }
+
+ /* baselength is the number of characters in the base path of
+ * the segment (which could be the same as the whole segment length,
+ * if it does not include any dot characters). */
+ if (baselength == 3 || baselength == 4) {
+ for (idx = 0; invalid_filenames[idx]; idx++) {
+ if (!strnicmp(invalid_filenames[idx], segstart, baselength)) {
+ return 0;
+ }
+ }
+ }
+ }
+
+ return 1;
+}
1.10 +1 -0 apache-1.3/src/support/httpd.exp
Index: httpd.exp
===================================================================
RCS file: /home/cvs/apache-1.3/src/support/httpd.exp,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- httpd.exp 1999/01/03 12:04:40 1.9
+++ httpd.exp 1999/01/05 08:17:36 1.10
@@ -203,6 +203,7 @@
ap_open_logs
ap_open_piped_log
ap_os_escape_path
+ap_os_is_filename_valid
ap_os_is_path_absolute
ap_overlay_tables
ap_overlap_tables