Annotation of embedaddon/php/TSRM/tsrm_win32.c, revision 1.1.1.4

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3   misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      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: 
                     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: 
1.1.1.2   misho     193: TSRM_API int tsrm_win32_access(const char *pathname, int mode TSRMLS_DC)
1.1       misho     194: {
                    195:        time_t t;
1.1.1.3   misho     196:        HANDLE thread_token = NULL;
1.1       misho     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:
1.1.1.3   misho     366:                if(thread_token != NULL) {
                    367:                        CloseHandle(thread_token);
                    368:                }
1.1       misho     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: {
1.1.1.2   misho     452:        TSRMLS_FETCH();
                    453: 
                    454:        return popen_ex(command, type, NULL, NULL TSRMLS_CC);
1.1       misho     455: }
                    456: 
1.1.1.2   misho     457: TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env TSRMLS_DC)
1.1       misho     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: 
1.1.1.4 ! misho     628:        if (NULL != shm->descriptor && created) {
1.1       misho     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: 
1.1.1.4 ! misho     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:                }
1.1       misho     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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>