1 /* $Id: smss.c 12852 2005-01-06 13:58:04Z mf $
3 * client.c - Session Manager client Management
5 * ReactOS Operating System
7 * --------------------------------------------------------------------
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
24 * --------------------------------------------------------------------
26 #define NTOS_MODE_USER
29 #include <sm/helper.h>
37 struct _SM_CLIENT_DIRECTORY
39 RTL_CRITICAL_SECTION Lock
;
41 PSM_CLIENT_DATA Client
;
42 PSM_CLIENT_DATA CandidateClient
;
47 /**********************************************************************
48 * SmInitializeClientManagement/0
51 SmInitializeClientManagement (VOID
)
53 DPRINT("SM: %s called\n", __FUNCTION__
);
54 RtlInitializeCriticalSection(& SmpClientDirectory
.Lock
);
55 SmpClientDirectory
.Count
= 0;
56 SmpClientDirectory
.Client
= NULL
;
57 SmpClientDirectory
.CandidateClient
= NULL
;
58 return STATUS_SUCCESS
;
61 /**********************************************************************
62 * SmpSetClientInitialized/1
65 SmpSetClientInitialized (PSM_CLIENT_DATA Client
)
67 Client
->Flags
|= SM_CLIENT_FLAG_INITIALIZED
;
69 /**********************************************************************
70 * SmpLookupClient/2 PRIVATE
73 * Lookup the subsystem server descriptor given its image ID.
76 * SubsystemId: IMAGE_SUBSYSTEM_xxx
77 * Parent: optional: caller provided storage for the
78 * the pointer to the SM_CLIENT_DATA which
79 * Next field contains the value returned by
80 * the function (on success).
83 * NULL on error; otherwise a pointer to the SM_CLIENT_DATA
87 * SmpClientDirectory.Lock must be held by the caller.
89 static PSM_CLIENT_DATA FASTCALL
90 SmpLookupClient (USHORT SubsystemId
,
91 PSM_CLIENT_DATA
* Parent
)
93 PSM_CLIENT_DATA Client
= NULL
;
95 DPRINT("SM: %s(%d) called\n", __FUNCTION__
, SubsystemId
);
101 if (SmpClientDirectory
.Count
> 0)
103 Client
= SmpClientDirectory
.Client
;
104 while (NULL
!= Client
)
106 if (SubsystemId
== Client
->SubsystemId
)
114 Client
= Client
->Next
;
119 /**********************************************************************
120 * SmBeginClientInitialization/1
123 * Check if the candidate client matches the begin session
124 * message from the subsystem process.
127 * Request: message received by \SmApiPort
134 SmBeginClientInitialization (IN PSM_PORT_MESSAGE Request
,
135 OUT PSM_CLIENT_DATA
* ClientData
)
137 NTSTATUS Status
= STATUS_SUCCESS
;
138 PSM_CONNECT_DATA ConnectData
= SmpGetConnectData (Request
);
139 ULONG SbApiPortNameSize
= SM_CONNECT_DATA_SIZE(*Request
);
142 DPRINT("SM: %s called\n", __FUNCTION__
);
144 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
146 * Is there a subsystem bootstrap in progress?
148 if (SmpClientDirectory
.CandidateClient
)
150 PROCESS_BASIC_INFORMATION pbi
;
152 RtlZeroMemory (& pbi
, sizeof pbi
);
153 Status
= NtQueryInformationProcess (Request
->Header
.ClientId
.UniqueProcess
,
154 ProcessBasicInformation
,
158 if (NT_SUCCESS(Status
))
160 SmpClientDirectory
.CandidateClient
->ServerProcessId
=
161 (ULONG
) pbi
.UniqueProcessId
;
166 RtlFreeHeap (SmpHeap
, 0, SmpClientDirectory
.CandidateClient
);
167 DPRINT1("SM: %s: subsys booting with no descriptor!\n", __FUNCTION__
);
168 Status
= STATUS_NOT_FOUND
;
169 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
173 * Check if a client for the ID already exist.
175 if (SmpLookupClient(ConnectData
->SubSystemId
, NULL
))
177 DPRINT("SM: %s: attempt to register again subsystem %d.\n",
179 ConnectData
->SubSystemId
);
180 return STATUS_UNSUCCESSFUL
;
182 DPRINT("SM: %s: registering subsystem ID=%d \n",
183 __FUNCTION__
, ConnectData
->SubSystemId
);
186 * Initialize the client data
188 SmpClientDirectory
.CandidateClient
->SubsystemId
= ConnectData
->SubSystemId
;
189 /* SM && DBG auto-initializes; other subsystems are required to call
190 * SM_API_COMPLETE_SESSION via SMDLL. */
191 if ((IMAGE_SUBSYSTEM_NATIVE
== SmpClientDirectory
.CandidateClient
->SubsystemId
) ||
192 (IMAGE_SUBSYSTEM_UNKNOWN
== SmpClientDirectory
.CandidateClient
->SubsystemId
))
194 SmpSetClientInitialized (SmpClientDirectory
.CandidateClient
);
196 if (SbApiPortNameSize
> 0)
198 RtlCopyMemory (SmpClientDirectory
.CandidateClient
->SbApiPortName
,
203 * Insert the new descriptor in the
206 if (NULL
== SmpClientDirectory
.Client
)
208 SmpClientDirectory
.Client
= SmpClientDirectory
.CandidateClient
;
210 PSM_CLIENT_DATA pCD
= NULL
;
212 for (pCD
=SmpClientDirectory
.Client
;
215 pCD
->Next
= SmpClientDirectory
.CandidateClient
;
217 SmpClientDirectory
.CandidateClient
->Next
= NULL
;
219 * Increment the number of active subsystems.
221 ++ SmpClientDirectory
.Count
;
223 * Notify to the caller the reference to the client data.
227 *ClientData
= SmpClientDirectory
.CandidateClient
;
230 * Free the slot for the candidate subsystem.
232 SmpClientDirectory
.CandidateClient
= NULL
;
234 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
236 return STATUS_SUCCESS
;
238 /**********************************************************************
239 * SmCompleteClientInitialization/1
242 * Lookup the subsystem server descriptor given the process ID
243 * of the subsystem server process.
246 SmCompleteClientInitialization (ULONG ProcessId
)
248 NTSTATUS Status
= STATUS_SUCCESS
;
249 PSM_CLIENT_DATA Client
= NULL
;
251 DPRINT("SM: %s called\n", __FUNCTION__
);
253 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
254 if (SmpClientDirectory
.Count
> 0)
256 Client
= SmpClientDirectory
.Client
;
257 while (NULL
!= Client
)
259 if (ProcessId
== Client
->ServerProcessId
)
261 SmpSetClientInitialized (Client
);
264 Client
= Client
->Next
;
266 Status
= STATUS_NOT_FOUND
;
268 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
272 /**********************************************************************
276 * Create a "candidate" client. Client descriptor will enter the
277 * client directory only at the end of the registration
278 * procedure. Otherwise, we will kill the associated process.
281 * ProcessHandle: handle of the subsystem server process.
287 SmCreateClient (PRTL_PROCESS_INFO ProcessInfo
, PWSTR ProgramName
)
289 NTSTATUS Status
= STATUS_SUCCESS
;
292 DPRINT("SM: %s(%lx) called\n", __FUNCTION__
, ProcessInfo
->ProcessHandle
);
293 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
295 * Check if the candidate client slot is empty.
297 if (NULL
!= SmpClientDirectory
.CandidateClient
)
299 DPRINT1("SM: %s: CandidateClient pending!\n", __FUNCTION__
);
300 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
301 return STATUS_UNSUCCESSFUL
;
304 * Allocate the storage for client data
306 SmpClientDirectory
.CandidateClient
=
307 RtlAllocateHeap (SmpHeap
,
309 sizeof (SM_CLIENT_DATA
));
310 if (NULL
== SmpClientDirectory
.CandidateClient
)
312 DPRINT("SM: %s(%lx): out of memory!\n",
313 __FUNCTION__
, ProcessInfo
->ProcessHandle
);
314 Status
= STATUS_NO_MEMORY
;
318 /* Initialize the candidate client. */
319 RtlInitializeCriticalSection(& SmpClientDirectory
.CandidateClient
->Lock
);
320 SmpClientDirectory
.CandidateClient
->ServerProcess
=
321 (HANDLE
) ProcessInfo
->ProcessHandle
;
322 SmpClientDirectory
.CandidateClient
->ServerProcessId
=
323 (ULONG
) ProcessInfo
->ClientId
.UniqueProcess
;
326 * Copy the program name
328 RtlCopyMemory (SmpClientDirectory
.CandidateClient
->ProgramName
,
330 SM_SB_NAME_MAX_LENGTH
);
331 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
335 /**********************************************************************
338 * 1. close any handle
339 * 2. kill client process
340 * 3. release resources
343 SmDestroyClient (ULONG SubsystemId
)
345 NTSTATUS Status
= STATUS_SUCCESS
;
346 PSM_CLIENT_DATA Parent
= NULL
;
347 PSM_CLIENT_DATA Client
= NULL
;
349 DPRINT("SM: %s called\n", __FUNCTION__
);
351 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
352 Client
= SmpLookupClient (SubsystemId
, & Parent
);
355 DPRINT1("SM: %s: del req for non existent subsystem (id=%d)\n",
356 __FUNCTION__
, SubsystemId
);
357 Status
= STATUS_NOT_FOUND
;
361 /* 1st in the list? */
364 SmpClientDirectory
.Client
= Client
->Next
;
370 Parent
->Next
= Client
->Next
;
372 DPRINT1("SM: %s: n-th has no parent!\n", __FUNCTION__
);
373 Status
= STATUS_UNSUCCESSFUL
; /* FIXME */
376 /* TODO: send shutdown or kill */
377 NtTerminateProcess (Client
->ServerProcess
, 0); //FIXME
378 RtlFreeHeap (SmpHeap
, 0, Client
);
379 -- SmpClientDirectory
.Count
;
381 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
385 /* === Utilities for SmQryInfo === */
387 /**********************************************************************
388 * SmGetClientBasicInformation/1
391 SmGetClientBasicInformation (PSM_BASIC_INFORMATION i
)
394 PSM_CLIENT_DATA ClientData
= NULL
;
396 DPRINT("SM: %s called\n", __FUNCTION__
);
398 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
400 i
->SubSystemCount
= SmpClientDirectory
.Count
;
403 if (SmpClientDirectory
.Count
> 0)
405 ClientData
= SmpClientDirectory
.Client
;
406 while ((NULL
!= ClientData
) && (Index
< SM_QRYINFO_MAX_SS_COUNT
))
408 i
->SubSystem
[Index
].Id
= ClientData
->SubsystemId
;
409 i
->SubSystem
[Index
].Flags
= ClientData
->Flags
;
410 i
->SubSystem
[Index
].ProcessId
= ClientData
->ServerProcessId
;
411 ClientData
= ClientData
->Next
;
415 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
416 return STATUS_SUCCESS
;
419 /**********************************************************************
420 * SmGetSubSystemInformation/1
423 SmGetSubSystemInformation (PSM_SUBSYSTEM_INFORMATION i
)
425 NTSTATUS Status
= STATUS_SUCCESS
;
426 PSM_CLIENT_DATA ClientData
= NULL
;
428 DPRINT("SM: %s called\n", __FUNCTION__
);
430 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
431 ClientData
= SmpLookupClient (i
->SubSystemId
, NULL
);
432 if (NULL
== ClientData
)
434 Status
= STATUS_NOT_FOUND
;
438 i
->Flags
= ClientData
->Flags
;
439 i
->ProcessId
= ClientData
->ServerProcessId
;
440 RtlCopyMemory (i
->NameSpaceRootNode
,
441 ClientData
->SbApiPortName
,
442 (SM_QRYINFO_MAX_ROOT_NODE
* sizeof(i
->NameSpaceRootNode
[0])));
444 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);