I am attempting to use JNA to invoke the QueryContextAttributes function in the Secur32.dll on Windows. I am unable to get the invocation correct for the SECPKG_ATTR_SIZES call. I have an implementation working for SECPKG_ATTR_NAMES and SECPKG_ATTR_PACKAGE_INFO. Therefore, I presume (famous last words) the issue is in the definition of the structure, or something about the invocation.
The Microsoft function definition for QueryContextAttributes is:
SECURITY_STATUS SEC_Entry QueryContextAttributes(
_In_ PCtxtHandle phContext,
_In_ ULONG ulAttribute,
_Out_ PVOID pBuffer
);
The Microsoft structure definition for the SecPkgContext_Sizes is:
typedef struct _SecPkgContext_Sizes {
ULONG cbMaxToken;
ULONG cbMaxSignature;
ULONG cbBlockSize;
ULONG cbSecurityTrailer;
} SecPkgContext_Sizes, *PSecPkgContext_Sizes;
The JNA library (I'm using jna-4.2.2 and jna-platform-4.2.2) provides an implementation in the Secur32 for some of the functions in that .dll. The definitions for the structures are at: SecPkgContext_Names structure, SecPkgInfo structure, and SecPkgContext_Sizes structure
I therefore have defined the following:
public interface ISecur32 extends Secur32 {
// get own copy of the INSTANCE variable
ISecur32 INSTANCE = (ISecur32) Native.loadLibrary("Secur32",
ISecur32.class,
W32APIOptions.UNICODE_OPTIONS);
// method definition to match
public int QueryContextAttributes(CtxtHandle phContext,
int SECPKG_ATTR,
PointerByReference pp);
//
// for the SECPKG_ATTR_NAMES call
// NOTE: this definition and invocation is working
//
public static class SecPkgContext_Names extends Structure {
public Pointer pName;
public SecPkgContext_Names(Pointer p)
{ super(p); }
@Override
protected List<?> getFieldOrder()
{ return Arrays.asList(new String[] { "pName" }); }
}
//
// for the SECPKG_ATTR_SIZES call
// NOTE: This invocation is NOT working
//
public static class SecPkgContext_SizesBis extends Structure {
public NativeLong cbMaxToken;
public NativeLong cbMaxSignature;
public NativeLong cbBlockSize;
public NativeLong cbSecurityTrailer;
public SecPkgContext_SizesBis(Pointer p)
{ super(p); }
@Override
protected List<?> getFieldOrder() {
return Arrays.asList(new String[] { "cbMaxToken", "cbMaxSignature",
"cbBlockSize", "cbSecurityTrailer"});
}
} //interface
The call for the Names (which is working) is:
public static void querySecPkgAttr_Names(CtxtHandle phContext) {
final int SECPKG_ATTR_NAMES = 1;
PointerByReference pp = new PointerByReference();
int rc = ISecur32.INSTANCE.QueryContextAttributes(phContext,
SECPKG_ATTR_NAMES,
pp);
if (rc != 0) {
_log.error("Error in QueryContextAttributes: {}", rc);
return;
}
Pointer p = pp.getPointer();
ISecur32.SecPkgContext_Names names = new ISecur32.SecPkgContext_Names(p);
names.read();
String name = names.pName.getWideString(0);
rc = ISecur32.INSTANCE.FreeContextBuffer(p);
_log.debug("FreeContextBuffer: {}", rc);
}
When I attempt to obtain the Sizes (specifically, I'm after the cbMaxSignature value), I use the following call:
public static int querySecPkgAttr_Sizes(CtxtHandle phContext) {
final int SECPKG_ATTR_SIZES = 0; // SECPKG_ATTR_SIZES is 0
PointerByReference pp = new PointerByReference();
int res = ISecur32.INSTANCE.QueryContextAttributes(phContext,
SECPKG_ATTR_SIZES,
pp);
// NOTE: the call is succeeding, so this line is not invoked
if (res != 0) {
return new NativeLong(0);
}
// NOTE: I have also used pp.getPointer()
Pointer p = pp.getValue();
ISecur32.SecPkgContext_Sizes sizes =
new ISecur32.SecPkgContext_Sizes(p);
// THIS LINE THROWS THE Invalid Memory Access Error
sizes.read();
NativeLong maxSig = sizes.cbMaxSignature;
rc = ISecur32.INSTANCE.FreeContextBuffer(p);
_log.debug("FreeContextBuffer: {}", rc);
return maxSig.intValue();
}
Using the above call, I receive the Exception stack trace of:
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.getInt(Native Method)
at com.sun.jna.Pointer.getInt(Pointer.java:601)
at com.sun.jna.Pointer.getValue(Pointer.java:389)
at com.sun.jna.Structure.readField(Structure.java:705)
at com.sun.jna.Structure.read(Structure.java:565)
at gov.sandia.dart.sspi.Utils.querySecPkgAttr_Sizes(Utils.java:145)
If instead of the pp.getValue()
call, I use pp.getPointer()
, I receive (when trying to instantiate the Object, I believe):
java.lang.IllegalArgumentException: Structure exceeds provided memory bounds
I am at a loss as to how to solve this issue.
I apologize for not having a complete program, but to get to the point of having the CtxtHandle needed requires a romp through AcquireCredentialsHandle and InitializeSecurityContext. I believe these are working appropriately, as the Kerberos ticket is showing in the MSLSA cache (viewable via klist) after the InitializeSecurityContext
completes.
I also looked at the solution Waffle, but it does not set the correct flags for in the initialization loop, and also does not implement QueryContextAttributes, or the ultimate goal in all of this the MakeSignature
function.
I apologize for the length of the post. If I have omitted any piece of information, please let me know.
Thank you!