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 38static ts_rsrc_id win32_globals_id; 39#else 40static tsrm_win32_globals win32_globals; 41#endif 42 43static 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 62static 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 90TSRM_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 99TSRM_API void tsrm_win32_shutdown(void) 100{ 101#ifndef ZTS 102 tsrm_win32_dtor(&win32_globals TSRMLS_CC); 103#endif 104} 105 106char * 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 140PSID 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 182Finished: 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 193TSRM_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 359Finished_Impersonate: 360 if(psec_desc != NULL) { 361 free(psec_desc); 362 psec_desc = NULL; 363 } 364 365Finished: 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 384static 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 410static 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 442static 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 450TSRM_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 457TSRM_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 570TSRM_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 591TSRM_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 (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 (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz ) { 643 CloseHandle(shm->segment); 644 UnmapViewOfFile(shm->descriptor); 645 CloseHandle(shm->info); 646 return -1; 647 } 648 649 return key; 650} 651 652TSRM_API void *shmat(int key, const void *shmaddr, int flags) 653{ 654 shm_pair *shm = shm_get(key, NULL); 655 656 if (!shm->segment) { 657 return (void*)-1; 658 } 659 660 shm->descriptor->shm_atime = time(NULL); 661 shm->descriptor->shm_lpid = getpid(); 662 shm->descriptor->shm_nattch++; 663 664 shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL); 665 666 return shm->addr; 667} 668 669TSRM_API int shmdt(const void *shmaddr) 670{ 671 shm_pair *shm = shm_get(0, (void*)shmaddr); 672 673 if (!shm->segment) { 674 return -1; 675 } 676 677 shm->descriptor->shm_dtime = time(NULL); 678 shm->descriptor->shm_lpid = getpid(); 679 shm->descriptor->shm_nattch--; 680 681 return UnmapViewOfFile(shm->addr) ? 0 : -1; 682} 683 684TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) { 685 shm_pair *shm = shm_get(key, NULL); 686 687 if (!shm->segment) { 688 return -1; 689 } 690 691 switch (cmd) { 692 case IPC_STAT: 693 memcpy(buf, shm->descriptor, sizeof(struct shmid_ds)); 694 return 0; 695 696 case IPC_SET: 697 shm->descriptor->shm_ctime = time(NULL); 698 shm->descriptor->shm_perm.uid = buf->shm_perm.uid; 699 shm->descriptor->shm_perm.gid = buf->shm_perm.gid; 700 shm->descriptor->shm_perm.mode = buf->shm_perm.mode; 701 return 0; 702 703 case IPC_RMID: 704 if (shm->descriptor->shm_nattch < 1) { 705 shm->descriptor->shm_perm.key = -1; 706 } 707 return 0; 708 709 default: 710 return -1; 711 } 712} 713 714TSRM_API char *realpath(char *orig_path, char *buffer) 715{ 716 int ret = GetFullPathName(orig_path, _MAX_PATH, buffer, NULL); 717 if(!ret || ret > _MAX_PATH) { 718 return NULL; 719 } 720 return buffer; 721} 722 723#endif 724