Skip to content

Commit 10ace3f

Browse files
committed
- #44859, fixed support for windows ACL, drop win9x code
1 parent 47f87a5 commit 10ace3f

File tree

8 files changed

+409
-11
lines changed

8 files changed

+409
-11
lines changed

TSRM/tsrm_win32.c

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <io.h>
2424
#include <process.h>
2525
#include <time.h>
26+
#include <errno.h>
2627

2728
#define TSRM_INCLUDE_FULL_WINDOWS_HEADERS
2829

@@ -45,6 +46,7 @@ static void tsrm_win32_ctor(tsrm_win32_globals *globals TSRMLS_DC)
4546
globals->process_size = 0;
4647
globals->shm_size = 0;
4748
globals->comspec = _strdup((GetVersion()<0x80000000)?"cmd.exe":"command.com");
49+
globals->impersonation_token = NULL;
4850
}
4951

5052
static void tsrm_win32_dtor(tsrm_win32_globals *globals TSRMLS_DC)
@@ -86,21 +88,82 @@ TSRM_API void tsrm_win32_shutdown(void)
8688

8789
TSRM_API int tsrm_win32_access(const char *pathname, int mode)
8890
{
91+
SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
92+
GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
93+
DWORD priv_set_length = sizeof(PRIVILEGE_SET);
94+
95+
PRIVILEGE_SET privilege_set = {0};
96+
DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0;
97+
BYTE * psec_desc = NULL;
98+
BOOL fAccess = FALSE;
99+
HANDLE process_token = NULL;
100+
TSRMLS_FETCH();
101+
89102
if (mode == 1 /*X_OK*/) {
90-
#if 1
91-
/* This code is not supported by Windows 98,
92-
* but we don't support it anymore */
93103
DWORD type;
104+
return GetBinaryType(pathname, &type) ? 0 : -1;
105+
} else {
106+
if(access(pathname, mode)) {
107+
return errno;
108+
}
94109

95-
return GetBinaryType(pathname, &type)?0:-1;
96-
#else
97-
SHFILEINFO sfi;
110+
/* Do a full access check because access() will only check read-only attribute */
111+
if(mode == 0 || mode > 6) {
112+
desired_access = FILE_GENERIC_READ;
113+
} else if(mode <= 2) {
114+
desired_access = FILE_GENERIC_WRITE;
115+
} else if(mode <= 4) {
116+
desired_access = FILE_GENERIC_READ;
117+
} else { // if(mode <= 6)
118+
desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
119+
}
98120

99-
return access(pathname, 0) == 0 &&
100-
SHGetFileInfo(pathname, 0, &sfi, sizeof(SHFILEINFO), SHGFI_EXETYPE) != 0 ? 0 : -1;
101-
#endif
102-
} else {
103-
return access(pathname, mode);
121+
/* Get size of security buffer. Call is expected to fail */
122+
if(GetFileSecurity(pathname, sec_info, NULL, 0, &sec_desc_length)) {
123+
goto Finished;
124+
}
125+
126+
psec_desc = (BYTE *)malloc(sec_desc_length);
127+
if(psec_desc == NULL ||
128+
!GetFileSecurity(pathname, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
129+
goto Finished;
130+
}
131+
132+
if(TWG(impersonation_token) == NULL) {
133+
134+
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &process_token)) {
135+
goto Finished;
136+
}
137+
138+
/* Access check requires impersonation token. Create a duplicate token. */
139+
if(!DuplicateToken(process_token, SecurityImpersonation, &TWG(impersonation_token))) {
140+
goto Finished;
141+
}
142+
}
143+
144+
if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
145+
goto Finished;
146+
}
147+
148+
Finished:
149+
150+
/* impersonation_token will be closed when the process dies */
151+
if(process_token != NULL) {
152+
CloseHandle(process_token);
153+
process_token = NULL;
154+
}
155+
156+
if(psec_desc != NULL) {
157+
free(psec_desc);
158+
psec_desc = NULL;
159+
}
160+
161+
if(fAccess == FALSE) {
162+
errno = EACCES;
163+
return errno;
164+
} else {
165+
return 0;
166+
}
104167
}
105168
}
106169

TSRM/tsrm_win32.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ typedef struct {
6363
int process_size;
6464
int shm_size;
6565
char *comspec;
66+
HANDLE impersonation_token;
6667
} tsrm_win32_globals;
6768

6869
#ifdef ZTS
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
--TEST--
2+
bug #44859 (incorrect result with NTFS ACL permissions, is_writable)
3+
--SKIPIF--
4+
<?php
5+
include_once __DIR__ . '/common.inc';
6+
skipif();
7+
?>
8+
--FILE--
9+
<?php
10+
include_once __DIR__ . '/common.inc';
11+
12+
$iteration = array(
13+
PHPT_ACL_READ => false,
14+
PHPT_ACL_NONE => false,
15+
PHPT_ACL_WRITE => true,
16+
PHPT_ACL_WRITE|PHPT_ACL_READ => true,
17+
);
18+
19+
echo "Testing file:\n";
20+
$i = 1;
21+
$path = __DIR__ . '/a.txt';
22+
foreach ($iteration as $perms => $exp) {
23+
create_file($path, $perms);
24+
echo 'Iteration #' . $i++ . ': ';
25+
if (is_writable($path) == $exp) {
26+
echo "passed.\n";
27+
} else {
28+
var_dump(is_writable($path), $exp);
29+
echo "failed.\n";
30+
}
31+
delete_file($path);
32+
}
33+
34+
echo "Testing directory:\n";
35+
$path = __DIR__ . '/adir';
36+
$i = 1;
37+
foreach ($iteration as $perms => $exp) {
38+
create_file($path, $perms);
39+
echo 'Iteration #' . $i++ . ': ';
40+
if (is_writable($path) == $exp) {
41+
echo "passed.\n";
42+
} else {
43+
var_dump(is_writable($path), $exp);
44+
echo "failed.\n";
45+
}
46+
delete_file($path);
47+
}
48+
49+
?>
50+
--EXPECT--
51+
Testing file:
52+
Iteration #1: passed.
53+
Iteration #2: passed.
54+
Iteration #3: passed.
55+
Iteration #4: passed.
56+
Testing directory:
57+
Iteration #1: passed.
58+
Iteration #2: passed.
59+
Iteration #3: passed.
60+
Iteration #4: passed.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
--TEST--
2+
bug #44859 (incorrect result with NTFS ACL permissions, is_readable)
3+
--SKIPIF--
4+
<?php
5+
include_once __DIR__ . '/common.inc';
6+
skipif();
7+
?>
8+
--FILE--
9+
<?php
10+
include_once __DIR__ . '/common.inc';
11+
12+
$iteration = array(
13+
PHPT_ACL_READ => true,
14+
PHPT_ACL_NONE => false,
15+
PHPT_ACL_WRITE => false,
16+
PHPT_ACL_WRITE|PHPT_ACL_READ => true,
17+
);
18+
19+
echo "Testing file:\n";
20+
$i = 1;
21+
$path = __DIR__ . '/a.txt';
22+
foreach ($iteration as $perms => $exp) {
23+
create_file($path, $perms);
24+
echo 'Iteration #' . $i++ . ': ';
25+
if (is_readable($path) == $exp) {
26+
echo "passed.\n";
27+
} else {
28+
var_dump(is_writable($path), $exp);
29+
echo "failed.\n";
30+
}
31+
delete_file($path);
32+
}
33+
34+
echo "Testing directory:\n";
35+
$path = __DIR__ . '/adir';
36+
$i = 1;
37+
foreach ($iteration as $perms => $exp) {
38+
create_file($path, $perms);
39+
echo 'Iteration #' . $i++ . ': ';
40+
if (is_readable($path) == $exp) {
41+
echo "passed.\n";
42+
} else {
43+
var_dump(is_writable($path), $exp);
44+
echo "failed.\n";
45+
}
46+
delete_file($path);
47+
}
48+
49+
?>
50+
--EXPECT--
51+
Testing file:
52+
Iteration #1: passed.
53+
Iteration #2: passed.
54+
Iteration #3: passed.
55+
Iteration #4: passed.
56+
Testing directory:
57+
Iteration #1: passed.
58+
Iteration #2: passed.
59+
Iteration #3: passed.
60+
Iteration #4: passed.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
bug #44859 (incorrect result with NTFS ACL permissions, is_executable)
3+
--SKIPIF--
4+
<?php
5+
include_once __DIR__ . '/common.inc';
6+
skipif();
7+
?>
8+
--FILE--
9+
<?php
10+
include_once __DIR__ . '/common.inc';
11+
12+
$iteration = array(
13+
'tiny.exe' => true,
14+
//'tiny.bat' => true, To be fixed in _access
15+
__FILE__ => false
16+
);
17+
18+
$i = 1;
19+
$path = __DIR__;
20+
21+
foreach ($iteration as $file => $exp) {
22+
$path = __DIR__ . '/' . $file;
23+
echo 'Iteration #' . $i++ . ': ';
24+
if (is_executable($path) == $exp) {
25+
echo "passed.\n";
26+
} else {
27+
var_dump(is_executable($path), $exp);
28+
echo "failed.\n";
29+
}
30+
}
31+
32+
33+
?>
34+
--EXPECT--
35+
Iteration #1: passed.
36+
Iteration #2: passed.

0 commit comments

Comments
 (0)