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.

536 lines
12 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. termsrv.c
  5. Abstract:
  6. Terminal Server routines for supporting multiple sessions.
  7. Author:
  8. Revision History:
  9. --*/
  10. #include "smsrvp.h"
  11. #include <ntexapi.h>
  12. #include <winerror.h>
  13. #include "stdio.h"
  14. HANDLE SmpSessionsObjectDirectory;
  15. extern PSECURITY_DESCRIPTOR SmpLiberalSecurityDescriptor;
  16. NTSTATUS
  17. SmpSetProcessMuSessionId (
  18. IN HANDLE Process,
  19. IN ULONG MuSessionId
  20. )
  21. /*++
  22. Routine Description:
  23. This function sets the multiuser session ID for a process.
  24. Arguments:
  25. Process - Supplies the handle of the process to set the ID for.
  26. MuSessionId - Supplies the ID to give to the supplied process.
  27. Return Value:
  28. NTSTATUS.
  29. --*/
  30. {
  31. NTSTATUS Status;
  32. PROCESS_SESSION_INFORMATION ProcessInfo;
  33. ProcessInfo.SessionId = MuSessionId;
  34. Status = NtSetInformationProcess (Process,
  35. ProcessSessionInformation,
  36. &ProcessInfo,
  37. sizeof( ProcessInfo ) );
  38. if ( !NT_SUCCESS( Status ) ) {
  39. KdPrint(( "SMSS: SetProcessMuSessionId, Process=%x, Status=%x\n",
  40. Process, Status ));
  41. }
  42. return Status;
  43. }
  44. NTSTATUS
  45. SmpTerminateProcessAndWait (
  46. IN HANDLE Process,
  47. IN ULONG Seconds
  48. )
  49. /*++
  50. Routine Description:
  51. This function terminates the process and waits for it to die.
  52. Arguments:
  53. Process - Supplies the handle of the process to terminate.
  54. Seconds - Supplies the number of seconds to wait for the process to die.
  55. Return Value:
  56. NTSTATUS.
  57. --*/
  58. {
  59. NTSTATUS Status;
  60. ULONG mSecs;
  61. LARGE_INTEGER Timeout;
  62. //
  63. // Try to terminate the process.
  64. //
  65. Status = NtTerminateProcess( Process, STATUS_SUCCESS );
  66. if ( !NT_SUCCESS( Status ) && Status != STATUS_PROCESS_IS_TERMINATING ) {
  67. KdPrint(( "SMSS: Terminate=0x%x\n", Status ));
  68. return Status;
  69. }
  70. //
  71. // Wait for the process to die.
  72. //
  73. mSecs = Seconds * 1000;
  74. Timeout = RtlEnlargedIntegerMultiply( mSecs, -10000 );
  75. Status = NtWaitForSingleObject( Process, FALSE, &Timeout );
  76. return Status;
  77. }
  78. NTSTATUS
  79. SmpGetProcessMuSessionId (
  80. IN HANDLE Process,
  81. OUT PULONG MuSessionId
  82. )
  83. /*++
  84. Routine Description:
  85. This function gets the multiuser session ID for a process.
  86. Arguments:
  87. Process - Supplies the handle of the process to get the ID for.
  88. MuSessionId - Supplies the location to place the ID in.
  89. Return Value:
  90. NTSTATUS.
  91. --*/
  92. {
  93. NTSTATUS Status;
  94. PROCESS_SESSION_INFORMATION ProcessInfo;
  95. Status = NtQueryInformationProcess (Process,
  96. ProcessSessionInformation,
  97. &ProcessInfo,
  98. sizeof( ProcessInfo ),
  99. NULL );
  100. if ( !NT_SUCCESS( Status ) ) {
  101. KdPrint(( "SMSS: GetProcessMuSessionId, Process=%x, Status=%x\n",
  102. Process, Status ));
  103. *MuSessionId = 0;
  104. }
  105. else {
  106. *MuSessionId = ProcessInfo.SessionId;
  107. }
  108. return Status;
  109. }
  110. NTSTATUS
  111. SmpTerminateCSR(
  112. IN ULONG MuSessionId
  113. )
  114. /*++
  115. Routine Description:
  116. This function terminates all known subsystems for this MuSessionId.
  117. Also closes all LPC ports and all process handles.
  118. Arguments:
  119. MuSessionId - Supplies the session ID to terminate subsystems for.
  120. Return Value:
  121. NTSTATUS.
  122. --*/
  123. {
  124. NTSTATUS Status = STATUS_SUCCESS;
  125. PLIST_ENTRY Next;
  126. PLIST_ENTRY Tmp;
  127. PSMPKNOWNSUBSYS KnownSubSys;
  128. CLIENT_ID ClientId;
  129. HANDLE Process;
  130. RtlEnterCriticalSection( &SmpKnownSubSysLock );
  131. //
  132. // Force all subsystems of this session to exit.
  133. //
  134. Next = SmpKnownSubSysHead.Flink;
  135. while ( Next != &SmpKnownSubSysHead ) {
  136. KnownSubSys = CONTAINING_RECORD(Next,SMPKNOWNSUBSYS,Links);
  137. Next = Next->Flink;
  138. if ( KnownSubSys->MuSessionId != MuSessionId ) {
  139. continue;
  140. }
  141. ClientId = KnownSubSys->InitialClientId;
  142. Process = KnownSubSys->Process;
  143. //
  144. // Reference the Subsystem so it does not go away while we using it.
  145. //
  146. SmpReferenceKnownSubSys(KnownSubSys);
  147. //
  148. // Set deleting so that this subsys will go away when refcount reaches
  149. // zero.
  150. //
  151. KnownSubSys->Deleting = TRUE;
  152. //
  153. // Unlock the SubSystemList as we don't want to leave it locked
  154. // around a wait.
  155. //
  156. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  157. Status = SmpTerminateProcessAndWait( Process, 10 );
  158. if ( Status != STATUS_SUCCESS ) {
  159. KdPrint(( "SMSS: Subsystem type %d failed to terminate\n",
  160. KnownSubSys->ImageType ));
  161. }
  162. RtlEnterCriticalSection( &SmpKnownSubSysLock );
  163. //
  164. // Must look for entry again.
  165. // BUGBUG: why re-look ? ICASRV shouldn't allow it to be deleted, but..
  166. //
  167. Tmp = SmpKnownSubSysHead.Flink;
  168. while ( Tmp != &SmpKnownSubSysHead ) {
  169. KnownSubSys = CONTAINING_RECORD(Tmp,SMPKNOWNSUBSYS,Links);
  170. if ( KnownSubSys->InitialClientId.UniqueProcess == ClientId.UniqueProcess ) {
  171. //
  172. // Remove the KnownSubSys block from the list.
  173. //
  174. RemoveEntryList( &KnownSubSys->Links );
  175. //
  176. // Dereference the subsystem. If this is the last reference,
  177. // the subsystem will be deleted.
  178. //
  179. SmpDeferenceKnownSubSys(KnownSubSys);
  180. break;
  181. }
  182. Tmp = Tmp->Flink;
  183. }
  184. //
  185. // Since we have waited, we must restart from the top of the list.
  186. //
  187. Next = SmpKnownSubSysHead.Flink;
  188. }
  189. //
  190. // Unlock SubSystemList.
  191. //
  192. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  193. return Status;
  194. }
  195. NTSTATUS
  196. SmpStartCsr(
  197. IN PSMAPIMSG SmApiMsg,
  198. IN PSMP_CLIENT_CONTEXT CallingClient,
  199. IN HANDLE CallPort
  200. )
  201. /*++
  202. Routine Description:
  203. This function creates a CSRSS system for a MuSessionId,
  204. returning the initial program and the windows subsystem.
  205. The console only returns the initial program
  206. and windows subsystem since it is started at boot.
  207. Arguments:
  208. TBD.
  209. Return Value:
  210. NTSTATUS.
  211. --*/
  212. {
  213. NTSTATUS St;
  214. NTSTATUS Status;
  215. PSMSTARTCSR args;
  216. ULONG MuSessionId;
  217. UNICODE_STRING InitialCommand;
  218. UNICODE_STRING DefaultInitialCommand;
  219. ULONG_PTR InitialCommandProcessId;
  220. ULONG_PTR WindowsSubSysProcessId;
  221. HANDLE InitialCommandProcess;
  222. extern ULONG SmpInitialCommandProcessId;
  223. extern ULONG SmpWindowsSubSysProcessId;
  224. PVOID State;
  225. LOGICAL TerminateCSR;
  226. TerminateCSR = FALSE;
  227. args = &SmApiMsg->u.StartCsr;
  228. MuSessionId = args->MuSessionId;
  229. InitialCommand.Length = (USHORT)args->InitialCommandLength;
  230. InitialCommand.MaximumLength = (USHORT)args->InitialCommandLength;
  231. InitialCommand.Buffer = args->InitialCommand;
  232. //
  233. // Things are different for the console.
  234. // SM starts him up and passes his ID back here.
  235. //
  236. if ( !MuSessionId ) {
  237. args->WindowsSubSysProcessId = SmpWindowsSubSysProcessId;
  238. args->InitialCommandProcessId = SmpInitialCommandProcessId;
  239. return STATUS_SUCCESS;
  240. }
  241. //
  242. // Load subsystems for this session.
  243. //
  244. WindowsSubSysProcessId = 0;
  245. Status = SmpLoadSubSystemsForMuSession (&MuSessionId,
  246. &WindowsSubSysProcessId,
  247. &DefaultInitialCommand );
  248. if ( Status != STATUS_SUCCESS ) {
  249. DbgPrint( "SMSS: SmpStartCsr, SmpLoadSubSystemsForMuSession Failed. Status=%x\n",
  250. Status );
  251. goto nostart;
  252. }
  253. //
  254. // Start the initial command for this session.
  255. //
  256. if ( InitialCommand.Length == 0 ) {
  257. Status = SmpExecuteInitialCommand( MuSessionId,
  258. &DefaultInitialCommand,
  259. &InitialCommandProcess,
  260. &InitialCommandProcessId );
  261. }
  262. else {
  263. Status = SmpExecuteInitialCommand( MuSessionId,
  264. &InitialCommand,
  265. &InitialCommandProcess,
  266. &InitialCommandProcessId );
  267. }
  268. if ( !NT_SUCCESS( Status ) ) {
  269. TerminateCSR = TRUE;
  270. DbgPrint( "SMSS: SmpStartCsr, SmpExecuteInitialCommand Failed. Status=%x\n",
  271. Status );
  272. goto nostart;
  273. }
  274. NtClose( InitialCommandProcess ); // This handle isn't needed
  275. args->InitialCommandProcessId = InitialCommandProcessId;
  276. args->WindowsSubSysProcessId = WindowsSubSysProcessId;
  277. args->MuSessionId = MuSessionId;
  278. nostart:
  279. if ((AttachedSessionId != (-1)) && NT_SUCCESS(SmpAcquirePrivilege( SE_LOAD_DRIVER_PRIVILEGE, &State ))) {
  280. //
  281. // If we are attached to a session space, leave it
  282. // so we can create a new one.
  283. //
  284. St = NtSetSystemInformation (SystemSessionDetach,
  285. (PVOID)&AttachedSessionId,
  286. sizeof(MuSessionId));
  287. if (NT_SUCCESS(St)) {
  288. AttachedSessionId = (-1);
  289. } else {
  290. //
  291. // This has to succeed otherwise we will bugcheck while trying to
  292. // create another session.
  293. //
  294. #if DBG
  295. DbgPrint( "SMSS: SmpStartCsr, Couldn't Detach from Session Space. Status=%x\n",
  296. St);
  297. DbgBreakPoint ();
  298. #endif
  299. }
  300. SmpReleasePrivilege( State );
  301. }
  302. if ( TerminateCSR == TRUE ) {
  303. St = SmpTerminateCSR( MuSessionId );
  304. #if DBG
  305. if (!NT_SUCCESS(St)) {
  306. DbgPrint( "SMSS: SmpStartCsr, Couldn't Terminate CSR. Status=%x\n", St);
  307. DbgBreakPoint();
  308. }
  309. #endif
  310. }
  311. return Status;
  312. }
  313. NTSTATUS
  314. SmpStopCsr(
  315. IN PSMAPIMSG SmApiMsg,
  316. IN PSMP_CLIENT_CONTEXT CallingClient,
  317. IN HANDLE CallPort
  318. )
  319. /*++
  320. Routine Description:
  321. This function terminates all known subsystems for this MuSessionId.
  322. Also closes all LPC ports and all process handles.
  323. Arguments:
  324. TBD.
  325. Return Value:
  326. NTSTATUS.
  327. --*/
  328. {
  329. PSMSTOPCSR args;
  330. ULONG MuSessionId;
  331. args = &SmApiMsg->u.StopCsr;
  332. MuSessionId = args->MuSessionId;
  333. return SmpTerminateCSR( MuSessionId );
  334. }
  335. BOOLEAN
  336. SmpCheckDuplicateMuSessionId(
  337. IN ULONG MuSessionId
  338. )
  339. /*++
  340. Routine Description:
  341. This function looks for this MuSessionId in the known subsystems.
  342. Arguments:
  343. MuSessionId - Supplies the session ID to look for.
  344. Return Value:
  345. TRUE if found, FALSE if not.
  346. --*/
  347. {
  348. PLIST_ENTRY Next;
  349. PSMPKNOWNSUBSYS KnownSubSys;
  350. RtlEnterCriticalSection( &SmpKnownSubSysLock );
  351. Next = SmpKnownSubSysHead.Flink;
  352. while ( Next != &SmpKnownSubSysHead ) {
  353. KnownSubSys = CONTAINING_RECORD(Next,SMPKNOWNSUBSYS,Links);
  354. if ( KnownSubSys->MuSessionId == MuSessionId ) {
  355. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  356. return TRUE;
  357. }
  358. Next = Next->Flink;
  359. }
  360. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  361. return FALSE;
  362. }