2011-05-25 39 views
13

我有一个使用OLE自动编组器的DCOM客户端和服务器应用程序。它们在同一台PC上运行时工作良好,但当服务器位于不同的PC上,而不在同一个域中时,我得到E_ACCESSDENIED(0x80070005)。DCOM中的模拟如何工作?

服务器PC使用dcomcnfg进行配置,以便将所有DCOM对象的访问权授予其客户端上指定的登录名和密码的用户。 ServerApp及其类型库在服务器PC上注册。

类型库也在客户端PC上注册。我直接在ClientApp中指定服务器名称,因此就我所知,客户端PC上不需要配置dcomcnfg。

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

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

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

首先,其凭据我ClientApp指定用户一个成功的网络登录。当我调用CreateInstanceEx()时会发生这种情况。

接下来,登录失败的用户登录客户端PC。由于两台PC不在一个域中,因此服务器PC不知道该用户。

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

研究CreateInterfaceEx参数,它似乎有某种模拟机制正在进行。但是谁扮演谁并不清楚。有包括三个用户凭证:在其下ServerApp服务器PC上运行(如在DCOMCNFG配置)

  1. 用户。

  2. ClientApp在连接时指定其凭据的用户。

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

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

对于DCOM来说,模拟#2似乎是合乎逻辑的,因为这是我明确指定的凭据。但为什么第二次登录尝试呢?

有人能解释一下模仿是如何工作的,以及是否有办法忽略它并以dcomcnfg中指定的用户身份运行?

回答

12

回答我自己的问题。多摸索很明显,DCOM有两种不同的标识情况

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

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

有两种方式指定#2的凭据。首先是CoSetProxyBlanket。它仅用于设置指定代理(编组,解组)的凭据:

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包装器。

0

对于那些在德尔福工作的人来说,有一点可以节省大量时间。在您完成obj as ISomeInterface操作后,您必须为新实例调用CoSetProxyBlanket。这可能不是很明显,但我们只知道as运算符调用了QueryInterface方法,并且它可以返回新的实例。