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