diff options
Diffstat (limited to 'TSRM/tsrm_win32.c')
-rw-r--r-- | TSRM/tsrm_win32.c | 188 |
1 files changed, 163 insertions, 25 deletions
diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index dedf05330a..44f6495d58 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -30,7 +30,7 @@ #include "TSRM.h" #ifdef TSRM_WIN32 - +#include <Sddl.h> #include "tsrm_win32.h" #include "tsrm_virtual_cwd.h" @@ -42,25 +42,21 @@ static tsrm_win32_globals win32_globals; static void tsrm_win32_ctor(tsrm_win32_globals *globals TSRMLS_DC) { - HANDLE process_token = NULL; - globals->process = NULL; globals->shm = NULL; globals->process_size = 0; globals->shm_size = 0; globals->comspec = _strdup((GetVersion()<0x80000000)?"cmd.exe":"command.com"); - globals->impersonation_token = NULL; - /* Access check requires impersonation token. Create a duplicate token. */ - if(OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &process_token)) { - DuplicateToken(process_token, SecurityImpersonation, &globals->impersonation_token); - } - - /* impersonation_token will be closed when the process dies */ - if(process_token != NULL) { - CloseHandle(process_token); - process_token = NULL; - } + /* Set it to INVALID_HANDLE_VALUE + * It will be initialized correctly in tsrm_win32_access or set to + * NULL if no impersonation has been done. + * the impersonated token can't be set here as the impersonation + * will happen later, in fcgi_accept_request (or whatever is the + * SAPI being used). + */ + globals->impersonation_token = INVALID_HANDLE_VALUE; + globals->impersonation_token_sid = NULL; } static void tsrm_win32_dtor(tsrm_win32_globals *globals TSRMLS_DC) @@ -83,9 +79,12 @@ static void tsrm_win32_dtor(tsrm_win32_globals *globals TSRMLS_DC) free(globals->comspec); - if(globals->impersonation_token) { + if (globals->impersonation_token && globals->impersonation_token != INVALID_HANDLE_VALUE ) { CloseHandle(globals->impersonation_token); } + if (globals->impersonation_token_sid) { + free(globals->impersonation_token_sid); + } } TSRM_API void tsrm_win32_startup(void) @@ -104,8 +103,97 @@ TSRM_API void tsrm_win32_shutdown(void) #endif } +char * tsrm_win32_get_path_sid_key(const char *pathname TSRMLS_DC) +{ + PSID pSid = TWG(impersonation_token_sid); + DWORD sid_len = pSid ? GetLengthSid(pSid) : 0; + TCHAR *ptcSid = NULL; + char *bucket_key = NULL; + + if (!pSid) { + bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(pathname)); + if (!bucket_key) { + return NULL; + } + memcpy(bucket_key, pathname, strlen(pathname)); + return bucket_key; + } + + if (!ConvertSidToStringSid(pSid, &ptcSid)) { + return NULL; + } + + bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(pathname) + strlen(ptcSid)); + if (!bucket_key) { + LocalFree(ptcSid); + return NULL; + } + + memcpy(bucket_key, ptcSid, strlen(ptcSid)); + memcpy(bucket_key + strlen(ptcSid), pathname, strlen(pathname)); + + LocalFree(ptcSid); + return bucket_key; +} + + +PSID tsrm_win32_get_token_sid(HANDLE hToken) +{ + BOOL bSuccess = FALSE; + DWORD dwLength = 0; + PTOKEN_USER pTokenUser = NULL; + PSID sid; + PSID *ppsid = &sid; + DWORD sid_len; + PSID pResultSid = NULL; + + /* Get the actual size of the TokenUser structure */ + if (!GetTokenInformation( + hToken, TokenUser, (LPVOID) pTokenUser, 0, &dwLength)) { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + goto Finished; + } + + pTokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); + if (pTokenUser == NULL) { + goto Finished; + } + } + + /* and fetch it now */ + if (!GetTokenInformation( + hToken, TokenUser, (LPVOID) pTokenUser, dwLength, &dwLength)) { + goto Finished; + } + + sid_len = GetLengthSid(pTokenUser->User.Sid); + + /* ConvertSidToStringSid(pTokenUser->User.Sid, &ptcSidOwner); */ + pResultSid = malloc(sid_len); + if (!pResultSid) { + goto Finished; + } + if (!CopySid(sid_len, pResultSid, pTokenUser->User.Sid)) { + goto Finished; + } + return pResultSid; + +Finished: + if (pResultSid) { + free(pResultSid); + } + /* Free the buffer for the token groups. */ + if (pTokenUser != NULL) { + HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser); + } + return NULL; +} + TSRM_API int tsrm_win32_access(const char *pathname, int mode) { + time_t t; + HANDLE thread_token; + PSID token_sid; SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS }; DWORD priv_set_length = sizeof(PRIVILEGE_SET); @@ -114,11 +202,10 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode) DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0; BYTE * psec_desc = NULL; BOOL fAccess = FALSE; - HANDLE process_token = NULL; + BOOL bucket_key_alloc = FALSE; realpath_cache_bucket * bucket = NULL; char * real_path = NULL; - time_t t; TSRMLS_FETCH(); @@ -126,10 +213,6 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode) DWORD type; return GetBinaryType(pathname, &type) ? 0 : -1; } else { - if(access(pathname, mode)) { - return errno; - } - if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) { real_path = (char *)malloc(MAX_PATH); if(tsrm_realpath(pathname, real_path TSRMLS_CC) == NULL) { @@ -138,6 +221,58 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode) pathname = real_path; } + if(access(pathname, mode)) { + return errno; + } + + /* If only existence check is made, return now */ + if (mode == 0) { + return 0; + } + +/* Only in NTS when impersonate==1 (aka FastCGI) */ + + /* + AccessCheck() requires an impersonation token. We first get a primary + token and then create a duplicate impersonation token. The + impersonation token is not actually assigned to the thread, but is + used in the call to AccessCheck. Thus, this function itself never + impersonates, but does use the identity of the thread. If the thread + was impersonating already, this function uses that impersonation context. + */ + if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) { + DWORD err = GetLastError(); + if (GetLastError() == ERROR_NO_TOKEN) { + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) { + TWG(impersonation_token) = NULL; + goto Finished; + } + } + } + + /* token_sid will be freed in tsrmwin32_dtor */ + token_sid = tsrm_win32_get_token_sid(thread_token); + if (!token_sid) { + if (TWG(impersonation_token_sid)) { + free(TWG(impersonation_token_sid)); + } + TWG(impersonation_token_sid) = NULL; + goto Finished; + } + + /* Different identity, we need a new impersontated token as well */ + if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) { + if (TWG(impersonation_token_sid)) { + free(TWG(impersonation_token_sid)); + } + TWG(impersonation_token_sid) = token_sid; + + /* Duplicate the token as impersonated token */ + if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) { + goto Finished; + } + } + if (CWDG(realpath_cache_size_limit)) { t = time(0); bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC); @@ -151,7 +286,7 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode) } } } - + /* Do a full access check because access() will only check read-only attribute */ if(mode == 0 || mode > 6) { if(bucket != NULL && bucket->is_rvalid) { @@ -164,7 +299,7 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode) fAccess = bucket->is_writable; goto Finished; } - desired_access = FILE_GENERIC_WRITE; + desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; } else if(mode <= 4) { if(bucket != NULL && bucket->is_rvalid) { fAccess = bucket->is_readable; @@ -194,8 +329,10 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode) goto Finished; } + MapGenericMask(&desired_access, &gen_map); + if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) { - goto Finished; + goto Finished_Impersonate; } /* Keep the result in realpath_cache */ @@ -210,12 +347,13 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode) } } -Finished: +Finished_Impersonate: if(psec_desc != NULL) { free(psec_desc); psec_desc = NULL; } +Finished: if(real_path != NULL) { free(real_path); real_path = NULL; |