【发布时间】:2026-01-17 06:30:01
【问题描述】:
问题:
我在代理上成功调用 CoSetProxyBlanket(如果这是正确的术语),然后我在同一个代理上调用 QueryInterface,但我收到 0x80070005(“拒绝访问”)的结果。但是,如果我首先使用相同的凭据调用 CoInitializeSecurity (我试图避免),那么调用就会成功。
问题:
如何在不调用 CoInitializeSecurity 的情况下成功获取我需要的接口?据我了解,一个进程只能调用一次此方法,因此它与制作 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,并且在返回值下,没有提到拒绝访问的可能性。我不认为这个问题是特定于实现的,因为我已经在一些著名的商业 OPC 服务器(例如 Matrikon Simulation Server)以及没有实现任何额外安全性的开源 LightOPC 上尝试了我的代码。
我猜我需要做的是找到一种方法来复制这个命令
hr = m_IOPCItemMgt->QueryInterface(IID_IOPCSyncIO, (void**)&m_IOPCSyncIO);
但同时提供authIdentity。这可能吗?可以通过 CoCreateInstanceEx 或 CoGetClassObject 或其他一些 COM 调用来完成吗?
【问题讨论】: