xref: /PHP-5.5/TSRM/tsrm_win32.c (revision 73c1be26)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2015 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 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, &copy, 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 			return -1;
620 		}
621 	}
622 
623 	shm = shm_get(key, NULL);
624 	shm->segment = shm_handle;
625 	shm->info	 = info_handle;
626 	shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
627 
628 	if (NULL != shm->descriptor && created) {
629 		shm->descriptor->shm_perm.key	= key;
630 		shm->descriptor->shm_segsz		= size;
631 		shm->descriptor->shm_ctime		= time(NULL);
632 		shm->descriptor->shm_cpid		= getpid();
633 		shm->descriptor->shm_perm.mode	= flags;
634 
635 		shm->descriptor->shm_perm.cuid	= shm->descriptor->shm_perm.cgid= 0;
636 		shm->descriptor->shm_perm.gid	= shm->descriptor->shm_perm.uid = 0;
637 		shm->descriptor->shm_atime		= shm->descriptor->shm_dtime	= 0;
638 		shm->descriptor->shm_lpid		= shm->descriptor->shm_nattch	= 0;
639 		shm->descriptor->shm_perm.mode	= shm->descriptor->shm_perm.seq	= 0;
640 	}
641 
642 	if (NULL != shm->descriptor && (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz)) {
643 		if (NULL != shm->segment) {
644 			CloseHandle(shm->segment);
645 		}
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