RSA Authentication Agent API 文档中的函数签名是否正确? [英] Are the function signatures correct in the RSA Authentication Agent API documentation?

查看:38
本文介绍了RSA Authentication Agent API 文档中的函数签名是否正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些软件,它使用 RSA 身份验证代理的文档化 API.这是一种在域中的客户端计算机上作为服务运行的产品,并通过与集中安装的RSA 身份验证管理器"通信来对本地用户进行身份验证.

I have some software which uses the documented API for RSA's Authentication Agent. This is a product which runs as a service on the client machines in a domain, and authenticates users locally by communicating with an "RSA Authentication Manager" installed centrally.

身份验证代理的 API 在此处公开记录:身份验证代理 API 8.1.1 for C 开发人员指南.但是,文档似乎不正确,而且我无权访问 RSA 头文件——它们不是公开的;只有 PDF 文档可供下载,无需向 RSA 支付 $$.如果这里有人可以访问最新头文件,您能帮我确认文档是否过时吗?

The Authentication Agent's API is publicly documented here: Authentication Agent API 8.1.1 for C Developers Guide. However, the docs seem to be incorrect, and I do not have access to the RSA header files - they are not public; only the PDF documentation is available for download without paying $$ to RSA. If anyone here has access to up to date header files, would you be able to confirm for me whether the documentation is out of date?

API 文档中给出的函数签名似乎不正确 - 事实上,我绝对相信它们在 x64 机器上是错误的.例如,最新的 PDF 文档显示如下:

The function signatures given in the API docs seem incorrect - in fact, I'm absolutely convinced that they are wrong on x64 machines. For example, the latest PDF documentation shows the following:

int WINAPI AceSetUserData(SDI_HANDLE hdl, unsigned int userData)
int WINAPI AceGetUserData(SDI_HANDLE hdl, unsigned int *pUserData)

文档多次声明userData"值是 32 位数量,例如在 AceInitAceSetUserDataAceGetUserData 的文档中.AceGetUserData 文档的相关摘录:

The documentation states several times that the "userData" value is a 32-bit quantity, for example in the documentation for AceInit, AceSetUserData, and AceGetUserData. A relevant excerpt from the docs for AceGetUserData:

此函数是同步的,调用者必须提供一个指针作为第二个参数,该指针指向一个 32 位存储区域(即无符号整数),用于将用户数据值复制到其中.

This function is synchronous and the caller must supply, as the second argument, a pointer to a 32-bit storage area (that is, an unsigned int) into which to copy the user data value.

这显然是错误的——从一些实验来看,如果你传入一个指向填充了 0xff 的缓冲区中心的指针,AceGetUserData肯定写出一个 64-位值,而不是 32 位数量.

This is clearly false - from some experimentation, if you pass in a pointer to the center of a buffer filled with 0xff, AceGetUserData is definitely writing out a 64-bit value, not a 32-bit quantity.

我的aceclnt.dll版本是8.1.3.563;相应的文档标记为身份验证代理 API 8.1 SP1",这对应于身份验证代理本身的 7.3.1 版.

My version of aceclnt.dll is 8.1.3.563; the corresponding documentation is labelled "Authentication Agent API 8.1 SP1", and this corresponds to version 7.3.1 of the Authentication Agent itself.

给出完整的测试代码,即使它根本与问题无关......如果其他人运行测试代码(我知道它做什么!)对我来说没有用,我需要的是可以访问的人可以确认函数签名的RSA头文件.

Full test code given, even though it's not relevant to the problem at all... It's no use to me if someone else runs the test code (I know what it does!), what I need is someone with access to the RSA header files who can confirm the function signatures.

#include <assert.h>
#include <stdlib.h>
#include <stdint.h>

#ifdef WIN32
#include <Windows.h>
#include <tchar.h>
#define SDAPI WINAPI
#else
#define SDAPI
#endif
typedef int SDI_HANDLE;
typedef uint32_t SD_BOOL;
typedef void (SDAPI* AceCallback)(SDI_HANDLE);
#define ACE_SUCCESS                    1
#define ACE_PROCESSING                 150

typedef SD_BOOL (SDAPI* AceInitializeEx_proto)(const char*, char*, uint32_t);
typedef int (SDAPI* AceInit_proto)(SDI_HANDLE*, void*, AceCallback);
typedef int (SDAPI* AceClose_proto)(SDI_HANDLE, AceCallback);

typedef int (SDAPI* AceGetUserData_proto)(SDI_HANDLE, void*);
typedef int (SDAPI* AceSetUserData_proto)(SDI_HANDLE, void*);

struct Api {
  AceInitializeEx_proto AceInitializeEx;
  AceInit_proto AceInit;
  AceClose_proto AceClose;
  AceGetUserData_proto AceGetUserData;
  AceSetUserData_proto AceSetUserData;
} api;

static void api_init(struct Api* api) {
  // All error-checking stripped...
  HMODULE dll = LoadLibrary(_T("aceclnt.dll")); // leak this for the demo
  api->AceInitializeEx = (AceInitializeEx_proto)GetProcAddress(dll, "AceInitializeEx");
  api->AceInit = (AceInit_proto)GetProcAddress(dll, "AceInit");
  api->AceClose = (AceClose_proto)GetProcAddress(dll, "AceClose");
  api->AceGetUserData = (AceGetUserData_proto)GetProcAddress(dll, "AceGetUserData");
  api->AceSetUserData = (AceSetUserData_proto)GetProcAddress(dll, "AceSetUserData");

  int success = api->AceInitializeEx("C:\\my\\conf\\directory", 0, 0);
  assert(success);
}

static void demoFunction(SDI_HANDLE handle) {
  union {
    unsigned char testBuffer[sizeof(void *) * 3];
    void *forceAlignment;
  } u;

  memset(u.testBuffer, 0xA5, sizeof u.testBuffer);

  int err = api.AceGetUserData(handle, (void*)(u.testBuffer + sizeof(void*)));
  assert(err == ACE_SUCCESS);

  fputs("DEBUG: testBuffer =", stderr);
  for (size_t i = 0; i < sizeof(u.testBuffer); i++) {
    if (i % 4 == 0)
      putc(' ', stderr);
    fprintf(stderr, "%02x", u.testBuffer[i]);
  }
  fputc('\n', stderr);
  // Prints:
  // DEBUG: testBuffer = a5a5a5a5 a5a5a5a5 00000000 00000000 a5a5a5a5 a5a5a5a5
  // According to the docs, this should only write out a 32-bit value
}

static void SDAPI demoCallback(SDI_HANDLE h) {
  fprintf(stderr, "Callback invoked, handle = %p\n", (void*)h);
}

int main(int argc, const char** argv)
{
  api_init(&api);
  SDI_HANDLE h;

  int err = api.AceInit(&h, /* contentious argument */ 0, &demoCallback);
  assert(err == ACE_PROCESSING);

  demoFunction(h);

  api.AceClose(h, 0);

  return 0;
}

推荐答案

由于您已经从文档中复制了函数/类型定义,因此您基本上没有也永远不会有正确的版本定义您正在使用的 .dll 文件可能总是以崩溃或更糟的未定义行为告终.

As you've copied the function/type definitions out of the documentation, you basically don't have and never will have the correct definition for the version of the .dll you're using and could always end up in crashes or worse, undefined behavior.

你可以做的是调试相应的.dll:

What you could do is to debug the corresponding .dll:

你运行 Visual Studio 吗?我记得 VS 可以在调试模式下进入函数调用并显示程序集,但不确定今天的情况.但是任何反汇编程序都可以解决问题.截至 x64 ABI 注册 rcx 获得第一个参数,rdx 第二个.如果函数在内部使用 32 位寄存器名称或清除高 32 位,则您可以假设为 32 位整数.如果它使用它来加载地址(例如 lea 指令),您可以假设一个指针.但正如你所看到的,那可能不是你想要走的路......

Do you run Visual Studio? I remember that VS could enter a function call in debug mode and show the assembly, not sure though how it is today. But any disassembler should do the trick. As of x64 ABI register rcx gets the first argument, rdx the second. If the function internally works with the 32bit register names or clears the upper 32bit than you can assume a 32bit integer. If it uses it to load an address (e.g. lea instruction) you could assume a pointer. But as you can see, that's probably not a road you wanna go down...

那你还剩下什么?

您链接的文档说明了 32 位和 64 位库 - 取决于您使用的平台.我猜您使用的是 64 位库并且 RSA 没有更新此库的文档,但在某些时候开发人员需要将库升级到 64 位.

The document you've linked states a 32-bit and 64-bit library - depending on the platform you use. I guess you use the 64bit lib and that RSA did not update the documentation for this library, but at some point the developers needed to upgrade the library to 64bit.

所以请这样想:如果您是 API 开发人员,哪些可以迁移到 64 位,哪些不能.例如.无法触及需要跨 32/64 实现(通过网络发送或存储和共享在磁盘上的东西)工作的所有内容.但是实例本地的所有内容都可以迁移.由于 userData 似乎是一个运行时的东西,所以支持平台提供的任何东西都是有意义的:unsigned long 在 64 位上和 unsigned int 在 32 位上.

So think about this way: If you would be the API developer, what is possible to migrate to 64bit and what not. E.g. everything that needs to work across 32/64 implementations (stuff that gets send over the network or stored and shared on disk) cannot be touched. But everything that's local to the instance, can be migrated. As the userData seems to be a runtime thing, it makes sense to support whatever the platform provides: unsigned long on 64bit and unsigned int on 32bit.

您已经发现 userData 必须是 64 位.但不是因为该函数写出一个 64 位整数,而是因为该函数看到一个 64 位值开始.由于整数是按值传递的(我想一般来说,但绝对在 WINAPI),如果函数是 32 位数据类型,则绝对不可能看到完整的 64 位值.所以最有可能的是,API 开发人员将数据类型更改为 unsigned long(在任何情况下都更改为 64 位类型).

You've figured out that userData must be 64 bit. But not because the function writes out a 64bit integer, but because the function sees a 64bit value to start with. As integers are passed by value (I guess in general, but definitely in WINAPI), there's absolutely no chance the function could see the full 64bit value if it would be a 32bit datatype. So most likely, the API developers changed the datatype to unsigned long (in any case to 64bit type).

PS:如果您最终将指针放入 userData,请将指针转换为 uintptr_t 并存储/读取该类型.

PS: If you end up putting a pointer into userData, cast the pointer to uintptr_t and store/read that type.

这篇关于RSA Authentication Agent API 文档中的函数签名是否正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆