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.

564 lines
14 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. #include "precomp.h"
  8. #include <wbemcli.h>
  9. #include <assert.h>
  10. #include "msmqcomn.h"
  11. #include "msmqhdlr.h"
  12. #include "msmqctx.h"
  13. #include "msmqhdr.h"
  14. #define CALLFUNC(FUNC) m_rApi.m_fp ## FUNC
  15. static MSGPROPID g_aPropID[] = {
  16. PROPID_M_EXTENSION, // header info - our hdr followed by user's hdr
  17. PROPID_M_EXTENSION_LEN, // len of entire hdr
  18. PROPID_M_CLASS, // contains msmq msg type - normal or nack
  19. PROPID_M_APPSPECIFIC, // contains ack status code
  20. PROPID_M_ADMIN_QUEUE, // contains format name to use for sending acks
  21. PROPID_M_ADMIN_QUEUE_LEN,// len of format name, if 0 then no sending acks
  22. PROPID_M_SENDERID, // SID of sender, only trustworthy if auth
  23. PROPID_M_SENDERID_LEN, // length of SID, may be zero
  24. PROPID_M_AUTHENTICATED, // tells us if message was authenticated.
  25. PROPID_M_PRIV_LEVEL, // tells us if message was encrypted when sending
  26. PROPID_M_BODY, // user's data
  27. PROPID_M_BODY_SIZE // user's data len
  28. };
  29. // eTotalProps must last.
  30. enum { eExt=0, eExtLen, eClass, eAppSpec, eAck, eAckLen,
  31. eSid, eSidLen, eAuth, ePriv, eBody, eBodyLen, eTotalProps };
  32. /*************************************************************************
  33. CMsgMsmqHandler
  34. **************************************************************************/
  35. void* CMsgMsmqHandler::GetInterface( REFIID riid )
  36. {
  37. if ( riid == IID_IWmiMessageQueueReceiver )
  38. {
  39. return &m_XQueueReceiver;
  40. }
  41. return NULL;
  42. }
  43. HRESULT CMsgMsmqHandler::ReceiveMessage( DWORD dwTimeout,
  44. DWORD dwAction,
  45. PVOID pvCursor,
  46. LPOVERLAPPED pOverlapped,
  47. ITransaction* pTxn )
  48. {
  49. ENTER_API_CALL
  50. HRESULT hr;
  51. MQMSGPROPS* pMsgProps = &m_MsgProps;
  52. switch( dwAction )
  53. {
  54. case WMIMSG_ACTION_QRCV_PEEK_CURRENT:
  55. dwAction = MQ_ACTION_PEEK_CURRENT;
  56. break;
  57. case WMIMSG_ACTION_QRCV_PEEK_NEXT:
  58. dwAction = MQ_ACTION_PEEK_NEXT;
  59. break;
  60. case WMIMSG_ACTION_QRCV_RECEIVE:
  61. dwAction = MQ_ACTION_RECEIVE;
  62. break;
  63. case WMIMSG_ACTION_QRCV_REMOVE:
  64. dwAction = MQ_ACTION_RECEIVE;
  65. pMsgProps = NULL;
  66. break;
  67. default:
  68. return WBEM_E_INVALID_OPERATION;
  69. };
  70. //
  71. // if receive fails due to some buffer being too small, then we resize
  72. // it and try again. We could only do this two times, however, if for
  73. // some reason there are multiple receivers for the same queue, there
  74. // could be a case where there are multiple threads trying to receive
  75. // the same message. In this case, we might need to grow more than once
  76. //
  77. do
  78. {
  79. hr = CALLFUNC(MQReceiveMessage)( m_hQueue,
  80. dwTimeout,
  81. dwAction,
  82. pMsgProps,
  83. pOverlapped,
  84. NULL,
  85. pvCursor,
  86. pTxn );
  87. } while( FAILED(hr) && (hr = CheckBufferResize(hr)) == S_OK );
  88. if ( SUCCEEDED(hr) && pMsgProps != NULL && pOverlapped == NULL )
  89. {
  90. //
  91. // handle the message here.
  92. //
  93. hr = HandleMessage( pTxn );
  94. }
  95. if ( FAILED(hr) )
  96. {
  97. return MqResToWmiRes( hr, S_OK );
  98. }
  99. return hr;
  100. EXIT_API_CALL
  101. }
  102. HRESULT CMsgMsmqHandler::CreateCursor( PVOID* ppvCursor )
  103. {
  104. return CALLFUNC(MQCreateCursor)( m_hQueue, ppvCursor );
  105. }
  106. HRESULT CMsgMsmqHandler::DestroyCursor( PVOID pvCursor )
  107. {
  108. return CALLFUNC(MQCloseCursor)( pvCursor );
  109. }
  110. HRESULT CMsgMsmqHandler::Create( CMsmqApi& rApi,
  111. IWmiMessageSendReceive* pRecv,
  112. QUEUEHANDLE hQueue,
  113. DWORD dwFlags,
  114. CMsgMsmqHandler** ppHndlr )
  115. {
  116. HRESULT hr;
  117. *ppHndlr = NULL;
  118. CWbemPtr<CMsgMsmqHandler> pHndlr;
  119. pHndlr = new CMsgMsmqHandler( rApi, pRecv, hQueue, dwFlags );
  120. if ( pHndlr == NULL )
  121. {
  122. return WBEM_E_OUT_OF_MEMORY;
  123. }
  124. MQPROPVARIANT* aPropVar = new MQPROPVARIANT[eTotalProps];
  125. if ( aPropVar == NULL )
  126. {
  127. delete pHndlr;
  128. return WBEM_E_OUT_OF_MEMORY;
  129. }
  130. ZeroMemory( aPropVar, sizeof(MQPROPVARIANT)*eTotalProps );
  131. //
  132. // Initialize msg props
  133. //
  134. pHndlr->m_MsgProps.cProp = eTotalProps;
  135. pHndlr->m_MsgProps.aPropID = g_aPropID;
  136. pHndlr->m_MsgProps.aPropVar = aPropVar;
  137. pHndlr->m_MsgProps.aStatus = NULL;
  138. aPropVar[eExt].vt = VT_VECTOR | VT_UI1;
  139. aPropVar[eExt].caub.pElems = new BYTE[256];
  140. aPropVar[eExt].caub.cElems = aPropVar[eExt].caub.pElems != NULL ? 256:0;
  141. aPropVar[eExtLen].vt = VT_UI4;
  142. aPropVar[eBody].vt = VT_VECTOR | VT_UI1;
  143. aPropVar[eBody].caub.pElems = new BYTE[1024];
  144. aPropVar[eBody].caub.cElems = aPropVar[eBody].caub.pElems!=NULL ? 1024:0;
  145. aPropVar[eBodyLen].vt = VT_UI4;
  146. aPropVar[eSid].vt = VT_VECTOR | VT_UI1;
  147. aPropVar[eSid].caub.pElems = new BYTE[256];
  148. aPropVar[eSid].caub.cElems = aPropVar[eSid].caub.pElems != NULL ? 256:0;
  149. aPropVar[eSidLen].vt = VT_UI4;
  150. aPropVar[eAck].vt = VT_LPWSTR;
  151. aPropVar[eAck].pwszVal = new WCHAR[256];
  152. aPropVar[eAckLen].vt = VT_UI4;
  153. aPropVar[eAckLen].ulVal = aPropVar[eAck].pwszVal != NULL ? 256 : 0;
  154. aPropVar[eClass].vt = VT_UI2;
  155. aPropVar[eAuth].vt = VT_UI1;
  156. aPropVar[eAppSpec].vt = VT_UI4;
  157. aPropVar[ePriv].vt = VT_UI4;
  158. //
  159. // this object is used to verify the private hashes on our header. Private
  160. // hashes are used to verify that receiving and sending machines are the
  161. // same.
  162. //
  163. hr = CSignMessage::Create( L"WMIMSG", &pHndlr->m_pSign );
  164. if ( FAILED(hr) )
  165. {
  166. return hr;
  167. }
  168. pHndlr->AddRef();
  169. *ppHndlr = pHndlr;
  170. return WBEM_S_NO_ERROR;
  171. }
  172. CMsgMsmqHandler::~CMsgMsmqHandler()
  173. {
  174. MQPROPVARIANT* aPropVar = m_MsgProps.aPropVar;
  175. //
  176. // clean up any allocated buffers.
  177. // delete (and vector delete) is guaranteed to handle NULL.
  178. //
  179. delete [] aPropVar[eExt].caub.pElems;
  180. delete [] aPropVar[eBody].caub.pElems;
  181. delete [] aPropVar[eSid].caub.pElems;
  182. delete [] aPropVar[eAck].caub.pElems;
  183. delete [] aPropVar;
  184. }
  185. //
  186. // returns S_OK if the error code specifies a buffer resize and
  187. // appropriate buffer was successfully resized. If hr does not
  188. // specify a buffer resize, then it just returns hr.
  189. //
  190. HRESULT CMsgMsmqHandler::CheckBufferResize( HRESULT hr )
  191. {
  192. DWORD dwSize;
  193. MQPROPVARIANT* aPropVar = m_MsgProps.aPropVar;
  194. int i = 0;
  195. if ( hr == MQ_ERROR_BUFFER_OVERFLOW )
  196. {
  197. //
  198. // do we need to resize the body or extension buffer ?
  199. //
  200. if ( aPropVar[eBodyLen].ulVal > aPropVar[eBody].caub.cElems )
  201. {
  202. i = eBody;
  203. dwSize = aPropVar[eBodyLen].ulVal;
  204. }
  205. else if ( aPropVar[eExtLen].ulVal > aPropVar[eExt].caub.cElems )
  206. {
  207. i = eExt;
  208. dwSize = aPropVar[eExtLen].ulVal;
  209. }
  210. else
  211. {
  212. assert(0);
  213. }
  214. }
  215. else if ( hr == MQ_ERROR_SENDERID_BUFFER_TOO_SMALL )
  216. {
  217. i = eSid;
  218. dwSize = aPropVar[eSidLen].ulVal;
  219. }
  220. else if ( hr == MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL )
  221. {
  222. i = eAck;
  223. dwSize = aPropVar[eAckLen].ulVal;
  224. }
  225. else
  226. {
  227. return hr; // not a buffer resize error code
  228. }
  229. delete [] aPropVar[i].caub.pElems;
  230. aPropVar[i].caub.pElems = new BYTE[dwSize];
  231. if ( aPropVar[i].caub.pElems != NULL )
  232. {
  233. aPropVar[i].caub.cElems = dwSize;
  234. }
  235. else
  236. {
  237. aPropVar[i].caub.cElems = 0;
  238. return WBEM_E_OUT_OF_MEMORY;
  239. }
  240. return S_OK;
  241. }
  242. HRESULT CMsgMsmqHandler::HandleMessageAck( HRESULT hrStatus )
  243. {
  244. HRESULT hr;
  245. MQPROPVARIANT* aPropVar = m_MsgProps.aPropVar;
  246. if ( aPropVar[eAckLen].ulVal == 0 )
  247. {
  248. //
  249. // no Ack queue specified.
  250. //
  251. return WBEM_S_NO_ERROR;
  252. }
  253. LPCWSTR wszAck = aPropVar[eAck].pwszVal;
  254. //
  255. // open a sender to the Ack queue. For right now, all nacks
  256. // use Guaranteed QoS.
  257. //
  258. CWbemPtr<IWmiMessageSender> pSender;
  259. hr = CoCreateInstance( CLSID_WmiMessageMsmqSender,
  260. NULL,
  261. CLSCTX_INPROC,
  262. IID_IWmiMessageSender,
  263. (void**)&pSender );
  264. if ( FAILED(hr) )
  265. {
  266. return hr;
  267. }
  268. CWbemPtr<IWmiMessageSendReceive> pSend;
  269. hr = pSender->Open( wszAck,
  270. WMIMSG_FLAG_QOS_GUARANTEED | WMIMSG_FLAG_SNDR_ACK,
  271. NULL,
  272. NULL,
  273. NULL,
  274. &pSend );
  275. if ( FAILED(hr) )
  276. {
  277. //
  278. // TODO: should notify error here.
  279. //
  280. return hr;
  281. }
  282. PBYTE pData = aPropVar[eBody].caub.pElems;
  283. ULONG cData = aPropVar[eBodyLen].ulVal;
  284. //
  285. // if encryption was specified to signal the data, then we cannot
  286. // specify it on the Ack (remains consistent with msmq nacks)
  287. //
  288. if ( aPropVar[ePriv].ulVal != MQMSG_PRIV_LEVEL_NONE )
  289. {
  290. pData = NULL;
  291. cData = 0;
  292. }
  293. PBYTE pAuxData = m_MsgProps.aPropVar[eExt].caub.pElems;
  294. ULONG cAuxData = m_MsgProps.aPropVar[eExtLen].ulVal;
  295. return pSend->SendReceive( pData,
  296. cData,
  297. pAuxData,
  298. cAuxData,
  299. hrStatus,
  300. NULL );
  301. }
  302. HRESULT CMsgMsmqHandler::HandleMessage( ITransaction* pTxn )
  303. {
  304. HRESULT hr;
  305. hr = HandleMessage2( pTxn );
  306. if ( FAILED(hr) )
  307. {
  308. if ( m_dwFlags & WMIMSG_FLAG_RCVR_ACK )
  309. {
  310. //
  311. // don't send acks, since we ourselves are an ack handler
  312. //
  313. return WBEM_S_NO_ERROR;
  314. }
  315. HandleMessageAck( hr );
  316. return hr;
  317. }
  318. //
  319. // TODO : handle positive ack if flags specify
  320. //
  321. return WBEM_S_NO_ERROR;
  322. }
  323. HRESULT CMsgMsmqHandler::HandleMessage2( ITransaction* pTxn )
  324. {
  325. HRESULT hr;
  326. if ( m_pRecv == NULL )
  327. {
  328. return WBEM_S_NO_ERROR;
  329. }
  330. MQPROPVARIANT* aPropVar = m_MsgProps.aPropVar;
  331. PBYTE pData = aPropVar[eBody].caub.pElems;
  332. ULONG cData = aPropVar[eBodyLen].ulVal;
  333. PBYTE pAuxData = aPropVar[eExt].caub.pElems;
  334. ULONG cAuxData = aPropVar[eExtLen].ulVal;
  335. //
  336. // handle the msmq hdr attached to the front of the aux data.
  337. //
  338. CMsgMsmqHdr MsmqHdr;
  339. CBuffer HdrStrm( pAuxData, cAuxData, FALSE );
  340. hr = MsmqHdr.Unpersist( HdrStrm );
  341. if ( FAILED(hr) )
  342. {
  343. return hr;
  344. }
  345. //
  346. // get user header information
  347. //
  348. PBYTE pUserAuxData = HdrStrm.GetRawData() + HdrStrm.GetIndex();
  349. ULONG cUserAuxData = MsmqHdr.GetAuxDataLength();
  350. hr = HdrStrm.Advance( cUserAuxData );
  351. if ( FAILED(hr) )
  352. {
  353. return hr;
  354. }
  355. //
  356. // we may need to verify that the msg originated from this machine.
  357. //
  358. if ( m_dwFlags & WMIMSG_FLAG_RCVR_PRIV_VERIFY )
  359. {
  360. //
  361. // first check the integrity of the user data
  362. //
  363. hr = m_pSign->Verify( pData,
  364. cData,
  365. MsmqHdr.GetDataHash(),
  366. MsmqHdr.GetDataHashLength() );
  367. if ( hr != S_OK )
  368. {
  369. return WMIMSG_E_INVALIDMESSAGE;
  370. }
  371. //
  372. // now check the integrity of the hdr.
  373. //
  374. ULONG cHdr = HdrStrm.GetIndex();
  375. ULONG cHdrHash;
  376. BYTE achHdrHash[MAXHASHSIZE];
  377. hr = HdrStrm.Read( &cHdrHash, sizeof(DWORD), NULL );
  378. if ( hr != S_OK || cHdrHash > MAXHASHSIZE )
  379. {
  380. return WMIMSG_E_INVALIDMESSAGE;
  381. }
  382. hr = HdrStrm.Read( achHdrHash, cHdrHash, NULL );
  383. if ( hr != S_OK )
  384. {
  385. return WMIMSG_E_INVALIDMESSAGE;
  386. }
  387. hr = m_pSign->Verify( HdrStrm.GetRawData(),
  388. cHdr,
  389. achHdrHash,
  390. cHdrHash );
  391. if ( hr != S_OK )
  392. {
  393. return WMIMSG_E_INVALIDMESSAGE;
  394. }
  395. }
  396. //
  397. // check to see if this is an msmq generated nack. If so, then
  398. // need to map nack type to error code. If not, then our status is
  399. // specified in the App specific field.
  400. //
  401. DWORD dwStatus;
  402. if ( aPropVar[eClass].uiVal == MQMSG_CLASS_NORMAL )
  403. {
  404. dwStatus = aPropVar[eAppSpec].ulVal;
  405. }
  406. else
  407. {
  408. dwStatus = MqClassToWmiRes( aPropVar[eClass].uiVal );
  409. }
  410. //
  411. // construct the receiver context for this message.
  412. //
  413. PSID pSenderSid = aPropVar[eSid].caub.cElems > 0 ?
  414. aPropVar[eSid].caub.pElems : NULL;
  415. BOOL bAuth = aPropVar[eAuth].bVal == MQMSG_AUTHENTICATION_REQUESTED ?
  416. TRUE : FALSE;
  417. CMsgMsmqRcvrCtx RcvrCtx( &MsmqHdr, pSenderSid, bAuth );
  418. //
  419. // hand the message off to the users code.
  420. //
  421. hr = m_pRecv->SendReceive( pData,
  422. cData,
  423. pUserAuxData,
  424. cUserAuxData,
  425. dwStatus,
  426. &RcvrCtx );
  427. if ( FAILED(hr) )
  428. {
  429. return hr;
  430. }
  431. return WBEM_S_NO_ERROR;
  432. }