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.

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