xref: /PHP-5.3/TSRM/tsrm_win32.c (revision a2045ff3)
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, &copy, 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