Я пытаюсь использовать 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
.
Извиняюсь за длину сообщения. Если я опустил какую-либо информацию, сообщите мне.
Спасибо!
'PointerByReference.getValue()' is _always_ как вы должны получить результат, возвращенный в ссылке. 'getPointer()' дает вам адрес памяти, удерживающей это значение. – technomage
У вас, скорее всего, есть неправильное сопоставление структуры (вы не предоставляете свое отображение 'CtxtHandle' или' SecPkgContext_Sizes', поэтому я ставлю, что ошибка есть). Запустите JVM с помощью '-Djna.dump_memory = true' и распечатайте структуры; что укажет макет JNA. Сопоставьте это с похожим нативным дампом выравнивания структуры/поля. – technomage
@technomage, спасибо за комментарии. CtxtHandle является стандартной структурой JNA. При копировании кода SecPkgContext_Sizes закончил с «Bis» в конце кода выше; Я извиняюсь. Я нашел решение, представленное ниже, хотя я считаю, что должен быть более элегантный способ достижения результата. Я ценю, что вы нашли время, чтобы прочитать и прокомментировать мою проблему! – KevinO