windows-nt/Source/XPSP1/NT/com/rpc/runtime/epmap/mqmgr.cxx
2020-09-26 16:20:57 +08:00

345 lines
9 KiB
C++

//-------------------------------------------------------------------
// Copyright (C) Microsoft Corporation, 1991 - 1999
//
// mqmgr.c
//
// Abstract:
//
// Functions to manage temporary Falcon message queues for RPC. The
// RPC support of Falcon as a transport allows for temporary queues
// which exist only as long as the process. These functions manage
// these temporary queues.
//
// Author:
//
// Edward Reus (edwardr)
//
// Revision History:
//
//-------------------------------------------------------------------
#include <sysinc.h>
#define FD_SETSIZE 1
#include <wtypes.h>
#include <rpc.h>
#include <rpcdcep.h>
#include <rpcerrp.h>
#include <rpctrans.hxx>
#include <stdlib.h>
#include <objidl.h>
#include <mq.h>
#include "mqmgr.h"
#define MAX_FORMAT_LEN 128
//-------------------------------------------------------------------
// Local Types:
//-------------------------------------------------------------------
typedef struct _MqTempQueue
{
struct _MqTempQueue *pNext;
WCHAR wsQFormat[MAX_FORMAT_LEN];
} MqTempQueue;
typedef struct _MqTempQueueList
{
HANDLE hToken; // For impersonation of the client.
MqTempQueue *pQueues;
} MqTempQueueList;
typedef HRESULT (APIENTRY *MQ_DELETE_QUEUE_FN)( WCHAR *pwsQFormat );
#define MQRT_DLL_NAME TEXT("MQRT.DLL")
#define MQ_DELETE_FN_NAME "MQDeleteQueue"
//-------------------------------------------------------------------
// Globals:
//-------------------------------------------------------------------
static HINSTANCE g_hMqDll = 0;
static MQ_DELETE_QUEUE_FN g_pMqDeleteQueue = 0;
//-------------------------------------------------------------------
// MqGetContext()
//
// Establishs a context handle to manage temporary queues. Once the
// context handle is created, the RPC client and server processes
// will automatically register temporary queues.
//-------------------------------------------------------------------
unsigned long MqGetContext( handle_t hBind,
PCONTEXT_HANDLE *pphContext )
{
RPC_STATUS Status = RPC_S_OK;
HANDLE hToken = 0;
HANDLE hThread = 0;
MqTempQueueList *pqList;
// First, check to see if the MQ runtime DLL has been loaded. If not,
// then load it and resolve the entry for the function to delete queues.
if (!g_hMqDll)
{
g_hMqDll = LoadLibrary(MQRT_DLL_NAME);
if (g_hMqDll)
{
g_pMqDeleteQueue = (MQ_DELETE_QUEUE_FN)GetProcAddress(g_hMqDll,MQ_DELETE_FN_NAME);
if (!g_pMqDeleteQueue)
{
Status = GetLastError();
FreeLibrary(g_hMqDll);
g_hMqDll = 0;
return Status;
}
}
else
{
// The LoadLibrary() call failed.
Status = GetLastError();
*pphContext = NULL;
return Status;
}
}
// Ok, create a context for this connection. Also, grab the
// client's security token for later use when deleting the
// queue.
*pphContext = pqList = (MqTempQueueList*)I_RpcAllocate(sizeof(MqTempQueueList));
if (!*pphContext)
{
Status = RPC_S_OUT_OF_MEMORY;
}
else
{
ZeroMemory( pqList, sizeof(MqTempQueueList) );
Status = RpcImpersonateClient(hBind);
if (RPC_S_OK == Status)
{
if ( (hThread=GetCurrentThread())
&& (OpenThreadToken(hThread,TOKEN_IMPERSONATE,FALSE,&hToken)) )
{
pqList->hToken = hToken;
}
else
{
Status = GetLastError();
}
if (hThread)
{
CloseHandle(hThread);
}
Status = RpcRevertToSelf();
}
else
{
// If the impersonation failed, then plow ahead anyway. We
// can still keep the list of queues and "maybe" delete them.
Status = RPC_S_OK;
}
}
#ifdef DBG
DbgPrint("MqGetContext(): hToken: 0x%x\n",hToken);
#endif
return Status;
}
//-------------------------------------------------------------------
// MqRegisterQueue()
//
// Register the specified queue as a temporary queue that will
// need to be deleted by the context rundown routine when the
// client exits. The registration is actually done by the MQ RPC
// client and server transport DLLs.
//-------------------------------------------------------------------
unsigned long MqRegisterQueue( PCONTEXT_HANDLE phContext,
wchar_t *pwsQFormat )
{
RPC_STATUS Status = RPC_S_OK;
MqTempQueue *pTempQueue;
MqTempQueueList *pqList = (MqTempQueueList*)phContext;
pTempQueue = (MqTempQueue*)I_RpcAllocate(sizeof(MqTempQueue));
if (!pTempQueue)
{
return RPC_S_OUT_OF_MEMORY;
}
memset(pTempQueue,0,sizeof(MqTempQueue));
ASSERT(pwsQFormat);
ASSERT(wcslen(pwsQFormat) < MAX_FORMAT_LEN);
wcscpy(pTempQueue->wsQFormat,pwsQFormat);
// Ok, put the queue on the list to delete.
pTempQueue->pNext = pqList->pQueues;
pqList->pQueues = pTempQueue;
return Status;
}
//-------------------------------------------------------------------
// MqDeregisterQueue()
//
// Remove the specified message queue from the list of queues to
// be deleted by the context rundown routine. This would be done
// if a queue (which is initially temporary) was turned into a
// permanent queue.
//-------------------------------------------------------------------
unsigned long MqDeregisterQueue( PCONTEXT_HANDLE phContext,
wchar_t *pwsQFormat )
{
RPC_STATUS Status = RPC_S_OK;
MqTempQueueList *pqList = (MqTempQueueList*)phContext;
MqTempQueue *pTempQueue;
MqTempQueue *pTempToFree;
if (!pqList)
{
return RPC_X_SS_IN_NULL_CONTEXT;
}
pTempQueue = pqList->pQueues;
if (!lstrcmpiW(pTempQueue->wsQFormat,pwsQFormat))
{
pqList->pQueues = pTempQueue->pNext;
I_RpcFree(pTempQueue);
return RPC_S_OK;
}
while (pTempQueue->pNext)
{
if (!lstrcmpiW(pTempQueue->pNext->wsQFormat,pwsQFormat))
{
pTempToFree = pTempQueue->pNext;
pTempQueue->pNext = pTempQueue->pNext->pNext;
I_RpcFree(pTempToFree);
break;
}
}
return Status;
}
//-------------------------------------------------------------------
// MqFreeContext()
//
// Called to remove all of the queues registered for automatic
// deletion and to close and free the context handle.
//-------------------------------------------------------------------
unsigned long MqFreeContext( PCONTEXT_HANDLE *pphContext,
long fFreeContext )
{
RPC_STATUS Status = RPC_S_OK;
HRESULT hr;
BOOL fImpersonate = FALSE;
MqTempQueueList *pqList = (MqTempQueueList*)*pphContext;
MqTempQueue *pTemp;
MqTempQueue *pToFree;
// First, impersonate the client who registered these queues
// to delete.
if (pqList->hToken)
{
fImpersonate = SetThreadToken(NULL,pqList->hToken);
#ifdef DBG
if (!fImpersonate)
{
Status = GetLastError();
}
#endif
}
// Run through the list of queues deleting each one as
// we go.
pTemp = pqList->pQueues;
while (pTemp)
{
pToFree = pTemp;
pTemp = pTemp->pNext;
hr = g_pMqDeleteQueue(pToFree->wsQFormat);
#ifdef FALSE
DbgPrint("Delete Queue: %S (hr: 0x%x)\n", pToFree->wsQFormat, hr );
#endif
I_RpcFree(pToFree);
}
// Stop the impersonation:
if (fImpersonate)
{
if (!SetThreadToken(NULL,NULL))
{
Status = GetLastError();
}
}
// Do we need to free up the context?
if (pqList->hToken)
{
if (!CloseHandle(pqList->hToken))
{
Status = GetLastError();
#ifdef DBG
DbgPrint("MqFreeContext(): CloseHandle() Failed: Status: %d (0x%x)\n",Status,Status);
#endif
}
}
if (fFreeContext)
{
I_RpcFree(pqList);
*pphContext = NULL;
}
else
{
pqList->hToken = 0;
pqList->pQueues = NULL;
}
return Status;
}
//-------------------------------------------------------------------
// PCONTEX_HANDLE_rundown()
//
// This is the context rundown routine. It will delete all of the
// Falcon message queues that are currently associated with the
// specified context handle.
//-------------------------------------------------------------------
void __RPC_USER PCONTEXT_HANDLE_rundown( PCONTEXT_HANDLE phContext )
{
RPC_STATUS Status;
Status = MqFreeContext(&phContext,FALSE);
}
//-------------------------------------------------------------------
// StartMqManagement()
//
// Called in dcomss\warpper\start.cxx by RPCSS to initialize the
// MQ Management interface.
//-------------------------------------------------------------------
extern "C"
DWORD StartMqManagement()
{
RPC_STATUS Status;
Status = RpcServerRegisterIf(MqMgr_ServerIfHandle,0,0);
return Status;
}