Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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