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.

2044 lines
55 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. process.c
  5. Abstract:
  6. This module contains the worker routines called to create and
  7. maintain the application process structure for the Client-Server
  8. Runtime Subsystem to the Session Manager SubSystem.
  9. Author:
  10. Steve Wood (stevewo) 10-Oct-1990
  11. Revision History:
  12. --*/
  13. #include "csrsrv.h"
  14. #include <wchar.h>
  15. // ProcessSequenceCount will never be a value less than FIRST_SEQUENCE_COUNT
  16. // currently GDI needs 0 - 4 to be reserved.
  17. ULONG ProcessSequenceCount = FIRST_SEQUENCE_COUNT;
  18. #define THREAD_HASH_SIZE 256
  19. #define THREAD_ID_TO_HASH(id) (HandleToUlong(id)&(THREAD_HASH_SIZE-1))
  20. LIST_ENTRY CsrThreadHashTable[THREAD_HASH_SIZE];
  21. SECURITY_QUALITY_OF_SERVICE CsrSecurityQos = {
  22. sizeof(SECURITY_QUALITY_OF_SERVICE), SecurityImpersonation,
  23. SECURITY_DYNAMIC_TRACKING, FALSE
  24. };
  25. PCSR_PROCESS
  26. FindProcessForShutdown(
  27. PLUID CallerLuid
  28. );
  29. NTSTATUS
  30. ReadUnicodeString(HANDLE ProcessHandle,
  31. PUNICODE_STRING RemoteString,
  32. PUNICODE_STRING LocalString
  33. );
  34. VOID
  35. CsrpSetToNormalPriority(
  36. VOID
  37. )
  38. {
  39. KPRIORITY SetBasePriority;
  40. SetBasePriority = FOREGROUND_BASE_PRIORITY + 4;
  41. NtSetInformationProcess(
  42. NtCurrentProcess(),
  43. ProcessBasePriority,
  44. (PVOID) &SetBasePriority,
  45. sizeof(SetBasePriority)
  46. );
  47. }
  48. VOID
  49. CsrpSetToShutdownPriority(
  50. VOID
  51. )
  52. {
  53. NTSTATUS Status;
  54. BOOLEAN WasEnabled;
  55. KPRIORITY SetBasePriority;
  56. Status = RtlAdjustPrivilege(
  57. SE_INC_BASE_PRIORITY_PRIVILEGE,
  58. TRUE,
  59. FALSE,
  60. &WasEnabled);
  61. if (!NT_SUCCESS(Status))
  62. return;
  63. SetBasePriority = FOREGROUND_BASE_PRIORITY + 6;
  64. NtSetInformationProcess(
  65. NtCurrentProcess(),
  66. ProcessBasePriority,
  67. (PVOID) &SetBasePriority,
  68. sizeof(SetBasePriority)
  69. );
  70. }
  71. VOID
  72. CsrSetForegroundPriority(
  73. IN PCSR_PROCESS Process
  74. )
  75. {
  76. PROCESS_FOREGROUND_BACKGROUND Fg;
  77. Fg.Foreground = TRUE;
  78. NtSetInformationProcess(
  79. Process->ProcessHandle,
  80. ProcessForegroundInformation,
  81. (PVOID)&Fg,
  82. sizeof(Fg)
  83. );
  84. }
  85. VOID
  86. CsrSetBackgroundPriority(
  87. IN PCSR_PROCESS Process
  88. )
  89. {
  90. PROCESS_FOREGROUND_BACKGROUND Fg;
  91. Fg.Foreground = FALSE;
  92. NtSetInformationProcess(
  93. Process->ProcessHandle,
  94. ProcessForegroundInformation,
  95. (PVOID)&Fg,
  96. sizeof(Fg)
  97. );
  98. }
  99. //
  100. // Though this function does not seem to cleanup on failure, failure
  101. // will cause Csrss to exit, so any allocated memory will be freed and
  102. // any open handle will be closed.
  103. //
  104. NTSTATUS
  105. CsrInitializeProcessStructure(
  106. VOID)
  107. {
  108. NTSTATUS Status;
  109. ULONG i;
  110. Status = RtlInitializeCriticalSection(&CsrProcessStructureLock);
  111. if (!NT_SUCCESS(Status)) {
  112. return Status;
  113. }
  114. CsrRootProcess = CsrAllocateProcess();
  115. if (CsrRootProcess == NULL) {
  116. return STATUS_NO_MEMORY;
  117. }
  118. InitializeListHead( &CsrRootProcess->ListLink );
  119. CsrRootProcess->ProcessHandle = (HANDLE) -1;
  120. CsrRootProcess->ClientId = NtCurrentTeb()->ClientId;
  121. for (i = 0; i < THREAD_HASH_SIZE; i++) {
  122. InitializeListHead(&CsrThreadHashTable[i]);
  123. }
  124. Status = RtlInitializeCriticalSection(&CsrWaitListsLock);
  125. return Status;
  126. }
  127. PCSR_PROCESS
  128. CsrAllocateProcess(
  129. VOID)
  130. {
  131. PCSR_PROCESS Process;
  132. ULONG ProcessSize;
  133. //
  134. // Allocate an Windows Process Object. At the end of the process
  135. // structure is an array of pointers to each server DLL's per process
  136. // data. The per process data is contained in the memory after the
  137. // array.
  138. //
  139. ProcessSize = (ULONG)QUAD_ALIGN(sizeof( CSR_PROCESS ) +
  140. (CSR_MAX_SERVER_DLL * sizeof(PVOID))) + CsrTotalPerProcessDataLength;
  141. Process = (PCSR_PROCESS)RtlAllocateHeap( CsrHeap, MAKE_TAG( PROCESS_TAG ),
  142. ProcessSize
  143. );
  144. if (Process == NULL) {
  145. return( NULL );
  146. }
  147. //
  148. // Initialize the fields of the process object
  149. //
  150. RtlZeroMemory( Process, ProcessSize);
  151. //
  152. // grab the ProcessSequenceNumber and increment it, making sure that it
  153. // is never less than FIRST_SEQUENCE_COUNT.
  154. //
  155. Process->SequenceNumber = ProcessSequenceCount++;
  156. if (ProcessSequenceCount < FIRST_SEQUENCE_COUNT)
  157. ProcessSequenceCount = FIRST_SEQUENCE_COUNT;
  158. CsrLockedReferenceProcess(Process);
  159. InitializeListHead( &Process->ThreadList );
  160. return( Process );
  161. }
  162. VOID
  163. CsrDeallocateProcess(
  164. IN PCSR_PROCESS Process
  165. )
  166. {
  167. RtlFreeHeap( CsrHeap, 0, Process );
  168. }
  169. //
  170. // NOTE: The process structure lock must be held when calling this routine.
  171. //
  172. VOID
  173. CsrInsertProcess(
  174. IN PCSR_PROCESS CallingProcess,
  175. IN PCSR_PROCESS Process
  176. )
  177. {
  178. PCSR_SERVER_DLL LoadedServerDll;
  179. ULONG i;
  180. ASSERT(ProcessStructureListLocked());
  181. InsertTailList( &CsrRootProcess->ListLink, &Process->ListLink );
  182. for (i=0; i<CSR_MAX_SERVER_DLL; i++) {
  183. LoadedServerDll = CsrLoadedServerDll[i];
  184. if (LoadedServerDll && LoadedServerDll->AddProcessRoutine) {
  185. (*LoadedServerDll->AddProcessRoutine)(CallingProcess, Process);
  186. }
  187. }
  188. }
  189. //
  190. // NOTE: The process structure lock must be held when calling this routine.
  191. //
  192. VOID
  193. CsrRemoveProcess(
  194. IN PCSR_PROCESS Process
  195. )
  196. {
  197. PCSR_SERVER_DLL LoadedServerDll;
  198. ULONG i;
  199. ASSERT(ProcessStructureListLocked());
  200. RemoveEntryList( &Process->ListLink );
  201. ReleaseProcessStructureLock();
  202. for (i=0; i<CSR_MAX_SERVER_DLL; i++) {
  203. LoadedServerDll = CsrLoadedServerDll[i];
  204. if (LoadedServerDll && LoadedServerDll->DisconnectRoutine) {
  205. (LoadedServerDll->DisconnectRoutine)(Process);
  206. }
  207. }
  208. }
  209. NTSTATUS
  210. CsrCreateProcess(
  211. IN HANDLE ProcessHandle,
  212. IN HANDLE ThreadHandle,
  213. IN PCLIENT_ID ClientId,
  214. IN PCSR_NT_SESSION Session,
  215. IN ULONG DebugFlags,
  216. IN PCLIENT_ID DebugUserInterface OPTIONAL
  217. )
  218. {
  219. PCSR_PROCESS Process;
  220. PCSR_THREAD Thread;
  221. NTSTATUS Status;
  222. ULONG i;
  223. PVOID ProcessDataPtr;
  224. CLIENT_ID CallingClientId;
  225. PCSR_THREAD CallingThread;
  226. PCSR_PROCESS CallingProcess;
  227. KERNEL_USER_TIMES TimeInfo;
  228. CallingThread = CSR_SERVER_QUERYCLIENTTHREAD();
  229. //
  230. // remember the client id of the calling process.
  231. //
  232. CallingClientId = CallingThread->ClientId;
  233. AcquireProcessStructureLock();
  234. //
  235. // look for calling thread.
  236. //
  237. CallingThread = CsrLocateThreadByClientId(&CallingProcess, &CallingClientId);
  238. if (CallingThread == NULL) {
  239. ReleaseProcessStructureLock();
  240. return STATUS_THREAD_IS_TERMINATING;
  241. }
  242. Process = CsrAllocateProcess();
  243. if (Process == NULL) {
  244. Status = STATUS_NO_MEMORY;
  245. ReleaseProcessStructureLock();
  246. return( Status );
  247. }
  248. //
  249. // copy per-process data from parent to child
  250. //
  251. CallingProcess = (CSR_SERVER_QUERYCLIENTTHREAD())->Process;
  252. ProcessDataPtr = (PVOID)QUAD_ALIGN(&Process->ServerDllPerProcessData[CSR_MAX_SERVER_DLL]);
  253. for (i=0; i<CSR_MAX_SERVER_DLL; i++) {
  254. if (CsrLoadedServerDll[i] != NULL && CsrLoadedServerDll[i]->PerProcessDataLength) {
  255. Process->ServerDllPerProcessData[i] = ProcessDataPtr;
  256. RtlMoveMemory(ProcessDataPtr,
  257. CallingProcess->ServerDllPerProcessData[i],
  258. CsrLoadedServerDll[i]->PerProcessDataLength
  259. );
  260. ProcessDataPtr = (PVOID)QUAD_ALIGN((PCHAR)ProcessDataPtr + CsrLoadedServerDll[i]->PerProcessDataLength);
  261. }
  262. else {
  263. Process->ServerDllPerProcessData[i] = NULL;
  264. }
  265. }
  266. Status = NtSetInformationProcess(
  267. ProcessHandle,
  268. ProcessExceptionPort,
  269. (PVOID)&CsrApiPort,
  270. sizeof(HANDLE)
  271. );
  272. if ( !NT_SUCCESS(Status) ) {
  273. CsrDeallocateProcess( Process );
  274. ReleaseProcessStructureLock();
  275. return( STATUS_NO_MEMORY );
  276. }
  277. //
  278. // If we are creating a process group, the group leader has the same
  279. // process id and sequence number of itself. If the leader dies and
  280. // his pid is recycled, the sequence number mismatch will prevent it
  281. // from being viewed as a group leader.
  282. //
  283. if ( DebugFlags & CSR_CREATE_PROCESS_GROUP ) {
  284. Process->ProcessGroupId = HandleToUlong(ClientId->UniqueProcess);
  285. Process->ProcessGroupSequence = Process->SequenceNumber;
  286. }
  287. else {
  288. Process->ProcessGroupId = CallingProcess->ProcessGroupId;
  289. Process->ProcessGroupSequence = CallingProcess->ProcessGroupSequence;
  290. }
  291. if ( DebugFlags & CSR_PROCESS_CONSOLEAPP ) {
  292. Process->Flags |= CSR_PROCESS_CONSOLEAPP;
  293. }
  294. DebugFlags &= ~(CSR_PROCESS_CONSOLEAPP | CSR_CREATE_PROCESS_GROUP);
  295. if ( !DebugFlags && CallingProcess->DebugFlags & CSR_DEBUG_PROCESS_TREE ) {
  296. Process->DebugFlags = CSR_DEBUG_PROCESS_TREE;
  297. Process->DebugUserInterface = CallingProcess->DebugUserInterface;
  298. }
  299. if ( DebugFlags & (CSR_DEBUG_THIS_PROCESS | CSR_DEBUG_PROCESS_TREE) &&
  300. ARGUMENT_PRESENT(DebugUserInterface) ) {
  301. Process->DebugFlags = DebugFlags;
  302. Process->DebugUserInterface = *DebugUserInterface;
  303. }
  304. if ( Process->DebugFlags ) {
  305. //
  306. // Process is being debugged, so set up debug port
  307. //
  308. Status = NtSetInformationProcess(
  309. ProcessHandle,
  310. ProcessDebugPort,
  311. (PVOID)&CsrApiPort,
  312. sizeof(HANDLE)
  313. );
  314. ASSERT(NT_SUCCESS(Status));
  315. if ( !NT_SUCCESS(Status) ) {
  316. CsrDeallocateProcess( Process );
  317. ReleaseProcessStructureLock();
  318. return( STATUS_NO_MEMORY );
  319. }
  320. }
  321. //
  322. // capture the thread's createtime so that we can use
  323. // this as a sequence number
  324. //
  325. Status = NtQueryInformationThread(
  326. ThreadHandle,
  327. ThreadTimes,
  328. (PVOID)&TimeInfo,
  329. sizeof(TimeInfo),
  330. NULL
  331. );
  332. if ( !NT_SUCCESS(Status) ) {
  333. CsrDeallocateProcess( Process );
  334. ReleaseProcessStructureLock();
  335. return( Status );
  336. }
  337. Thread = CsrAllocateThread( Process );
  338. if (Thread == NULL) {
  339. CsrDeallocateProcess( Process );
  340. ReleaseProcessStructureLock();
  341. return( STATUS_NO_MEMORY );
  342. }
  343. Thread->CreateTime = TimeInfo.CreateTime;
  344. Thread->ClientId = *ClientId;
  345. Thread->ThreadHandle = ThreadHandle;
  346. ProtectHandle(ThreadHandle);
  347. Thread->Flags = 0;
  348. CsrInsertThread( Process, Thread );
  349. CsrReferenceNtSession(Session);
  350. Process->NtSession = Session;
  351. Process->ClientId = *ClientId;
  352. Process->ProcessHandle = ProcessHandle;
  353. CsrSetBackgroundPriority(Process);
  354. Process->ShutdownLevel = 0x00000280;
  355. CsrInsertProcess((CSR_SERVER_QUERYCLIENTTHREAD())->Process, Process);
  356. ReleaseProcessStructureLock();
  357. return STATUS_SUCCESS;
  358. }
  359. NTSTATUS
  360. CsrDestroyProcess(
  361. IN PCLIENT_ID ClientId,
  362. IN NTSTATUS ExitStatus
  363. )
  364. {
  365. PLIST_ENTRY ListHead, ListNext;
  366. PCSR_THREAD DyingThread;
  367. PCSR_PROCESS DyingProcess;
  368. CLIENT_ID DyingClientId;
  369. DyingClientId = *ClientId;
  370. AcquireProcessStructureLock();
  371. DyingThread = CsrLocateThreadByClientId( &DyingProcess,
  372. &DyingClientId
  373. );
  374. if (DyingThread == NULL) {
  375. ReleaseProcessStructureLock();
  376. return STATUS_THREAD_IS_TERMINATING;
  377. }
  378. //
  379. // prevent multiple destroys from causing problems. Scottlu and Markl
  380. // beleive all known race conditions are now fixed. This is simply a
  381. // precaution since we know that if this happens we process reference
  382. // count underflow
  383. //
  384. if ( DyingProcess->Flags & CSR_PROCESS_DESTROYED ) {
  385. ReleaseProcessStructureLock();
  386. return STATUS_THREAD_IS_TERMINATING;
  387. }
  388. DyingProcess->Flags |= CSR_PROCESS_DESTROYED;
  389. ListHead = &DyingProcess->ThreadList;
  390. ListNext = ListHead->Flink;
  391. while (ListNext != ListHead) {
  392. DyingThread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link );
  393. if ( DyingThread->Flags & CSR_THREAD_DESTROYED ) {
  394. ListNext = ListNext->Flink;
  395. continue;
  396. }
  397. else {
  398. DyingThread->Flags |= CSR_THREAD_DESTROYED;
  399. }
  400. AcquireWaitListsLock();
  401. if (DyingThread->WaitBlock != NULL) {
  402. CsrNotifyWaitBlock(DyingThread->WaitBlock,
  403. NULL,
  404. NULL,
  405. NULL,
  406. CSR_PROCESS_TERMINATING,
  407. TRUE
  408. );
  409. }
  410. ReleaseWaitListsLock();
  411. CsrLockedDereferenceThread(DyingThread);
  412. ListNext = ListHead->Flink;
  413. }
  414. ReleaseProcessStructureLock();
  415. return STATUS_SUCCESS;
  416. }
  417. NTSTATUS
  418. CsrCreateThread(
  419. IN PCSR_PROCESS Process,
  420. IN HANDLE ThreadHandle,
  421. IN PCLIENT_ID ClientId,
  422. IN BOOLEAN ValidateCaller
  423. )
  424. {
  425. PCSR_THREAD Thread;
  426. CLIENT_ID CallingClientId;
  427. PCSR_THREAD CallingThread;
  428. PCSR_PROCESS CallingProcess;
  429. KERNEL_USER_TIMES TimeInfo;
  430. NTSTATUS Status;
  431. if (ValidateCaller)
  432. {
  433. CallingThread = CSR_SERVER_QUERYCLIENTTHREAD();
  434. //
  435. // remember the client id of the calling process.
  436. //
  437. CallingClientId = CallingThread->ClientId;
  438. AcquireProcessStructureLock();
  439. //
  440. // look for calling thread.
  441. //
  442. CallingThread = CsrLocateThreadByClientId( &CallingProcess,
  443. &CallingClientId
  444. );
  445. if (CallingThread == NULL) {
  446. ReleaseProcessStructureLock();
  447. return STATUS_THREAD_IS_TERMINATING;
  448. }
  449. } else {
  450. AcquireProcessStructureLock();
  451. }
  452. Status = NtQueryInformationThread(
  453. ThreadHandle,
  454. ThreadTimes,
  455. (PVOID)&TimeInfo,
  456. sizeof(TimeInfo),
  457. NULL
  458. );
  459. if ( !NT_SUCCESS(Status) ) {
  460. ReleaseProcessStructureLock();
  461. return( Status );
  462. }
  463. if (Process->Flags & CSR_PROCESS_DESTROYED) {
  464. IF_DEBUG {
  465. DbgPrint("CSRSS: CsrCreateThread - process %p is destroyed\n", Process);
  466. }
  467. ReleaseProcessStructureLock();
  468. return STATUS_THREAD_IS_TERMINATING;
  469. }
  470. Thread = CsrAllocateThread( Process );
  471. if (Thread == NULL) {
  472. ReleaseProcessStructureLock();
  473. return( STATUS_NO_MEMORY );
  474. }
  475. Thread->CreateTime = TimeInfo.CreateTime;
  476. Thread->ClientId = *ClientId;
  477. Thread->ThreadHandle = ThreadHandle;
  478. ProtectHandle(ThreadHandle);
  479. Thread->Flags = 0;
  480. CsrInsertThread( Process, Thread );
  481. ReleaseProcessStructureLock();
  482. return STATUS_SUCCESS;
  483. }
  484. NTSTATUS
  485. CsrCreateRemoteThread(
  486. IN HANDLE ThreadHandle,
  487. IN PCLIENT_ID ClientId
  488. )
  489. {
  490. PCSR_THREAD Thread;
  491. PCSR_PROCESS Process;
  492. NTSTATUS Status;
  493. HANDLE hThread;
  494. KERNEL_USER_TIMES TimeInfo;
  495. Status = NtQueryInformationThread(
  496. ThreadHandle,
  497. ThreadTimes,
  498. (PVOID)&TimeInfo,
  499. sizeof(TimeInfo),
  500. NULL
  501. );
  502. if ( !NT_SUCCESS(Status) ) {
  503. return( Status );
  504. }
  505. Status = CsrLockProcessByClientId( ClientId->UniqueProcess,
  506. &Process
  507. );
  508. if (!NT_SUCCESS( Status )) {
  509. return( Status );
  510. }
  511. //
  512. // Don't create the thread structure if the thread
  513. // has already terminated.
  514. //
  515. if ( TimeInfo.ExitTime.QuadPart != 0 ) {
  516. CsrUnlockProcess( Process );
  517. return( STATUS_THREAD_IS_TERMINATING );
  518. }
  519. Thread = CsrAllocateThread( Process );
  520. if (Thread == NULL) {
  521. CsrUnlockProcess( Process );
  522. return( STATUS_NO_MEMORY );
  523. }
  524. Status = NtDuplicateObject(
  525. NtCurrentProcess(),
  526. ThreadHandle,
  527. NtCurrentProcess(),
  528. &hThread,
  529. 0L,
  530. 0L,
  531. DUPLICATE_SAME_ACCESS
  532. );
  533. if (!NT_SUCCESS(Status)) {
  534. hThread = ThreadHandle;
  535. }
  536. Thread->CreateTime = TimeInfo.CreateTime;
  537. Thread->ClientId = *ClientId;
  538. Thread->ThreadHandle = hThread;
  539. ProtectHandle(hThread);
  540. Thread->Flags = 0;
  541. CsrInsertThread( Process, Thread );
  542. CsrUnlockProcess( Process );
  543. return STATUS_SUCCESS;
  544. }
  545. NTSTATUS
  546. CsrDestroyThread(
  547. IN PCLIENT_ID ClientId
  548. )
  549. {
  550. CLIENT_ID DyingClientId;
  551. PCSR_THREAD DyingThread;
  552. PCSR_PROCESS DyingProcess;
  553. DyingClientId = *ClientId;
  554. AcquireProcessStructureLock();
  555. DyingThread = CsrLocateThreadByClientId( &DyingProcess,
  556. &DyingClientId
  557. );
  558. if (DyingThread == NULL) {
  559. ReleaseProcessStructureLock();
  560. return STATUS_THREAD_IS_TERMINATING;
  561. }
  562. if ( DyingThread->Flags & CSR_THREAD_DESTROYED ) {
  563. ReleaseProcessStructureLock();
  564. return STATUS_THREAD_IS_TERMINATING;
  565. }
  566. else {
  567. DyingThread->Flags |= CSR_THREAD_DESTROYED;
  568. }
  569. AcquireWaitListsLock();
  570. if (DyingThread->WaitBlock != NULL) {
  571. CsrNotifyWaitBlock(DyingThread->WaitBlock,
  572. NULL,
  573. NULL,
  574. NULL,
  575. CSR_PROCESS_TERMINATING,
  576. TRUE
  577. );
  578. }
  579. ReleaseWaitListsLock();
  580. CsrLockedDereferenceThread(DyingThread);
  581. ReleaseProcessStructureLock();
  582. return STATUS_SUCCESS;
  583. }
  584. PCSR_THREAD
  585. CsrAllocateThread(
  586. IN PCSR_PROCESS Process
  587. )
  588. {
  589. PCSR_THREAD Thread;
  590. ULONG ThreadSize;
  591. //
  592. // Allocate an Windows Thread Object.
  593. //
  594. ThreadSize = QUAD_ALIGN(sizeof( CSR_THREAD ));
  595. Thread = (PCSR_THREAD)RtlAllocateHeap( CsrHeap, MAKE_TAG( THREAD_TAG ),
  596. ThreadSize
  597. );
  598. if (Thread == NULL) {
  599. return( NULL );
  600. }
  601. //
  602. // Initialize the fields of the thread object
  603. //
  604. RtlZeroMemory( Thread, ThreadSize );
  605. CsrLockedReferenceThread(Thread);
  606. CsrLockedReferenceProcess(Process);
  607. Thread->Process = Process;
  608. return( Thread );
  609. }
  610. VOID
  611. CsrDeallocateThread(
  612. IN PCSR_THREAD Thread
  613. )
  614. {
  615. ASSERT (Thread->WaitBlock == NULL);
  616. RtlFreeHeap( CsrHeap, 0, Thread );
  617. }
  618. //
  619. // NOTE: The process structure lock must be held while calling this routine.
  620. //
  621. VOID
  622. CsrInsertThread(
  623. IN PCSR_PROCESS Process,
  624. IN PCSR_THREAD Thread)
  625. {
  626. ULONG i;
  627. ASSERT(ProcessStructureListLocked());
  628. InsertTailList(&Process->ThreadList, &Thread->Link);
  629. Process->ThreadCount++;
  630. i = THREAD_ID_TO_HASH(Thread->ClientId.UniqueThread);
  631. InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks);
  632. }
  633. //
  634. // NOTE: The process structure lock must be held while calling this routine.
  635. //
  636. VOID
  637. CsrRemoveThread(
  638. IN PCSR_THREAD Thread)
  639. {
  640. ASSERT(ProcessStructureListLocked());
  641. RemoveEntryList(&Thread->Link);
  642. Thread->Process->ThreadCount--;
  643. if (Thread->HashLinks.Flink) {
  644. RemoveEntryList(&Thread->HashLinks);
  645. }
  646. //
  647. // If this is the last thread, then make sure we undo the reference
  648. // that this thread had on the process.
  649. //
  650. if (Thread->Process->ThreadCount == 0) {
  651. if (!(Thread->Process->Flags & CSR_PROCESS_LASTTHREADOK)) {
  652. Thread->Process->Flags |= CSR_PROCESS_LASTTHREADOK;
  653. CsrLockedDereferenceProcess(Thread->Process);
  654. }
  655. }
  656. Thread->Flags |= CSR_THREAD_TERMINATING;
  657. }
  658. NTSTATUS
  659. CsrLockProcessByClientId(
  660. IN HANDLE UniqueProcessId,
  661. OUT PCSR_PROCESS *Process
  662. )
  663. {
  664. NTSTATUS Status;
  665. PLIST_ENTRY ListHead, ListNext;
  666. PCSR_PROCESS ProcessPtr;
  667. AcquireProcessStructureLock();
  668. ASSERT( Process != NULL );
  669. *Process = NULL;
  670. Status = STATUS_UNSUCCESSFUL;
  671. ListHead = &CsrRootProcess->ListLink;
  672. ListNext = ListHead;
  673. do {
  674. ProcessPtr = CONTAINING_RECORD( ListNext, CSR_PROCESS, ListLink );
  675. if (ProcessPtr->ClientId.UniqueProcess == UniqueProcessId) {
  676. Status = STATUS_SUCCESS;
  677. break;
  678. }
  679. ListNext = ListNext->Flink;
  680. } while (ListNext != ListHead);
  681. if (NT_SUCCESS( Status )) {
  682. CsrLockedReferenceProcess(ProcessPtr);
  683. *Process = ProcessPtr;
  684. }
  685. else {
  686. ReleaseProcessStructureLock();
  687. }
  688. return( Status );
  689. }
  690. NTSTATUS
  691. CsrUnlockProcess(
  692. IN PCSR_PROCESS Process
  693. )
  694. {
  695. CsrLockedDereferenceProcess( Process );
  696. ReleaseProcessStructureLock();
  697. return( STATUS_SUCCESS );
  698. }
  699. NTSTATUS
  700. CsrLockThreadByClientId(
  701. IN HANDLE UniqueThreadId,
  702. OUT PCSR_THREAD *Thread)
  703. {
  704. NTSTATUS Status;
  705. ULONG Index;
  706. PLIST_ENTRY ListHead, ListNext;
  707. PCSR_THREAD ThreadPtr;
  708. AcquireProcessStructureLock();
  709. ASSERT(Thread != NULL);
  710. Index = THREAD_ID_TO_HASH(UniqueThreadId);
  711. ListHead = &CsrThreadHashTable[Index];
  712. ListNext = ListHead->Flink;
  713. while (ListNext != ListHead) {
  714. ThreadPtr = CONTAINING_RECORD( ListNext, CSR_THREAD, HashLinks );
  715. if (ThreadPtr->ClientId.UniqueThread == UniqueThreadId &&
  716. !(ThreadPtr->Flags & CSR_THREAD_DESTROYED)) {
  717. break;
  718. }
  719. ListNext = ListNext->Flink;
  720. }
  721. if (ListNext != ListHead) {
  722. *Thread = ThreadPtr;
  723. Status = STATUS_SUCCESS;
  724. CsrLockedReferenceThread(ThreadPtr);
  725. } else {
  726. Status = STATUS_UNSUCCESSFUL;
  727. ReleaseProcessStructureLock();
  728. }
  729. return Status;
  730. }
  731. //
  732. // NOTE: The process structure lock must be held while calling this routine.
  733. //
  734. NTSTATUS
  735. CsrUnlockThread(
  736. IN PCSR_THREAD Thread)
  737. {
  738. ASSERT(ProcessStructureListLocked());
  739. CsrLockedDereferenceThread(Thread);
  740. ReleaseProcessStructureLock();
  741. return STATUS_SUCCESS;
  742. }
  743. //
  744. // NOTE: The process structure lock must be held while calling this routine.
  745. //
  746. PCSR_THREAD
  747. CsrLocateThreadByClientId(
  748. OUT PCSR_PROCESS *Process OPTIONAL,
  749. IN PCLIENT_ID ClientId)
  750. {
  751. ULONG Index;
  752. PLIST_ENTRY ListHead, ListNext;
  753. PCSR_THREAD Thread;
  754. ASSERT(ProcessStructureListLocked());
  755. Index = THREAD_ID_TO_HASH(ClientId->UniqueThread);
  756. if (ARGUMENT_PRESENT(Process)) {
  757. *Process = NULL;
  758. }
  759. ListHead = &CsrThreadHashTable[Index];
  760. ListNext = ListHead->Flink;
  761. while (ListNext != ListHead) {
  762. Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, HashLinks );
  763. if (Thread->ClientId.UniqueThread == ClientId->UniqueThread &&
  764. Thread->ClientId.UniqueProcess == ClientId->UniqueProcess) {
  765. if (ARGUMENT_PRESENT(Process)) {
  766. *Process = Thread->Process;
  767. }
  768. return Thread;
  769. }
  770. ListNext = ListNext->Flink;
  771. }
  772. return NULL;
  773. }
  774. //
  775. // NOTE: The process structure lock must be held while calling this routine.
  776. //
  777. PCSR_THREAD
  778. CsrLocateServerThread(
  779. IN PCLIENT_ID ClientId)
  780. {
  781. PLIST_ENTRY ListHead, ListNext;
  782. PCSR_THREAD Thread;
  783. ListHead = &CsrRootProcess->ThreadList;
  784. ListNext = ListHead->Flink;
  785. while (ListNext != ListHead) {
  786. Thread = CONTAINING_RECORD( ListNext, CSR_THREAD, Link );
  787. if (Thread->ClientId.UniqueThread == ClientId->UniqueThread) {
  788. return Thread;
  789. }
  790. ListNext = ListNext->Flink;
  791. }
  792. return NULL;
  793. }
  794. BOOLEAN
  795. CsrImpersonateClient(
  796. IN PCSR_THREAD Thread)
  797. {
  798. NTSTATUS Status;
  799. PCSR_THREAD CallingThread;
  800. CallingThread = CSR_SERVER_QUERYCLIENTTHREAD();
  801. if (Thread == NULL) {
  802. Thread = CallingThread;
  803. if (Thread == NULL) {
  804. return FALSE;
  805. }
  806. }
  807. Status = NtImpersonateThread(NtCurrentThread(),
  808. Thread->ThreadHandle,
  809. &CsrSecurityQos);
  810. if (!NT_SUCCESS(Status)) {
  811. IF_DEBUG {
  812. DbgPrint("CSRSS: Can't impersonate client thread - Status = %lx\n",
  813. Status);
  814. if (Status != STATUS_BAD_IMPERSONATION_LEVEL) {
  815. DbgBreakPoint();
  816. }
  817. }
  818. return FALSE;
  819. }
  820. //
  821. // Keep track of recursion by printer drivers.
  822. //
  823. if (CallingThread != NULL) {
  824. ++CallingThread->ImpersonateCount;
  825. }
  826. return TRUE;
  827. }
  828. BOOLEAN
  829. CsrRevertToSelf(
  830. VOID)
  831. {
  832. HANDLE NewToken;
  833. NTSTATUS Status;
  834. PCSR_THREAD CallingThread;
  835. CallingThread = CSR_SERVER_QUERYCLIENTTHREAD();
  836. //
  837. // Keep track of recursion by printer drivers.
  838. //
  839. if (CallingThread != NULL) {
  840. if (CallingThread->ImpersonateCount == 0) {
  841. IF_DEBUG {
  842. DbgPrint( "CSRSS: CsrRevertToSelf called while not impersonating\n" );
  843. DbgBreakPoint();
  844. }
  845. return FALSE;
  846. }
  847. if (--CallingThread->ImpersonateCount > 0) {
  848. return TRUE;
  849. }
  850. }
  851. NewToken = NULL;
  852. Status = NtSetInformationThread(NtCurrentThread(),
  853. ThreadImpersonationToken,
  854. (PVOID)&NewToken,
  855. (ULONG)sizeof(HANDLE));
  856. ASSERT(NT_SUCCESS(Status));
  857. return NT_SUCCESS(Status);
  858. }
  859. /*++
  860. Routine Description:
  861. This function must be called by client DLL's whenever they create a
  862. thread that runs in the context of CSR. This function is not called
  863. for server threads that are attached to a client in the "server
  864. handle" field. This function replaces the old static thread tables.
  865. Arguments:
  866. ThreadHandle - Supplies a handle to the thread.
  867. ClientId - Supplies the address of the thread's client id.
  868. Flags - Not Used.
  869. Return Value:
  870. Returns the address of the static server thread created by this
  871. function.
  872. --*/
  873. PVOID
  874. CsrAddStaticServerThread(
  875. IN HANDLE ThreadHandle,
  876. IN PCLIENT_ID ClientId,
  877. IN ULONG Flags
  878. )
  879. {
  880. PCSR_THREAD Thread;
  881. AcquireProcessStructureLock();
  882. ASSERT(CsrRootProcess != NULL);
  883. Thread = CsrAllocateThread(CsrRootProcess);
  884. if (Thread) {
  885. Thread->ThreadHandle = ThreadHandle;
  886. ProtectHandle(ThreadHandle);
  887. Thread->ClientId = *ClientId;
  888. Thread->Flags = Flags;
  889. InsertTailList(&CsrRootProcess->ThreadList, &Thread->Link);
  890. CsrRootProcess->ThreadCount++;
  891. }
  892. ReleaseProcessStructureLock();
  893. return (PVOID)Thread;
  894. }
  895. NTSTATUS
  896. CsrExecServerThread(
  897. IN PUSER_THREAD_START_ROUTINE StartAddress,
  898. IN ULONG Flags
  899. )
  900. {
  901. PCSR_THREAD Thread;
  902. NTSTATUS Status;
  903. HANDLE ThreadHandle;
  904. CLIENT_ID ClientId;
  905. AcquireProcessStructureLock();
  906. ASSERT(CsrRootProcess != NULL);
  907. Thread = CsrAllocateThread(CsrRootProcess);
  908. if (Thread == NULL) {
  909. Status = STATUS_NO_MEMORY;
  910. goto Exit;
  911. }
  912. Status = RtlCreateUserThread(NtCurrentProcess(),
  913. NULL,
  914. FALSE,
  915. 0,
  916. 0,
  917. 0,
  918. (PUSER_THREAD_START_ROUTINE)StartAddress,
  919. NULL,
  920. &ThreadHandle,
  921. &ClientId);
  922. if (NT_SUCCESS(Status)) {
  923. Thread->ThreadHandle = ThreadHandle;
  924. ProtectHandle(ThreadHandle);
  925. Thread->ClientId = ClientId;
  926. Thread->Flags = Flags;
  927. InsertTailList(&CsrRootProcess->ThreadList, &Thread->Link);
  928. CsrRootProcess->ThreadCount++;
  929. } else {
  930. CsrDeallocateThread(Thread);
  931. }
  932. Exit:
  933. ReleaseProcessStructureLock();
  934. return Status;
  935. }
  936. VOID
  937. CsrReferenceThread(
  938. PCSR_THREAD t
  939. )
  940. {
  941. ASSERT (t != NULL);
  942. AcquireProcessStructureLock();
  943. ASSERT((t->Flags & CSR_THREAD_DESTROYED) == 0);
  944. ASSERT(t->ReferenceCount != 0);
  945. t->ReferenceCount++;
  946. ReleaseProcessStructureLock();
  947. }
  948. VOID
  949. CsrProcessRefcountZero(
  950. PCSR_PROCESS p
  951. )
  952. {
  953. ASSERT (p != NULL);
  954. CsrRemoveProcess(p);
  955. if (p->NtSession) {
  956. CsrDereferenceNtSession(p->NtSession,0);
  957. }
  958. //
  959. // process might not have made it through dll init routine.
  960. //
  961. if ( p->ClientPort ) {
  962. NtClose(p->ClientPort);
  963. }
  964. NtClose(p->ProcessHandle );
  965. CsrDeallocateProcess(p);
  966. }
  967. VOID
  968. CsrDereferenceProcess(
  969. PCSR_PROCESS p
  970. )
  971. {
  972. LONG LockCount;
  973. ASSERT (p != NULL);
  974. AcquireProcessStructureLock();
  975. LockCount = --(p->ReferenceCount);
  976. ASSERT(LockCount >= 0);
  977. if ( !LockCount ) {
  978. CsrProcessRefcountZero(p);
  979. } else {
  980. ReleaseProcessStructureLock();
  981. }
  982. }
  983. VOID
  984. CsrThreadRefcountZero(
  985. PCSR_THREAD t
  986. )
  987. {
  988. PCSR_PROCESS p;
  989. NTSTATUS Status;
  990. ASSERT (t != NULL);
  991. p = t->Process;
  992. ASSERT (p != NULL);
  993. CsrRemoveThread(t);
  994. ReleaseProcessStructureLock();
  995. UnProtectHandle(t->ThreadHandle);
  996. Status = NtClose(t->ThreadHandle);
  997. ASSERT(NT_SUCCESS(Status));
  998. CsrDeallocateThread(t);
  999. CsrDereferenceProcess(p);
  1000. }
  1001. ULONG
  1002. CsrDereferenceThread(
  1003. PCSR_THREAD t)
  1004. {
  1005. ULONG LockCount;
  1006. ASSERT (t != NULL);
  1007. AcquireProcessStructureLock();
  1008. ASSERT(t->ReferenceCount > 0);
  1009. LockCount = --(t->ReferenceCount);
  1010. if (!LockCount) {
  1011. CsrThreadRefcountZero(t);
  1012. } else {
  1013. ReleaseProcessStructureLock();
  1014. }
  1015. return LockCount;
  1016. }
  1017. VOID
  1018. CsrLockedReferenceProcess(
  1019. PCSR_PROCESS p)
  1020. {
  1021. ASSERT (p != NULL);
  1022. p->ReferenceCount++;
  1023. }
  1024. VOID
  1025. CsrLockedReferenceThread(
  1026. PCSR_THREAD t)
  1027. {
  1028. ASSERT (t != NULL);
  1029. t->ReferenceCount++;
  1030. }
  1031. VOID
  1032. CsrLockedDereferenceProcess(
  1033. PCSR_PROCESS p)
  1034. {
  1035. LONG LockCount;
  1036. ASSERT (p != NULL);
  1037. LockCount = --(p->ReferenceCount);
  1038. ASSERT(LockCount >= 0);
  1039. if (!LockCount) {
  1040. CsrProcessRefcountZero(p);
  1041. AcquireProcessStructureLock();
  1042. }
  1043. }
  1044. VOID
  1045. CsrLockedDereferenceThread(
  1046. PCSR_THREAD t
  1047. )
  1048. {
  1049. LONG LockCount;
  1050. ASSERT (t != NULL);
  1051. LockCount = --(t->ReferenceCount);
  1052. ASSERT(LockCount >= 0);
  1053. if ( !LockCount ) {
  1054. CsrThreadRefcountZero(t);
  1055. AcquireProcessStructureLock();
  1056. }
  1057. }
  1058. //
  1059. // This routine will shutdown processes so either a logoff or a shutdown can
  1060. // occur. This simply calls the shutdown process handlers for each .dll until
  1061. // one .dll recognizes this process and will shut it down. Only the processes
  1062. // with the passed sid are shutdown.
  1063. //
  1064. NTSTATUS
  1065. CsrShutdownProcesses(
  1066. PLUID CallerLuid,
  1067. ULONG Flags
  1068. )
  1069. {
  1070. PLIST_ENTRY ListHead, ListNext;
  1071. PCSR_PROCESS Process;
  1072. ULONG i;
  1073. PCSR_SERVER_DLL LoadedServerDll;
  1074. ULONG Command;
  1075. BOOLEAN fFirstPass;
  1076. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1077. AcquireProcessStructureLock();
  1078. //
  1079. // Mark the root process as system context.
  1080. //
  1081. CsrRootProcess->ShutdownFlags |= SHUTDOWN_SYSTEMCONTEXT;
  1082. //
  1083. // Clear all the bits indicating that shutdown has visited the existing
  1084. // processes.
  1085. //
  1086. ListHead = &CsrRootProcess->ListLink;
  1087. ListNext = ListHead->Flink;
  1088. while (ListNext != ListHead) {
  1089. Process = CONTAINING_RECORD(ListNext, CSR_PROCESS, ListLink);
  1090. Process->Flags &= ~CSR_PROCESS_SHUTDOWNSKIP;
  1091. Process->ShutdownFlags = 0;
  1092. ListNext = ListNext->Flink;
  1093. }
  1094. CsrpSetToShutdownPriority();
  1095. while (TRUE) {
  1096. //
  1097. // Find the next process to shutdown.
  1098. //
  1099. Process = FindProcessForShutdown(CallerLuid);
  1100. if (Process == NULL) {
  1101. ReleaseProcessStructureLock();
  1102. Status = STATUS_SUCCESS;
  1103. break;
  1104. }
  1105. CsrLockedReferenceProcess(Process);
  1106. fFirstPass = TRUE;
  1107. TryAgain:
  1108. for (i = 0; i < CSR_MAX_SERVER_DLL; i++) {
  1109. LoadedServerDll = CsrLoadedServerDll[i];
  1110. if (LoadedServerDll && LoadedServerDll->ShutdownProcessRoutine) {
  1111. //
  1112. // Release process structure lock before calling off.
  1113. // CSR_PROCESS structure is still reference counted.
  1114. //
  1115. ReleaseProcessStructureLock();
  1116. Command = (*LoadedServerDll->ShutdownProcessRoutine)(Process,
  1117. Flags,
  1118. fFirstPass);
  1119. AcquireProcessStructureLock();
  1120. if (Command == SHUTDOWN_KNOWN_PROCESS) {
  1121. //
  1122. // Process structure is unlocked.
  1123. //
  1124. break;
  1125. } else if (Command == SHUTDOWN_UNKNOWN_PROCESS) {
  1126. //
  1127. // Process structure is locked.
  1128. //
  1129. continue;
  1130. } else if (Command == SHUTDOWN_CANCEL) {
  1131. #if DBG
  1132. if (Flags & 4) {
  1133. DbgPrint("Process %x cancelled forced shutdown\n",
  1134. Process->ClientId.UniqueProcess);
  1135. DbgBreakPoint();
  1136. }
  1137. #endif
  1138. //
  1139. // Unlock process structure.
  1140. //
  1141. ReleaseProcessStructureLock();
  1142. Status = STATUS_CANCELLED;
  1143. goto ExitLoop;
  1144. }
  1145. }
  1146. }
  1147. //
  1148. // No subsystem has an exact match. Now go through them again and
  1149. // let them know there was no exact match. Some .dll should terminate
  1150. // it for us (most likely, console).
  1151. //
  1152. if (fFirstPass && Command == SHUTDOWN_UNKNOWN_PROCESS) {
  1153. fFirstPass = FALSE;
  1154. goto TryAgain;
  1155. }
  1156. //
  1157. // Dereference this process structure if nothing knows about it.
  1158. //
  1159. if (i == CSR_MAX_SERVER_DLL) {
  1160. CsrLockedDereferenceProcess(Process);
  1161. }
  1162. }
  1163. ExitLoop:
  1164. CsrpSetToNormalPriority();
  1165. return Status;
  1166. }
  1167. PCSR_PROCESS
  1168. FindProcessForShutdown(
  1169. PLUID CallerLuid)
  1170. {
  1171. LUID ProcessLuid;
  1172. LUID SystemLuid = SYSTEM_LUID;
  1173. PLIST_ENTRY ListHead, ListNext;
  1174. PCSR_PROCESS Process;
  1175. PCSR_PROCESS ProcessT = NULL;
  1176. PCSR_THREAD Thread;
  1177. ULONG dwLevel = 0;
  1178. NTSTATUS Status;
  1179. ListHead = &CsrRootProcess->ListLink;
  1180. ListNext = ListHead->Flink;
  1181. while (ListNext != ListHead) {
  1182. Process = CONTAINING_RECORD(ListNext, CSR_PROCESS, ListLink);
  1183. ListNext = ListNext->Flink;
  1184. //
  1185. // If we've visited this process already, then skip it.
  1186. //
  1187. if (Process->Flags & CSR_PROCESS_SHUTDOWNSKIP) {
  1188. continue;
  1189. }
  1190. //
  1191. // See if this process is running under the passed sid. If not, mark
  1192. // it as visited and continue.
  1193. //
  1194. Status = CsrGetProcessLuid(Process->ProcessHandle, &ProcessLuid);
  1195. if (Status == STATUS_ACCESS_DENIED && Process->ThreadCount > 0) {
  1196. //
  1197. // Impersonate one of the threads and try again.
  1198. //
  1199. Thread = CONTAINING_RECORD(Process->ThreadList.Flink, CSR_THREAD, Link);
  1200. if (CsrImpersonateClient(Thread)) {
  1201. Status = CsrGetProcessLuid(NULL, &ProcessLuid);
  1202. CsrRevertToSelf();
  1203. } else {
  1204. Status = STATUS_BAD_IMPERSONATION_LEVEL;
  1205. }
  1206. }
  1207. if (!NT_SUCCESS(Status)) {
  1208. //
  1209. // We don't have access to this process's luid, so skip it.
  1210. //
  1211. Process->Flags |= CSR_PROCESS_SHUTDOWNSKIP;
  1212. continue;
  1213. }
  1214. //
  1215. // Is it equal to the system context luid? If so, we want to
  1216. // remember this because we don't terminate this process: we only
  1217. // notify them.
  1218. //
  1219. if (RtlEqualLuid(&ProcessLuid, &SystemLuid)) {
  1220. Process->ShutdownFlags |= SHUTDOWN_SYSTEMCONTEXT;
  1221. } else {
  1222. //
  1223. // See if this process's luid is the same as the luid we're supposed
  1224. // to shut down (CallerSid).
  1225. //
  1226. if (!RtlEqualLuid(&ProcessLuid, CallerLuid)) {
  1227. //
  1228. // If not equal to either, mark it as such.
  1229. //
  1230. Process->ShutdownFlags |= SHUTDOWN_OTHERCONTEXT;
  1231. }
  1232. }
  1233. if (Process->ShutdownLevel > dwLevel || ProcessT == NULL) {
  1234. dwLevel = Process->ShutdownLevel;
  1235. ProcessT = Process;
  1236. }
  1237. }
  1238. if (ProcessT != NULL) {
  1239. ProcessT->Flags |= CSR_PROCESS_SHUTDOWNSKIP;
  1240. return ProcessT;
  1241. }
  1242. return NULL;
  1243. }
  1244. NTSTATUS
  1245. CsrGetProcessLuid(
  1246. HANDLE ProcessHandle,
  1247. PLUID LuidProcess
  1248. )
  1249. {
  1250. HANDLE UserToken = NULL;
  1251. PTOKEN_STATISTICS pStats;
  1252. ULONG BytesRequired;
  1253. NTSTATUS Status, CloseStatus;
  1254. if (ProcessHandle == NULL) {
  1255. //
  1256. // Check for a thread token first
  1257. //
  1258. Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_QUERY, FALSE,
  1259. &UserToken);
  1260. if (!NT_SUCCESS(Status)) {
  1261. if (Status != STATUS_NO_TOKEN)
  1262. return Status;
  1263. //
  1264. // No thread token, go to the process
  1265. //
  1266. ProcessHandle = NtCurrentProcess();
  1267. UserToken = NULL;
  1268. }
  1269. }
  1270. if (UserToken == NULL) {
  1271. Status = NtOpenProcessToken(ProcessHandle, TOKEN_QUERY, &UserToken);
  1272. if (!NT_SUCCESS(Status))
  1273. return Status;
  1274. }
  1275. Status = NtQueryInformationToken(
  1276. UserToken, // Handle
  1277. TokenStatistics, // TokenInformationClass
  1278. NULL, // TokenInformation
  1279. 0, // TokenInformationLength
  1280. &BytesRequired // ReturnLength
  1281. );
  1282. if (Status != STATUS_BUFFER_TOO_SMALL) {
  1283. NtClose(UserToken);
  1284. return Status;
  1285. }
  1286. //
  1287. // Allocate space for the user info
  1288. //
  1289. pStats = (PTOKEN_STATISTICS)RtlAllocateHeap(CsrHeap, MAKE_TAG( TMP_TAG ), BytesRequired);
  1290. if (pStats == NULL) {
  1291. NtClose(UserToken);
  1292. return Status;
  1293. }
  1294. //
  1295. // Read in the user info
  1296. //
  1297. Status = NtQueryInformationToken(
  1298. UserToken, // Handle
  1299. TokenStatistics, // TokenInformationClass
  1300. pStats, // TokenInformation
  1301. BytesRequired, // TokenInformationLength
  1302. &BytesRequired // ReturnLength
  1303. );
  1304. //
  1305. // We're finished with the token handle
  1306. //
  1307. CloseStatus = NtClose(UserToken);
  1308. ASSERT(NT_SUCCESS(CloseStatus));
  1309. //
  1310. // Return the authentication LUID
  1311. //
  1312. *LuidProcess = pStats->AuthenticationId;
  1313. RtlFreeHeap(CsrHeap, 0, pStats);
  1314. return Status;
  1315. }
  1316. VOID
  1317. CsrSetCallingSpooler(
  1318. BOOLEAN fSet)
  1319. {
  1320. //
  1321. // Obsolete function that may be called by third part drivers.
  1322. //
  1323. UNREFERENCED_PARAMETER(fSet);
  1324. }
  1325. //
  1326. // This routine creates a process based on a message passed in to sb port.
  1327. // Used by smss to have Posix and OS/2 apps created in the appropriate
  1328. // (terminal server) session.
  1329. //
  1330. BOOLEAN
  1331. CsrSbCreateProcess(
  1332. IN OUT PSBAPIMSG m
  1333. )
  1334. {
  1335. NTSTATUS Status;
  1336. RTL_USER_PROCESS_INFORMATION ProcessInformation;
  1337. PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  1338. PROCESS_SESSION_INFORMATION ProcessInfo;
  1339. PSBCREATEPROCESS a = &(m->u.CreateProcess);
  1340. HANDLE RemoteProcess = NULL;
  1341. CLIENT_ID RemoteClientId;
  1342. UNICODE_STRING ImageFileName, DefaultLibPath, CurrentDirectory, CommandLine;
  1343. PVOID DefaultEnvironment = NULL;
  1344. PROCESS_BASIC_INFORMATION ProcInfo;
  1345. OBJECT_ATTRIBUTES ObjA;
  1346. RtlInitUnicodeString(&ImageFileName,NULL);
  1347. RtlInitUnicodeString(&DefaultLibPath,NULL);
  1348. RtlInitUnicodeString(&CurrentDirectory,NULL);
  1349. RtlInitUnicodeString(&CommandLine,NULL);
  1350. Status = NtQueryInformationProcess(NtCurrentProcess(),
  1351. ProcessBasicInformation,
  1352. &ProcInfo,
  1353. sizeof(ProcInfo),
  1354. NULL
  1355. );
  1356. if ( !NT_SUCCESS( Status ) ) {
  1357. DbgPrint( "CSRSS: CsrSrvCreateProcess: NtQueryInformationProcess failed - Status = %lx\n", Status );
  1358. goto Done;
  1359. }
  1360. InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
  1361. RemoteClientId.UniqueProcess = (HANDLE)ProcInfo.InheritedFromUniqueProcessId;
  1362. RemoteClientId.UniqueThread = NULL;
  1363. Status = NtOpenProcess(&RemoteProcess,
  1364. PROCESS_ALL_ACCESS,
  1365. &ObjA,
  1366. &RemoteClientId);
  1367. if ( !NT_SUCCESS( Status ) ) {
  1368. DbgPrint( "CSRSS: CsrSrvCreateProcess: NtOpenProcess failed - Status = %lx\n", Status );
  1369. goto Done;
  1370. }
  1371. //
  1372. // Read pointer parameters from calling process's virtual memory
  1373. //
  1374. Status = ReadUnicodeString(RemoteProcess,a->i.ImageFileName,&ImageFileName);
  1375. if ( !NT_SUCCESS( Status ) ) {
  1376. DbgPrint( "CSRSS: CsrSrvCreateProcess: ReadUnicodeString ImageFileName failed - Status = %lx\n", Status );
  1377. goto Done;
  1378. }
  1379. Status = ReadUnicodeString(RemoteProcess,a->i.DefaultLibPath,&DefaultLibPath);
  1380. if ( !NT_SUCCESS( Status ) ) {
  1381. DbgPrint( "CSRSS: CsrSrvCreateProcess: ReadUnicodeString DefaultLibPath failed - Status = %lx\n", Status );
  1382. goto Done;
  1383. }
  1384. Status = ReadUnicodeString(RemoteProcess,a->i.CurrentDirectory,&CurrentDirectory);
  1385. if ( !NT_SUCCESS( Status ) ) {
  1386. DbgPrint( "CSRSS: CsrSrvCreateProcess: ReadUnicodeString CurrentDirectory failed - Status = %lx\n", Status );
  1387. goto Done;
  1388. }
  1389. Status = ReadUnicodeString(RemoteProcess,a->i.CommandLine,&CommandLine);
  1390. if ( !NT_SUCCESS( Status ) ) {
  1391. DbgPrint( "CSRSS: CsrSrvCreateProcess: ReadUnicodeString CommandLine failed - Status = %lx\n", Status );
  1392. goto Done;
  1393. }
  1394. //
  1395. // Copy our environment to be used by new process
  1396. //
  1397. Status = RtlCreateEnvironment(TRUE, &DefaultEnvironment);
  1398. if (!NT_SUCCESS( Status )) {
  1399. DbgPrint( "CSRSS: CsrSrvCreateProcess: Can't create environemnt\n");
  1400. goto Done;
  1401. }
  1402. Status = RtlCreateProcessParameters( &ProcessParameters,
  1403. &ImageFileName,
  1404. DefaultLibPath.Length == 0 ?
  1405. NULL : &DefaultLibPath,
  1406. &CurrentDirectory,
  1407. &CommandLine,
  1408. DefaultEnvironment,
  1409. NULL,
  1410. NULL,
  1411. NULL,
  1412. NULL
  1413. );
  1414. if ( !NT_SUCCESS( Status ) ) {
  1415. DbgPrint( "CSRSS: CsrSrvCreateProcess: RtlCreateProcessParameters failed - Status = %lx\n", Status );
  1416. goto Done;
  1417. }
  1418. if (a->i.Flags & SMP_DEBUG_FLAG) {
  1419. ProcessParameters->DebugFlags = TRUE;
  1420. }
  1421. else {
  1422. ProcessParameters->DebugFlags = a->i.DefaultDebugFlags;
  1423. }
  1424. if ( a->i.Flags & SMP_SUBSYSTEM_FLAG ) {
  1425. ProcessParameters->Flags |= RTL_USER_PROC_RESERVE_1MB;
  1426. }
  1427. ProcessInformation.Length = sizeof( RTL_USER_PROCESS_INFORMATION );
  1428. Status = RtlCreateUserProcess( &ImageFileName,
  1429. OBJ_CASE_INSENSITIVE,
  1430. ProcessParameters,
  1431. NULL,
  1432. NULL,
  1433. RemoteProcess, // set smss as the parent
  1434. FALSE,
  1435. NULL,
  1436. NULL,
  1437. &ProcessInformation
  1438. );
  1439. RtlDestroyProcessParameters( ProcessParameters );
  1440. if ( !NT_SUCCESS( Status ) ) {
  1441. DbgPrint( "CSRSS: CsrSrvCreateProcess: RtlCreateUserProcess failed - Status = %lx\n", Status );
  1442. goto Done;
  1443. }
  1444. if (IsTerminalServer()) {
  1445. //
  1446. // Set the MuSessionId in the PEB of the new process
  1447. //
  1448. ProcessInfo.SessionId = NtCurrentPeb()->SessionId;
  1449. if (ProcessInfo.SessionId) {
  1450. PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
  1451. UNICODE_STRING UnicodeString;
  1452. OBJECT_ATTRIBUTES Attributes;
  1453. HANDLE DirectoryHandle = NULL;
  1454. WCHAR szSessionString[MAX_SESSION_PATH];
  1455. //
  1456. // Change the devmap of the process to per session.
  1457. //
  1458. swprintf(szSessionString, L"%ws\\%ld%ws", SESSION_ROOT, NtCurrentPeb()->SessionId, DOSDEVICES);
  1459. RtlInitUnicodeString(&UnicodeString, szSessionString);
  1460. InitializeObjectAttributes(&Attributes,
  1461. &UnicodeString,
  1462. OBJ_CASE_INSENSITIVE,
  1463. NULL,
  1464. NULL);
  1465. Status = NtOpenDirectoryObject(&DirectoryHandle,
  1466. DIRECTORY_ALL_ACCESS,
  1467. &Attributes);
  1468. if (!NT_SUCCESS(Status)) {
  1469. DbgPrint("CSRSS: NtOpenDirectoryObject failed in CsrSbCreateProcess - status = %lx\n", Status);
  1470. goto Done;
  1471. }
  1472. ProcessDeviceMapInfo.Set.DirectoryHandle = DirectoryHandle;
  1473. Status = NtSetInformationProcess(ProcessInformation.Process,
  1474. ProcessDeviceMap,
  1475. &ProcessDeviceMapInfo.Set,
  1476. sizeof(ProcessDeviceMapInfo.Set));
  1477. if (!NT_SUCCESS( Status )) {
  1478. DbgPrint("CSRSS: NtSetInformationProcess failed in CsrSbCreateProcess - status = %lx\n", Status);
  1479. if (DirectoryHandle) {
  1480. NtClose(DirectoryHandle);
  1481. }
  1482. goto Done;
  1483. }
  1484. if (DirectoryHandle) {
  1485. NtClose(DirectoryHandle);
  1486. }
  1487. }
  1488. Status = NtSetInformationProcess( ProcessInformation.Process,
  1489. ProcessSessionInformation,
  1490. &ProcessInfo, sizeof( ProcessInfo ));
  1491. if ( !NT_SUCCESS( Status ) ) {
  1492. DbgPrint( "CSRSS: CsrSrvCreateProcess: NtSetInformationProcess failed - Status = %lx\n", Status );
  1493. goto Done;
  1494. }
  1495. }
  1496. if (!(a->i.Flags & SMP_DONT_START)) {
  1497. if (ProcessInformation.ImageInformation.SubSystemType !=
  1498. IMAGE_SUBSYSTEM_NATIVE
  1499. ) {
  1500. NtTerminateProcess( ProcessInformation.Process,
  1501. STATUS_INVALID_IMAGE_FORMAT
  1502. );
  1503. NtWaitForSingleObject( ProcessInformation.Thread, FALSE, NULL );
  1504. NtClose( ProcessInformation.Thread );
  1505. NtClose( ProcessInformation.Process );
  1506. Status = STATUS_INVALID_IMAGE_FORMAT;
  1507. goto Done;
  1508. }
  1509. Status = NtResumeThread( ProcessInformation.Thread, NULL );
  1510. if (!NT_SUCCESS(Status)) {
  1511. DbgPrint( "CSRSS: CsrSrvCreateProcess - NtResumeThread failed Status %lx\n",Status );
  1512. goto Done;
  1513. }
  1514. if (!(a->i.Flags & SMP_ASYNC_FLAG)) {
  1515. NtWaitForSingleObject( ProcessInformation.Thread, FALSE, NULL );
  1516. }
  1517. NtClose( ProcessInformation.Thread );
  1518. NtClose( ProcessInformation.Process );
  1519. }
  1520. //
  1521. // Copy output parameters to message
  1522. //
  1523. a->o.SubSystemType = ProcessInformation.ImageInformation.SubSystemType;
  1524. a->o.ClientId.UniqueProcess = ProcessInformation.ClientId.UniqueProcess;
  1525. a->o.ClientId.UniqueThread = ProcessInformation.ClientId.UniqueThread;
  1526. //
  1527. // Convert handles to caller's process
  1528. //
  1529. Status = NtDuplicateObject( NtCurrentProcess(),
  1530. ProcessInformation.Process,
  1531. RemoteProcess,
  1532. &a->o.Process,
  1533. 0,
  1534. FALSE,
  1535. DUPLICATE_SAME_ACCESS
  1536. );
  1537. if ( !NT_SUCCESS(Status) ) {
  1538. DbgPrint( "CSRSS: CsrSrvCreateProcess: NtDuplicateObject failed for process - Status = %lx\n", Status );
  1539. goto Done;
  1540. }
  1541. Status = NtDuplicateObject( NtCurrentProcess(),
  1542. ProcessInformation.Thread,
  1543. RemoteProcess,
  1544. &a->o.Thread,
  1545. 0,
  1546. FALSE,
  1547. DUPLICATE_SAME_ACCESS
  1548. );
  1549. if ( !NT_SUCCESS(Status) ) {
  1550. DbgPrint( "CSRSS: CsrSrvCreateProcess: NtDuplicateObject failed for thread - Status = %lx\n", Status );
  1551. goto Done;
  1552. }
  1553. Done:
  1554. if (NULL != ImageFileName.Buffer)
  1555. RtlFreeHeap(CsrHeap,0,ImageFileName.Buffer);
  1556. if (NULL != DefaultLibPath.Buffer)
  1557. RtlFreeHeap(CsrHeap,0,DefaultLibPath.Buffer);
  1558. if (NULL != CurrentDirectory.Buffer)
  1559. RtlFreeHeap(CsrHeap,0,CurrentDirectory.Buffer);
  1560. if (NULL != CommandLine.Buffer)
  1561. RtlFreeHeap(CsrHeap,0,CommandLine.Buffer);
  1562. if (NULL != RemoteProcess)
  1563. NtClose(RemoteProcess);
  1564. m->ReturnedStatus = Status;
  1565. return TRUE;
  1566. }
  1567. //
  1568. // This routine will copy a UNICODE_STRING from a remote process to this one
  1569. //
  1570. NTSTATUS
  1571. ReadUnicodeString(HANDLE ProcessHandle,
  1572. PUNICODE_STRING RemoteString,
  1573. PUNICODE_STRING LocalString
  1574. )
  1575. {
  1576. PWSTR Buffer = NULL;
  1577. NTSTATUS Status;
  1578. RtlInitUnicodeString(LocalString, NULL);
  1579. if (NULL != RemoteString) {
  1580. Status = NtReadVirtualMemory(ProcessHandle,
  1581. RemoteString,
  1582. LocalString,
  1583. sizeof(UNICODE_STRING),
  1584. NULL);
  1585. if ( !NT_SUCCESS( Status ) ) {
  1586. DbgPrint( "CSRSS: ReadUnicodeString: NtReadVirtualMemory failed - Status = %lx\n", Status );
  1587. return Status;
  1588. }
  1589. if ((0 != LocalString->Length) && (NULL != LocalString->Buffer)) {
  1590. Buffer = RtlAllocateHeap( CsrHeap,
  1591. MAKE_TAG( PROCESS_TAG ),
  1592. LocalString->Length + sizeof(WCHAR)
  1593. );
  1594. if (Buffer == NULL) {
  1595. return STATUS_NO_MEMORY;
  1596. }
  1597. Status = NtReadVirtualMemory(ProcessHandle,
  1598. LocalString->Buffer,
  1599. Buffer,
  1600. LocalString->Length + sizeof(WCHAR),
  1601. NULL);
  1602. if ( !NT_SUCCESS( Status ) ) {
  1603. DbgPrint( "CSRSS: ReadUnicodeString: NtReadVirtualMemory Buffer failed - Status = %lx\n", Status );
  1604. RtlFreeHeap(CsrHeap,0,Buffer);
  1605. LocalString->Buffer = NULL; // don't want caller to free this
  1606. return Status;
  1607. }
  1608. LocalString->Buffer = Buffer;
  1609. }
  1610. }
  1611. return STATUS_SUCCESS;
  1612. }
  1613. #if CSRSS_PROTECT_HANDLES
  1614. BOOLEAN
  1615. ProtectHandle(
  1616. HANDLE hObject
  1617. )
  1618. {
  1619. NTSTATUS Status;
  1620. OBJECT_HANDLE_FLAG_INFORMATION HandleInfo;
  1621. Status = NtQueryObject( hObject,
  1622. ObjectHandleFlagInformation,
  1623. &HandleInfo,
  1624. sizeof( HandleInfo ),
  1625. NULL
  1626. );
  1627. if (NT_SUCCESS( Status )) {
  1628. HandleInfo.ProtectFromClose = TRUE;
  1629. Status = NtSetInformationObject( hObject,
  1630. ObjectHandleFlagInformation,
  1631. &HandleInfo,
  1632. sizeof( HandleInfo )
  1633. );
  1634. if (NT_SUCCESS( Status )) {
  1635. return TRUE;
  1636. }
  1637. }
  1638. return FALSE;
  1639. }
  1640. BOOLEAN
  1641. UnProtectHandle(
  1642. HANDLE hObject
  1643. )
  1644. {
  1645. NTSTATUS Status;
  1646. OBJECT_HANDLE_FLAG_INFORMATION HandleInfo;
  1647. Status = NtQueryObject( hObject,
  1648. ObjectHandleFlagInformation,
  1649. &HandleInfo,
  1650. sizeof( HandleInfo ),
  1651. NULL
  1652. );
  1653. if (NT_SUCCESS( Status )) {
  1654. HandleInfo.ProtectFromClose = FALSE;
  1655. Status = NtSetInformationObject( hObject,
  1656. ObjectHandleFlagInformation,
  1657. &HandleInfo,
  1658. sizeof( HandleInfo )
  1659. );
  1660. if (NT_SUCCESS( Status )) {
  1661. return TRUE;
  1662. }
  1663. }
  1664. return FALSE;
  1665. }
  1666. #endif // CSRSS_PROTECT_HANDLES