]> granicus.if.org Git - php/commitdiff
- Fix ACL support and add support for ACL for TS SAPI. Be sure to get the impersonate...
authorPierre Joye <pajoye@php.net>
Mon, 19 Oct 2009 23:32:07 +0000 (23:32 +0000)
committerPierre Joye <pajoye@php.net>
Mon, 19 Oct 2009 23:32:07 +0000 (23:32 +0000)
TSRM/tsrm_virtual_cwd.c
TSRM/tsrm_win32.c
TSRM/tsrm_win32.h

index 6b84a3bdaf15556c828f35d7e44f09946d05e411..89097892f2eb74c020ae7bfa5e575c56b2bf62b1 100644 (file)
@@ -428,6 +428,31 @@ CWD_API char *virtual_getcwd(char *buf, size_t size TSRMLS_DC) /* {{{ */
 }
 /* }}} */
 
+#ifdef PHP_WIN32
+static inline unsigned long realpath_cache_key(const char *path, int path_len TSRMLS_DC) /* {{{ */
+{
+       register unsigned long h;
+       char *bucket_key = tsrm_win32_get_path_sid_key(path TSRMLS_CC);
+       char *bucket_key_start = (char *)bucket_key;
+       const char *e = bucket_key + strlen(bucket_key);
+
+       if (!bucket_key) {
+               return 0;
+       }
+
+       for (h = 2166136261U; bucket_key < e;) {
+               h *= 16777619;
+               h ^= *bucket_key++;
+       }
+       /* if no SID were present the path is returned. Otherwise a Heap 
+          allocated string is returned. */
+       if (bucket_key_start != path) {
+               LocalFree(bucket_key_start);
+       }
+       return h;
+}
+/* }}} */
+#else
 static inline unsigned long realpath_cache_key(const char *path, int path_len) /* {{{ */
 {
        register unsigned long h;
@@ -441,6 +466,7 @@ static inline unsigned long realpath_cache_key(const char *path, int path_len) /
        return h;
 }
 /* }}} */
+#endif /* defined(PHP_WIN32) */
 
 CWD_API void realpath_cache_clean(TSRMLS_D) /* {{{ */
 {
@@ -461,7 +487,11 @@ CWD_API void realpath_cache_clean(TSRMLS_D) /* {{{ */
 
 CWD_API void realpath_cache_del(const char *path, int path_len TSRMLS_DC) /* {{{ */
 {
+#ifdef PHP_WIN32
+       unsigned long key = realpath_cache_key(path, path_len TSRMLS_CC);
+#else
        unsigned long key = realpath_cache_key(path, path_len);
+#endif
        unsigned long n = key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
        realpath_cache_bucket **bucket = &CWDG(realpath_cache)[n];
 
@@ -494,8 +524,12 @@ static inline void realpath_cache_add(const char *path, int path_len, const char
        if (CWDG(realpath_cache_size) + size <= CWDG(realpath_cache_size_limit)) {
                realpath_cache_bucket *bucket = malloc(size);
                unsigned long n;
-       
+
+#ifdef PHP_WIN32
+               bucket->key = realpath_cache_key(path, path_len TSRMLS_CC);
+#else
                bucket->key = realpath_cache_key(path, path_len);
+#endif
                bucket->path = (char*)bucket + sizeof(realpath_cache_bucket);
                memcpy(bucket->path, path, path_len+1);
                bucket->path_len = path_len;
@@ -524,7 +558,12 @@ static inline void realpath_cache_add(const char *path, int path_len, const char
 
 static inline realpath_cache_bucket* realpath_cache_find(const char *path, int path_len, time_t t TSRMLS_DC) /* {{{ */
 {
+#ifdef PHP_WIN32
+       unsigned long key = realpath_cache_key(path, path_len TSRMLS_CC);
+#else
        unsigned long key = realpath_cache_key(path, path_len);
+#endif
+
        unsigned long n = key % (sizeof(CWDG(realpath_cache)) / sizeof(CWDG(realpath_cache)[0]));
        realpath_cache_bucket **bucket = &CWDG(realpath_cache)[n];
 
@@ -670,7 +709,6 @@ static int tsrm_realpath_r(char *path, int start, int len, int *ll, time_t *t, i
                        unsigned int retlength = 0, rname_off = 0;
                        int bufindex = 0, rname_len = 0, isabsolute = 0;
                        wchar_t * reparsetarget;
-                       WCHAR szVolumePathNames[MAX_PATH];
                        BOOL isVolume = FALSE;
 
                        if(++(*ll) > LINK_MAX) {
index 2a8503e82c776b9cf232198170e9e4ff79bcf09f..49541e8d75e177351177fcac8842685afbe9f99c 100644 (file)
 #include <errno.h>
 
 #define TSRM_INCLUDE_FULL_WINDOWS_HEADERS
-
 #include "SAPI.h"
 #include "TSRM.h"
 
 #ifdef TSRM_WIN32
-
+#include <Sddl.h>
 #include "tsrm_win32.h"
 #include "tsrm_virtual_cwd.h"
 
@@ -43,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)
@@ -84,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)
@@ -105,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);
@@ -115,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();
 
@@ -127,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) {
@@ -139,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);
@@ -152,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) {
@@ -165,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;
@@ -195,13 +329,15 @@ 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 */
                if(bucket != NULL) {
-                       if(desired_access == (FILE_GENERIC_READ | FILE_FLAG_BACKUP_SEMANTICS)) {
+                       if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
                                bucket->is_rvalid = 1;
                                bucket->is_readable = fAccess;
                        }
@@ -211,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;
@@ -381,7 +518,6 @@ TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd,
                if (err == ERROR_NO_TOKEN) {
                        asuser = FALSE;
                }
-
        }
 
        cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
index e41db0327ad5872a1d01aec8c0860cb417866025..989da42ded4e79ac097cae4c312f919a0bcc0808 100644 (file)
@@ -64,6 +64,7 @@ typedef struct {
        int                             shm_size;
        char                    *comspec;
        HANDLE impersonation_token;
+       PSID                    impersonation_token_sid;
 } tsrm_win32_globals;
 
 #ifdef ZTS
@@ -89,6 +90,7 @@ typedef struct {
 #define        SHM_RND         FILE_MAP_WRITE
 #define        SHM_REMAP       FILE_MAP_COPY
 
+char * tsrm_win32_get_path_sid_key(const char *pathname  TSRMLS_DC);
 
 TSRM_API void tsrm_win32_startup(void);
 TSRM_API void tsrm_win32_shutdown(void);