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