2016-12-05 6 views
0

Я пытаюсь использовать JNA для вызова функции QueryContextAttributes в Secur32.dll в Windows. Я не могу правильно вызвать вызов для вызова SECPKG_ATTR_SIZES. У меня есть реализация, работающая для SECPKG_ATTR_NAMES и SECPKG_ATTR_PACKAGE_INFO. Поэтому, я полагаю (известные последние слова) проблема заключается в определении структуры, или что-то о вызове.Недопустимый доступ к памяти в QueryContextAttributes с использованием JNA

Определение Microsoft функция QueryContextAttributes является:

SECURITY_STATUS SEC_Entry QueryContextAttributes(
    _In_ PCtxtHandle phContext, 
    _In_ ULONG  ulAttribute, 
    _Out_ PVOID  pBuffer 
); 

Структура определения Microsoft для SecPkgContext_Sizes является:

typedef struct _SecPkgContext_Sizes { 
    ULONG cbMaxToken; 
    ULONG cbMaxSignature; 
    ULONG cbBlockSize; 
    ULONG cbSecurityTrailer; 
} SecPkgContext_Sizes, *PSecPkgContext_Sizes; 

Библиотека ЮНА (я использую ЮНА-4.2.2 и ЮНА -platform-4.2.2) обеспечивает реализацию в Secur32 для некоторых функций из этой DLL. Определения структур находятся: SecPkgContext_Names structure, SecPkgInfo structure и SecPkgContext_Sizes structure

Поэтому я определил следующее:

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);  
    } 

Когда я пытаюсь получить размеры (в частности, после значения 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 трассировку стека:

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.getValue() вызова, я использую pp.getPointer(), я получаю (при попытке создать экземпляр объекта, я считаю,):

java.lang.IllegalArgumentException: Structure exceeds provided memory bounds 

Я затрудняюсь с тем, как решить эту проблему.

Извиняюсь за то, что у меня нет полной программы, но для того, чтобы иметь необходимый CtxtHandle, требуется прорыв через AcquireCredentialsHandle и InitializeSecurityContext. Я считаю, что они работают надлежащим образом, поскольку билет Kerberos отображается в кеше MSLSA (просматривается через klist) после завершения InitializeSecurityContext.

Я также рассмотрел решение Waffle, но он не устанавливает правильные флаги в цикле инициализации, а также не реализует QueryContextAttributes или конечную цель во всей этой функции MakeSignature.

Извиняюсь за длину сообщения. Если я опустил какую-либо информацию, сообщите мне.

Спасибо!

+0

'PointerByReference.getValue()' is _always_ как вы должны получить результат, возвращенный в ссылке. 'getPointer()' дает вам адрес памяти, удерживающей это значение. – technomage

+0

У вас, скорее всего, есть неправильное сопоставление структуры (вы не предоставляете свое отображение 'CtxtHandle' или' SecPkgContext_Sizes', поэтому я ставлю, что ошибка есть). Запустите JVM с помощью '-Djna.dump_memory = true' и распечатайте структуры; что укажет макет JNA. Сопоставьте это с похожим нативным дампом выравнивания структуры/поля. – technomage

+0

@technomage, спасибо за комментарии. CtxtHandle является стандартной структурой JNA. При копировании кода SecPkgContext_Sizes закончил с «Bis» в конце кода выше; Я извиняюсь. Я нашел решение, представленное ниже, хотя я считаю, что должен быть более элегантный способ достижения результата. Я ценю, что вы нашли время, чтобы прочитать и прокомментировать мою проблему! – KevinO

ответ

0

Я смог решить вопрос, который у меня был, хотя и не очень изящным образом. Вместо того, чтобы пытаться использовать a PointerByReference в QueryContextAttributes, как было предложено в вопросе, я закончил создание нескольких определений методов, по одному для каждой структуры.Поэтому у меня есть интерфейс, подход:

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(...), будучи предшественником), и у меня были проблемы Усиливая структуру по умолчанию ЮНА SecBufferDesc. Я нашел указатель на решение от JSch SSPI by Joe Khoobyar и использовал базовое определение с этого сайта, изменив объекты NativeLong на int и добавив новый необходимый метод getFieldOrder().

MakeSignature метод, следуя определения от Microsoft, был определен в интерфейсе, как:

public int MakeSignature(CtxtHandle phContext, 
         int fQOP, 
         ISecur32.SecBufferDesc pMessage, 
         int messageSeqNo); 

После того, как с использованием вышеуказанных способов QueryContextAttributes и модифицированной структуры для SecBufferDesc, я был в состоянии получить рабочий раствор. Теперь клиенты Java могут использовать систему Microsoft SSPI для SSO для удаленных Linux-машин.

+0

Это на самом деле предпочтительный метод отображения функций, которые принимают многоцелевые аргументы, поскольку он обеспечивает большую безопасность типов, чем сама нативная функция. – technomage