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.

723 lines
17 KiB

  1. #include "precomp.h"
  2. #include <wbemutil.h>
  3. #include <arrtempl.h>
  4. #include <wmimsg.h>
  5. #include <ntdsapi.h>
  6. #include "fconsend.h"
  7. // flags below 0x10000 are reserved for msg implementations.
  8. #define FWD_FLAG_NO_INDIRECT 0x00010000
  9. // {DDE18466-D244-4a5b-B91F-93D17E13178D}
  10. static const GUID g_guidQueueType =
  11. {0xdde18466, 0xd244, 0x4a5b, {0xb9, 0x1f, 0x93, 0xd1, 0x7e, 0x13, 0x17, 0x8d}};
  12. HRESULT IsTcpIpAddress( LPCWSTR wszTarget )
  13. {
  14. HRESULT hr;
  15. WSADATA wsaData;
  16. WORD wVersionRequested;
  17. wVersionRequested = MAKEWORD( 2, 2 );
  18. int err = WSAStartup( wVersionRequested, &wsaData );
  19. if ( err == 0 )
  20. {
  21. IN_ADDR ia;
  22. //
  23. // convert unicode addr to ansi ..
  24. //
  25. int cTarget = wcstombs( NULL, wszTarget, 0 );
  26. LPSTR szTarget = new char[cTarget+1];
  27. if ( szTarget != NULL )
  28. {
  29. wcstombs( szTarget, wszTarget, cTarget+1 );
  30. ULONG in_ad = inet_addr( szTarget );
  31. hr = in_ad == INADDR_NONE ? WBEM_S_FALSE : WBEM_S_NO_ERROR;
  32. delete [] szTarget;
  33. }
  34. else
  35. {
  36. hr = WBEM_E_OUT_OF_MEMORY;
  37. }
  38. WSACleanup();
  39. }
  40. else
  41. {
  42. hr = WMIMSG_E_REQSVCNOTAVAIL;
  43. }
  44. return hr;
  45. }
  46. HRESULT GetDnsName( LPCWSTR wszTarget, LPWSTR* pwszDnsName )
  47. {
  48. HRESULT hr;
  49. *pwszDnsName = NULL;
  50. //
  51. // first make sure winsock is initialized.
  52. //
  53. WSADATA wsaData;
  54. WORD wVersionRequested;
  55. wVersionRequested = MAKEWORD( 2, 2 );
  56. int err = WSAStartup( wVersionRequested, &wsaData );
  57. if ( err == 0 )
  58. {
  59. IN_ADDR ia;
  60. HOSTENT* pHost;
  61. //
  62. // convert unicode addr to ansi ..
  63. //
  64. int cTarget = wcstombs( NULL, wszTarget, 0 );
  65. LPSTR szTarget = new char[cTarget+1];
  66. if ( szTarget != NULL )
  67. {
  68. wcstombs( szTarget, wszTarget, cTarget+1 );
  69. //
  70. // see if its an ip address ...
  71. //
  72. ULONG in_ad = inet_addr( szTarget );
  73. if ( in_ad == INADDR_NONE )
  74. {
  75. pHost = gethostbyname( szTarget );
  76. }
  77. else
  78. {
  79. pHost = gethostbyaddr( (char*)&in_ad, 4, PF_INET );
  80. }
  81. if ( pHost != NULL )
  82. {
  83. int cDnsTarget = MultiByteToWideChar( CP_ACP,
  84. 0,
  85. pHost->h_name,
  86. -1,
  87. NULL,
  88. 0 );
  89. *pwszDnsName = new WCHAR[cDnsTarget+1];
  90. if ( *pwszDnsName != NULL )
  91. {
  92. MultiByteToWideChar( CP_ACP,
  93. 0,
  94. pHost->h_name,
  95. -1,
  96. *pwszDnsName,
  97. cDnsTarget+1 );
  98. hr = WBEM_S_NO_ERROR;
  99. }
  100. else
  101. {
  102. hr = WBEM_E_OUT_OF_MEMORY;
  103. }
  104. }
  105. else
  106. {
  107. hr = WMIMSG_E_INVALIDADDRESS;
  108. }
  109. delete [] szTarget;
  110. }
  111. else
  112. {
  113. hr = WBEM_E_OUT_OF_MEMORY;
  114. }
  115. WSACleanup();
  116. }
  117. else
  118. {
  119. hr = WMIMSG_E_REQSVCNOTAVAIL;
  120. }
  121. return hr;
  122. }
  123. HRESULT GetSpn( LPCWSTR wszTarget, LPWSTR* wszSpn )
  124. {
  125. HRESULT hr;
  126. *wszSpn = NULL;
  127. LPWSTR wszNormTarget;
  128. hr = GetDnsName( wszTarget, &wszNormTarget );
  129. if ( FAILED(hr) )
  130. return hr;
  131. CVectorDeleteMe<WCHAR> vdm( wszNormTarget );
  132. DWORD cSpn = 0;
  133. DWORD dwRes = DsMakeSpn( L"HOST", wszNormTarget, NULL, 0,
  134. NULL, &cSpn, NULL);
  135. if ( dwRes == ERROR_MORE_DATA || dwRes == ERROR_BUFFER_OVERFLOW )
  136. {
  137. *wszSpn = new WCHAR[cSpn];
  138. if ( *wszSpn != NULL )
  139. {
  140. dwRes = DsMakeSpn( L"HOST",
  141. wszNormTarget,
  142. NULL,
  143. 0,
  144. NULL,
  145. &cSpn,
  146. *wszSpn );
  147. if ( dwRes == ERROR_SUCCESS )
  148. {
  149. hr = WBEM_S_NO_ERROR;
  150. }
  151. else
  152. {
  153. delete [] *wszSpn;
  154. *wszSpn = NULL;
  155. hr = HRESULT_FROM_WIN32( dwRes );
  156. }
  157. }
  158. else
  159. {
  160. hr = WBEM_E_OUT_OF_MEMORY;
  161. }
  162. }
  163. else
  164. {
  165. hr = HRESULT_FROM_WIN32( dwRes );
  166. }
  167. return hr;
  168. }
  169. /********************************************************************
  170. CFwdConsSend
  171. *********************************************************************/
  172. HRESULT CFwdConsSend::AddMSMQSender( LPCWSTR wszName )
  173. {
  174. HRESULT hr;
  175. //
  176. // need to construct the Ack address for this sender.
  177. //
  178. TCHAR atchComputer[MAX_COMPUTERNAME_LENGTH+1];
  179. DWORD cComputer = MAX_COMPUTERNAME_LENGTH+1;
  180. GetComputerName( atchComputer, &cComputer );
  181. WCHAR awchComputer[MAX_COMPUTERNAME_LENGTH+1];
  182. cComputer = MAX_COMPUTERNAME_LENGTH+1;
  183. tsz2wsz( atchComputer, awchComputer, &cComputer );
  184. WString wsAckQueueName = L"DIRECT=OS:";
  185. wsAckQueueName += awchComputer;
  186. wsAckQueueName += L"\\private$\\WMIFwdAck";
  187. //
  188. // create the sender object and add it to the multisender.
  189. //
  190. CWbemPtr<IWmiMessageSender> pSender;
  191. hr = CoCreateInstance( CLSID_WmiMessageMsmqSender,
  192. NULL,
  193. CLSCTX_INPROC,
  194. IID_IWmiMessageSender,
  195. (void**)&pSender );
  196. if ( FAILED(hr) )
  197. {
  198. return hr;
  199. }
  200. CWbemPtr<IWmiMessageSendReceive> pSend;
  201. DWORD dwFlags = m_dwFlags |
  202. WMIMSG_FLAG_SNDR_LAZY_INIT |
  203. WMIMSG_FLAG_SNDR_PRIV_SIGN |
  204. WMIMSG_FLAG_SNDR_NACK_ONLY;
  205. hr = pSender->Open( wszName,
  206. dwFlags,
  207. NULL,
  208. wsAckQueueName,
  209. m_pTraceSink,
  210. &pSend );
  211. if ( FAILED(hr) )
  212. {
  213. return hr;
  214. }
  215. return m_pMultiSend->Add( WMIMSG_FLAG_MULTISEND_TERMINATING_SENDER, pSend);
  216. }
  217. HRESULT CFwdConsSend::AddAsyncSender( LPCWSTR wszMachine )
  218. {
  219. HRESULT hr;
  220. //
  221. // derive the msmq address from the target and add the sender.
  222. //
  223. WString wsQueueName;
  224. if ( (m_dwFlags & WMIMSG_FLAG_SNDR_ENCRYPT) == 0 )
  225. {
  226. //
  227. // we can use a direct format name to identify the target. This is
  228. // the most flexible type of address besides a private format name,
  229. // but those cannot be derived. ( public pathnames can only be used
  230. // when online )
  231. //
  232. wsQueueName = L"DIRECT=";
  233. hr = IsTcpIpAddress( wszMachine );
  234. if ( FAILED(hr) )
  235. {
  236. return hr;
  237. }
  238. if ( hr == WBEM_S_NO_ERROR )
  239. {
  240. wsQueueName += L"TCP:";
  241. }
  242. else
  243. {
  244. wsQueueName += L"OS:";
  245. }
  246. wsQueueName += wszMachine;
  247. wsQueueName += L"\\private$\\";
  248. }
  249. else
  250. {
  251. //
  252. // we must use a public queue pathname to reference the queue. this is
  253. // because msmq will not accept direct format names for encryption.
  254. // encryption is supported by msmq only when the sender has access to
  255. // ds. This means when this machine is offline, we cannot encrypt
  256. // messages.
  257. //
  258. wsQueueName = L"wszMachine\\";
  259. }
  260. DWORD dwQos = m_dwFlags & WMIMSG_MASK_QOS;
  261. _DBG_ASSERT( dwQos != WMIMSG_FLAG_QOS_SYNCHRONOUS );
  262. if( dwQos == WMIMSG_FLAG_QOS_EXPRESS )
  263. {
  264. wsQueueName += L"WMIFwdExpress";
  265. }
  266. else if( dwQos == WMIMSG_FLAG_QOS_GUARANTEED )
  267. {
  268. wsQueueName += L"WMIFwdGuaranteed";
  269. }
  270. else if ( dwQos == WMIMSG_FLAG_QOS_XACT )
  271. {
  272. wsQueueName += L"WMIFwdXact";
  273. }
  274. if ( m_dwFlags & WMIMSG_FLAG_SNDR_ENCRYPT )
  275. {
  276. wsQueueName += L"Encrypt";
  277. }
  278. else if ( m_dwFlags & WMIMSG_FLAG_SNDR_AUTHENTICATE )
  279. {
  280. wsQueueName += L"Auth";
  281. }
  282. return AddMSMQSender(wsQueueName);
  283. }
  284. HRESULT CFwdConsSend::AddSyncSender( LPCWSTR wszMachine )
  285. {
  286. HRESULT hr;
  287. CWbemPtr<IWmiMessageSender> pSender;
  288. hr = CoCreateInstance( CLSID_WmiMessageRpcSender,
  289. NULL,
  290. CLSCTX_INPROC,
  291. IID_IWmiMessageSender,
  292. (void**)&pSender );
  293. if ( FAILED(hr) )
  294. {
  295. return hr;
  296. }
  297. //
  298. // construct target binding : OBJID@ncacn_ip_tcp:target
  299. //
  300. WString wsTarget = L"7879E40D-9FB5-450a-8A6D-00C89F349FCE@ncacn_ip_tcp:";
  301. wsTarget += wszMachine;
  302. //
  303. // construct the target principal name - for kerberos. We expect that
  304. // has registered its SPN with AD. we only need to do this if we
  305. // are sending authenticated though ...
  306. //
  307. LPWSTR wszSpn = NULL;
  308. if ( m_dwFlags & WMIMSG_FLAG_SNDR_AUTHENTICATE )
  309. {
  310. hr = GetSpn( wszMachine, &wszSpn );
  311. if ( FAILED(hr) )
  312. {
  313. DEBUGTRACE((LOG_ESS,"FC: Could not determine SPN for target %S. "
  314. "hr=0x%x. Will try to forward events using NTLM\n",
  315. wszMachine, hr ));
  316. }
  317. }
  318. CVectorDeleteMe<WCHAR> vdm2( wszSpn );
  319. WMIMSG_SNDR_AUTH_INFO AuthInfo;
  320. ZeroMemory( &AuthInfo, sizeof( WMIMSG_SNDR_AUTH_INFO ) );
  321. AuthInfo.wszTargetPrincipal = wszSpn;
  322. //
  323. // open sender
  324. //
  325. CWbemPtr<IWmiMessageSendReceive> pSend;
  326. hr = pSender->Open( wsTarget,
  327. m_dwFlags | WMIMSG_FLAG_SNDR_LAZY_INIT,
  328. &AuthInfo,
  329. NULL,
  330. m_pTraceSink,
  331. &pSend );
  332. if ( FAILED(hr) )
  333. {
  334. return hr;
  335. }
  336. //
  337. // add to multi sender and return.
  338. //
  339. return m_pMultiSend->Add(WMIMSG_FLAG_MULTISEND_TERMINATING_SENDER, pSend );
  340. }
  341. HRESULT CFwdConsSend::AddPhysicalSender( LPCWSTR wszMachine )
  342. {
  343. HRESULT hr;
  344. #ifndef __WHISTLER_UNCUT
  345. if ( (m_dwFlags & WMIMSG_MASK_QOS) != WMIMSG_FLAG_QOS_SYNCHRONOUS )
  346. {
  347. return WBEM_E_NOT_SUPPORTED;
  348. }
  349. return AddSyncSender( wszMachine );
  350. #else
  351. //
  352. // here, we always add a sync sender first even if a qos
  353. // of async is specified. Later this type of service may change to
  354. // be its own QoS class.
  355. //
  356. hr = AddSyncSender( wszMachine );
  357. if ( FAILED(hr) )
  358. {
  359. return hr;
  360. }
  361. if ( (m_dwFlags & WMIMSG_MASK_QOS) == WMIMSG_FLAG_QOS_SYNCHRONOUS )
  362. {
  363. return WBEM_S_NO_ERROR;
  364. }
  365. return AddAsyncSender( wszMachine );
  366. #endif
  367. }
  368. HRESULT CFwdConsSend::AddLogicalSender( LPCWSTR wszTarget )
  369. {
  370. HRESULT hr;
  371. CWbemPtr<IWmiMessageSendReceive> pSend;
  372. hr = Create( m_pControl,
  373. wszTarget,
  374. m_dwFlags | FWD_FLAG_NO_INDIRECT,
  375. NULL,
  376. m_pTraceSink,
  377. &pSend );
  378. if ( FAILED(hr) )
  379. {
  380. return hr;
  381. }
  382. return m_pMultiSend->Add( 0, pSend );
  383. }
  384. HRESULT CFwdConsSend::AddLogicalSender( LPCWSTR wszObjpath, LPCWSTR wszProp )
  385. {
  386. HRESULT hr;
  387. //
  388. // Check to make sure that indirect names are supported.
  389. // This flag is mostly used to prohibit recursive indirect
  390. // addesses.
  391. //
  392. if ( m_dwFlags & FWD_FLAG_NO_INDIRECT )
  393. {
  394. return WBEM_E_NOT_SUPPORTED;
  395. }
  396. CWbemBSTR bsObjPath = wszObjpath;
  397. //
  398. // Resolve the address by obtaining the object and getting
  399. // the value of the specified property.
  400. //
  401. VARIANT var;
  402. CWbemPtr<IWbemClassObject> pObj;
  403. hr = m_pDefaultSvc->GetObject( bsObjPath, 0, NULL, &pObj, NULL );
  404. if ( FAILED(hr) )
  405. {
  406. return hr;
  407. }
  408. hr = pObj->Get( wszProp, 0, &var, NULL, NULL );
  409. if ( FAILED(hr) )
  410. {
  411. return hr;
  412. }
  413. CClearMe cmvar(&var);
  414. //
  415. // Add a new logical sender after resolving the address.
  416. // Before adding the new sender, make sure we disable indirect
  417. // addresses on it to prohibit recursive resolution.
  418. //
  419. DWORD dwFlags = m_dwFlags | FWD_FLAG_NO_INDIRECT;
  420. if ( V_VT(&var) == VT_BSTR )
  421. {
  422. return AddLogicalSender( V_BSTR(&var) );
  423. }
  424. else if ( V_VT(&var) == (VT_ARRAY | VT_BSTR) )
  425. {
  426. BSTR* abstrNames;
  427. hr = SafeArrayAccessData( V_ARRAY(&var), (void**)&abstrNames );
  428. if ( FAILED(hr) )
  429. {
  430. return hr;
  431. }
  432. long lUbound;
  433. hr = SafeArrayGetUBound( V_ARRAY(&var), 0, &lUbound );
  434. _DBG_ASSERT(SUCCEEDED(hr));
  435. for( long i=0; i < lUbound+1; i++ )
  436. {
  437. AddLogicalSender( V_BSTR(&var) );
  438. }
  439. SafeArrayUnaccessData( V_ARRAY(&var) );
  440. }
  441. else
  442. {
  443. return WBEM_E_TYPE_MISMATCH;
  444. }
  445. return hr;
  446. }
  447. HRESULT CFwdConsSend::EnsureSender()
  448. {
  449. HRESULT hr;
  450. CInCritSec ics(&m_cs);
  451. if ( m_bResolved )
  452. {
  453. return S_OK;
  454. }
  455. WString wsTarget = m_wsTarget;
  456. LPWSTR wszToken = wcstok( wsTarget, L"!" );
  457. LPWSTR wszToken2 = wcstok( NULL, L"!" );
  458. if ( wszToken2 == NULL )
  459. {
  460. hr = AddPhysicalSender( wszToken );
  461. }
  462. #ifdef __WHISTLER_UNCUT
  463. else if ( wbem_wcsicmp( wszToken, L"msmq" ) == 0 )
  464. {
  465. hr = AddMSMQSender( wszToken2 );
  466. }
  467. else if ( wbem_wcsicmp( wszToken, L"wmi" ) == 0 )
  468. {
  469. LPWSTR wszToken3 = wcstok( NULL, L"!" );
  470. if ( wszToken3 == NULL )
  471. {
  472. return WMIMSG_E_INVALIDADDRESS;
  473. }
  474. hr = AddLogicalSender( wszToken2, wszToken3 );
  475. }
  476. #endif
  477. else
  478. {
  479. return WMIMSG_E_INVALIDADDRESS;
  480. }
  481. if ( FAILED(hr) )
  482. {
  483. return hr;
  484. }
  485. m_bResolved = TRUE;
  486. return hr;
  487. }
  488. HRESULT CFwdConsSend::HandleTrace( HRESULT hr, IUnknown* pCtx )
  489. {
  490. if ( m_pTraceSink == NULL )
  491. {
  492. return WBEM_S_NO_ERROR;
  493. }
  494. return m_pTraceSink->Notify( hr, g_guidQueueType, m_wsTarget, pCtx );
  495. }
  496. HRESULT CFwdConsSend::SendReceive( PBYTE pData,
  497. ULONG cData,
  498. PBYTE pAuxData,
  499. ULONG cAuxData,
  500. DWORD dwFlagStatus,
  501. IUnknown* pCtx )
  502. {
  503. HRESULT hr;
  504. hr = EnsureSender();
  505. if ( FAILED(hr) )
  506. {
  507. HandleTrace( hr, pCtx );
  508. return hr;
  509. }
  510. return m_pMultiSend->SendReceive( pData,
  511. cData,
  512. pAuxData,
  513. cAuxData,
  514. dwFlagStatus,
  515. pCtx );
  516. }
  517. HRESULT CFwdConsSend::Create( CLifeControl* pCtl,
  518. LPCWSTR wszTarget,
  519. DWORD dwFlags,
  520. IWbemServices* pDefaultSvc,
  521. IWmiMessageTraceSink* pTraceSink,
  522. IWmiMessageSendReceive** ppSend )
  523. {
  524. HRESULT hr;
  525. *ppSend = NULL;
  526. CWbemPtr<IWmiMessageMultiSendReceive> pMultiSend;
  527. hr = CoCreateInstance( CLSID_WmiMessageMultiSendReceive,
  528. NULL,
  529. CLSCTX_INPROC,
  530. IID_IWmiMessageMultiSendReceive,
  531. (void**)&pMultiSend );
  532. if ( FAILED(hr) )
  533. {
  534. return hr;
  535. }
  536. CWbemPtr<CFwdConsSend> pSend = new CFwdConsSend( pCtl );
  537. if ( pSend == NULL )
  538. {
  539. return WBEM_E_OUT_OF_MEMORY;
  540. }
  541. if ( wszTarget != NULL && *wszTarget != 0 )
  542. {
  543. pSend->m_wsTarget = wszTarget;
  544. }
  545. else
  546. {
  547. //
  548. // the default is to send to local computer.
  549. //
  550. TCHAR achComputer[MAX_COMPUTERNAME_LENGTH+1];
  551. ULONG ulSize = MAX_COMPUTERNAME_LENGTH+1;
  552. GetComputerName( achComputer, &ulSize );
  553. pSend->m_wsTarget = achComputer;
  554. }
  555. pSend->m_dwFlags = dwFlags;
  556. pSend->m_pDefaultSvc = pDefaultSvc;
  557. pSend->m_pTraceSink = pTraceSink;
  558. pSend->m_pMultiSend = pMultiSend;
  559. hr = pSend->QueryInterface( IID_IWmiMessageSendReceive, (void**)ppSend );
  560. _DBG_ASSERT(SUCCEEDED(hr));
  561. return WBEM_S_NO_ERROR;
  562. }