c++ - 使用自定义标识调用 QueryInterface

标签 c++ com dcom opc

问题:

我在代理上成功调用了 CoSetProxyBlanket(如果这是正确的术语),然后我在同一个代理上调用了 QueryInterface,但我收到了 0x80070005(“拒绝访问”)的结果。但是,如果我首先使用相同的凭据调用 CoInitializeSecurity (我试图避免这种情况),则调用会成功。

问题:

如何在不调用CoInitializeSecurity的情况下成功获取到自己需要的接口(interface)?据我了解,一个进程只能调用此方法一次,因此它与制作 dll 不兼容,通常可以用对 CoSetProxyBlanket 的调用来代替。

详细信息:

我正在尝试构建自己的 OPC 客户端,它可以与运行在不同域上的计算机通信,无需匹配的用户帐户。

首先,我创建一个身份结构,其中包含在服务器上有效的域、用户名和密码:

COAUTHINFO      authInfo;
COAUTHIDENTITY  authIdentity;

authIdentity.Domain             = (unsigned short *) w_domain;
authIdentity.DomainLength       = wcslen( w_domain);
authIdentity.Flags              = SEC_WINNT_AUTH_IDENTITY_UNICODE;
authIdentity.Password           = (unsigned short *) w_password;
authIdentity.PasswordLength     = wcslen(w_password);
authIdentity.User               = (unsigned short *) w_username;
authIdentity.UserLength         = wcslen(w_username);

authInfo.dwAuthnLevel           = RPC_C_AUTHN_LEVEL_CALL;
authInfo.dwAuthnSvc             = RPC_C_AUTHN_WINNT;
authInfo.dwAuthzSvc             = RPC_C_AUTHZ_NONE;
authInfo.dwCapabilities         = EOAC_NONE;
authInfo.dwImpersonationLevel   = RPC_C_IMP_LEVEL_IMPERSONATE;
authInfo.pAuthIdentityData      = &authIdentity;
authInfo.pwszServerPrincName    = NULL;

ServerInfo.pAuthInfo = &authInfo;

然后我可以使用此服务器信息调用 CoCreateInstanceEx 并获取我的 OPC 服务器 (IID_IOPCServer) 的句柄 (m_IOPCServer)。

获得句柄后,我发现有必要通过此调用再次设置更多权限(参见 How does impersonation in DCOM work?):

hr = CoSetProxyBlanket(m_IOPCServer, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, 
         NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, 
         &authIdentity, EOAC_NONE);

在此之后,我能够成功获得 OPC 项组的句柄:

hr = m_IOPCServer->AddGroup(L"", FALSE, reqUptRate, clientHandle, 
         NULL, NULL, lcid, &m_hServerGroup, &revisedUptRate, 
         IID_IOPCItemMgt,(LPUNKNOWN*)&m_IOPCItemMgt);

但是,当我尝试使用这段代码时:

hr = m_IOPCItemMgt->QueryInterface(IID_IOPCSyncIO, (void**)&m_IOPCSyncIO);

结果是 0x80070005(“拒绝访问”)。即使我在 m_IOPCItemMgt 上成功调用 CoSetProxyBlanket 也是如此。但是,如果我首先调用 CoInitializeSecurity,则调用会成功。

我认为问题与 How does impersonation in DCOM work? 有关因为 QueryInterface 函数是一种对象创建形式,所以它不使用与其他方法调用(如 AddGroup)相同的安全性。但是在 Microsoft 引用中 QueryInterface ,在给实现者的注释下,听起来 QueryInterface 不应该检查 ACL,并且在返回值下,没有提到 Access Denied 是一种可能性。我不认为这个问题是特定于实现的,因为我已经在一些著名的商业 OPC 服务器(例如 Matrikon Simulation Server)以及没有实现任何额外安全性的开源 LightOPC 上尝试了我的代码。

我猜我需要做的是找到一种方法来复制这个命令

hr = m_IOPCItemMgt->QueryInterface(IID_IOPCSyncIO, (void**)&m_IOPCSyncIO);

但同时提供 authIdentity。这可能吗?可以使用 CoCreateInstanceEx 或 CoGetClassObject 或其他一些 COM 调用来完成吗?

最佳答案

无需过多赘述:CoInitializeSecurity 总是在每个进程中至少调用一次。这可以隐式或显式地完成。如果您的代码没有进行显式调用,DCOM 运行时会使用从注册表填充的参数为您完成。您可以尝试调整适当的注册表值以强制 DCOm 使用与显式调用中使用的值相似的值。保存这些值的注册表项是“HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID{AppID_GUID}” 此处描述了此项:https://msdn.microsoft.com/en-us/library/windows/desktop/ms693736(v=vs.85).aspx

关于c++ - 使用自定义标识调用 QueryInterface,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39460079/

相关文章:

c++ - boost::random::variate_generator - 构造后更改参数

c++ - 如何使用对象指针而不是对象来编写赋值运算符/复制构造函数?

com - 从 Go 查询 WMI

c++ - Winforms DLL 在 DCOM 下不启动

vb.net - 注册 COM+ 应用程序代理时出错

.net - 什么是二进制标准

c++ - 0MQ 远程登录数据 C++

c++ - C++继承/类设计问题

c# - 我可以在 WCF 命名管道上传递 COM 接口(interface)吗?

c++ - 如何从 64 位进程或 64 位 dll 访问 32 位 dll