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.

577 lines
19 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: APIConnectionThread.cpp
  3. //
  4. // Copyright (c) 1999-2000, Microsoft Corporation
  5. //
  6. // A class that listens to an LPC connection port waiting for requests from
  7. // a client to connect to the port or a request which references a previously
  8. // established connection.
  9. //
  10. // History: 1999-11-07 vtan created
  11. // 2000-08-25 vtan moved from Neptune to Whistler
  12. // --------------------------------------------------------------------------
  13. #include "StandardHeader.h"
  14. #include "APIConnection.h"
  15. #include <lpcgeneric.h>
  16. #include "Access.h"
  17. #include "StatusCode.h"
  18. // --------------------------------------------------------------------------
  19. // CAPIConnection::CAPIConnection
  20. //
  21. // Arguments: <none>
  22. //
  23. // Returns: <none>
  24. //
  25. // Purpose: Constructor for CAPIConnectionThread. Store the CServerAPI
  26. // function table. This describes how to react to LPC messages.
  27. // This function also creates the server connection port.
  28. //
  29. // History: 1999-11-07 vtan created
  30. // 2000-08-25 vtan moved from Neptune to Whistler
  31. // 2000-09-01 vtan use explicit security descriptor
  32. // --------------------------------------------------------------------------
  33. CAPIConnection::CAPIConnection (CServerAPI* pServerAPI) :
  34. _status(STATUS_NO_MEMORY),
  35. _fStopListening(false),
  36. _pServerAPI(pServerAPI),
  37. _hPort(NULL),
  38. _pAPIDispatchSync(NULL)
  39. {
  40. OBJECT_ATTRIBUTES objectAttributes;
  41. UNICODE_STRING portName;
  42. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  43. // Increment the reference on the interface.
  44. pServerAPI->AddRef();
  45. // Get the name from the interface.
  46. RtlInitUnicodeString(&portName, pServerAPI->GetPortName());
  47. // Build a security descriptor for the port that allows:
  48. // S-1-5-18 NT AUTHORITY\SYSTEM PORT_ALL_ACCESS
  49. // S-1-5-32-544 <local administrators> READ_CONTROL | PORT_CONNECT
  50. static SID_IDENTIFIER_AUTHORITY s_SecurityNTAuthority = SECURITY_NT_AUTHORITY;
  51. static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
  52. {
  53. {
  54. &s_SecurityNTAuthority,
  55. 1,
  56. SECURITY_LOCAL_SYSTEM_RID,
  57. 0, 0, 0, 0, 0, 0, 0,
  58. PORT_ALL_ACCESS
  59. },
  60. {
  61. &s_SecurityNTAuthority,
  62. 2,
  63. SECURITY_BUILTIN_DOMAIN_RID,
  64. DOMAIN_ALIAS_RID_ADMINS,
  65. 0, 0, 0, 0, 0, 0,
  66. READ_CONTROL | PORT_CONNECT
  67. }
  68. };
  69. // Build a security descriptor that allows the described access above.
  70. pSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
  71. // Initialize the object attributes.
  72. InitializeObjectAttributes(&objectAttributes,
  73. &portName,
  74. 0,
  75. NULL,
  76. pSecurityDescriptor);
  77. // Create the port.
  78. _status = NtCreatePort(&_hPort,
  79. &objectAttributes,
  80. 128, // Max connection info length (kernel accepts (MaxMessageLength - 68) maximum (188 here)),
  81. // used for client validation
  82. PORT_MAXIMUM_MESSAGE_LENGTH, // MaxMessageLength
  83. 16 * PORT_MAXIMUM_MESSAGE_LENGTH);
  84. // Release the security descriptor memory.
  85. ReleaseMemory(pSecurityDescriptor);
  86. if (!NT_SUCCESS(_status))
  87. {
  88. pServerAPI->Release();
  89. }
  90. }
  91. // --------------------------------------------------------------------------
  92. // CAPIConnection::~CAPIConnection
  93. //
  94. // Arguments: <none>
  95. //
  96. // Returns: <none>
  97. //
  98. // Purpose: Destructor for CAPIConnectionThread. Close the port. Release
  99. // the interface referrence.
  100. //
  101. // History: 1999-11-07 vtan created
  102. // 2000-08-25 vtan moved from Neptune to Whistler
  103. // --------------------------------------------------------------------------
  104. CAPIConnection::~CAPIConnection (void)
  105. {
  106. ReleaseHandle(_hPort);
  107. _pServerAPI->Release();
  108. _pServerAPI = NULL;
  109. }
  110. // --------------------------------------------------------------------------
  111. // CAPIConnection::ConstructorStatusCode
  112. //
  113. // Arguments: <none>
  114. //
  115. // Returns: NTSTATUS
  116. //
  117. // Purpose: Returns the constructor status code back to the caller.
  118. //
  119. // History: 2000-10-18 vtan created
  120. // --------------------------------------------------------------------------
  121. NTSTATUS CAPIConnection::ConstructorStatusCode (void) const
  122. {
  123. return(_status);
  124. }
  125. // --------------------------------------------------------------------------
  126. // CAPIConnection::Listen
  127. //
  128. // Arguments: <none>
  129. //
  130. // Returns: NTSTATUS
  131. //
  132. // Purpose: Listens for server API connections and requests.
  133. //
  134. // History: 2000-11-28 vtan created
  135. // --------------------------------------------------------------------------
  136. NTSTATUS CAPIConnection::Listen (CAPIDispatchSync* pAPIDispatchSync)
  137. {
  138. NTSTATUS status;
  139. // If a connection port was created then start listening.
  140. if (_hPort != NULL)
  141. {
  142. _pAPIDispatchSync = pAPIDispatchSync;
  143. do
  144. {
  145. (NTSTATUS)ListenToServerConnectionPort();
  146. } while (!_fStopListening);
  147. status = STATUS_SUCCESS;
  148. }
  149. else
  150. {
  151. status = STATUS_OBJECT_NAME_NOT_FOUND;
  152. }
  153. return(status);
  154. }
  155. // --------------------------------------------------------------------------
  156. // CAPIConnection::AddAccess
  157. //
  158. // Arguments: <none>
  159. //
  160. // Returns: NTSTATUS
  161. //
  162. // Purpose: Adds access allowed to the ACL of the port.
  163. //
  164. // History: 2000-10-10 vtan created
  165. // --------------------------------------------------------------------------
  166. NTSTATUS CAPIConnection::AddAccess (PSID pSID, DWORD dwMask)
  167. {
  168. CSecuredObject object(_hPort, SE_KERNEL_OBJECT);
  169. return(object.Allow(pSID, dwMask, 0));
  170. }
  171. // --------------------------------------------------------------------------
  172. // CAPIConnection::RemoveAccess
  173. //
  174. // Arguments: <none>
  175. //
  176. // Returns: NTSTATUS
  177. //
  178. // Purpose: Removes access allowed from the ACL of the port.
  179. //
  180. // History: 2000-10-10 vtan created
  181. // --------------------------------------------------------------------------
  182. NTSTATUS CAPIConnection::RemoveAccess (PSID pSID)
  183. {
  184. CSecuredObject object(_hPort, SE_KERNEL_OBJECT);
  185. return(object.Remove(pSID));
  186. }
  187. // --------------------------------------------------------------------------
  188. // CAPIConnection::ListenToServerConnectionPort
  189. //
  190. // Arguments: <none>
  191. //
  192. // Returns: NTSTATUS
  193. //
  194. // Purpose: Calls ntdll!NtReplyWaitReceivePort to listen to the LPC port
  195. // for a message. Respond to the message. Messages understood are
  196. // LPC_REQUEST / LPC_CONNECTION_REQUEST / LPC_PORT_CLOSED.
  197. //
  198. // History: 1999-11-07 vtan created
  199. // 2000-08-25 vtan moved from Neptune to Whistler
  200. // --------------------------------------------------------------------------
  201. NTSTATUS CAPIConnection::ListenToServerConnectionPort (void)
  202. {
  203. NTSTATUS status;
  204. CAPIDispatcher *pAPIDispatcher;
  205. CPortMessage portMessage;
  206. status = NtReplyWaitReceivePort(_hPort,
  207. reinterpret_cast<void**>(&pAPIDispatcher),
  208. NULL,
  209. portMessage.GetPortMessage());
  210. if (NT_SUCCESS(status))
  211. {
  212. switch (portMessage.GetType())
  213. {
  214. case LPC_REQUEST:
  215. status = HandleServerRequest(portMessage, pAPIDispatcher);
  216. break;
  217. case LPC_CONNECTION_REQUEST:
  218. (NTSTATUS)HandleServerConnectionRequest(portMessage);
  219. break;
  220. case LPC_PORT_CLOSED:
  221. status = HandleServerConnectionClosed(portMessage, pAPIDispatcher);
  222. break;
  223. default:
  224. break;
  225. }
  226. TSTATUS(status);
  227. }
  228. return(status);
  229. }
  230. // --------------------------------------------------------------------------
  231. // CAPIConnection::HandleServerRequest
  232. //
  233. // Arguments: portMessage = CPortMessage containing the message.
  234. // pAPIDispatcher = CAPIDispatcher to handle request.
  235. //
  236. // Returns: NTSTATUS
  237. //
  238. // Purpose: Queue the PORT_MESSAGE request to the handling dispatcher and
  239. // wait for the next message. The queue operation will queue the
  240. // request and either queue a work item if no work item is
  241. // currently executing or just add it to the currently executing
  242. // work item.
  243. //
  244. // History: 1999-11-07 vtan created
  245. // 2000-08-25 vtan moved from Neptune to Whistler
  246. // --------------------------------------------------------------------------
  247. NTSTATUS CAPIConnection::HandleServerRequest (const CPortMessage& portMessage, CAPIDispatcher *pAPIDispatcher)
  248. {
  249. NTSTATUS status;
  250. unsigned long ulAPINumber;
  251. const API_GENERIC *pAPI;
  252. pAPI = reinterpret_cast<const API_GENERIC*>(portMessage.GetData());
  253. ulAPINumber = pAPI->ulAPINumber;
  254. if ((ulAPINumber & API_GENERIC_SPECIAL_MASK) != 0)
  255. {
  256. switch (pAPI->ulAPINumber & API_GENERIC_SPECIAL_MASK)
  257. {
  258. case API_GENERIC_STOPSERVER:
  259. {
  260. // Here, our job is to tear down the API port management infrastructure.
  261. // First, verify that we received this from ourselves, and not some
  262. // other random process.
  263. if (HandleToULong(portMessage.GetUniqueProcess()) == GetCurrentProcessId())
  264. {
  265. status = STATUS_SUCCESS;
  266. // Cause our LPC port listening loop to exit. After this we're
  267. // no longer monitoring the port for new requests.
  268. _fStopListening = true;
  269. }
  270. else
  271. {
  272. status = STATUS_ACCESS_DENIED;
  273. }
  274. // Blow the message back to our caller. Even though this is
  275. // RejectRequest(), it'll cause the calling thread's NtRequestWaitReplyPort
  276. // to return.
  277. TSTATUS(pAPIDispatcher->RejectRequest(portMessage, status));
  278. // Wait a reasonable about of time for any outstanding requests to
  279. // come home and be dequeued.
  280. if( CAPIDispatchSync::WaitForZeroDispatches(_pAPIDispatchSync, DISPATCHSYNC_TIMEOUT)
  281. != WAIT_TIMEOUT )
  282. {
  283. int i, iLimit;
  284. // Now iterate all the CAPIDispatchers we know of and close them.
  285. // this will reject any further requests and not have clients
  286. // block in NtRequestWaitReplyPort.
  287. _dispatchers_lock.Acquire(); // protect vs. competing cleanup threads
  288. // (eg. Listen() --> HandleServerConnectionClosed() )
  289. iLimit = _dispatchers.GetCount();
  290. for (i = iLimit - 1; i >= 0; --i)
  291. {
  292. CAPIDispatcher *p;
  293. p = static_cast<CAPIDispatcher*>(_dispatchers.Get(i));
  294. if (p != NULL)
  295. {
  296. p->CloseConnection();
  297. p->Release();
  298. }
  299. _dispatchers.Remove(i);
  300. }
  301. _dispatchers_lock.Release();
  302. // Proceed w/ shutdown sequence
  303. CAPIDispatchSync::SignalPortShutdown(_pAPIDispatchSync);
  304. }
  305. else
  306. {
  307. _fStopListening = false;
  308. status = STATUS_TIMEOUT;
  309. }
  310. break;
  311. }
  312. default:
  313. status = STATUS_NOT_IMPLEMENTED;
  314. DISPLAYMSG("Invalid API number special code passed to CAPIConnection::HandleServerRequest");
  315. break;
  316. }
  317. }
  318. else if ((pAPI->ulAPINumber & API_GENERIC_OPTIONS_MASK) != 0)
  319. {
  320. switch (pAPI->ulAPINumber & API_GENERIC_OPTIONS_MASK)
  321. {
  322. case API_GENERIC_EXECUTE_IMMEDIATELY:
  323. status = pAPIDispatcher->ExecuteRequest(portMessage);
  324. break;
  325. default:
  326. status = STATUS_NOT_IMPLEMENTED;
  327. DISPLAYMSG("Invalid API number option passed to CAPIConnection::HandleServerRequest");
  328. break;
  329. }
  330. }
  331. else
  332. {
  333. status = pAPIDispatcher->QueueRequest(portMessage, _pAPIDispatchSync);
  334. }
  335. return(status);
  336. }
  337. // --------------------------------------------------------------------------
  338. // CAPIConnection::HandleServerConnectionRequest
  339. //
  340. // Arguments: portMessage = CPortMessage containing the message.
  341. //
  342. // Returns: NTSTATUS
  343. //
  344. // Purpose: Ask the interface whether this connection should be accepted.
  345. // If the connection is accepted then create the dispatcher that
  346. // handles requests from this particular client. Either way
  347. // inform the kernel that the request is either rejected or
  348. // accepted. If the connection is accepted then complete the
  349. // connection and give the dispatcher that will handle the
  350. // requests the port to reply to.
  351. //
  352. // History: 1999-11-07 vtan created
  353. // 2000-08-25 vtan moved from Neptune to Whistler
  354. // --------------------------------------------------------------------------
  355. NTSTATUS CAPIConnection::HandleServerConnectionRequest (const CPortMessage& portMessage)
  356. {
  357. NTSTATUS status;
  358. bool fConnectionAccepted;
  359. HANDLE hPort;
  360. CAPIDispatcher *pAPIDispatcher;
  361. // Should the connection be accepted?
  362. fConnectionAccepted = _pServerAPI->ConnectionAccepted(portMessage);
  363. if (fConnectionAccepted)
  364. {
  365. // If so then create the dispatcher to handle this client.
  366. pAPIDispatcher = _pServerAPI->CreateDispatcher(portMessage);
  367. if (pAPIDispatcher != NULL)
  368. {
  369. // First try to add the CAPIDispatcher object to the static array.
  370. // If this fails then reject the connection and release the memory.
  371. if (!NT_SUCCESS(_dispatchers.Add(pAPIDispatcher)))
  372. {
  373. pAPIDispatcher->Release();
  374. pAPIDispatcher = NULL;
  375. }
  376. }
  377. }
  378. else
  379. {
  380. pAPIDispatcher = NULL;
  381. }
  382. // Without a CAPIDispatcher object reject the connection.
  383. if (pAPIDispatcher == NULL)
  384. {
  385. fConnectionAccepted = false;
  386. }
  387. // Tell the kernel what the result is.
  388. status = NtAcceptConnectPort(&hPort,
  389. pAPIDispatcher,
  390. const_cast<PORT_MESSAGE*>(portMessage.GetPortMessage()),
  391. fConnectionAccepted,
  392. NULL,
  393. NULL);
  394. if (fConnectionAccepted)
  395. {
  396. // If we tried to accept the connection but NtAcceptConnectPort
  397. // couldn't allocate the port objects or something then we need
  398. // to clean up the _dispatchers array CAPIDispatcher entry added.
  399. if (NT_SUCCESS(status))
  400. {
  401. pAPIDispatcher->SetPort(hPort);
  402. // If the connection is accepted then complete the connection and set
  403. // the reply port to the CAPIDispatcher that will process requests.
  404. TSTATUS(NtCompleteConnectPort(hPort));
  405. }
  406. else
  407. {
  408. int iIndex;
  409. // Otherwise find the CAPIDispatcher that was added and remove it
  410. // from the array. There's no need to wake the client up because
  411. // NtAcceptConnectPort wakes it up in cases of failure.
  412. iIndex = FindIndexDispatcher(pAPIDispatcher);
  413. if (iIndex >= 0)
  414. {
  415. TSTATUS(_dispatchers.Remove(iIndex));
  416. }
  417. TSTATUS(pAPIDispatcher->CloseConnection());
  418. pAPIDispatcher->Release();
  419. }
  420. }
  421. return(status);
  422. }
  423. // --------------------------------------------------------------------------
  424. // CAPIConnection::HandleServerConnectionClosed
  425. //
  426. // Arguments: portMessage = CPortMessage containing the message.
  427. // pAPIDispatcher = CAPIDispatcher to handle request.
  428. //
  429. // Returns: NTSTATUS
  430. //
  431. // Purpose: The port associated with the CAPIDispatcher client was
  432. // closed. This is probably because the client process went away.
  433. // Let the dispatcher clean itself up.
  434. //
  435. // History: 1999-11-07 vtan created
  436. // 2000-08-25 vtan moved from Neptune to Whistler
  437. // --------------------------------------------------------------------------
  438. NTSTATUS CAPIConnection::HandleServerConnectionClosed (const CPortMessage& portMessage, CAPIDispatcher *pAPIDispatcher)
  439. {
  440. UNREFERENCED_PARAMETER(portMessage);
  441. NTSTATUS status;
  442. if (pAPIDispatcher != NULL)
  443. {
  444. int iIndex;
  445. status = pAPIDispatcher->CloseConnection();
  446. pAPIDispatcher->Release();
  447. _dispatchers_lock.Acquire(); // protect vs. competing cleanup threads (eg. API_GENERIC_STOPSERVER).
  448. iIndex = FindIndexDispatcher(pAPIDispatcher);
  449. if (iIndex >= 0)
  450. {
  451. _dispatchers.Remove(iIndex);
  452. }
  453. _dispatchers_lock.Release();
  454. }
  455. else
  456. {
  457. status = STATUS_SUCCESS;
  458. }
  459. return(status);
  460. }
  461. // --------------------------------------------------------------------------
  462. // CAPIConnection::FindIndexDispatcher
  463. //
  464. // Arguments: pAPIDispatcher = CAPIDispatcher to find.
  465. //
  466. // Returns: int
  467. //
  468. // Purpose: Finds the index in the dynamic counted object array of the
  469. // dispatcher.
  470. //
  471. // History: 2000-12-02 vtan created
  472. // --------------------------------------------------------------------------
  473. int CAPIConnection::FindIndexDispatcher (CAPIDispatcher *pAPIDispatcher)
  474. {
  475. int i, iLimit, iResult;
  476. iResult = -1;
  477. iLimit = _dispatchers.GetCount();
  478. for (i = 0; (iResult < 0) && (i < iLimit); ++i)
  479. {
  480. if (pAPIDispatcher == static_cast<CAPIDispatcher*>(_dispatchers.Get(i)))
  481. {
  482. iResult = i;
  483. }
  484. }
  485. return(iResult);
  486. }