Merge pull request #301 from BusyByte/master

Added Advapi32Util accessCheck method to verify file permissions
Esse commit está contido em:
Daniel Doubrovkine (dB.)
2014-01-22 14:35:06 -08:00
6 arquivos alterados com 317 adições e 2 exclusões
+1
Ver Arquivo
@@ -18,6 +18,7 @@ Features
* [#250](https://github.com/twall/jna/pull/250): Added `com.sun.jna.platform.win32.Kernel32.GetPrivateProfileSection`, `GetPrivateProfileSectionNames` and `WritePrivateProfileSection` and corresponding `Kernel32Util` helpers - [@quipsy-karg](https://github.com/quipsy-karg).
* [#287](https://github.com/twall/jna/pull/287): Added `DBTF_MEDIA` and `DBTF_NET` to `com.sun.jna.platform.win32.DBT` - [@daifei4321](https://github.com/daifei4321).
* [#295](https://github.com/twall/jna/pull/295): Added `com.sun.jna.platform.win32.Kernel32.ResetEvent` - [@manithree](https://github.com/manithree).
* [#301](https://github.com/twall/jna/pull/301): Added `accessCheck` to `com.sun.jna.platform.win32.Advapi32Util`, `MapGenericMask` and `AccessCheck` to `com.sun.jna.platform.win32.Advapi32`, `PRIVILEGE_SET` and `GENERIC_MAPPING` to `com.sun.jna.platform.win32.WinNT` - [@BusyByte](https://github.com/BusyByte).
Bug Fixes
---------
@@ -32,6 +32,12 @@ import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import static com.sun.jna.platform.win32.WinDef.BOOLByReference;
import static com.sun.jna.platform.win32.WinDef.DWORD;
import static com.sun.jna.platform.win32.WinDef.DWORDByReference;
import static com.sun.jna.platform.win32.WinNT.GENERIC_MAPPING;
import static com.sun.jna.platform.win32.WinNT.PRIVILEGE_SET;
/**
* Advapi32.dll Interface.
*
@@ -1523,4 +1529,33 @@ public interface Advapi32 extends StdCallLibrary {
int RequestedInformation, Pointer pointer, int nLength,
IntByReference lpnLengthNeeded);
/**
* Applies the given mapping of generic access rights to the given access mask.
* @param AccessMask [in, out] A pointer to an access mask.
* @param GenericMapping [in] A pointer to a GENERIC_MAPPING structure specifying a mapping of generic access types to specific and standard access types.
*/
public void MapGenericMask(DWORDByReference AccessMask, GENERIC_MAPPING GenericMapping);
/**
* Check if the if the security descriptor grants access to the given client token.
*
* @param pSecurityDescriptor [in] A pointer to a SECURITY_DESCRIPTOR structure against which access is checked.
* @param ClientToken [in] A handle to an impersonation token that represents the client that is attempting to gain access. The handle must have TOKEN_QUERY access to the token; otherwise, the function fails with ERROR_ACCESS_DENIED.
* @param DesiredAccess [in] Access mask that specifies the access rights to check. This mask must have been mapped by the MapGenericMask function to contain no generic access rights.<br>
* If this parameter is MAXIMUM_ALLOWED, the function sets the GrantedAccess access mask to indicate the maximum access rights the security descriptor allows the client.
* @param GenericMapping [in] A pointer to the GENERIC_MAPPING structure associated with the object for which access is being checked.
* @param PrivilegeSet [out, optional] A pointer to a PRIVILEGE_SET structure that receives the privileges used to perform the access validation. If no privileges were used, the function sets the PrivilegeCount member to zero.
* @param PrivilegeSetLength [in, out] Specifies the size, in bytes, of the buffer pointed to by the PrivilegeSet parameter.
* @param GrantedAccess [out] A pointer to an access mask that receives the granted access rights. If AccessStatus is set to FALSE, the function sets the access mask to zero. If the function fails, it does not set the access mask.
* @param AccessStatus [out] A pointer to a variable that receives the results of the access check. If the security descriptor allows the requested access rights to the client identified by the access token, AccessStatus is set to TRUE. Otherwise, AccessStatus is set to FALSE, and you can call GetLastError to get extended error information.
* @return true on success; false on failure (use GetLastError to get extended error information)
*/
public boolean AccessCheck(Pointer pSecurityDescriptor,
HANDLE ClientToken, DWORD DesiredAccess,
GENERIC_MAPPING GenericMapping,
PRIVILEGE_SET PrivilegeSet,
DWORDByReference PrivilegeSetLength,
DWORDByReference GrantedAccess, BOOLByReference AccessStatus);
}
@@ -12,6 +12,7 @@
*/
package com.sun.jna.platform.win32;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -40,6 +41,12 @@ import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.LongByReference;
import com.sun.jna.ptr.PointerByReference;
import static com.sun.jna.platform.win32.WinDef.BOOLByReference;
import static com.sun.jna.platform.win32.WinDef.DWORD;
import static com.sun.jna.platform.win32.WinDef.DWORDByReference;
import static com.sun.jna.platform.win32.WinNT.*;
/**
* Advapi32 utility API.
*
@@ -81,6 +88,7 @@ public abstract class Advapi32Util {
public String fqn;
}
/**
* Retrieves the name of the user associated with the current thread.
*
@@ -430,14 +438,14 @@ public abstract class Advapi32Util {
// open thread or process token
HANDLE threadHandle = Kernel32.INSTANCE.GetCurrentThread();
if (!Advapi32.INSTANCE.OpenThreadToken(threadHandle,
WinNT.TOKEN_DUPLICATE | WinNT.TOKEN_QUERY, true, phToken)) {
TOKEN_DUPLICATE | TOKEN_QUERY, true, phToken)) {
if (W32Errors.ERROR_NO_TOKEN != Kernel32.INSTANCE
.GetLastError()) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
HANDLE processHandle = Kernel32.INSTANCE.GetCurrentProcess();
if (!Advapi32.INSTANCE.OpenProcessToken(processHandle,
WinNT.TOKEN_DUPLICATE | WinNT.TOKEN_QUERY, phToken)) {
TOKEN_DUPLICATE | TOKEN_QUERY, phToken)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
}
@@ -2062,4 +2070,119 @@ public abstract class Advapi32Util {
}
return aceStructures;
}
public static enum AccessCheckPermission {
READ(GENERIC_READ),
WRITE(GENERIC_WRITE),
EXECUTE(GENERIC_EXECUTE);
final int code;
AccessCheckPermission(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
private static Memory getSecurityDescriptorForFile(final String absoluteFilePath) {
final int infoType = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION;
final IntByReference lpnSize = new IntByReference();
boolean succeeded = Advapi32.INSTANCE.GetFileSecurity(
new WString(absoluteFilePath),
infoType,
null,
0, lpnSize);
if (!succeeded) {
final int lastError = Kernel32.INSTANCE.GetLastError();
if (W32Errors.ERROR_INSUFFICIENT_BUFFER != lastError) {
throw new Win32Exception(lastError);
}
}
final int nLength = lpnSize.getValue();
final Memory securityDescriptorMemoryPointer = new Memory(nLength);
succeeded = Advapi32.INSTANCE.GetFileSecurity(new WString(
absoluteFilePath), infoType, securityDescriptorMemoryPointer, nLength, lpnSize);
if (!succeeded) {
securityDescriptorMemoryPointer.clear();
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
return securityDescriptorMemoryPointer;
}
/**
* Checks if the current process has the given permission for the file.
* @param file the file to check
* @param permissionToCheck the permission to check for the file
* @return true if has access, otherwise false
*/
public static boolean accessCheck(File file, AccessCheckPermission permissionToCheck) {
boolean hasAccess = false;
final Memory securityDescriptorMemoryPointer = getSecurityDescriptorForFile(file.getAbsolutePath().replaceAll("/", "\\"));
HANDLEByReference openedAccessToken = null;
final HANDLEByReference duplicatedToken = new HANDLEByReference();
try{
openedAccessToken = new HANDLEByReference();
final int desireAccess = TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ;
if(!Advapi32.INSTANCE.OpenProcessToken(Kernel32.INSTANCE.GetCurrentProcess(), desireAccess, openedAccessToken)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
if(!Advapi32.INSTANCE.DuplicateToken(openedAccessToken.getValue(), SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, duplicatedToken)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
final GENERIC_MAPPING mapping = new GENERIC_MAPPING();
mapping.genericRead = new DWORD(FILE_GENERIC_READ);
mapping.genericWrite = new DWORD(FILE_GENERIC_WRITE);
mapping.genericExecute = new DWORD(FILE_GENERIC_EXECUTE);
mapping.genericAll = new DWORD(FILE_ALL_ACCESS);
final DWORDByReference rights = new DWORDByReference(new DWORD(permissionToCheck.getCode()));
Advapi32.INSTANCE.MapGenericMask(rights, mapping);
final PRIVILEGE_SET privileges = new PRIVILEGE_SET(1);
privileges.PrivilegeCount = new DWORD(0);
final DWORDByReference privilegeLength = new DWORDByReference(new DWORD(privileges.size()));
final DWORDByReference grantedAccess = new DWORDByReference();
final BOOLByReference result = new BOOLByReference();
if(!Advapi32.INSTANCE.AccessCheck(securityDescriptorMemoryPointer,
duplicatedToken.getValue(),
rights.getValue(),
mapping,
privileges, privilegeLength, grantedAccess, result)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
hasAccess = result.getValue().booleanValue();
} finally {
if(openedAccessToken != null && openedAccessToken.getValue() != null) {
Kernel32.INSTANCE.CloseHandle(openedAccessToken.getValue());
}
if(duplicatedToken != null && duplicatedToken.getValue() != null) {
Kernel32.INSTANCE.CloseHandle(duplicatedToken.getValue());
}
if(securityDescriptorMemoryPointer != null) {
securityDescriptorMemoryPointer.clear();
}
}
return hasAccess;
}
}
@@ -453,6 +453,46 @@ public interface WinNT extends WinError, WinDef, WinBase, BaseTSD {
}
}
/**
* Specifies a set of privileges. <br>
* It is also used to indicate which, if any, privileges are held by a user or group requesting access to an object.
*/
public static class PRIVILEGE_SET extends Structure {
public DWORD PrivilegeCount;
public DWORD Control;
public LUID_AND_ATTRIBUTES Privileges[];
@Override
protected List getFieldOrder() {
return Arrays.asList("PrivilegeCount", "Control", "Privileges");
}
public PRIVILEGE_SET() {
this(0);
}
/**
* @param nbOfPrivileges
* Desired size of the Privileges array
*/
public PRIVILEGE_SET(int nbOfPrivileges) {
PrivilegeCount = new DWORD(nbOfPrivileges);
if(nbOfPrivileges > 0) {
Privileges = new LUID_AND_ATTRIBUTES[nbOfPrivileges];
}
}
/** Initialize a TOKEN_PRIVILEGES instance from initialized memory. */
public PRIVILEGE_SET(Pointer p) {
super(p);
final int count = p.getInt(0);
PrivilegeCount = new DWORD(count);
if(count > 0) {
Privileges = new LUID_AND_ATTRIBUTES[count];
}
read();
}
}
/**
* The TOKEN_PRIVILEGES structure contains information about a set of
* privileges for an access token.
@@ -2176,6 +2216,25 @@ public interface WinNT extends WinError, WinDef, WinBase, BaseTSD {
WinBase.OVERLAPPED overlapped);
}
/**
* Defines the mapping of generic access rights to specific and standard access rights for an object
*/
public static class GENERIC_MAPPING extends Structure {
public static class ByReference extends GENERIC_MAPPING implements Structure.ByReference {
}
public DWORD genericRead;
public DWORD genericWrite;
public DWORD genericExecute;
public DWORD genericAll;
@Override
protected List getFieldOrder() {
return Arrays.asList("genericRead", "genericWrite", "genericExecute", "genericAll");
}
}
/**
* Describes the relationship between the specified processor set. This structure is used with the
* {@link Kernel32#GetLogicalProcessorInformation} function.
@@ -41,6 +41,8 @@ import com.sun.jna.platform.win32.Winsvc.SERVICE_STATUS_PROCESS;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import static com.sun.jna.platform.win32.WinNT.*;
/**
* @author dblock[at]dblock[dot]org
*/
@@ -826,4 +828,82 @@ public class Advapi32Test extends TestCase {
assertTrue(Advapi32.INSTANCE.ImpersonateSelf(WinNT.SECURITY_IMPERSONATION_LEVEL.SecurityAnonymous));
assertTrue(Advapi32.INSTANCE.RevertToSelf());
}
public void testMapGenericReadMask() {
final GENERIC_MAPPING mapping = new GENERIC_MAPPING();
mapping.genericRead = new DWORD(FILE_GENERIC_READ);
mapping.genericWrite = new DWORD(FILE_GENERIC_WRITE);
mapping.genericExecute = new DWORD(FILE_GENERIC_EXECUTE);
mapping.genericAll = new DWORD(FILE_ALL_ACCESS);
final DWORDByReference rights = new DWORDByReference(new DWORD(GENERIC_READ));
Advapi32.INSTANCE.MapGenericMask(rights, mapping);
assertEquals(FILE_GENERIC_READ, rights.getValue().intValue());
assertTrue(GENERIC_READ != (rights.getValue().intValue() & GENERIC_READ));
}
public void testMapGenericWriteMask() {
final GENERIC_MAPPING mapping = new GENERIC_MAPPING();
mapping.genericRead = new DWORD(FILE_GENERIC_READ);
mapping.genericWrite = new DWORD(FILE_GENERIC_WRITE);
mapping.genericExecute = new DWORD(FILE_GENERIC_EXECUTE);
mapping.genericAll = new DWORD(FILE_ALL_ACCESS);
final DWORDByReference rights = new DWORDByReference(new DWORD(GENERIC_WRITE));
Advapi32.INSTANCE.MapGenericMask(rights, mapping);
assertEquals(FILE_GENERIC_WRITE, rights.getValue().intValue());
assertTrue(GENERIC_WRITE != (rights.getValue().intValue() & GENERIC_WRITE));
}
public void testMapGenericExecuteMask() {
final GENERIC_MAPPING mapping = new GENERIC_MAPPING();
mapping.genericRead = new DWORD(FILE_GENERIC_READ);
mapping.genericWrite = new DWORD(FILE_GENERIC_WRITE);
mapping.genericExecute = new DWORD(FILE_GENERIC_EXECUTE);
mapping.genericAll = new DWORD(FILE_ALL_ACCESS);
final DWORDByReference rights = new DWORDByReference(new DWORD(GENERIC_EXECUTE));
Advapi32.INSTANCE.MapGenericMask(rights, mapping);
assertEquals(FILE_GENERIC_EXECUTE, rights.getValue().intValue());
assertTrue(GENERIC_EXECUTE != (rights.getValue().intValue() & GENERIC_EXECUTE));
}
public void testMapGenericAllMask() {
final GENERIC_MAPPING mapping = new GENERIC_MAPPING();
mapping.genericRead = new DWORD(FILE_GENERIC_READ);
mapping.genericWrite = new DWORD(FILE_GENERIC_WRITE);
mapping.genericExecute = new DWORD(FILE_GENERIC_EXECUTE);
mapping.genericAll = new DWORD(FILE_ALL_ACCESS);
final DWORDByReference rights = new DWORDByReference(new DWORD(GENERIC_ALL));
Advapi32.INSTANCE.MapGenericMask(rights, mapping);
assertEquals(FILE_ALL_ACCESS, rights.getValue().intValue());
assertTrue(GENERIC_ALL != (rights.getValue().intValue() & GENERIC_ALL));
}
public void testAccessCheck() {
final GENERIC_MAPPING mapping = new GENERIC_MAPPING();
mapping.genericRead = new DWORD(FILE_GENERIC_READ);
mapping.genericWrite = new DWORD(FILE_GENERIC_WRITE);
mapping.genericExecute = new DWORD(FILE_GENERIC_EXECUTE);
mapping.genericAll = new DWORD(FILE_ALL_ACCESS);
final Memory securityDescriptorMemoryPointer = new Memory(1);
final PRIVILEGE_SET privileges = new PRIVILEGE_SET(1);
privileges.PrivilegeCount = new DWORD(0);
final DWORDByReference privilegeLength = new DWORDByReference(new DWORD(privileges.size()));
final DWORDByReference grantedAccess = new DWORDByReference();
final BOOLByReference result = new BOOLByReference();
final boolean status = Advapi32.INSTANCE.AccessCheck(securityDescriptorMemoryPointer, null, new DWORD(FILE_GENERIC_READ), mapping, privileges, privilegeLength, grantedAccess, result);
assertFalse(status);
assertFalse(result.getValue().booleanValue());
assertEquals(WinError.ERROR_INVALID_HANDLE, Kernel32.INSTANCE.GetLastError());
}
}
@@ -12,6 +12,7 @@
*/
package com.sun.jna.platform.win32;
import java.io.File;
import java.util.Map;
import java.util.TreeMap;
@@ -55,6 +56,22 @@ public class Advapi32UtilTest extends TestCase {
System.out.println(" Name: " + accountBySid.name);
System.out.println(" Domain: " + accountBySid.domain);
}
public void testReadAccess() {
final boolean access = Advapi32Util.accessCheck(new File(System.getProperty("java.io.tmpdir")), Advapi32Util.AccessCheckPermission.READ);
assertTrue(access);
}
public void testWriteAccess() {
final boolean access = Advapi32Util.accessCheck(new File(System.getProperty("java.io.tmpdir")), Advapi32Util.AccessCheckPermission.WRITE);
assertTrue(access);
}
public void testExecuteAccess() {
final boolean access = Advapi32Util.accessCheck(new File(System.getProperty("java.io.tmpdir")), Advapi32Util.AccessCheckPermission.EXECUTE);
assertTrue(access);
}
public void testGetUsername() {
String username = Advapi32Util.getUserName();