remove whitespace from end of lines
[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
9 #include "smss.h"
10 #include <rosrtl/string.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBAL VARIABLES *********************************************************/
16
17 static HANDLE SmApiPort = INVALID_HANDLE_VALUE;
18
19 /* SM API *******************************************************************/
20
21 SMAPI(SmInvalid)
22 {
23 DPRINT("SM: %s called\n",__FUNCTION__);
24 Request->SmHeader.Status = STATUS_NOT_IMPLEMENTED;
25 return STATUS_SUCCESS;
26 }
27
28 /* SM API Table */
29 typedef NTSTATUS (FASTCALL * SM_PORT_API)(PSM_PORT_MESSAGE);
30
31 SM_PORT_API SmApi [] =
32 {
33 SmInvalid, /* unused */
34 SmCompSes, /* smapicomp.c */
35 SmInvalid, /* obsolete */
36 SmInvalid, /* unknown */
37 SmExecPgm, /* smapiexec.c */
38 SmQryInfo /* smapyqry.c */
39 };
40
41 /* TODO: optimize this address computation (it should be done
42 * with a macro) */
43 PSM_CONNECT_DATA FASTCALL SmpGetConnectData (PSM_PORT_MESSAGE Request)
44 {
45 PLPC_MAX_MESSAGE LpcMaxMessage = (PLPC_MAX_MESSAGE) Request;
46 return (PSM_CONNECT_DATA) & LpcMaxMessage->Data[0];
47 }
48
49 #if !defined(__USE_NT_LPC__)
50 NTSTATUS STDCALL
51 SmpHandleConnectionRequest (PSM_PORT_MESSAGE Request);
52 #endif
53
54 /**********************************************************************
55 * SmpCallback/2
56 *
57 * The SM calls back a previously connected subsystem process to
58 * authorizes it to bootstrap (initialize). The SM connects to a
59 * named LPC port which name was sent in the connection data by the
60 * candidate subsystem server process.
61 */
62 static NTSTATUS
63 SmpCallbackServer (PSM_PORT_MESSAGE Request,
64 PSM_CLIENT_DATA ClientData)
65 {
66 NTSTATUS Status = STATUS_SUCCESS;
67 PSM_CONNECT_DATA ConnectData = SmpGetConnectData (Request);
68 UNICODE_STRING CallbackPortName;
69 ULONG CallbackPortNameLength = SM_SB_NAME_MAX_LENGTH; /* TODO: compute length */
70 SB_CONNECT_DATA SbConnectData;
71 ULONG SbConnectDataLength = sizeof SbConnectData;
72
73 DPRINT("SM: %s called\n", __FUNCTION__);
74
75 if(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 PVOID Unknown = NULL;
111 PLPC_MESSAGE Reply = NULL;
112 SM_PORT_MESSAGE Request = {{0}};
113 HANDLE ConnectedPort = * (PHANDLE) pConnectedPort;
114
115 DPRINT("SM: %s called\n", __FUNCTION__);
116
117 while (TRUE)
118 {
119 DPRINT("SM: %s: waiting for message\n",__FUNCTION__);
120
121 Status = NtReplyWaitReceivePort(ConnectedPort,
122 (PULONG) & Unknown,
123 Reply,
124 (PLPC_MESSAGE) & Request);
125 if (NT_SUCCESS(Status))
126 {
127 DPRINT("SM: %s: message received (type=%d)\n",
128 __FUNCTION__,
129 PORT_MESSAGE_TYPE(Request));
130
131 switch (Request.Header.MessageType)
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 = (PLPC_MESSAGE) & Request;
150 } else {
151 Request.SmHeader.Status = STATUS_NOT_IMPLEMENTED;
152 Reply = (PLPC_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.DataSize)
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 * SmCreateClient/2 is called here explicitly to *fail*.
214 * If it succeeds, there is something wrong in the
215 * connection request. An environment subsystem *never*
216 * registers twice. (security issue)
217 */
218 Status = SmCreateClient (Request, & ClientData);
219 if(STATUS_SUCCESS == Status)
220 {
221 DPRINT("SM: %s: ClientData = 0x%08lx\n",
222 __FUNCTION__, ClientData);
223 /*
224 * OK: the client is an environment subsystem
225 * willing to manage a free image type.
226 */
227 ClientDataApiPort = & ClientData->ApiPort;
228 ClientDataApiPortThread = & ClientData->ApiPortThread;
229 /*
230 * Call back the candidate environment subsystem
231 * server (use the port name sent in in the
232 * connection request message).
233 */
234 Status = SmpCallbackServer (Request, ClientData);
235 if(NT_SUCCESS(Status))
236 {
237 DPRINT("SM: %s: SmpCallbackServer OK\n",
238 __FUNCTION__);
239 Accept = TRUE;
240 } else {
241 DPRINT("SM: %s: SmpCallbackServer failed (Status=%08lx)\n",
242 __FUNCTION__, Status);
243 Status = SmDestroyClient (ConnectData->SubSystemId);
244 }
245 }
246 }
247 }
248 }
249 DPRINT("SM: %s: before NtAcceptConnectPort\n", __FUNCTION__);
250 #if defined(__USE_NT_LPC__)
251 Status = NtAcceptConnectPort (ClientDataApiPort,
252 Context,
253 (PLPC_MESSAGE) Request,
254 Accept,
255 NULL,
256 NULL);
257 #else /* ReactOS LPC */
258 Status = NtAcceptConnectPort (ClientDataApiPort,
259 SmApiPort, // ROS LPC requires the listen port here
260 Context,
261 Accept,
262 NULL,
263 NULL);
264 #endif
265 if(Accept)
266 {
267 if(!NT_SUCCESS(Status))
268 {
269 DPRINT1("SM: %s: NtAcceptConnectPort() failed (Status=0x%08lx)\n",
270 __FUNCTION__, Status);
271 return Status;
272 } else {
273 DPRINT("SM: %s: completing conn req\n", __FUNCTION__);
274 Status = NtCompleteConnectPort (*ClientDataApiPort);
275 if (!NT_SUCCESS(Status))
276 {
277 DPRINT1("SM: %s: NtCompleteConnectPort() failed (Status=0x%08lx)\n",
278 __FUNCTION__, Status);
279 return Status;
280 }
281 #if !defined(__USE_NT_LPC__) /* ReactOS LPC */
282 DPRINT("SM: %s: server side comm port thread (ROS LPC)\n", __FUNCTION__);
283 Status = RtlCreateUserThread(NtCurrentProcess(),
284 NULL,
285 FALSE,
286 0,
287 NULL,
288 NULL,
289 (PTHREAD_START_ROUTINE) SmpApiConnectedThread,
290 ClientDataApiPort,
291 ClientDataApiPortThread,
292 NULL);
293 if (!NT_SUCCESS(Status))
294 {
295 DPRINT1("SM: %s: Unable to create server thread (Status=0x%08lx)\n",
296 __FUNCTION__, Status);
297 return Status;
298 }
299 #endif
300 }
301 Status = STATUS_SUCCESS;
302 }
303 DPRINT("SM: %s done\n", __FUNCTION__);
304 return Status;
305 }
306
307 /**********************************************************************
308 * NAME
309 * SmpApiThread/1
310 *
311 * DECRIPTION
312 * Due to differences in LPC implementation between NT and ROS,
313 * we need a thread to listen for connection request that
314 * creates a new thread for each connected port. This is not
315 * necessary in NT LPC, because server side connected ports are
316 * never used to receive requests.
317 */
318 VOID STDCALL
319 SmpApiThread (HANDLE ListeningPort)
320 {
321 NTSTATUS Status = STATUS_SUCCESS;
322 LPC_MAX_MESSAGE Request = {{0}};
323
324 DPRINT("SM: %s called\n", __FUNCTION__);
325
326 while (TRUE)
327 {
328 Status = NtListenPort (ListeningPort, & Request.Header);
329 if (!NT_SUCCESS(Status))
330 {
331 DPRINT1("SM: %s: NtListenPort() failed! (Status==x%08lx)\n", __FUNCTION__, Status);
332 break;
333 }
334 Status = SmpHandleConnectionRequest ((PSM_PORT_MESSAGE) & Request);
335 if(!NT_SUCCESS(Status))
336 {
337 DPRINT1("SM: %s: SmpHandleConnectionRequest failed (Status=0x%08lx)\n",
338 __FUNCTION__, Status);
339 break;
340 }
341 }
342 /* Cleanup */
343 NtClose(ListeningPort);
344 /* DIE */
345 NtTerminateThread(NtCurrentThread(), Status);
346 }
347
348
349 /* LPC PORT INITIALIZATION **************************************************/
350
351
352 /**********************************************************************
353 * NAME
354 * SmCreateApiPort/0
355 *
356 * DECRIPTION
357 */
358 NTSTATUS
359 SmCreateApiPort(VOID)
360 {
361 OBJECT_ATTRIBUTES ObjectAttributes = {0};
362 UNICODE_STRING UnicodeString = {0};
363 NTSTATUS Status = STATUS_SUCCESS;
364
365 RtlRosInitUnicodeStringFromLiteral(&UnicodeString,
366 L"\\SmApiPort");
367 InitializeObjectAttributes(&ObjectAttributes,
368 &UnicodeString,
369 PORT_ALL_ACCESS,
370 NULL,
371 NULL);
372
373 Status = NtCreatePort(&SmApiPort,
374 &ObjectAttributes,
375 0,
376 0,
377 0);
378 if (!NT_SUCCESS(Status))
379 {
380 return(Status);
381 }
382 /*
383 * Create one thread for the named LPC
384 * port \SmApiPort
385 */
386 RtlCreateUserThread(NtCurrentProcess(),
387 NULL,
388 FALSE,
389 0,
390 NULL,
391 NULL,
392 (PTHREAD_START_ROUTINE)SmpApiThread,
393 (PVOID)SmApiPort,
394 NULL,
395 NULL);
396
397 return(Status);
398 }
399
400 /* EOF */