DCOM中的模拟如何工作?

我有一个使用OLE自动编组器的DCOM客户端和服务器应用程序。 它们在同一台PC上运行时工作正常,但是当服务器在不同的PC上不在同一个域中时,我得到E_ACCESSDENIED(0x80070005)。

使用dcomcnfgconfiguration服务器PC,以便将所有DCOM对象的访问权限授予在客户端上指定其login名和密码的用户。 ServerApp及其types库在服务器PC上注册。

types库也在客户端PC上注册。 我直接在ClientApp中指定服务器名称,所以就我所知,客户端PC上不需要configurationdcomcnfg。

CreateInstanceEx()与服务器名称,login,域和密码工作正常。 它返回IUnknown,同时在服务器PC上启动ServerApp。

但是,当我尝试QueryInterface()为服务器支持的接口,我得到E_ACCESSDENIED。

分析安全事件日志,我有两个logging:

首先,用户在ClientApp中指定的凭据成功进行networkinglogin。 当我调用CreateInstanceEx()时会发生这种情况。

接下来, 我在客户端PC上login的用户login失败。 由于两台PC不在一个域中,所以该用户对于服务器PC是未知的。

现在,为什么这个用户会login到服务器,特别是当我调用QueryInterface的所有东西?

研究CreateInterfaceEx参数,似乎有某种模拟机制正在进行。 但是谁扮演谁还不清楚。 有三个用户凭证参与:

  1. ServerApp在服务器PC上运行的用户(在dcomcnfg中configuration)。

  2. 连接时ClientApp指定的用户的用户。

  3. 用户ClientApp在客户端PC上运行的凭据。

无论你如何看待它,如果涉及#3,它是一个用户太多。 如果DCOM要在服务器PC上识别/模拟#3,为什么我需要指定#2的凭据? 到了什么地步?

DCOM假冒#2似乎是合乎逻辑的,因为这是我明确指定的凭据。 但为什么第二次login尝试呢?

有人能解释一下模拟是如何工作的,而且如果有一种方法可以忽略它并以dcomcnfg中指定的用户身份运行?

Solutions Collecting From Web of "DCOM中的模拟如何工作?"

回答我自己的问题。 经过很多的探索, DCOM有两个不同的识别案例

  1. 对象创建授权(CoCreateInstanceEx)
  2. 方法调用的授权。

由于未知原因,#2不会继承#1设置。 默认情况下,它使用客户端进程的凭据,因此奇怪的登录。

有两种方式指定#2的凭证。 第一个是CoSetProxyBlanket 。 它仅为指定的代理(marshaller-unmarshaller)设置凭据:

CoCreateInstanceEx(IID_IObject1, /*login, pass*/, obj1); //Success! //Logged in and recevied IObject1 proxy in obj1 obj1->DoSomething(); //IObject1 proxy in obj1 now tries to login under process credentials. //Failure! E_ACCESSDENIED CoSetProxyBlanket(obj1, /*login, pass*/); //Success! //IObject1 proxy is now authorized. obj1->DoSomething(); //Success! obj1->QueryInterface(IID_IObject2, obj2); //Success! obj2->DoSomethingElse(); //Failure! //This different proxy for IObject2 have not yet been authorized. CoSetProxyBlanket(obj2, /*login, pass*/); //etc. 

请注意,尽管CoCreateInstanceEx要求模拟级别至少为IMPERSONATE,但CoSetProxyBlanket似乎不适用于除IDENTIFY以外的任何其他功能。

另一个选项是使用CoInitializeSecurity为整个过程设置默认凭据。 那么你不必在每个代理上调用CoSetProxyBlanket:

 CoInitializeSecurity(/* login, pass */); CoCreateInstanceEx(IID_IUnknown, /*login, pass*/, obj); //Success! obj->DoSomething(); //Success! 

当在客户端上使用CoInitializeSecurity时,你也必须指定asAuthSvc ,即使MSDN说你没有。

这种方法的缺点很明显,如果你有不同的PC的几个DCOM对象,你将不得不在这个调用中指定所有的凭证,并且每次打开一个不同的代理时,这些凭证可能会在每台计算机上被试用。

当你从一个DLL运行的时候,这也是不可靠的(如果一个进程有不同的默认安全性呢?)。 所以,最好在从每次调用返回之前实现一个CoSetsProxyBlanket的QueryInterface包装器。