COM Delegation Using the COM Channel Hook Mechanism

Environment: Windows NT, COM

In one of my projects I needed a delegation feature for COM mechanism. The server, running under high-privileged account needed to issue COM calls on behalf of low-privileged clients to another COM server. After searching in MSDN I have found that the current situation is pretty simple: "COM does not support delegation". Although named pipes in WindowsNT environment support it for a single machine operations - COM does not. To overcome this situation I created my own user impersonation mechanism based on the usage of COM channel hook interface.

The idea behind the usage of COM channel hook mechanism is described in the very good and comprehensive way in January'98 issue of MSJ. In short, application could register COM callback interface that will be called by COM engine when it sends or receives a call. So application can add a whatever information it needs in the transparent for the interface user way. The callback interface IChannelHook consists of the following functions:

void ClientGetSize(REFGUID uExtent, 
                   REFIID riid, 
                   ULONG *pDataSize);

void ClientFillBuffer(REFGUID uExtent, 
                      REFIID riid, 
                      ULONG *pDataSize, 
                      void *pDataBuffer);

void ClientNotify(REFGUID uExtent, 
                  REFIID riid, 
                  ULONG cbDataSize, 
                  void *pDataBuffer, 
                  DWORD lDataRep, 
                  HRESULT hrFault);

void ServerNotify(REFGUID uExtent, 
                  REFIID riid, 
                  ULONG cbDataSize, 
                  void *pDataBuffer, 
                  DWORD lDataRep);

void ServerGetSize(REFGUID uExtent, 
                   REFIID riid, 
                   HRESULT hrFault, 
                   ULONG *pDataSize); 

void ServerFillBuffer(REFGUID uExtent, 
                      REFIID riid, 
                      ULONG *pDataSize, 
                      void *pDataBuffer, 
                      HRESULT hrFault);

When a COM client issues call to server, first ClientGetSize is called on the client's side to determine size of additional data and then ClientFillBuffer to fill buffer with actual data. When COM call arrives to the server - server side gets notified about arrived data through ServerNotify function. Functions ServerGetSize and ServerFillBuffer are called on the way back on the server's side and, finally, ClientNotify when the call returns on the client's side.

To make delegation possible I attach the following information to the COM hook buffer:

  • process ID of the process that issued a call
  • network name of the computer that issued a call
  • user token of the thread that issued a call (if it exists) or process-wide user token (if it does not)

When the data arrives on the server's side the code first checks whether the client and server reside on the same machine, using transferred machine name, because user token that we have transferred as well makes sense only on the same machine. If machine is the same, server tries to open a process that issued a call and duplicate token, for it to be valid for the server's process. And then it uses the duplicated token to call ImpersonateLoggedOnUser function to do actual user impersonation.

All information about incoming calls is kept in the thread local storage (TLS) on per-thread basis. To avoid losing information in case of recursive COM calls, the information about incoming calls is kept as a stack and every new call pushes its new context on the stack and removes it on the way back to server.

The COM channel hook will be installed automatically as long as DLL is loaded into memory of the process. This could be done either by explicit call to LoadLibrary function or implicitly by CoCreateInstance call, creating IClientInfo interface.

For the proper functionality of the discussed user impersonation method the channel hook must be installed both in the client and server processes. For my project I managed to do it automatically for client and for server by initializing interface to the IClientInfo from the Proxy-Stub DLL that is automatically generated by MSVC Wizard. To do so you need to create a new "c" file that looks like this :

#include "..\COMchannelinfo\dcom_channel_info.h"
#include "..\dcomchannelinfo\dcom_channel_info_i.c"

//previous DLLMain function 
                    DWORD fdwReason, 
                    LPVOID lpvReserved);

                       DWORD fdwReason, 
                       LPVOID lpvReserved)
static IClientInfo* client_info_iface;
switch (fdwReason)
    client_info_iface = NULL;
    hr = CoCreateInstance(&CLSID_ClientInfo, 
    if (FAILED(hr))
        return FALSE;
    }; break;
        if (client_info_iface != NULL)
    } __except (1)
        //we do not care if something has happened on shutdown
    }; break;
return DllMain(hinstDLL, fdwReason, lpvReserved);

And then patch a generated make-file for your proxy-stub DLL (usually it has name of the project + "" at the end) and make the following changes to it:

rcserverps.dll: dlldata.obj rcserver_p.obj rcserver_i.obj rcserverps_dllmain.obj
(this is a new object file)
    link /dll /out:rcserverps.dll /def:rcserverps.def /entry:newDllMain (this is new DLL entry point) dlldata.obj rcserver_p.obj \
    rcserver_i.obj rcserverps_dllmain.obj (this is a new object file) \
    kernel32.lib rpcndr.lib rpcns4.lib rpcrt4.lib oleaut32.lib uuid.lib ole32.lib (additional standard library)

The effect of this operation is the following: as soon as you make a first call to your COM interface - proxy-stub DLL will be loaded automatically by COM engine and in its DLLMain it loads and installs our COM channel hook that transfers required information about called user automatically! You have an advanced impersonation routine for free! :)

Interface Usage

You need to register the DLL with the call to regsvr32.exe dcom_channel_info.dll.

Sources, Demos, Updates and Legal Stuff

  • Latest sources and updates for the application could be found here.
  • Interface itself is used in the Remote Control application (in its server part) which could be used as an example on usage of this impersonation method. It also could be found here.
  • You can drop an e-mail to author here.


Big thanks to Don Box for pointing an elegant solution to my problem.


Download source - 40 Kb


  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • "Security" is the number one issue holding business leaders back from the cloud. But does the reality match the perception? Keeping data close to home, on premises, makes business and IT leaders feel inherently more secure. But the truth is, cloud solutions can offer companies real, tangible security advantages. Before you assume that on-site is the only way to keep data safe, it's worth taking a comprehensive approach to evaluating risks. Doing so can lead to big benefits.

  • Hybrid cloud platforms need to think in terms of sweet spots when it comes to application platform interface (API) integration. Cloud Velocity has taken a unique approach to tight integration with the API sweet spot; enough to support the agility of physical and virtual apps, including multi-tier environments and databases, while reducing capital and operating costs. Read this case study to learn how a global-level Fortune 1000 company was able to deploy an entire 6+ TB Oracle eCommerce stack in Amazon Web …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds