Fix a memory leak
[reactos.git] / reactos / subsys / smss / smapi.c
1 /* $Id$
2 *
3 * smapi.c - \SmApiPort LPC port message management
4 *
5 * Reactos Session Manager
6 *
7 */
8 #include "smss.h"
9
10 #define NDEBUG
11 #include <debug.h>
12
13 /* GLOBAL VARIABLES *********************************************************/
14
15 static HANDLE SmApiPort = INVALID_HANDLE_VALUE;
16
17 /* SM API *******************************************************************/
18
19 SMAPI(SmInvalid)
20 {
21 DPRINT("SM: %s called\n",__FUNCTION__);
22 Request->SmHeader.Status = STATUS_NOT_IMPLEMENTED;
23 return STATUS_SUCCESS;
24 }
25
26 /* SM API Table */
27 typedef NTSTATUS (FASTCALL * SM_PORT_API)(PSM_PORT_MESSAGE);
28
29 SM_PORT_API SmApi [] =
30 {
31 SmInvalid, /* unused */
32 SmCompSes, /* smapicomp.c */
33 SmInvalid, /* obsolete */
34 SmInvalid, /* unknown */
35 SmExecPgm, /* smapiexec.c */
36 SmQryInfo /* smapyqry.c */
37 };
38
39 /* TODO: optimize this address computation (it should be done
40 * with a macro) */
41 PSM_CONNECT_DATA FASTCALL SmpGetConnectData (PSM_PORT_MESSAGE Request)
42 {
43 PPORT_MESSAGE PortMessage = (PPORT_MESSAGE) Request;
44 return (PSM_CONNECT_DATA)(PortMessage + 1);
45 }
46
47 #if !defined(__USE_NT_LPC__)
48 NTSTATUS STDCALL
49 SmpHandleConnectionRequest (PSM_PORT_MESSAGE Request);
50 #endif
51
52 /**********************************************************************
53 * SmpCallbackServer/2
54 *
55 * DESCRIPTION
56 * The SM calls back a previously connected subsystem process to
57 * authorize it to bootstrap (initialize). The SM connects to a
58 * named LPC port which name was sent in the connection data by
59 * the candidate subsystem server process.
60 */
61 static NTSTATUS
62 SmpCallbackServer (PSM_PORT_MESSAGE Request,
63 PSM_CLIENT_DATA ClientData)
64 {
65 NTSTATUS Status = STATUS_SUCCESS;
66 PSM_CONNECT_DATA ConnectData = SmpGetConnectData (Request);
67 UNICODE_STRING CallbackPortName;
68 ULONG CallbackPortNameLength = SM_SB_NAME_MAX_LENGTH; /* TODO: compute length */
69 SB_CONNECT_DATA SbConnectData;
70 ULONG SbConnectDataLength = sizeof SbConnectData;
71
72 DPRINT("SM: %s called\n", __FUNCTION__);
73
74 if ( ((USHORT)-1 == ConnectData->SubSystemId) ||
75 (IMAGE_SUBSYSTEM_NATIVE == ConnectData->SubSystemId))
76 {
77 DPRINT("SM: %s: we do not need calling back SM!\n",
78 __FUNCTION__);
79 return STATUS_SUCCESS;
80 }
81 RtlCopyMemory (ClientData->SbApiPortName,
82 ConnectData->SbName,
83 CallbackPortNameLength);
84 RtlInitUnicodeString (& CallbackPortName,
85 ClientData->SbApiPortName);
86
87 SbConnectData.SmApiMax = (sizeof SmApi / sizeof SmApi[0]);
88 Status = NtConnectPort (& ClientData->SbApiPort,
89 & CallbackPortName,
90 NULL,
91 NULL,
92 NULL,
93 NULL,
94 & SbConnectData,
95 & SbConnectDataLength);
96 return Status;
97 }
98
99 /**********************************************************************
100 * NAME
101 * SmpApiConnectedThread/1
102 *
103 * DESCRIPTION
104 * Entry point for the listener thread of LPC port "\SmApiPort".
105 */
106 VOID STDCALL
107 SmpApiConnectedThread(PVOID pConnectedPort)
108 {
109 NTSTATUS Status = STATUS_SUCCESS;
110 PPORT_MESSAGE Reply = NULL;
111 SM_PORT_MESSAGE Request;
112 HANDLE ConnectedPort = * (PHANDLE) pConnectedPort;
113
114 DPRINT("SM: %s called\n", __FUNCTION__);
115 RtlZeroMemory(&Request, sizeof(SM_PORT_MESSAGE));
116
117 while (TRUE)
118 {
119 DPRINT("SM: %s: waiting for message\n",__FUNCTION__);
120
121 Status = NtReplyWaitReceivePort(ConnectedPort,
122 NULL,
123 Reply,
124 (PPORT_MESSAGE) & Request);
125 if (NT_SUCCESS(Status))
126 {
127 DPRINT("SM: %s: message received (type=%d)\n",
128 __FUNCTION__,
129 Request.Header.u2.s2.Type);
130
131 switch (Request.Header.u2.s2.Type)
132 {
133 case LPC_CONNECTION_REQUEST:
134 SmpHandleConnectionRequest (&Request);
135 Reply = NULL;
136 break;
137 case LPC_DEBUG_EVENT:
138 // DbgSsHandleKmApiMsg (&Request, 0);
139 Reply = NULL;
140 break;
141 case LPC_PORT_CLOSED:
142 Reply = NULL;
143 break;
144 default:
145 if ((Request.SmHeader.ApiIndex) &&
146 (Request.SmHeader.ApiIndex < (sizeof SmApi / sizeof SmApi[0])))
147 {
148 Status = SmApi[Request.SmHeader.ApiIndex](&Request);
149 Reply = (PPORT_MESSAGE) & Request;
150 } else {
151 Request.SmHeader.Status = STATUS_NOT_IMPLEMENTED;
152 Reply = (PPORT_MESSAGE) & Request;
153 }
154 }
155 } else {
156 /* LPC failed */
157 break;
158 }
159 }
160 NtClose (ConnectedPort);
161 NtTerminateThread (NtCurrentThread(), Status);
162 }
163
164 /**********************************************************************
165 * NAME
166 * SmpHandleConnectionRequest/1
167 *
168 * ARGUMENTS
169 * Request: LPC connection request message
170 *
171 * REMARKS
172 * Quoted in http://support.microsoft.com/kb/258060/EN-US/
173 */
174 NTSTATUS STDCALL
175 SmpHandleConnectionRequest (PSM_PORT_MESSAGE Request)
176 {
177 PSM_CONNECT_DATA ConnectData = SmpGetConnectData (Request);
178 NTSTATUS Status = STATUS_SUCCESS;
179 BOOL Accept = FALSE;
180 PSM_CLIENT_DATA ClientData = NULL;
181 HANDLE hClientDataApiPort = (HANDLE) 0;
182 PHANDLE ClientDataApiPort = & hClientDataApiPort;
183 HANDLE hClientDataApiPortThread = (HANDLE) 0;
184 PHANDLE ClientDataApiPortThread = & hClientDataApiPortThread;
185 PVOID Context = NULL;
186
187 DPRINT("SM: %s called:\n SubSystemID=%d\n SbName=\"%S\"\n",
188 __FUNCTION__, ConnectData->SubSystemId, ConnectData->SbName);
189
190 if(sizeof (SM_CONNECT_DATA) == Request->Header.u1.s1.DataLength)
191 {
192 if(IMAGE_SUBSYSTEM_UNKNOWN == ConnectData->SubSystemId)
193 {
194 /*
195 * This is not a call to register an image set,
196 * but a simple connection request from a process
197 * that will use the SM API.
198 */
199 DPRINT("SM: %s: simple request\n", __FUNCTION__);
200 ClientDataApiPort = & hClientDataApiPort;
201 ClientDataApiPortThread = & hClientDataApiPortThread;
202 Accept = TRUE;
203 } else {
204 DPRINT("SM: %s: request to register an image set\n", __FUNCTION__);
205 /*
206 * Reject GUIs classes: only odd subsystem IDs are
207 * allowed to register here (tty mode images).
208 */
209 if(1 == (ConnectData->SubSystemId % 2))
210 {
211 DPRINT("SM: %s: id = %d\n", __FUNCTION__, ConnectData->SubSystemId);
212 /*
213 * SmBeginClientInitialization/2 will succeed only if there
214 * is a candidate client ready.
215 */
216 Status = SmBeginClientInitialization (Request, & ClientData);
217 if(STATUS_SUCCESS == Status)
218 {
219 DPRINT("SM: %s: ClientData = 0x%08lx\n",
220 __FUNCTION__, ClientData);
221 /*
222 * OK: the client is an environment subsystem
223 * willing to manage a free image type.
224 */
225 ClientDataApiPort = & ClientData->ApiPort;
226 ClientDataApiPortThread = & ClientData->ApiPortThread;
227 /*
228 * Call back the candidate environment subsystem
229 * server (use the port name sent in in the
230 * connection request message).
231 */
232 Status = SmpCallbackServer (Request, ClientData);
233 if(NT_SUCCESS(Status))
234 {
235 DPRINT("SM: %s: SmpCallbackServer OK\n",
236 __FUNCTION__);
237 Accept = TRUE;
238 } else {
239 DPRINT("SM: %s: SmpCallbackServer failed (Status=%08lx)\n",
240 __FUNCTION__, Status);
241 Status = SmDestroyClient (ConnectData->SubSystemId);
242 }
243 }
244 }
245 }
246 }
247 DPRINT("SM: %s: before NtAcceptConnectPort\n", __FUNCTION__);
248 #if defined(__USE_NT_LPC__)
249 Status = NtAcceptConnectPort (ClientDataApiPort,
250 Context,
251 (PPORT_MESSAGE) Request,
252 Accept,
253 NULL,
254 NULL);
255 #else /* ReactOS LPC */
256 Status = NtAcceptConnectPort (ClientDataApiPort,
257 SmApiPort, // ROS LPC requires the listen port here
258 Context,
259 Accept,
260 NULL,
261 NULL);
262 #endif
263 if(Accept)
264 {
265 if(!NT_SUCCESS(Status))
266 {
267 DPRINT1("SM: %s: NtAcceptConnectPort() failed (Status=0x%08lx)\n",
268 __FUNCTION__, Status);
269 return Status;
270 } else {
271 DPRINT("SM: %s: completing conn req\n", __FUNCTION__);
272 Status = NtCompleteConnectPort (*ClientDataApiPort);
273 if (!NT_SUCCESS(Status))
274 {
275 DPRINT1("SM: %s: NtCompleteConnectPort() failed (Status=0x%08lx)\n",
276 __FUNCTION__, Status);
277 return Status;
278 }
279 #if !defined(__USE_NT_LPC__) /* ReactOS LPC */
280 DPRINT("SM: %s: server side comm port thread (ROS LPC)\n", __FUNCTION__);
281 Status = RtlCreateUserThread(NtCurrentProcess(),
282 NULL,
283 FALSE,
284 0,
285 0,
286 0,
287 (PTHREAD_START_ROUTINE) SmpApiConnectedThread,
288 ClientDataApiPort,
289 ClientDataApiPortThread,
290 NULL);
291 if (!NT_SUCCESS(Status))
292 {
293 DPRINT1("SM: %s: Unable to create server thread (Status=0x%08lx)\n",
294 __FUNCTION__, Status);
295 return Status;
296 }
297 #endif
298 }
299 Status = STATUS_SUCCESS;
300 }
301 DPRINT("SM: %s done\n", __FUNCTION__);
302 return Status;
303 }
304
305 /**********************************************************************
306 * NAME
307 * SmpApiThread/1
308 *
309 * DECRIPTION
310 * Due to differences in LPC implementation between NT and ROS,
311 * we need a thread to listen to for connection request that
312 * creates a new thread for each connected port. This is not
313 * necessary in NT LPC, because server side connected ports are
314 * never used to receive requests.
315 */
316 VOID STDCALL
317 SmpApiThread (HANDLE ListeningPort)
318 {
319 NTSTATUS Status = STATUS_SUCCESS;
320 SM_PORT_MESSAGE Request;
321
322 DPRINT("SM: %s called\n", __FUNCTION__);
323 RtlZeroMemory(&Request, sizeof(PORT_MESSAGE));
324
325 while (TRUE)
326 {
327 Status = NtListenPort (ListeningPort, & Request.Header);
328 if (!NT_SUCCESS(Status))
329 {
330 DPRINT1("SM: %s: NtListenPort() failed! (Status==x%08lx)\n", __FUNCTION__, Status);
331 break;
332 }
333 Status = SmpHandleConnectionRequest (& Request);
334 if(!NT_SUCCESS(Status))
335 {
336 DPRINT1("SM: %s: SmpHandleConnectionRequest failed (Status=0x%08lx)\n",
337 __FUNCTION__, Status);
338 break;
339 }
340 }
341 /* Cleanup */
342 NtClose(ListeningPort);
343 /* DIE */
344 NtTerminateThread(NtCurrentThread(), Status);
345 }
346
347
348 /* LPC PORT INITIALIZATION **************************************************/
349
350
351 /**********************************************************************
352 * NAME
353 * SmCreateApiPort/0
354 *
355 * DECRIPTION
356 */
357 NTSTATUS
358 SmCreateApiPort(VOID)
359 {
360 OBJECT_ATTRIBUTES ObjectAttributes = {0};
361 UNICODE_STRING UnicodeString = RTL_CONSTANT_STRING(L"\\SmApiPort");
362 NTSTATUS Status = STATUS_SUCCESS;
363
364 InitializeObjectAttributes(&ObjectAttributes,
365 &UnicodeString,
366 0,
367 NULL,
368 NULL);
369
370 Status = NtCreatePort(&SmApiPort,
371 &ObjectAttributes,
372 0,
373 0,
374 0);
375 if (!NT_SUCCESS(Status))
376 {
377 return(Status);
378 }
379 /*
380 * Create one thread for the named LPC
381 * port \SmApiPort
382 */
383 RtlCreateUserThread(NtCurrentProcess(),
384 NULL,
385 FALSE,
386 0,
387 0,
388 0,
389 (PTHREAD_START_ROUTINE)SmpApiThread,
390 (PVOID)SmApiPort,
391 NULL,
392 NULL);
393
394 return(Status);
395 }
396
397 /* EOF */