[英]Invalid Memory Access on QueryContextAttributes using JNA
我正在嘗試使用JNA在Windows上的Secur32.dll中調用QueryContextAttributes函數。 我無法正確調用SECPKG_ATTR_SIZES調用。 我有一個適用於SECPKG_ATTR_NAMES和SECPKG_ATTR_PACKAGE_INFO的實現。 因此,我認為(著名的遺言)問題在於結構的定義或有關調用的問題。
QueryContextAttributes的Microsoft函數定義為:
SECURITY_STATUS SEC_Entry QueryContextAttributes(
_In_ PCtxtHandle phContext,
_In_ ULONG ulAttribute,
_Out_ PVOID pBuffer
);
SecPkgContext_Sizes的Microsoft結構定義為:
typedef struct _SecPkgContext_Sizes {
ULONG cbMaxToken;
ULONG cbMaxSignature;
ULONG cbBlockSize;
ULONG cbSecurityTrailer;
} SecPkgContext_Sizes, *PSecPkgContext_Sizes;
JNA庫(我正在使用jna-4.2.2和jna-platform-4.2.2)在Secur32中提供了該.dll中某些功能的實現。 這些結構的定義位於: SecPkgContext_Names結構 , SecPkgInfo結構和SecPkgContext_Sizes結構
因此,我定義了以下內容:
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
名稱的調用(正在運行)是:
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);
}
當我嘗試獲取Sizes時(特別是在cbMaxSignature值之后),我使用以下調用:
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();
}
使用上面的調用,我收到以下異常堆棧跟蹤:
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)
如果我使用pp.getPointer()
而不是pp.getValue()
調用,我會收到(我相信在嘗試實例化Object時):
java.lang.IllegalArgumentException: Structure exceeds provided memory bounds
我不知道如何解決這個問題。
對於沒有完整的程序,我深表歉意,但是要達到需要CtxtHandle的地步,需要通過AcquireCredentialsHandle和InitializeSecurityContext來加油。 我相信它們工作正常,因為在InitializeSecurityContext
完成后,Kerberos票證顯示在MSLSA緩存中(可通過klist查看)。
我還查看了解決方案Waffle ,但是它沒有在初始化循環中設置正確的標志,也沒有實現QueryContextAttributes或所有MakeSignature
函數的最終目標。
對於帖子的長度,我深表歉意。 如果我省略了任何信息,請告訴我。
謝謝!
我可以解決我遇到的問題,盡管不是很優雅。 我沒有按照問題中的建議嘗試在QueryContextAttributes
使用PointerByReference
,而是最終創建了多個方法定義,每個方法定義一個。 所以我在接口中有以下方法:
public int QueryContextAttributes(CtxtHandle phContext,
int SECPKG_ATTR,
SecPkgContext_NegotiationInfo negoInfo);
public static class SecPkgContext_NegotiationInfo extends Structure
{
public Pointer pPackageInfo;
public int negotiationState;
public SecPkgContext_NegotiationInfo() {
super();
}
public SecPkgContext_NegotiationInfo(Pointer p) {
super(p);
}
@Override
protected List<?> getFieldOrder() {
return Arrays.asList(new String[] { "pPackageInfo", "negotiationState"
});
}
}
public int QueryContextAttributes(CtxtHandle phContext,
int SECPKG_ATTR,
SecPkgContext_Sizes sizes);
public static class SecPkgContext_Sizes extends Structure
{
public int cbMaxToken;
public int cbMaxSignature;
public int cbBlockSize;
public int cbSecurityTrailer;
public SecPkgContext_Sizes() {
super();
}
public SecPkgContext_Sizes(Pointer p) {
super(p);
}
@Override
protected List<?> getFieldOrder() {
return Arrays.asList(new String[] { "cbMaxToken",
"cbMaxSignature",
"cbBlockSize",
"cbSecurityTrailer"
});
}
}
對於我需要的一些定義,依此類推。
最終的目標是使MakeSignature
調用正常工作( QueryContextAttributes(...)
是前身),而我在利用默認JNA SecBufferDesc
結構時遇到了麻煩。 我找到了Joe Khoobyar的JSch SSPI解決方案的指針,並利用了該站點的基本定義,將NativeLong
對象更改為int
,並添加了新的必需方法getFieldOrder()
。
根據Microsoft的定義, MakeSignature
方法在Interface中定義為:
public int MakeSignature(CtxtHandle phContext,
int fQOP,
ISecur32.SecBufferDesc pMessage,
int messageSeqNo);
在將以上方法用於QueryContextAttributes
和修改后的結構用於SecBufferDesc
,我能夠得到一個可行的解決方案。 Java客戶端現在可以將Microsoft SSPI系統用於SSO到遠程Linux機器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.