SM: change the way sessions are managed.
[reactos.git] / reactos / subsys / smss / client.c
1 /* $Id: smss.c 12852 2005-01-06 13:58:04Z mf $
2 *
3 * client.c - Session Manager client Management
4 *
5 * ReactOS Operating System
6 *
7 * --------------------------------------------------------------------
8 *
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.
13 *
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.
18 *
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,
22 * MA 02139, USA.
23 *
24 * --------------------------------------------------------------------
25 */
26 #define NTOS_MODE_USER
27 #include <ntos.h>
28 #include "smss.h"
29 #include <sm/helper.h>
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /* Private ADT */
35
36
37 struct _SM_CLIENT_DIRECTORY
38 {
39 RTL_CRITICAL_SECTION Lock;
40 ULONG Count;
41 PSM_CLIENT_DATA Client;
42 PSM_CLIENT_DATA CandidateClient;
43
44 } SmpClientDirectory;
45
46
47 /**********************************************************************
48 * SmInitializeClientManagement/0
49 */
50 NTSTATUS
51 SmInitializeClientManagement (VOID)
52 {
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;
59
60 }
61 /**********************************************************************
62 * SmpSetClientInitialized/1
63 */
64 VOID FASTCALL
65 SmpSetClientInitialized (PSM_CLIENT_DATA Client)
66 {
67 Client->Flags |= SM_CLIENT_FLAG_INITIALIZED;
68 }
69 /**********************************************************************
70 * SmpLookupClient/2 PRIVATE
71 *
72 * DESCRIPTION
73 * Lookup the subsystem server descriptor given its image ID.
74 *
75 * ARGUMENTS
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).
81 *
82 * RETURN VALUES
83 * NULL on error; otherwise a pointer to the SM_CLIENT_DATA
84 * looked up object.
85 *
86 * WARNING
87 * SmpClientDirectory.Lock must be held by the caller.
88 */
89 static PSM_CLIENT_DATA FASTCALL
90 SmpLookupClient (USHORT SubsystemId,
91 PSM_CLIENT_DATA * Parent)
92 {
93 PSM_CLIENT_DATA Client = NULL;
94
95 DPRINT("SM: %s(%d) called\n", __FUNCTION__, SubsystemId);
96
97 if(NULL != Parent)
98 {
99 *Parent = NULL;
100 }
101 if (SmpClientDirectory.Count > 0)
102 {
103 Client = SmpClientDirectory.Client;
104 while (NULL != Client)
105 {
106 if (SubsystemId == Client->SubsystemId)
107 {
108 break;
109 }
110 if(NULL != Parent)
111 {
112 *Parent = Client;
113 }
114 Client = Client->Next;
115 }
116 }
117 return Client;
118 }
119 /**********************************************************************
120 * SmBeginClientInitialization/1
121 *
122 * DESCRIPTION
123 * Check if the candidate client matches the begin session
124 * message from the subsystem process.
125 *
126 * ARGUMENTS
127 * Request: message received by \SmApiPort
128 * ClientData:
129 *
130 * RETURN VALUES
131 * NTSTATUS
132 */
133 NTSTATUS STDCALL
134 SmBeginClientInitialization (IN PSM_PORT_MESSAGE Request,
135 OUT PSM_CLIENT_DATA * ClientData)
136 {
137 NTSTATUS Status = STATUS_SUCCESS;
138 PSM_CONNECT_DATA ConnectData = SmpGetConnectData (Request);
139 ULONG SbApiPortNameSize = SM_CONNECT_DATA_SIZE(*Request);
140
141
142 DPRINT("SM: %s called\n", __FUNCTION__);
143
144 RtlEnterCriticalSection (& SmpClientDirectory.Lock);
145 /*
146 * Is there a subsystem bootstrap in progress?
147 */
148 if (SmpClientDirectory.CandidateClient)
149 {
150 PROCESS_BASIC_INFORMATION pbi;
151
152 RtlZeroMemory (& pbi, sizeof pbi);
153 Status = NtQueryInformationProcess (Request->Header.ClientId.UniqueProcess,
154 ProcessBasicInformation,
155 & pbi,
156 sizeof pbi,
157 NULL);
158 if (NT_SUCCESS(Status))
159 {
160 SmpClientDirectory.CandidateClient->ServerProcessId =
161 (ULONG) pbi.UniqueProcessId;
162 }
163 }
164 else
165 {
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);
170 return Status;
171 }
172 /*
173 * Check if a client for the ID already exist.
174 */
175 if (SmpLookupClient(ConnectData->SubSystemId, NULL))
176 {
177 DPRINT("SM: %s: attempt to register again subsystem %d.\n",
178 __FUNCTION__,
179 ConnectData->SubSystemId);
180 return STATUS_UNSUCCESSFUL;
181 }
182 DPRINT("SM: %s: registering subsystem ID=%d \n",
183 __FUNCTION__, ConnectData->SubSystemId);
184
185 /*
186 * Initialize the client data
187 */
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))
193 {
194 SmpSetClientInitialized (SmpClientDirectory.CandidateClient);
195 }
196 if (SbApiPortNameSize > 0)
197 {
198 RtlCopyMemory (SmpClientDirectory.CandidateClient->SbApiPortName,
199 ConnectData->SbName,
200 SbApiPortNameSize);
201 }
202 /*
203 * Insert the new descriptor in the
204 * client directory.
205 */
206 if (NULL == SmpClientDirectory.Client)
207 {
208 SmpClientDirectory.Client = SmpClientDirectory.CandidateClient;
209 } else {
210 PSM_CLIENT_DATA pCD = NULL;
211
212 for (pCD=SmpClientDirectory.Client;
213 (NULL != pCD->Next);
214 pCD = pCD->Next);
215 pCD->Next = SmpClientDirectory.CandidateClient;
216 }
217 SmpClientDirectory.CandidateClient->Next = NULL;
218 /*
219 * Increment the number of active subsystems.
220 */
221 ++ SmpClientDirectory.Count;
222 /*
223 * Notify to the caller the reference to the client data.
224 */
225 if (ClientData)
226 {
227 *ClientData = SmpClientDirectory.CandidateClient;
228 }
229 /*
230 * Free the slot for the candidate subsystem.
231 */
232 SmpClientDirectory.CandidateClient = NULL;
233
234 RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
235
236 return STATUS_SUCCESS;
237 }
238 /**********************************************************************
239 * SmCompleteClientInitialization/1
240 *
241 * DESCRIPTION
242 * Lookup the subsystem server descriptor given the process ID
243 * of the subsystem server process.
244 */
245 NTSTATUS STDCALL
246 SmCompleteClientInitialization (ULONG ProcessId)
247 {
248 NTSTATUS Status = STATUS_SUCCESS;
249 PSM_CLIENT_DATA Client = NULL;
250
251 DPRINT("SM: %s called\n", __FUNCTION__);
252
253 RtlEnterCriticalSection (& SmpClientDirectory.Lock);
254 if (SmpClientDirectory.Count > 0)
255 {
256 Client = SmpClientDirectory.Client;
257 while (NULL != Client)
258 {
259 if (ProcessId == Client->ServerProcessId)
260 {
261 SmpSetClientInitialized (Client);
262 break;
263 }
264 Client = Client->Next;
265 }
266 Status = STATUS_NOT_FOUND;
267 }
268 RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
269 return Status;
270 }
271
272 /**********************************************************************
273 * SmpCreateClient/1
274 *
275 * DESCRIPTION
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.
279 *
280 * ARGUMENTS
281 * ProcessHandle: handle of the subsystem server process.
282 *
283 * RETURN VALUE
284 * NTSTATUS:
285 */
286 NTSTATUS STDCALL
287 SmCreateClient (PRTL_PROCESS_INFO ProcessInfo, PWSTR ProgramName)
288 {
289 NTSTATUS Status = STATUS_SUCCESS;
290
291
292 DPRINT("SM: %s(%lx) called\n", __FUNCTION__, ProcessInfo->ProcessHandle);
293 RtlEnterCriticalSection (& SmpClientDirectory.Lock);
294 /*
295 * Check if the candidate client slot is empty.
296 */
297 if (NULL != SmpClientDirectory.CandidateClient)
298 {
299 DPRINT1("SM: %s: CandidateClient pending!\n", __FUNCTION__);
300 RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
301 return STATUS_UNSUCCESSFUL;
302 }
303 /*
304 * Allocate the storage for client data
305 */
306 SmpClientDirectory.CandidateClient =
307 RtlAllocateHeap (SmpHeap,
308 HEAP_ZERO_MEMORY,
309 sizeof (SM_CLIENT_DATA));
310 if (NULL == SmpClientDirectory.CandidateClient)
311 {
312 DPRINT("SM: %s(%lx): out of memory!\n",
313 __FUNCTION__, ProcessInfo->ProcessHandle);
314 Status = STATUS_NO_MEMORY;
315 }
316 else
317 {
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;
324 }
325 /*
326 * Copy the program name
327 */
328 RtlCopyMemory (SmpClientDirectory.CandidateClient->ProgramName,
329 ProgramName,
330 SM_SB_NAME_MAX_LENGTH);
331 RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
332 return Status;
333 }
334
335 /**********************************************************************
336 * SmpDestroyClient/1
337 *
338 * 1. close any handle
339 * 2. kill client process
340 * 3. release resources
341 */
342 NTSTATUS STDCALL
343 SmDestroyClient (ULONG SubsystemId)
344 {
345 NTSTATUS Status = STATUS_SUCCESS;
346 PSM_CLIENT_DATA Parent = NULL;
347 PSM_CLIENT_DATA Client = NULL;
348
349 DPRINT("SM: %s called\n", __FUNCTION__);
350
351 RtlEnterCriticalSection (& SmpClientDirectory.Lock);
352 Client = SmpLookupClient (SubsystemId, & Parent);
353 if(NULL == Client)
354 {
355 DPRINT1("SM: %s: del req for non existent subsystem (id=%d)\n",
356 __FUNCTION__, SubsystemId);
357 Status = STATUS_NOT_FOUND;
358 }
359 else
360 {
361 /* 1st in the list? */
362 if(NULL == Parent)
363 {
364 SmpClientDirectory.Client = Client->Next;
365 }
366 else
367 {
368 if(NULL != Parent)
369 {
370 Parent->Next = Client->Next;
371 } else {
372 DPRINT1("SM: %s: n-th has no parent!\n", __FUNCTION__);
373 Status = STATUS_UNSUCCESSFUL; /* FIXME */
374 }
375 }
376 /* TODO: send shutdown or kill */
377 NtTerminateProcess (Client->ServerProcess, 0); //FIXME
378 RtlFreeHeap (SmpHeap, 0, Client);
379 -- SmpClientDirectory.Count;
380 }
381 RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
382 return Status;
383 }
384
385 /* === Utilities for SmQryInfo === */
386
387 /**********************************************************************
388 * SmGetClientBasicInformation/1
389 */
390 NTSTATUS FASTCALL
391 SmGetClientBasicInformation (PSM_BASIC_INFORMATION i)
392 {
393 INT Index = 0;
394 PSM_CLIENT_DATA ClientData = NULL;
395
396 DPRINT("SM: %s called\n", __FUNCTION__);
397
398 RtlEnterCriticalSection (& SmpClientDirectory.Lock);
399
400 i->SubSystemCount = SmpClientDirectory.Count;
401 i->Unused = 0;
402
403 if (SmpClientDirectory.Count > 0)
404 {
405 ClientData = SmpClientDirectory.Client;
406 while ((NULL != ClientData) && (Index < SM_QRYINFO_MAX_SS_COUNT))
407 {
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;
412 }
413 }
414
415 RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
416 return STATUS_SUCCESS;
417 }
418
419 /**********************************************************************
420 * SmGetSubSystemInformation/1
421 */
422 NTSTATUS FASTCALL
423 SmGetSubSystemInformation (PSM_SUBSYSTEM_INFORMATION i)
424 {
425 NTSTATUS Status = STATUS_SUCCESS;
426 PSM_CLIENT_DATA ClientData = NULL;
427
428 DPRINT("SM: %s called\n", __FUNCTION__);
429
430 RtlEnterCriticalSection (& SmpClientDirectory.Lock);
431 ClientData = SmpLookupClient (i->SubSystemId, NULL);
432 if (NULL == ClientData)
433 {
434 Status = STATUS_NOT_FOUND;
435 }
436 else
437 {
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])));
443 }
444 RtlLeaveCriticalSection (& SmpClientDirectory.Lock);
445 return Status;
446 }
447
448 /* EOF */