繁体   English   中英

使用JNA对QueryContextAttributes进行无效的内存访问

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM