1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 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 "tsrm_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)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 BOOL bucket_key_alloc = FALSE;
208 realpath_cache_bucket * bucket = NULL;
209 char * real_path = NULL;
210
211 TSRMLS_FETCH();
212
213 if (mode == 1 /*X_OK*/) {
214 DWORD type;
215 return GetBinaryType(pathname, &type) ? 0 : -1;
216 } else {
217 if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
218 real_path = (char *)malloc(MAX_PATH);
219 if(tsrm_realpath(pathname, real_path TSRMLS_CC) == NULL) {
220 goto Finished;
221 }
222 pathname = real_path;
223 }
224
225 if(access(pathname, mode)) {
226 free(real_path);
227 return errno;
228 }
229
230 /* If only existence check is made, return now */
231 if (mode == 0) {
232 free(real_path);
233 return 0;
234 }
235
236 /* Only in NTS when impersonate==1 (aka FastCGI) */
237
238 /*
239 AccessCheck() requires an impersonation token. We first get a primary
240 token and then create a duplicate impersonation token. The
241 impersonation token is not actually assigned to the thread, but is
242 used in the call to AccessCheck. Thus, this function itself never
243 impersonates, but does use the identity of the thread. If the thread
244 was impersonating already, this function uses that impersonation context.
245 */
246 if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
247 DWORD err = GetLastError();
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, strlen(pathname), t TSRMLS_CC);
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 TSRMLS_CC) != NULL) {
290 pathname = real_path;
291 bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
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 TSRMLS_DC)386 static process_pair *process_get(FILE *stream TSRMLS_DC)
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 TSRMLS_FETCH();
417
418 for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
419 if (!ptr->descriptor) {
420 continue;
421 }
422 if (!addr && ptr->descriptor->shm_perm.key == key) {
423 break;
424 } else if (ptr->addr == addr) {
425 break;
426 }
427 }
428
429 if (ptr < (TWG(shm) + TWG(shm_size))) {
430 return ptr;
431 }
432
433 newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
434 if (newptr == NULL) {
435 return NULL;
436 }
437
438 TWG(shm) = newptr;
439 ptr = newptr + TWG(shm_size);
440 TWG(shm_size)++;
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 return popen_ex(command, type, NULL, NULL);
455 }
456
popen_ex(const char * command,const char * type,const char * cwd,char * env)457 TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env)
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 TSRMLS_FETCH();
476
477 if (!type) {
478 return NULL;
479 }
480
481 /*The following two checks can be removed once we drop XP support */
482 type_len = strlen(type);
483 if (type_len <1 || type_len > 2) {
484 return NULL;
485 }
486
487 for (i=0; i < type_len; i++) {
488 if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) {
489 return NULL;
490 }
491 ptype++;
492 }
493
494 security.nLength = sizeof(SECURITY_ATTRIBUTES);
495 security.bInheritHandle = TRUE;
496 security.lpSecurityDescriptor = NULL;
497
498 if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
499 return NULL;
500 }
501
502 memset(&startup, 0, sizeof(STARTUPINFO));
503 memset(&process, 0, sizeof(PROCESS_INFORMATION));
504
505 startup.cb = sizeof(STARTUPINFO);
506 startup.dwFlags = STARTF_USESTDHANDLES;
507 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
508
509 read = (type[0] == 'r') ? TRUE : FALSE;
510 mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
511
512 if (read) {
513 in = dupHandle(in, FALSE);
514 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
515 startup.hStdOutput = out;
516 } else {
517 out = dupHandle(out, FALSE);
518 startup.hStdInput = in;
519 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
520 }
521
522 dwCreateFlags = NORMAL_PRIORITY_CLASS;
523 if (strcmp(sapi_module.name, "cli") != 0) {
524 dwCreateFlags |= CREATE_NO_WINDOW;
525 }
526
527 /* Get a token with the impersonated user. */
528 if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
529 DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
530 } else {
531 DWORD err = GetLastError();
532 if (err == ERROR_NO_TOKEN) {
533 asuser = FALSE;
534 }
535 }
536
537 cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
538 if (!cmd) {
539 return NULL;
540 }
541
542 sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);
543 if (asuser) {
544 res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
545 CloseHandle(token_user);
546 } else {
547 res = CreateProcess(NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
548 }
549 free(cmd);
550
551 if (!res) {
552 return NULL;
553 }
554
555 CloseHandle(process.hThread);
556 proc = process_get(NULL TSRMLS_CC);
557
558 if (read) {
559 fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
560 CloseHandle(out);
561 } else {
562 fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
563 CloseHandle(in);
564 }
565
566 stream = _fdopen(fno, type);
567 proc->prochnd = process.hProcess;
568 proc->stream = stream;
569 return stream;
570 }
571
pclose(FILE * stream)572 TSRM_API int pclose(FILE *stream)
573 {
574 DWORD termstat = 0;
575 process_pair *process;
576 TSRMLS_FETCH();
577
578 if ((process = process_get(stream TSRMLS_CC)) == NULL) {
579 return 0;
580 }
581
582 fflush(process->stream);
583 fclose(process->stream);
584
585 WaitForSingleObject(process->prochnd, INFINITE);
586 GetExitCodeProcess(process->prochnd, &termstat);
587 process->stream = NULL;
588 CloseHandle(process->prochnd);
589
590 return termstat;
591 }
592
shmget(int key,int size,int flags)593 TSRM_API int shmget(int key, int size, int flags)
594 {
595 shm_pair *shm;
596 char shm_segment[26], shm_info[29];
597 HANDLE shm_handle, info_handle;
598 BOOL created = FALSE;
599
600 if (size < 0) {
601 return -1;
602 }
603
604 sprintf(shm_segment, "TSRM_SHM_SEGMENT:%d", key);
605 sprintf(shm_info, "TSRM_SHM_DESCRIPTOR:%d", key);
606
607 shm_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment);
608 info_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_info);
609
610 if ((!shm_handle && !info_handle)) {
611 if (flags & IPC_CREAT) {
612 shm_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, shm_segment);
613 info_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shm->descriptor), shm_info);
614 created = TRUE;
615 }
616 if ((!shm_handle || !info_handle)) {
617 return -1;
618 }
619 } else {
620 if (flags & IPC_EXCL) {
621 return -1;
622 }
623 }
624
625 shm = shm_get(key, NULL);
626 shm->segment = shm_handle;
627 shm->info = info_handle;
628 shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
629
630 if (created) {
631 shm->descriptor->shm_perm.key = key;
632 shm->descriptor->shm_segsz = size;
633 shm->descriptor->shm_ctime = time(NULL);
634 shm->descriptor->shm_cpid = getpid();
635 shm->descriptor->shm_perm.mode = flags;
636
637 shm->descriptor->shm_perm.cuid = shm->descriptor->shm_perm.cgid= 0;
638 shm->descriptor->shm_perm.gid = shm->descriptor->shm_perm.uid = 0;
639 shm->descriptor->shm_atime = shm->descriptor->shm_dtime = 0;
640 shm->descriptor->shm_lpid = shm->descriptor->shm_nattch = 0;
641 shm->descriptor->shm_perm.mode = shm->descriptor->shm_perm.seq = 0;
642 }
643
644 if (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz ) {
645 CloseHandle(shm->segment);
646 UnmapViewOfFile(shm->descriptor);
647 CloseHandle(shm->info);
648 return -1;
649 }
650
651 return key;
652 }
653
shmat(int key,const void * shmaddr,int flags)654 TSRM_API void *shmat(int key, const void *shmaddr, int flags)
655 {
656 shm_pair *shm = shm_get(key, NULL);
657
658 if (!shm->segment) {
659 return (void*)-1;
660 }
661
662 shm->descriptor->shm_atime = time(NULL);
663 shm->descriptor->shm_lpid = getpid();
664 shm->descriptor->shm_nattch++;
665
666 shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
667
668 return shm->addr;
669 }
670
shmdt(const void * shmaddr)671 TSRM_API int shmdt(const void *shmaddr)
672 {
673 shm_pair *shm = shm_get(0, (void*)shmaddr);
674
675 if (!shm->segment) {
676 return -1;
677 }
678
679 shm->descriptor->shm_dtime = time(NULL);
680 shm->descriptor->shm_lpid = getpid();
681 shm->descriptor->shm_nattch--;
682
683 return UnmapViewOfFile(shm->addr) ? 0 : -1;
684 }
685
shmctl(int key,int cmd,struct shmid_ds * buf)686 TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) {
687 shm_pair *shm = shm_get(key, NULL);
688
689 if (!shm->segment) {
690 return -1;
691 }
692
693 switch (cmd) {
694 case IPC_STAT:
695 memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
696 return 0;
697
698 case IPC_SET:
699 shm->descriptor->shm_ctime = time(NULL);
700 shm->descriptor->shm_perm.uid = buf->shm_perm.uid;
701 shm->descriptor->shm_perm.gid = buf->shm_perm.gid;
702 shm->descriptor->shm_perm.mode = buf->shm_perm.mode;
703 return 0;
704
705 case IPC_RMID:
706 if (shm->descriptor->shm_nattch < 1) {
707 shm->descriptor->shm_perm.key = -1;
708 }
709 return 0;
710
711 default:
712 return -1;
713 }
714 }
715
realpath(char * orig_path,char * buffer)716 TSRM_API char *realpath(char *orig_path, char *buffer)
717 {
718 int ret = GetFullPathName(orig_path, _MAX_PATH, buffer, NULL);
719 if(!ret || ret > _MAX_PATH) {
720 return NULL;
721 }
722 return buffer;
723 }
724
725 #endif
726