DCOM 中的模拟如何工作? [英] How does impersonation in DCOM work?

查看:8
本文介绍了DCOM 中的模拟如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a DCOM client and server applications which use OLE automation marshaller. They work fine when run on the same PC but when the server is on a different PC not in the same domain I get E_ACCESSDENIED (0x80070005).

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

Server PC is configured with dcomcnfg to give all access to any DCOM object to the user whose login and password I specify on the client. ServerApp and its type library are registered on the server pc.

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

Type library is also registered on the client PC. I specify server name directly in the ClientApp so no dcomcnfg configuration is needed on the Client PC as far as I understand.

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

CreateInstanceEx() with server name, login, domain and password works fine. It returns IUnknown and at the same time starts ServerApp on server PC.

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

But when I try to QueryInterface() for the interface which server supports, I get E_ACCESSDENIED.

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

Analyzing the Security Event Log, I have two records there:

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

First, a successful network login by the user whose credentials I specify in ClientApp. This happens when I call CreateInstanceEx().

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

Next, a failed login attempt by the user under which I'm logged in on a client PC. Since two PCs are not in a domain, this user is unknown to server PC.

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

Now, why the heck would THIS user be logging into server, especially when I call QueryInterface of all things?

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

Studying CreateInterfaceEx params, it appears there's some kind of impersonation mechanism going on. But it's unclear who impersonates who. There are THREE user credentials involved:

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

  1. User under which ServerApp runs on the server PC (as configured in dcomcnfg).

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

User whose credentials ClientApp specifies when connecting.

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

User under whose credentials ClientApp runs on client PC.

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

No matter how you look at it, if #3 is involved it's one user too much. If DCOM is going to identify/impersonate #3 on server PC anyway, why do I need to specify #2's credentials? To what point?

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

It would have seem logical for DCOM to impersonate #2 because this is what I have explicitly specified as my credentials. But why the second login attempt then?

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

Can someone please explain how exactly the impersonation works, and also if there's a way to just ignore it and run as user which is specified in dcomcnfg?

推荐答案

回答我自己的问题.经过大量探索,很明显DCOM 有两种不同的识别案例:

Answering my own question. After much exploration it became apparent that DCOM has TWO different identification cases:

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

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

For reasons unknown, #2 doesn't inherit #1 settings. By default it uses the credentials of the client process, hence strange logins.

有两种方法可以为 #2 指定凭据.第一个是 CoSetProxyBlanket.它只为指定的代理 (marshaller-unmarshaller) 设置凭据:

There are two ways to specify credentials for #2. First one is CoSetProxyBlanket. It sets credentials for a specified proxy (marshaller-unmarshaller) only:

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 之外没有任何作用.

It's important to note that while CoCreateInstanceEx requires impersonation level to be at least IMPERSONATE, CoSetProxyBlanket doesn't seem to work on anything except IDENTIFY.

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

Another option is to use CoInitializeSecurity to set default credentials for the whole process. Then you don't have to call CoSetProxyBlanket on every proxy:

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

在客户端上使用 CoInitializeSecurity 时,您也必须指定 asAuthSvc,即使 MSDN 说您不这样做.

When using CoInitializeSecurity on the client you have to specify asAuthSvc too, even though MSDN says you don't.

此方法的缺点显然是,如果您有来自不同 PC 的多个 DCOM 对象,您将不得不在此调用中指定所有凭据,并且每次打开一个不同的代理.

The drawback of this method is obviously that if you have several DCOM objects from different PCs you're going to have to specify all the credentials in this call and those are probably going to be tried against every computer every time you open a different proxy.

当您从 DLL 运行时,它也不可靠(如果进程具有不同的默认安全性怎么办?).因此,最好在每次调用返回之前实现一个 QueryInterface 包装器,该包装器 CoSetsProxyBlanket.

It also is not reliable when you're running from a DLL (what if a process has different default security?). So, it's probably better to implement a QueryInterface wrapper which CoSetsProxyBlanket before returning from every call.

这篇关于DCOM 中的模拟如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆