3 * smapi.c - \SmApiPort LPC port message management
5 * Reactos Session Manager
13 /* GLOBAL VARIABLES *********************************************************/
15 static HANDLE SmApiPort
= INVALID_HANDLE_VALUE
;
17 /* SM API *******************************************************************/
21 DPRINT("SM: %s called\n",__FUNCTION__
);
22 Request
->SmHeader
.Status
= STATUS_NOT_IMPLEMENTED
;
23 return STATUS_SUCCESS
;
27 typedef NTSTATUS (FASTCALL
* SM_PORT_API
)(PSM_PORT_MESSAGE
);
29 SM_PORT_API SmApi
[] =
31 SmInvalid
, /* unused */
32 SmCompSes
, /* smapicomp.c */
33 SmInvalid
, /* obsolete */
34 SmInvalid
, /* unknown */
35 SmExecPgm
, /* smapiexec.c */
36 SmQryInfo
/* smapyqry.c */
39 /* TODO: optimize this address computation (it should be done
41 PSM_CONNECT_DATA FASTCALL
SmpGetConnectData (PSM_PORT_MESSAGE Request
)
43 PPORT_MESSAGE PortMessage
= (PPORT_MESSAGE
) Request
;
44 return (PSM_CONNECT_DATA
)(PortMessage
+ 1);
48 SmpHandleConnectionRequest (PSM_PORT_MESSAGE Request
);
50 /**********************************************************************
54 * The SM calls back a previously connected subsystem process to
55 * authorize it to bootstrap (initialize). The SM connects to a
56 * named LPC port which name was sent in the connection data by
57 * the candidate subsystem server process.
60 SmpCallbackServer (PSM_PORT_MESSAGE Request
,
61 PSM_CLIENT_DATA ClientData
)
63 NTSTATUS Status
= STATUS_SUCCESS
;
64 PSM_CONNECT_DATA ConnectData
= SmpGetConnectData (Request
);
65 UNICODE_STRING CallbackPortName
;
66 ULONG CallbackPortNameLength
= SM_SB_NAME_MAX_LENGTH
; /* TODO: compute length */
67 SB_CONNECT_DATA SbConnectData
;
68 ULONG SbConnectDataLength
= sizeof SbConnectData
;
69 SECURITY_QUALITY_OF_SERVICE SecurityQos
;
71 DPRINT("SM: %s called\n", __FUNCTION__
);
73 if ( ((USHORT
)-1 == ConnectData
->SubSystemId
) ||
74 (IMAGE_SUBSYSTEM_NATIVE
== ConnectData
->SubSystemId
))
76 DPRINT("SM: %s: we do not need calling back SM!\n",
78 return STATUS_SUCCESS
;
80 RtlCopyMemory (ClientData
->SbApiPortName
,
82 CallbackPortNameLength
);
83 RtlInitUnicodeString (& CallbackPortName
,
84 ClientData
->SbApiPortName
);
86 SecurityQos
.Length
= sizeof (SecurityQos
);
87 SecurityQos
.ImpersonationLevel
= SecurityIdentification
;
88 SecurityQos
.ContextTrackingMode
= SECURITY_DYNAMIC_TRACKING
;
89 SecurityQos
.EffectiveOnly
= TRUE
;
91 SbConnectData
.SmApiMax
= (sizeof SmApi
/ sizeof SmApi
[0]);
92 Status
= NtConnectPort (& ClientData
->SbApiPort
,
99 & SbConnectDataLength
);
103 /**********************************************************************
105 * SmpApiConnectedThread/1
108 * Entry point for the listener thread of LPC port "\SmApiPort".
111 SmpApiConnectedThread(PVOID pConnectedPort
)
113 NTSTATUS Status
= STATUS_SUCCESS
;
114 PPORT_MESSAGE Reply
= NULL
;
115 SM_PORT_MESSAGE Request
;
116 HANDLE ConnectedPort
= * (PHANDLE
) pConnectedPort
;
118 DPRINT("SM: %s called\n", __FUNCTION__
);
119 RtlZeroMemory(&Request
, sizeof(SM_PORT_MESSAGE
));
123 DPRINT("SM: %s: waiting for message\n",__FUNCTION__
);
125 Status
= NtReplyWaitReceivePort(ConnectedPort
,
128 (PPORT_MESSAGE
) & Request
);
129 if (NT_SUCCESS(Status
))
131 DPRINT("SM: %s: message received (type=%d)\n",
133 Request
.Header
.u2
.s2
.Type
);
135 switch (Request
.Header
.u2
.s2
.Type
)
137 case LPC_CONNECTION_REQUEST
:
138 SmpHandleConnectionRequest (&Request
);
141 case LPC_DEBUG_EVENT
:
142 // DbgSsHandleKmApiMsg (&Request, 0);
145 case LPC_PORT_CLOSED
:
149 if ((Request
.SmHeader
.ApiIndex
) &&
150 (Request
.SmHeader
.ApiIndex
< (sizeof SmApi
/ sizeof SmApi
[0])))
152 Status
= SmApi
[Request
.SmHeader
.ApiIndex
](&Request
);
153 Reply
= (PPORT_MESSAGE
) & Request
;
155 Request
.SmHeader
.Status
= STATUS_NOT_IMPLEMENTED
;
156 Reply
= (PPORT_MESSAGE
) & Request
;
164 NtClose (ConnectedPort
);
165 NtTerminateThread (NtCurrentThread(), Status
);
168 /**********************************************************************
170 * SmpHandleConnectionRequest/1
173 * Request: LPC connection request message
176 * Quoted in http://support.microsoft.com/kb/258060/EN-US/
179 SmpHandleConnectionRequest (PSM_PORT_MESSAGE Request
)
181 PSM_CONNECT_DATA ConnectData
= SmpGetConnectData (Request
);
182 NTSTATUS Status
= STATUS_SUCCESS
;
184 PSM_CLIENT_DATA ClientData
= NULL
;
185 HANDLE hClientDataApiPort
= (HANDLE
) 0;
186 PHANDLE ClientDataApiPort
= & hClientDataApiPort
;
187 HANDLE hClientDataApiPortThread
= (HANDLE
) 0;
188 PHANDLE ClientDataApiPortThread
= & hClientDataApiPortThread
;
189 PVOID Context
= NULL
;
191 DPRINT("SM: %s called:\n SubSystemID=%d\n SbName=\"%S\"\n",
192 __FUNCTION__
, ConnectData
->SubSystemId
, ConnectData
->SbName
);
194 if(sizeof (SM_CONNECT_DATA
) == Request
->Header
.u1
.s1
.DataLength
)
196 if(IMAGE_SUBSYSTEM_UNKNOWN
== ConnectData
->SubSystemId
)
199 * This is not a call to register an image set,
200 * but a simple connection request from a process
201 * that will use the SM API.
203 DPRINT("SM: %s: simple request\n", __FUNCTION__
);
204 ClientDataApiPort
= & hClientDataApiPort
;
205 ClientDataApiPortThread
= & hClientDataApiPortThread
;
208 DPRINT("SM: %s: request to register an image set\n", __FUNCTION__
);
210 * Reject GUIs classes: only odd subsystem IDs are
211 * allowed to register here (tty mode images).
213 if(1 == (ConnectData
->SubSystemId
% 2))
215 DPRINT("SM: %s: id = %d\n", __FUNCTION__
, ConnectData
->SubSystemId
);
217 * SmBeginClientInitialization/2 will succeed only if there
218 * is a candidate client ready.
220 Status
= SmBeginClientInitialization (Request
, & ClientData
);
221 if(STATUS_SUCCESS
== Status
)
223 DPRINT("SM: %s: ClientData = 0x%08lx\n",
224 __FUNCTION__
, ClientData
);
226 * OK: the client is an environment subsystem
227 * willing to manage a free image type.
229 ClientDataApiPort
= & ClientData
->ApiPort
;
230 ClientDataApiPortThread
= & ClientData
->ApiPortThread
;
232 * Call back the candidate environment subsystem
233 * server (use the port name sent in in the
234 * connection request message).
236 Status
= SmpCallbackServer (Request
, ClientData
);
237 if(NT_SUCCESS(Status
))
239 DPRINT("SM: %s: SmpCallbackServer OK\n",
243 DPRINT("SM: %s: SmpCallbackServer failed (Status=%08lx)\n",
244 __FUNCTION__
, Status
);
245 Status
= SmDestroyClient (ConnectData
->SubSystemId
);
251 DPRINT("SM: %s: before NtAcceptConnectPort\n", __FUNCTION__
);
253 Status
= NtAcceptConnectPort (ClientDataApiPort
,
255 (PPORT_MESSAGE
) Request
,
259 #else /* ReactOS LPC */
260 Status
= NtAcceptConnectPort (ClientDataApiPort
,
261 SmApiPort
, // ROS LPC requires the listen port here
269 if(!NT_SUCCESS(Status
))
271 DPRINT1("SM: %s: NtAcceptConnectPort() failed (Status=0x%08lx)\n",
272 __FUNCTION__
, Status
);
275 DPRINT("SM: %s: completing conn req\n", __FUNCTION__
);
276 Status
= NtCompleteConnectPort (*ClientDataApiPort
);
277 if (!NT_SUCCESS(Status
))
279 DPRINT1("SM: %s: NtCompleteConnectPort() failed (Status=0x%08lx)\n",
280 __FUNCTION__
, Status
);
283 #if !defined(NTLPC) /* ReactOS LPC */
284 DPRINT("SM: %s: server side comm port thread (ROS LPC)\n", __FUNCTION__
);
285 Status
= RtlCreateUserThread(NtCurrentProcess(),
291 (PTHREAD_START_ROUTINE
) SmpApiConnectedThread
,
293 ClientDataApiPortThread
,
295 if (!NT_SUCCESS(Status
))
297 DPRINT1("SM: %s: Unable to create server thread (Status=0x%08lx)\n",
298 __FUNCTION__
, Status
);
303 Status
= STATUS_SUCCESS
;
305 DPRINT("SM: %s done\n", __FUNCTION__
);
309 /**********************************************************************
314 * Due to differences in LPC implementation between NT and ROS,
315 * we need a thread to listen to for connection request that
316 * creates a new thread for each connected port. This is not
317 * necessary in NT LPC, because server side connected ports are
318 * never used to receive requests.
321 SmpApiThread (HANDLE ListeningPort
)
323 NTSTATUS Status
= STATUS_SUCCESS
;
324 SM_PORT_MESSAGE Request
;
326 DPRINT("SM: %s called\n", __FUNCTION__
);
327 RtlZeroMemory(&Request
, sizeof(PORT_MESSAGE
));
331 Status
= NtListenPort (ListeningPort
, & Request
.Header
);
332 if (!NT_SUCCESS(Status
))
334 DPRINT1("SM: %s: NtListenPort() failed! (Status==x%08lx)\n", __FUNCTION__
, Status
);
337 Status
= SmpHandleConnectionRequest (& Request
);
338 if(!NT_SUCCESS(Status
))
340 DPRINT1("SM: %s: SmpHandleConnectionRequest failed (Status=0x%08lx)\n",
341 __FUNCTION__
, Status
);
346 NtClose(ListeningPort
);
348 NtTerminateThread(NtCurrentThread(), Status
);
352 /* LPC PORT INITIALIZATION **************************************************/
355 /**********************************************************************
362 SmCreateApiPort(VOID
)
364 OBJECT_ATTRIBUTES ObjectAttributes
= {0};
365 UNICODE_STRING UnicodeString
= RTL_CONSTANT_STRING(L
"\\SmApiPort");
366 NTSTATUS Status
= STATUS_SUCCESS
;
368 InitializeObjectAttributes(&ObjectAttributes
,
374 Status
= NtCreatePort(&SmApiPort
,
376 sizeof(SM_CONNECT_DATA
),
377 sizeof(SM_PORT_MESSAGE
),
379 if (!NT_SUCCESS(Status
))
384 * Create one thread for the named LPC
387 RtlCreateUserThread(NtCurrentProcess(),
394 (PTHREAD_START_ROUTINE
)SmpApiConnectedThread
,
397 (PTHREAD_START_ROUTINE
)SmpApiThread
,
405 // On NT LPC, we need a second thread to handle incoming connections
406 // generated by incoming requests, otherwise the thread handling
407 // the request will be busy sending the LPC message, without any other
408 // thread being busy to receive the LPC message.
410 Status
= RtlCreateUserThread(NtCurrentProcess(),
416 (PTHREAD_START_ROUTINE
)SmpApiConnectedThread
,