From: Pierre Joye Date: Sun, 17 May 2009 19:51:13 +0000 (+0000) Subject: - MFB: #44859, fixed support for windows ACL, drop win9x code X-Git-Tag: php-5.4.0alpha1~191^2~3632 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=20ab93a3e3b78698b524f9681775037a4dcb35ad;p=php - MFB: #44859, fixed support for windows ACL, drop win9x code --- diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 2201e9e98f..acddc46868 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -23,6 +23,7 @@ #include #include #include +#include #define TSRM_INCLUDE_FULL_WINDOWS_HEADERS @@ -45,6 +46,7 @@ static void tsrm_win32_ctor(tsrm_win32_globals *globals TSRMLS_DC) globals->process_size = 0; globals->shm_size = 0; globals->comspec = _strdup((GetVersion()<0x80000000)?"cmd.exe":"command.com"); + globals->impersonation_token = NULL; } static void tsrm_win32_dtor(tsrm_win32_globals *globals TSRMLS_DC) @@ -86,21 +88,82 @@ TSRM_API void tsrm_win32_shutdown(void) TSRM_API int tsrm_win32_access(const char *pathname, int mode) { + SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; + GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS }; + DWORD priv_set_length = sizeof(PRIVILEGE_SET); + + PRIVILEGE_SET privilege_set = {0}; + DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0; + BYTE * psec_desc = NULL; + BOOL fAccess = FALSE; + HANDLE process_token = NULL; + TSRMLS_FETCH(); + if (mode == 1 /*X_OK*/) { -#if 1 - /* This code is not supported by Windows 98, - * but we don't support it anymore */ DWORD type; + return GetBinaryType(pathname, &type) ? 0 : -1; + } else { + if(access(pathname, mode)) { + return errno; + } - return GetBinaryType(pathname, &type)?0:-1; -#else - SHFILEINFO sfi; + /* Do a full access check because access() will only check read-only attribute */ + if(mode == 0 || mode > 6) { + desired_access = FILE_GENERIC_READ; + } else if(mode <= 2) { + desired_access = FILE_GENERIC_WRITE; + } else if(mode <= 4) { + desired_access = FILE_GENERIC_READ; + } else { // if(mode <= 6) + desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; + } - return access(pathname, 0) == 0 && - SHGetFileInfo(pathname, 0, &sfi, sizeof(SHFILEINFO), SHGFI_EXETYPE) != 0 ? 0 : -1; -#endif - } else { - return access(pathname, mode); + /* Get size of security buffer. Call is expected to fail */ + if(GetFileSecurity(pathname, sec_info, NULL, 0, &sec_desc_length)) { + goto Finished; + } + + psec_desc = (BYTE *)malloc(sec_desc_length); + if(psec_desc == NULL || + !GetFileSecurity(pathname, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) { + goto Finished; + } + + if(TWG(impersonation_token) == NULL) { + + if(!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &process_token)) { + goto Finished; + } + + /* Access check requires impersonation token. Create a duplicate token. */ + if(!DuplicateToken(process_token, SecurityImpersonation, &TWG(impersonation_token))) { + goto Finished; + } + } + + if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) { + goto Finished; + } + +Finished: + + /* impersonation_token will be closed when the process dies */ + if(process_token != NULL) { + CloseHandle(process_token); + process_token = NULL; + } + + if(psec_desc != NULL) { + free(psec_desc); + psec_desc = NULL; + } + + if(fAccess == FALSE) { + errno = EACCES; + return errno; + } else { + return 0; + } } } diff --git a/TSRM/tsrm_win32.h b/TSRM/tsrm_win32.h index 09b3cafd09..0fc952ad5a 100644 --- a/TSRM/tsrm_win32.h +++ b/TSRM/tsrm_win32.h @@ -63,6 +63,7 @@ typedef struct { int process_size; int shm_size; char *comspec; + HANDLE impersonation_token; } tsrm_win32_globals; #ifdef ZTS diff --git a/ext/standard/tests/file/windows_acls/bug44859.phpt b/ext/standard/tests/file/windows_acls/bug44859.phpt new file mode 100644 index 0000000000..0716ee5ac4 --- /dev/null +++ b/ext/standard/tests/file/windows_acls/bug44859.phpt @@ -0,0 +1,60 @@ +--TEST-- +bug #44859 (incorrect result with NTFS ACL permissions, is_writable) +--SKIPIF-- + +--FILE-- + false, + PHPT_ACL_NONE => false, + PHPT_ACL_WRITE => true, + PHPT_ACL_WRITE|PHPT_ACL_READ => true, +); + +echo "Testing file:\n"; +$i = 1; +$path = __DIR__ . '/a.txt'; +foreach ($iteration as $perms => $exp) { + create_file($path, $perms); + echo 'Iteration #' . $i++ . ': '; + if (is_writable($path) == $exp) { + echo "passed.\n"; + } else { + var_dump(is_writable($path), $exp); + echo "failed.\n"; + } + delete_file($path); +} + +echo "Testing directory:\n"; +$path = __DIR__ . '/adir'; +$i = 1; +foreach ($iteration as $perms => $exp) { + create_file($path, $perms); + echo 'Iteration #' . $i++ . ': '; + if (is_writable($path) == $exp) { + echo "passed.\n"; + } else { + var_dump(is_writable($path), $exp); + echo "failed.\n"; + } + delete_file($path); +} + +?> +--EXPECT-- +Testing file: +Iteration #1: passed. +Iteration #2: passed. +Iteration #3: passed. +Iteration #4: passed. +Testing directory: +Iteration #1: passed. +Iteration #2: passed. +Iteration #3: passed. +Iteration #4: passed. diff --git a/ext/standard/tests/file/windows_acls/bug44859_2.phpt b/ext/standard/tests/file/windows_acls/bug44859_2.phpt new file mode 100644 index 0000000000..8326eb473e --- /dev/null +++ b/ext/standard/tests/file/windows_acls/bug44859_2.phpt @@ -0,0 +1,60 @@ +--TEST-- +bug #44859 (incorrect result with NTFS ACL permissions, is_readable) +--SKIPIF-- + +--FILE-- + true, + PHPT_ACL_NONE => false, + PHPT_ACL_WRITE => false, + PHPT_ACL_WRITE|PHPT_ACL_READ => true, +); + +echo "Testing file:\n"; +$i = 1; +$path = __DIR__ . '/a.txt'; +foreach ($iteration as $perms => $exp) { + create_file($path, $perms); + echo 'Iteration #' . $i++ . ': '; + if (is_readable($path) == $exp) { + echo "passed.\n"; + } else { + var_dump(is_writable($path), $exp); + echo "failed.\n"; + } + delete_file($path); +} + +echo "Testing directory:\n"; +$path = __DIR__ . '/adir'; +$i = 1; +foreach ($iteration as $perms => $exp) { + create_file($path, $perms); + echo 'Iteration #' . $i++ . ': '; + if (is_readable($path) == $exp) { + echo "passed.\n"; + } else { + var_dump(is_writable($path), $exp); + echo "failed.\n"; + } + delete_file($path); +} + +?> +--EXPECT-- +Testing file: +Iteration #1: passed. +Iteration #2: passed. +Iteration #3: passed. +Iteration #4: passed. +Testing directory: +Iteration #1: passed. +Iteration #2: passed. +Iteration #3: passed. +Iteration #4: passed. diff --git a/ext/standard/tests/file/windows_acls/bug44859_3.phpt b/ext/standard/tests/file/windows_acls/bug44859_3.phpt new file mode 100644 index 0000000000..7300112fc0 --- /dev/null +++ b/ext/standard/tests/file/windows_acls/bug44859_3.phpt @@ -0,0 +1,36 @@ +--TEST-- +bug #44859 (incorrect result with NTFS ACL permissions, is_executable) +--SKIPIF-- + +--FILE-- + true, + //'tiny.bat' => true, To be fixed in _access + __FILE__ => false +); + +$i = 1; +$path = __DIR__; + +foreach ($iteration as $file => $exp) { + $path = __DIR__ . '/' . $file; + echo 'Iteration #' . $i++ . ': '; + if (is_executable($path) == $exp) { + echo "passed.\n"; + } else { + var_dump(is_executable($path), $exp); + echo "failed.\n"; + } +} + + +?> +--EXPECT-- +Iteration #1: passed. +Iteration #2: passed. diff --git a/ext/standard/tests/file/windows_acls/common.inc b/ext/standard/tests/file/windows_acls/common.inc new file mode 100644 index 0000000000..6bcaf2b327 --- /dev/null +++ b/ext/standard/tests/file/windows_acls/common.inc @@ -0,0 +1,177 @@ +