b9a8ca73d651ce310ecca98d84ca6c37d48bc6c1
[reactos.git] / subsystems / win32 / csrsrv / api.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Client/Server Runtime SubSystem
4 * FILE: subsystems/win32/csrsrv/api.c
5 * PURPOSE: CSR Server DLL API LPC Implementation
6 * "\windows\ApiPort" port process management functions
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include "srv.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 static unsigned ApiDefinitionsCount = 0;
20 static PCSRSS_API_DEFINITION ApiDefinitions = NULL;
21
22 BOOLEAN (*CsrClientThreadSetup)(VOID) = NULL;
23 UNICODE_STRING CsrApiPortName;
24 volatile LONG CsrpStaticThreadCount;
25 volatile LONG CsrpDynamicThreadTotal;
26 extern ULONG CsrMaxApiRequestThreads;
27
28 /* FUNCTIONS *****************************************************************/
29
30 #if 0
31 NTSTATUS FASTCALL
32 CsrApiRegisterDefinitions(PCSRSS_API_DEFINITION NewDefinitions)
33 {
34 unsigned NewCount;
35 PCSRSS_API_DEFINITION Scan;
36 PCSRSS_API_DEFINITION New;
37
38 DPRINT("CSR: %s called\n", __FUNCTION__);
39
40 NewCount = 0;
41 for (Scan = NewDefinitions; 0 != Scan->Handler; Scan++)
42 {
43 NewCount++;
44 }
45
46 New = RtlAllocateHeap(CsrHeap, 0,
47 (ApiDefinitionsCount + NewCount)
48 * sizeof(CSRSS_API_DEFINITION));
49 if (NULL == New)
50 {
51 DPRINT1("Unable to allocate memory\n");
52 return STATUS_NO_MEMORY;
53 }
54 if (0 != ApiDefinitionsCount)
55 {
56 RtlCopyMemory(New, ApiDefinitions,
57 ApiDefinitionsCount * sizeof(CSRSS_API_DEFINITION));
58 RtlFreeHeap(CsrHeap, 0, ApiDefinitions);
59 }
60 RtlCopyMemory(New + ApiDefinitionsCount, NewDefinitions,
61 NewCount * sizeof(CSRSS_API_DEFINITION));
62 ApiDefinitions = New;
63 ApiDefinitionsCount += NewCount;
64
65 return STATUS_SUCCESS;
66 }
67 #endif
68
69 /*
70 VOID
71 FASTCALL
72 CsrApiCallHandler(PCSR_PROCESS ProcessData,
73 PCSR_API_MESSAGE Request)
74 */
75 VOID
76 FASTCALL
77 CsrApiCallHandler(
78 IN OUT PCSR_API_MESSAGE ApiMessage,
79 OUT PULONG Reply
80 )
81 {
82 unsigned DefIndex;
83 ULONG ApiId;
84
85 DPRINT("CSR: Calling handler for ApiNumber: %x.\n", ApiMessage->ApiNumber);
86 ApiId = CSR_API_NUMBER_TO_API_ID(ApiMessage->ApiNumber);
87 DPRINT("CSR: ApiID: %x ServerID: %x\n", ApiId, CSR_API_NUMBER_TO_SERVER_ID(ApiMessage->ApiNumber));
88
89 /* FIXME: Extract DefIndex instead of looping */
90 for (DefIndex = 0; DefIndex < ApiDefinitionsCount; DefIndex++)
91 {
92 if (ApiDefinitions[DefIndex].ApiID == ApiId)
93 {
94 if (ApiMessage->Header.u1.s1.DataLength < ApiDefinitions[DefIndex].MinRequestSize)
95 {
96 DPRINT1("Request ApiID %d min request size %d actual %d\n",
97 ApiId, ApiDefinitions[DefIndex].MinRequestSize,
98 ApiMessage->Header.u1.s1.DataLength);
99 ApiMessage->Status = STATUS_INVALID_PARAMETER;
100 }
101 else
102 {
103 ApiMessage->Status = (ApiDefinitions[DefIndex].Handler)(ApiMessage, Reply);
104 }
105 return;
106 }
107 }
108 DPRINT1("CSR: Unknown request ApiNumber 0x%x\n", ApiMessage->ApiNumber);
109 ApiMessage->Status = STATUS_INVALID_SYSTEM_SERVICE;
110 }
111
112 VOID
113 CallHardError(IN PCSR_THREAD ThreadData,
114 IN PHARDERROR_MSG HardErrorMessage);
115
116 #if 0
117 static
118 VOID
119 NTAPI
120 CsrHandleHardError(IN PCSR_THREAD ThreadData,
121 IN OUT PHARDERROR_MSG Message)
122 {
123 DPRINT1("CSR: received hard error %lx\n", Message->Status);
124
125 /* Call the hard error handler in win32csr */
126 CallHardError(ThreadData, Message);
127 }
128 #endif
129
130 /*++
131 * @name CsrCallServerFromServer
132 * @implemented NT4
133 *
134 * The CsrCallServerFromServer routine calls a CSR API from within a server.
135 * It avoids using LPC messages since the request isn't coming from a client.
136 *
137 * @param ReceiveMsg
138 * Pointer to the CSR API Message to send to the server.
139 *
140 * @param ReplyMsg
141 * Pointer to the CSR API Message to receive from the server.
142 *
143 * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
144 * if the ApiNumber is invalid, or STATUS_ACCESS_VIOLATION if there
145 * was a problem executing the API.
146 *
147 * @remarks None.
148 *
149 *--*/
150 NTSTATUS
151 NTAPI
152 CsrCallServerFromServer(IN PCSR_API_MESSAGE ReceiveMsg,
153 IN OUT PCSR_API_MESSAGE ReplyMsg)
154 {
155 #if 1 // Real code
156 ULONG ServerId;
157 PCSR_SERVER_DLL ServerDll;
158 ULONG ApiId;
159 ULONG Reply;
160 NTSTATUS Status;
161
162 /* Get the Server ID */
163 ServerId = CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg->ApiNumber);
164
165 /* Make sure that the ID is within limits, and the Server DLL loaded */
166 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
167 (!(ServerDll = CsrLoadedServerDll[ServerId])))
168 {
169 /* We are beyond the Maximum Server ID */
170 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId, ServerDll);
171 ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
172 return STATUS_ILLEGAL_FUNCTION;
173 }
174 else
175 {
176 /* Get the API ID */
177 ApiId = CSR_API_NUMBER_TO_API_ID(ReceiveMsg->ApiNumber);
178
179 /* Normalize it with our Base ID */
180 ApiId -= ServerDll->ApiBase;
181
182 /* Make sure that the ID is within limits, and the entry exists */
183 if ((ApiId >= ServerDll->HighestApiSupported) ||
184 ((ServerDll->ValidTable) && !(ServerDll->ValidTable[ApiId])))
185 {
186 /* We are beyond the Maximum API ID, or it doesn't exist */
187 DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
188 "invalid API to call from the server.\n",
189 ServerDll->ValidTable[ApiId],
190 ((ServerDll->NameTable) && (ServerDll->NameTable[ApiId])) ?
191 ServerDll->NameTable[ApiId] : "*** UNKNOWN ***", &ServerDll->Name);
192 DbgBreakPoint();
193 ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
194 return STATUS_ILLEGAL_FUNCTION;
195 }
196 }
197
198 if (CsrDebug & 2)
199 {
200 DPRINT1("CSRSS: %s Api Request received from server process\n",
201 ServerDll->NameTable[ApiId]);
202 }
203
204 /* Validation complete, start SEH */
205 _SEH2_TRY
206 {
207 /* Call the API and get the result */
208 /// CsrApiCallHandler(ReplyMsg, /*ProcessData*/ &ReplyCode); ///
209 Status = (ServerDll->DispatchTable[ApiId])(ReceiveMsg, &Reply);
210
211 /* Return the result, no matter what it is */
212 ReplyMsg->Status = Status;
213 }
214 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
215 {
216 /* If we got an exception, return access violation */
217 ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
218 }
219 _SEH2_END;
220
221 /* Return success */
222 return STATUS_SUCCESS;
223
224 #else // Hacky reactos code
225
226 PCSR_PROCESS ProcessData;
227 ULONG ReplyCode;
228
229 /* Get the Process Data */
230 CsrLockProcessByClientId(&ReceiveMsg->Header.ClientId.UniqueProcess, &ProcessData);
231 if (!ProcessData)
232 {
233 DPRINT1("Message: Unable to find data for process 0x%x\n",
234 ReceiveMsg->Header.ClientId.UniqueProcess);
235 return STATUS_NOT_SUPPORTED;
236 }
237
238 /* Validation complete, start SEH */
239 _SEH2_TRY
240 {
241 /* Call the API and get the result */
242 CsrApiCallHandler(ReplyMsg, /*ProcessData*/ &ReplyCode);
243 }
244 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
245 {
246 /* If we got an exception, return access violation */
247 ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
248 }
249 _SEH2_END;
250
251 /* Release the process reference */
252 CsrUnlockProcess(ProcessData);
253
254 /* Return success */
255 return STATUS_SUCCESS;
256 #endif
257 }
258
259 /*++
260 * @name CsrApiHandleConnectionRequest
261 *
262 * The CsrApiHandleConnectionRequest routine handles and accepts a new
263 * connection request to the CSR API LPC Port.
264 *
265 * @param ApiMessage
266 * Pointer to the incoming CSR API Message which contains the
267 * connection request.
268 *
269 * @return STATUS_SUCCESS in case of success, or status code which caused
270 * the routine to error.
271 *
272 * @remarks This routine is responsible for attaching the Shared Section to
273 * new clients connecting to CSR.
274 *
275 *--*/
276 NTSTATUS
277 NTAPI
278 CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage)
279 {
280 PCSR_THREAD CsrThread = NULL;
281 PCSR_PROCESS CsrProcess = NULL;
282 NTSTATUS Status = STATUS_SUCCESS;
283 PCSR_CONNECTION_INFO ConnectInfo = &ApiMessage->ConnectionInfo;
284 BOOLEAN AllowConnection = FALSE;
285 REMOTE_PORT_VIEW RemotePortView;
286 HANDLE hPort;
287
288 /* Acquire the Process Lock */
289 CsrAcquireProcessLock();
290
291 /* Lookup the CSR Thread */
292 CsrThread = CsrLocateThreadByClientId(NULL, &ApiMessage->Header.ClientId);
293
294 /* Check if we have a thread */
295 if (CsrThread)
296 {
297 /* Get the Process */
298 CsrProcess = CsrThread->Process;
299
300 /* Make sure we have a Process as well */
301 if (CsrProcess)
302 {
303 /* Reference the Process */
304 CsrLockedReferenceProcess(CsrThread->Process);
305
306 /* Release the lock */
307 CsrReleaseProcessLock();
308
309 /* Duplicate the Object Directory */
310 Status = NtDuplicateObject(NtCurrentProcess(),
311 CsrObjectDirectory,
312 CsrProcess->ProcessHandle,
313 &ConnectInfo->ObjectDirectory,
314 0,
315 0,
316 DUPLICATE_SAME_ACCESS |
317 DUPLICATE_SAME_ATTRIBUTES);
318
319 /* Acquire the lock */
320 CsrAcquireProcessLock();
321
322 /* Check for success */
323 if (NT_SUCCESS(Status))
324 {
325 /* Attach the Shared Section */
326 Status = CsrSrvAttachSharedSection(CsrProcess, ConnectInfo);
327
328 /* Check how this went */
329 if (NT_SUCCESS(Status)) AllowConnection = TRUE;
330 }
331
332 /* Dereference the project */
333 CsrLockedDereferenceProcess(CsrProcess);
334 }
335 }
336
337 /* Release the lock */
338 CsrReleaseProcessLock();
339
340 /* Setup the Port View Structure */
341 RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
342 RemotePortView.ViewSize = 0;
343 RemotePortView.ViewBase = NULL;
344
345 /* Save the Process ID */
346 ConnectInfo->ProcessId = NtCurrentTeb()->ClientId.UniqueProcess;
347
348 /* Accept the Connection */
349 Status = NtAcceptConnectPort(&hPort,
350 AllowConnection ? UlongToPtr(CsrProcess->SequenceNumber) : 0,
351 &ApiMessage->Header,
352 AllowConnection,
353 NULL,
354 &RemotePortView);
355 if (!NT_SUCCESS(Status))
356 {
357 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status);
358 }
359 else if (AllowConnection)
360 {
361 if (CsrDebug & 2)
362 {
363 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
364 ApiMessage->Header.ClientId.UniqueProcess,
365 ApiMessage->Header.ClientId.UniqueThread,
366 RemotePortView.ViewBase,
367 RemotePortView.ViewSize);
368 }
369
370 /* Set some Port Data in the Process */
371 CsrProcess->ClientPort = hPort;
372 CsrProcess->ClientViewBase = (ULONG_PTR)RemotePortView.ViewBase;
373 CsrProcess->ClientViewBounds = (ULONG_PTR)((ULONG_PTR)RemotePortView.ViewBase +
374 (ULONG_PTR)RemotePortView.ViewSize);
375
376 /* Complete the connection */
377 Status = NtCompleteConnectPort(hPort);
378 if (!NT_SUCCESS(Status))
379 {
380 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status);
381 }
382 }
383 else
384 {
385 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
386 ApiMessage->Header.ClientId.UniqueProcess,
387 ApiMessage->Header.ClientId.UniqueThread);
388 }
389
390 /* Return status to caller */
391 return Status;
392 }
393
394 /*++
395 * @name CsrpCheckRequestThreads
396 *
397 * The CsrpCheckRequestThreads routine checks if there are no more threads
398 * to handle CSR API Requests, and creates a new thread if possible, to
399 * avoid starvation.
400 *
401 * @param None.
402 *
403 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
404 * if a new thread couldn't be created.
405 *
406 * @remarks None.
407 *
408 *--*/
409 NTSTATUS
410 NTAPI
411 CsrpCheckRequestThreads(VOID)
412 {
413 HANDLE hThread;
414 CLIENT_ID ClientId;
415 NTSTATUS Status;
416
417 /* Decrease the count, and see if we're out */
418 if (!(_InterlockedDecrement(&CsrpStaticThreadCount)))
419 {
420 /* Check if we've still got space for a Dynamic Thread */
421 if (CsrpDynamicThreadTotal < CsrMaxApiRequestThreads)
422 {
423 /* Create a new dynamic thread */
424 Status = RtlCreateUserThread(NtCurrentProcess(),
425 NULL,
426 TRUE,
427 0,
428 0,
429 0,
430 (PVOID)CsrApiRequestThread,
431 NULL,
432 &hThread,
433 &ClientId);
434 /* Check success */
435 if (NT_SUCCESS(Status))
436 {
437 /* Increase the thread counts */
438 _InterlockedIncrement(&CsrpStaticThreadCount);
439 _InterlockedIncrement(&CsrpDynamicThreadTotal);
440
441 /* Add a new server thread */
442 if (CsrAddStaticServerThread(hThread,
443 &ClientId,
444 CsrThreadIsServerThread))
445 {
446 /* Activate it */
447 NtResumeThread(hThread, NULL);
448 }
449 else
450 {
451 /* Failed to create a new static thread */
452 _InterlockedDecrement(&CsrpStaticThreadCount);
453 _InterlockedDecrement(&CsrpDynamicThreadTotal);
454
455 /* Terminate it */
456 DPRINT1("Failing\n");
457 NtTerminateThread(hThread, 0);
458 NtClose(hThread);
459
460 /* Return */
461 return STATUS_UNSUCCESSFUL;
462 }
463 }
464 }
465 }
466
467 /* Success */
468 return STATUS_SUCCESS;
469 }
470
471 /*++
472 * @name CsrApiRequestThread
473 *
474 * The CsrApiRequestThread routine handles incoming messages or connection
475 * requests on the CSR API LPC Port.
476 *
477 * @param Parameter
478 * System-default user-defined parameter. Unused.
479 *
480 * @return The thread exit code, if the thread is terminated.
481 *
482 * @remarks Before listening on the port, the routine will first attempt
483 * to connect to the user subsystem.
484 *
485 *--*/
486 NTSTATUS
487 NTAPI
488 CsrApiRequestThread(IN PVOID Parameter)
489 #if 1
490 {
491 PTEB Teb = NtCurrentTeb();
492 LARGE_INTEGER TimeOut;
493 PCSR_THREAD CurrentThread, CsrThread;
494 NTSTATUS Status;
495 PCSR_API_MESSAGE ReplyMsg;
496 CSR_API_MESSAGE ReceiveMsg;
497 PCSR_PROCESS CsrProcess;
498 PHARDERROR_MSG HardErrorMsg;
499 PVOID PortContext;
500 PCSR_SERVER_DLL ServerDll;
501 PCLIENT_DIED_MSG ClientDiedMsg;
502 PDBGKM_MSG DebugMessage;
503 ULONG ServerId, ApiId, Reply, MessageType, i;
504 HANDLE ReplyPort;
505
506 /* Setup LPC loop port and message */
507 ReplyMsg = NULL;
508 ReplyPort = CsrApiPort;
509
510 /* Connect to user32 */
511 while (!CsrConnectToUser())
512 {
513 /* Set up the timeout for the connect (30 seconds) */
514 TimeOut.QuadPart = -30 * 1000 * 1000 * 10;
515
516 /* Keep trying until we get a response */
517 Teb->Win32ClientInfo[0] = 0;
518 NtDelayExecution(FALSE, &TimeOut);
519 }
520
521 /* Get our thread */
522 CurrentThread = Teb->CsrClientThread;
523
524 /* If we got an event... */
525 if (Parameter)
526 {
527 /* Set it, to let stuff waiting on us load */
528 Status = NtSetEvent((HANDLE)Parameter, NULL);
529 ASSERT(NT_SUCCESS(Status));
530
531 /* Increase the Thread Counts */
532 _InterlockedIncrement(&CsrpStaticThreadCount);
533 _InterlockedIncrement(&CsrpDynamicThreadTotal);
534 }
535
536 /* Now start the loop */
537 while (TRUE)
538 {
539 /* Make sure the real CID is set */
540 Teb->RealClientId = Teb->ClientId;
541
542 /* Debug check */
543 if (Teb->CountOfOwnedCriticalSections)
544 {
545 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
546 Teb->CountOfOwnedCriticalSections);
547 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
548 &ReceiveMsg, ReplyMsg);
549 DbgBreakPoint();
550 }
551
552 /* Wait for a message to come through */
553 Status = NtReplyWaitReceivePort(ReplyPort,
554 &PortContext,
555 &ReplyMsg->Header,
556 &ReceiveMsg.Header);
557
558 /* Check if we didn't get success */
559 if (Status != STATUS_SUCCESS)
560 {
561 /* Was it a failure or another success code? */
562 if (!NT_SUCCESS(Status))
563 {
564 /* Check for specific status cases */
565 if ((Status != STATUS_INVALID_CID) &&
566 (Status != STATUS_UNSUCCESSFUL) &&
567 ((Status == STATUS_INVALID_HANDLE) || (ReplyPort == CsrApiPort)))
568 {
569 /* Notify the debugger */
570 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
571 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort, CsrApiPort);
572 }
573
574 /* We failed big time, so start out fresh */
575 ReplyMsg = NULL;
576 ReplyPort = CsrApiPort;
577 continue;
578 }
579 else
580 {
581 /* A bizare "success" code, just try again */
582 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status);
583 continue;
584 }
585 }
586
587 /* Use whatever Client ID we got */
588 Teb->RealClientId = ReceiveMsg.Header.ClientId;
589
590 /* Get the Message Type */
591 MessageType = ReceiveMsg.Header.u2.s2.Type;
592
593 /* Handle connection requests */
594 if (MessageType == LPC_CONNECTION_REQUEST)
595 {
596 /* Handle the Connection Request */
597 CsrApiHandleConnectionRequest(&ReceiveMsg);
598 ReplyPort = CsrApiPort;
599 ReplyMsg = NULL;
600 continue;
601 }
602
603 /* It's some other kind of request. Get the lock for the lookup */
604 CsrAcquireProcessLock();
605
606 /* Now do the lookup to get the CSR_THREAD */
607 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
608 &ReceiveMsg.Header.ClientId);
609
610 /* Did we find a thread? */
611 if (!CsrThread)
612 {
613 /* This wasn't a CSR Thread, release lock */
614 CsrReleaseProcessLock();
615
616 /* If this was an exception, handle it */
617 if (MessageType == LPC_EXCEPTION)
618 {
619 ReplyMsg = &ReceiveMsg;
620 ReplyPort = CsrApiPort;
621 ReplyMsg->Status = DBG_CONTINUE;
622 }
623 else if (MessageType == LPC_PORT_CLOSED ||
624 MessageType == LPC_CLIENT_DIED)
625 {
626 /* The Client or Port are gone, loop again */
627 ReplyMsg = NULL;
628 ReplyPort = CsrApiPort;
629 }
630 else if (MessageType == LPC_ERROR_EVENT)
631 {
632 /* If it's a hard error, handle this too */
633 HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
634
635 /* Default it to unhandled */
636 HardErrorMsg->Response = ResponseNotHandled;
637
638 /* Check if there are free api threads */
639 CsrpCheckRequestThreads();
640 if (CsrpStaticThreadCount)
641 {
642 /* Loop every Server DLL */
643 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
644 {
645 /* Get the Server DLL */
646 ServerDll = CsrLoadedServerDll[i];
647
648 /* Check if it's valid and if it has a Hard Error Callback */
649 if ((ServerDll) && (ServerDll->HardErrorCallback))
650 {
651 /* Call it */
652 ServerDll->HardErrorCallback(NULL, HardErrorMsg);
653
654 /* If it's handled, get out of here */
655 if (HardErrorMsg->Response != ResponseNotHandled) break;
656 }
657 }
658 }
659
660 /* Increase the thread count */
661 _InterlockedIncrement(&CsrpStaticThreadCount);
662
663 /* If the response was 0xFFFFFFFF, we'll ignore it */
664 if (HardErrorMsg->Response == 0xFFFFFFFF)
665 {
666 ReplyMsg = NULL;
667 ReplyPort = CsrApiPort;
668 }
669 else
670 {
671 ReplyMsg = &ReceiveMsg;
672 }
673 }
674 else if (MessageType == LPC_REQUEST)
675 {
676 /* This is an API Message coming from a non-CSR Thread */
677 ReplyMsg = &ReceiveMsg;
678 ReplyPort = CsrApiPort;
679 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
680 }
681 else if (MessageType == LPC_DATAGRAM)
682 {
683 /* This is an API call, get the Server ID */
684 ServerId = CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg.ApiNumber);
685
686 /* Make sure that the ID is within limits, and the Server DLL loaded */
687 ServerDll = NULL;
688 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
689 (!(ServerDll = CsrLoadedServerDll[ServerId])))
690 {
691 /* We are beyond the Maximum Server ID */
692 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
693 ServerId, ServerDll);
694 DbgBreakPoint();
695 ReplyPort = CsrApiPort;
696 ReplyMsg = NULL;
697 continue;
698 }
699
700 /* Get the API ID */
701 ApiId = CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber);
702
703 /* Normalize it with our Base ID */
704 ApiId -= ServerDll->ApiBase;
705
706 /* Make sure that the ID is within limits, and the entry exists */
707 if (ApiId >= ServerDll->HighestApiSupported)
708 {
709 /* We are beyond the Maximum API ID, or it doesn't exist */
710 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
711 CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber),
712 &ServerDll->Name);
713 ReplyPort = CsrApiPort;
714 ReplyMsg = NULL;
715 continue;
716 }
717
718 if (CsrDebug & 2)
719 {
720 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
721 Teb->ClientId.UniqueThread,
722 ReceiveMsg.Header.ClientId.UniqueProcess,
723 ReceiveMsg.Header.ClientId.UniqueThread,
724 ServerDll->NameTable[ApiId],
725 NULL);
726 }
727
728 /* Assume success */
729 ReceiveMsg.Status = STATUS_SUCCESS;
730
731 /* Validation complete, start SEH */
732 _SEH2_TRY
733 {
734 /* Make sure we have enough threads */
735 CsrpCheckRequestThreads();
736
737 /* Call the API and get the result */
738 ReplyMsg = NULL;
739 ReplyPort = CsrApiPort;
740 ServerDll->DispatchTable[ApiId](&ReceiveMsg, &Reply);
741
742 /* Increase the static thread count */
743 _InterlockedIncrement(&CsrpStaticThreadCount);
744 }
745 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
746 {
747 ReplyMsg = NULL;
748 ReplyPort = CsrApiPort;
749 }
750 _SEH2_END;
751 }
752 else
753 {
754 /* Some other ignored message type */
755 ReplyMsg = NULL;
756 ReplyPort = CsrApiPort;
757 }
758
759 /* Keep going */
760 continue;
761 }
762
763 /* We have a valid thread, was this an LPC Request? */
764 if (MessageType != LPC_REQUEST)
765 {
766 /* It's not an API, check if the client died */
767 if (MessageType == LPC_CLIENT_DIED)
768 {
769 /* Get the information and check if it matches our thread */
770 ClientDiedMsg = (PCLIENT_DIED_MSG)&ReceiveMsg;
771 if (ClientDiedMsg->CreateTime.QuadPart == CsrThread->CreateTime.QuadPart)
772 {
773 /* Reference the thread */
774 CsrLockedReferenceThread(CsrThread);
775
776 /* Destroy the thread in the API Message */
777 CsrDestroyThread(&ReceiveMsg.Header.ClientId);
778
779 /* Check if the thread was actually ourselves */
780 if (CsrProcess->ThreadCount == 1)
781 {
782 /* Kill the process manually here */
783 CsrDestroyProcess(&CsrThread->ClientId, 0);
784 }
785
786 /* Remove our extra reference */
787 CsrLockedDereferenceThread(CsrThread);
788 }
789
790 /* Release the lock and keep looping */
791 CsrReleaseProcessLock();
792 ReplyMsg = NULL;
793 ReplyPort = CsrApiPort;
794 continue;
795 }
796
797 /* Reference the thread and release the lock */
798 CsrLockedReferenceThread(CsrThread);
799 CsrReleaseProcessLock();
800
801 /* Check if this was an exception */
802 if (MessageType == LPC_EXCEPTION)
803 {
804 /* Kill the process */
805 NtTerminateProcess(CsrProcess->ProcessHandle, STATUS_ABANDONED);
806
807 /* Destroy it from CSR */
808 CsrDestroyProcess(&ReceiveMsg.Header.ClientId, STATUS_ABANDONED);
809
810 /* Return a Debug Message */
811 DebugMessage = (PDBGKM_MSG)&ReceiveMsg;
812 DebugMessage->ReturnedStatus = DBG_CONTINUE;
813 ReplyMsg = &ReceiveMsg;
814 ReplyPort = CsrApiPort;
815
816 /* Remove our extra reference */
817 CsrDereferenceThread(CsrThread);
818 }
819 else if (MessageType == LPC_ERROR_EVENT)
820 {
821 /* If it's a hard error, handle this too */
822 HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
823
824 /* Default it to unhandled */
825 HardErrorMsg->Response = ResponseNotHandled;
826
827 /* Check if there are free api threads */
828 CsrpCheckRequestThreads();
829 if (CsrpStaticThreadCount)
830 {
831 /* Loop every Server DLL */
832 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
833 {
834 /* Get the Server DLL */
835 ServerDll = CsrLoadedServerDll[i];
836
837 /* Check if it's valid and if it has a Hard Error Callback */
838 if ((ServerDll) && (ServerDll->HardErrorCallback))
839 {
840 /* Call it */
841 ServerDll->HardErrorCallback(CsrThread, HardErrorMsg);
842
843 /* If it's handled, get out of here */
844 if (HardErrorMsg->Response != ResponseNotHandled) break;
845 }
846 }
847 }
848
849 /* Increase the thread count */
850 _InterlockedIncrement(&CsrpStaticThreadCount);
851
852 /* If the response was 0xFFFFFFFF, we'll ignore it */
853 if (HardErrorMsg->Response == 0xFFFFFFFF)
854 {
855 ReplyMsg = NULL;
856 ReplyPort = CsrApiPort;
857 }
858 else
859 {
860 CsrDereferenceThread(CsrThread);
861 ReplyMsg = &ReceiveMsg;
862 ReplyPort = CsrApiPort;
863 }
864 }
865 else
866 {
867 /* Something else */
868 CsrDereferenceThread(CsrThread);
869 ReplyMsg = NULL;
870 }
871
872 /* Keep looping */
873 continue;
874 }
875
876 /* We got an API Request */
877 CsrLockedReferenceThread(CsrThread);
878 CsrReleaseProcessLock();
879
880 /* This is an API call, get the Server ID */
881 ServerId = CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg.ApiNumber);
882
883 /* Make sure that the ID is within limits, and the Server DLL loaded */
884 ServerDll = NULL;
885 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
886 (!(ServerDll = CsrLoadedServerDll[ServerId])))
887 {
888 /* We are beyond the Maximum Server ID */
889 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
890 ServerId, ServerDll);
891 DbgBreakPoint();
892
893 ReplyPort = CsrApiPort;
894 ReplyMsg = &ReceiveMsg;
895 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
896 CsrDereferenceThread(CsrThread);
897 continue;
898 }
899
900 /* Get the API ID */
901 ApiId = CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber);
902
903 /* Normalize it with our Base ID */
904 ApiId -= ServerDll->ApiBase;
905
906 /* Make sure that the ID is within limits, and the entry exists */
907 if (ApiId >= ServerDll->HighestApiSupported)
908 {
909 /* We are beyond the Maximum API ID, or it doesn't exist */
910 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
911 CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber),
912 &ServerDll->Name);
913
914 ReplyPort = CsrApiPort;
915 ReplyMsg = &ReceiveMsg;
916 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
917 CsrDereferenceThread(CsrThread);
918 continue;
919 }
920
921 if (CsrDebug & 2)
922 {
923 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
924 Teb->ClientId.UniqueThread,
925 ReceiveMsg.Header.ClientId.UniqueProcess,
926 ReceiveMsg.Header.ClientId.UniqueThread,
927 ServerDll->NameTable[ApiId],
928 CsrThread);
929 }
930
931 /* Assume success */
932 ReplyMsg = &ReceiveMsg;
933 ReceiveMsg.Status = STATUS_SUCCESS;
934
935 /* Now we reply to a particular client */
936 ReplyPort = CsrThread->Process->ClientPort;
937
938 /* Check if there's a capture buffer */
939 if (ReceiveMsg.CsrCaptureData)
940 {
941 /* Capture the arguments */
942 if (!CsrCaptureArguments(CsrThread, &ReceiveMsg))
943 {
944 /* Ignore this message if we failed to get the arguments */
945 CsrDereferenceThread(CsrThread);
946 continue;
947 }
948 }
949
950 /* Validation complete, start SEH */
951 _SEH2_TRY
952 {
953 /* Make sure we have enough threads */
954 CsrpCheckRequestThreads();
955
956 Teb->CsrClientThread = CsrThread;
957
958 /* Call the API and get the result */
959 Reply = 0;
960 ServerDll->DispatchTable[ApiId](&ReceiveMsg, &Reply);
961
962 /* Increase the static thread count */
963 _InterlockedIncrement(&CsrpStaticThreadCount);
964
965 Teb->CsrClientThread = CurrentThread;
966
967 if (Reply == 3)
968 {
969 ReplyMsg = NULL;
970 if (ReceiveMsg.CsrCaptureData)
971 {
972 CsrReleaseCapturedArguments(&ReceiveMsg);
973 }
974 CsrDereferenceThread(CsrThread);
975 ReplyPort = CsrApiPort;
976 }
977 else if (Reply == 2)
978 {
979 NtReplyPort(ReplyPort, &ReplyMsg->Header);
980 ReplyPort = CsrApiPort;
981 ReplyMsg = NULL;
982 CsrDereferenceThread(CsrThread);
983 }
984 else if (Reply == 1)
985 {
986 ReplyPort = CsrApiPort;
987 ReplyMsg = NULL;
988 }
989 else
990 {
991 if (ReceiveMsg.CsrCaptureData)
992 {
993 CsrReleaseCapturedArguments(&ReceiveMsg);
994 }
995 CsrDereferenceThread(CsrThread);
996 }
997 }
998 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
999 {
1000 ReplyMsg = NULL;
1001 ReplyPort = CsrApiPort;
1002 }
1003 _SEH2_END;
1004 }
1005
1006 /* We're out of the loop for some reason, terminate! */
1007 NtTerminateThread(NtCurrentThread(), Status);
1008 return Status;
1009 }
1010 #else
1011 {
1012 PTEB Teb = NtCurrentTeb();
1013 LARGE_INTEGER TimeOut;
1014 NTSTATUS Status;
1015 BYTE RawRequest[LPC_MAX_DATA_LENGTH];
1016 PCSR_API_MESSAGE Request = (PCSR_API_MESSAGE)RawRequest;
1017 PCSR_API_MESSAGE Reply;
1018 PCSR_PROCESS CsrProcess;
1019 PCSR_THREAD ServerThread, CsrThread;
1020 ULONG MessageType;
1021 HANDLE ReplyPort;
1022 PDBGKM_MSG DebugMessage;
1023 PHARDERROR_MSG HardErrorMsg;
1024 PCLIENT_DIED_MSG ClientDiedMsg;
1025 DPRINT("CSR: %s called\n", __FUNCTION__);
1026
1027 /* Setup LPC loop port and message */
1028 Reply = NULL;
1029 ReplyPort = CsrApiPort;
1030
1031 /* Connect to user32 */
1032 while (!CsrConnectToUser())
1033 {
1034 /* Set up the timeout for the connect (30 seconds) */
1035 TimeOut.QuadPart = -30 * 1000 * 1000 * 10;
1036
1037 /* Keep trying until we get a response */
1038 Teb->Win32ClientInfo[0] = 0;
1039 NtDelayExecution(FALSE, &TimeOut);
1040 }
1041
1042 /* Get our thread */
1043 ServerThread = Teb->CsrClientThread;
1044
1045 /* If we got an event... */
1046 if (Parameter)
1047 {
1048 /* Set it, to let stuff waiting on us load */
1049 Status = NtSetEvent((HANDLE)Parameter, NULL);
1050 ASSERT(NT_SUCCESS(Status));
1051
1052 /* Increase the Thread Counts */
1053 _InterlockedIncrement(&CsrpStaticThreadCount);
1054 _InterlockedIncrement(&CsrpDynamicThreadTotal);
1055 }
1056
1057 /* Now start the loop */
1058 while (TRUE)
1059 {
1060 /* Make sure the real CID is set */
1061 Teb->RealClientId = Teb->ClientId;
1062
1063 /* Debug check */
1064 if (Teb->CountOfOwnedCriticalSections)
1065 {
1066 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
1067 Teb->CountOfOwnedCriticalSections);
1068 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
1069 Request, Reply);
1070 DbgBreakPoint();
1071 }
1072
1073 /* Send the reply and wait for a new request */
1074 DPRINT("Replying to: %lx (%lx)\n", ReplyPort, CsrApiPort);
1075 Status = NtReplyWaitReceivePort(ReplyPort,
1076 0,
1077 &Reply->Header,
1078 &Request->Header);
1079 /* Check if we didn't get success */
1080 if (Status != STATUS_SUCCESS)
1081 {
1082 /* Was it a failure or another success code? */
1083 if (!NT_SUCCESS(Status))
1084 {
1085 /* Check for specific status cases */
1086 if ((Status != STATUS_INVALID_CID) &&
1087 (Status != STATUS_UNSUCCESSFUL) &&
1088 ((Status == STATUS_INVALID_HANDLE) || (ReplyPort == CsrApiPort)))
1089 {
1090 /* Notify the debugger */
1091 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
1092 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort, CsrApiPort);
1093 }
1094
1095 /* We failed big time, so start out fresh */
1096 Reply = NULL;
1097 ReplyPort = CsrApiPort;
1098 DPRINT1("failed: %lx\n", Status);
1099 continue;
1100 }
1101 else
1102 {
1103 /* A bizare "success" code, just try again */
1104 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status);
1105 continue;
1106 }
1107 }
1108
1109 /* Use whatever Client ID we got */
1110 Teb->RealClientId = Request->Header.ClientId;
1111
1112 /* Get the Message Type */
1113 MessageType = Request->Header.u2.s2.Type;
1114
1115 /* Handle connection requests */
1116 if (MessageType == LPC_CONNECTION_REQUEST)
1117 {
1118 /* Handle the Connection Request */
1119 DPRINT("Accepting new connection\n");
1120 CsrpHandleConnectionRequest((PPORT_MESSAGE)Request);
1121 Reply = NULL;
1122 ReplyPort = CsrApiPort;
1123 continue;
1124 }
1125
1126 /* It's some other kind of request. Get the lock for the lookup */
1127 CsrAcquireProcessLock();
1128
1129 /* Now do the lookup to get the CSR_THREAD */
1130 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
1131 &Request->Header.ClientId);
1132
1133 /* Did we find a thread? */
1134 if (!CsrThread)
1135 {
1136 /* This wasn't a CSR Thread, release lock */
1137 CsrReleaseProcessLock();
1138
1139 /* If this was an exception, handle it */
1140 if (MessageType == LPC_EXCEPTION)
1141 {
1142 DPRINT1("Exception from unknown thread, just continue\n");
1143 Reply = Request;
1144 ReplyPort = CsrApiPort;
1145 Reply->Status = DBG_CONTINUE;
1146 }
1147 else if (MessageType == LPC_PORT_CLOSED ||
1148 MessageType == LPC_CLIENT_DIED)
1149 {
1150 /* The Client or Port are gone, loop again */
1151 DPRINT("Death from unknown thread, just continue\n");
1152 Reply = NULL;
1153 ReplyPort = CsrApiPort;
1154 }
1155 else if (MessageType == LPC_ERROR_EVENT)
1156 {
1157 /* If it's a hard error, handle this too */
1158 DPRINT1("Hard error from unknown thread, call handlers\n");
1159 HandleHardError:
1160 HardErrorMsg = (PHARDERROR_MSG)Request;
1161
1162 /* Default it to unhandled */
1163 HardErrorMsg->Response = ResponseNotHandled;
1164
1165 /* Check if there are free api threads */
1166 CsrpCheckRequestThreads();
1167 if (CsrpStaticThreadCount)
1168 {
1169 CsrHandleHardError(CsrThread, (PHARDERROR_MSG)Request);
1170 }
1171
1172 /* If the response was 0xFFFFFFFF, we'll ignore it */
1173 if (HardErrorMsg->Response == 0xFFFFFFFF)
1174 {
1175 Reply = NULL;
1176 ReplyPort = CsrApiPort;
1177 }
1178 else
1179 {
1180 if (CsrThread) CsrDereferenceThread(CsrThread);
1181 Reply = Request;
1182 ReplyPort = CsrApiPort;
1183 }
1184 }
1185 else if (MessageType == LPC_REQUEST)
1186 {
1187 /* This is an API Message coming from a non-CSR Thread */
1188 DPRINT1("No thread found for request %lx and clientID %lx.%lx\n",
1189 Request->ApiNumber & 0xFFFF,
1190 Request->Header.ClientId.UniqueProcess,
1191 Request->Header.ClientId.UniqueThread);
1192 Reply = Request;
1193 ReplyPort = CsrApiPort;
1194 Reply->Status = STATUS_ILLEGAL_FUNCTION;
1195 }
1196 else if (MessageType == LPC_DATAGRAM)
1197 {
1198 DPRINT1("Kernel datagram: not yet supported\n");
1199 Reply = NULL;
1200 ReplyPort = CsrApiPort;
1201 }
1202 else
1203 {
1204 /* Some other ignored message type */
1205 Reply = NULL;
1206 ReplyPort = CsrApiPort;
1207 }
1208
1209 /* Keep going */
1210 continue;
1211 }
1212
1213 /* We have a valid thread, was this an LPC Request? */
1214 if (MessageType != LPC_REQUEST)
1215 {
1216 /* It's not an API, check if the client died */
1217 if (MessageType == LPC_CLIENT_DIED)
1218 {
1219 /* Get the information and check if it matches our thread */
1220 ClientDiedMsg = (PCLIENT_DIED_MSG)Request;
1221 if (ClientDiedMsg->CreateTime.QuadPart == CsrThread->CreateTime.QuadPart)
1222 {
1223 /* Reference the thread */
1224 CsrLockedReferenceThread(CsrThread);
1225
1226 /* Destroy the thread in the API Message */
1227 CsrDestroyThread(&Request->Header.ClientId);
1228
1229 /* Check if the thread was actually ourselves */
1230 if (CsrProcess->ThreadCount == 1)
1231 {
1232 /* Kill the process manually here */
1233 DPRINT1("Last thread\n");
1234 CsrDestroyProcess(&CsrThread->ClientId, 0);
1235 }
1236
1237 /* Remove our extra reference */
1238 CsrLockedDereferenceThread(CsrThread);
1239 }
1240
1241 /* Release the lock and keep looping */
1242 CsrReleaseProcessLock();
1243 Reply = NULL;
1244 ReplyPort = CsrApiPort;
1245 continue;
1246 }
1247
1248 /* Reference the thread and release the lock */
1249 CsrLockedReferenceThread(CsrThread);
1250 CsrReleaseProcessLock();
1251
1252 /* If this was an exception, handle it */
1253 if (MessageType == LPC_EXCEPTION)
1254 {
1255 /* Kill the process */
1256 DPRINT1("Exception in %lx.%lx. Killing...\n",
1257 Request->Header.ClientId.UniqueProcess,
1258 Request->Header.ClientId.UniqueThread);
1259 NtTerminateProcess(CsrProcess->ProcessHandle, STATUS_ABANDONED);
1260
1261 /* Destroy it from CSR */
1262 CsrDestroyProcess(&Request->Header.ClientId, STATUS_ABANDONED);
1263
1264 /* Return a Debug Message */
1265 DebugMessage = (PDBGKM_MSG)Request;
1266 DebugMessage->ReturnedStatus = DBG_CONTINUE;
1267 Reply = Request;
1268 ReplyPort = CsrApiPort;
1269
1270 /* Remove our extra reference */
1271 CsrDereferenceThread(CsrThread);
1272 }
1273 else if (MessageType == LPC_ERROR_EVENT)
1274 {
1275 DPRINT1("Hard error from known CSR thread... handling\n");
1276 goto HandleHardError;
1277 }
1278 else
1279 {
1280 /* Something else */
1281 DPRINT1("Unhandled message type: %lx\n", MessageType);
1282 CsrDereferenceThread(CsrThread);
1283 Reply = NULL;
1284 }
1285
1286 /* Keep looping */
1287 continue;
1288 }
1289
1290 /* We got an API Request */
1291 CsrLockedReferenceThread(CsrThread);
1292 CsrReleaseProcessLock();
1293
1294 /* Assume success */
1295 Reply = Request;
1296 Request->Status = STATUS_SUCCESS;
1297
1298 /* Now we reply to a particular client */
1299 ReplyPort = CsrThread->Process->ClientPort;
1300
1301 DPRINT("CSR: Got CSR API: %x [Message Origin: %x]\n",
1302 Request->ApiNumber,
1303 Request->Header.ClientId.UniqueThread);
1304
1305 /* Validation complete, start SEH */
1306 _SEH2_TRY
1307 {
1308 ULONG ReplyCode;
1309
1310 /* Make sure we have enough threads */
1311 CsrpCheckRequestThreads();
1312
1313 /* Set the client thread pointer */
1314 NtCurrentTeb()->CsrClientThread = CsrThread;
1315
1316 /* Call the Handler */
1317 CsrApiCallHandler(Request, &ReplyCode);
1318
1319 /* Increase the static thread count */
1320 _InterlockedIncrement(&CsrpStaticThreadCount);
1321
1322 /* Restore the server thread */
1323 NtCurrentTeb()->CsrClientThread = ServerThread;
1324
1325 /* Check if this is a dead client now */
1326 if (Request->ApiNumber == 0xBABE)
1327 {
1328 /* Reply to the death message */
1329 NtReplyPort(ReplyPort, &Reply->Header);
1330
1331 /* Reply back to the API port now */
1332 ReplyPort = CsrApiPort;
1333 Reply = NULL;
1334
1335 /* Drop the reference */
1336 CsrDereferenceThread(CsrThread);
1337 }
1338 else
1339 {
1340 /* Drop the reference */
1341 CsrDereferenceThread(CsrThread);
1342 }
1343 }
1344 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
1345 {
1346 Reply = NULL;
1347 ReplyPort = CsrApiPort;
1348 }
1349 _SEH2_END;
1350 }
1351
1352 /* Close the port and exit the thread */
1353 // NtClose(ServerPort);
1354
1355 DPRINT1("CSR: %s done\n", __FUNCTION__);
1356 /* We're out of the loop for some reason, terminate! */
1357 NtTerminateThread(NtCurrentThread(), Status);
1358 //return Status;
1359 }
1360 #endif
1361
1362 /*++
1363 * @name CsrApiPortInitialize
1364 *
1365 * The CsrApiPortInitialize routine initializes the LPC Port used for
1366 * communications with the Client/Server Runtime (CSR) and initializes the
1367 * static thread that will handle connection requests and APIs.
1368 *
1369 * @param None
1370 *
1371 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
1372 * otherwise.
1373 *
1374 * @remarks None.
1375 *
1376 *--*/
1377 NTSTATUS
1378 NTAPI
1379 CsrApiPortInitialize(VOID)
1380 {
1381 ULONG Size;
1382 OBJECT_ATTRIBUTES ObjectAttributes;
1383 NTSTATUS Status;
1384 HANDLE hRequestEvent, hThread;
1385 CLIENT_ID ClientId;
1386 PLIST_ENTRY ListHead, NextEntry;
1387 PCSR_THREAD ServerThread;
1388
1389 /* Calculate how much space we'll need for the Port Name */
1390 Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR);
1391
1392 /* Create the buffer for it */
1393 CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
1394 if (!CsrApiPortName.Buffer) return STATUS_NO_MEMORY;
1395
1396 /* Setup the rest of the empty string */
1397 CsrApiPortName.Length = 0;
1398 CsrApiPortName.MaximumLength = (USHORT)Size;
1399 RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
1400 RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
1401 RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);
1402 if (CsrDebug & 1)
1403 {
1404 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName);
1405 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
1406 sizeof(CSR_CONNECTION_INFO), sizeof(CSR_API_MESSAGE));
1407 }
1408
1409 /* FIXME: Create a Security Descriptor */
1410
1411 /* Initialize the Attributes */
1412 InitializeObjectAttributes(&ObjectAttributes,
1413 &CsrApiPortName,
1414 0,
1415 NULL,
1416 NULL /* FIXME*/);
1417
1418 /* Create the Port Object */
1419 Status = NtCreatePort(&CsrApiPort,
1420 &ObjectAttributes,
1421 LPC_MAX_DATA_LENGTH, // hack ; sizeof(CSR_CONNECTION_INFO),
1422 LPC_MAX_MESSAGE_LENGTH, // hack ; sizeof(CSR_API_MESSAGE),
1423 16 * PAGE_SIZE);
1424 if (NT_SUCCESS(Status))
1425 {
1426 /* Create the event the Port Thread will use */
1427 Status = NtCreateEvent(&hRequestEvent,
1428 EVENT_ALL_ACCESS,
1429 NULL,
1430 SynchronizationEvent,
1431 FALSE);
1432 if (NT_SUCCESS(Status))
1433 {
1434 /* Create the Request Thread */
1435 Status = RtlCreateUserThread(NtCurrentProcess(),
1436 NULL,
1437 TRUE,
1438 0,
1439 0,
1440 0,
1441 (PVOID)CsrApiRequestThread,
1442 (PVOID)hRequestEvent,
1443 &hThread,
1444 &ClientId);
1445 if (NT_SUCCESS(Status))
1446 {
1447 /* Add this as a static thread to CSRSRV */
1448 CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread);
1449
1450 /* Get the Thread List Pointers */
1451 ListHead = &CsrRootProcess->ThreadList;
1452 NextEntry = ListHead->Flink;
1453
1454 /* Start looping the list */
1455 while (NextEntry != ListHead)
1456 {
1457 /* Get the Thread */
1458 ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
1459
1460 /* Start it up */
1461 Status = NtResumeThread(ServerThread->ThreadHandle, NULL);
1462
1463 /* Is this a Server Thread? */
1464 if (ServerThread->Flags & CsrThreadIsServerThread)
1465 {
1466 /* If so, then wait for it to initialize */
1467 Status = NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
1468 ASSERT(NT_SUCCESS(Status));
1469 }
1470
1471 /* Next thread */
1472 NextEntry = NextEntry->Flink;
1473 }
1474
1475 /* We don't need this anymore */
1476 NtClose(hRequestEvent);
1477 }
1478 }
1479 }
1480
1481 /* Return */
1482 return Status;
1483 }
1484
1485 NTSTATUS WINAPI
1486 CsrpHandleConnectionRequest(PPORT_MESSAGE Request)
1487 {
1488 NTSTATUS Status;
1489 HANDLE ServerPort = NULL;//, ServerThread = NULL;
1490 PCSR_PROCESS ProcessData = NULL;
1491 REMOTE_PORT_VIEW RemotePortView;
1492 // CLIENT_ID ClientId;
1493 BOOLEAN AllowConnection = FALSE;
1494 PCSR_CONNECTION_INFO ConnectInfo;
1495 ServerPort = NULL;
1496
1497 DPRINT("CSR: %s: Handling: %p\n", __FUNCTION__, Request);
1498
1499 ConnectInfo = (PCSR_CONNECTION_INFO)(Request + 1);
1500
1501 /* Save the process ID */
1502 RtlZeroMemory(ConnectInfo, sizeof(CSR_CONNECTION_INFO));
1503
1504 CsrLockProcessByClientId(Request->ClientId.UniqueProcess, &ProcessData);
1505 if (!ProcessData)
1506 {
1507 DPRINT1("CSRSRV: Unknown process: %lx. Will be rejecting connection\n",
1508 Request->ClientId.UniqueProcess);
1509 }
1510
1511 if ((ProcessData) && (ProcessData != CsrRootProcess))
1512 {
1513 /* Attach the Shared Section */
1514 Status = CsrSrvAttachSharedSection(ProcessData, ConnectInfo);
1515 if (NT_SUCCESS(Status))
1516 {
1517 DPRINT("Connection ok\n");
1518 AllowConnection = TRUE;
1519 }
1520 else
1521 {
1522 DPRINT1("Shared section map failed: %lx\n", Status);
1523 }
1524 }
1525 else if (ProcessData == CsrRootProcess)
1526 {
1527 AllowConnection = TRUE;
1528 }
1529
1530 /* Release the process */
1531 if (ProcessData) CsrUnlockProcess(ProcessData);
1532
1533 /* Setup the Port View Structure */
1534 RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
1535 RemotePortView.ViewSize = 0;
1536 RemotePortView.ViewBase = NULL;
1537
1538 /* Save the Process ID */
1539 ConnectInfo->ProcessId = NtCurrentTeb()->ClientId.UniqueProcess;
1540
1541 Status = NtAcceptConnectPort(&ServerPort,
1542 AllowConnection ? UlongToPtr(ProcessData->SequenceNumber) : 0,
1543 Request,
1544 AllowConnection,
1545 NULL,
1546 &RemotePortView);
1547 if (!NT_SUCCESS(Status))
1548 {
1549 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status);
1550 }
1551 else if (AllowConnection)
1552 {
1553 if (CsrDebug & 2)
1554 {
1555 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
1556 Request->ClientId.UniqueProcess,
1557 Request->ClientId.UniqueThread,
1558 RemotePortView.ViewBase,
1559 RemotePortView.ViewSize);
1560 }
1561
1562 /* Set some Port Data in the Process */
1563 ProcessData->ClientPort = ServerPort;
1564 ProcessData->ClientViewBase = (ULONG_PTR)RemotePortView.ViewBase;
1565 ProcessData->ClientViewBounds = (ULONG_PTR)((ULONG_PTR)RemotePortView.ViewBase +
1566 (ULONG_PTR)RemotePortView.ViewSize);
1567
1568 /* Complete the connection */
1569 Status = NtCompleteConnectPort(ServerPort);
1570 if (!NT_SUCCESS(Status))
1571 {
1572 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status);
1573 }
1574 }
1575 else
1576 {
1577 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
1578 Request->ClientId.UniqueProcess,
1579 Request->ClientId.UniqueThread);
1580 }
1581
1582 return Status;
1583 }
1584
1585 /*++
1586 * @name CsrConnectToUser
1587 * @implemented NT4
1588 *
1589 * The CsrConnectToUser connects to the User subsystem.
1590 *
1591 * @param None
1592 *
1593 * @return A pointer to the CSR Thread
1594 *
1595 * @remarks None.
1596 *
1597 *--*/
1598 PCSR_THREAD
1599 NTAPI
1600 CsrConnectToUser(VOID)
1601 {
1602 NTSTATUS Status;
1603 ANSI_STRING DllName;
1604 UNICODE_STRING TempName;
1605 HANDLE hUser32;
1606 STRING StartupName;
1607 PTEB Teb = NtCurrentTeb();
1608 PCSR_THREAD CsrThread;
1609 BOOLEAN Connected;
1610
1611 /* Check if we didn't already find it */
1612 if (!CsrClientThreadSetup)
1613 {
1614 /* Get the DLL Handle for user32.dll */
1615 RtlInitAnsiString(&DllName, "user32");
1616 RtlAnsiStringToUnicodeString(&TempName, &DllName, TRUE);
1617 Status = LdrGetDllHandle(NULL,
1618 NULL,
1619 &TempName,
1620 &hUser32);
1621 RtlFreeUnicodeString(&TempName);
1622
1623 /* If we got teh handle, get the Client Thread Startup Entrypoint */
1624 if (NT_SUCCESS(Status))
1625 {
1626 RtlInitAnsiString(&StartupName,"ClientThreadSetup");
1627 Status = LdrGetProcedureAddress(hUser32,
1628 &StartupName,
1629 0,
1630 (PVOID)&CsrClientThreadSetup);
1631 }
1632 }
1633
1634 /* Connect to user32 */
1635 _SEH2_TRY
1636 {
1637 Connected = CsrClientThreadSetup();
1638 }
1639 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1640 {
1641 Connected = FALSE;
1642 } _SEH2_END;
1643
1644 if (!Connected)
1645 {
1646 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1647 return NULL;
1648 }
1649
1650 /* Save pointer to this thread in TEB */
1651 CsrAcquireProcessLock();
1652 CsrThread = CsrLocateThreadInProcess(NULL, &Teb->ClientId);
1653 CsrReleaseProcessLock();
1654 if (CsrThread) Teb->CsrClientThread = CsrThread;
1655
1656 /* Return it */
1657 return CsrThread;
1658 }
1659
1660 /*++
1661 * @name CsrQueryApiPort
1662 * @implemented NT4
1663 *
1664 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1665 *
1666 * @param None.
1667 *
1668 * @return A handle to the port.
1669 *
1670 * @remarks None.
1671 *
1672 *--*/
1673 HANDLE
1674 NTAPI
1675 CsrQueryApiPort(VOID)
1676 {
1677 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
1678 return CsrApiPort;
1679 }
1680
1681 /*++
1682 * @name CsrCaptureArguments
1683 * @implemented NT5.1
1684 *
1685 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1686 * re-captures it into a server CSR Capture Buffer.
1687 *
1688 * @param CsrThread
1689 * Pointer to the CSR Thread performing the validation.
1690 *
1691 * @param ApiMessage
1692 * Pointer to the CSR API Message containing the Capture Buffer
1693 * that needs to be validated.
1694 *
1695 * @return TRUE if validation succeeded, FALSE otherwise.
1696 *
1697 * @remarks None.
1698 *
1699 *--*/
1700 BOOLEAN
1701 NTAPI
1702 CsrCaptureArguments(IN PCSR_THREAD CsrThread,
1703 IN PCSR_API_MESSAGE ApiMessage)
1704 {
1705 PCSR_CAPTURE_BUFFER LocalCaptureBuffer = NULL, RemoteCaptureBuffer = NULL;
1706 ULONG LocalLength = 0, PointerCount = 0;
1707 SIZE_T BufferDistance = 0;
1708 ULONG_PTR **PointerOffsets = NULL, *CurrentPointer = NULL;
1709
1710 /* Use SEH to make sure this is valid */
1711 _SEH2_TRY
1712 {
1713 /* Get the buffer we got from whoever called NTDLL */
1714 LocalCaptureBuffer = ApiMessage->CsrCaptureData;
1715 LocalLength = LocalCaptureBuffer->Size;
1716
1717 /* Now check if the buffer is inside our mapped section */
1718 if (((ULONG_PTR)LocalCaptureBuffer < CsrThread->Process->ClientViewBase) ||
1719 (((ULONG_PTR)LocalCaptureBuffer + LocalLength) >= CsrThread->Process->ClientViewBounds))
1720 {
1721 /* Return failure */
1722 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1723 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1724 _SEH2_YIELD(return FALSE);
1725 }
1726
1727 /* Check if the Length is valid */
1728 if (((LocalCaptureBuffer->PointerCount * 4 + sizeof(CSR_CAPTURE_BUFFER)) >
1729 LocalLength) ||(LocalLength > MAXWORD))
1730 {
1731 /* Return failure */
1732 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer);
1733 DbgBreakPoint();
1734 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1735 _SEH2_YIELD(return FALSE);
1736 }
1737 }
1738 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1739 {
1740 /* Return failure */
1741 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1742 _SEH2_YIELD(return FALSE);
1743 } _SEH2_END;
1744
1745 /* We validated the incoming buffer, now allocate the remote one */
1746 RemoteCaptureBuffer = RtlAllocateHeap(CsrHeap, 0, LocalLength);
1747 if (!RemoteCaptureBuffer)
1748 {
1749 /* We're out of memory */
1750 ApiMessage->Status = STATUS_NO_MEMORY;
1751 return FALSE;
1752 }
1753
1754 /* Copy the client's buffer */
1755 RtlMoveMemory(RemoteCaptureBuffer, LocalCaptureBuffer, LocalLength);
1756
1757 /* Copy the length */
1758 RemoteCaptureBuffer->Size = LocalLength;
1759
1760 /* Calculate the difference between our buffer and the client's */
1761 BufferDistance = (ULONG_PTR)RemoteCaptureBuffer - (ULONG_PTR)LocalCaptureBuffer;
1762
1763 /* Save the pointer count and offset pointer */
1764 PointerCount = RemoteCaptureBuffer->PointerCount;
1765 PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1);
1766
1767 /* Start the loop */
1768 while (PointerCount)
1769 {
1770 /* Get the current pointer */
1771 if ((CurrentPointer = *PointerOffsets++))
1772 {
1773 /* Add it to the CSR Message structure */
1774 CurrentPointer += (ULONG_PTR)ApiMessage;
1775
1776 /* Validate the bounds of the current pointer */
1777 if ((*CurrentPointer >= CsrThread->Process->ClientViewBase) &&
1778 (*CurrentPointer < CsrThread->Process->ClientViewBounds))
1779 {
1780 /* Modify the pointer to take into account its new position */
1781 *CurrentPointer += BufferDistance;
1782 }
1783 else
1784 {
1785 /* Invalid pointer, fail */
1786 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1787 DbgBreakPoint();
1788 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1789 }
1790 }
1791
1792 /* Move to the next Pointer */
1793 PointerCount--;
1794 }
1795
1796 /* Check if we got success */
1797 if (ApiMessage->Status != STATUS_SUCCESS)
1798 {
1799 /* Failure. Free the buffer and return*/
1800 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1801 return FALSE;
1802 }
1803 else
1804 {
1805 /* Success, save the previous buffer */
1806 RemoteCaptureBuffer->PreviousCaptureBuffer = LocalCaptureBuffer;
1807 ApiMessage->CsrCaptureData = RemoteCaptureBuffer;
1808 }
1809
1810 /* Success */
1811 return TRUE;
1812 }
1813
1814 /*++
1815 * @name CsrReleaseCapturedArguments
1816 * @implemented NT5.1
1817 *
1818 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1819 * that was previously captured with CsrCaptureArguments.
1820 *
1821 * @param ApiMessage
1822 * Pointer to the CSR API Message containing the Capture Buffer
1823 * that needs to be released.
1824 *
1825 * @return None.
1826 *
1827 * @remarks None.
1828 *
1829 *--*/
1830 VOID
1831 NTAPI
1832 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
1833 {
1834 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer, LocalCaptureBuffer;
1835 SIZE_T BufferDistance;
1836 ULONG PointerCount;
1837 ULONG_PTR **PointerOffsets, *CurrentPointer;
1838
1839 /* Get the capture buffers */
1840 RemoteCaptureBuffer = ApiMessage->CsrCaptureData;
1841 LocalCaptureBuffer = RemoteCaptureBuffer->PreviousCaptureBuffer;
1842
1843 /* Free the previous one */
1844 RemoteCaptureBuffer->PreviousCaptureBuffer = NULL;
1845
1846 /* Find out the difference between the two buffers */
1847 BufferDistance = (ULONG_PTR)LocalCaptureBuffer - (ULONG_PTR)RemoteCaptureBuffer;
1848
1849 /* Save the pointer count and offset pointer */
1850 PointerCount = RemoteCaptureBuffer->PointerCount;
1851 PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1);
1852
1853 /* Start the loop */
1854 while (PointerCount)
1855 {
1856 /* Get the current pointer */
1857 CurrentPointer = *PointerOffsets++;
1858 if (CurrentPointer)
1859 {
1860 /* Add it to the CSR Message structure */
1861 CurrentPointer += (ULONG_PTR)ApiMessage;
1862
1863 /* Modify the pointer to take into account its new position */
1864 *CurrentPointer += BufferDistance;
1865 }
1866
1867 /* Move to the next Pointer */
1868 PointerCount--;
1869 }
1870
1871 /* Copy the data back */
1872 RtlMoveMemory(LocalCaptureBuffer, RemoteCaptureBuffer, RemoteCaptureBuffer->Size);
1873
1874 /* Free our allocated buffer */
1875 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1876 }
1877
1878
1879 /*++
1880 * @name CsrValidateMessageBuffer
1881 * @implemented NT5.1
1882 *
1883 * The CsrValidateMessageBuffer routine validates a captured message buffer
1884 * present in the CSR Api Message
1885 *
1886 * @param ApiMessage
1887 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1888 *
1889 * @param Buffer
1890 * Pointer to the message buffer to validate.
1891 *
1892 * @param ArgumentSize
1893 * Size of the message to check.
1894 *
1895 * @param ArgumentCount
1896 * Number of messages to check.
1897 *
1898 * @return TRUE if validation suceeded, FALSE otherwise.
1899 *
1900 * @remarks None.
1901 *
1902 *--*/
1903 BOOLEAN
1904 NTAPI
1905 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage,
1906 IN PVOID *Buffer,
1907 IN ULONG ArgumentSize,
1908 IN ULONG ArgumentCount)
1909 {
1910 PCSR_CAPTURE_BUFFER CaptureBuffer = ApiMessage->CsrCaptureData;
1911 SIZE_T BufferDistance;
1912 ULONG PointerCount, i;
1913 ULONG_PTR **PointerOffsets, *CurrentPointer;
1914
1915 /* Make sure there are some arguments */
1916 if (!ArgumentCount) return FALSE;
1917
1918 /* Check if didn't get a buffer and there aren't any arguments to check */
1919 if (!(*Buffer) && (!(ArgumentCount * ArgumentSize))) return TRUE;
1920
1921 /* Check if we have no capture buffer */
1922 if (!CaptureBuffer)
1923 {
1924 /* In this case, check only the Process ID */
1925 if (NtCurrentTeb()->ClientId.UniqueProcess ==
1926 ApiMessage->Header.ClientId.UniqueProcess)
1927 {
1928 /* There is a match, validation succeeded */
1929 return TRUE;
1930 }
1931 }
1932 else
1933 {
1934 /* Make sure that there is still space left in the buffer */
1935 if ((CaptureBuffer->Size - (ULONG_PTR)*Buffer + (ULONG_PTR)CaptureBuffer) <
1936 (ArgumentCount * ArgumentSize))
1937 {
1938 /* Find out the difference between the two buffers */
1939 BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage;
1940
1941 /* Save the pointer count */
1942 PointerCount = CaptureBuffer->PointerCount;
1943 PointerOffsets = (ULONG_PTR**)(CaptureBuffer + 1);
1944
1945 /* Start the loop */
1946 for (i = 0; i < PointerCount; i++)
1947 {
1948 /* Get the current pointer */
1949 CurrentPointer = *PointerOffsets++;
1950
1951 /* Check if its' equal to the difference */
1952 if (*CurrentPointer == BufferDistance) return TRUE;
1953 }
1954 }
1955 }
1956
1957 /* Failure */
1958 DbgPrint("CSRSRV: Bad message buffer %p\n", ApiMessage);
1959 DbgBreakPoint();
1960 return FALSE;
1961 }
1962
1963 /*++
1964 * @name CsrValidateMessageString
1965 * @implemented NT5.1
1966 *
1967 * The CsrValidateMessageString validates a captured Wide-Character String
1968 * present in a CSR API Message.
1969 *
1970 * @param ApiMessage
1971 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1972 *
1973 * @param MessageString
1974 * Pointer to the buffer containing the string to validate.
1975 *
1976 * @return TRUE if validation suceeded, FALSE otherwise.
1977 *
1978 * @remarks None.
1979 *
1980 *--*/
1981 BOOLEAN
1982 NTAPI
1983 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage,
1984 IN LPWSTR *MessageString)
1985 {
1986 DPRINT1("CSRSRV: %s called\n", __FUNCTION__);
1987 return FALSE;
1988 }
1989
1990 /* EOF */