1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Daniel Beulshausen <daniel@php4win.de> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <io.h>
24 #include <process.h>
25 #include <time.h>
26 #include <errno.h>
27
28 #define TSRM_INCLUDE_FULL_WINDOWS_HEADERS
29 #include "SAPI.h"
30 #include "TSRM.h"
31
32 #ifdef TSRM_WIN32
33 #include <Sddl.h>
34 #include "tsrm_win32.h"
35 #include "zend_virtual_cwd.h"
36 #include "win32/ioutil.h"
37
38 #ifdef ZTS
39 static ts_rsrc_id win32_globals_id;
40 #else
41 static tsrm_win32_globals win32_globals;
42 #endif
43
tsrm_win32_ctor(tsrm_win32_globals * globals)44 static void tsrm_win32_ctor(tsrm_win32_globals *globals)
45 {
46 #ifdef ZTS
47 TSRMLS_CACHE_UPDATE();
48 #endif
49 globals->process = NULL;
50 globals->shm = NULL;
51 globals->process_size = 0;
52 globals->shm_size = 0;
53 globals->comspec = _strdup("cmd.exe");
54
55 /* Set it to INVALID_HANDLE_VALUE
56 * It will be initialized correctly in tsrm_win32_access or set to
57 * NULL if no impersonation has been done.
58 * the impersonated token can't be set here as the impersonation
59 * will happen later, in fcgi_accept_request (or whatever is the
60 * SAPI being used).
61 */
62 globals->impersonation_token = INVALID_HANDLE_VALUE;
63 globals->impersonation_token_sid = NULL;
64 }
65
tsrm_win32_dtor(tsrm_win32_globals * globals)66 static void tsrm_win32_dtor(tsrm_win32_globals *globals)
67 {
68 shm_pair *ptr;
69
70 if (globals->process) {
71 free(globals->process);
72 }
73
74 if (globals->shm) {
75 for (ptr = globals->shm; ptr < (globals->shm + globals->shm_size); ptr++) {
76 UnmapViewOfFile(ptr->addr);
77 CloseHandle(ptr->segment);
78 UnmapViewOfFile(ptr->descriptor);
79 CloseHandle(ptr->info);
80 }
81 free(globals->shm);
82 }
83
84 free(globals->comspec);
85
86 if (globals->impersonation_token && globals->impersonation_token != INVALID_HANDLE_VALUE ) {
87 CloseHandle(globals->impersonation_token);
88 }
89 if (globals->impersonation_token_sid) {
90 free(globals->impersonation_token_sid);
91 }
92 }
93
tsrm_win32_startup(void)94 TSRM_API void tsrm_win32_startup(void)
95 {
96 #ifdef ZTS
97 ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_ctor)tsrm_win32_dtor);
98 #else
99 tsrm_win32_ctor(&win32_globals);
100 #endif
101 }
102
tsrm_win32_shutdown(void)103 TSRM_API void tsrm_win32_shutdown(void)
104 {
105 #ifndef ZTS
106 tsrm_win32_dtor(&win32_globals);
107 #endif
108 }
109
tsrm_win32_get_path_sid_key(const char * pathname)110 char * tsrm_win32_get_path_sid_key(const char *pathname)
111 {
112 PSID pSid = TWG(impersonation_token_sid);
113 TCHAR *ptcSid = NULL;
114 char *bucket_key = NULL;
115 size_t ptc_sid_len, pathname_len;
116
117 pathname_len = strlen(pathname);
118
119 if (!pSid) {
120 bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pathname_len + 1);
121 if (!bucket_key) {
122 return NULL;
123 }
124 memcpy(bucket_key, pathname, pathname_len);
125 return bucket_key;
126 }
127
128 if (!ConvertSidToStringSid(pSid, &ptcSid)) {
129 return NULL;
130 }
131
132
133 ptc_sid_len = strlen(ptcSid);
134 bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pathname_len + ptc_sid_len + 1);
135 if (!bucket_key) {
136 LocalFree(ptcSid);
137 return NULL;
138 }
139
140 memcpy(bucket_key, ptcSid, ptc_sid_len);
141 memcpy(bucket_key + ptc_sid_len, pathname, pathname_len + 1);
142
143 LocalFree(ptcSid);
144 return bucket_key;
145 }
146
147
tsrm_win32_get_token_sid(HANDLE hToken)148 PSID tsrm_win32_get_token_sid(HANDLE hToken)
149 {
150 DWORD dwLength = 0;
151 PTOKEN_USER pTokenUser = NULL;
152 DWORD sid_len;
153 PSID pResultSid = NULL;
154
155 /* Get the actual size of the TokenUser structure */
156 if (!GetTokenInformation(
157 hToken, TokenUser, (LPVOID) pTokenUser, 0, &dwLength)) {
158 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
159 goto Finished;
160 }
161
162 pTokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
163 if (pTokenUser == NULL) {
164 goto Finished;
165 }
166 }
167
168 /* and fetch it now */
169 if (!GetTokenInformation(
170 hToken, TokenUser, (LPVOID) pTokenUser, dwLength, &dwLength)) {
171 goto Finished;
172 }
173
174 sid_len = GetLengthSid(pTokenUser->User.Sid);
175
176 /* ConvertSidToStringSid(pTokenUser->User.Sid, &ptcSidOwner); */
177 pResultSid = malloc(sid_len);
178 if (!pResultSid) {
179 goto Finished;
180 }
181 if (!CopySid(sid_len, pResultSid, pTokenUser->User.Sid)) {
182 goto Finished;
183 }
184 HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
185 return pResultSid;
186
187 Finished:
188 if (pResultSid) {
189 free(pResultSid);
190 }
191 /* Free the buffer for the token groups. */
192 if (pTokenUser != NULL) {
193 HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
194 }
195 return NULL;
196 }
197
tsrm_win32_access(const char * pathname,int mode)198 TSRM_API int tsrm_win32_access(const char *pathname, int mode)
199 {
200 time_t t;
201 HANDLE thread_token = NULL;
202 PSID token_sid;
203 SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
204 GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
205 DWORD priv_set_length = sizeof(PRIVILEGE_SET);
206
207 PRIVILEGE_SET privilege_set = {0};
208 DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0;
209 BYTE * psec_desc = NULL;
210 BOOL fAccess = FALSE;
211 realpath_cache_bucket * bucket = NULL;
212 char * real_path = NULL;
213
214 PHP_WIN32_IOUTIL_INIT_W(pathname)
215 if (!pathw) {
216 return -1;
217 }
218
219 if (mode == 1 /*X_OK*/) {
220 DWORD type;
221 int ret;
222
223 ret = GetBinaryTypeW(pathw, &type) ? 0 : -1;
224
225 PHP_WIN32_IOUTIL_CLEANUP_W()
226
227 return ret;
228 } else {
229 if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
230 real_path = (char *)malloc(MAXPATHLEN);
231 if(tsrm_realpath(pathname, real_path) == NULL) {
232 goto Finished;
233 }
234 pathname = real_path;
235 PHP_WIN32_IOUTIL_REINIT_W(pathname);
236 }
237
238 if(php_win32_ioutil_access(pathname, mode)) {
239 PHP_WIN32_IOUTIL_CLEANUP_W()
240 free(real_path);
241 return errno;
242 }
243
244 /* If only existence check is made, return now */
245 if (mode == 0) {
246 PHP_WIN32_IOUTIL_CLEANUP_W()
247 free(real_path);
248 return 0;
249 }
250
251 /* Only in NTS when impersonate==1 (aka FastCGI) */
252
253 /*
254 AccessCheck() requires an impersonation token. We first get a primary
255 token and then create a duplicate impersonation token. The
256 impersonation token is not actually assigned to the thread, but is
257 used in the call to AccessCheck. Thus, this function itself never
258 impersonates, but does use the identity of the thread. If the thread
259 was impersonating already, this function uses that impersonation context.
260 */
261 if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
262 if (GetLastError() == ERROR_NO_TOKEN) {
263 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
264 TWG(impersonation_token) = NULL;
265 goto Finished;
266 }
267 }
268 }
269
270 /* token_sid will be freed in tsrmwin32_dtor */
271 token_sid = tsrm_win32_get_token_sid(thread_token);
272 if (!token_sid) {
273 if (TWG(impersonation_token_sid)) {
274 free(TWG(impersonation_token_sid));
275 }
276 TWG(impersonation_token_sid) = NULL;
277 goto Finished;
278 }
279
280 /* Different identity, we need a new impersontated token as well */
281 if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) {
282 if (TWG(impersonation_token_sid)) {
283 free(TWG(impersonation_token_sid));
284 }
285 TWG(impersonation_token_sid) = token_sid;
286
287 /* Duplicate the token as impersonated token */
288 if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
289 goto Finished;
290 }
291 } else {
292 /* we already have it, free it then */
293 free(token_sid);
294 }
295
296 if (CWDG(realpath_cache_size_limit)) {
297 t = time(0);
298 bucket = realpath_cache_lookup(pathname, (int)strlen(pathname), t);
299 if(bucket == NULL && real_path == NULL) {
300 /* We used the pathname directly. Call tsrm_realpath */
301 /* so that entry is created in realpath cache */
302 real_path = (char *)malloc(MAXPATHLEN);
303 if(tsrm_realpath(pathname, real_path) != NULL) {
304 pathname = real_path;
305 bucket = realpath_cache_lookup(pathname, (int)strlen(pathname), t);
306 PHP_WIN32_IOUTIL_REINIT_W(pathname);
307 }
308 }
309 }
310
311 /* Do a full access check because access() will only check read-only attribute */
312 if(mode == 0 || mode > 6) {
313 if(bucket != NULL && bucket->is_rvalid) {
314 fAccess = bucket->is_readable;
315 goto Finished;
316 }
317 desired_access = FILE_GENERIC_READ;
318 } else if(mode <= 2) {
319 if(bucket != NULL && bucket->is_wvalid) {
320 fAccess = bucket->is_writable;
321 goto Finished;
322 }
323 desired_access = FILE_GENERIC_WRITE;
324 } else if(mode <= 4) {
325 if(bucket != NULL && bucket->is_rvalid) {
326 fAccess = bucket->is_readable;
327 goto Finished;
328 }
329 desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
330 } else { // if(mode <= 6)
331 if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
332 fAccess = bucket->is_readable & bucket->is_writable;
333 goto Finished;
334 }
335 desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
336 }
337
338 if(TWG(impersonation_token) == NULL) {
339 goto Finished;
340 }
341
342 /* Get size of security buffer. Call is expected to fail */
343 if(GetFileSecurityW(pathw, sec_info, NULL, 0, &sec_desc_length)) {
344 goto Finished;
345 }
346
347 psec_desc = (BYTE *)malloc(sec_desc_length);
348 if(psec_desc == NULL ||
349 !GetFileSecurityW(pathw, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
350 goto Finished;
351 }
352
353 MapGenericMask(&desired_access, &gen_map);
354
355 if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
356 goto Finished_Impersonate;
357 }
358
359 /* Keep the result in realpath_cache */
360 if(bucket != NULL) {
361 if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
362 bucket->is_rvalid = 1;
363 bucket->is_readable = fAccess;
364 }
365 else if(desired_access == FILE_GENERIC_WRITE) {
366 bucket->is_wvalid = 1;
367 bucket->is_writable = fAccess;
368 } else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
369 bucket->is_rvalid = 1;
370 bucket->is_readable = fAccess;
371 bucket->is_wvalid = 1;
372 bucket->is_writable = fAccess;
373 }
374 }
375
376 Finished_Impersonate:
377 if(psec_desc != NULL) {
378 free(psec_desc);
379 psec_desc = NULL;
380 }
381
382 Finished:
383 if(thread_token != NULL) {
384 CloseHandle(thread_token);
385 }
386 if(real_path != NULL) {
387 free(real_path);
388 real_path = NULL;
389 }
390
391 PHP_WIN32_IOUTIL_CLEANUP_W()
392 if(fAccess == FALSE) {
393 errno = EACCES;
394 return errno;
395 } else {
396 return 0;
397 }
398 }
399 }
400
401
process_get(FILE * stream)402 static process_pair *process_get(FILE *stream)
403 {
404 process_pair *ptr;
405 process_pair *newptr;
406
407 for (ptr = TWG(process); ptr < (TWG(process) + TWG(process_size)); ptr++) {
408 if (ptr->stream == stream) {
409 break;
410 }
411 }
412
413 if (ptr < (TWG(process) + TWG(process_size))) {
414 return ptr;
415 }
416
417 newptr = (process_pair*)realloc((void*)TWG(process), (TWG(process_size)+1)*sizeof(process_pair));
418 if (newptr == NULL) {
419 return NULL;
420 }
421
422 TWG(process) = newptr;
423 ptr = newptr + TWG(process_size);
424 TWG(process_size)++;
425 return ptr;
426 }
427
shm_get(int key,void * addr)428 static shm_pair *shm_get(int key, void *addr)
429 {
430 shm_pair *ptr;
431 shm_pair *newptr;
432
433 for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
434 if (!ptr->descriptor) {
435 continue;
436 }
437 if (!addr && ptr->descriptor->shm_perm.key == key) {
438 break;
439 } else if (ptr->addr == addr) {
440 break;
441 }
442 }
443
444 if (ptr < (TWG(shm) + TWG(shm_size))) {
445 return ptr;
446 }
447
448 newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
449 if (newptr == NULL) {
450 return NULL;
451 }
452
453 TWG(shm) = newptr;
454 ptr = newptr + TWG(shm_size);
455 TWG(shm_size)++;
456 memset(ptr, 0, sizeof(*ptr));
457 return ptr;
458 }
459
dupHandle(HANDLE fh,BOOL inherit)460 static HANDLE dupHandle(HANDLE fh, BOOL inherit) {
461 HANDLE copy, self = GetCurrentProcess();
462 if (!DuplicateHandle(self, fh, self, ©, 0, inherit, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
463 return NULL;
464 }
465 return copy;
466 }
467
popen(const char * command,const char * type)468 TSRM_API FILE *popen(const char *command, const char *type)
469 {
470
471 return popen_ex(command, type, NULL, NULL);
472 }
473
popen_ex(const char * command,const char * type,const char * cwd,char * env)474 TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env)
475 {
476 FILE *stream = NULL;
477 int fno, type_len, read, mode;
478 STARTUPINFOW startup;
479 PROCESS_INFORMATION process;
480 SECURITY_ATTRIBUTES security;
481 HANDLE in, out;
482 DWORD dwCreateFlags = 0;
483 BOOL res;
484 process_pair *proc;
485 char *cmd = NULL;
486 wchar_t *cmdw = NULL, *cwdw = NULL, *envw = NULL;
487 int i;
488 char *ptype = (char *)type;
489 HANDLE thread_token = NULL;
490 HANDLE token_user = NULL;
491 BOOL asuser = TRUE;
492
493 if (!type) {
494 return NULL;
495 }
496
497 /*The following two checks can be removed once we drop XP support */
498 type_len = (int)strlen(type);
499 if (type_len <1 || type_len > 2) {
500 return NULL;
501 }
502
503 for (i=0; i < type_len; i++) {
504 if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) {
505 return NULL;
506 }
507 ptype++;
508 }
509
510 cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
511 if (!cmd) {
512 return NULL;
513 }
514
515 sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);
516 cmdw = php_win32_cp_any_to_w(cmd);
517 if (!cmdw) {
518 free(cmd);
519 return NULL;
520 }
521
522 if (cwd) {
523 cwdw = php_win32_ioutil_any_to_w(cwd);
524 if (!cwdw) {
525 free(cmd);
526 free(cmdw);
527 return NULL;
528 }
529 }
530
531 security.nLength = sizeof(SECURITY_ATTRIBUTES);
532 security.bInheritHandle = TRUE;
533 security.lpSecurityDescriptor = NULL;
534
535 if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
536 free(cmdw);
537 free(cwdw);
538 free(cmd);
539 return NULL;
540 }
541
542 memset(&startup, 0, sizeof(STARTUPINFOW));
543 memset(&process, 0, sizeof(PROCESS_INFORMATION));
544
545 startup.cb = sizeof(STARTUPINFOW);
546 startup.dwFlags = STARTF_USESTDHANDLES;
547 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
548
549 read = (type[0] == 'r') ? TRUE : FALSE;
550 mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
551
552 if (read) {
553 in = dupHandle(in, FALSE);
554 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
555 startup.hStdOutput = out;
556 } else {
557 out = dupHandle(out, FALSE);
558 startup.hStdInput = in;
559 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
560 }
561
562 dwCreateFlags = NORMAL_PRIORITY_CLASS;
563 if (strcmp(sapi_module.name, "cli") != 0) {
564 dwCreateFlags |= CREATE_NO_WINDOW;
565 }
566
567 /* Get a token with the impersonated user. */
568 if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
569 DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
570 } else {
571 DWORD err = GetLastError();
572 if (err == ERROR_NO_TOKEN) {
573 asuser = FALSE;
574 }
575 }
576
577 envw = php_win32_cp_env_any_to_w(env);
578 if (envw) {
579 dwCreateFlags |= CREATE_UNICODE_ENVIRONMENT;
580 } else {
581 if (env) {
582 free(cmd);
583 free(cmdw);
584 free(cwdw);
585 return NULL;
586 }
587 }
588
589 if (asuser) {
590 res = CreateProcessAsUserW(token_user, NULL, cmdw, &security, &security, security.bInheritHandle, dwCreateFlags, envw, cwdw, &startup, &process);
591 CloseHandle(token_user);
592 } else {
593 res = CreateProcessW(NULL, cmdw, &security, &security, security.bInheritHandle, dwCreateFlags, envw, cwdw, &startup, &process);
594 }
595 free(cmd);
596 free(cmdw);
597 free(cwdw);
598 free(envw);
599
600 if (!res) {
601 return NULL;
602 }
603
604 CloseHandle(process.hThread);
605 proc = process_get(NULL);
606
607 if (read) {
608 fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
609 CloseHandle(out);
610 } else {
611 fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
612 CloseHandle(in);
613 }
614
615 stream = _fdopen(fno, type);
616 proc->prochnd = process.hProcess;
617 proc->stream = stream;
618 return stream;
619 }
620
pclose(FILE * stream)621 TSRM_API int pclose(FILE *stream)
622 {
623 DWORD termstat = 0;
624 process_pair *process;
625
626 if ((process = process_get(stream)) == NULL) {
627 return 0;
628 }
629
630 fflush(process->stream);
631 fclose(process->stream);
632
633 WaitForSingleObject(process->prochnd, INFINITE);
634 GetExitCodeProcess(process->prochnd, &termstat);
635 process->stream = NULL;
636 CloseHandle(process->prochnd);
637
638 return termstat;
639 }
640
shmget(int key,int size,int flags)641 TSRM_API int shmget(int key, int size, int flags)
642 {
643 shm_pair *shm;
644 char shm_segment[26], shm_info[29];
645 HANDLE shm_handle, info_handle;
646 BOOL created = FALSE;
647
648 if (size < 0) {
649 return -1;
650 }
651
652 snprintf(shm_segment, sizeof(shm_segment), "TSRM_SHM_SEGMENT:%d", key);
653 snprintf(shm_info, sizeof(shm_info), "TSRM_SHM_DESCRIPTOR:%d", key);
654
655 shm_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment);
656 info_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_info);
657
658 if (!shm_handle && !info_handle) {
659 if (flags & IPC_CREAT) {
660 shm_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, shm_segment);
661 info_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shm->descriptor), shm_info);
662 created = TRUE;
663 }
664 if (!shm_handle || !info_handle) {
665 if (shm_handle) {
666 CloseHandle(shm_handle);
667 }
668 if (info_handle) {
669 CloseHandle(info_handle);
670 }
671 return -1;
672 }
673 } else {
674 if (flags & IPC_EXCL) {
675 if (shm_handle) {
676 CloseHandle(shm_handle);
677 }
678 if (info_handle) {
679 CloseHandle(info_handle);
680 }
681 return -1;
682 }
683 }
684
685 shm = shm_get(key, NULL);
686 if (!shm) {
687 CloseHandle(shm_handle);
688 CloseHandle(info_handle);
689 return -1;
690 }
691 shm->segment = shm_handle;
692 shm->info = info_handle;
693 shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
694
695 if (NULL != shm->descriptor && created) {
696 shm->descriptor->shm_perm.key = key;
697 shm->descriptor->shm_segsz = size;
698 shm->descriptor->shm_ctime = time(NULL);
699 shm->descriptor->shm_cpid = getpid();
700 shm->descriptor->shm_perm.mode = flags;
701
702 shm->descriptor->shm_perm.cuid = shm->descriptor->shm_perm.cgid= 0;
703 shm->descriptor->shm_perm.gid = shm->descriptor->shm_perm.uid = 0;
704 shm->descriptor->shm_atime = shm->descriptor->shm_dtime = 0;
705 shm->descriptor->shm_lpid = shm->descriptor->shm_nattch = 0;
706 shm->descriptor->shm_perm.mode = shm->descriptor->shm_perm.seq = 0;
707 }
708
709 if (NULL != shm->descriptor && (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz)) {
710 if (NULL != shm->segment) {
711 CloseHandle(shm->segment);
712 }
713 UnmapViewOfFile(shm->descriptor);
714 CloseHandle(shm->info);
715 return -1;
716 }
717
718 return key;
719 }
720
shmat(int key,const void * shmaddr,int flags)721 TSRM_API void *shmat(int key, const void *shmaddr, int flags)
722 {
723 shm_pair *shm = shm_get(key, NULL);
724
725 if (!shm->segment) {
726 return (void*)-1;
727 }
728
729 shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
730
731 if (NULL == shm->addr) {
732 int err = GetLastError();
733 SET_ERRNO_FROM_WIN32_CODE(err);
734 return (void*)-1;
735 }
736
737 shm->descriptor->shm_atime = time(NULL);
738 shm->descriptor->shm_lpid = getpid();
739 shm->descriptor->shm_nattch++;
740
741 return shm->addr;
742 }
743
shmdt(const void * shmaddr)744 TSRM_API int shmdt(const void *shmaddr)
745 {
746 shm_pair *shm = shm_get(0, (void*)shmaddr);
747
748 if (!shm->segment) {
749 return -1;
750 }
751
752 shm->descriptor->shm_dtime = time(NULL);
753 shm->descriptor->shm_lpid = getpid();
754 shm->descriptor->shm_nattch--;
755
756 return UnmapViewOfFile(shm->addr) ? 0 : -1;
757 }
758
shmctl(int key,int cmd,struct shmid_ds * buf)759 TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) {
760 shm_pair *shm = shm_get(key, NULL);
761
762 if (!shm->segment) {
763 return -1;
764 }
765
766 switch (cmd) {
767 case IPC_STAT:
768 memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
769 return 0;
770
771 case IPC_SET:
772 shm->descriptor->shm_ctime = time(NULL);
773 shm->descriptor->shm_perm.uid = buf->shm_perm.uid;
774 shm->descriptor->shm_perm.gid = buf->shm_perm.gid;
775 shm->descriptor->shm_perm.mode = buf->shm_perm.mode;
776 return 0;
777
778 case IPC_RMID:
779 if (shm->descriptor->shm_nattch < 1) {
780 shm->descriptor->shm_perm.key = -1;
781 }
782 return 0;
783
784 default:
785 return -1;
786 }
787 }
788
realpath(char * orig_path,char * buffer)789 TSRM_API char *realpath(char *orig_path, char *buffer)
790 {
791 int ret = GetFullPathName(orig_path, _MAX_PATH, buffer, NULL);
792 if(!ret || ret > _MAX_PATH) {
793 return NULL;
794 }
795 return buffer;
796 }
797
798 #if HAVE_UTIME
UnixTimeToFileTime(time_t t,LPFILETIME pft)799 static zend_always_inline void UnixTimeToFileTime(time_t t, LPFILETIME pft) /* {{{ */
800 {
801 // Note that LONGLONG is a 64-bit value
802 LONGLONG ll;
803
804 ll = Int32x32To64(t, 10000000) + 116444736000000000;
805 pft->dwLowDateTime = (DWORD)ll;
806 pft->dwHighDateTime = ll >> 32;
807 }
808 /* }}} */
809
win32_utime(const char * filename,struct utimbuf * buf)810 TSRM_API int win32_utime(const char *filename, struct utimbuf *buf) /* {{{ */
811 {
812 FILETIME mtime, atime;
813 HANDLE hFile;
814 PHP_WIN32_IOUTIL_INIT_W(filename)
815
816 if (!pathw) {
817 return -1;
818 }
819
820 hFile = CreateFileW(pathw, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL,
821 OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
822
823 PHP_WIN32_IOUTIL_CLEANUP_W()
824
825 /* OPEN_ALWAYS mode sets the last error to ERROR_ALREADY_EXISTS but
826 the CreateFile operation succeeds */
827 if (GetLastError() == ERROR_ALREADY_EXISTS) {
828 SetLastError(0);
829 }
830
831 if ( hFile == INVALID_HANDLE_VALUE ) {
832 return -1;
833 }
834
835 if (!buf) {
836 SYSTEMTIME st;
837 GetSystemTime(&st);
838 SystemTimeToFileTime(&st, &mtime);
839 atime = mtime;
840 } else {
841 UnixTimeToFileTime(buf->modtime, &mtime);
842 UnixTimeToFileTime(buf->actime, &atime);
843 }
844 if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
845 CloseHandle(hFile);
846 return -1;
847 }
848 CloseHandle(hFile);
849 return 1;
850 }
851 /* }}} */
852 #endif
853 #endif
854