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.

540 lines
13 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. #include "precomp.h"
  8. #include <assert.h>
  9. #include <arrtempl.h>
  10. #include <comutl.h>
  11. #include <wbemcli.h>
  12. #include <buffer.h>
  13. #include "msmqhdr.h"
  14. #include "msmqsend.h"
  15. #include "msmqcomn.h"
  16. #define MAXPROPS 10
  17. #define MAXHASHSIZE 64
  18. struct MsmqOutgoingMessage : MQMSGPROPS
  19. {
  20. MSGPROPID m_aPropID[MAXPROPS];
  21. MQPROPVARIANT m_aPropVar[MAXPROPS];
  22. MsmqOutgoingMessage( DWORD dwFlags, DWORD dwStatus,
  23. LPBYTE pData, ULONG cData,
  24. LPBYTE pHdr, ULONG cHdr,
  25. HANDLE hSecCtx, LPCWSTR wszAckFormatName );
  26. };
  27. /*****************************************************************
  28. CMsgMsmqSender
  29. ******************************************************************/
  30. HRESULT CMsgMsmqSender::Open( LPCWSTR wszTarget,
  31. DWORD dwFlags,
  32. WMIMSG_SNDR_AUTH_INFOP pAuthInfo,
  33. LPCWSTR wszResponse,
  34. IWmiMessageTraceSink* pTraceSink,
  35. IWmiMessageSendReceive** ppSend )
  36. {
  37. HRESULT hr;
  38. *ppSend = NULL;
  39. ENTER_API_CALL
  40. if ( (dwFlags & WMIMSG_MASK_QOS) != WMIMSG_FLAG_QOS_EXPRESS &&
  41. (dwFlags & WMIMSG_MASK_QOS) != WMIMSG_FLAG_QOS_GUARANTEED )
  42. {
  43. return WBEM_E_NOT_SUPPORTED;
  44. }
  45. CWbemPtr<CMsgMsmqSend> pSend;
  46. pSend = new CMsgMsmqSend( m_pControl,
  47. wszTarget,
  48. dwFlags,
  49. wszResponse,
  50. pTraceSink );
  51. if ( pSend == NULL )
  52. {
  53. return WBEM_E_OUT_OF_MEMORY;
  54. }
  55. if ( (dwFlags & WMIMSG_FLAG_SNDR_LAZY_INIT) == 0 )
  56. {
  57. hr = pSend->EnsureSender();
  58. if ( FAILED(hr) )
  59. {
  60. return hr;
  61. }
  62. }
  63. return pSend->QueryInterface(IID_IWmiMessageSendReceive, (void**)ppSend);
  64. EXIT_API_CALL
  65. }
  66. /*****************************************************************
  67. CMsgMsmqSend
  68. ******************************************************************/
  69. #define CALLFUNC(FUNC) (*m_Api.m_fp ## FUNC )
  70. CMsgMsmqSend::CMsgMsmqSend( CLifeControl* pCtl,
  71. LPCWSTR wszTarget,
  72. DWORD dwFlags,
  73. LPCWSTR wszResponse,
  74. IWmiMessageTraceSink* pTraceSink )
  75. : CUnkBase<IWmiMessageSendReceive,&IID_IWmiMessageSendReceive>(pCtl),
  76. m_bInit(FALSE), m_hQueue(NULL), m_dwFlags(dwFlags),
  77. m_wsResponse( wszResponse ), m_hSecCtx( NULL ), m_pTraceSink( pTraceSink )
  78. {
  79. //
  80. // save our computer name.
  81. //
  82. TCHAR achComputer[MAX_COMPUTERNAME_LENGTH+1];
  83. ULONG ulSize = MAX_COMPUTERNAME_LENGTH+1;
  84. GetComputerName( achComputer, &ulSize );
  85. m_wsComputer = achComputer;
  86. //
  87. // if the target is NULL, then we use our computer name as the target.
  88. //
  89. if ( wszTarget != NULL && *wszTarget != '\0' )
  90. {
  91. m_wsTarget = wszTarget;
  92. }
  93. else
  94. {
  95. m_wsTarget = m_wsComputer;
  96. }
  97. }
  98. CMsgMsmqSend::~CMsgMsmqSend()
  99. {
  100. Clear();
  101. }
  102. HRESULT CMsgMsmqSend::HandleTrace( HRESULT hr, IUnknown* pCtx )
  103. {
  104. if ( m_pTraceSink != NULL )
  105. {
  106. return m_pTraceSink->Notify( hr,
  107. CLSID_WmiMessageMsmqSender,
  108. m_wsTarget,
  109. pCtx );
  110. }
  111. return WBEM_S_NO_ERROR;
  112. }
  113. void CMsgMsmqSend::Clear()
  114. {
  115. m_bInit = FALSE;
  116. if ( m_hSecCtx != NULL )
  117. {
  118. CALLFUNC(MQFreeSecurityContext)( m_hSecCtx );
  119. m_hSecCtx = NULL;
  120. }
  121. if ( m_hQueue != NULL )
  122. {
  123. CALLFUNC(MQCloseQueue)( m_hQueue );
  124. m_hQueue = NULL;
  125. }
  126. }
  127. HRESULT CMsgMsmqSend::EnsureSender()
  128. {
  129. HRESULT hr;
  130. CInCritSec ics(&m_cs);
  131. if ( m_bInit )
  132. {
  133. return WBEM_S_NO_ERROR;
  134. }
  135. hr = m_Api.Initialize();
  136. if ( FAILED(hr) )
  137. {
  138. return hr; // MSMQ probably isn't installed.
  139. }
  140. hr = EnsureMsmqService( m_Api );
  141. if ( FAILED(hr) )
  142. {
  143. return hr;
  144. }
  145. Clear();
  146. WString wsFormatName;
  147. hr = NormalizeQueueName( m_Api, m_wsTarget, wsFormatName );
  148. if ( FAILED(hr) )
  149. {
  150. return MqResToWmiRes( hr, WMIMSG_E_INVALIDADDRESS );
  151. }
  152. hr = CALLFUNC(MQOpenQueue)( wsFormatName,
  153. MQ_SEND_ACCESS,
  154. MQ_DENY_NONE,
  155. &m_hQueue );
  156. if ( FAILED(hr) )
  157. {
  158. return MqResToWmiRes( hr, WMIMSG_E_TARGETNOTFOUND );
  159. }
  160. if ( m_dwFlags & WMIMSG_FLAG_SNDR_AUTHENTICATE )
  161. {
  162. //
  163. // get security context for process account.
  164. //
  165. hr = CALLFUNC(MQGetSecurityContext)( NULL, 0, &m_hSecCtx );
  166. if ( FAILED(hr) )
  167. {
  168. return MqResToWmiRes( hr, WMIMSG_E_AUTHFAILURE );
  169. }
  170. }
  171. //
  172. // this will be used to sign our hdr so that a local receiver ( such as
  173. // an ack receiver can verify this machine sent it ).
  174. //
  175. hr = CSignMessage::Create( L"WMIMSG", &m_pSign );
  176. if ( FAILED(hr) )
  177. {
  178. return hr;
  179. }
  180. m_bInit = TRUE;
  181. return hr;
  182. }
  183. MsmqOutgoingMessage::MsmqOutgoingMessage( DWORD dwFlags, DWORD dwStatus,
  184. LPBYTE pData, ULONG cData,
  185. LPBYTE pHdr, ULONG cHdr,
  186. HANDLE hSecCtx,
  187. LPCWSTR wszAckFormatName )
  188. {
  189. cProp = 0;
  190. aPropID = m_aPropID;
  191. aPropVar = m_aPropVar;
  192. aStatus= NULL;
  193. m_aPropID[cProp] = PROPID_M_BODY;
  194. m_aPropVar[cProp].vt = VT_VECTOR | VT_UI1;
  195. m_aPropVar[cProp].caub.cElems = cData;
  196. m_aPropVar[cProp].caub.pElems = pData;
  197. cProp++;
  198. m_aPropID[cProp] = PROPID_M_EXTENSION;
  199. m_aPropVar[cProp].vt = VT_VECTOR | VT_UI1;
  200. m_aPropVar[cProp].caub.cElems = cHdr;
  201. m_aPropVar[cProp].caub.pElems = pHdr;
  202. cProp++;
  203. m_aPropID[cProp] = PROPID_M_APPSPECIFIC;
  204. m_aPropVar[cProp].vt = VT_UI4;
  205. m_aPropVar[cProp].ulVal = dwStatus;
  206. cProp++;
  207. if ( wszAckFormatName != NULL && *wszAckFormatName != '\0')
  208. {
  209. m_aPropID[cProp] = PROPID_M_ACKNOWLEDGE;
  210. m_aPropVar[cProp].vt = VT_UI1;
  211. m_aPropVar[cProp].bVal = MQMSG_ACKNOWLEDGMENT_NACK_RECEIVE;
  212. cProp++;
  213. m_aPropID[cProp] = PROPID_M_ADMIN_QUEUE;
  214. m_aPropVar[cProp].vt = VT_LPWSTR;
  215. m_aPropVar[cProp].pwszVal = LPWSTR(wszAckFormatName);
  216. cProp++;
  217. }
  218. if ( (dwFlags & WMIMSG_MASK_QOS) != WMIMSG_FLAG_QOS_EXPRESS )
  219. {
  220. m_aPropID[cProp] = PROPID_M_DELIVERY;
  221. m_aPropVar[cProp].vt = VT_UI1;
  222. m_aPropVar[cProp].bVal = MQMSG_DELIVERY_RECOVERABLE;
  223. cProp++;
  224. }
  225. if ( dwFlags & WMIMSG_FLAG_SNDR_AUTHENTICATE )
  226. {
  227. m_aPropID[cProp] = PROPID_M_AUTH_LEVEL;
  228. m_aPropVar[cProp].vt = VT_UI4;
  229. m_aPropVar[cProp].ulVal = MQMSG_AUTH_LEVEL_ALWAYS;
  230. cProp++;
  231. #ifndef _WIN64
  232. m_aPropID[cProp] = PROPID_M_SECURITY_CONTEXT;
  233. m_aPropVar[cProp].vt = VT_UI4;
  234. m_aPropVar[cProp].ulVal = ULONG(hSecCtx);
  235. cProp++;
  236. #endif
  237. }
  238. if ( dwFlags & WMIMSG_FLAG_SNDR_ENCRYPT )
  239. {
  240. m_aPropID[cProp] = PROPID_M_PRIV_LEVEL;
  241. m_aPropVar[cProp].vt = VT_UI4;
  242. m_aPropVar[cProp].ulVal = MQMSG_PRIV_LEVEL_BODY;
  243. cProp++;
  244. }
  245. }
  246. HRESULT CMsgMsmqSend::SendReceive( PBYTE pData,
  247. ULONG cData,
  248. PBYTE pAuxData,
  249. ULONG cAuxData,
  250. DWORD dwFlagStatus,
  251. IUnknown* pCtx )
  252. {
  253. ENTER_API_CALL
  254. HRESULT hr;
  255. hr = Send( pData, cData, pAuxData, cAuxData, dwFlagStatus, pCtx );
  256. if ( FAILED(hr) )
  257. {
  258. HandleTrace( hr, pCtx );
  259. return hr;
  260. }
  261. return HandleTrace( hr, pCtx );
  262. EXIT_API_CALL
  263. }
  264. HRESULT CMsgMsmqSend::Send( PBYTE pData,
  265. ULONG cData,
  266. PBYTE pAuxData,
  267. ULONG cAuxData,
  268. DWORD dwFlagStatus,
  269. IUnknown* pCtx )
  270. {
  271. HRESULT hr;
  272. hr = EnsureSender();
  273. if ( FAILED(hr) )
  274. {
  275. return hr;
  276. }
  277. DWORD dwStatus = 0;
  278. ULONG cHash = MAXHASHSIZE;
  279. BYTE achHash[MAXHASHSIZE];
  280. if ( m_dwFlags & WMIMSG_FLAG_SNDR_PRIV_SIGN )
  281. {
  282. //
  283. // create a 'private' hash on the data. this will be used by local
  284. // receivers to verify that it sent the message and that it has not
  285. // been tampered with.
  286. //
  287. hr = m_pSign->Sign( pData, cData, achHash, cHash );
  288. if ( FAILED(hr) )
  289. {
  290. return hr;
  291. }
  292. }
  293. else
  294. {
  295. cHash = 0;
  296. }
  297. //
  298. // now we can create our msmq msg header. this header will be prepended
  299. // to the users header in auxdata. We do not create our own header if
  300. // this is an ack sender because AuxData already contains an msmq msg hdr.
  301. // For nacks, msmq will return data as sent, so we want to remain
  302. // consistent with this for our 'application' level acks.
  303. //
  304. BYTE achHdr[512];
  305. CBuffer HdrStrm( achHdr, 512, FALSE );
  306. CMsgMsmqHdr MsmqHdr( m_wsTarget, m_wsComputer, achHash, cHash, cAuxData );
  307. if ( (m_dwFlags & WMIMSG_FLAG_SNDR_ACK) == 0 )
  308. {
  309. hr = MsmqHdr.Persist( HdrStrm );
  310. if ( FAILED(hr) )
  311. {
  312. return hr;
  313. }
  314. }
  315. else
  316. {
  317. //
  318. // the flagstatus param contains the status.
  319. //
  320. dwStatus = dwFlagStatus;
  321. }
  322. hr = HdrStrm.Write( pAuxData, cAuxData, NULL );
  323. if ( FAILED(hr) )
  324. {
  325. return hr;
  326. }
  327. if ( m_dwFlags & WMIMSG_FLAG_SNDR_PRIV_SIGN )
  328. {
  329. //
  330. // hash the entire header and store it at the end of the header.
  331. //
  332. hr = m_pSign->Sign( HdrStrm.GetRawData(),
  333. HdrStrm.GetIndex(),
  334. achHash,
  335. cHash );
  336. if ( FAILED(hr) )
  337. {
  338. return hr;
  339. }
  340. }
  341. else
  342. {
  343. cHash = 0;
  344. }
  345. hr = HdrStrm.Write( &cHash, sizeof(DWORD), NULL );
  346. if ( FAILED(hr) )
  347. {
  348. return hr;
  349. }
  350. hr = HdrStrm.Write( achHash, cHash, NULL );
  351. if ( FAILED(hr) )
  352. {
  353. return hr;
  354. }
  355. //
  356. // Obtain the correct ITransaction ptr. If the user did not specify
  357. // a txn and we are sending using xact qos, then we need to use the
  358. // single message txn.
  359. //
  360. CWbemPtr<ITransaction> pTxn;
  361. if ( pCtx != NULL )
  362. {
  363. pCtx->QueryInterface( IID_ITransaction, (void**)&pTxn );
  364. }
  365. DWORD dwQos = m_dwFlags & WMIMSG_MASK_QOS;
  366. if ( pTxn == NULL && dwQos == WMIMSG_FLAG_QOS_XACT )
  367. {
  368. pTxn = MQ_SINGLE_MESSAGE;
  369. }
  370. HANDLE hSecCtx = m_hSecCtx;
  371. if ( m_dwFlags & WMIMSG_FLAG_SNDR_AUTHENTICATE )
  372. {
  373. //
  374. // Check to see if we're impersonating. If so, then we need to
  375. // obtain the MSMQ security context and use it when sending the
  376. // message.
  377. //
  378. HANDLE hToken;
  379. if ( OpenThreadToken( GetCurrentThread(),
  380. TOKEN_QUERY,
  381. TRUE,
  382. &hToken ) )
  383. {
  384. CloseHandle( &hToken );
  385. //
  386. // we are forgiving when encountering errors with authentication
  387. // on the send side. This is because the receiving end might not
  388. // even care about authentication ( and msmq doesn't have mutual
  389. // auth ). If the target cares about auth, then we'll be sure to
  390. // find out via a nack msg.
  391. //
  392. hr = CALLFUNC(MQGetSecurityContext)( NULL, 0, &hSecCtx );
  393. if ( FAILED(hr) )
  394. {
  395. return MqResToWmiRes( hr, WMIMSG_E_AUTHFAILURE );
  396. }
  397. }
  398. }
  399. MsmqOutgoingMessage Msg( m_dwFlags,
  400. dwStatus,
  401. pData,
  402. cData,
  403. HdrStrm.GetRawData(),
  404. HdrStrm.GetIndex(),
  405. hSecCtx,
  406. m_wsResponse );
  407. hr = CALLFUNC(MQSendMessage)( m_hQueue, &Msg, pTxn );
  408. if( hSecCtx != m_hSecCtx && hSecCtx != NULL )
  409. {
  410. CALLFUNC(MQFreeSecurityContext)( hSecCtx );
  411. }
  412. if ( FAILED(hr) )
  413. {
  414. //
  415. // this is so the next call will reset us.
  416. //
  417. Clear();
  418. return MqResToWmiRes( hr );
  419. }
  420. return hr;
  421. }