Back to index

php5  5.3.10
tsrm_win32.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Daniel Beulshausen <daniel@php4win.de>                      |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: tsrm_win32.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #include <stdio.h>
00022 #include <fcntl.h>
00023 #include <io.h>
00024 #include <process.h>
00025 #include <time.h>
00026 #include <errno.h>
00027 
00028 #define TSRM_INCLUDE_FULL_WINDOWS_HEADERS
00029 #include "SAPI.h"
00030 #include "TSRM.h"
00031 
00032 #ifdef TSRM_WIN32
00033 #include <Sddl.h>
00034 #include "tsrm_win32.h"
00035 #include "tsrm_virtual_cwd.h"
00036 
00037 #ifdef ZTS
00038 static ts_rsrc_id win32_globals_id;
00039 #else
00040 static tsrm_win32_globals win32_globals;
00041 #endif
00042 
00043 static void tsrm_win32_ctor(tsrm_win32_globals *globals TSRMLS_DC)
00044 {
00045        globals->process = NULL;
00046        globals->shm   = NULL;
00047        globals->process_size = 0;
00048        globals->shm_size      = 0;
00049        globals->comspec = _strdup((GetVersion()<0x80000000)?"cmd.exe":"command.com");
00050 
00051        /* Set it to INVALID_HANDLE_VALUE
00052         * It will be initialized correctly in tsrm_win32_access or set to 
00053         * NULL if no impersonation has been done.
00054         * the impersonated token can't be set here as the impersonation
00055         * will happen later, in fcgi_accept_request (or whatever is the
00056         * SAPI being used).
00057         */
00058        globals->impersonation_token = INVALID_HANDLE_VALUE;
00059        globals->impersonation_token_sid = NULL;
00060 }
00061 
00062 static void tsrm_win32_dtor(tsrm_win32_globals *globals TSRMLS_DC)
00063 {
00064        shm_pair *ptr;
00065 
00066        if (globals->process) {
00067               free(globals->process);
00068        }
00069 
00070        if (globals->shm) {
00071               for (ptr = globals->shm; ptr < (globals->shm + globals->shm_size); ptr++) {
00072                      UnmapViewOfFile(ptr->addr);
00073                      CloseHandle(ptr->segment);
00074                      UnmapViewOfFile(ptr->descriptor);
00075                      CloseHandle(ptr->info);
00076               }
00077               free(globals->shm);
00078        }
00079 
00080        free(globals->comspec);
00081 
00082        if (globals->impersonation_token && globals->impersonation_token != INVALID_HANDLE_VALUE   ) {
00083               CloseHandle(globals->impersonation_token);
00084        }
00085        if (globals->impersonation_token_sid) {
00086               free(globals->impersonation_token_sid);
00087        }
00088 }
00089 
00090 TSRM_API void tsrm_win32_startup(void)
00091 {
00092 #ifdef ZTS
00093        ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_ctor)tsrm_win32_dtor);
00094 #else
00095        tsrm_win32_ctor(&win32_globals TSRMLS_CC);
00096 #endif
00097 }
00098 
00099 TSRM_API void tsrm_win32_shutdown(void)
00100 {
00101 #ifndef ZTS
00102        tsrm_win32_dtor(&win32_globals TSRMLS_CC);
00103 #endif
00104 }
00105 
00106 char * tsrm_win32_get_path_sid_key(const char *pathname TSRMLS_DC)
00107 {
00108        PSID pSid = TWG(impersonation_token_sid);
00109        DWORD sid_len = pSid ? GetLengthSid(pSid) : 0;
00110        TCHAR *ptcSid = NULL;
00111        char *bucket_key = NULL;
00112 
00113        if (!pSid) {
00114               bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(pathname) + 1);
00115               if (!bucket_key) {
00116                      return NULL;
00117               }
00118               memcpy(bucket_key, pathname, strlen(pathname));
00119               return bucket_key;
00120        }
00121 
00122        if (!ConvertSidToStringSid(pSid, &ptcSid)) {
00123               return NULL;
00124        }
00125 
00126        bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(pathname) + strlen(ptcSid) + 1);
00127        if (!bucket_key) {
00128               LocalFree(ptcSid);
00129               return NULL;
00130        }
00131 
00132        memcpy(bucket_key, ptcSid, strlen(ptcSid));
00133        memcpy(bucket_key + strlen(ptcSid), pathname, strlen(pathname) + 1);
00134 
00135        LocalFree(ptcSid);
00136        return bucket_key;
00137 }
00138 
00139 
00140 PSID tsrm_win32_get_token_sid(HANDLE hToken)
00141 {
00142        BOOL bSuccess = FALSE;
00143        DWORD dwLength = 0;
00144        PTOKEN_USER pTokenUser = NULL;
00145        PSID sid;
00146        PSID *ppsid = &sid;
00147        DWORD sid_len;
00148        PSID pResultSid = NULL;
00149 
00150        /* Get the actual size of the TokenUser structure */
00151        if (!GetTokenInformation(
00152                      hToken, TokenUser, (LPVOID) pTokenUser, 0, &dwLength))  {
00153               if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
00154                      goto Finished;
00155               }
00156 
00157               pTokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
00158               if (pTokenUser == NULL) {
00159                      goto Finished;
00160               }
00161        }
00162 
00163        /* and fetch it now */
00164        if (!GetTokenInformation(
00165               hToken, TokenUser, (LPVOID) pTokenUser, dwLength, &dwLength)) {
00166               goto Finished;
00167        }
00168 
00169        sid_len = GetLengthSid(pTokenUser->User.Sid);
00170 
00171        /* ConvertSidToStringSid(pTokenUser->User.Sid, &ptcSidOwner); */
00172        pResultSid = malloc(sid_len);
00173        if (!pResultSid) {
00174               goto Finished;
00175        }
00176        if (!CopySid(sid_len, pResultSid, pTokenUser->User.Sid)) {
00177               goto Finished;
00178        }
00179        HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
00180        return pResultSid;
00181 
00182 Finished:
00183        if (pResultSid) {
00184               free(pResultSid);
00185        }
00186        /* Free the buffer for the token groups. */
00187        if (pTokenUser != NULL) {
00188               HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
00189        }
00190        return NULL;
00191 }
00192 
00193 TSRM_API int tsrm_win32_access(const char *pathname, int mode)
00194 {
00195        time_t t;
00196        HANDLE thread_token;
00197        PSID token_sid;
00198        SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
00199        GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
00200        DWORD priv_set_length = sizeof(PRIVILEGE_SET);
00201 
00202        PRIVILEGE_SET privilege_set = {0};
00203        DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0;
00204        BYTE * psec_desc = NULL;
00205        BOOL fAccess = FALSE;
00206 
00207        BOOL bucket_key_alloc = FALSE;
00208        realpath_cache_bucket * bucket = NULL;
00209        char * real_path = NULL;
00210 
00211        TSRMLS_FETCH();
00212 
00213        if (mode == 1 /*X_OK*/) {
00214               DWORD type;
00215               return GetBinaryType(pathname, &type) ? 0 : -1;
00216        } else {
00217               if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
00218                      real_path = (char *)malloc(MAX_PATH);
00219                      if(tsrm_realpath(pathname, real_path TSRMLS_CC) == NULL) {
00220                             goto Finished;
00221                      }
00222                      pathname = real_path;
00223               }
00224 
00225               if(access(pathname, mode)) {
00226                      free(real_path);
00227                      return errno;
00228               }
00229 
00230               /* If only existence check is made, return now */
00231               if (mode == 0) {
00232                      free(real_path);
00233                      return 0;
00234               }
00235 
00236 /* Only in NTS when impersonate==1 (aka FastCGI) */
00237 
00238               /*
00239                AccessCheck() requires an impersonation token.  We first get a primary
00240                token and then create a duplicate impersonation token.  The
00241                impersonation token is not actually assigned to the thread, but is
00242                used in the call to AccessCheck.  Thus, this function itself never
00243                impersonates, but does use the identity of the thread.  If the thread
00244                was impersonating already, this function uses that impersonation context.
00245               */
00246               if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
00247                      DWORD err = GetLastError();
00248                      if (GetLastError() == ERROR_NO_TOKEN) {
00249                             if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
00250                                     TWG(impersonation_token) = NULL;
00251                                     goto Finished;
00252                              }
00253                      }
00254               }
00255 
00256               /* token_sid will be freed in tsrmwin32_dtor */
00257               token_sid = tsrm_win32_get_token_sid(thread_token);
00258               if (!token_sid) {
00259                      if (TWG(impersonation_token_sid)) {
00260                             free(TWG(impersonation_token_sid));
00261                      }
00262                      TWG(impersonation_token_sid) = NULL;
00263                      goto Finished;
00264               }
00265 
00266               /* Different identity, we need a new impersontated token as well */
00267               if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) {
00268                      if (TWG(impersonation_token_sid)) {
00269                             free(TWG(impersonation_token_sid));
00270                      }
00271                      TWG(impersonation_token_sid) = token_sid;
00272 
00273                      /* Duplicate the token as impersonated token */
00274                      if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
00275                             goto Finished;
00276                      }
00277               } else {
00278                      /* we already have it, free it then */
00279                      free(token_sid);
00280               }
00281 
00282               if (CWDG(realpath_cache_size_limit)) {
00283                      t = time(0);
00284                      bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
00285                      if(bucket == NULL && real_path == NULL) {
00286                             /* We used the pathname directly. Call tsrm_realpath */
00287                             /* so that entry is created in realpath cache */
00288                             real_path = (char *)malloc(MAX_PATH);
00289                             if(tsrm_realpath(pathname, real_path TSRMLS_CC) != NULL) {
00290                                    pathname = real_path;
00291                                    bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
00292                             }
00293                      }
00294               }
00295 
00296               /* Do a full access check because access() will only check read-only attribute */
00297               if(mode == 0 || mode > 6) {
00298                      if(bucket != NULL && bucket->is_rvalid) {
00299                             fAccess = bucket->is_readable;
00300                             goto Finished;
00301                      }
00302                      desired_access = FILE_GENERIC_READ;
00303               } else if(mode <= 2) {
00304                      if(bucket != NULL && bucket->is_wvalid) {
00305                             fAccess = bucket->is_writable;
00306                             goto Finished;
00307                      }
00308                      desired_access = FILE_GENERIC_WRITE;
00309               } else if(mode <= 4) {
00310                      if(bucket != NULL && bucket->is_rvalid) {
00311                             fAccess = bucket->is_readable;
00312                             goto Finished;
00313                      }
00314                      desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
00315               } else { // if(mode <= 6)
00316                      if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
00317                             fAccess = bucket->is_readable & bucket->is_writable;
00318                             goto Finished;
00319                      }
00320                      desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
00321               }
00322 
00323               if(TWG(impersonation_token) == NULL) {
00324                      goto Finished;
00325               }
00326 
00327               /* Get size of security buffer. Call is expected to fail */
00328               if(GetFileSecurity(pathname, sec_info, NULL, 0, &sec_desc_length)) {
00329                      goto Finished;
00330               }
00331 
00332               psec_desc = (BYTE *)malloc(sec_desc_length);
00333               if(psec_desc == NULL ||
00334                       !GetFileSecurity(pathname, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
00335                      goto Finished;
00336               }
00337 
00338               MapGenericMask(&desired_access, &gen_map);
00339 
00340               if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
00341                      goto Finished_Impersonate;
00342               }
00343 
00344               /* Keep the result in realpath_cache */
00345               if(bucket != NULL) {
00346                      if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
00347                             bucket->is_rvalid = 1;
00348                             bucket->is_readable = fAccess;
00349                      }
00350                      else if(desired_access == FILE_GENERIC_WRITE) {
00351                             bucket->is_wvalid = 1;
00352                             bucket->is_writable = fAccess;
00353                      } else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
00354                             bucket->is_rvalid = 1;
00355                             bucket->is_readable = fAccess;
00356                             bucket->is_wvalid = 1;
00357                             bucket->is_writable = fAccess;
00358                      }
00359               }
00360 
00361 Finished_Impersonate:
00362               if(psec_desc != NULL) {
00363                      free(psec_desc);
00364                      psec_desc = NULL;
00365               }
00366 
00367 Finished:
00368               if(real_path != NULL) {
00369                      free(real_path);
00370                      real_path = NULL;
00371               }
00372 
00373               if(fAccess == FALSE) {
00374                      errno = EACCES;
00375                      return errno;
00376               } else {
00377                      return 0;
00378               }
00379        }
00380 }
00381 
00382 
00383 static process_pair *process_get(FILE *stream TSRMLS_DC)
00384 {
00385        process_pair *ptr;
00386        process_pair *newptr;
00387 
00388        for (ptr = TWG(process); ptr < (TWG(process) + TWG(process_size)); ptr++) {
00389               if (ptr->stream == stream) {
00390                      break;
00391               }
00392        }
00393 
00394        if (ptr < (TWG(process) + TWG(process_size))) {
00395               return ptr;
00396        }
00397 
00398        newptr = (process_pair*)realloc((void*)TWG(process), (TWG(process_size)+1)*sizeof(process_pair));
00399        if (newptr == NULL) {
00400               return NULL;
00401        }
00402 
00403        TWG(process) = newptr;
00404        ptr = newptr + TWG(process_size);
00405        TWG(process_size)++;
00406        return ptr;
00407 }
00408 
00409 static shm_pair *shm_get(int key, void *addr)
00410 {
00411        shm_pair *ptr;
00412        shm_pair *newptr;
00413        TSRMLS_FETCH();
00414 
00415        for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
00416               if (!ptr->descriptor) {
00417                      continue;
00418               }
00419               if (!addr && ptr->descriptor->shm_perm.key == key) {
00420                      break;
00421               } else if (ptr->addr == addr) {
00422                      break;
00423               }
00424        }
00425 
00426        if (ptr < (TWG(shm) + TWG(shm_size))) {
00427               return ptr;
00428        }
00429 
00430        newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
00431        if (newptr == NULL) {
00432               return NULL;
00433        }
00434 
00435        TWG(shm) = newptr;
00436        ptr = newptr + TWG(shm_size);
00437        TWG(shm_size)++;
00438        return ptr;
00439 }
00440 
00441 static HANDLE dupHandle(HANDLE fh, BOOL inherit) {
00442        HANDLE copy, self = GetCurrentProcess();
00443        if (!DuplicateHandle(self, fh, self, &copy, 0, inherit, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
00444               return NULL;
00445        }
00446        return copy;
00447 }
00448 
00449 TSRM_API FILE *popen(const char *command, const char *type)
00450 {
00451        return popen_ex(command, type, NULL, NULL);
00452 }
00453 
00454 TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env)
00455 {
00456        FILE *stream = NULL;
00457        int fno, type_len = strlen(type), read, mode;
00458        STARTUPINFO startup;
00459        PROCESS_INFORMATION process;
00460        SECURITY_ATTRIBUTES security;
00461        HANDLE in, out;
00462        DWORD dwCreateFlags = 0;
00463        BOOL res;
00464        process_pair *proc;
00465        char *cmd;
00466        int i;
00467        char *ptype = (char *)type;
00468        HANDLE thread_token = NULL;
00469        HANDLE token_user = NULL;
00470        BOOL asuser = TRUE;
00471 
00472        TSRMLS_FETCH();
00473 
00474        if (!type) {
00475               return NULL;
00476        }
00477 
00478        /*The following two checks can be removed once we drop XP support */
00479        type_len = strlen(type);
00480        if (type_len <1 || type_len > 2) {
00481               return NULL;
00482        }
00483 
00484        for (i=0; i < type_len; i++) {
00485               if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) {
00486                      return NULL;
00487               }
00488               ptype++;
00489        }
00490 
00491        security.nLength                          = sizeof(SECURITY_ATTRIBUTES);
00492        security.bInheritHandle                   = TRUE;
00493        security.lpSecurityDescriptor      = NULL;
00494 
00495        if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
00496               return NULL;
00497        }
00498 
00499        memset(&startup, 0, sizeof(STARTUPINFO));
00500        memset(&process, 0, sizeof(PROCESS_INFORMATION));
00501 
00502        startup.cb                  = sizeof(STARTUPINFO);
00503        startup.dwFlags             = STARTF_USESTDHANDLES;
00504        startup.hStdError    = GetStdHandle(STD_ERROR_HANDLE);
00505 
00506        read = (type[0] == 'r') ? TRUE : FALSE;
00507        mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
00508 
00509        if (read) {
00510               in = dupHandle(in, FALSE);
00511               startup.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
00512               startup.hStdOutput = out;
00513        } else {
00514               out = dupHandle(out, FALSE);
00515               startup.hStdInput  = in;
00516               startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
00517        }
00518 
00519        dwCreateFlags = NORMAL_PRIORITY_CLASS;
00520        if (strcmp(sapi_module.name, "cli") != 0) {
00521               dwCreateFlags |= CREATE_NO_WINDOW;
00522        }
00523 
00524        /* Get a token with the impersonated user. */
00525        if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
00526               DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
00527        } else {
00528               DWORD err = GetLastError();
00529               if (err == ERROR_NO_TOKEN) {
00530                      asuser = FALSE;
00531               }
00532        }
00533 
00534        cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
00535        if (!cmd) {
00536               return NULL;
00537        }
00538 
00539        sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);
00540        if (asuser) {
00541               res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
00542               CloseHandle(token_user);
00543        } else {
00544               res = CreateProcess(NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
00545        }
00546        free(cmd);
00547 
00548        if (!res) {
00549               return NULL;
00550        }
00551 
00552        CloseHandle(process.hThread);
00553        proc = process_get(NULL TSRMLS_CC);
00554 
00555        if (read) {
00556               fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
00557               CloseHandle(out);
00558        } else {
00559               fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
00560               CloseHandle(in);
00561        }
00562 
00563        stream = _fdopen(fno, type);
00564        proc->prochnd = process.hProcess;
00565        proc->stream = stream;
00566        return stream;
00567 }
00568 
00569 TSRM_API int pclose(FILE *stream)
00570 {
00571        DWORD termstat = 0;
00572        process_pair *process;
00573        TSRMLS_FETCH();
00574 
00575        if ((process = process_get(stream TSRMLS_CC)) == NULL) {
00576               return 0;
00577        }
00578 
00579        fflush(process->stream);
00580        fclose(process->stream);
00581 
00582        WaitForSingleObject(process->prochnd, INFINITE);
00583        GetExitCodeProcess(process->prochnd, &termstat);
00584        process->stream = NULL;
00585        CloseHandle(process->prochnd);
00586 
00587        return termstat;
00588 }
00589 
00590 TSRM_API int shmget(int key, int size, int flags)
00591 {
00592        shm_pair *shm;
00593        char shm_segment[26], shm_info[29];
00594        HANDLE shm_handle, info_handle;
00595        BOOL created = FALSE;
00596 
00597        if (size < 0) {
00598               return -1;
00599        }
00600 
00601        sprintf(shm_segment, "TSRM_SHM_SEGMENT:%d", key);
00602        sprintf(shm_info, "TSRM_SHM_DESCRIPTOR:%d", key);
00603 
00604        shm_handle  = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment);
00605        info_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_info);
00606 
00607        if ((!shm_handle && !info_handle)) {
00608               if (flags & IPC_CREAT) {
00609                      shm_handle    = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, shm_segment);
00610                      info_handle   = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shm->descriptor), shm_info);
00611                      created              = TRUE;
00612               }
00613               if ((!shm_handle || !info_handle)) {
00614                      return -1;
00615               }
00616        } else {
00617               if (flags & IPC_EXCL) {
00618                      return -1;
00619               }
00620        }
00621 
00622        shm = shm_get(key, NULL);
00623        shm->segment = shm_handle;
00624        shm->info      = info_handle;
00625        shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
00626 
00627        if (created) {
00628               shm->descriptor->shm_perm.key      = key;
00629               shm->descriptor->shm_segsz         = size;
00630               shm->descriptor->shm_ctime         = time(NULL);
00631               shm->descriptor->shm_cpid          = getpid();
00632               shm->descriptor->shm_perm.mode     = flags;
00633 
00634               shm->descriptor->shm_perm.cuid     = shm->descriptor->shm_perm.cgid= 0;
00635               shm->descriptor->shm_perm.gid      = shm->descriptor->shm_perm.uid = 0;
00636               shm->descriptor->shm_atime         = shm->descriptor->shm_dtime       = 0;
00637               shm->descriptor->shm_lpid          = shm->descriptor->shm_nattch      = 0;
00638               shm->descriptor->shm_perm.mode     = shm->descriptor->shm_perm.seq    = 0;
00639        }
00640 
00641        if (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz ) {
00642               CloseHandle(shm->segment);
00643               UnmapViewOfFile(shm->descriptor);
00644               CloseHandle(shm->info);
00645               return -1;
00646        }
00647 
00648        return key;
00649 }
00650 
00651 TSRM_API void *shmat(int key, const void *shmaddr, int flags)
00652 {
00653        shm_pair *shm = shm_get(key, NULL);
00654 
00655        if (!shm->segment) {
00656               return (void*)-1;
00657        }
00658 
00659        shm->descriptor->shm_atime = time(NULL);
00660        shm->descriptor->shm_lpid  = getpid();
00661        shm->descriptor->shm_nattch++;
00662 
00663        shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
00664 
00665        return shm->addr;
00666 }
00667 
00668 TSRM_API int shmdt(const void *shmaddr)
00669 {
00670        shm_pair *shm = shm_get(0, (void*)shmaddr);
00671 
00672        if (!shm->segment) {
00673               return -1;
00674        }
00675 
00676        shm->descriptor->shm_dtime = time(NULL);
00677        shm->descriptor->shm_lpid  = getpid();
00678        shm->descriptor->shm_nattch--;
00679 
00680        return UnmapViewOfFile(shm->addr) ? 0 : -1;
00681 }
00682 
00683 TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) {
00684        shm_pair *shm = shm_get(key, NULL);
00685 
00686        if (!shm->segment) {
00687               return -1;
00688        }
00689 
00690        switch (cmd) {
00691               case IPC_STAT:
00692                      memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
00693                      return 0;
00694 
00695               case IPC_SET:
00696                      shm->descriptor->shm_ctime         = time(NULL);
00697                      shm->descriptor->shm_perm.uid      = buf->shm_perm.uid;
00698                      shm->descriptor->shm_perm.gid      = buf->shm_perm.gid;
00699                      shm->descriptor->shm_perm.mode     = buf->shm_perm.mode;
00700                      return 0;
00701 
00702               case IPC_RMID:
00703                      if (shm->descriptor->shm_nattch < 1) {
00704                             shm->descriptor->shm_perm.key = -1;
00705                      }
00706                      return 0;
00707 
00708               default:
00709                      return -1;
00710        }
00711 }
00712 
00713 TSRM_API char *realpath(char *orig_path, char *buffer)
00714 {
00715        int ret = GetFullPathName(orig_path, _MAX_PATH, buffer, NULL);
00716        if(!ret || ret > _MAX_PATH) {
00717               return NULL;
00718        }
00719        return buffer;
00720 }
00721 
00722 #endif