1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2016 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 TSRMLS_DC)43 static void tsrm_win32_ctor(tsrm_win32_globals *globals TSRMLS_DC)
44 {
45 globals->process = NULL;
46 globals->shm = NULL;
47 globals->process_size = 0;
48 globals->shm_size = 0;
49 globals->comspec = _strdup((GetVersion()<0x80000000)?"cmd.exe":"command.com");
50
51 /* Set it to INVALID_HANDLE_VALUE
52 * It will be initialized correctly in tsrm_win32_access or set to
53 * NULL if no impersonation has been done.
54 * the impersonated token can't be set here as the impersonation
55 * will happen later, in fcgi_accept_request (or whatever is the
56 * SAPI being used).
57 */
58 globals->impersonation_token = INVALID_HANDLE_VALUE;
59 globals->impersonation_token_sid = NULL;
60 }
61
tsrm_win32_dtor(tsrm_win32_globals * globals TSRMLS_DC)62 static void tsrm_win32_dtor(tsrm_win32_globals *globals TSRMLS_DC)
63 {
64 shm_pair *ptr;
65
66 if (globals->process) {
67 free(globals->process);
68 }
69
70 if (globals->shm) {
71 for (ptr = globals->shm; ptr < (globals->shm + globals->shm_size); ptr++) {
72 UnmapViewOfFile(ptr->addr);
73 CloseHandle(ptr->segment);
74 UnmapViewOfFile(ptr->descriptor);
75 CloseHandle(ptr->info);
76 }
77 free(globals->shm);
78 }
79
80 free(globals->comspec);
81
82 if (globals->impersonation_token && globals->impersonation_token != INVALID_HANDLE_VALUE ) {
83 CloseHandle(globals->impersonation_token);
84 }
85 if (globals->impersonation_token_sid) {
86 free(globals->impersonation_token_sid);
87 }
88 }
89
tsrm_win32_startup(void)90 TSRM_API void tsrm_win32_startup(void)
91 {
92 #ifdef ZTS
93 ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_ctor)tsrm_win32_dtor);
94 #else
95 tsrm_win32_ctor(&win32_globals TSRMLS_CC);
96 #endif
97 }
98
tsrm_win32_shutdown(void)99 TSRM_API void tsrm_win32_shutdown(void)
100 {
101 #ifndef ZTS
102 tsrm_win32_dtor(&win32_globals TSRMLS_CC);
103 #endif
104 }
105
tsrm_win32_get_path_sid_key(const char * pathname TSRMLS_DC)106 char * tsrm_win32_get_path_sid_key(const char *pathname TSRMLS_DC)
107 {
108 PSID pSid = TWG(impersonation_token_sid);
109 DWORD sid_len = pSid ? GetLengthSid(pSid) : 0;
110 TCHAR *ptcSid = NULL;
111 char *bucket_key = NULL;
112
113 if (!pSid) {
114 bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(pathname) + 1);
115 if (!bucket_key) {
116 return NULL;
117 }
118 memcpy(bucket_key, pathname, strlen(pathname));
119 return bucket_key;
120 }
121
122 if (!ConvertSidToStringSid(pSid, &ptcSid)) {
123 return NULL;
124 }
125
126 bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(pathname) + strlen(ptcSid) + 1);
127 if (!bucket_key) {
128 LocalFree(ptcSid);
129 return NULL;
130 }
131
132 memcpy(bucket_key, ptcSid, strlen(ptcSid));
133 memcpy(bucket_key + strlen(ptcSid), pathname, strlen(pathname) + 1);
134
135 LocalFree(ptcSid);
136 return bucket_key;
137 }
138
139
tsrm_win32_get_token_sid(HANDLE hToken)140 PSID tsrm_win32_get_token_sid(HANDLE hToken)
141 {
142 BOOL bSuccess = FALSE;
143 DWORD dwLength = 0;
144 PTOKEN_USER pTokenUser = NULL;
145 PSID sid;
146 PSID *ppsid = &sid;
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 TSRMLS_DC)193 TSRM_API int tsrm_win32_access(const char *pathname, int mode TSRMLS_DC)
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 BOOL bucket_key_alloc = FALSE;
208 realpath_cache_bucket * bucket = NULL;
209 char * real_path = NULL;
210
211 if (mode == 1 /*X_OK*/) {
212 DWORD type;
213 return GetBinaryType(pathname, &type) ? 0 : -1;
214 } else {
215 if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
216 real_path = (char *)malloc(MAX_PATH);
217 if(tsrm_realpath(pathname, real_path TSRMLS_CC) == NULL) {
218 goto Finished;
219 }
220 pathname = real_path;
221 }
222
223 if(access(pathname, mode)) {
224 free(real_path);
225 return errno;
226 }
227
228 /* If only existence check is made, return now */
229 if (mode == 0) {
230 free(real_path);
231 return 0;
232 }
233
234 /* Only in NTS when impersonate==1 (aka FastCGI) */
235
236 /*
237 AccessCheck() requires an impersonation token. We first get a primary
238 token and then create a duplicate impersonation token. The
239 impersonation token is not actually assigned to the thread, but is
240 used in the call to AccessCheck. Thus, this function itself never
241 impersonates, but does use the identity of the thread. If the thread
242 was impersonating already, this function uses that impersonation context.
243 */
244 if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
245 DWORD err = GetLastError();
246 if (GetLastError() == ERROR_NO_TOKEN) {
247 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
248 TWG(impersonation_token) = NULL;
249 goto Finished;
250 }
251 }
252 }
253
254 /* token_sid will be freed in tsrmwin32_dtor */
255 token_sid = tsrm_win32_get_token_sid(thread_token);
256 if (!token_sid) {
257 if (TWG(impersonation_token_sid)) {
258 free(TWG(impersonation_token_sid));
259 }
260 TWG(impersonation_token_sid) = NULL;
261 goto Finished;
262 }
263
264 /* Different identity, we need a new impersontated token as well */
265 if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) {
266 if (TWG(impersonation_token_sid)) {
267 free(TWG(impersonation_token_sid));
268 }
269 TWG(impersonation_token_sid) = token_sid;
270
271 /* Duplicate the token as impersonated token */
272 if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
273 goto Finished;
274 }
275 } else {
276 /* we already have it, free it then */
277 free(token_sid);
278 }
279
280 if (CWDG(realpath_cache_size_limit)) {
281 t = time(0);
282 bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
283 if(bucket == NULL && real_path == NULL) {
284 /* We used the pathname directly. Call tsrm_realpath */
285 /* so that entry is created in realpath cache */
286 real_path = (char *)malloc(MAX_PATH);
287 if(tsrm_realpath(pathname, real_path TSRMLS_CC) != NULL) {
288 pathname = real_path;
289 bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
290 }
291 }
292 }
293
294 /* Do a full access check because access() will only check read-only attribute */
295 if(mode == 0 || mode > 6) {
296 if(bucket != NULL && bucket->is_rvalid) {
297 fAccess = bucket->is_readable;
298 goto Finished;
299 }
300 desired_access = FILE_GENERIC_READ;
301 } else if(mode <= 2) {
302 if(bucket != NULL && bucket->is_wvalid) {
303 fAccess = bucket->is_writable;
304 goto Finished;
305 }
306 desired_access = FILE_GENERIC_WRITE;
307 } else if(mode <= 4) {
308 if(bucket != NULL && bucket->is_rvalid) {
309 fAccess = bucket->is_readable;
310 goto Finished;
311 }
312 desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
313 } else { // if(mode <= 6)
314 if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
315 fAccess = bucket->is_readable & bucket->is_writable;
316 goto Finished;
317 }
318 desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
319 }
320
321 if(TWG(impersonation_token) == NULL) {
322 goto Finished;
323 }
324
325 /* Get size of security buffer. Call is expected to fail */
326 if(GetFileSecurity(pathname, sec_info, NULL, 0, &sec_desc_length)) {
327 goto Finished;
328 }
329
330 psec_desc = (BYTE *)malloc(sec_desc_length);
331 if(psec_desc == NULL ||
332 !GetFileSecurity(pathname, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
333 goto Finished;
334 }
335
336 MapGenericMask(&desired_access, &gen_map);
337
338 if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
339 goto Finished_Impersonate;
340 }
341
342 /* Keep the result in realpath_cache */
343 if(bucket != NULL) {
344 if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
345 bucket->is_rvalid = 1;
346 bucket->is_readable = fAccess;
347 }
348 else if(desired_access == FILE_GENERIC_WRITE) {
349 bucket->is_wvalid = 1;
350 bucket->is_writable = fAccess;
351 } else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
352 bucket->is_rvalid = 1;
353 bucket->is_readable = fAccess;
354 bucket->is_wvalid = 1;
355 bucket->is_writable = fAccess;
356 }
357 }
358
359 Finished_Impersonate:
360 if(psec_desc != NULL) {
361 free(psec_desc);
362 psec_desc = NULL;
363 }
364
365 Finished:
366 if(thread_token != NULL) {
367 CloseHandle(thread_token);
368 }
369 if(real_path != NULL) {
370 free(real_path);
371 real_path = NULL;
372 }
373
374 if(fAccess == FALSE) {
375 errno = EACCES;
376 return errno;
377 } else {
378 return 0;
379 }
380 }
381 }
382
383
process_get(FILE * stream TSRMLS_DC)384 static process_pair *process_get(FILE *stream TSRMLS_DC)
385 {
386 process_pair *ptr;
387 process_pair *newptr;
388
389 for (ptr = TWG(process); ptr < (TWG(process) + TWG(process_size)); ptr++) {
390 if (ptr->stream == stream) {
391 break;
392 }
393 }
394
395 if (ptr < (TWG(process) + TWG(process_size))) {
396 return ptr;
397 }
398
399 newptr = (process_pair*)realloc((void*)TWG(process), (TWG(process_size)+1)*sizeof(process_pair));
400 if (newptr == NULL) {
401 return NULL;
402 }
403
404 TWG(process) = newptr;
405 ptr = newptr + TWG(process_size);
406 TWG(process_size)++;
407 return ptr;
408 }
409
shm_get(int key,void * addr)410 static shm_pair *shm_get(int key, void *addr)
411 {
412 shm_pair *ptr;
413 shm_pair *newptr;
414 TSRMLS_FETCH();
415
416 for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
417 if (!ptr->descriptor) {
418 continue;
419 }
420 if (!addr && ptr->descriptor->shm_perm.key == key) {
421 break;
422 } else if (ptr->addr == addr) {
423 break;
424 }
425 }
426
427 if (ptr < (TWG(shm) + TWG(shm_size))) {
428 return ptr;
429 }
430
431 newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
432 if (newptr == NULL) {
433 return NULL;
434 }
435
436 TWG(shm) = newptr;
437 ptr = newptr + TWG(shm_size);
438 TWG(shm_size)++;
439 return ptr;
440 }
441
dupHandle(HANDLE fh,BOOL inherit)442 static HANDLE dupHandle(HANDLE fh, BOOL inherit) {
443 HANDLE copy, self = GetCurrentProcess();
444 if (!DuplicateHandle(self, fh, self, ©, 0, inherit, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
445 return NULL;
446 }
447 return copy;
448 }
449
popen(const char * command,const char * type)450 TSRM_API FILE *popen(const char *command, const char *type)
451 {
452 TSRMLS_FETCH();
453
454 return popen_ex(command, type, NULL, NULL TSRMLS_CC);
455 }
456
popen_ex(const char * command,const char * type,const char * cwd,char * env TSRMLS_DC)457 TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env TSRMLS_DC)
458 {
459 FILE *stream = NULL;
460 int fno, type_len = strlen(type), read, mode;
461 STARTUPINFO startup;
462 PROCESS_INFORMATION process;
463 SECURITY_ATTRIBUTES security;
464 HANDLE in, out;
465 DWORD dwCreateFlags = 0;
466 BOOL res;
467 process_pair *proc;
468 char *cmd;
469 int i;
470 char *ptype = (char *)type;
471 HANDLE thread_token = NULL;
472 HANDLE token_user = NULL;
473 BOOL asuser = TRUE;
474
475 if (!type) {
476 return NULL;
477 }
478
479 /*The following two checks can be removed once we drop XP support */
480 type_len = strlen(type);
481 if (type_len <1 || type_len > 2) {
482 return NULL;
483 }
484
485 for (i=0; i < type_len; i++) {
486 if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) {
487 return NULL;
488 }
489 ptype++;
490 }
491
492 security.nLength = sizeof(SECURITY_ATTRIBUTES);
493 security.bInheritHandle = TRUE;
494 security.lpSecurityDescriptor = NULL;
495
496 if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
497 return NULL;
498 }
499
500 memset(&startup, 0, sizeof(STARTUPINFO));
501 memset(&process, 0, sizeof(PROCESS_INFORMATION));
502
503 startup.cb = sizeof(STARTUPINFO);
504 startup.dwFlags = STARTF_USESTDHANDLES;
505 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
506
507 read = (type[0] == 'r') ? TRUE : FALSE;
508 mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
509
510 if (read) {
511 in = dupHandle(in, FALSE);
512 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
513 startup.hStdOutput = out;
514 } else {
515 out = dupHandle(out, FALSE);
516 startup.hStdInput = in;
517 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
518 }
519
520 dwCreateFlags = NORMAL_PRIORITY_CLASS;
521 if (strcmp(sapi_module.name, "cli") != 0) {
522 dwCreateFlags |= CREATE_NO_WINDOW;
523 }
524
525 /* Get a token with the impersonated user. */
526 if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
527 DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
528 } else {
529 DWORD err = GetLastError();
530 if (err == ERROR_NO_TOKEN) {
531 asuser = FALSE;
532 }
533 }
534
535 cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
536 if (!cmd) {
537 return NULL;
538 }
539
540 sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);
541 if (asuser) {
542 res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
543 CloseHandle(token_user);
544 } else {
545 res = CreateProcess(NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
546 }
547 free(cmd);
548
549 if (!res) {
550 return NULL;
551 }
552
553 CloseHandle(process.hThread);
554 proc = process_get(NULL TSRMLS_CC);
555
556 if (read) {
557 fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
558 CloseHandle(out);
559 } else {
560 fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
561 CloseHandle(in);
562 }
563
564 stream = _fdopen(fno, type);
565 proc->prochnd = process.hProcess;
566 proc->stream = stream;
567 return stream;
568 }
569
pclose(FILE * stream)570 TSRM_API int pclose(FILE *stream)
571 {
572 DWORD termstat = 0;
573 process_pair *process;
574 TSRMLS_FETCH();
575
576 if ((process = process_get(stream TSRMLS_CC)) == 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 sprintf(shm_segment, "TSRM_SHM_SEGMENT:%d", key);
603 sprintf(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 return -1;
616 }
617 } else {
618 if (flags & IPC_EXCL) {
619 if (shm_handle) {
620 CloseHandle(shm_handle);
621 }
622 if (info_handle) {
623 CloseHandle(info_handle);
624 }
625 return -1;
626 }
627 }
628
629 shm = shm_get(key, NULL);
630 shm->segment = shm_handle;
631 shm->info = info_handle;
632 shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
633
634 if (NULL != shm->descriptor && created) {
635 shm->descriptor->shm_perm.key = key;
636 shm->descriptor->shm_segsz = size;
637 shm->descriptor->shm_ctime = time(NULL);
638 shm->descriptor->shm_cpid = getpid();
639 shm->descriptor->shm_perm.mode = flags;
640
641 shm->descriptor->shm_perm.cuid = shm->descriptor->shm_perm.cgid= 0;
642 shm->descriptor->shm_perm.gid = shm->descriptor->shm_perm.uid = 0;
643 shm->descriptor->shm_atime = shm->descriptor->shm_dtime = 0;
644 shm->descriptor->shm_lpid = shm->descriptor->shm_nattch = 0;
645 shm->descriptor->shm_perm.mode = shm->descriptor->shm_perm.seq = 0;
646 }
647
648 if (NULL != shm->descriptor && (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz)) {
649 if (NULL != shm->segment) {
650 CloseHandle(shm->segment);
651 }
652 UnmapViewOfFile(shm->descriptor);
653 CloseHandle(shm->info);
654 return -1;
655 }
656
657 return key;
658 }
659
shmat(int key,const void * shmaddr,int flags)660 TSRM_API void *shmat(int key, const void *shmaddr, int flags)
661 {
662 shm_pair *shm = shm_get(key, NULL);
663 int err;
664
665 if (!shm->segment) {
666 return (void*)-1;
667 }
668
669 shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
670
671 err = GetLastError();
672 if (err) {
673 /* Catch more errors */
674 if (ERROR_NOT_ENOUGH_MEMORY == err) {
675 _set_errno(ENOMEM);
676 }
677 return (void*)-1;
678 }
679
680 shm->descriptor->shm_atime = time(NULL);
681 shm->descriptor->shm_lpid = getpid();
682 shm->descriptor->shm_nattch++;
683
684 return shm->addr;
685 }
686
shmdt(const void * shmaddr)687 TSRM_API int shmdt(const void *shmaddr)
688 {
689 shm_pair *shm = shm_get(0, (void*)shmaddr);
690
691 if (!shm->segment) {
692 return -1;
693 }
694
695 shm->descriptor->shm_dtime = time(NULL);
696 shm->descriptor->shm_lpid = getpid();
697 shm->descriptor->shm_nattch--;
698
699 return UnmapViewOfFile(shm->addr) ? 0 : -1;
700 }
701
shmctl(int key,int cmd,struct shmid_ds * buf)702 TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) {
703 shm_pair *shm = shm_get(key, NULL);
704
705 if (!shm->segment) {
706 return -1;
707 }
708
709 switch (cmd) {
710 case IPC_STAT:
711 memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
712 return 0;
713
714 case IPC_SET:
715 shm->descriptor->shm_ctime = time(NULL);
716 shm->descriptor->shm_perm.uid = buf->shm_perm.uid;
717 shm->descriptor->shm_perm.gid = buf->shm_perm.gid;
718 shm->descriptor->shm_perm.mode = buf->shm_perm.mode;
719 return 0;
720
721 case IPC_RMID:
722 if (shm->descriptor->shm_nattch < 1) {
723 shm->descriptor->shm_perm.key = -1;
724 }
725 return 0;
726
727 default:
728 return -1;
729 }
730 }
731
realpath(char * orig_path,char * buffer)732 TSRM_API char *realpath(char *orig_path, char *buffer)
733 {
734 int ret = GetFullPathName(orig_path, _MAX_PATH, buffer, NULL);
735 if(!ret || ret > _MAX_PATH) {
736 return NULL;
737 }
738 return buffer;
739 }
740
741 #endif
742