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.

567 lines
15 KiB

  1. // NCProvider.cpp : Implementation of CNCProvider
  2. #include "precomp.h"
  3. #include "NCProv.h"
  4. #include "NCProvider.h"
  5. #include "NCDefs.h"
  6. #include <list>
  7. #include "Buffer.h"
  8. #include "dutils.h"
  9. #include "NCObjAPI.h"
  10. #include <Winntsec.h>
  11. #define COUNTOF(x) (sizeof(x)/sizeof(x[0]))
  12. /////////////////////////////////////////////////////////////////////////////
  13. // CNCProvider
  14. CNCProvider::CNCProvider() :
  15. m_heventDone(NULL),
  16. m_heventConnect(NULL),
  17. m_hPipe( NULL ),
  18. m_hthreadConnect(NULL),
  19. m_pProv(NULL)
  20. {
  21. InitializeCriticalSection(&m_cs);
  22. }
  23. CNCProvider::~CNCProvider()
  24. {
  25. DeleteCriticalSection(&m_cs);
  26. }
  27. void CNCProvider::FinalRelease()
  28. {
  29. //
  30. // do potentially time consuming cleanup in this function rather than
  31. // DTOR. Reason is that ATL decrements the module ref count before calling
  32. // the DTOR. This means that a call to DllCanUnloadNow will return TRUE
  33. // while there is still a call executing in the module. The race condition
  34. // is that the module could be unloaded while it is still being executed.
  35. // ATL will call FinalRelease() before decrementing the module refcount
  36. // making this race condition much smaller. COM addresses this race
  37. // condition by waiting for a bit to unload the module after returning
  38. // TRUE. This wait can be controlled by the delay unload param to
  39. // CoFreeUnusedLibrariesEx(). This allows the call to the last Release()
  40. // of the COM object to finish, before being unloaded.
  41. //
  42. if ( m_hthreadConnect )
  43. {
  44. SetEvent(m_heventDone);
  45. WaitForSingleObject( m_hthreadConnect, INFINITE );
  46. CloseHandle(m_hthreadConnect);
  47. }
  48. if (m_heventDone)
  49. CloseHandle(m_heventDone);
  50. delete m_pProv;
  51. }
  52. HRESULT STDMETHODCALLTYPE CNCProvider::Initialize(
  53. /* [in] */ LPWSTR pszUser,
  54. /* [in] */ LONG lFlags,
  55. /* [in] */ LPWSTR pszNamespace,
  56. /* [in] */ LPWSTR pszLocale,
  57. /* [in] */ IWbemServices __RPC_FAR *pNamespace,
  58. /* [in] */ IWbemContext __RPC_FAR *pCtx,
  59. /* [in] */ IWbemProviderInitSink __RPC_FAR *pInitSink)
  60. {
  61. m_pProv = new CProvInfo;
  62. if ( m_pProv == NULL )
  63. {
  64. return WBEM_E_OUT_OF_MEMORY;
  65. }
  66. m_pProv->SetNamespace(pNamespace);
  67. m_heventDone =
  68. CreateEvent(
  69. NULL,
  70. TRUE,
  71. FALSE,
  72. NULL);
  73. if ( m_heventDone == NULL )
  74. {
  75. return HRESULT_FROM_WIN32( GetLastError() );
  76. }
  77. try
  78. {
  79. m_strNamespace = pszNamespace;
  80. }
  81. catch( _com_error )
  82. {
  83. return WBEM_E_OUT_OF_MEMORY;
  84. }
  85. // Tell Windows Management our initialization status.
  86. return pInitSink->SetStatus( WBEM_S_INITIALIZED, 0 );
  87. }
  88. HRESULT STDMETHODCALLTYPE CNCProvider::SetRegistrationObject(
  89. LONG lFlags,
  90. IWbemClassObject __RPC_FAR *pProvReg)
  91. {
  92. _variant_t vName;
  93. if (SUCCEEDED(pProvReg->Get(
  94. L"Name",
  95. 0,
  96. &vName,
  97. NULL,
  98. NULL)) )
  99. {
  100. if ( V_VT(&vName) != VT_BSTR )
  101. return WBEM_E_INVALID_OBJECT;
  102. m_strProvider = V_BSTR(&vName);
  103. }
  104. return S_OK;
  105. }
  106. HRESULT STDMETHODCALLTYPE CNCProvider::AccessCheck(
  107. /* [in] */ WBEM_CWSTR wszQueryLanguage,
  108. /* [in] */ WBEM_CWSTR wszQuery,
  109. /* [in] */ long lSidLength,
  110. /* [unique][size_is][in] */ const BYTE __RPC_FAR *pSid)
  111. {
  112. HRESULT hr;
  113. try
  114. {
  115. hr =
  116. m_pProv->AccessCheck(
  117. wszQueryLanguage,
  118. wszQuery,
  119. lSidLength,
  120. (LPBYTE) pSid);
  121. }
  122. catch(...)
  123. {
  124. hr = WBEM_E_FAILED;
  125. }
  126. return hr;
  127. }
  128. HRESULT STDMETHODCALLTYPE CNCProvider::NewQuery(
  129. /* [in] */ DWORD dwID,
  130. /* [in] */ WBEM_WSTR wszQueryLanguage,
  131. /* [in] */ WBEM_WSTR wszQuery)
  132. {
  133. HRESULT hr;
  134. try
  135. {
  136. hr = m_pProv->NewQuery(dwID, wszQueryLanguage, wszQuery);
  137. }
  138. catch(...)
  139. {
  140. hr = WBEM_E_FAILED;
  141. }
  142. return hr;
  143. }
  144. HRESULT STDMETHODCALLTYPE CNCProvider::CancelQuery(
  145. /* [in] */ DWORD dwID)
  146. {
  147. try
  148. {
  149. // Get rid of the query item(s).
  150. m_pProv->CancelQuery(dwID);
  151. }
  152. catch(...)
  153. {
  154. }
  155. return S_OK;
  156. }
  157. HRESULT STDMETHODCALLTYPE CNCProvider::ProvideEvents(
  158. /* [in] */ IWbemObjectSink __RPC_FAR *pSink,
  159. /* [in] */ long lFlags)
  160. {
  161. DWORD dwID;
  162. IWbemEventSink *pEventSink = NULL;
  163. HRESULT hr;
  164. if (SUCCEEDED(pSink->QueryInterface(
  165. IID_IWbemEventSink, (LPVOID*) &pEventSink)))
  166. {
  167. m_pProv->SetSink(pEventSink);
  168. pEventSink->Release();
  169. if (!m_hthreadConnect)
  170. {
  171. m_hthreadConnect =
  172. CreateThread(
  173. NULL,
  174. 0,
  175. (LPTHREAD_START_ROUTINE) ConnectThreadProc,
  176. this,
  177. 0,
  178. &dwID);
  179. }
  180. hr = S_OK;
  181. }
  182. else
  183. hr = WBEM_E_FAILED;
  184. return hr;
  185. }
  186. DWORD WINAPI CNCProvider::ConnectThreadProc(CNCProvider *pThis)
  187. {
  188. DWORD dwRet = ERROR_SUCCESS;
  189. if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
  190. {
  191. try
  192. {
  193. pThis->ConnectLoop();
  194. }
  195. catch( CX_MemoryException )
  196. {
  197. dwRet = ERROR_OUTOFMEMORY;
  198. }
  199. CoUninitialize();
  200. }
  201. return dwRet;
  202. }
  203. // ConnectToNewClient(HANDLE, LPOVERLAPPED)
  204. // This function is called to start an overlapped connect operation.
  205. // It returns TRUE if an operation is pending or FALSE if the
  206. // connection has been completed.
  207. BOOL CNCProvider::ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
  208. {
  209. BOOL bConnected,
  210. bPendingIO = FALSE;
  211. // Start an overlapped connection for this pipe instance.
  212. bConnected = ConnectNamedPipe(hPipe, lpo);
  213. // Overlapped ConnectNamedPipe should return zero.
  214. if (bConnected)
  215. return FALSE;
  216. switch (GetLastError())
  217. {
  218. // The overlapped connection in progress.
  219. case ERROR_IO_PENDING:
  220. bPendingIO = TRUE;
  221. break;
  222. // Client is already connected, so signal an event.
  223. case ERROR_PIPE_CONNECTED:
  224. SetEvent(lpo->hEvent);
  225. break;
  226. // If an error occurs during the connect operation...
  227. default:
  228. return FALSE;
  229. }
  230. return bPendingIO;
  231. }
  232. #define PIPE_SIZE 64000
  233. BOOL CNCProvider::CreateAndConnectInstance(LPOVERLAPPED lpoOverlap, BOOL bFirst)
  234. {
  235. SECURITY_ATTRIBUTES sa;
  236. sa.nLength = sizeof( SECURITY_ATTRIBUTES );
  237. sa.bInheritHandle = FALSE;
  238. LPWSTR lpwszSD = L"D:" // DACL
  239. L"(A;;GA;;;SY)" // Allow local system full control
  240. L"(A;;GRGW;;;LS)" // Allow local service Read/Write
  241. L"(A;;GRGW;;;NS)"; // Allow network service Read/Write
  242. if ( ConvertStringSecurityDescriptorToSecurityDescriptor(
  243. lpwszSD,
  244. SDDL_REVISION_1,
  245. &(sa.lpSecurityDescriptor),
  246. NULL ) )
  247. {
  248. long lFlags = PIPE_ACCESS_DUPLEX | // read/write access
  249. FILE_FLAG_OVERLAPPED; // overlapped mode
  250. if( bFirst )
  251. {
  252. lFlags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
  253. }
  254. m_hPipe = CreateNamedPipe(
  255. m_szNamedPipe, // pipe name
  256. lFlags,
  257. PIPE_TYPE_MESSAGE | // message-type pipe
  258. PIPE_READMODE_MESSAGE | // message read mode
  259. PIPE_WAIT, // blocking mode
  260. PIPE_UNLIMITED_INSTANCES, // unlimited instances
  261. PIPE_SIZE, // output buffer size
  262. PIPE_SIZE, // input buffer size
  263. 0, // client time-out
  264. &sa ); // security per above
  265. if ( INVALID_HANDLE_VALUE == m_hPipe )
  266. {
  267. return FALSE;
  268. }
  269. }
  270. else
  271. {
  272. return FALSE;
  273. }
  274. //
  275. // Make sure that the pipe is owned by us
  276. // Call a subroutine to connect to the new client.
  277. //
  278. return ConnectToNewClient(m_hPipe, lpoOverlap);
  279. /*
  280. HRESULT hr = WBEM_S_NO_ERROR;
  281. SID_IDENTIFIER_AUTHORITY id = SECURITY_NT_AUTHORITY;
  282. PSID pSidSystem;
  283. if (AllocateAndInitializeSid(&id, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0,0,0,0,0,0,&pSidSystem))
  284. {
  285. // Create an everyone SID
  286. PSID pRawSid;
  287. SID_IDENTIFIER_AUTHORITY id2 = SECURITY_WORLD_SID_AUTHORITY;;
  288. if( FALSE == AllocateAndInitializeSid( &id2, 1,0,0,0,0,0,0,0,0, &pRawSid ) )
  289. {
  290. FreeSid ( pSidSystem );
  291. return FALSE;
  292. }
  293. // setup security descriptor with read/write for everyone & owned by local system
  294. // actual check for valid client is performed in CProvInfo::ClientAccessCheck
  295. CNtSid sidWorld( pRawSid );
  296. FreeSid(pRawSid);
  297. CNtAce aceWorld(GENERIC_READ | GENERIC_WRITE, ACCESS_ALLOWED_ACE_TYPE, 0, sidWorld);
  298. CNtSid sidSystem(pSidSystem);
  299. FreeSid ( pSidSystem );
  300. pSidSystem = NULL;
  301. CNtAce aceSystem(FULL_CONTROL, ACCESS_ALLOWED_ACE_TYPE, 0, sidSystem);
  302. CNtAcl ackl;
  303. ackl.AddAce(&aceWorld);
  304. ackl.AddAce(&aceSystem);
  305. ackl.Resize(CNtAcl::MinimumSize);
  306. CNtSecurityDescriptor cSD;
  307. cSD.SetDacl(&ackl);
  308. SECURITY_ATTRIBUTES sa;
  309. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  310. sa.bInheritHandle = true;
  311. sa.lpSecurityDescriptor = (void*)cSD.GetPtr();
  312. long lFlags = PIPE_ACCESS_DUPLEX | // read/write access
  313. FILE_FLAG_OVERLAPPED; // overlapped mode
  314. if(bFirst)
  315. lFlags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
  316. m_hPipe =
  317. CreateNamedPipe(
  318. m_szNamedPipe, // pipe name
  319. lFlags,
  320. PIPE_TYPE_MESSAGE | // message-type pipe
  321. PIPE_READMODE_MESSAGE | // message read mode
  322. PIPE_WAIT, // blocking mode
  323. PIPE_UNLIMITED_INSTANCES, // unlimited instances
  324. PIPE_SIZE, // output buffer size
  325. PIPE_SIZE, // input buffer size
  326. 0, // client time-out
  327. &sa); // security per above
  328. }
  329. else // AllocateAndInitSid failed - outta here
  330. return FALSE;
  331. if (m_hPipe == INVALID_HANDLE_VALUE)
  332. return FALSE;
  333. //
  334. // Make sure that the pipe is owned by us
  335. // Call a subroutine to connect to the new client.
  336. return ConnectToNewClient(m_hPipe, lpoOverlap);
  337. */
  338. }
  339. void CNCProvider::ConnectLoop()
  340. {
  341. // Init our provider info which will tell our comless providers that
  342. // we're ready.
  343. try
  344. {
  345. m_pProv->Init(m_strNamespace, m_strProvider);
  346. }
  347. catch( CX_MemoryException )
  348. {
  349. return;
  350. }
  351. m_heventConnect =
  352. CreateEvent(
  353. NULL, // no security attribute
  354. TRUE, // manual reset event
  355. TRUE, // initial state = signaled
  356. NULL); // unnamed event object
  357. //m_pServerPost = new CPostBuffer(this);
  358. // TODO: We need to indicate an error here.
  359. if (!m_heventConnect)
  360. return;
  361. StringCchPrintf(
  362. m_szNamedPipe,
  363. 256,
  364. L"\\\\.\\pipe\\" OBJNAME_NAMED_PIPE L"%s%s",
  365. (LPCWSTR) m_pProv->m_strBaseNamespace,
  366. (LPCWSTR) m_pProv->m_strBaseName);
  367. OVERLAPPED oConnect;
  368. BOOL bSuccess,
  369. bPendingIO;
  370. HANDLE hWait[2] = { m_heventDone, m_heventConnect };
  371. DWORD dwRet;
  372. oConnect.hEvent = m_heventConnect;
  373. bPendingIO = CreateAndConnectInstance(&oConnect, TRUE); // first instance
  374. while ((dwRet = WaitForMultipleObjectsEx(2, hWait, FALSE, INFINITE, TRUE))
  375. != WAIT_OBJECT_0)
  376. {
  377. if ( dwRet == WAIT_FAILED )
  378. {
  379. break;
  380. }
  381. switch(dwRet)
  382. {
  383. case 1:
  384. {
  385. if (bPendingIO)
  386. {
  387. DWORD dwBytes;
  388. bSuccess =
  389. GetOverlappedResult(
  390. m_hPipe, // pipe handle
  391. &oConnect, // OVERLAPPED structure
  392. &dwBytes, // bytes transferred
  393. FALSE); // does not wait
  394. // TODO: This is an error, but what to do?
  395. if (!bSuccess)
  396. break;
  397. }
  398. CPipeClient *pInfo = new CPipeClient(this, m_hPipe);
  399. if (pInfo)
  400. {
  401. bSuccess =
  402. ReadFileEx(
  403. pInfo->m_hPipe,
  404. pInfo->m_bufferRecv.m_pBuffer,
  405. pInfo->m_bufferRecv.m_dwSize,
  406. &pInfo->m_info.overlap,
  407. (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
  408. if (!bSuccess)
  409. DisconnectAndClose(pInfo);
  410. }
  411. bPendingIO = CreateAndConnectInstance(&oConnect, FALSE);
  412. break;
  413. }
  414. case WAIT_IO_COMPLETION:
  415. break;
  416. }
  417. }
  418. CloseHandle(m_hPipe);
  419. CloseHandle(m_heventConnect);
  420. }
  421. void CNCProvider::DisconnectAndClose(CClientInfo *pInfo)
  422. {
  423. m_pProv->RemoveClient(pInfo);
  424. }
  425. void WINAPI CNCProvider::CompletedReadRoutine(
  426. DWORD dwErr,
  427. DWORD nBytesRead,
  428. LPOVERLAPPED pOverlap)
  429. {
  430. CPipeClient *pInfo = ((OLAP_AND_CLIENT*) pOverlap)->pInfo;
  431. CNCProvider *pThis = pInfo->m_pProvider;
  432. #ifndef _DEBUG
  433. try
  434. #endif
  435. {
  436. #ifndef NO_DECODE
  437. if (nBytesRead)
  438. {
  439. pInfo->PostBuffer(pInfo->m_bufferRecv.m_pBuffer, nBytesRead);
  440. }
  441. #endif
  442. }
  443. #ifndef _DEBUG
  444. catch(...)
  445. {
  446. }
  447. #endif
  448. try
  449. {
  450. // The read operation has finished, so write a response (if no
  451. // error occurred).
  452. if (dwErr == 0)
  453. {
  454. BOOL bSuccess;
  455. bSuccess =
  456. ReadFileEx(
  457. pInfo->m_hPipe,
  458. pInfo->m_bufferRecv.m_pBuffer,
  459. pInfo->m_bufferRecv.m_dwSize,
  460. pOverlap,
  461. (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
  462. if (!bSuccess)
  463. pThis->DisconnectAndClose(pInfo);
  464. }
  465. else
  466. pThis->DisconnectAndClose(pInfo);
  467. }
  468. catch( CX_MemoryException )
  469. {
  470. }
  471. }