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.

1820 lines
47 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. handle.c
  5. Abstract:
  6. This file manages console and io handles.
  7. Author:
  8. Therese Stowell (thereses) 16-Nov-1990
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // array of pointers to consoles
  15. //
  16. PCONSOLE_INFORMATION InitialConsoleHandles[CONSOLE_INITIAL_CONSOLES];
  17. PCONSOLE_INFORMATION *ConsoleHandles;
  18. ULONG NumberOfConsoleHandles;
  19. CRITICAL_SECTION ConsoleHandleLock; // serializes console handle table access
  20. ULONG ConsoleId = 47; // unique number identifying console
  21. //
  22. // Macros to manipulate console handles
  23. //
  24. #define HandleFromIndex(i) (LongToHandle(((i & 0xFFFF) | (ConsoleId++ << 16))))
  25. #define IndexFromHandle(h) ((USHORT)((ULONG_PTR)h & 0xFFFF))
  26. #define ConsoleHandleTableLocked() (ConsoleHandleLock.OwningThread == NtCurrentTeb()->ClientId.UniqueThread)
  27. VOID
  28. AddProcessToList(
  29. IN OUT PCONSOLE_INFORMATION Console,
  30. IN OUT PCONSOLE_PROCESS_HANDLE ProcessHandleRecord,
  31. IN HANDLE ProcessHandle
  32. );
  33. VOID
  34. FreeInputHandle(
  35. IN PHANDLE_DATA HandleData
  36. );
  37. #if DBG
  38. VOID RefConsole(
  39. PCONSOLE_INFORMATION Console)
  40. {
  41. PCONSOLE_REF_NODE pNode;
  42. UserAssert(Console->RefCount < 0xFFFFFFFF);
  43. Console->RefCount += 1;
  44. pNode = ConsoleHeapAlloc(TMP_TAG, sizeof(CONSOLE_REF_NODE));
  45. if (pNode == NULL) {
  46. return;
  47. }
  48. RtlZeroMemory(pNode, sizeof(CONSOLE_REF_NODE));
  49. RtlWalkFrameChain(pNode->pStackTrace, ARRAY_SIZE(pNode->pStackTrace), 0);
  50. pNode->bRef = TRUE;
  51. pNode->pNext = Console->pRefNodes;
  52. Console->pRefNodes = pNode;
  53. }
  54. VOID DerefConsole(
  55. PCONSOLE_INFORMATION Console)
  56. {
  57. PCONSOLE_REF_NODE pNode;
  58. UserAssert(Console->RefCount > 0);
  59. Console->RefCount -= 1;
  60. pNode = ConsoleHeapAlloc(TMP_TAG, sizeof(CONSOLE_REF_NODE));
  61. if (pNode == NULL) {
  62. return;
  63. }
  64. RtlZeroMemory(pNode, sizeof(CONSOLE_REF_NODE));
  65. RtlWalkFrameChain(pNode->pStackTrace, ARRAY_SIZE(pNode->pStackTrace), 0);
  66. pNode->bRef = FALSE;
  67. pNode->pNext = Console->pRefNodes;
  68. Console->pRefNodes = pNode;
  69. }
  70. #endif
  71. NTSTATUS
  72. InitializeConsoleHandleTable( VOID )
  73. /*++
  74. Routine Description:
  75. This routine initializes the global console handle table.
  76. Arguments:
  77. none.
  78. Return Value:
  79. none.
  80. --*/
  81. {
  82. NTSTATUS Status;
  83. Status = RtlInitializeCriticalSectionAndSpinCount(&ConsoleHandleLock,
  84. 0x80000000);
  85. RtlZeroMemory(InitialConsoleHandles, sizeof(InitialConsoleHandles));
  86. ConsoleHandles = InitialConsoleHandles;
  87. NumberOfConsoleHandles = NELEM(InitialConsoleHandles);
  88. return Status;
  89. }
  90. #if DBG
  91. VOID
  92. LockConsoleHandleTable( VOID )
  93. /*++
  94. Routine Description:
  95. This routine locks the global console handle table. It also verifies
  96. that we're not in the USER critical section. This is necessary to
  97. prevent potential deadlocks. This routine is only defined in debug
  98. builds.
  99. Arguments:
  100. none.
  101. Return Value:
  102. none.
  103. --*/
  104. {
  105. RtlEnterCriticalSection(&ConsoleHandleLock);
  106. }
  107. VOID
  108. UnlockConsoleHandleTable( VOID )
  109. /*++
  110. Routine Description:
  111. This routine unlocks the global console handle table. This routine
  112. is only defined in debug builds.
  113. Arguments:
  114. none.
  115. Return Value:
  116. none.
  117. --*/
  118. {
  119. RtlLeaveCriticalSection(&ConsoleHandleLock);
  120. }
  121. VOID
  122. LockConsole(
  123. IN PCONSOLE_INFORMATION Console)
  124. /*++
  125. Routine Description:
  126. This routine locks the console. This routine is only defined
  127. in debug builds.
  128. Arguments:
  129. none.
  130. Return Value:
  131. none.
  132. --*/
  133. {
  134. ASSERT(!ConsoleHandleTableLocked());
  135. RtlEnterCriticalSection(&(Console->ConsoleLock));
  136. ASSERT(ConsoleLocked(Console));
  137. }
  138. #endif // DBG
  139. NTSTATUS
  140. DereferenceConsoleHandle(
  141. IN HANDLE ConsoleHandle,
  142. OUT PCONSOLE_INFORMATION *Console)
  143. /*++
  144. Routine Description:
  145. This routine converts a console handle value into a pointer to the
  146. console data structure.
  147. Arguments:
  148. ConsoleHandle - console handle to convert.
  149. Console - On output, contains pointer to the console data structure.
  150. Return Value:
  151. none.
  152. Note:
  153. The console handle table lock must be held when calling this routine.
  154. --*/
  155. {
  156. ULONG i;
  157. ASSERT(ConsoleHandleTableLocked());
  158. i = IndexFromHandle(ConsoleHandle);
  159. if ((i >= NumberOfConsoleHandles) ||
  160. ((*Console = ConsoleHandles[i]) == NULL) ||
  161. ((*Console)->ConsoleHandle != ConsoleHandle)) {
  162. *Console = NULL;
  163. return STATUS_INVALID_HANDLE;
  164. }
  165. if ((*Console)->Flags & CONSOLE_TERMINATING) {
  166. *Console = NULL;
  167. return STATUS_PROCESS_IS_TERMINATING;
  168. }
  169. return STATUS_SUCCESS;
  170. }
  171. NTSTATUS
  172. GrowConsoleHandleTable( VOID )
  173. /*++
  174. Routine Description:
  175. This routine grows the console handle table.
  176. Arguments:
  177. none
  178. Return Value:
  179. --*/
  180. {
  181. PCONSOLE_INFORMATION *NewTable;
  182. PCONSOLE_INFORMATION *OldTable;
  183. ULONG i;
  184. ULONG MaxConsoleHandles;
  185. ASSERT(ConsoleHandleTableLocked());
  186. MaxConsoleHandles = NumberOfConsoleHandles + CONSOLE_CONSOLE_HANDLE_INCREMENT;
  187. ASSERT(MaxConsoleHandles <= 0xFFFF);
  188. NewTable = ConsoleHeapAlloc(HANDLE_TAG, MaxConsoleHandles * sizeof(PCONSOLE_INFORMATION));
  189. if (NewTable == NULL) {
  190. return STATUS_NO_MEMORY;
  191. }
  192. RtlCopyMemory(NewTable, ConsoleHandles,
  193. NumberOfConsoleHandles * sizeof(PCONSOLE_INFORMATION));
  194. for (i=NumberOfConsoleHandles;i<MaxConsoleHandles;i++) {
  195. NewTable[i] = NULL;
  196. }
  197. OldTable = ConsoleHandles;
  198. ConsoleHandles = NewTable;
  199. NumberOfConsoleHandles = MaxConsoleHandles;
  200. if (OldTable != InitialConsoleHandles) {
  201. ConsoleHeapFree(OldTable);
  202. }
  203. return STATUS_SUCCESS;
  204. }
  205. NTSTATUS
  206. AllocateConsoleHandle(
  207. OUT PHANDLE Handle)
  208. /*++
  209. Routine Description:
  210. This routine allocates a console handle from the global table.
  211. Arguments:
  212. Handle - Pointer to store handle in.
  213. Return Value:
  214. Note:
  215. The console handle table lock must be held when calling this routine.
  216. --*/
  217. {
  218. ULONG i;
  219. NTSTATUS Status;
  220. ASSERT(ConsoleHandleTableLocked());
  221. //
  222. // have to start allocation at 1 because 0 indicates no console handle
  223. // in ConDllInitialize.
  224. //
  225. for (i=1;i<NumberOfConsoleHandles;i++) {
  226. if (ConsoleHandles[i] == NULL) {
  227. ConsoleHandles[i] = (PCONSOLE_INFORMATION) CONSOLE_HANDLE_ALLOCATED;
  228. *Handle = HandleFromIndex(i);
  229. return STATUS_SUCCESS;
  230. }
  231. }
  232. //
  233. // grow console handle table
  234. //
  235. Status = GrowConsoleHandleTable();
  236. if (!NT_SUCCESS(Status))
  237. return Status;
  238. for ( ;i<NumberOfConsoleHandles;i++) {
  239. if (ConsoleHandles[i] == NULL) {
  240. ConsoleHandles[i] = (PCONSOLE_INFORMATION) CONSOLE_HANDLE_ALLOCATED;
  241. *Handle = HandleFromIndex(i);
  242. return STATUS_SUCCESS;
  243. }
  244. }
  245. ASSERT (FALSE);
  246. return STATUS_UNSUCCESSFUL;
  247. }
  248. NTSTATUS
  249. FreeConsoleHandle(
  250. IN HANDLE Handle)
  251. /*++
  252. Routine Description:
  253. This routine frees a console handle from the global table.
  254. Arguments:
  255. Handle - Handle to free.
  256. Return Value:
  257. Note:
  258. The console handle table lock must be held when calling this routine.
  259. --*/
  260. {
  261. ULONG i;
  262. ASSERT(ConsoleHandleTableLocked());
  263. ASSERT (Handle != NULL);
  264. i = IndexFromHandle(Handle);
  265. if ((i >= NumberOfConsoleHandles) || (ConsoleHandles[i] == NULL)) {
  266. ASSERT (FALSE);
  267. } else {
  268. ConsoleHandles[i] = NULL;
  269. }
  270. return STATUS_SUCCESS;
  271. }
  272. NTSTATUS
  273. ValidateConsole(
  274. IN PCONSOLE_INFORMATION Console)
  275. /*++
  276. Routine Description:
  277. This routine ensures that the given console pointer is valid.
  278. Arguments:
  279. Console - Console pointer to validate.
  280. --*/
  281. {
  282. ULONG i;
  283. if (Console != NULL) {
  284. for (i = 0; i < NumberOfConsoleHandles; i++) {
  285. if (ConsoleHandles[i] == Console) {
  286. return STATUS_SUCCESS;
  287. }
  288. }
  289. }
  290. return STATUS_UNSUCCESSFUL;
  291. }
  292. NTSTATUS
  293. InitializeIoHandleTable(
  294. IN OUT PCONSOLE_INFORMATION Console,
  295. OUT PCONSOLE_PER_PROCESS_DATA ProcessData,
  296. OUT PHANDLE StdIn,
  297. OUT PHANDLE StdOut,
  298. OUT PHANDLE StdErr)
  299. /*++
  300. Routine Description:
  301. This routine initializes a process's handle table for the first
  302. time (there is no parent process). It also sets up stdin, stdout,
  303. and stderr.
  304. Arguments:
  305. Console - Pointer to console information structure.
  306. ProcessData - Pointer to per process data structure.
  307. Stdin - Pointer in which to return StdIn handle.
  308. StdOut - Pointer in which to return StdOut handle.
  309. StdErr - Pointer in which to return StdErr handle.
  310. Return Value:
  311. --*/
  312. {
  313. ULONG i;
  314. HANDLE Handle;
  315. NTSTATUS Status;
  316. PHANDLE_DATA HandleData, InputHandleData;
  317. //
  318. // HandleTablePtr gets set up by ConsoleAddProcessRoutine.
  319. // it will be != to HandleTable if the new process was created
  320. // using "start xxx" at the command line and cmd.exe has >
  321. // CONSOLE_INITIAL_IO_HANDLES.
  322. //
  323. if (ProcessData->HandleTablePtr != ProcessData->HandleTable) {
  324. UserAssert(ProcessData->HandleTableSize != CONSOLE_INITIAL_IO_HANDLES);
  325. ConsoleHeapFree(ProcessData->HandleTablePtr);
  326. ProcessData->HandleTablePtr = ProcessData->HandleTable;
  327. }
  328. for (i = 0;i < CONSOLE_INITIAL_IO_HANDLES; i++) {
  329. ProcessData->HandleTable[i].HandleType = CONSOLE_FREE_HANDLE;
  330. }
  331. ProcessData->HandleTableSize = CONSOLE_INITIAL_IO_HANDLES;
  332. //
  333. // Set up stdin, stdout, and stderr.
  334. //
  335. // stdin
  336. //
  337. Status = AllocateIoHandle(ProcessData, CONSOLE_INPUT_HANDLE, &Handle);
  338. if (!NT_SUCCESS(Status)) {
  339. return Status;
  340. }
  341. Status = DereferenceIoHandleNoCheck(ProcessData, Handle, &InputHandleData);
  342. UserAssert(NT_SUCCESS(Status));
  343. if (!NT_SUCCESS(Status)) {
  344. return Status;
  345. }
  346. if (!InitializeInputHandle(InputHandleData, &Console->InputBuffer)) {
  347. return STATUS_NO_MEMORY;
  348. }
  349. InputHandleData->HandleType |= CONSOLE_INHERITABLE;
  350. Status = ConsoleAddShare(GENERIC_READ | GENERIC_WRITE,
  351. FILE_SHARE_READ | FILE_SHARE_WRITE,
  352. &Console->InputBuffer.ShareAccess,
  353. InputHandleData);
  354. UserAssert(NT_SUCCESS(Status));
  355. if (!NT_SUCCESS(Status)) {
  356. goto Cleanup;
  357. }
  358. *StdIn = INDEX_TO_HANDLE(Handle);
  359. //
  360. // stdout
  361. //
  362. Status = AllocateIoHandle(ProcessData, CONSOLE_OUTPUT_HANDLE, &Handle);
  363. if (!NT_SUCCESS(Status)) {
  364. goto Cleanup;
  365. }
  366. Status = DereferenceIoHandleNoCheck(ProcessData, Handle, &HandleData);
  367. UserAssert(NT_SUCCESS(Status));
  368. if (!NT_SUCCESS(Status)) {
  369. goto Cleanup;
  370. }
  371. InitializeOutputHandle(HandleData,Console->CurrentScreenBuffer);
  372. HandleData->HandleType |= CONSOLE_INHERITABLE;
  373. Status = ConsoleAddShare(GENERIC_READ | GENERIC_WRITE,
  374. FILE_SHARE_READ | FILE_SHARE_WRITE,
  375. &Console->ScreenBuffers->ShareAccess,
  376. HandleData);
  377. UserAssert(NT_SUCCESS(Status));
  378. if (!NT_SUCCESS(Status)) {
  379. goto Cleanup;
  380. }
  381. *StdOut = INDEX_TO_HANDLE(Handle);
  382. //
  383. // stderr
  384. //
  385. Status = AllocateIoHandle(ProcessData, CONSOLE_OUTPUT_HANDLE, &Handle);
  386. if (!NT_SUCCESS(Status)) {
  387. goto Cleanup;
  388. }
  389. Status = DereferenceIoHandleNoCheck(ProcessData, Handle, &HandleData);
  390. UserAssert(NT_SUCCESS(Status));
  391. if (!NT_SUCCESS(Status)) {
  392. goto Cleanup;
  393. }
  394. InitializeOutputHandle(HandleData,Console->CurrentScreenBuffer);
  395. HandleData->HandleType |= CONSOLE_INHERITABLE;
  396. Status = ConsoleAddShare(GENERIC_READ | GENERIC_WRITE,
  397. FILE_SHARE_READ | FILE_SHARE_WRITE,
  398. &Console->ScreenBuffers->ShareAccess,
  399. HandleData);
  400. UserAssert(NT_SUCCESS(Status));
  401. if (!NT_SUCCESS(Status)) {
  402. goto Cleanup;
  403. }
  404. *StdErr = INDEX_TO_HANDLE(Handle);
  405. return STATUS_SUCCESS;
  406. Cleanup:
  407. FreeInputHandle(InputHandleData);
  408. return Status;
  409. }
  410. NTSTATUS
  411. InheritIoHandleTable(
  412. IN PCONSOLE_INFORMATION Console,
  413. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  414. IN PCONSOLE_PER_PROCESS_DATA ParentProcessData)
  415. /*++
  416. Routine Description:
  417. This routine creates a process's handle table from the parent
  418. process's handle table. ProcessData contains the process data
  419. copied directly from the parent to the child process by CSR.
  420. This routine allocates a new handle table, if necessary, then
  421. invalidates non-inherited handles and increments the sharing
  422. and reference counts for inherited handles.
  423. Arguments:
  424. ProcessData - Pointer to per process data structure.
  425. Return Value:
  426. Note:
  427. The console lock must be held when calling this routine.
  428. --*/
  429. {
  430. ULONG i;
  431. NTSTATUS Status;
  432. //
  433. // Copy handles from parent process. If the table size
  434. // is CONSOLE_INITIAL_IO_HANDLES, CSR has done the copy
  435. // for us.
  436. //
  437. UNREFERENCED_PARAMETER(Console);
  438. ASSERT(ParentProcessData->HandleTableSize != 0);
  439. ASSERT(ParentProcessData->HandleTableSize <= 0x0000FFFF);
  440. if (ParentProcessData->HandleTableSize != CONSOLE_INITIAL_IO_HANDLES) {
  441. ProcessData->HandleTableSize = ParentProcessData->HandleTableSize;
  442. ProcessData->HandleTablePtr = ConsoleHeapAlloc(HANDLE_TAG, ProcessData->HandleTableSize * sizeof(HANDLE_DATA));
  443. if (ProcessData->HandleTablePtr == NULL) {
  444. ProcessData->HandleTablePtr = ProcessData->HandleTable;
  445. ProcessData->HandleTableSize = CONSOLE_INITIAL_IO_HANDLES;
  446. return STATUS_NO_MEMORY;
  447. }
  448. RtlCopyMemory(ProcessData->HandleTablePtr,
  449. ParentProcessData->HandleTablePtr,
  450. ProcessData->HandleTableSize * sizeof(HANDLE_DATA));
  451. }
  452. ASSERT(!(Console->Flags & CONSOLE_SHUTTING_DOWN));
  453. //
  454. // Allocate any memory associated with each handle.
  455. //
  456. Status = STATUS_SUCCESS;
  457. for (i = 0;i < ProcessData->HandleTableSize; i++) {
  458. if (NT_SUCCESS(Status) && ProcessData->HandleTablePtr[i].HandleType & CONSOLE_INHERITABLE) {
  459. if (ProcessData->HandleTablePtr[i].HandleType & CONSOLE_INPUT_HANDLE) {
  460. ProcessData->HandleTablePtr[i].InputReadData = ConsoleHeapAlloc(HANDLE_TAG, sizeof(INPUT_READ_HANDLE_DATA));
  461. if (!ProcessData->HandleTablePtr[i].InputReadData) {
  462. ProcessData->HandleTablePtr[i].HandleType = CONSOLE_FREE_HANDLE;
  463. Status = STATUS_NO_MEMORY;
  464. continue;
  465. }
  466. ProcessData->HandleTablePtr[i].InputReadData->InputHandleFlags = 0;
  467. ProcessData->HandleTablePtr[i].InputReadData->ReadCount = 0;
  468. Status = RtlInitializeCriticalSection(&ProcessData->HandleTablePtr[i].InputReadData->ReadCountLock);
  469. if (!NT_SUCCESS(Status)) {
  470. ConsoleHeapFree(ProcessData->HandleTablePtr[i].InputReadData);
  471. ProcessData->HandleTablePtr[i].InputReadData = NULL;
  472. ProcessData->HandleTablePtr[i].HandleType = CONSOLE_FREE_HANDLE;
  473. continue;
  474. }
  475. }
  476. } else {
  477. ProcessData->HandleTablePtr[i].HandleType = CONSOLE_FREE_HANDLE;
  478. }
  479. }
  480. //
  481. // If something failed, we need to free any input data we allocated and
  482. // free the handle table.
  483. //
  484. if (!NT_SUCCESS(Status)) {
  485. for (i=0;i<ProcessData->HandleTableSize;i++) {
  486. if (ProcessData->HandleTablePtr[i].HandleType & CONSOLE_INPUT_HANDLE) {
  487. FreeInputHandle(&ProcessData->HandleTablePtr[i]);
  488. }
  489. }
  490. if (ProcessData->HandleTableSize != CONSOLE_INITIAL_IO_HANDLES) {
  491. ConsoleHeapFree(ProcessData->HandleTablePtr);
  492. ProcessData->HandleTablePtr = ProcessData->HandleTable;
  493. ProcessData->HandleTableSize = CONSOLE_INITIAL_IO_HANDLES;
  494. }
  495. return Status;
  496. }
  497. //
  498. // All the memory allocations succeeded. Now go through and increment the
  499. // object reference counts and dup the shares.
  500. //
  501. for (i=0;i<ProcessData->HandleTableSize;i++) {
  502. if (ProcessData->HandleTablePtr[i].HandleType != CONSOLE_FREE_HANDLE) {
  503. PCONSOLE_SHARE_ACCESS ShareAccess;
  504. if (ProcessData->HandleTablePtr[i].HandleType & CONSOLE_INPUT_HANDLE) {
  505. ProcessData->HandleTablePtr[i].Buffer.InputBuffer->RefCount++;
  506. ShareAccess = &ProcessData->HandleTablePtr[i].Buffer.InputBuffer->ShareAccess;
  507. } else {
  508. ProcessData->HandleTablePtr[i].Buffer.ScreenBuffer->RefCount++;
  509. ShareAccess = &ProcessData->HandleTablePtr[i].Buffer.ScreenBuffer->ShareAccess;
  510. }
  511. Status = ConsoleDupShare(ProcessData->HandleTablePtr[i].Access,
  512. ProcessData->HandleTablePtr[i].ShareAccess,
  513. ShareAccess,
  514. &ProcessData->HandleTablePtr[i]
  515. );
  516. ASSERT (NT_SUCCESS(Status));
  517. }
  518. }
  519. return STATUS_SUCCESS;
  520. }
  521. NTSTATUS
  522. ConsoleAddProcessRoutine(
  523. IN PCSR_PROCESS ParentProcess,
  524. IN PCSR_PROCESS Process)
  525. {
  526. PCONSOLE_PER_PROCESS_DATA ProcessData, ParentProcessData;
  527. PCONSOLE_INFORMATION Console;
  528. PCONSOLE_PROCESS_HANDLE ProcessHandleRecord;
  529. NTSTATUS Status = STATUS_SUCCESS;
  530. ULONG i;
  531. ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process);
  532. ProcessData->HandleTablePtr = ProcessData->HandleTable;
  533. ProcessData->HandleTableSize = CONSOLE_INITIAL_IO_HANDLES;
  534. CONSOLE_SETCONSOLEAPPFROMPROCESSDATA(ProcessData,FALSE);
  535. if (ParentProcess) {
  536. ProcessData->RootProcess = FALSE;
  537. ProcessData->ParentProcessId = HandleToUlong(ParentProcess->ClientId.UniqueProcess);
  538. ParentProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(ParentProcess);
  539. //
  540. // If both the parent and new processes are console apps,
  541. // inherit handles from the parent process.
  542. //
  543. if (ParentProcessData->ConsoleHandle != NULL &&
  544. (Process->Flags & CSR_PROCESS_CONSOLEAPP)) {
  545. if (!(NT_SUCCESS(RevalidateConsole(ParentProcessData->ConsoleHandle,
  546. &Console)))) {
  547. ProcessData->ConsoleHandle = NULL;
  548. return STATUS_PROCESS_IS_TERMINATING;
  549. }
  550. //
  551. // Don't add the process if the console is being shutdown.
  552. //
  553. if (Console->Flags & CONSOLE_SHUTTING_DOWN) {
  554. Status = STATUS_PROCESS_IS_TERMINATING;
  555. } else {
  556. ProcessHandleRecord = ConsoleHeapAlloc(HANDLE_TAG, sizeof(CONSOLE_PROCESS_HANDLE));
  557. if (ProcessHandleRecord == NULL) {
  558. Status = STATUS_NO_MEMORY;
  559. } else {
  560. //
  561. // duplicate parent's handle table
  562. //
  563. Status = InheritIoHandleTable(Console, ProcessData, ParentProcessData);
  564. if (NT_SUCCESS(Status)) {
  565. ProcessHandleRecord->Process = Process;
  566. ProcessHandleRecord->CtrlRoutine = NULL;
  567. ProcessHandleRecord->PropRoutine = NULL;
  568. AddProcessToList(Console,ProcessHandleRecord,Process->ProcessHandle);
  569. //
  570. // increment console reference count
  571. //
  572. RefConsole(Console);
  573. } else {
  574. ConsoleHeapFree(ProcessHandleRecord);
  575. }
  576. }
  577. }
  578. if (!NT_SUCCESS(Status)) {
  579. ProcessData->ConsoleHandle = NULL;
  580. for (i=0;i<CONSOLE_INITIAL_IO_HANDLES;i++) {
  581. ProcessData->HandleTable[i].HandleType = CONSOLE_FREE_HANDLE;
  582. }
  583. }
  584. UnlockConsole(Console);
  585. } else {
  586. ProcessData->ConsoleHandle = NULL;
  587. }
  588. } else {
  589. ProcessData->ConsoleHandle = NULL;
  590. }
  591. return Status;
  592. }
  593. NTSTATUS
  594. MapEventHandles(
  595. IN HANDLE ClientProcessHandle,
  596. IN PCONSOLE_INFORMATION Console,
  597. IN OUT PCONSOLE_INFO ConsoleInfo)
  598. {
  599. if (!MapHandle(ClientProcessHandle,
  600. Console->InitEvents[INITIALIZATION_SUCCEEDED],
  601. &ConsoleInfo->InitEvents[INITIALIZATION_SUCCEEDED]
  602. )) {
  603. return STATUS_NO_MEMORY;
  604. }
  605. if (!MapHandle(ClientProcessHandle,
  606. Console->InitEvents[INITIALIZATION_FAILED],
  607. &ConsoleInfo->InitEvents[INITIALIZATION_FAILED]
  608. )) {
  609. return STATUS_NO_MEMORY;
  610. }
  611. if (!MapHandle(ClientProcessHandle,
  612. Console->InputBuffer.InputWaitEvent,
  613. &ConsoleInfo->InputWaitHandle
  614. )) {
  615. return STATUS_NO_MEMORY;
  616. }
  617. return STATUS_SUCCESS;
  618. }
  619. NTSTATUS
  620. AllocateConsole(
  621. IN HANDLE ConsoleHandle,
  622. IN LPWSTR Title,
  623. IN USHORT TitleLength,
  624. IN HANDLE ClientProcessHandle,
  625. OUT PHANDLE StdIn,
  626. OUT PHANDLE StdOut,
  627. OUT PHANDLE StdErr,
  628. OUT PCONSOLE_PER_PROCESS_DATA ProcessData,
  629. IN OUT PCONSOLE_INFO ConsoleInfo,
  630. IN BOOLEAN WindowVisible,
  631. IN DWORD dwConsoleThreadId)
  632. /*++
  633. Routine Description:
  634. This routine allocates and initialized a console and its associated
  635. data - input buffer and screen buffer.
  636. Arguments:
  637. ConsoleHandle - Handle of console to allocate.
  638. dwWindowSize - Initial size of screen buffer window, in rows and columns.
  639. nFont - Initial number of font text is displayed in.
  640. dwScreenBufferSize - Initial size of screen buffer, in rows and columns.
  641. nInputBufferSize - Initial size of input buffer, in events.
  642. dwWindowFlags -
  643. StdIn - On return, contains handle to stdin.
  644. StdOut - On return, contains handle to stdout.
  645. StdErr - On return, contains handle to stderr.
  646. ProcessData - On return, contains the initialized per-process data.
  647. Return Value:
  648. Note:
  649. The console handle table lock must be held when calling this routine.
  650. --*/
  651. {
  652. PCONSOLE_INFORMATION Console;
  653. NTSTATUS Status;
  654. BOOL Success;
  655. //
  656. // allocate console data
  657. //
  658. Console = ConsoleHeapAlloc(CONSOLE_TAG | HEAP_ZERO_MEMORY,
  659. sizeof(CONSOLE_INFORMATION));
  660. if (Console == NULL) {
  661. return STATUS_NO_MEMORY;
  662. }
  663. ConsoleHandles[IndexFromHandle(ConsoleHandle)] = Console;
  664. Console->Flags = WindowVisible ? 0 : CONSOLE_NO_WINDOW;
  665. Console->hIcon = ConsoleInfo->hIcon;
  666. Console->hSmIcon = ConsoleInfo->hSmIcon;
  667. Console->iIconId = ConsoleInfo->iIconId;
  668. Console->dwHotKey = ConsoleInfo->dwHotKey;
  669. #if !defined(FE_SB)
  670. Console->CP = OEMCP;
  671. Console->OutputCP = ConsoleOutputCP;
  672. #endif
  673. Console->ReserveKeys = CONSOLE_NOSHORTCUTKEY;
  674. Console->ConsoleHandle = ConsoleHandle;
  675. Console->bIconInit = TRUE;
  676. Console->VerticalClientToWindow = VerticalClientToWindow;
  677. Console->HorizontalClientToWindow = HorizontalClientToWindow;
  678. #if defined(FE_SB)
  679. SetConsoleCPInfo(Console,TRUE);
  680. SetConsoleCPInfo(Console,FALSE);
  681. #endif
  682. //
  683. // must wait for window to be destroyed or client impersonation won't
  684. // work.
  685. //
  686. Status = NtDuplicateObject(NtCurrentProcess(),
  687. CONSOLE_CLIENTTHREADHANDLE(CSR_SERVER_QUERYCLIENTTHREAD()),
  688. NtCurrentProcess(),
  689. &Console->ClientThreadHandle,
  690. 0,
  691. FALSE,
  692. DUPLICATE_SAME_ACCESS
  693. );
  694. if (!NT_SUCCESS(Status)) {
  695. goto ErrorExit5;
  696. }
  697. #if DBG
  698. //
  699. // Make sure the handle isn't protected so we can close it later
  700. //
  701. UnProtectHandle(Console->ClientThreadHandle);
  702. #endif // DBG
  703. InitializeListHead(&Console->OutputQueue);
  704. InitializeListHead(&Console->ProcessHandleList);
  705. InitializeListHead(&Console->ExeAliasList);
  706. InitializeListHead(&Console->MessageQueue);
  707. Status = NtCreateEvent(&Console->InitEvents[INITIALIZATION_SUCCEEDED],
  708. EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
  709. if (!NT_SUCCESS(Status)) {
  710. goto ErrorExit4a;
  711. }
  712. Status = NtCreateEvent(&Console->InitEvents[INITIALIZATION_FAILED],
  713. EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
  714. if (!NT_SUCCESS(Status)) {
  715. goto ErrorExit4;
  716. }
  717. Status = RtlInitializeCriticalSection(&Console->ConsoleLock);
  718. if (!NT_SUCCESS(Status)) {
  719. goto ErrorExit3a;
  720. }
  721. InitializeConsoleCommandData(Console);
  722. //
  723. // initialize input buffer
  724. //
  725. #if defined(FE_SB)
  726. Status = CreateInputBuffer(ConsoleInfo->nInputBufferSize,
  727. &Console->InputBuffer,
  728. Console);
  729. #else
  730. Status = CreateInputBuffer(ConsoleInfo->nInputBufferSize,
  731. &Console->InputBuffer);
  732. #endif
  733. if (!NT_SUCCESS(Status)) {
  734. goto ErrorExit3;
  735. }
  736. Console->Title = ConsoleHeapAlloc(TITLE_TAG, TitleLength+sizeof(WCHAR));
  737. if (Console->Title == NULL) {
  738. Status = STATUS_NO_MEMORY;
  739. goto ErrorExit2;
  740. }
  741. RtlCopyMemory(Console->Title,Title,TitleLength);
  742. Console->Title[TitleLength/sizeof(WCHAR)] = (WCHAR)0; // NULL terminate
  743. Console->TitleLength = TitleLength;
  744. Console->OriginalTitle = TranslateConsoleTitle(Console->Title, &Console->OriginalTitleLength, TRUE, FALSE);
  745. if (Console->OriginalTitle == NULL) {
  746. Status = STATUS_NO_MEMORY;
  747. goto ErrorExit1;
  748. }
  749. Status = NtCreateEvent(&Console->TerminationEvent,
  750. EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
  751. if (!NT_SUCCESS(Status)) {
  752. goto ErrorExit1a;
  753. }
  754. //
  755. // initialize screen buffer. we don't call OpenConsole to do this
  756. // because we need to specify the font, windowsize, etc.
  757. //
  758. Status = DoCreateScreenBuffer(Console,
  759. ConsoleInfo);
  760. if (!NT_SUCCESS(Status)){
  761. goto ErrorExit1b;
  762. }
  763. Console->CurrentScreenBuffer = Console->ScreenBuffers;
  764. #if defined(FE_SB)
  765. #if defined(FE_IME)
  766. SetUndetermineAttribute(Console);
  767. #endif
  768. Status = CreateEUDC(Console);
  769. if (!NT_SUCCESS(Status)) {
  770. goto ErrorExit1c;
  771. }
  772. #endif
  773. Status = InitializeIoHandleTable(Console,
  774. ProcessData,
  775. StdIn,
  776. StdOut,
  777. StdErr);
  778. if (!NT_SUCCESS(Status)) {
  779. goto ErrorExit0;
  780. }
  781. //
  782. // map event handles
  783. //
  784. Status = MapEventHandles(ClientProcessHandle, Console, ConsoleInfo);
  785. if (!NT_SUCCESS(Status)) {
  786. goto ErrorExit0;
  787. }
  788. Success = PostThreadMessage(dwConsoleThreadId,
  789. CM_CREATE_CONSOLE_WINDOW,
  790. (WPARAM)ConsoleHandle,
  791. (LPARAM)ClientProcessHandle);
  792. if (!Success) {
  793. RIPMSG1(RIP_WARNING, "PostThreadMessage failed 0x%x", GetLastError());
  794. Status = STATUS_UNSUCCESSFUL;
  795. goto ErrorExit0;
  796. }
  797. return STATUS_SUCCESS;
  798. ErrorExit0: Console->ScreenBuffers->RefCount = 0;
  799. #if defined(FE_SB)
  800. if (Console->EudcInformation != NULL) {
  801. ConsoleHeapFree(Console->EudcInformation);
  802. }
  803. ErrorExit1c:
  804. #endif
  805. FreeScreenBuffer(Console->ScreenBuffers);
  806. ErrorExit1b: NtClose(Console->TerminationEvent);
  807. ErrorExit1a: ConsoleHeapFree(Console->OriginalTitle);
  808. ErrorExit1: ConsoleHeapFree(Console->Title);
  809. ErrorExit2: Console->InputBuffer.RefCount = 0;
  810. FreeInputBuffer(&Console->InputBuffer);
  811. ErrorExit3: RtlDeleteCriticalSection(&Console->ConsoleLock);
  812. ErrorExit3a: NtClose(Console->InitEvents[INITIALIZATION_FAILED]);
  813. ErrorExit4: NtClose(Console->InitEvents[INITIALIZATION_SUCCEEDED]);
  814. ErrorExit4a: NtClose(Console->ClientThreadHandle);
  815. ErrorExit5: ConsoleHeapFree(Console);
  816. return Status;
  817. }
  818. VOID
  819. DestroyConsole(
  820. IN PCONSOLE_INFORMATION Console)
  821. /*++
  822. Routine Description:
  823. This routine frees a console structure if it's not being referenced.
  824. Arguments:
  825. Console - Console to free.
  826. Return Value:
  827. --*/
  828. {
  829. HANDLE ConsoleHandle = Console->ConsoleHandle;
  830. //
  831. // Make sure we have the console locked and it really is going away.
  832. //
  833. ASSERT(ConsoleLocked(Console));
  834. ASSERT(Console->hWnd == NULL);
  835. //
  836. // Mark this console as being destroyed.
  837. //
  838. Console->Flags |= CONSOLE_IN_DESTRUCTION;
  839. //
  840. // Unlock this console.
  841. //
  842. RtlLeaveCriticalSection(&Console->ConsoleLock);
  843. //
  844. // If the console still exists and no one is waiting on it, free it.
  845. //
  846. LockConsoleHandleTable();
  847. if (Console == ConsoleHandles[IndexFromHandle(ConsoleHandle)] &&
  848. Console->ConsoleHandle == ConsoleHandle &&
  849. Console->ConsoleLock.OwningThread == NULL &&
  850. Console->WaitCount == 0) {
  851. FreeConsoleHandle(ConsoleHandle);
  852. RtlDeleteCriticalSection(&Console->ConsoleLock);
  853. #if DBG
  854. if (Console->pRefNodes != NULL) {
  855. ConsoleHeapFree(Console->pRefNodes);
  856. }
  857. #endif
  858. ConsoleHeapFree(Console);
  859. }
  860. UnlockConsoleHandleTable();
  861. }
  862. VOID
  863. FreeCon(
  864. IN PCONSOLE_INFORMATION Console)
  865. /*++
  866. Routine Description:
  867. This routine frees a console and its associated
  868. data - input buffer and screen buffer.
  869. Arguments:
  870. ConsoleHandle - Handle of console to free.
  871. Return Value:
  872. Note:
  873. The console handle table lock must be held when calling this routine.
  874. --*/
  875. {
  876. HWND hWnd;
  877. USERTHREAD_USEDESKTOPINFO utudi;
  878. NTSTATUS Status;
  879. Console->Flags |= CONSOLE_TERMINATING;
  880. NtSetEvent(Console->TerminationEvent,NULL);
  881. hWnd = Console->hWnd;
  882. //
  883. // Wait 10 seconds or until the input thread replies
  884. // to synchronize the window destruction with
  885. // the termination of the thread
  886. //
  887. if (hWnd != NULL) {
  888. UnlockConsole(Console);
  889. utudi.hThread = NULL;
  890. utudi.drdRestore.pdeskRestore = NULL;
  891. Status = NtUserSetInformationThread(NtCurrentThread(),
  892. UserThreadUseActiveDesktop,
  893. &utudi, sizeof(utudi));
  894. ASSERT(NT_SUCCESS(Status));
  895. if (NT_SUCCESS(Status)) {
  896. SendMessageTimeout(hWnd, CM_DESTROY_WINDOW, 0, 0, SMTO_BLOCK, 10000, NULL);
  897. Status = NtUserSetInformationThread(NtCurrentThread(),
  898. UserThreadUseDesktop,
  899. &utudi,
  900. sizeof(utudi));
  901. ASSERT(NT_SUCCESS(Status));
  902. }
  903. } else {
  904. AbortCreateConsole(Console);
  905. }
  906. }
  907. VOID
  908. InsertScreenBuffer(
  909. IN PCONSOLE_INFORMATION Console,
  910. IN PSCREEN_INFORMATION ScreenInfo)
  911. /*++
  912. Routine Description:
  913. This routine inserts the screen buffer pointer into the console's
  914. list of screen buffers.
  915. Arguments:
  916. Console - Pointer to console information structure.
  917. ScreenInfo - Pointer to screen information structure.
  918. Return Value:
  919. Note:
  920. The console lock must be held when calling this routine.
  921. --*/
  922. {
  923. ScreenInfo->Next = Console->ScreenBuffers;
  924. Console->ScreenBuffers = ScreenInfo;
  925. }
  926. VOID
  927. RemoveScreenBuffer(
  928. IN PCONSOLE_INFORMATION Console,
  929. IN PSCREEN_INFORMATION ScreenInfo)
  930. /*++
  931. Routine Description:
  932. This routine removes the screen buffer pointer from the console's
  933. list of screen buffers.
  934. Arguments:
  935. Console - Pointer to console information structure.
  936. ScreenInfo - Pointer to screen information structure.
  937. Return Value:
  938. Note:
  939. The console lock must be held when calling this routine.
  940. --*/
  941. {
  942. PSCREEN_INFORMATION Prev,Cur;
  943. if (ScreenInfo == Console->ScreenBuffers) {
  944. Console->ScreenBuffers = ScreenInfo->Next;
  945. return;
  946. }
  947. Prev = Cur = Console->ScreenBuffers;
  948. while (Cur != NULL) {
  949. if (ScreenInfo == Cur)
  950. break;
  951. Prev = Cur;
  952. Cur = Cur->Next;
  953. }
  954. ASSERT (Cur != NULL);
  955. if (Cur != NULL) {
  956. Prev->Next = Cur->Next;
  957. }
  958. }
  959. NTSTATUS
  960. GrowIoHandleTable(
  961. IN PCONSOLE_PER_PROCESS_DATA ProcessData)
  962. /*++
  963. Routine Description:
  964. This routine grows the per-process io handle table.
  965. Arguments:
  966. ProcessData - Pointer to the per-process data structure.
  967. Return Value:
  968. --*/
  969. {
  970. PHANDLE_DATA NewTable;
  971. ULONG i;
  972. ULONG MaxFileHandles;
  973. MaxFileHandles = ProcessData->HandleTableSize + CONSOLE_IO_HANDLE_INCREMENT;
  974. NewTable = ConsoleHeapAlloc(HANDLE_TAG, MaxFileHandles * sizeof(HANDLE_DATA));
  975. if (NewTable == NULL) {
  976. return STATUS_NO_MEMORY;
  977. }
  978. RtlCopyMemory(NewTable, ProcessData->HandleTablePtr,
  979. ProcessData->HandleTableSize * sizeof(HANDLE_DATA));
  980. for (i=ProcessData->HandleTableSize;i<MaxFileHandles;i++) {
  981. NewTable[i].HandleType = CONSOLE_FREE_HANDLE;
  982. }
  983. if (ProcessData->HandleTableSize != CONSOLE_INITIAL_IO_HANDLES) {
  984. ConsoleHeapFree(ProcessData->HandleTablePtr);
  985. }
  986. ProcessData->HandleTablePtr = NewTable;
  987. ProcessData->HandleTableSize = MaxFileHandles;
  988. ASSERT(ProcessData->HandleTableSize != 0);
  989. ASSERT(ProcessData->HandleTableSize <= 0x0000FFFF);
  990. return STATUS_SUCCESS;
  991. }
  992. VOID
  993. FreeProcessData(
  994. IN PCONSOLE_PER_PROCESS_DATA ProcessData)
  995. /*++
  996. Routine Description:
  997. This routine frees any per-process data allocated by the console.
  998. Arguments:
  999. ProcessData - Pointer to the per-process data structure.
  1000. Return Value:
  1001. --*/
  1002. {
  1003. if (ProcessData->HandleTableSize != CONSOLE_INITIAL_IO_HANDLES) {
  1004. ConsoleHeapFree(ProcessData->HandleTablePtr);
  1005. ProcessData->HandleTablePtr = ProcessData->HandleTable;
  1006. ProcessData->HandleTableSize = CONSOLE_INITIAL_IO_HANDLES;
  1007. }
  1008. }
  1009. VOID
  1010. InitializeOutputHandle(
  1011. PHANDLE_DATA HandleData,
  1012. PSCREEN_INFORMATION ScreenBuffer)
  1013. /*++
  1014. Routine Description:
  1015. This routine initializes the output-specific fields of the handle data
  1016. structure.
  1017. Arguments:
  1018. HandleData - Pointer to handle data structure.
  1019. ScreenBuffer - Pointer to screen buffer data structure.
  1020. Return Value:
  1021. --*/
  1022. {
  1023. HandleData->Buffer.ScreenBuffer = ScreenBuffer;
  1024. HandleData->Buffer.ScreenBuffer->RefCount++;
  1025. }
  1026. BOOLEAN
  1027. InitializeInputHandle(
  1028. PHANDLE_DATA HandleData,
  1029. PINPUT_INFORMATION InputBuffer)
  1030. /*++
  1031. Routine Description:
  1032. This routine initializes the input-specific fields of the handle data
  1033. structure.
  1034. Arguments:
  1035. HandleData - Pointer to handle data structure.
  1036. InputBuffer - Pointer to input buffer data structure.
  1037. Return Value:
  1038. --*/
  1039. {
  1040. NTSTATUS Status;
  1041. HandleData->InputReadData = ConsoleHeapAlloc(HANDLE_TAG, sizeof(INPUT_READ_HANDLE_DATA));
  1042. if (!HandleData->InputReadData) {
  1043. return FALSE;
  1044. }
  1045. Status = RtlInitializeCriticalSection(&HandleData->InputReadData->ReadCountLock);
  1046. if (!NT_SUCCESS(Status)) {
  1047. ConsoleHeapFree(HandleData->InputReadData);
  1048. HandleData->InputReadData = NULL;
  1049. return FALSE;
  1050. }
  1051. HandleData->InputReadData->ReadCount = 0;
  1052. HandleData->InputReadData->InputHandleFlags = 0;
  1053. HandleData->Buffer.InputBuffer = InputBuffer;
  1054. HandleData->Buffer.InputBuffer->RefCount++;
  1055. return TRUE;
  1056. }
  1057. VOID
  1058. FreeInputHandle(
  1059. IN PHANDLE_DATA HandleData)
  1060. {
  1061. if (HandleData->InputReadData) {
  1062. RtlDeleteCriticalSection(&HandleData->InputReadData->ReadCountLock);
  1063. ConsoleHeapFree(HandleData->InputReadData);
  1064. HandleData->InputReadData = NULL;
  1065. }
  1066. }
  1067. NTSTATUS
  1068. AllocateIoHandle(
  1069. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  1070. IN ULONG HandleType,
  1071. OUT PHANDLE Handle)
  1072. /*++
  1073. Routine Description:
  1074. This routine allocates an input or output handle from the process's
  1075. handle table.
  1076. This routine initializes all non-type specific fields in the handle
  1077. data structure.
  1078. Arguments:
  1079. ProcessData - Pointer to per process data structure.
  1080. HandleType - Flag indicating input or output handle.
  1081. Handle - On return, contains allocated handle. Handle is an index
  1082. internally. When returned to the API caller, it is translated into
  1083. a handle.
  1084. Return Value:
  1085. Note:
  1086. The console lock must be held when calling this routine. The handle
  1087. is allocated from the per-process handle table. Holding the console
  1088. lock serializes both threads within the calling process and any other
  1089. process that shares the console.
  1090. --*/
  1091. {
  1092. ULONG i;
  1093. NTSTATUS Status;
  1094. for (i = 0;i < ProcessData->HandleTableSize; i++) {
  1095. if (ProcessData->HandleTablePtr[i].HandleType == CONSOLE_FREE_HANDLE) {
  1096. ProcessData->HandleTablePtr[i].HandleType = HandleType;
  1097. *Handle = LongToHandle(i);
  1098. return STATUS_SUCCESS;
  1099. }
  1100. }
  1101. Status = GrowIoHandleTable(ProcessData);
  1102. if (!NT_SUCCESS(Status)) {
  1103. return Status;
  1104. }
  1105. for ( ;i < ProcessData->HandleTableSize; i++) {
  1106. if (ProcessData->HandleTablePtr[i].HandleType == CONSOLE_FREE_HANDLE) {
  1107. ProcessData->HandleTablePtr[i].HandleType = HandleType;
  1108. *Handle = LongToHandle(i);
  1109. return STATUS_SUCCESS;
  1110. }
  1111. }
  1112. ASSERT (FALSE);
  1113. return STATUS_UNSUCCESSFUL;
  1114. }
  1115. NTSTATUS
  1116. FreeIoHandle(
  1117. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  1118. IN HANDLE Handle)
  1119. /*++
  1120. Routine Description:
  1121. This routine frees an input or output handle from the process's
  1122. handle table.
  1123. Arguments:
  1124. ProcessData - Pointer to per process data structure.
  1125. Handle - Handle to free.
  1126. Return Value:
  1127. Note:
  1128. The console lock must be held when calling this routine. The handle
  1129. is freed from the per-process handle table. Holding the console
  1130. lock serializes both threads within the calling process and any other
  1131. process that shares the console.
  1132. --*/
  1133. {
  1134. NTSTATUS Status;
  1135. PHANDLE_DATA HandleData;
  1136. Status = DereferenceIoHandleNoCheck(ProcessData,
  1137. Handle,
  1138. &HandleData
  1139. );
  1140. ASSERT (NT_SUCCESS(Status));
  1141. if (!NT_SUCCESS(Status)) {
  1142. return Status;
  1143. }
  1144. if (HandleData->HandleType & CONSOLE_INPUT_HANDLE) {
  1145. FreeInputHandle(HandleData);
  1146. }
  1147. HandleData->HandleType = CONSOLE_FREE_HANDLE;
  1148. return STATUS_SUCCESS;
  1149. }
  1150. NTSTATUS
  1151. DereferenceIoHandleNoCheck(
  1152. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  1153. IN HANDLE Handle,
  1154. OUT PHANDLE_DATA *HandleData)
  1155. /*++
  1156. Routine Description:
  1157. This routine verifies a handle's validity, then returns a pointer to
  1158. the handle data structure.
  1159. Arguments:
  1160. ProcessData - Pointer to per process data structure.
  1161. Handle - Handle to dereference.
  1162. HandleData - On return, pointer to handle data structure.
  1163. Return Value:
  1164. --*/
  1165. {
  1166. if (((ULONG_PTR)Handle >= ProcessData->HandleTableSize) ||
  1167. (ProcessData->HandleTablePtr[(ULONG_PTR)Handle].HandleType == CONSOLE_FREE_HANDLE) ) {
  1168. return STATUS_INVALID_HANDLE;
  1169. }
  1170. *HandleData = &ProcessData->HandleTablePtr[(ULONG_PTR)Handle];
  1171. return STATUS_SUCCESS;
  1172. }
  1173. NTSTATUS
  1174. DereferenceIoHandle(
  1175. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  1176. IN HANDLE Handle,
  1177. IN ULONG HandleType,
  1178. IN ACCESS_MASK Access,
  1179. OUT PHANDLE_DATA *HandleData)
  1180. /*++
  1181. Routine Description:
  1182. This routine verifies a handle's validity, then returns a pointer to
  1183. the handle data structure.
  1184. Arguments:
  1185. ProcessData - Pointer to per process data structure.
  1186. Handle - Handle to dereference.
  1187. HandleData - On return, pointer to handle data structure.
  1188. Return Value:
  1189. --*/
  1190. {
  1191. ULONG_PTR Index;
  1192. if (!CONSOLE_HANDLE(Handle)) {
  1193. return STATUS_INVALID_HANDLE;
  1194. }
  1195. Index = (ULONG_PTR)HANDLE_TO_INDEX(Handle);
  1196. if ((Index >= ProcessData->HandleTableSize) ||
  1197. (ProcessData->HandleTablePtr[Index].HandleType == CONSOLE_FREE_HANDLE) ||
  1198. !(ProcessData->HandleTablePtr[Index].HandleType & HandleType) ||
  1199. !(ProcessData->HandleTablePtr[Index].Access & Access) ) {
  1200. return STATUS_INVALID_HANDLE;
  1201. }
  1202. *HandleData = &ProcessData->HandleTablePtr[Index];
  1203. return STATUS_SUCCESS;
  1204. }
  1205. ULONG
  1206. SrvVerifyConsoleIoHandle(
  1207. IN OUT PCSR_API_MSG m,
  1208. IN OUT PCSR_REPLY_STATUS ReplyStatus)
  1209. /*++
  1210. Routine Description:
  1211. This routine verifies that a console io handle is valid.
  1212. Arguments:
  1213. ApiMessageData - Points to parameter structure.
  1214. Return Value:
  1215. --*/
  1216. {
  1217. PCONSOLE_VERIFYIOHANDLE_MSG a = (PCONSOLE_VERIFYIOHANDLE_MSG)&m->u.ApiMessageData;
  1218. PCONSOLE_INFORMATION Console;
  1219. NTSTATUS Status;
  1220. PHANDLE_DATA HandleData;
  1221. PCONSOLE_PER_PROCESS_DATA ProcessData;
  1222. UNREFERENCED_PARAMETER(ReplyStatus);
  1223. Status = ApiPreamble(a->ConsoleHandle,
  1224. &Console
  1225. );
  1226. if (NT_SUCCESS(Status)) {
  1227. ProcessData = CONSOLE_PERPROCESSDATA();
  1228. Status = DereferenceIoHandleNoCheck(ProcessData,
  1229. HANDLE_TO_INDEX(a->Handle),
  1230. &HandleData
  1231. );
  1232. UnlockConsole(Console);
  1233. }
  1234. a->Valid = (NT_SUCCESS(Status));
  1235. return STATUS_SUCCESS;
  1236. }
  1237. NTSTATUS
  1238. ApiPreamble(
  1239. IN HANDLE ConsoleHandle,
  1240. OUT PCONSOLE_INFORMATION *Console)
  1241. {
  1242. NTSTATUS Status;
  1243. //
  1244. // If this process doesn't have a console handle, bail immediately.
  1245. //
  1246. if (ConsoleHandle == NULL || ConsoleHandle != CONSOLE_GETCONSOLEHANDLE()) {
  1247. return STATUS_INVALID_HANDLE;
  1248. }
  1249. #ifdef i386
  1250. //Do not lock the console if we are in the special case:
  1251. //(1). we are in the middle of handshaking with ntvdm doing
  1252. // full-screen to windowed mode transition
  1253. //(2). the calling process is THE ntvdm process(this implies that the
  1254. // the console has vdm registered.
  1255. //(3). the console handle is the same one.
  1256. // if (1), (2) and (3) are true then the console is already locked
  1257. // (locked by the windowproc while processing the WM_FULLSCREEN
  1258. // message)
  1259. RtlEnterCriticalSection(&ConsoleVDMCriticalSection);
  1260. if (ConsoleVDMOnSwitching != NULL &&
  1261. ConsoleVDMOnSwitching->ConsoleHandle == ConsoleHandle &&
  1262. ConsoleVDMOnSwitching->VDMProcessId == CONSOLE_CLIENTPROCESSID()) {
  1263. RIPMSG1(RIP_WARNING, "ApiPreamble - Thread %lx Entered VDM CritSec", GetCurrentThreadId());
  1264. *Console = ConsoleVDMOnSwitching;
  1265. return STATUS_SUCCESS;
  1266. }
  1267. RtlLeaveCriticalSection(&ConsoleVDMCriticalSection);
  1268. #endif
  1269. Status = RevalidateConsole(ConsoleHandle,
  1270. Console
  1271. );
  1272. if (!NT_SUCCESS(Status)) {
  1273. return Status;
  1274. }
  1275. //
  1276. // Make sure the console has been initialized and the window is valid
  1277. //
  1278. if ((*Console)->hWnd == NULL || ((*Console)->Flags & CONSOLE_TERMINATING)) {
  1279. KdPrint(("CONSRV: bogus window for console %lx\n", *Console));
  1280. UnlockConsole(*Console);
  1281. return STATUS_INVALID_HANDLE;
  1282. }
  1283. return Status;
  1284. }
  1285. NTSTATUS
  1286. RevalidateConsole(
  1287. IN HANDLE ConsoleHandle,
  1288. OUT PCONSOLE_INFORMATION *Console)
  1289. {
  1290. NTSTATUS Status;
  1291. LockConsoleHandleTable();
  1292. Status = DereferenceConsoleHandle(ConsoleHandle,
  1293. Console
  1294. );
  1295. if (!NT_SUCCESS(Status)) {
  1296. UnlockConsoleHandleTable();
  1297. return Status;
  1298. }
  1299. //
  1300. // The WaitCount ensures the console won't go away between the time
  1301. // we unlock the console handle table and we lock the console.
  1302. //
  1303. InterlockedIncrement(&(*Console)->WaitCount);
  1304. UnlockConsoleHandleTable();
  1305. try {
  1306. LockConsole(*Console);
  1307. } except (EXCEPTION_EXECUTE_HANDLER) {
  1308. InterlockedDecrement(&(*Console)->WaitCount);
  1309. return GetExceptionCode();
  1310. }
  1311. InterlockedDecrement(&(*Console)->WaitCount);
  1312. //
  1313. // If the console was marked for destruction while we were waiting to
  1314. // lock it, try to destroy it and return.
  1315. //
  1316. if ((*Console)->Flags & CONSOLE_IN_DESTRUCTION) {
  1317. DestroyConsole(*Console);
  1318. *Console = NULL;
  1319. return STATUS_INVALID_HANDLE;
  1320. }
  1321. //
  1322. // If the console was marked for termination while we were waiting to
  1323. // lock it, bail out.
  1324. //
  1325. if ((*Console)->Flags & CONSOLE_TERMINATING) {
  1326. UnlockConsole(*Console);
  1327. *Console = NULL;
  1328. return STATUS_PROCESS_IS_TERMINATING;
  1329. }
  1330. return Status;
  1331. }
  1332. #if DBG
  1333. BOOLEAN
  1334. UnProtectHandle(
  1335. HANDLE hObject)
  1336. {
  1337. NTSTATUS Status;
  1338. OBJECT_HANDLE_FLAG_INFORMATION HandleInfo;
  1339. Status = NtQueryObject(hObject,
  1340. ObjectHandleFlagInformation,
  1341. &HandleInfo,
  1342. sizeof(HandleInfo),
  1343. NULL
  1344. );
  1345. if (NT_SUCCESS(Status)) {
  1346. HandleInfo.ProtectFromClose = FALSE;
  1347. Status = NtSetInformationObject(hObject,
  1348. ObjectHandleFlagInformation,
  1349. &HandleInfo,
  1350. sizeof(HandleInfo)
  1351. );
  1352. if (NT_SUCCESS(Status)) {
  1353. return TRUE;
  1354. }
  1355. }
  1356. return FALSE;
  1357. }
  1358. #endif // DBG