]> granicus.if.org Git - php/commitdiff
Improve ioutil access impl and refactor tsrm_win32_access
authorAnatol Belski <ab@php.net>
Fri, 8 Dec 2017 15:35:45 +0000 (16:35 +0100)
committerAnatol Belski <ab@php.net>
Fri, 8 Dec 2017 19:58:19 +0000 (20:58 +0100)
TSRM/tsrm_win32.c
win32/ioutil.c
win32/ioutil.h

index 039fef7cc20686c48b99f08b41623809ea3de74c..43d9f8e57291e470f4c51e694fd4ff55c6b01d4d 100644 (file)
@@ -209,190 +209,175 @@ TSRM_API int tsrm_win32_access(const char *pathname, int mode)
        realpath_cache_bucket * bucket = NULL;
        char * real_path = NULL;
 
+       if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
+               real_path = (char *)malloc(MAXPATHLEN);
+               if(tsrm_realpath(pathname, real_path) == NULL) {
+                       SET_ERRNO_FROM_WIN32_CODE(ERROR_FILE_NOT_FOUND);
+                       return -1;
+               }
+               pathname = real_path;
+       }
+
        PHP_WIN32_IOUTIL_INIT_W(pathname)
        if (!pathw) {
+               free(real_path);
                return -1;
        }
 
-       if (mode == 1 /*X_OK*/) {
-               DWORD type;
-               int ret;
-
-               ret = GetBinaryTypeW(pathw, &type) ? 0 : -1;
-
+       /* Either access call failed, or the mode was asking for a specific check.*/
+       int ret = php_win32_ioutil_access_w(pathw, mode);
+       if (0 > ret || X_OK == mode || F_OK == mode) {
                PHP_WIN32_IOUTIL_CLEANUP_W()
-
+               free(real_path);
                return ret;
-       } else {
-               if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
-                       real_path = (char *)malloc(MAXPATHLEN);
-                       if(tsrm_realpath(pathname, real_path) == NULL) {
-                               goto Finished;
-                       }
-                       pathname = real_path;
-                       PHP_WIN32_IOUTIL_REINIT_W(pathname);
-               }
-
-               if(php_win32_ioutil_access(pathname, mode)) {
-                       PHP_WIN32_IOUTIL_CLEANUP_W()
-                       free(real_path);
-                       return errno;
-               }
-
-               /* If only existence check is made, return now */
-               if (mode == 0) {
-                       PHP_WIN32_IOUTIL_CLEANUP_W()
-                       free(real_path);
-                       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)) {
-                       if (GetLastError() == ERROR_NO_TOKEN) {
-                               if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
-                                        TWG(impersonation_token) = NULL;
-                                        goto Finished;
-                                }
-                       }
+       /*
+        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)) {
+               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;
+       /* 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;
-                       }
-               } else {
-                       /* we already have it, free it then */
-                       free(token_sid);
+       /* 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;
 
-               if (CWDG(realpath_cache_size_limit)) {
-                       t = time(0);
-                       bucket = realpath_cache_lookup(pathname, strlen(pathname), t);
-                       if(bucket == NULL && real_path == NULL) {
-                               /* We used the pathname directly. Call tsrm_realpath */
-                               /* so that entry is created in realpath cache */
-                               real_path = (char *)malloc(MAXPATHLEN);
-                               if(tsrm_realpath(pathname, real_path) != NULL) {
-                                       pathname = real_path;
-                                       bucket = realpath_cache_lookup(pathname, strlen(pathname), t);
-                                       PHP_WIN32_IOUTIL_REINIT_W(pathname);
-                               }
-                       }
-               }
+               /* Duplicate the token as impersonated token */
+               if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
+                       goto Finished;
+               }
+       } else {
+               /* we already have it, free it then */
+               free(token_sid);
+       }
 
-               /* Do a full access check because access() will only check read-only attribute */
-               if(mode == 0 || mode > 6) {
-                       if(bucket != NULL && bucket->is_rvalid) {
-                               fAccess = bucket->is_readable;
-                               goto Finished;
-                       }
-                       desired_access = FILE_GENERIC_READ;
-               } else if(mode <= 2) {
-                       if(bucket != NULL && bucket->is_wvalid) {
-                               fAccess = bucket->is_writable;
-                               goto Finished;
-                       }
-                       desired_access = FILE_GENERIC_WRITE;
-               } else if(mode <= 4) {
-                       if(bucket != NULL && bucket->is_rvalid) {
-                               fAccess = bucket->is_readable;
-                               goto Finished;
-                       }
-                       desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
-               } else { // if(mode <= 6)
-                       if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
-                               fAccess = bucket->is_readable & bucket->is_writable;
-                               goto Finished;
+       if (CWDG(realpath_cache_size_limit)) {
+               t = time(0);
+               bucket = realpath_cache_lookup(pathname, strlen(pathname), t);
+               if(bucket == NULL && real_path == NULL) {
+                       /* We used the pathname directly. Call tsrm_realpath */
+                       /* so that entry is created in realpath cache */
+                       real_path = (char *)malloc(MAXPATHLEN);
+                       if(tsrm_realpath(pathname, real_path) != NULL) {
+                               pathname = real_path;
+                               bucket = realpath_cache_lookup(pathname, strlen(pathname), t);
+                               PHP_WIN32_IOUTIL_REINIT_W(pathname);
                        }
-                       desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
-               }
+               }
+       }
 
-               if(TWG(impersonation_token) == NULL) {
+       /* Do a full access check because access() will only check read-only attribute */
+       if(mode == 0 || mode > 6) {
+               if(bucket != NULL && bucket->is_rvalid) {
+                       fAccess = bucket->is_readable;
                        goto Finished;
                }
-
-               /* Get size of security buffer. Call is expected to fail */
-               if(GetFileSecurityW(pathw, sec_info, NULL, 0, &sec_desc_length)) {
+               desired_access = FILE_GENERIC_READ;
+       } else if(mode <= 2) {
+               if(bucket != NULL && bucket->is_wvalid) {
+                       fAccess = bucket->is_writable;
                        goto Finished;
                }
-
-               psec_desc = (BYTE *)malloc(sec_desc_length);
-               if(psec_desc == NULL ||
-                        !GetFileSecurityW(pathw, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
+               desired_access = FILE_GENERIC_WRITE;
+       } else if(mode <= 4) {
+               if(bucket != NULL && bucket->is_rvalid) {
+                       fAccess = bucket->is_readable;
+                       goto Finished;
+               }
+               desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
+       } else { // if(mode <= 6)
+               if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
+                       fAccess = bucket->is_readable & bucket->is_writable;
                        goto Finished;
                }
+               desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
+       }
 
-               MapGenericMask(&desired_access, &gen_map);
+       if(TWG(impersonation_token) == NULL) {
+               goto Finished;
+       }
 
-               if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
-                       goto Finished_Impersonate;
-               }
+       /* Get size of security buffer. Call is expected to fail */
+       if(GetFileSecurityW(pathw, sec_info, NULL, 0, &sec_desc_length)) {
+               goto Finished;
+       }
 
-               /* Keep the result in realpath_cache */
-               if(bucket != NULL) {
-                       if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
-                               bucket->is_rvalid = 1;
-                               bucket->is_readable = fAccess;
-                       }
-                       else if(desired_access == FILE_GENERIC_WRITE) {
-                               bucket->is_wvalid = 1;
-                               bucket->is_writable = fAccess;
-                       } else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
-                               bucket->is_rvalid = 1;
-                               bucket->is_readable = fAccess;
-                               bucket->is_wvalid = 1;
-                               bucket->is_writable = fAccess;
-                       }
+       psec_desc = (BYTE *)malloc(sec_desc_length);
+       if(psec_desc == NULL ||
+                !GetFileSecurityW(pathw, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
+               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_Impersonate;
+       }
+
+       /* Keep the result in realpath_cache */
+       if(bucket != NULL) {
+               if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
+                       bucket->is_rvalid = 1;
+                       bucket->is_readable = fAccess;
                }
+               else if(desired_access == FILE_GENERIC_WRITE) {
+                       bucket->is_wvalid = 1;
+                       bucket->is_writable = fAccess;
+               } else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
+                       bucket->is_rvalid = 1;
+                       bucket->is_readable = fAccess;
+                       bucket->is_wvalid = 1;
+                       bucket->is_writable = fAccess;
+               }
+       }
 
 Finished_Impersonate:
-               if(psec_desc != NULL) {
-                       free(psec_desc);
-                       psec_desc = NULL;
-               }
+       if(psec_desc != NULL) {
+               free(psec_desc);
+               psec_desc = NULL;
+       }
 
 Finished:
-               if(thread_token != NULL) {
-                       CloseHandle(thread_token);
-               }
-               if(real_path != NULL) {
-                       free(real_path);
-                       real_path = NULL;
-               }
+       if(thread_token != NULL) {
+               CloseHandle(thread_token);
+       }
+       if(real_path != NULL) {
+               free(real_path);
+               real_path = NULL;
+       }
 
-               PHP_WIN32_IOUTIL_CLEANUP_W()
-               if(fAccess == FALSE) {
-                       errno = EACCES;
-                       return errno;
-               } else {
-                       return 0;
-               }
+       PHP_WIN32_IOUTIL_CLEANUP_W()
+       if(fAccess == FALSE) {
+               errno = EACCES;
+               return errno;
+       } else {
+               return 0;
        }
 }/*}}}*/
 
index 7f1f75845638968385462dbfbbf3278307471e8b..4c4e60d5d1f0319e77512904b7ec956e07a5d53f 100644 (file)
@@ -655,13 +655,33 @@ BOOL php_win32_ioutil_init(void)
        return TRUE;
 }/*}}}*/
 
-/* an extended version could be implemented, for now direct functions can be used. */
-#if 0
 PW32IO int php_win32_ioutil_access_w(const wchar_t *path, mode_t mode)
-{
-       return _waccess(path, mode);
-}
-#endif
+{/*{{{*/
+       DWORD attr, err;
+
+       if ((mode & X_OK) == X_OK) {
+               DWORD type;
+               return GetBinaryTypeW(path, &type) ? 0 : -1;
+       }
+
+       attr = GetFileAttributesW(path);
+       if (attr == INVALID_FILE_ATTRIBUTES) {
+               err = GetLastError();
+               SET_ERRNO_FROM_WIN32_CODE(err);
+               return -1;
+       }
+
+       if (F_OK == mode) {
+               return 0;
+       }
+
+       if ((mode &W_OK) == W_OK && (attr & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) {
+               SET_ERRNO_FROM_WIN32_CODE(ERROR_ACCESS_DENIED);
+               return -1;
+       }
+
+       return 0;
+}/*}}}*/
 
 #if 0
 PW32IO HANDLE php_win32_ioutil_findfirstfile_w(char *path, WIN32_FIND_DATA *data)
index 5d06fd194082a4667ae07f37a9896a97436c8899..5e661fc096202f0d57f3f748656912eebfd84660 100644 (file)
@@ -242,6 +242,7 @@ PW32IO int php_win32_ioutil_chdir_w(const wchar_t *path);
 PW32IO int php_win32_ioutil_rename_w(const wchar_t *oldname, const wchar_t *newname);
 PW32IO wchar_t *php_win32_ioutil_getcwd_w(wchar_t *buf, size_t len);
 PW32IO int php_win32_ioutil_unlink_w(const wchar_t *path);
+PW32IO int php_win32_ioutil_access_w(const wchar_t *path, mode_t mode);
 
 #if 0
 PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode);
@@ -264,14 +265,14 @@ __forceinline static int php_win32_ioutil_access(const char *path, mode_t mode)
 
        PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
 
-       ret = _waccess(pathw, mode);
+       ret = php_win32_ioutil_access_w(pathw, mode);
        if (0 > ret) {
-               _get_errno(&err);
+               err = GetLastError();
        }
        PHP_WIN32_IOUTIL_CLEANUP_W()
 
        if (0 > ret) {
-               _set_errno(err);
+               SET_ERRNO_FROM_WIN32_CODE(err);
        }
 
        return ret;