Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added WinioctlUtil, Ntifs and modified Kernel32 #732

Merged
merged 5 commits into from
Dec 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ Features
* [#689](https://github.com/java-native-access/jna/pull/689): Add `GetProcAddress(HMODULE, int)` to `com.sun.jna.platform.win32.Kernel32` - [@matthiasblaesing](https://github.com/matthiasblaesing).
* [#723](https://github.com/java-native-access/jna/pull/723): Added `com.sun.jna.platform.win32.Wevtapi` and `com.sun.jna.platform.win32.Winevt` - [@sakamotodesu](https://github.com/sakamotodesu).
* [#720](https://github.com/java-native-access/jna/issues/720): Added `SetThreadExecutionState` to `com.sun.jna.platform.win32.Kernel32` - [@matthiasblaesing](https://github.com/matthiasblaesing).
* [#732](https://github.com/java-native-access/jna/pull/732): Added `com.sun.jna.platform.win32.WinioctlUtil` for help in determining FSCTL_* codes - [@amarcionek](https://github.com/amarcionek).
* [#732](https://github.com/java-native-access/jna/pull/732): Added `com.sun.jna.platform.win32.Ntifs` with Reparse Point structures and defines - [@amarcionek](https://github.com/amarcionek).
* [#732](https://github.com/java-native-access/jna/pull/732): Added initialization of FILETIME from LARGE_INTEGER - [@amarcionek](https://github.com/amarcionek).
* [#732](https://github.com/java-native-access/jna/pull/732): Added `GetFileInformationByHandleEx` and `SetFileInformationByHandle` to `com.sun.jna.platform.win32.Kernel32` - [@amarcionek](https://github.com/amarcionek).

Bug Fixes
---------
Expand Down
206 changes: 206 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@
import static com.sun.jna.platform.win32.WinNT.SE_DACL_PROTECTED;
import static com.sun.jna.platform.win32.WinNT.SE_SACL_PROTECTED;
import static com.sun.jna.platform.win32.WinNT.STANDARD_RIGHTS_READ;
import static com.sun.jna.platform.win32.WinNT.TOKEN_ADJUST_PRIVILEGES;
import static com.sun.jna.platform.win32.WinNT.TOKEN_DUPLICATE;
import static com.sun.jna.platform.win32.WinNT.TOKEN_IMPERSONATE;
import static com.sun.jna.platform.win32.WinNT.TOKEN_QUERY;
import static com.sun.jna.platform.win32.WinNT.UNPROTECTED_DACL_SECURITY_INFORMATION;
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 @@ -81,6 +83,7 @@
import com.sun.jna.platform.win32.WinNT.SECURITY_IMPERSONATION_LEVEL;
import com.sun.jna.platform.win32.WinNT.SID_AND_ATTRIBUTES;
import com.sun.jna.platform.win32.WinNT.SID_NAME_USE;
import com.sun.jna.platform.win32.WinNT.TOKEN_TYPE;
import com.sun.jna.platform.win32.WinReg.HKEY;
import com.sun.jna.platform.win32.WinReg.HKEYByReference;
import com.sun.jna.ptr.IntByReference;
Expand Down Expand Up @@ -2636,4 +2639,207 @@ public DWORD callback(Pointer pbData, Pointer pvCallbackContext,
// close
Advapi32.INSTANCE.CloseEncryptedFileRaw(pvContext.getValue());
}

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

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

/**
* LUID form of the privileges
*/
private final WinNT.LUID[] pLuids;

/**
* Construct and enable a set of privileges
* @param privileges the names of the privileges in the form of SE_* from Advapi32.java
* @throws IllegalArgumentException
*/
public Privilege(String... privileges) 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++;
}
}

/**
* Calls disable() to remove the privileges
* @see java.io.Closeable#close()
*/
@Override
public void close() {
this.disable();
}

/**
* 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 Privilege enable() throws Win32Exception {
// Ignore if already enabled.
if (privilegesEnabled)
return this;

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

try {
phThreadToken.setValue(getThreadToken());
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());
}
privilegesEnabled = true;
}
catch (Win32Exception ex) {
// If fails, clean up
if (currentlyImpersonating) {
Advapi32.INSTANCE.SetThreadToken(null, null);
currentlyImpersonating = false;
}
else {
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);
privilegesEnabled = false;
}
}
throw ex;
}
finally {
// Always close the thread token
if ((phThreadToken.getValue() != WinBase.INVALID_HANDLE_VALUE)
&& (phThreadToken.getValue() != null)) {
Kernel32.INSTANCE.CloseHandle(phThreadToken.getValue());
phThreadToken.setValue(null);
}
}
return this;
}

/**
* Disabled the prior enabled privilege
* @throws Win32Exception
*/
public void disable() throws Win32Exception {
// Get thread token
final HANDLEByReference phThreadToken = new HANDLEByReference();

try {
phThreadToken.setValue(getThreadToken());
if (currentlyImpersonating) {
Advapi32.INSTANCE.SetThreadToken(null, null);
}
else
{
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);
privilegesEnabled = false;
}
}
}
finally {
// Close the thread token
if ((phThreadToken.getValue() != WinBase.INVALID_HANDLE_VALUE)
&& (phThreadToken.getValue() != null)) {
Kernel32.INSTANCE.CloseHandle(phThreadToken.getValue());
phThreadToken.setValue(null);
}
}
}

/**
* Get a handle to the thread token. May duplicate the process token
* and set as the thread token if ther thread has no token.
* @return HANDLE to the thread token
* @throws Win32Exception
*/
private HANDLE getThreadToken() throws Win32Exception {
// we need to create a new token here for the duplicate
final HANDLEByReference phThreadToken = new HANDLEByReference();
final HANDLEByReference phProcessToken = new HANDLEByReference();

try {
// open thread token
if (!Advapi32.INSTANCE.OpenThreadToken(Kernel32.INSTANCE.GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES,
false,
phThreadToken)) {
// OpenThreadToken may fail with W32Errors.ERROR_NO_TOKEN if current thread is anonymous. Check for that condition here. If not, throw an error.
int lastError = Kernel32.INSTANCE.GetLastError();
if (W32Errors.ERROR_NO_TOKEN != lastError) {
throw new Win32Exception(lastError);
}

// Due to ERROR_NO_TOKEN, we need to open the process token to duplicate it, then set our thread token.
if (!Advapi32.INSTANCE.OpenProcessToken(Kernel32.INSTANCE.GetCurrentProcess(), TOKEN_DUPLICATE, phProcessToken)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

// Process token opened, now duplicate
if (!Advapi32.INSTANCE.DuplicateTokenEx(phProcessToken.getValue(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE,
null,
SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
TOKEN_TYPE.TokenImpersonation,
phThreadToken)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

// And set thread token.
if (!Advapi32.INSTANCE.SetThreadToken(null, phThreadToken.getValue())) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
currentlyImpersonating = true;
}
}
catch (Win32Exception ex) {
// Close the thread token
if ((phThreadToken.getValue() != WinBase.INVALID_HANDLE_VALUE)
&& (phThreadToken.getValue() != null)) {
Kernel32.INSTANCE.CloseHandle(phThreadToken.getValue());
phThreadToken.setValue(null);
}
throw ex;
}
finally
{
// Always close the process token
if ((phProcessToken.getValue() != WinBase.INVALID_HANDLE_VALUE)
&& (phProcessToken.getValue() != null)) {
Kernel32.INSTANCE.CloseHandle(phProcessToken.getValue());
phProcessToken.setValue(null);
}
}

return phThreadToken.getValue();
}
}
}
Loading