[nginx] svn commit: r4674 - trunk/src/os/win32
mdounin at mdounin.ru
mdounin at mdounin.ru
Tue Jun 5 13:36:09 UTC 2012
Author: mdounin
Date: 2012-06-05 13:36:09 +0000 (Tue, 05 Jun 2012)
New Revision: 4674
URL: http://trac.nginx.org/nginx/changeset/4674/nginx
Log:
Win32: disallowed access to various non-canonical name variants.
This includes trailings dots and spaces, NTFS streams (and short names, as
previously checked). The checks are now also done in ngx_file_info(), thus
allowing to use the "try_files" directive to protect external scripts.
Modified:
trunk/src/os/win32/ngx_files.c
Modified: trunk/src/os/win32/ngx_files.c
===================================================================
--- trunk/src/os/win32/ngx_files.c 2012-06-05 13:17:05 UTC (rev 4673)
+++ trunk/src/os/win32/ngx_files.c 2012-06-05 13:36:09 UTC (rev 4674)
@@ -11,6 +11,8 @@
#define NGX_UTF16_BUFLEN 256
+static ngx_int_t ngx_win32_check_filename(u_char *name, u_short *u,
+ size_t len);
static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len);
@@ -20,8 +22,7 @@
ngx_open_file(u_char *name, u_long mode, u_long create, u_long access)
{
size_t len;
- u_long n;
- u_short *u, *lu;
+ u_short *u;
ngx_fd_t fd;
ngx_err_t err;
u_short utf16[NGX_UTF16_BUFLEN];
@@ -34,25 +35,11 @@
}
fd = INVALID_HANDLE_VALUE;
- lu = NULL;
- if (create == NGX_FILE_OPEN) {
-
- lu = malloc(len * 2);
- if (lu == NULL) {
- goto failed;
- }
-
- n = GetLongPathNameW(u, lu, len);
-
- if (n == 0) {
- goto failed;
- }
-
- if (n != len - 1 || _wcsicmp(u, lu) != 0) {
- ngx_set_errno(NGX_ENOENT);
- goto failed;
- }
+ if (create == NGX_FILE_OPEN
+ && ngx_win32_check_filename(name, u, len) != NGX_OK)
+ {
+ goto failed;
}
fd = CreateFileW(u, mode,
@@ -61,18 +48,12 @@
failed:
- err = ngx_errno;
-
- if (lu) {
- ngx_free(lu);
- }
-
if (u != utf16) {
+ err = ngx_errno;
ngx_free(u);
+ ngx_set_errno(err);
}
- ngx_set_errno(err);
-
return fd;
}
@@ -294,14 +275,14 @@
return NGX_FILE_ERROR;
}
- rc = GetFileAttributesExW(u, GetFileExInfoStandard, &fa);
+ rc = NGX_FILE_ERROR;
- if (u != utf16) {
- err = ngx_errno;
- ngx_free(u);
- ngx_set_errno(err);
+ if (ngx_win32_check_filename(file, u, len) != NGX_OK) {
+ goto failed;
}
+ rc = GetFileAttributesExW(u, GetFileExInfoStandard, &fa);
+
sb->dwFileAttributes = fa.dwFileAttributes;
sb->ftCreationTime = fa.ftCreationTime;
sb->ftLastAccessTime = fa.ftLastAccessTime;
@@ -309,6 +290,14 @@
sb->nFileSizeHigh = fa.nFileSizeHigh;
sb->nFileSizeLow = fa.nFileSizeLow;
+failed:
+
+ if (u != utf16) {
+ err = ngx_errno;
+ ngx_free(u);
+ ngx_set_errno(err);
+ }
+
return rc;
}
@@ -640,6 +629,148 @@
}
+static ngx_int_t
+ngx_win32_check_filename(u_char *name, u_short *u, size_t len)
+{
+ u_char *p, ch;
+ u_long n;
+ u_short *lu;
+ ngx_err_t err;
+ enum {
+ sw_start = 0,
+ sw_normal,
+ sw_after_slash,
+ sw_after_colon,
+ sw_after_dot
+ } state;
+
+ /* check for NTFS streams (":"), trailing dots and spaces */
+
+ lu = NULL;
+ state = sw_start;
+
+ for (p = name; *p; p++) {
+ ch = *p;
+
+ switch (state) {
+
+ case sw_start:
+
+ /*
+ * skip till first "/" to allow paths starting with drive and
+ * relative path, like "c:html/"
+ */
+
+ if (ch == '/' || ch == '\\') {
+ state = sw_after_slash;
+ }
+
+ break;
+
+ case sw_normal:
+
+ if (ch == ':') {
+ state = sw_after_colon;
+ break;
+ }
+
+ if (ch == '.' || ch == ' ') {
+ state = sw_after_dot;
+ break;
+ }
+
+ if (ch == '/' || ch == '\\') {
+ state = sw_after_slash;
+ break;
+ }
+
+ break;
+
+ case sw_after_slash:
+
+ if (ch == '/' || ch == '\\') {
+ break;
+ }
+
+ if (ch == '.') {
+ break;
+ }
+
+ if (ch == ':') {
+ state = sw_after_colon;
+ break;
+ }
+
+ state = sw_normal;
+ break;
+
+ case sw_after_colon:
+
+ if (ch == '/' || ch == '\\') {
+ state = sw_after_slash;
+ break;
+ }
+
+ goto invalid;
+
+ case sw_after_dot:
+
+ if (ch == '/' || ch == '\\') {
+ goto invalid;
+ }
+
+ if (ch == ':') {
+ goto invalid;
+ }
+
+ if (ch == '.' || ch == ' ') {
+ break;
+ }
+
+ state = sw_normal;
+ break;
+ }
+ }
+
+ if (state == sw_after_dot) {
+ goto invalid;
+ }
+
+ /* check if long name match */
+
+ lu = malloc(len * 2);
+ if (lu == NULL) {
+ return NGX_ERROR;
+ }
+
+ n = GetLongPathNameW(u, lu, len);
+
+ if (n == 0) {
+ goto failed;
+ }
+
+ if (n != len - 1 || _wcsicmp(u, lu) != 0) {
+ goto invalid;
+ }
+
+ return NGX_OK;
+
+invalid:
+
+ ngx_set_errno(NGX_ENOENT);
+
+failed:
+
+ if (lu) {
+ err = ngx_errno;
+ ngx_free(lu);
+ ngx_set_errno(err);
+ }
+
+ return NGX_ERROR;
+}
+
+
static u_short *
ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len)
{
More information about the nginx-devel
mailing list