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 *******************************************************************/
16 /* GLOBALS ********************************************************************/
18 typedef struct _SMP_CLIENT_CONTEXT
24 } SMP_CLIENT_CONTEXT
, *PSMP_CLIENT_CONTEXT
;
28 (NTAPI
*PSM_API_HANDLER
)(
29 IN PSM_API_MSG SmApiMsg
,
30 IN PSMP_CLIENT_CONTEXT ClientContext
,
34 volatile LONG SmTotalApiThreads
;
35 HANDLE SmUniqueProcessId
;
37 /* API HANDLERS ***************************************************************/
41 SmpCreateForeignSession(IN PSM_API_MSG SmApiMsg
,
42 IN PSMP_CLIENT_CONTEXT ClientContext
,
45 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
46 return STATUS_NOT_IMPLEMENTED
;
51 SmpSessionComplete(IN PSM_API_MSG SmApiMsg
,
52 IN PSMP_CLIENT_CONTEXT ClientContext
,
55 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
56 return STATUS_NOT_IMPLEMENTED
;
61 SmpTerminateForeignSession(IN PSM_API_MSG SmApiMsg
,
62 IN PSMP_CLIENT_CONTEXT ClientContext
,
65 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
66 return STATUS_NOT_IMPLEMENTED
;
71 SmpExecPgm(IN PSM_API_MSG SmApiMsg
,
72 IN PSMP_CLIENT_CONTEXT ClientContext
,
77 PSM_EXEC_PGM_MSG SmExecPgm
;
78 RTL_USER_PROCESS_INFORMATION ProcessInformation
;
79 OBJECT_ATTRIBUTES ObjectAttributes
;
81 /* Open the client process */
82 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
83 Status
= NtOpenProcess(&ProcessHandle
,
86 &SmApiMsg
->h
.ClientId
);
87 if (!NT_SUCCESS(Status
))
90 DPRINT1("SmExecPgm: NtOpenProcess Failed %lx\n", Status
);
94 /* Copy the process information out of the message */
95 SmExecPgm
= &SmApiMsg
->u
.ExecPgm
;
96 ProcessInformation
= SmExecPgm
->ProcessInformation
;
98 /* Duplicate the process handle */
99 Status
= NtDuplicateObject(ProcessHandle
,
100 SmExecPgm
->ProcessInformation
.ProcessHandle
,
102 &ProcessInformation
.ProcessHandle
,
106 if (!NT_SUCCESS(Status
))
108 /* Close the handle and fail */
109 NtClose(ProcessHandle
);
110 DPRINT1("SmExecPgm: NtDuplicateObject (Process) Failed %lx\n", Status
);
114 /* Duplicate the thread handle */
115 Status
= NtDuplicateObject(ProcessHandle
,
116 SmExecPgm
->ProcessInformation
.ThreadHandle
,
118 &ProcessInformation
.ThreadHandle
,
122 if (!NT_SUCCESS(Status
))
124 /* Close both handles and fail */
125 NtClose(ProcessInformation
.ProcessHandle
);
126 NtClose(ProcessHandle
);
127 DPRINT1("SmExecPgm: NtDuplicateObject (Thread) Failed %lx\n", Status
);
131 /* Close the process handle and call the internal client API */
132 NtClose(ProcessHandle
);
133 return SmpSbCreateSession(NULL
,
137 SmExecPgm
->DebugFlag
? &SmApiMsg
->h
.ClientId
: NULL
);
142 SmpLoadDeferedSubsystem(IN PSM_API_MSG SmApiMsg
,
143 IN PSMP_CLIENT_CONTEXT ClientContext
,
146 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
147 return STATUS_NOT_IMPLEMENTED
;
152 SmpStartCsr(IN PSM_API_MSG SmApiMsg
,
153 IN PSMP_CLIENT_CONTEXT ClientContext
,
156 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
157 return STATUS_NOT_IMPLEMENTED
;
162 SmpStopCsr(IN PSM_API_MSG SmApiMsg
,
163 IN PSMP_CLIENT_CONTEXT ClientContext
,
166 DPRINT1("%s is not yet implemented\n", __FUNCTION__
);
167 return STATUS_NOT_IMPLEMENTED
;
170 PSM_API_HANDLER SmpApiDispatch
[SmpMaxApiNumber
- SmpCreateForeignSessionApi
] =
172 SmpCreateForeignSession
,
174 SmpTerminateForeignSession
,
176 SmpLoadDeferedSubsystem
,
181 /* FUNCTIONS ******************************************************************/
185 SmpHandleConnectionRequest(IN HANDLE SmApiPort
,
186 IN PSB_API_MSG SbApiMsg
)
188 BOOLEAN Accept
= TRUE
;
189 HANDLE PortHandle
, ProcessHandle
;
191 UNICODE_STRING SubsystemPort
;
192 SMP_CLIENT_CONTEXT
*ClientContext
;
194 OBJECT_ATTRIBUTES ObjectAttributes
;
195 REMOTE_PORT_VIEW PortView
;
196 SECURITY_QUALITY_OF_SERVICE SecurityQos
;
197 PSMP_SUBSYSTEM CidSubsystem
, TypeSubsystem
;
199 /* Initialize QoS data */
200 SecurityQos
.ImpersonationLevel
= SecurityIdentification
;
201 SecurityQos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
202 SecurityQos
.EffectiveOnly
= TRUE
;
204 /* Check if this is SM connecting to itself */
205 if (SbApiMsg
->h
.ClientId
.UniqueProcess
== SmUniqueProcessId
)
207 /* No need to get any handle -- assume session 0 */
208 ProcessHandle
= NULL
;
213 /* Reference the foreign process */
214 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
215 Status
= NtOpenProcess(&ProcessHandle
,
216 PROCESS_QUERY_INFORMATION
,
218 &SbApiMsg
->h
.ClientId
);
219 if (!NT_SUCCESS(Status
)) Accept
= FALSE
;
221 /* Get its session ID */
222 SmpGetProcessMuSessionId(ProcessHandle
, &SessionId
);
225 /* See if we already know about the caller's subystem */
226 CidSubsystem
= SmpLocateKnownSubSysByCid(&SbApiMsg
->h
.ClientId
);
227 if ((CidSubsystem
) && (Accept
))
229 /* Check if we already have a subsystem for this kind of image */
230 TypeSubsystem
= SmpLocateKnownSubSysByType(SessionId
,
231 SbApiMsg
->ConnectionInfo
.SubsystemType
);
232 if (TypeSubsystem
== CidSubsystem
)
234 /* Someone is trying to take control of an existing subsystem, fail */
236 DPRINT1("SMSS: Connection from SubSystem rejected\n");
237 DPRINT1("SMSS: Image type already being served\n");
241 /* Set this image type as the type for this subsystem */
242 CidSubsystem
->ImageType
= SbApiMsg
->ConnectionInfo
.SubsystemType
;
245 /* Drop the reference we had acquired */
246 if (TypeSubsystem
) SmpDereferenceSubsystem(TypeSubsystem
);
249 /* Check if we'll be accepting the connection */
252 /* We will, so create a client context for it */
253 ClientContext
= RtlAllocateHeap(SmpHeap
, 0, sizeof(SMP_CLIENT_CONTEXT
));
256 ClientContext
->ProcessHandle
= ProcessHandle
;
257 ClientContext
->Subsystem
= CidSubsystem
;
258 ClientContext
->dword10
= 0;
259 ClientContext
->PortHandle
= NULL
;
263 /* Failed to allocate a client context, so reject the connection */
264 DPRINT1("Rejecting connectiond due to lack of memory\n");
270 /* Use a bogus context since we're going to reject the message */
271 ClientContext
= (PSMP_CLIENT_CONTEXT
)SbApiMsg
;
274 /* Now send the actual accept reply (which could be a rejection) */
275 PortView
.Length
= sizeof(PortView
);
276 Status
= NtAcceptConnectPort(&PortHandle
,
282 if (!(Accept
) || !(NT_SUCCESS(Status
)))
284 /* Close the process handle, reference the subsystem, and exit */
285 DPRINT1("Accept failed or rejected: %lx\n", Status
);
286 if (ClientContext
!= (PVOID
)SbApiMsg
) RtlFreeHeap(SmpHeap
, 0, ClientContext
);
287 if (ProcessHandle
) NtClose(ProcessHandle
);
288 if (CidSubsystem
) SmpDereferenceSubsystem(CidSubsystem
);
292 /* Save the port handle now that we've accepted it */
293 if (ClientContext
) ClientContext
->PortHandle
= PortHandle
;
294 if (CidSubsystem
) CidSubsystem
->PortHandle
= PortHandle
;
296 /* Complete the port connection */
297 Status
= NtCompleteConnectPort(PortHandle
);
298 if ((NT_SUCCESS(Status
)) && (CidSubsystem
))
300 /* This was an actual subsystem, so connect back to it */
301 SbApiMsg
->ConnectionInfo
.SbApiPortName
[119] = UNICODE_NULL
;
302 RtlCreateUnicodeString(&SubsystemPort
,
303 SbApiMsg
->ConnectionInfo
.SbApiPortName
);
304 Status
= NtConnectPort(&CidSubsystem
->SbApiPort
,
312 if (!NT_SUCCESS(Status
))
314 DPRINT1("SMSS: Connect back to Sb %wZ failed %lx\n", &SubsystemPort
, Status
);
316 RtlFreeUnicodeString(&SubsystemPort
);
318 /* Now that we're connected, signal the event handle */
319 NtSetEvent(CidSubsystem
->Event
, NULL
);
321 else if (CidSubsystem
)
323 /* We failed to complete the connection, so clear the port handle */
324 DPRINT1("Completing the connection failed: %lx\n", Status
);
325 CidSubsystem
->PortHandle
= NULL
;
328 /* Dereference the subsystem and return the result */
329 if (CidSubsystem
) SmpDereferenceSubsystem(CidSubsystem
);
335 SmpApiLoop(IN PVOID Parameter
)
337 HANDLE SmApiPort
= (HANDLE
)Parameter
;
339 PSMP_CLIENT_CONTEXT ClientContext
;
340 PSM_API_MSG ReplyMsg
= NULL
;
341 SM_API_MSG RequestMsg
;
342 PROCESS_BASIC_INFORMATION ProcessInformation
;
343 LARGE_INTEGER Timeout
;
345 /* Increase the number of API threads for throttling code for later */
346 _InterlockedExchangeAdd(&SmTotalApiThreads
, 1);
348 /* Mark us critical */
349 RtlSetThreadIsCritical(TRUE
, NULL
, TRUE
);
351 /* Set the PID of the SM process itself for later checking */
352 NtQueryInformationProcess(NtCurrentProcess(),
353 ProcessBasicInformation
,
355 sizeof(ProcessInformation
),
357 SmUniqueProcessId
= (HANDLE
)ProcessInformation
.UniqueProcessId
;
359 /* Now process incoming messages */
362 /* Begin waiting on a request */
363 Status
= NtReplyWaitReceivePort(SmApiPort
,
364 (PVOID
*)&ClientContext
,
367 if (Status
== STATUS_NO_MEMORY
)
369 /* Ran out of memory, so do a little timeout and try again */
370 if (ReplyMsg
) DPRINT1("SMSS: Failed to reply to calling thread, retrying.\n");
371 Timeout
.QuadPart
= -50000000;
372 NtDelayExecution(FALSE
, &Timeout
);
376 /* Check what kind of request we received */
377 switch (RequestMsg
.h
.u2
.s2
.Type
)
379 /* A new connection */
380 case LPC_CONNECTION_REQUEST
:
381 /* Create the right structures for it */
382 SmpHandleConnectionRequest(SmApiPort
, (PSB_API_MSG
)&RequestMsg
);
386 /* A closed connection */
387 case LPC_PORT_CLOSED
:
388 /* Destroy any state we had for this client */
389 DPRINT1("Port closed\n");
390 //if (ClientContext) SmpPushDeferredClientContext(ClientContext);
394 /* An actual API message */
402 RequestMsg
.ReturnValue
= STATUS_PENDING
;
404 /* Check if the API is valid */
405 if (RequestMsg
.ApiNumber
>= SmpMaxApiNumber
)
408 DPRINT1("Invalid API: %lx\n", RequestMsg
.ApiNumber
);
409 Status
= STATUS_NOT_IMPLEMENTED
;
411 else if ((RequestMsg
.ApiNumber
<= SmpTerminateForeignSessionApi
) &&
412 !(ClientContext
->Subsystem
))
414 /* It's valid, but doesn't have a subsystem with it */
415 DPRINT1("Invalid session API\n");
416 Status
= STATUS_INVALID_PARAMETER
;
420 /* It's totally okay, so call the dispatcher for it */
421 Status
= SmpApiDispatch
[RequestMsg
.ApiNumber
](&RequestMsg
,
426 /* Write the result valud and return the message back */
427 RequestMsg
.ReturnValue
= Status
;
428 ReplyMsg
= &RequestMsg
;
432 return STATUS_SUCCESS
;