How does impersonation in DCOM work? How does impersonation in DCOM work? windows windows

How does impersonation in DCOM work?


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 obj1obj1->DoSomething();//IObject1 proxy in obj1 now tries to login under process credentials.//Failure! E_ACCESSDENIEDCoSetProxyBlanket(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.