How does impersonation in DCOM work?

馋奶兔 提交于 2019-11-30 05:11:32

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

  1. Authorization for object creation (CoCreateInstanceEx)
  2. Authorization for method calls.

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

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.

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.

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!

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

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.

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.

For those who are working in Delphi there is one little note that can save a lot of your time. After you did obj as ISomeInterface operation, you have to call CoSetProxyBlanket for the new instance. This could be not very obvious, but all we know that as operator calls QueryInterface method, and it can return new instance.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!