Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

344 lines
9.0 KiB

  1. //-------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation, 1991 - 1999
  3. //
  4. // mqmgr.c
  5. //
  6. // Abstract:
  7. //
  8. // Functions to manage temporary Falcon message queues for RPC. The
  9. // RPC support of Falcon as a transport allows for temporary queues
  10. // which exist only as long as the process. These functions manage
  11. // these temporary queues.
  12. //
  13. // Author:
  14. //
  15. // Edward Reus (edwardr)
  16. //
  17. // Revision History:
  18. //
  19. //-------------------------------------------------------------------
  20. #include <sysinc.h>
  21. #define FD_SETSIZE 1
  22. #include <wtypes.h>
  23. #include <rpc.h>
  24. #include <rpcdcep.h>
  25. #include <rpcerrp.h>
  26. #include <rpctrans.hxx>
  27. #include <stdlib.h>
  28. #include <objidl.h>
  29. #include <mq.h>
  30. #include "mqmgr.h"
  31. #define MAX_FORMAT_LEN 128
  32. //-------------------------------------------------------------------
  33. // Local Types:
  34. //-------------------------------------------------------------------
  35. typedef struct _MqTempQueue
  36. {
  37. struct _MqTempQueue *pNext;
  38. WCHAR wsQFormat[MAX_FORMAT_LEN];
  39. } MqTempQueue;
  40. typedef struct _MqTempQueueList
  41. {
  42. HANDLE hToken; // For impersonation of the client.
  43. MqTempQueue *pQueues;
  44. } MqTempQueueList;
  45. typedef HRESULT (APIENTRY *MQ_DELETE_QUEUE_FN)( WCHAR *pwsQFormat );
  46. #define MQRT_DLL_NAME TEXT("MQRT.DLL")
  47. #define MQ_DELETE_FN_NAME "MQDeleteQueue"
  48. //-------------------------------------------------------------------
  49. // Globals:
  50. //-------------------------------------------------------------------
  51. static HINSTANCE g_hMqDll = 0;
  52. static MQ_DELETE_QUEUE_FN g_pMqDeleteQueue = 0;
  53. //-------------------------------------------------------------------
  54. // MqGetContext()
  55. //
  56. // Establishs a context handle to manage temporary queues. Once the
  57. // context handle is created, the RPC client and server processes
  58. // will automatically register temporary queues.
  59. //-------------------------------------------------------------------
  60. unsigned long MqGetContext( handle_t hBind,
  61. PCONTEXT_HANDLE *pphContext )
  62. {
  63. RPC_STATUS Status = RPC_S_OK;
  64. HANDLE hToken = 0;
  65. HANDLE hThread = 0;
  66. MqTempQueueList *pqList;
  67. // First, check to see if the MQ runtime DLL has been loaded. If not,
  68. // then load it and resolve the entry for the function to delete queues.
  69. if (!g_hMqDll)
  70. {
  71. g_hMqDll = LoadLibrary(MQRT_DLL_NAME);
  72. if (g_hMqDll)
  73. {
  74. g_pMqDeleteQueue = (MQ_DELETE_QUEUE_FN)GetProcAddress(g_hMqDll,MQ_DELETE_FN_NAME);
  75. if (!g_pMqDeleteQueue)
  76. {
  77. Status = GetLastError();
  78. FreeLibrary(g_hMqDll);
  79. g_hMqDll = 0;
  80. return Status;
  81. }
  82. }
  83. else
  84. {
  85. // The LoadLibrary() call failed.
  86. Status = GetLastError();
  87. *pphContext = NULL;
  88. return Status;
  89. }
  90. }
  91. // Ok, create a context for this connection. Also, grab the
  92. // client's security token for later use when deleting the
  93. // queue.
  94. *pphContext = pqList = (MqTempQueueList*)I_RpcAllocate(sizeof(MqTempQueueList));
  95. if (!*pphContext)
  96. {
  97. Status = RPC_S_OUT_OF_MEMORY;
  98. }
  99. else
  100. {
  101. ZeroMemory( pqList, sizeof(MqTempQueueList) );
  102. Status = RpcImpersonateClient(hBind);
  103. if (RPC_S_OK == Status)
  104. {
  105. if ( (hThread=GetCurrentThread())
  106. && (OpenThreadToken(hThread,TOKEN_IMPERSONATE,FALSE,&hToken)) )
  107. {
  108. pqList->hToken = hToken;
  109. }
  110. else
  111. {
  112. Status = GetLastError();
  113. }
  114. if (hThread)
  115. {
  116. CloseHandle(hThread);
  117. }
  118. Status = RpcRevertToSelf();
  119. }
  120. else
  121. {
  122. // If the impersonation failed, then plow ahead anyway. We
  123. // can still keep the list of queues and "maybe" delete them.
  124. Status = RPC_S_OK;
  125. }
  126. }
  127. #ifdef DBG
  128. DbgPrint("MqGetContext(): hToken: 0x%x\n",hToken);
  129. #endif
  130. return Status;
  131. }
  132. //-------------------------------------------------------------------
  133. // MqRegisterQueue()
  134. //
  135. // Register the specified queue as a temporary queue that will
  136. // need to be deleted by the context rundown routine when the
  137. // client exits. The registration is actually done by the MQ RPC
  138. // client and server transport DLLs.
  139. //-------------------------------------------------------------------
  140. unsigned long MqRegisterQueue( PCONTEXT_HANDLE phContext,
  141. wchar_t *pwsQFormat )
  142. {
  143. RPC_STATUS Status = RPC_S_OK;
  144. MqTempQueue *pTempQueue;
  145. MqTempQueueList *pqList = (MqTempQueueList*)phContext;
  146. pTempQueue = (MqTempQueue*)I_RpcAllocate(sizeof(MqTempQueue));
  147. if (!pTempQueue)
  148. {
  149. return RPC_S_OUT_OF_MEMORY;
  150. }
  151. memset(pTempQueue,0,sizeof(MqTempQueue));
  152. ASSERT(pwsQFormat);
  153. ASSERT(wcslen(pwsQFormat) < MAX_FORMAT_LEN);
  154. wcscpy(pTempQueue->wsQFormat,pwsQFormat);
  155. // Ok, put the queue on the list to delete.
  156. pTempQueue->pNext = pqList->pQueues;
  157. pqList->pQueues = pTempQueue;
  158. return Status;
  159. }
  160. //-------------------------------------------------------------------
  161. // MqDeregisterQueue()
  162. //
  163. // Remove the specified message queue from the list of queues to
  164. // be deleted by the context rundown routine. This would be done
  165. // if a queue (which is initially temporary) was turned into a
  166. // permanent queue.
  167. //-------------------------------------------------------------------
  168. unsigned long MqDeregisterQueue( PCONTEXT_HANDLE phContext,
  169. wchar_t *pwsQFormat )
  170. {
  171. RPC_STATUS Status = RPC_S_OK;
  172. MqTempQueueList *pqList = (MqTempQueueList*)phContext;
  173. MqTempQueue *pTempQueue;
  174. MqTempQueue *pTempToFree;
  175. if (!pqList)
  176. {
  177. return RPC_X_SS_IN_NULL_CONTEXT;
  178. }
  179. pTempQueue = pqList->pQueues;
  180. if (!lstrcmpiW(pTempQueue->wsQFormat,pwsQFormat))
  181. {
  182. pqList->pQueues = pTempQueue->pNext;
  183. I_RpcFree(pTempQueue);
  184. return RPC_S_OK;
  185. }
  186. while (pTempQueue->pNext)
  187. {
  188. if (!lstrcmpiW(pTempQueue->pNext->wsQFormat,pwsQFormat))
  189. {
  190. pTempToFree = pTempQueue->pNext;
  191. pTempQueue->pNext = pTempQueue->pNext->pNext;
  192. I_RpcFree(pTempToFree);
  193. break;
  194. }
  195. }
  196. return Status;
  197. }
  198. //-------------------------------------------------------------------
  199. // MqFreeContext()
  200. //
  201. // Called to remove all of the queues registered for automatic
  202. // deletion and to close and free the context handle.
  203. //-------------------------------------------------------------------
  204. unsigned long MqFreeContext( PCONTEXT_HANDLE *pphContext,
  205. long fFreeContext )
  206. {
  207. RPC_STATUS Status = RPC_S_OK;
  208. HRESULT hr;
  209. BOOL fImpersonate = FALSE;
  210. MqTempQueueList *pqList = (MqTempQueueList*)*pphContext;
  211. MqTempQueue *pTemp;
  212. MqTempQueue *pToFree;
  213. // First, impersonate the client who registered these queues
  214. // to delete.
  215. if (pqList->hToken)
  216. {
  217. fImpersonate = SetThreadToken(NULL,pqList->hToken);
  218. #ifdef DBG
  219. if (!fImpersonate)
  220. {
  221. Status = GetLastError();
  222. }
  223. #endif
  224. }
  225. // Run through the list of queues deleting each one as
  226. // we go.
  227. pTemp = pqList->pQueues;
  228. while (pTemp)
  229. {
  230. pToFree = pTemp;
  231. pTemp = pTemp->pNext;
  232. hr = g_pMqDeleteQueue(pToFree->wsQFormat);
  233. #ifdef FALSE
  234. DbgPrint("Delete Queue: %S (hr: 0x%x)\n", pToFree->wsQFormat, hr );
  235. #endif
  236. I_RpcFree(pToFree);
  237. }
  238. // Stop the impersonation:
  239. if (fImpersonate)
  240. {
  241. if (!SetThreadToken(NULL,NULL))
  242. {
  243. Status = GetLastError();
  244. }
  245. }
  246. // Do we need to free up the context?
  247. if (pqList->hToken)
  248. {
  249. if (!CloseHandle(pqList->hToken))
  250. {
  251. Status = GetLastError();
  252. #ifdef DBG
  253. DbgPrint("MqFreeContext(): CloseHandle() Failed: Status: %d (0x%x)\n",Status,Status);
  254. #endif
  255. }
  256. }
  257. if (fFreeContext)
  258. {
  259. I_RpcFree(pqList);
  260. *pphContext = NULL;
  261. }
  262. else
  263. {
  264. pqList->hToken = 0;
  265. pqList->pQueues = NULL;
  266. }
  267. return Status;
  268. }
  269. //-------------------------------------------------------------------
  270. // PCONTEX_HANDLE_rundown()
  271. //
  272. // This is the context rundown routine. It will delete all of the
  273. // Falcon message queues that are currently associated with the
  274. // specified context handle.
  275. //-------------------------------------------------------------------
  276. void __RPC_USER PCONTEXT_HANDLE_rundown( PCONTEXT_HANDLE phContext )
  277. {
  278. RPC_STATUS Status;
  279. Status = MqFreeContext(&phContext,FALSE);
  280. }
  281. //-------------------------------------------------------------------
  282. // StartMqManagement()
  283. //
  284. // Called in dcomss\warpper\start.cxx by RPCSS to initialize the
  285. // MQ Management interface.
  286. //-------------------------------------------------------------------
  287. extern "C"
  288. DWORD StartMqManagement()
  289. {
  290. RPC_STATUS Status;
  291. Status = RpcServerRegisterIf(MqMgr_ServerIfHandle,0,0);
  292. return Status;
  293. }