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