Leaked source code of windows server 2003
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.

613 lines
17 KiB

  1. #include "precomp.h"
  2. #include <stdio.h>
  3. #include <assert.h>
  4. #include <buffer.h>
  5. #include <wbemutil.h>
  6. #include <sddl.h>
  7. #include "fwdhdr.h"
  8. #include "fconsink.h"
  9. #include "fconsend.h"
  10. LPCWSTR g_wszQos = L"ForwardingQos";
  11. LPCWSTR g_wszAuth = L"Authenticate";
  12. LPCWSTR g_wszEncrypt = L"Encryption";
  13. LPCWSTR g_wszTargets = L"Targets";
  14. LPCWSTR g_wszName = L"Name";
  15. LPCWSTR g_wszTargetSD = L"TargetSD";
  16. LPCWSTR g_wszSendSchema = L"IncludeSchema";
  17. typedef BOOL (APIENTRY*PStringSDToSD)(
  18. LPCWSTR StringSecurityDescriptor,
  19. DWORD StringSDRevision,
  20. PSECURITY_DESCRIPTOR *SecurityDescriptor,
  21. PULONG SecurityDescriptorSize );
  22. #define OPTIMAL_MESSAGE_SIZE 0x4000
  23. class CTraceSink
  24. : public CUnkBase< IWmiMessageTraceSink, &IID_IWmiMessageTraceSink >
  25. {
  26. CFwdConsSink* m_pOwner;
  27. public:
  28. CTraceSink( CFwdConsSink* pOwner ) : m_pOwner( pOwner ) { }
  29. STDMETHOD(Notify)( HRESULT hRes,
  30. GUID guidSource,
  31. LPCWSTR wszTrace,
  32. IUnknown* pContext )
  33. {
  34. return m_pOwner->Notify( hRes, guidSource, wszTrace, pContext );
  35. }
  36. };
  37. /****************************************************************************
  38. CFwdConsSink
  39. *****************************************************************************/
  40. CFwdConsSink::~CFwdConsSink()
  41. {
  42. if ( m_pTargetSD != NULL )
  43. {
  44. LocalFree( m_pTargetSD );
  45. }
  46. }
  47. HRESULT CFwdConsSink::Initialize( CFwdConsNamespace* pNspc,
  48. IWbemClassObject* pCons )
  49. {
  50. HRESULT hr;
  51. CPropVar vQos, vAuth, vEncrypt, vTargets, vName, vSendSchema, vTargetSD;
  52. m_pNamespace = pNspc;
  53. //
  54. // initialize multi sender. each forwarding consumer can
  55. // contain multiple targets.
  56. //
  57. hr = CoCreateInstance( CLSID_WmiMessageMultiSendReceive,
  58. NULL,
  59. CLSCTX_INPROC,
  60. IID_IWmiMessageMultiSendReceive,
  61. (void**)&m_pMultiSend );
  62. if ( FAILED(hr) )
  63. {
  64. return hr;
  65. }
  66. hr = CoCreateInstance( CLSID_WmiSmartObjectMarshal,
  67. NULL,
  68. CLSCTX_INPROC,
  69. IID_IWmiObjectMarshal,
  70. (void**)&m_pMrsh );
  71. if ( FAILED(hr) )
  72. {
  73. return hr;
  74. }
  75. //
  76. // initialize internal props from forwarding consumer props.
  77. //
  78. hr = pCons->Get( g_wszQos, 0, &vQos, NULL, NULL );
  79. if ( FAILED(hr) || FAILED( hr=vQos.SetType(VT_UI4) ) )
  80. {
  81. return hr;
  82. }
  83. if ( V_UI4(&vQos) != WMIMSG_FLAG_QOS_SYNCHRONOUS )
  84. {
  85. return WBEM_E_VALUE_OUT_OF_RANGE;
  86. }
  87. hr = pCons->Get( g_wszName, 0, &vName, NULL, NULL );
  88. if ( FAILED(hr) || FAILED( hr=vName.CheckType(VT_BSTR) ) )
  89. {
  90. return hr;
  91. }
  92. m_wsName = V_BSTR(&vName);
  93. hr = pCons->Get( g_wszTargetSD, 0, &vTargetSD, NULL, NULL );
  94. if ( FAILED(hr) )
  95. {
  96. return hr;
  97. }
  98. if ( V_VT(&vTargetSD) != VT_NULL )
  99. {
  100. if ( V_VT(&vTargetSD) != VT_BSTR )
  101. {
  102. return WBEM_E_INVALID_OBJECT;
  103. }
  104. //
  105. // convert the SD string to a relative SD. The function to do this
  106. // needs to be dynamically loaded because its w2k+ only.
  107. //
  108. HMODULE hMod = LoadLibrary( TEXT("advapi32") );
  109. if ( hMod != NULL )
  110. {
  111. PStringSDToSD fpTextToSD;
  112. fpTextToSD = (PStringSDToSD)GetProcAddress( hMod,
  113. "ConvertStringSecurityDescriptorToSecurityDescriptorW" );
  114. if ( fpTextToSD != NULL )
  115. {
  116. if ( (*fpTextToSD)( V_BSTR(&vTargetSD),
  117. SDDL_REVISION_1,
  118. &m_pTargetSD,
  119. &m_cTargetSD ) )
  120. {
  121. hr = WBEM_S_NO_ERROR;
  122. }
  123. else
  124. {
  125. hr = HRESULT_FROM_WIN32( GetLastError() );
  126. }
  127. }
  128. else
  129. {
  130. hr = WBEM_E_NOT_SUPPORTED;
  131. }
  132. FreeLibrary( hMod );
  133. if ( FAILED(hr) )
  134. {
  135. return hr;
  136. }
  137. }
  138. else
  139. {
  140. return WBEM_E_NOT_SUPPORTED;
  141. }
  142. }
  143. hr = pCons->Get( g_wszAuth, 0, &vAuth, NULL, NULL );
  144. if ( FAILED(hr) || FAILED( hr=vAuth.SetType(VT_BOOL) ) )
  145. {
  146. return hr;
  147. }
  148. hr = pCons->Get( g_wszEncrypt, 0, &vEncrypt, NULL, NULL );
  149. if ( FAILED(hr) || FAILED( hr=vEncrypt.SetType(VT_BOOL) ) )
  150. {
  151. return hr;
  152. }
  153. hr = pCons->Get( g_wszSendSchema, 0, &vSendSchema, NULL, NULL );
  154. if ( FAILED(hr) || FAILED( hr=vSendSchema.SetType(VT_BOOL) ) )
  155. {
  156. return hr;
  157. }
  158. m_dwFlags = V_UI4(&vQos);
  159. m_dwFlags |= V_BOOL(&vAuth)==VARIANT_TRUE ?WMIMSG_FLAG_SNDR_AUTHENTICATE:0;
  160. m_dwFlags |= V_BOOL(&vEncrypt)==VARIANT_TRUE ? WMIMSG_FLAG_SNDR_ENCRYPT:0;
  161. m_dwCurrentMrshFlags = WMIMSG_FLAG_MRSH_FULL_ONCE;
  162. m_dwDisconnectedMrshFlags = V_BOOL(&vSendSchema) == VARIANT_TRUE ?
  163. WMIMSG_FLAG_MRSH_FULL : WMIMSG_FLAG_MRSH_PARTIAL;
  164. //
  165. // create a trace sink for receiving callbacks from wmimsg. Note that
  166. // this sink's lifetime must be decoupled from this objects, else we'd
  167. // end up with a circular ref.
  168. //
  169. CWbemPtr<CTraceSink> pInternalTraceSink = new CTraceSink( this );
  170. if ( pInternalTraceSink == NULL )
  171. {
  172. return WBEM_E_OUT_OF_MEMORY;
  173. }
  174. CWbemPtr<IWmiMessageTraceSink> pTraceSink;
  175. hr = pInternalTraceSink->QueryInterface( IID_IWmiMessageTraceSink,
  176. (void**)&pTraceSink );
  177. _DBG_ASSERT( SUCCEEDED(hr) );
  178. //
  179. // targets array can be null, in which case we treat it as if the array
  180. // had one element, the empty string.
  181. //
  182. hr = pCons->Get( g_wszTargets, 0, &vTargets, NULL, NULL );
  183. if ( FAILED(hr) )
  184. {
  185. return hr;
  186. }
  187. if ( V_VT(&vTargets) != VT_NULL )
  188. {
  189. if ( FAILED(hr=vTargets.CheckType(VT_ARRAY|VT_BSTR) ) )
  190. {
  191. return WBEM_E_INVALID_OBJECT;
  192. }
  193. CPropSafeArray<BSTR> aTargets( V_ARRAY(&vTargets) );
  194. //
  195. // create all the fwd cons senders for the targets.
  196. //
  197. for( ULONG i=0; i < aTargets.Length(); i++ )
  198. {
  199. CWbemPtr<IWmiMessageSendReceive> pSend;
  200. hr = CFwdConsSend::Create( m_pControl,
  201. aTargets[i],
  202. m_dwFlags,
  203. m_pNamespace->GetSvc(),
  204. pTraceSink,
  205. &pSend );
  206. if ( FAILED(hr) )
  207. {
  208. break;
  209. }
  210. hr = m_pMultiSend->Add( 0, pSend );
  211. if ( FAILED(hr) )
  212. {
  213. break;
  214. }
  215. }
  216. }
  217. else
  218. {
  219. CWbemPtr<IWmiMessageSendReceive> pSend;
  220. hr = CFwdConsSend::Create( m_pControl,
  221. L"",
  222. m_dwFlags,
  223. m_pNamespace->GetSvc(),
  224. pTraceSink,
  225. &pSend );
  226. if ( FAILED(hr) )
  227. {
  228. return hr;
  229. }
  230. hr = m_pMultiSend->Add( 0, pSend );
  231. }
  232. if ( FAILED(hr) )
  233. {
  234. return hr;
  235. }
  236. return WBEM_S_NO_ERROR;
  237. }
  238. //
  239. // this method handles all sending/marshaling errors internally and will
  240. // return either S_OK when all objects are processed or S_FALSE
  241. // if only some are processed.
  242. //
  243. HRESULT CFwdConsSink::IndicateSome( IWbemClassObject* pConsumer,
  244. long cObjs,
  245. IWbemClassObject** ppObjs,
  246. long* pcProcessed )
  247. {
  248. HRESULT hr;
  249. _DBG_ASSERT( cObjs > 0 );
  250. //
  251. // create an execution id for this indicate.
  252. //
  253. GUID guidExecution;
  254. CoCreateGuid( &guidExecution );
  255. //
  256. // marshal the events. we will stop marshaling them when the buffer
  257. // gets bigger than it should for an optimally sized message.
  258. //
  259. BYTE achData[512];
  260. BYTE achHdr[256];
  261. CBuffer DataStrm( achData, 512, FALSE );
  262. CBuffer HdrStrm( achHdr, 256, FALSE );
  263. //
  264. // we remembered our last buffer size, so set to that in the hopes that
  265. // we can avoid a retry on the packing.
  266. //
  267. hr = DataStrm.SetSize( m_ulLastDataSize );
  268. m_ulLastDataSize = 0;
  269. ULONG i;
  270. for( i = 0; i < cObjs && SUCCEEDED(hr); i++ )
  271. {
  272. ULONG cUsed;
  273. PBYTE pData = DataStrm.GetRawData();
  274. ULONG cData = DataStrm.GetSize();
  275. ULONG iData = DataStrm.GetIndex();
  276. if ( iData < OPTIMAL_MESSAGE_SIZE )
  277. {
  278. hr = m_pMrsh->Pack( ppObjs[i],
  279. m_pNamespace->GetName(),
  280. m_dwCurrentMrshFlags,
  281. cData-iData,
  282. pData+iData,
  283. &cUsed );
  284. if ( hr == WBEM_E_BUFFER_TOO_SMALL )
  285. {
  286. hr = DataStrm.SetSize( iData + cUsed );
  287. if ( SUCCEEDED(hr) )
  288. {
  289. pData = DataStrm.GetRawData();
  290. cData = DataStrm.GetSize();
  291. hr = m_pMrsh->Pack( ppObjs[i],
  292. m_pNamespace->GetName(),
  293. m_dwCurrentMrshFlags,
  294. cData-iData,
  295. pData+iData,
  296. &cUsed);
  297. }
  298. }
  299. if ( SUCCEEDED(hr) )
  300. {
  301. DataStrm.Advance( cUsed );
  302. }
  303. }
  304. else
  305. {
  306. break;
  307. }
  308. }
  309. //
  310. // at this point, we know how many events we've actually processed
  311. // i will always be the number of objects successfully processed.
  312. // we want to try to separate out the events that fail to be packed
  313. // from ones that are packed. For this reason, pretend we didn't event
  314. // process the one that failed, unless it is the first one.
  315. //
  316. *pcProcessed = i > 0 ? i : 1;
  317. //
  318. // create a context object for this indicate. This is used to
  319. // thread information through to the trace functions
  320. // which are invoked by the senders.
  321. //
  322. CFwdContext Ctx( guidExecution, pConsumer, *pcProcessed, ppObjs );
  323. if ( i > 0 ) // at least some were successfully processed.
  324. {
  325. m_ulLastDataSize = DataStrm.GetIndex();
  326. //
  327. // create and stream the msg header
  328. //
  329. CFwdMsgHeader Hdr( *pcProcessed,
  330. m_dwFlags & WMIMSG_MASK_QOS,
  331. m_dwFlags & WMIMSG_FLAG_SNDR_AUTHENTICATE,
  332. m_dwFlags & WMIMSG_FLAG_SNDR_ENCRYPT,
  333. guidExecution,
  334. m_wsName,
  335. m_pNamespace->GetName(),
  336. PBYTE(m_pTargetSD),
  337. m_cTargetSD );
  338. hr = Hdr.Persist( HdrStrm );
  339. if ( SUCCEEDED(hr) )
  340. {
  341. //
  342. // send it and notify the tracing sink of the result. Always try
  343. // once with return immediately set. This will try all the
  344. // primary senders first.
  345. //
  346. hr = m_pMultiSend->SendReceive( DataStrm.GetRawData(),
  347. DataStrm.GetIndex(),
  348. HdrStrm.GetRawData(),
  349. HdrStrm.GetIndex(),
  350. WMIMSG_FLAG_MULTISEND_RETURN_IMMEDIATELY,
  351. &Ctx );
  352. if ( SUCCEEDED(hr) )
  353. {
  354. ;
  355. }
  356. else
  357. {
  358. //
  359. // o.k so all the primary ones failed, so now lets try all the
  360. // senders.
  361. //
  362. hr = m_pMultiSend->SendReceive( DataStrm.GetRawData(),
  363. DataStrm.GetIndex(),
  364. HdrStrm.GetRawData(),
  365. HdrStrm.GetIndex(),
  366. 0,
  367. &Ctx );
  368. }
  369. }
  370. }
  371. m_pNamespace->HandleTrace( hr, &Ctx );
  372. return *pcProcessed == cObjs ? S_OK : S_FALSE;
  373. }
  374. //
  375. // this is where we get notified of every target send event. here, we look
  376. // at the information and adjust our marshalers accordingly. we then pass the
  377. // event onto the namespace sink for tracing purposes. NOTE: This solution of
  378. // adjusting our marshalers on callbacks means that we're assuming a couple
  379. // things about the send implementation .. 1 ) the notification of the send
  380. // must be on the same control path as the send call. 2 ) the sender will
  381. // use the same target when it has successfully sent to it previously (e.g it
  382. // will not notify us that it sent to an rpc target, we then optimize our
  383. // marshalers for it, then it chooses to send to an msmq target ).
  384. //
  385. HRESULT CFwdConsSink::Notify( HRESULT hRes,
  386. GUID guidSource,
  387. LPCWSTR wszTrace,
  388. IUnknown* pContext )
  389. {
  390. HRESULT hr;
  391. ENTER_API_CALL
  392. if ( FAILED(hRes) )
  393. {
  394. //
  395. // we failed sending to a target, flush any state the marshaler
  396. // was keeping.
  397. //
  398. m_pMrsh->Flush();
  399. }
  400. //
  401. // check that current marshaling flags against the type of sender that
  402. // was used.
  403. //
  404. if ( guidSource == CLSID_WmiMessageRpcSender )
  405. {
  406. if ( SUCCEEDED(hRes) &&
  407. m_dwCurrentMrshFlags != WMIMSG_FLAG_MRSH_FULL_ONCE )
  408. {
  409. //
  410. // lets give schema once-only a whirl..
  411. //
  412. m_dwCurrentMrshFlags = WMIMSG_FLAG_MRSH_FULL_ONCE;
  413. }
  414. }
  415. else // must be queueing
  416. {
  417. if ( m_dwCurrentMrshFlags == WMIMSG_FLAG_MRSH_FULL_ONCE )
  418. {
  419. //
  420. // once only is not for messaging !! Its o.k. though
  421. // because we are sure that we've only used it once
  422. // and it did send the schema. Just don't use it again.
  423. //
  424. m_dwCurrentMrshFlags = m_dwDisconnectedMrshFlags;
  425. }
  426. }
  427. //
  428. // pass the call onto the namespace sink for tracing.
  429. //
  430. hr = m_pNamespace->Notify( hRes, guidSource, wszTrace, pContext );
  431. EXIT_API_CALL
  432. return hr;
  433. }
  434. HRESULT CFwdConsSink::IndicateToConsumer( IWbemClassObject* pConsumer,
  435. long cObjs,
  436. IWbemClassObject** ppObjs )
  437. {
  438. HRESULT hr;
  439. ENTER_API_CALL
  440. //
  441. // If the security context of the event provider is maintained then
  442. // we will use it to send the forwarded event.
  443. //
  444. CWbemPtr<IServerSecurity> pSec;
  445. hr = CoGetCallContext( IID_IServerSecurity, (void**)&pSec );
  446. if ( SUCCEEDED(hr) )
  447. {
  448. hr = pSec->ImpersonateClient();
  449. if ( FAILED(hr) )
  450. return hr;
  451. }
  452. long cProcessed = 0;
  453. //
  454. // IndicateSome() may send only a subset of the total indicated events.
  455. // This is to avoid sending potentially huge messages. So we'll keep
  456. // calling IndicateSome() until all messages are sent or there's an error.
  457. //
  458. do
  459. {
  460. cObjs -= cProcessed;
  461. ppObjs += cProcessed;
  462. hr = IndicateSome( pConsumer, cObjs, ppObjs, &cProcessed );
  463. _DBG_ASSERT( FAILED(hr) || (SUCCEEDED(hr) && cProcessed > 0 ));
  464. } while ( SUCCEEDED(hr) && cProcessed < cObjs );
  465. if ( pSec != NULL )
  466. pSec->RevertToSelf();
  467. EXIT_API_CALL
  468. return hr;
  469. }
  470. HRESULT CFwdConsSink::Create( CLifeControl* pCtl,
  471. CFwdConsNamespace* pNspc,
  472. IWbemClassObject* pCons,
  473. IWbemUnboundObjectSink** ppSink )
  474. {
  475. HRESULT hr;
  476. *ppSink = NULL;
  477. CWbemPtr<CFwdConsSink> pSink = new CFwdConsSink( pCtl );
  478. if ( pSink == NULL )
  479. {
  480. return WBEM_E_OUT_OF_MEMORY;
  481. }
  482. hr = pSink->Initialize( pNspc, pCons );
  483. if ( FAILED(hr) )
  484. {
  485. return hr;
  486. }
  487. hr = pSink->QueryInterface( IID_IWbemUnboundObjectSink, (void**)ppSink );
  488. assert( SUCCEEDED(hr) );
  489. return WBEM_S_NO_ERROR;
  490. }