发行:
我成功地在代理上调用了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)。
在获得句柄后,我发现有必要再次使用此调用设置更多权限(请参见DCOM中的模拟是如何工作的?):
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上调用了m_IOPCItemMgt,情况也是如此。但是,如果我首先调用CoInitializeSecurity,那么调用就成功了。
我认为与DCOM中的模拟是如何工作的?相关的问题是,QueryInterface函数是一种对象创建形式,因此它不使用与其他方法调用(如AddGroup )相同的安全性。然而,在Microsoft QueryInterface中,在提交给实现者的说明中,它让人觉得QueryInterface不应该检查ACL,而且在返回值下,拒绝访问也不是一种可能。不过,我并不认为这个问题是具体的实现问题,因为我已经在一些著名的商用OPC服务器(例如)上尝试了我的代码,以及没有实现任何额外安全性的开源LightOPC。
我猜我需要做的是找到一种复制这个命令的方法
hr = m_IOPCItemMgt->QueryInterface(IID_IOPCSyncIO, (void**)&m_IOPCSyncIO);但是这样做的同时也提供了authIdentity。这个是可能的吗?可以用CoCreateInstanceEx、CoGetClassObject或其他COM调用来完成吗?
发布于 2016-09-12 23:30:23
没有过多的细节:每个进程总是至少调用一次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
发布于 2018-02-02 13:27:30
您必须在每个新的COM对象实例上调用CoSetProxyBlanket,所以在您的示例中,甚至对于m_IOPCItemMgt,都必须调用它。
发布于 2021-01-26 15:17:25
在使用CoSetProxyBlanket之前,需要在IUnknown接口中调用QueryInterface
CComPtr<IUnknown> pUnknown;
hr = m_IOPCItemMgt->QueryInterface(IID_IUnknown, (void**)&pUnknown);
hr = CoSetProxyBlanket(pUnknown, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE,
&authIdentity, EOAC_NONE);
hr = pUnknown->QueryInterface(IID_IOPCSyncIO, (void**)&m_IOPCSyncIO);您可以查看这以获得更多信息。
https://stackoverflow.com/questions/39460079
复制相似问题