# HG changeset patch # User uta # Date 1363166522 -14400 # Node ID 81d282e3cdaf41eb6975c8829f83101e4e25349c # Parent 36055e4b5305230c9355a2b9f914f1b8fe7a6749 7190897: (fs) Files.isWritable method returns false when the path is writable (win) Summary: The [GetEffectiveRightsFromAcl] based implementation was changed to the [AccessCheck] based. Reviewed-by: alanb diff -r 36055e4b5305 -r 81d282e3cdaf jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java Tue Mar 12 15:31:49 2013 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java Wed Mar 13 13:22:02 2013 +0400 @@ -181,6 +181,11 @@ public static final int FILE_READ_ATTRIBUTES = 0x0080; public static final int FILE_WRITE_ATTRIBUTES = 0x0100; + public static final int FILE_GENERIC_READ = 0x00120089; + public static final int FILE_GENERIC_WRITE = 0x00120116; + public static final int FILE_GENERIC_EXECUTE = 0x001200a0; + public static final int FILE_ALL_ACCESS = 0x001f01ff; + // operating system security public static final int TOKEN_DUPLICATE = 0x0002; public static final int TOKEN_IMPERSONATE = 0x0004; diff -r 36055e4b5305 -r 81d282e3cdaf jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java Tue Mar 12 15:31:49 2013 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java Wed Mar 13 13:22:02 2013 +0400 @@ -38,6 +38,7 @@ import sun.security.util.SecurityConstants; import static sun.nio.fs.WindowsNativeDispatcher.*; +import static sun.nio.fs.WindowsSecurity.*; import static sun.nio.fs.WindowsConstants.*; public class WindowsFileSystemProvider @@ -289,67 +290,29 @@ } /** - * Returns buffer with SID_AND_ATTRIBUTES structure representing the user - * associated with the current thread access token. - * FIXME - this should be cached. + * Checks the file security against desired access. */ - private static NativeBuffer getUserInfo(WindowsPath file) throws IOException { - try { - long hToken = WindowsSecurity.processTokenWithQueryAccess; - int size = GetTokenInformation(hToken, TokenUser, 0L, 0); - assert size > 0; - - NativeBuffer buffer = NativeBuffers.getNativeBuffer(size); - try { - int newsize = GetTokenInformation(hToken, TokenUser, - buffer.address(), size); - if (newsize != size) - throw new AssertionError(); - return buffer; - } catch (WindowsException x) { - buffer.release(); - throw x; - } - } catch (WindowsException x) { - throw new IOException(x.getMessage()); - } - } - - /** - * Reads the file ACL and return the effective access as ACCESS_MASK - */ - private static int getEffectiveAccess(WindowsPath file) throws IOException { - // read security descriptor continaing ACL (symlinks are followed) + private static boolean hasDesiredAccess(WindowsPath file, int rights) throws IOException { + // read security descriptor containing ACL (symlinks are followed) + boolean hasRights = false; String target = WindowsLinkSupport.getFinalPath(file, true); NativeBuffer aclBuffer = WindowsAclFileAttributeView - .getFileSecurity(target, DACL_SECURITY_INFORMATION); - - // retrieves DACL from security descriptor - long pAcl = GetSecurityDescriptorDacl(aclBuffer.address()); - - // Use GetEffectiveRightsFromAcl to get effective access to file + .getFileSecurity(target, + DACL_SECURITY_INFORMATION + | OWNER_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION); try { - NativeBuffer userBuffer = getUserInfo(file); - try { - try { - // SID_AND_ATTRIBUTES->pSid - long pSid = unsafe.getAddress(userBuffer.address()); - long pTrustee = BuildTrusteeWithSid(pSid); - try { - return GetEffectiveRightsFromAcl(pAcl, pTrustee); - } finally { - LocalFree(pTrustee); - } - } catch (WindowsException x) { - throw new IOException("Unable to get effective rights from ACL: " + - x.getMessage()); - } - } finally { - userBuffer.release(); - } + hasRights = checkAccessMask(aclBuffer.address(), rights, + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_ALL_ACCESS); + } catch (WindowsException exc) { + exc.rethrowAsIOException(file); } finally { aclBuffer.release(); } + return hasRights; } /** @@ -416,10 +379,10 @@ mask |= FILE_EXECUTE; } - if ((getEffectiveAccess(file) & mask) == 0) + if (!hasDesiredAccess(file, mask)) throw new AccessDeniedException( file.getPathForExceptionMessage(), null, - "Effective permissions does not allow requested access"); + "Permissions does not allow requested access"); // for write access we neeed to check if the DOS readonly attribute // and if the volume is read-only @@ -438,7 +401,6 @@ throw new AccessDeniedException( file.getPathForExceptionMessage(), null, "Read-only file system"); } - return; } } diff -r 36055e4b5305 -r 81d282e3cdaf jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Tue Mar 12 15:31:49 2013 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Wed Mar 13 13:22:02 2013 +0400 @@ -844,6 +844,23 @@ static native void AdjustTokenPrivileges(long token, long luid, int attributes) throws WindowsException; + + /** + * AccessCheck( + * PSECURITY_DESCRIPTOR pSecurityDescriptor, + * HANDLE ClientToken, + * DWORD DesiredAccess, + * PGENERIC_MAPPING GenericMapping, + * PPRIVILEGE_SET PrivilegeSet, + * LPDWORD PrivilegeSetLength, + * LPDWORD GrantedAccess, + * LPBOOL AccessStatus + * ) + */ + static native boolean AccessCheck(long token, long securityInfo, int accessMask, + int genericRead, int genericWrite, int genericExecute, int genericAll) + throws WindowsException; + /** */ static long LookupPrivilegeValue(String name) throws WindowsException { @@ -858,28 +875,6 @@ throws WindowsException; /** - * BuildTrusteeWithSid( - * PTRUSTEE pTrustee, - * PSID pSid - * ) - * - * @return pTrustee - */ - static native long BuildTrusteeWithSid(long pSid); - - /** - * GetEffectiveRightsFromAcl( - * PACL pacl, - * PTRUSTEE pTrustee, - * PACCESS_MASK pAccessRights - * ) - * - * @return AccessRights - */ - static native int GetEffectiveRightsFromAcl(long pAcl, long pTrustee) - throws WindowsException; - - /** * CreateSymbolicLink( * LPCWSTR lpSymlinkFileName, * LPCWSTR lpTargetFileName, diff -r 36055e4b5305 -r 81d282e3cdaf jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java Tue Mar 12 15:31:49 2013 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java Wed Mar 13 13:22:02 2013 +0400 @@ -105,19 +105,46 @@ return new Privilege() { @Override public void drop() { - try { - if (stopImpersontating) { - SetThreadToken(0L, 0L); - } else { - if (needToRevert) { + if (token != 0L) { + try { + if (stopImpersontating) + SetThreadToken(0L, 0L); + else if (needToRevert) AdjustTokenPrivileges(token, pLuid, 0); - } + } catch (WindowsException x) { + // should not happen + throw new AssertionError(x); + } finally { + CloseHandle(token); } - } catch (WindowsException x) { - // should not happen - throw new AssertionError(x); } } }; } + + /** + * Check the access right against the securityInfo in the current thread. + */ + static boolean checkAccessMask(long securityInfo, int accessMask, + int genericRead, int genericWrite, int genericExecute, int genericAll) + throws WindowsException + { + int privilegies = TOKEN_QUERY; + long hToken = OpenThreadToken(GetCurrentThread(), privilegies, false); + if (hToken == 0L && processTokenWithDuplicateAccess != 0L) + hToken = DuplicateTokenEx(processTokenWithDuplicateAccess, + privilegies); + + boolean hasRight = false; + if (hToken != 0L) { + try { + hasRight = AccessCheck(hToken, securityInfo, accessMask, + genericRead, genericWrite, genericExecute, genericAll); + } finally { + CloseHandle(hToken); + } + } + return hasRight; + } + } diff -r 36055e4b5305 -r 81d282e3cdaf jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c --- a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c Tue Mar 12 15:31:49 2013 -0700 +++ b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c Wed Mar 13 13:22:02 2013 +0400 @@ -1021,6 +1021,33 @@ throwWindowsException(env, GetLastError()); } +JNIEXPORT jboolean JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_AccessCheck(JNIEnv* env, + jclass this, jlong token, jlong securityInfo, jint accessMask, + jint genericRead, jint genericWrite, jint genericExecute, jint genericAll) +{ + HANDLE hImpersonatedToken = (HANDLE)jlong_to_ptr(token); + PSECURITY_DESCRIPTOR security = (PSECURITY_DESCRIPTOR)jlong_to_ptr(securityInfo); + DWORD checkAccessRights = (DWORD)accessMask; + GENERIC_MAPPING mapping = { + genericRead, + genericWrite, + genericExecute, + genericAll}; + PRIVILEGE_SET privileges = {0}; + DWORD privilegesLength = sizeof(privileges); + DWORD grantedAccess = 0; + BOOL result = FALSE; + + /* checkAccessRights is in-out parameter */ + MapGenericMask(&checkAccessRights, &mapping); + if (AccessCheck(security, hImpersonatedToken, checkAccessRights, + &mapping, &privileges, &privilegesLength, &grantedAccess, &result) == 0) + throwWindowsException(env, GetLastError()); + + return (result == FALSE) ? JNI_FALSE : JNI_TRUE; +} + JNIEXPORT jlong JNICALL Java_sun_nio_fs_WindowsNativeDispatcher_LookupPrivilegeValue0(JNIEnv* env, jclass this, jlong name) @@ -1037,35 +1064,6 @@ return ptr_to_jlong(pLuid); } -JNIEXPORT jlong JNICALL -Java_sun_nio_fs_WindowsNativeDispatcher_BuildTrusteeWithSid(JNIEnv* env, - jclass this, jlong sid) -{ - PSID pSid = (HANDLE)jlong_to_ptr(sid); - PTRUSTEE_W pTrustee = LocalAlloc(0, sizeof(TRUSTEE_W)); - - if (pTrustee == NULL) { - JNU_ThrowInternalError(env, "Unable to allocate TRUSTEE_W structure"); - } else { - BuildTrusteeWithSidW(pTrustee, pSid); - } - return ptr_to_jlong(pTrustee); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_fs_WindowsNativeDispatcher_GetEffectiveRightsFromAcl(JNIEnv* env, - jclass this, jlong acl, jlong trustee) -{ - ACCESS_MASK access; - PACL pAcl = (PACL)jlong_to_ptr(acl); - PTRUSTEE pTrustee = (PTRUSTEE)jlong_to_ptr(trustee); - - if (GetEffectiveRightsFromAcl(pAcl, pTrustee, &access) != ERROR_SUCCESS) { - throwWindowsException(env, GetLastError()); - } - return (jint)access; -} - JNIEXPORT void JNICALL Java_sun_nio_fs_WindowsNativeDispatcher_CreateSymbolicLink0(JNIEnv* env, jclass this, jlong linkAddress, jlong targetAddress, jint flags)