【问题标题】:How does impersonation in DCOM work?DCOM 中的模拟如何工作?
【发布时间】:2011-09-01 16:07:23
【问题描述】:

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

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

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

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

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

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

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

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

现在,为什么这个用户会登录服务器,尤其是当我调用所有事物的 QueryInterface 时?

研究 CreateInterfaceEx 参数,似乎存在某种模拟机制。但目前还不清楚谁冒充谁。涉及三个用户凭据:

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

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

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

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

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

谁能解释一下模拟的具体工作原理,以及是否有办法忽略它并以 dcomcnfg 中指定的用户身份运行?

【问题讨论】:

    标签: windows com remoting dcom


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      回答我自己的问题。经过大量探索,很明显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 运行时,它也不可靠(如果进程具有不同的默认安全性怎么办?)。因此,最好在每次调用返回之前实现一个 QueryInterface 包装器,该包装器 CoSetsProxyBlanket。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-07
        • 2017-04-21
        • 1970-01-01
        • 2012-10-28
        • 2020-03-14
        • 2019-02-03
        • 2017-06-23
        相关资源
        最近更新 更多