php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
winutil.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Zeev Suraski <zeev@php.net> |
14 * Pierre Joye <pierre@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18#include "php.h"
19#include "winutil.h"
20#include "codepage.h"
21#include <bcrypt.h>
22#include <lmcons.h>
23
24
26{/*{{{*/
27 wchar_t *bufw = NULL, *pw;
28 char *buf;
29
30 DWORD ret = FormatMessageW(
31 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
32 NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (LPWSTR)&bufw, 0, NULL
33 );
34
35 if (!ret || !bufw) {
36 return "";
37 }
38
39 /* strip trailing line breaks and periods */
40 for (pw = bufw + wcslen(bufw) - 1; pw >= bufw && (*pw == L'\r' || *pw == L'\n' || *pw == L'.'); pw--);
41 pw[1] = L'\0';
42
43 buf = php_win32_cp_conv_w_to_any(bufw, ret, PHP_WIN32_CP_IGNORE_LEN_P);
44
45 LocalFree(bufw);
46
47 return (buf ? buf : "");
48}/*}}}*/
49
51{/*{{{*/
52 if (msg && msg[0]) {
53 free(msg);
54 }
55}/*}}}*/
56
57int php_win32_check_trailing_space(const char * path, const size_t path_len)
58{/*{{{*/
59 if (path_len == 0 || path_len > MAXPATHLEN - 1) {
60 return 1;
61 }
62 if (path) {
63 if (path[0] == ' ' || path[path_len - 1] == ' ') {
64 return 0;
65 } else {
66 return 1;
67 }
68 } else {
69 return 0;
70 }
71}/*}}}*/
72
73static BCRYPT_ALG_HANDLE bcrypt_algo;
74static BOOL has_bcrypt_algo = 0;
75
76#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
77
78#ifdef PHP_EXPORTS
79BOOL php_win32_shutdown_random_bytes(void)
80{/*{{{*/
81 BOOL ret = TRUE;
82
83 if (has_bcrypt_algo) {
84 ret = NT_SUCCESS(BCryptCloseAlgorithmProvider(bcrypt_algo, 0));
85 has_bcrypt_algo = 0;
86 }
87
88 return ret;
89}/*}}}*/
90
91BOOL php_win32_init_random_bytes(void)
92{/*{{{*/
93 if (has_bcrypt_algo) {
94 return TRUE;
95 }
96
97 has_bcrypt_algo = NT_SUCCESS(BCryptOpenAlgorithmProvider(&bcrypt_algo, BCRYPT_RNG_ALGORITHM, NULL, 0));
98
99 return has_bcrypt_algo;
100}/*}}}*/
101#endif
102
104{ /* {{{ */
105
106 BOOL ret;
107
108#if 0
109 /* Currently we fail on startup, with CNG API it shows no regressions so far and is secure.
110 Should switch on and try to reinit, if it fails too often on startup. This means also
111 bringing locks back. */
112 if (has_bcrypt_algo == 0) {
113 return FAILURE;
114 }
115#endif
116
117 /* No sense to loop here, the limit is huge enough. */
118 ret = NT_SUCCESS(BCryptGenRandom(bcrypt_algo, buf, (ULONG)size, 0));
119
120 return ret ? SUCCESS : FAILURE;
121}
122/* }}} */
123
124
125/*
126* This functions based on the code from the UNIXem project under
127* the BSD like license. Modified for PHP by ab@php.net
128*
129* Home: http://synesis.com.au/software/
130*
131* Copyright (c) 2005-2010, Matthew Wilson and Synesis Software
132*/
133
135{/*{{{*/
136 size_t i;
137
138 struct code_to_errno_map
139 {
140 unsigned long w32Err;
141 int eerrno;
142 };
143
144 static const struct code_to_errno_map errmap[] =
145 {
146 /* 1 */ { ERROR_INVALID_FUNCTION , EINVAL }
147 /* 2 */ , { ERROR_FILE_NOT_FOUND , ENOENT }
148 /* 3 */ , { ERROR_PATH_NOT_FOUND , ENOENT }
149 /* 4 */ , { ERROR_TOO_MANY_OPEN_FILES , EMFILE }
150 /* 5 */ , { ERROR_ACCESS_DENIED , EACCES }
151 /* 6 */ , { ERROR_INVALID_HANDLE , EBADF }
152 /* 7 */ , { ERROR_ARENA_TRASHED , ENOMEM }
153 /* 8 */ , { ERROR_NOT_ENOUGH_MEMORY , ENOMEM }
154 /* 9 */ , { ERROR_INVALID_BLOCK , ENOMEM }
155 /* 10 */ , { ERROR_BAD_ENVIRONMENT , E2BIG }
156 /* 11 */ , { ERROR_BAD_FORMAT , ENOEXEC }
157 /* 12 */ , { ERROR_INVALID_ACCESS , EINVAL }
158 /* 13 */ , { ERROR_INVALID_DATA , EINVAL }
159 /* 14 */ , { ERROR_OUTOFMEMORY , ENOMEM }
160 /* 15 */ , { ERROR_INVALID_DRIVE , ENOENT }
161 /* 16 */ , { ERROR_CURRENT_DIRECTORY , ECURDIR }
162 /* 17 */ , { ERROR_NOT_SAME_DEVICE , EXDEV }
163 /* 18 */ , { ERROR_NO_MORE_FILES , ENOENT }
164 /* 19 */ , { ERROR_WRITE_PROTECT , EROFS }
165 /* 20 */ , { ERROR_BAD_UNIT , ENXIO }
166 /* 21 */ , { ERROR_NOT_READY , EBUSY }
167 /* 22 */ , { ERROR_BAD_COMMAND , EIO }
168 /* 23 */ , { ERROR_CRC , EIO }
169 /* 24 */ , { ERROR_BAD_LENGTH , EIO }
170 /* 25 */ , { ERROR_SEEK , EIO }
171 /* 26 */ , { ERROR_NOT_DOS_DISK , EIO }
172 /* 27 */ , { ERROR_SECTOR_NOT_FOUND , ENXIO }
173 /* 28 */ , { ERROR_OUT_OF_PAPER , EBUSY }
174 /* 29 */ , { ERROR_WRITE_FAULT , EIO }
175 /* 30 */ , { ERROR_READ_FAULT , EIO }
176 /* 31 */ , { ERROR_GEN_FAILURE , EIO }
177 /* 32 */ , { ERROR_SHARING_VIOLATION , EAGAIN }
178 /* 33 */ , { ERROR_LOCK_VIOLATION , EACCES }
179 /* 34 */ , { ERROR_WRONG_DISK , ENXIO }
180 /* 35 */ , { 35 , ENFILE }
181 /* 36 */ , { ERROR_SHARING_BUFFER_EXCEEDED , ENFILE }
182 /* 37 */ , { ERROR_HANDLE_EOF , EINVAL }
183 /* 38 */ , { ERROR_HANDLE_DISK_FULL , ENOSPC }
184#if 0
185 /* 39 */ , { 0 , 0 }
186 /* 40 */ , { 0 , 0 }
187 /* 41 */ , { 0 , 0 }
188 /* 42 */ , { 0 , 0 }
189 /* 43 */ , { 0 , 0 }
190 /* 44 */ , { 0 , 0 }
191 /* 45 */ , { 0 , 0 }
192 /* 46 */ , { 0 , 0 }
193 /* 47 */ , { 0 , 0 }
194 /* 48 */ , { 0 , 0 }
195 /* 49 */ , { 0 , 0 }
196#endif
197 /* 50 */ , { ERROR_NOT_SUPPORTED , ENOSYS }
198#if 0
199 /* 51 */ , { 0 , 0 }
200 /* 52 */ , { 0 , 0 }
201#endif
202 /* 53 */ , { ERROR_BAD_NETPATH , ENOENT }
203#if 0
204 /* 54 */ , { 0 , 0 }
205 /* 55 */ , { 0 , 0 }
206 /* 56 */ , { 0 , 0 }
207 /* 57 */ , { 0 , 0 }
208 /* 58 */ , { 0 , 0 }
209 /* 59 */ , { 0 , 0 }
210 /* 60 */ , { 0 , 0 }
211 /* 61 */ , { 0 , 0 }
212 /* 62 */ , { 0 , 0 }
213 /* 63 */ , { 0 , 0 }
214 /* 64 */ , { 0 , 0 }
215#endif
216 /* 65 */ , { ERROR_NETWORK_ACCESS_DENIED , EACCES }
217#if 0
218 /* 66 */ , { 0 , 0 }
219#endif
220 /* 67 */ , { ERROR_BAD_NET_NAME , ENOENT }
221#if 0
222 /* 68 */ , { 0 , 0 }
223 /* 69 */ , { 0 , 0 }
224 /* 70 */ , { 0 , 0 }
225 /* 71 */ , { 0 , 0 }
226 /* 72 */ , { 0 , 0 }
227 /* 73 */ , { 0 , 0 }
228 /* 74 */ , { 0 , 0 }
229 /* 75 */ , { 0 , 0 }
230 /* 76 */ , { 0 , 0 }
231 /* 77 */ , { 0 , 0 }
232 /* 78 */ , { 0 , 0 }
233 /* 79 */ , { 0 , 0 }
234#endif
235 /* 80 */ , { ERROR_FILE_EXISTS , EEXIST }
236#if 0
237 /* 81 */ , { 0 , 0 }
238#endif
239 /* 82 */ , { ERROR_CANNOT_MAKE , EACCES }
240 /* 83 */ , { ERROR_FAIL_I24 , EACCES }
241#if 0
242 /* 84 */ , { 0 , 0 }
243 /* 85 */ , { 0 , 0 }
244 /* 86 */ , { 0 , 0 }
245#endif
246 /* 87 */ , { ERROR_INVALID_PARAMETER , EINVAL }
247#if 0
248 /* 88 */ , { 0 , 0 }
249#endif
250 /* 89 */ , { ERROR_NO_PROC_SLOTS , EAGAIN }
251#if 0
252 /* 90 */ , { 0 , 0 }
253 /* 91 */ , { 0 , 0 }
254 /* 92 */ , { 0 , 0 }
255 /* 93 */ , { 0 , 0 }
256 /* 94 */ , { 0 , 0 }
257 /* 95 */ , { 0 , 0 }
258 /* 96 */ , { 0 , 0 }
259 /* 97 */ , { 0 , 0 }
260 /* 98 */ , { 0 , 0 }
261 /* 99 */ , { 0 , 0 }
262 /* 100 */ , { 0 , 0 }
263 /* 101 */ , { 0 , 0 }
264 /* 102 */ , { 0 , 0 }
265 /* 103 */ , { 0 , 0 }
266 /* 104 */ , { 0 , 0 }
267 /* 105 */ , { 0 , 0 }
268 /* 106 */ , { 0 , 0 }
269 /* 107 */ , { 0 , 0 }
270#endif
271 /* 108 */ , { ERROR_DRIVE_LOCKED , EACCES }
272 /* 109 */ , { ERROR_BROKEN_PIPE , EPIPE }
273#if 0
274 /* 110 */ , { 0 , 0 }
275#endif
276 /* 111 */ , { ERROR_BUFFER_OVERFLOW , ENAMETOOLONG }
277 /* 112 */ , { ERROR_DISK_FULL , ENOSPC }
278#if 0
279 /* 113 */ , { 0 , 0 }
280#endif
281 /* 114 */ , { ERROR_INVALID_TARGET_HANDLE , EBADF }
282#if 0
283 /* 115 */ , { 0 , 0 }
284 /* 116 */ , { 0 , 0 }
285 /* 117 */ , { 0 , 0 }
286 /* 118 */ , { 0 , 0 }
287 /* 119 */ , { 0 , 0 }
288 /* 120 */ , { 0 , 0 }
289 /* 121 */ , { 0 , 0 }
290#endif
291 /* 122 */ , { ERROR_INSUFFICIENT_BUFFER , ERANGE }
292 /* 123 */ , { ERROR_INVALID_NAME , ENOENT }
293 /* 124 */ , { ERROR_INVALID_HANDLE , EINVAL }
294#if 0
295 /* 125 */ , { 0 , 0 }
296#endif
297 /* 126 */ , { ERROR_MOD_NOT_FOUND , ENOENT }
298 /* 127 */ , { ERROR_PROC_NOT_FOUND , ENOENT }
299 /* 128 */ , { ERROR_WAIT_NO_CHILDREN , ECHILD }
300 /* 129 */ , { ERROR_CHILD_NOT_COMPLETE , ECHILD }
301 /* 130 */ , { ERROR_DIRECT_ACCESS_HANDLE , EBADF }
302 /* 131 */ , { ERROR_NEGATIVE_SEEK , EINVAL }
303 /* 132 */ , { ERROR_SEEK_ON_DEVICE , EACCES }
304#if 0
305 /* 133 */ , { 0 , 0 }
306 /* 134 */ , { 0 , 0 }
307 /* 135 */ , { 0 , 0 }
308 /* 136 */ , { 0 , 0 }
309 /* 137 */ , { 0 , 0 }
310 /* 138 */ , { 0 , 0 }
311 /* 139 */ , { 0 , 0 }
312 /* 140 */ , { 0 , 0 }
313 /* 141 */ , { 0 , 0 }
314 /* 142 */ , { 0 , 0 }
315 /* 143 */ , { 0 , 0 }
316 /* 144 */ , { 0 , 0 }
317#endif
318 /* 145 */ , { ERROR_DIR_NOT_EMPTY , ENOTEMPTY }
319#if 0
320 /* 146 */ , { 0 , 0 }
321 /* 147 */ , { 0 , 0 }
322 /* 148 */ , { 0 , 0 }
323 /* 149 */ , { 0 , 0 }
324 /* 150 */ , { 0 , 0 }
325 /* 151 */ , { 0 , 0 }
326 /* 152 */ , { 0 , 0 }
327 /* 153 */ , { 0 , 0 }
328 /* 154 */ , { 0 , 0 }
329 /* 155 */ , { 0 , 0 }
330 /* 156 */ , { 0 , 0 }
331 /* 157 */ , { 0 , 0 }
332#endif
333 /* 158 */ , { ERROR_NOT_LOCKED , EACCES }
334#if 0
335 /* 159 */ , { 0 , 0 }
336 /* 160 */ , { 0 , 0 }
337#endif
338 /* 161 */ , { ERROR_BAD_PATHNAME , ENOENT }
339#if 0
340 /* 162 */ , { 0 , 0 }
341 /* 163 */ , { 0 , 0 }
342#endif
343 /* 164 */ , { ERROR_MAX_THRDS_REACHED , EAGAIN }
344#if 0
345 /* 165 */ , { 0 , 0 }
346 /* 166 */ , { 0 , 0 }
347#endif
348 /* 167 */ , { ERROR_LOCK_FAILED , EACCES }
349#if 0
350 /* 168 */ , { 0 , 0 }
351 /* 169 */ , { 0 , 0 }
352 /* 170 */ , { 0 , 0 }
353 /* 171 */ , { 0 , 0 }
354 /* 172 */ , { 0 , 0 }
355 /* 173 */ , { 0 , 0 }
356 /* 174 */ , { 0 , 0 }
357 /* 175 */ , { 0 , 0 }
358 /* 176 */ , { 0 , 0 }
359 /* 177 */ , { 0 , 0 }
360 /* 178 */ , { 0 , 0 }
361 /* 179 */ , { 0 , 0 }
362 /* 180 */ , { 0 , 0 }
363 /* 181 */ , { 0 , 0 }
364 /* 182 */ , { 0 , 0 }
365#endif
366 /* 183 */ , { ERROR_ALREADY_EXISTS , EEXIST }
367#if 0
368 /* 184 */ , { 0 , 0 }
369 /* 185 */ , { 0 , 0 }
370 /* 186 */ , { 0 , 0 }
371 /* 187 */ , { 0 , 0 }
372 /* 188 */ , { 0 , 0 }
373 /* 189 */ , { 0 , 0 }
374 /* 190 */ , { 0 , 0 }
375 /* 191 */ , { 0 , 0 }
376 /* 192 */ , { 0 , 0 }
377 /* 193 */ , { 0 , 0 }
378 /* 194 */ , { 0 , 0 }
379 /* 195 */ , { 0 , 0 }
380 /* 196 */ , { 0 , 0 }
381 /* 197 */ , { 0 , 0 }
382 /* 198 */ , { 0 , 0 }
383 /* 199 */ , { 0 , 0 }
384#endif
385
386 /* 206 */ , { ERROR_FILENAME_EXCED_RANGE , ENAMETOOLONG }
387
388 /* 215 */ , { ERROR_NESTING_NOT_ALLOWED , EAGAIN }
389 /* 258 */ , { WAIT_TIMEOUT, ETIME}
390
391 /* 267 */ , { ERROR_DIRECTORY , ENOTDIR }
392 /* 336 */ , { ERROR_DIRECTORY_NOT_SUPPORTED , EISDIR }
393
394 /* 996 */ , { ERROR_IO_INCOMPLETE , EAGAIN }
395 /* 997 */ , { ERROR_IO_PENDING , EAGAIN }
396
397 /* 1004 */ , { ERROR_INVALID_FLAGS , EINVAL }
398 /* 1113 */ , { ERROR_NO_UNICODE_TRANSLATION , EINVAL }
399 /* 1168 */ , { ERROR_NOT_FOUND , ENOENT }
400 /* 1224 */ , { ERROR_USER_MAPPED_FILE , EACCES }
401 /* 1314 */ , { ERROR_PRIVILEGE_NOT_HELD , EACCES }
402 /* 1816 */ , { ERROR_NOT_ENOUGH_QUOTA , ENOMEM }
403 , { ERROR_ABANDONED_WAIT_0 , EIO }
404 /* 1464 */ , { ERROR_SYMLINK_NOT_SUPPORTED , EINVAL }
405 /* 4390 */ , { ERROR_NOT_A_REPARSE_POINT , EINVAL }
406 };
407
408 for(i = 0; i < sizeof(errmap)/sizeof(struct code_to_errno_map); ++i)
409 {
410 if(w32Err == errmap[i].w32Err)
411 {
412 return errmap[i].eerrno;
413 }
414 }
415
416 assert(!"Unrecognised value");
417
418 return EINVAL;
419}/*}}}*/
420
422{/*{{{*/
423 wchar_t unamew[UNLEN + 1];
424 size_t uname_len;
425 char *uname;
426 DWORD unsize = UNLEN;
427
428 GetUserNameW(unamew, &unsize);
429 uname = php_win32_cp_conv_w_to_any(unamew, unsize - 1, &uname_len);
430 if (!uname) {
431 return NULL;
432 }
433
434 /* Ensure the length doesn't overflow. */
435 if (uname_len > UNLEN) {
436 uname[uname_len] = '\0';
437 }
438
439 return uname;
440}/*}}}*/
441
442static zend_always_inline BOOL is_compatible(HMODULE handle, BOOL is_smaller, char *format, char **err)
443{/*{{{*/
444 PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER) handle;
445 PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((char *) dosHeader + dosHeader->e_lfanew);
446
447 DWORD major = pNTHeader->OptionalHeader.MajorLinkerVersion;
448 DWORD minor = pNTHeader->OptionalHeader.MinorLinkerVersion;
449
450#if PHP_LINKER_MAJOR == 14
451 /* VS 2015, 2017, 2019 and 2022 are binary compatible, but only forward compatible.
452 It should be fine, if we load a module linked with an older one into
453 the core linked with the newer one, but not the otherway round.
454 Analogously, it should be fine, if a PHP build linked with an older version
455 is used with a newer CRT, but not the other way round.
456 Otherwise, if the linker major version is not same, it is an error, as
457 per the current knowledge.
458
459 This check is to be extended as new VS versions come out. */
460 DWORD core_minor = (DWORD)(PHP_LINKER_MINOR/10);
461 DWORD comp_minor = (DWORD)(minor/10);
462 if (14 == major && (is_smaller ? core_minor < comp_minor : core_minor > comp_minor) || PHP_LINKER_MAJOR != major)
463#else
464 if (PHP_LINKER_MAJOR != major)
465#endif
466 {
467 char buf[MAX_PATH];
468 if (GetModuleFileName(handle, buf, sizeof(buf)) != 0) {
469 spprintf(err, 0, format, buf, major, minor, PHP_LINKER_MAJOR, PHP_LINKER_MINOR);
470 } else {
471 spprintf(err, 0, "Can't retrieve the module name (error %u)", GetLastError());
472 }
473 return FALSE;
474 }
475
476 return TRUE;
477}/*}}}*/
478
480{/*{{{*/
481 return is_compatible(handle, TRUE, "Can't load module '%s' as it's linked with %u.%u, but the core is linked with %d.%d", err);
482}/*}}}*/
483
484/* Expect a CRT module handle */
486{/*{{{*/
487#if PHP_LINKER_MAJOR == 14
488 /* Extend for other CRT if needed. */
489# if PHP_DEBUG
490 const char *crt_name = "vcruntime140d.dll";
491# else
492 const char *crt_name = "vcruntime140.dll";
493# endif
494 HMODULE handle = GetModuleHandle(crt_name);
495 if (handle == NULL) {
496 spprintf(err, 0, "Can't get handle of module %s (error %u)", crt_name, GetLastError());
497 return FALSE;
498 }
499 return is_compatible(handle, FALSE, "'%s' %u.%u is not compatible with this PHP build linked with %d.%d", err);
500#endif
501 return TRUE;
502}/*}}}*/
assert(mixed $assertion, Throwable|string|null $description=null)
#define PHP_WIN32_CP_IGNORE_LEN_P
Definition codepage.h:31
#define PHP_WINUTIL_API
Definition console.h:24
#define DWORD
Definition exif.c:1762
error($message)
Definition ext_skel.php:22
DL_HANDLE handle
Definition ffi.c:3028
new_type size
Definition ffi.c:4365
char * err
Definition ffi.c:3029
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
#define minor(dev)
Definition fsmagic.c:66
#define major(dev)
Definition fsmagic.c:65
#define TRUE
Definition gd_gd.c:7
#define FALSE
Definition gd_gd.c:8
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
int BOOL
char * msg
Definition phpdbg.h:289
#define spprintf
Definition spprintf.h:29
#define ENAMETOOLONG
#define ENOTEMPTY
#define EAGAIN
PHP_WINUTIL_API char * php_win32_error_to_msg(HRESULT error)
Definition winutil.c:25
PHP_WINUTIL_API BOOL php_win32_crt_compatible(char **err)
Definition winutil.c:485
PHP_WINUTIL_API char * php_win32_get_username(void)
Definition winutil.c:421
PHP_WINUTIL_API int php_win32_get_random_bytes(unsigned char *buf, size_t size)
Definition winutil.c:103
PHP_WINUTIL_API int php_win32_code_to_errno(unsigned long w32Err)
Definition winutil.c:134
int php_win32_check_trailing_space(const char *path, const size_t path_len)
Definition winutil.c:57
PHP_WINUTIL_API BOOL php_win32_image_compatible(HMODULE handle, char **err)
Definition winutil.c:479
#define NT_SUCCESS(Status)
Definition winutil.c:76
PHP_WINUTIL_API void php_win32_error_msg_free(char *msg)
Definition winutil.c:50
#define ENOSYS
Definition winutil.h:42
#define ECURDIR
Definition winutil.h:39
#define zend_always_inline
@ FAILURE
Definition zend_types.h:61
#define MAXPATHLEN
zval * ret