root/TSRM/tsrm_win32.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tsrm_win32_ctor
  2. tsrm_win32_dtor
  3. tsrm_win32_startup
  4. tsrm_win32_shutdown
  5. tsrm_win32_get_path_sid_key
  6. tsrm_win32_get_token_sid
  7. tsrm_win32_access
  8. process_get
  9. shm_get
  10. dupHandle
  11. popen
  12. popen_ex
  13. pclose
  14. shmget
  15. shmat
  16. shmdt
  17. shmctl
  18. realpath

   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 
  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 
  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 
  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 
  99 TSRM_API void tsrm_win32_shutdown(void)
 100 {
 101 #ifndef ZTS
 102         tsrm_win32_dtor(&win32_globals TSRMLS_CC);
 103 #endif
 104 }
 105 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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

/* [<][>][^][v][top][bottom][index][help] */