2016-09-12 44 views
1

问题:定制身份调用的QueryInterface

我成功地调用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与此服务器信息的获取句柄(m_IOPCServer )到我的OPC服务器(IID_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这样的其他方法调用使用相同的安全性。但是在微软的参考QueryInterface中,在实现者的注释中,它使得听起来像QueryInterface不应该检查ACL,并且在返回值下,Access Denied没有被提及为可能。我不认为这个问题是特定于实现的,但是因为我已经在一些众所周知的商业OPC服务器(例如Matrikon Simulation Server)以及不实现任何额外安全性的开源LightOPC上尝试了我的代码。

我猜测什么,我需要做的是找到一种方法来复制该命令

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

,但这样做的同时也提供authIdentity。这可能吗?它可以通过CoCreateInstanceEx或CoGetClassObject或其他COM调用完成吗?

回答

1

没有进入太多细节:每个进程总是至少调用一次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

+0

这并没有帮助我。我怎样才能调用QueryInterface与进程不同的安全上下文?例如,我怎样才能创建一个程序连接到多个使用不同凭证的OPC服务器? – bruceceng

+0

只需注意“返回值不足,访问被拒绝就不被视为可能性”:在COM中,一组成功代码被认为是接口合约的一部分,而错误代码则不成立。也就是说,即使没有记录,接口方法也可以返回它想要的任何错误,而不会破坏“接口合同”。有许多错误代码(比如RPC_xxxx),几乎可以返回任何(D)COM方法,并且每个方法都没有记录它们。所记录的错误代码因此是“用于说明”,那些值得解释的错误代码,但仅此而已。 – ZbynekZ

+0

对QuerryInterface调用中的安全上下文没有太多控制。您可以在代理中实现自定义代理并调整CoInitializeSecurity,但每个代理都会有一个安全上下文。有关自定义代理的更多信息,请访问:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682432(v=vs.85).aspx –

0

你必须调用CoSetProxyBlanket对每一个新的COM对象实例,所以你的情况,你必须即使是m_IOPCItemMgt