2 * PROJECT: ReactOS Windows-Compatible Session Manager
3 * LICENSE: BSD 2-Clause License
4 * FILE: base/system/smss/smss.c
5 * PURPOSE: Main SMSS Code
6 * PROGRAMMERS: Alex Ionescu
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 typedef struct _SMP_CLIENT_CONTEXT
23 } SMP_CLIENT_CONTEXT
, *PSMP_CLIENT_CONTEXT
;
27 (NTAPI
*PSM_API_HANDLER
)(
28 IN PSM_API_MSG SmApiMsg
,
29 IN PSMP_CLIENT_CONTEXT ClientContext
,
33 volatile LONG SmTotalApiThreads
;
34 HANDLE SmUniqueProcessId
;
36 /* API HANDLERS ***************************************************************/
40 SmpCreateForeignSession(IN PSM_API_MSG SmApiMsg
,
41 IN PSMP_CLIENT_CONTEXT ClientContext
,
44 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
45 return STATUS_NOT_IMPLEMENTED
;
50 SmpSessionComplete(IN PSM_API_MSG SmApiMsg
,
51 IN PSMP_CLIENT_CONTEXT ClientContext
,
54 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
55 return STATUS_NOT_IMPLEMENTED
;
60 SmpTerminateForeignSession(IN PSM_API_MSG SmApiMsg
,
61 IN PSMP_CLIENT_CONTEXT ClientContext
,
64 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
65 return STATUS_NOT_IMPLEMENTED
;
70 SmpExecPgm(IN PSM_API_MSG SmApiMsg
,
71 IN PSMP_CLIENT_CONTEXT ClientContext
,
76 PSM_EXEC_PGM_MSG SmExecPgm
;
77 RTL_USER_PROCESS_INFORMATION ProcessInformation
;
78 OBJECT_ATTRIBUTES ObjectAttributes
;
80 /* Open the client process */
81 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
82 Status
= NtOpenProcess(&ProcessHandle
,
85 &SmApiMsg
->h
.ClientId
);
86 if (!NT_SUCCESS(Status
))
89 DPRINT1("SmExecPgm: NtOpenProcess Failed %lx\n", Status
);
93 /* Copy the process information out of the message */
94 SmExecPgm
= &SmApiMsg
->u
.ExecPgm
;
95 ProcessInformation
= SmExecPgm
->ProcessInformation
;
97 /* Duplicate the process handle */
98 Status
= NtDuplicateObject(ProcessHandle
,
99 SmExecPgm
->ProcessInformation
.ProcessHandle
,
101 &ProcessInformation
.ProcessHandle
,
105 if (!NT_SUCCESS(Status
))
107 /* Close the handle and fail */
108 NtClose(ProcessHandle
);
109 DPRINT1("SmExecPgm: NtDuplicateObject (Process) Failed %lx\n", Status
);
113 /* Duplicate the thread handle */
114 Status
= NtDuplicateObject(ProcessHandle
,
115 SmExecPgm
->ProcessInformation
.ThreadHandle
,
117 &ProcessInformation
.ThreadHandle
,
121 if (!NT_SUCCESS(Status
))
123 /* Close both handles and fail */
124 NtClose(ProcessInformation
.ProcessHandle
);
125 NtClose(ProcessHandle
);
126 DPRINT1("SmExecPgm: NtDuplicateObject (Thread) Failed %lx\n", Status
);
130 /* Close the process handle and call the internal client API */
131 NtClose(ProcessHandle
);
132 return SmpSbCreateSession(NULL
,
136 SmExecPgm
->DebugFlag
? &SmApiMsg
->h
.ClientId
: NULL
);
141 SmpLoadDeferedSubsystem(IN PSM_API_MSG SmApiMsg
,
142 IN PSMP_CLIENT_CONTEXT ClientContext
,
145 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
146 return STATUS_NOT_IMPLEMENTED
;
151 SmpStartCsr(IN PSM_API_MSG SmApiMsg
,
152 IN PSMP_CLIENT_CONTEXT ClientContext
,
155 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
156 return STATUS_NOT_IMPLEMENTED
;
161 SmpStopCsr(IN PSM_API_MSG SmApiMsg
,
162 IN PSMP_CLIENT_CONTEXT ClientContext
,
165 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
166 return STATUS_NOT_IMPLEMENTED
;
169 PSM_API_HANDLER SmpApiDispatch
[SmpMaxApiNumber
- SmpCreateForeignSessionApi
] =
171 SmpCreateForeignSession
,
173 SmpTerminateForeignSession
,
175 SmpLoadDeferedSubsystem
,
180 /* FUNCTIONS ******************************************************************/
184 SmpHandleConnectionRequest(IN HANDLE SmApiPort
,
185 IN PSB_API_MSG SbApiMsg
)
187 BOOLEAN Accept
= TRUE
;
188 HANDLE PortHandle
, ProcessHandle
;
190 UNICODE_STRING SubsystemPort
;
191 SMP_CLIENT_CONTEXT
*ClientContext
;
193 OBJECT_ATTRIBUTES ObjectAttributes
;
194 REMOTE_PORT_VIEW PortView
;
195 SECURITY_QUALITY_OF_SERVICE SecurityQos
;
196 PSMP_SUBSYSTEM CidSubsystem
, TypeSubsystem
;
198 /* Initialize QoS data */
199 SecurityQos
.ImpersonationLevel
= SecurityIdentification
;
200 SecurityQos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
201 SecurityQos
.EffectiveOnly
= TRUE
;
203 /* Check if this is SM connecting to itself */
204 if (SbApiMsg
->h
.ClientId
.UniqueProcess
== SmUniqueProcessId
)
206 /* No need to get any handle -- assume session 0 */
207 ProcessHandle
= NULL
;
212 /* Reference the foreign process */
213 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
214 Status
= NtOpenProcess(&ProcessHandle
,
215 PROCESS_QUERY_INFORMATION
,
217 &SbApiMsg
->h
.ClientId
);
218 if (!NT_SUCCESS(Status
)) Accept
= FALSE
;
220 /* Get its session ID */
221 SmpGetProcessMuSessionId(ProcessHandle
, &SessionId
);
224 /* See if we already know about the caller's subystem */
225 CidSubsystem
= SmpLocateKnownSubSysByCid(&SbApiMsg
->h
.ClientId
);
226 if ((CidSubsystem
) && (Accept
))
228 /* Check if we already have a subsystem for this kind of image */
229 TypeSubsystem
= SmpLocateKnownSubSysByType(SessionId
,
230 SbApiMsg
->ConnectionInfo
.SubsystemType
);
231 if (TypeSubsystem
== CidSubsystem
)
233 /* Someone is trying to take control of an existing subsystem, fail */
235 DPRINT1("SMSS: Connection from SubSystem rejected\n");
236 DPRINT1("SMSS: Image type already being served\n");
240 /* Set this image type as the type for this subsystem */
241 CidSubsystem
->ImageType
= SbApiMsg
->ConnectionInfo
.SubsystemType
;
244 /* Drop the reference we had acquired */
245 if (TypeSubsystem
) SmpDereferenceSubsystem(TypeSubsystem
);
248 /* Check if we'll be accepting the connection */
251 /* We will, so create a client context for it */
252 ClientContext
= RtlAllocateHeap(SmpHeap
, 0, sizeof(SMP_CLIENT_CONTEXT
));
255 ClientContext
->ProcessHandle
= ProcessHandle
;
256 ClientContext
->Subsystem
= CidSubsystem
;
257 ClientContext
->dword10
= 0;
258 ClientContext
->PortHandle
= NULL
;
262 /* Failed to allocate a client context, so reject the connection */
263 DPRINT1("Rejecting connectiond due to lack of memory\n");
269 /* Use a bogus context since we're going to reject the message */
270 ClientContext
= (PSMP_CLIENT_CONTEXT
)SbApiMsg
;
273 /* Now send the actual accept reply (which could be a rejection) */
274 PortView
.Length
= sizeof(PortView
);
275 Status
= NtAcceptConnectPort(&PortHandle
,
281 if (!(Accept
) || !(NT_SUCCESS(Status
)))
283 /* Close the process handle, reference the subsystem, and exit */
284 DPRINT1("Accept failed or rejected: %lx\n", Status
);
285 if (ClientContext
!= (PVOID
)SbApiMsg
) RtlFreeHeap(SmpHeap
, 0, ClientContext
);
286 if (ProcessHandle
) NtClose(ProcessHandle
);
287 if (CidSubsystem
) SmpDereferenceSubsystem(CidSubsystem
);
291 /* Save the port handle now that we've accepted it */
292 if (ClientContext
) ClientContext
->PortHandle
= PortHandle
;
293 if (CidSubsystem
) CidSubsystem
->PortHandle
= PortHandle
;
295 /* Complete the port connection */
296 Status
= NtCompleteConnectPort(PortHandle
);
297 if ((NT_SUCCESS(Status
)) && (CidSubsystem
))
299 /* This was an actual subsystem, so connect back to it */
300 SbApiMsg
->ConnectionInfo
.SbApiPortName
[119] = UNICODE_NULL
;
301 RtlCreateUnicodeString(&SubsystemPort
,
302 SbApiMsg
->ConnectionInfo
.SbApiPortName
);
303 Status
= NtConnectPort(&CidSubsystem
->SbApiPort
,
311 if (!NT_SUCCESS(Status
))
313 DPRINT1("SMSS: Connect back to Sb %wZ failed %lx\n", &SubsystemPort
, Status
);
315 RtlFreeUnicodeString(&SubsystemPort
);
317 /* Now that we're connected, signal the event handle */
318 NtSetEvent(CidSubsystem
->Event
, NULL
);
320 else if (CidSubsystem
)
322 /* We failed to complete the connection, so clear the port handle */
323 DPRINT1("Completing the connection failed: %lx\n", Status
);
324 CidSubsystem
->PortHandle
= NULL
;
327 /* Dereference the subsystem and return the result */
328 if (CidSubsystem
) SmpDereferenceSubsystem(CidSubsystem
);
334 SmpApiLoop(IN PVOID Parameter
)
336 HANDLE SmApiPort
= (HANDLE
)Parameter
;
338 PSMP_CLIENT_CONTEXT ClientContext
;
339 PSM_API_MSG ReplyMsg
= NULL
;
340 SM_API_MSG RequestMsg
;
341 PROCESS_BASIC_INFORMATION ProcessInformation
;
342 LARGE_INTEGER Timeout
;
344 /* Increase the number of API threads for throttling code for later */
345 _InterlockedExchangeAdd(&SmTotalApiThreads
, 1);
347 /* Mark us critical */
348 RtlSetThreadIsCritical(TRUE
, NULL
, TRUE
);
350 /* Set the PID of the SM process itself for later checking */
351 NtQueryInformationProcess(NtCurrentProcess(),
352 ProcessBasicInformation
,
354 sizeof(ProcessInformation
),
356 SmUniqueProcessId
= (HANDLE
)ProcessInformation
.UniqueProcessId
;
358 /* Now process incoming messages */
361 /* Begin waiting on a request */
362 Status
= NtReplyWaitReceivePort(SmApiPort
,
363 (PVOID
*)&ClientContext
,
366 if (Status
== STATUS_NO_MEMORY
)
368 /* Ran out of memory, so do a little timeout and try again */
369 if (ReplyMsg
) DPRINT1("SMSS: Failed to reply to calling thread, retrying.\n");
370 Timeout
.QuadPart
= -50000000;
371 NtDelayExecution(FALSE
, &Timeout
);
375 /* Check what kind of request we received */
376 switch (RequestMsg
.h
.u2
.s2
.Type
)
378 /* A new connection */
379 case LPC_CONNECTION_REQUEST
:
380 /* Create the right structures for it */
381 SmpHandleConnectionRequest(SmApiPort
, (PSB_API_MSG
)&RequestMsg
);
385 /* A closed connection */
386 case LPC_PORT_CLOSED
:
387 /* Destroy any state we had for this client */
388 DPRINT1("Port closed\n");
389 //if (ClientContext) SmpPushDeferredClientContext(ClientContext);
393 /* An actual API message */
401 RequestMsg
.ReturnValue
= STATUS_PENDING
;
403 /* Check if the API is valid */
404 if (RequestMsg
.ApiNumber
>= SmpMaxApiNumber
)
407 DPRINT1("Invalid API: %lx\n", RequestMsg
.ApiNumber
);
408 Status
= STATUS_NOT_IMPLEMENTED
;
410 else if ((RequestMsg
.ApiNumber
<= SmpTerminateForeignSessionApi
) &&
411 !(ClientContext
->Subsystem
))
413 /* It's valid, but doesn't have a subsystem with it */
414 DPRINT1("Invalid session API\n");
415 Status
= STATUS_INVALID_PARAMETER
;
419 /* It's totally okay, so call the dispatcher for it */
420 Status
= SmpApiDispatch
[RequestMsg
.ApiNumber
](&RequestMsg
,
425 /* Write the result valud and return the message back */
426 RequestMsg
.ReturnValue
= Status
;
427 ReplyMsg
= &RequestMsg
;
431 return STATUS_SUCCESS
;