Skip to content

Commit

Permalink
More changes based on feedback
Browse files Browse the repository at this point in the history
* Converted char to byte for UCHAR
* Made Privilege implement Closeable
  • Loading branch information
amarcionek committed Dec 5, 2016
1 parent 2cea718 commit d8a8438
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 95 deletions.
85 changes: 52 additions & 33 deletions contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import static com.sun.jna.platform.win32.WinNT.UNPROTECTED_SACL_SECURITY_INFORMATION;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -2640,63 +2641,78 @@ public DWORD callback(Pointer pbData, Pointer pvCallbackContext,
}

/**
* Convenience class to enables a certain Windows process privilege
* Convenience class to enable certain Windows process privileges
*/
public static class Privilege {
public static class Privilege implements Closeable {
/**
* If true, the thread is currently impersonating
*/
private boolean currentlyImpersonating = false;

/**
* If true, the Privilege has been enabled
* If true, the privileges have been enabled
*/
private boolean privilegeEnabled = false;
private boolean privilegesEnabled = false;

/**
* LUID form of the privilege
* LUID form of the privileges
*/
private final WinNT.LUID pLuid = new WinNT.LUID();
private final WinNT.LUID[] pLuids;

/**
* String form of the privilege
* Construct and enable a set of privileges
* @param privileges the name of the privileges in the form of SE_* from Advapi32.java
* @enable if true, enable the privilege immediately.
* @throws IllegalArgumentException
*/
private final String privilege;
public Privilege(String[] privileges, boolean enable) throws IllegalArgumentException, Win32Exception {
pLuids = new WinNT.LUID[privileges.length];
int i = 0;
for (String p : privileges) {
pLuids[i] = new WinNT.LUID();
if (!Advapi32.INSTANCE.LookupPrivilegeValue(null, p, pLuids[i])) {
throw new IllegalArgumentException("Failed to find privilege \"" + privileges[i] + "\" - " + Kernel32.INSTANCE.GetLastError());
}
i++;
}
if (enable)
this.enable();
}

/**
* Construct a Privilege
* @param privilege the name of the privilege in the form of SE_* from Advapi32.java
* @throws IllegalArgumentException
* Calls {@link#disable} to remove the privileges
* @see java.io.Closeable#close()
*/
public Privilege(String privilege) throws IllegalArgumentException {
this.privilege = privilege;
if (!Advapi32.INSTANCE.LookupPrivilegeValue(null, this.privilege, pLuid)) {
throw new IllegalArgumentException("Failed to find privilege \"" + privilege + "\" - " + Kernel32.INSTANCE.GetLastError());
}
@Override
public void close() {
this.disable();
}

/**
* Enables the given privilege. If required, it will duplicate the process token. No resources are left open when this completes. That is, it is
* NOT required to drop the privilege, although it is considered a best practice if you do not need it. This class is state full. It keeps track
* of whether it has enabled a privilege. Multiple calls to enable() without a drop() in between have no affect.
* Enables the given privileges. If required, it will duplicate the process token. No resources are left open when this completes. That is, it is
* NOT required to drop the privileges, although it is considered a best practice if you do not need it. This class is state full. It keeps track
* of whether it has enabled the privileges. Multiple calls to enable() without a drop() in between have no affect.
* @return pointer to self (Privilege) as a convenience for try with resources statements
* @throws Win32Exception
*/
public void enable() throws Win32Exception {
// Ignore if already enabled.
if (privilegeEnabled)
if (privilegesEnabled)
return;

// Get thread token
final HANDLEByReference phThreadToken = new HANDLEByReference();

try {
phThreadToken.setValue(getThreadToken());
WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1);
tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(pLuid, new DWORD(WinNT.SE_PRIVILEGE_ENABLED));
WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(pLuids.length);
for (int i = 0; i < pLuids.length; i++) {
tp.Privileges[i] = new WinNT.LUID_AND_ATTRIBUTES(pLuids[i], new DWORD(WinNT.SE_PRIVILEGE_ENABLED));
}
if (!Advapi32.INSTANCE.AdjustTokenPrivileges(phThreadToken.getValue(), false, tp, 0, null, null)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
privilegeEnabled = true;
privilegesEnabled = true;
}
catch (Win32Exception ex) {
// If fails, clean up
Expand All @@ -2705,11 +2721,13 @@ public void enable() throws Win32Exception {
currentlyImpersonating = false;
}
else {
if (privilegeEnabled) {
WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1);
tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(pLuid, new DWORD(0));
if (privilegesEnabled) {
WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(pLuids.length);
for (int i = 0; i < pLuids.length; i++) {
tp.Privileges[i] = new WinNT.LUID_AND_ATTRIBUTES(pLuids[i], new DWORD(0));
}
Advapi32.INSTANCE.AdjustTokenPrivileges(phThreadToken.getValue(), false, tp, 0, null, null);
privilegeEnabled = false;
privilegesEnabled = false;
}
}
throw ex;
Expand All @@ -2728,8 +2746,7 @@ public void enable() throws Win32Exception {
* Disabled the prior enabled privilege
* @throws Win32Exception
*/
public void disable() throws Win32Exception
{
public void disable() throws Win32Exception {
// Get thread token
final HANDLEByReference phThreadToken = new HANDLEByReference();

Expand All @@ -2740,11 +2757,13 @@ public void disable() throws Win32Exception
}
else
{
if (privilegeEnabled) {
WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1);
tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(pLuid, new DWORD(0));
if (privilegesEnabled) {
WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(pLuids.length);
for (int i = 0; i < pLuids.length; i++) {
tp.Privileges[i] = new WinNT.LUID_AND_ATTRIBUTES(pLuids[i], new DWORD(0));
}
Advapi32.INSTANCE.AdjustTokenPrivileges(phThreadToken.getValue(), false, tp, 0, null, null);
privilegeEnabled = false;
privilegesEnabled = false;
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions contrib/platform/src/com/sun/jna/platform/win32/WinBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -456,22 +456,22 @@ public ByReference(Pointer memory) {
/**
* The factor that the compression uses.
*/
public char CompressionUnitShift;
public byte CompressionUnitShift;

/**
* The number of chunks that are shifted by compression.
*/
public char ChunkShift;
public byte ChunkShift;

/**
* The number of clusters that are shifted by compression.
*/
public char ClusterShift;
public byte ClusterShift;

/**
* Reserved
*/
public char[] Reserved = new char[3];
public byte[] Reserved = new byte[3];

public static int sizeOf()
{
Expand All @@ -494,15 +494,15 @@ public FILE_COMPRESSION_INFO(Pointer memory) {

public FILE_COMPRESSION_INFO(LARGE_INTEGER CompressedFileSize,
short CompressionFormat,
char CompressionUnitShift,
char ChunkShift,
char ClusterShift) {
byte CompressionUnitShift,
byte ChunkShift,
byte ClusterShift) {
this.CompressedFileSize = CompressedFileSize;
this.CompressionFormat = CompressionFormat;
this.CompressionUnitShift = CompressionUnitShift;
this.ChunkShift = ChunkShift;
this.ClusterShift = ClusterShift;
this.Reserved = new char[3];
this.Reserved = new byte[3];
write();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,12 +603,20 @@ public void testBackupEncryptedFile() throws Exception {
* Test Privilege class
*/
public void testPrivilege() {
Advapi32Util.Privilege p = new Advapi32Util.Privilege(WinNT.SE_ASSIGNPRIMARYTOKEN_NAME);
try {
p.enable(); // Will throw if it fails
// Test multiple known privileges
try(Advapi32Util.Privilege p = new Advapi32Util.Privilege(new String[] { WinNT.SE_ASSIGNPRIMARYTOKEN_NAME, WinNT.SE_BACKUP_NAME }, true);) {
// Will throw if it fails p.enable() fails
}

// Test unknown privilege
try(Advapi32Util.Privilege p = new Advapi32Util.Privilege(new String[] { "NOT_A_PRIVILEGE"}, true);) {
// Will throw if it fails p.enable() fails
}
catch (IllegalArgumentException ex) {
// Exception is expected
}
finally {
p.disable();
catch (Exception ex) {
fail("Encountered unknown exception - " + ex.getMessage());
}
}

Expand Down
97 changes: 48 additions & 49 deletions contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -643,56 +643,55 @@ public void testDeviceIoControlFsctlReparse() throws IOException {
delLink.deleteOnExit();

// Required for FSCTL_SET_REPARSE_POINT
Advapi32Util.Privilege restore = new Advapi32Util.Privilege(WinNT.SE_RESTORE_NAME);
restore.enable();

HANDLE hFile = Kernel32.INSTANCE.CreateFile(link.toAbsolutePath().toString(),
WinNT.GENERIC_READ | WinNT.FILE_WRITE_ATTRIBUTES | WinNT.FILE_WRITE_EA,
WinNT.FILE_SHARE_READ | WinNT.FILE_SHARE_WRITE | WinNT.FILE_SHARE_DELETE,
new WinBase.SECURITY_ATTRIBUTES(),
WinNT.OPEN_EXISTING,
WinNT.FILE_ATTRIBUTE_DIRECTORY | WinNT.FILE_FLAG_BACKUP_SEMANTICS | WinNT.FILE_FLAG_OPEN_REPARSE_POINT,
null);

if (WinBase.INVALID_HANDLE_VALUE.equals(hFile)) {
fail("CreateFile failed with " + Kernel32.INSTANCE.GetLastError());
}

try {
SymbolicLinkReparseBuffer symLinkReparseBuffer = new SymbolicLinkReparseBuffer(folder.getFileName().toString(),
folder.getFileName().toString(),
Ntifs.SYMLINK_FLAG_RELATIVE);

REPARSE_DATA_BUFFER lpBuffer = new REPARSE_DATA_BUFFER(WinNT.IO_REPARSE_TAG_SYMLINK, (short) 0, symLinkReparseBuffer);

assertTrue(Kernel32.INSTANCE.DeviceIoControl(hFile,
new FSCTL_SET_REPARSE_POINT().getControlCode(),
lpBuffer.getPointer(),
lpBuffer.getSize(),
null,
0,
null,
null));
try(Advapi32Util.Privilege restore = new Advapi32Util.Privilege(new String[] { WinNT.SE_RESTORE_NAME }, true)) {

HANDLE hFile = Kernel32.INSTANCE.CreateFile(link.toAbsolutePath().toString(),
WinNT.GENERIC_READ | WinNT.FILE_WRITE_ATTRIBUTES | WinNT.FILE_WRITE_EA,
WinNT.FILE_SHARE_READ | WinNT.FILE_SHARE_WRITE | WinNT.FILE_SHARE_DELETE,
new WinBase.SECURITY_ATTRIBUTES(),
WinNT.OPEN_EXISTING,
WinNT.FILE_ATTRIBUTE_DIRECTORY | WinNT.FILE_FLAG_BACKUP_SEMANTICS | WinNT.FILE_FLAG_OPEN_REPARSE_POINT,
null);

if (WinBase.INVALID_HANDLE_VALUE.equals(hFile)) {
fail("CreateFile failed with " + Kernel32.INSTANCE.GetLastError());
}

Memory p = new Memory(REPARSE_DATA_BUFFER.sizeOf());
IntByReference lpBytes = new IntByReference();
assertTrue(Kernel32.INSTANCE.DeviceIoControl(hFile,
new FSCTL_GET_REPARSE_POINT().getControlCode(),
null,
0,
p,
(int) p.size(),
lpBytes,
null));
// Is a reparse point
lpBuffer = new REPARSE_DATA_BUFFER(p);
assertTrue(lpBytes.getValue() > 0);
assertTrue(lpBuffer.ReparseTag == WinNT.IO_REPARSE_TAG_SYMLINK);
assertEquals(folder.getFileName().toString(), lpBuffer.u.symLinkReparseBuffer.getPrintName());
assertEquals(folder.getFileName().toString(), lpBuffer.u.symLinkReparseBuffer.getSubstituteName());
} finally {
Kernel32Util.closeHandle(hFile);
restore.disable();
try {
SymbolicLinkReparseBuffer symLinkReparseBuffer = new SymbolicLinkReparseBuffer(folder.getFileName().toString(),
folder.getFileName().toString(),
Ntifs.SYMLINK_FLAG_RELATIVE);

REPARSE_DATA_BUFFER lpBuffer = new REPARSE_DATA_BUFFER(WinNT.IO_REPARSE_TAG_SYMLINK, (short) 0, symLinkReparseBuffer);

assertTrue(Kernel32.INSTANCE.DeviceIoControl(hFile,
new FSCTL_SET_REPARSE_POINT().getControlCode(),
lpBuffer.getPointer(),
lpBuffer.getSize(),
null,
0,
null,
null));

Memory p = new Memory(REPARSE_DATA_BUFFER.sizeOf());
IntByReference lpBytes = new IntByReference();
assertTrue(Kernel32.INSTANCE.DeviceIoControl(hFile,
new FSCTL_GET_REPARSE_POINT().getControlCode(),
null,
0,
p,
(int) p.size(),
lpBytes,
null));
// Is a reparse point
lpBuffer = new REPARSE_DATA_BUFFER(p);
assertTrue(lpBytes.getValue() > 0);
assertTrue(lpBuffer.ReparseTag == WinNT.IO_REPARSE_TAG_SYMLINK);
assertEquals(folder.getFileName().toString(), lpBuffer.u.symLinkReparseBuffer.getPrintName());
assertEquals(folder.getFileName().toString(), lpBuffer.u.symLinkReparseBuffer.getSubstituteName());
} finally {
Kernel32Util.closeHandle(hFile);
}
}
}

Expand Down

0 comments on commit d8a8438

Please sign in to comment.