29f01f150bc7e25a62e7d5dc8a27031e5631d71d
[reactos.git] / reactos / subsys / csr / csrsrv / api.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR Sub System
4 * FILE: subsys/csr/csrsrv/api.c
5 * PURPOSE: CSR Server DLL API LPC Implementation
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "srv.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* DATA **********************************************************************/
17 BOOLEAN (*CsrClientThreadSetup)(VOID) = NULL;
18 ULONG CsrMaxApiRequestThreads;
19 UNICODE_STRING CsrSbApiPortName;
20 UNICODE_STRING CsrApiPortName;
21 HANDLE CsrSbApiPort;
22 HANDLE CsrApiPort;
23 PCSR_THREAD CsrSbApiRequestThreadPtr;
24 ULONG CsrpStaticThreadCount;
25 ULONG CsrpDynamicThreadTotal;
26
27 /* PRIVATE FUNCTIONS *********************************************************/
28
29 /*++
30 * @name CsrCheckRequestThreads
31 *
32 * The CsrCheckRequestThreads routine checks if there are no more threads
33 * to handle CSR API Requests, and creates a new thread if possible, to
34 * avoid starvation.
35 *
36 * @param None.
37 *
38 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
39 * if a new thread couldn't be created.
40 *
41 * @remarks None.
42 *
43 *--*/
44 NTSTATUS
45 NTAPI
46 CsrCheckRequestThreads(VOID)
47 {
48 HANDLE hThread;
49 CLIENT_ID ClientId;
50 NTSTATUS Status;
51
52 /* Decrease the count, and see if we're out */
53 if (!(InterlockedDecrement(&CsrpStaticThreadCount)))
54 {
55 /* Check if we've still got space for a Dynamic Thread */
56 if (CsrpDynamicThreadTotal < CsrMaxApiRequestThreads)
57 {
58 /* Create a new dynamic thread */
59 Status = RtlCreateUserThread(NtCurrentProcess(),
60 NULL,
61 TRUE,
62 0,
63 0,
64 0,
65 (PVOID)CsrApiRequestThread,
66 NULL,
67 &hThread,
68 &ClientId);
69 /* Check success */
70 if(NT_SUCCESS(Status))
71 {
72 /* Increase the thread counts */
73 CsrpStaticThreadCount++;
74 CsrpDynamicThreadTotal++;
75
76 /* Add a new server thread */
77 if (CsrAddStaticServerThread(hThread,
78 &ClientId,
79 CsrThreadIsServerThread))
80 {
81 /* Activate it */
82 NtResumeThread(hThread,NULL);
83 }
84 else
85 {
86 /* Failed to create a new static thread */
87 CsrpStaticThreadCount--;
88 CsrpDynamicThreadTotal--;
89
90 /* Terminate it */
91 NtTerminateThread(hThread,0);
92 NtClose(hThread);
93
94 /* Return */
95 return STATUS_UNSUCCESSFUL;
96 }
97 }
98 }
99 }
100
101 /* Success */
102 return STATUS_SUCCESS;
103 }
104
105 /*++
106 * @name CsrSbApiPortInitialize
107 *
108 * The CsrSbApiPortInitialize routine initializes the LPC Port used for
109 * communications with the Session Manager (SM) and initializes the static
110 * thread that will handle connection requests and APIs.
111 *
112 * @param None
113 *
114 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
115 * othwerwise.
116 *
117 * @remarks None.
118 *
119 *--*/
120 NTSTATUS
121 NTAPI
122 CsrSbApiPortInitialize(VOID)
123 {
124 ULONG Size;
125 PSECURITY_DESCRIPTOR PortSd;
126 OBJECT_ATTRIBUTES ObjectAttributes;
127 NTSTATUS Status;
128 HANDLE hRequestThread;
129 CLIENT_ID ClientId;
130
131 /* Calculate how much space we'll need for the Port Name */
132 Size = CsrDirectoryName.Length + sizeof(SB_PORT_NAME) + sizeof(WCHAR);
133
134 /* Allocate space for it, and create it */
135 CsrSbApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
136 CsrSbApiPortName.Length = 0;
137 CsrSbApiPortName.MaximumLength = (USHORT)Size;
138 RtlAppendUnicodeStringToString(&CsrSbApiPortName, &CsrDirectoryName);
139 RtlAppendUnicodeToString(&CsrSbApiPortName, UNICODE_PATH_SEP);
140 RtlAppendUnicodeToString(&CsrSbApiPortName, SB_PORT_NAME);
141
142 /* Create Security Descriptor for this Port */
143 CsrCreateLocalSystemSD(&PortSd);
144
145 /* Initialize the Attributes */
146 InitializeObjectAttributes(&ObjectAttributes,
147 &CsrSbApiPortName,
148 0,
149 PortSd,
150 NULL);
151
152 /* Create the Port Object */
153 Status = NtCreatePort(&CsrSbApiPort,
154 &ObjectAttributes,
155 sizeof(SB_CONNECTION_INFO),
156 sizeof(SB_API_MESSAGE),
157 32 * sizeof(SB_API_MESSAGE));
158 if(!NT_SUCCESS(Status))
159 {
160
161 }
162
163 /* Create the Thread to handle the API Requests */
164 Status = RtlCreateUserThread(NtCurrentProcess(),
165 NULL,
166 TRUE,
167 0,
168 0,
169 0,
170 (PVOID)CsrSbApiRequestThread,
171 NULL,
172 &hRequestThread,
173 &ClientId);
174 if(!NT_SUCCESS(Status))
175 {
176
177 }
178
179 /* Add it as a Static Server Thread */
180 CsrSbApiRequestThreadPtr = CsrAddStaticServerThread(hRequestThread,
181 &ClientId,
182 0);
183
184 /* Activate it */
185 return NtResumeThread(hRequestThread, NULL);
186 }
187
188 /*++
189 * @name CsrApiPortInitialize
190 *
191 * The CsrApiPortInitialize routine initializes the LPC Port used for
192 * communications with the Client/Server Runtime (CSR) and initializes the
193 * static thread that will handle connection requests and APIs.
194 *
195 * @param None
196 *
197 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
198 * othwerwise.
199 *
200 * @remarks None.
201 *
202 *--*/
203 NTSTATUS
204 NTAPI
205 CsrApiPortInitialize(VOID)
206 {
207 ULONG Size;
208 OBJECT_ATTRIBUTES ObjectAttributes;
209 NTSTATUS Status;
210 HANDLE hRequestEvent, hThread;
211 CLIENT_ID ClientId;
212 PLIST_ENTRY ListHead, NextEntry;
213 PCSR_THREAD ServerThread;
214
215 /* Calculate how much space we'll need for the Port Name */
216 Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR);
217
218 /* Allocate space for it, and create it */
219 CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
220 CsrApiPortName.Length = 0;
221 CsrApiPortName.MaximumLength = (USHORT)Size;
222 RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
223 RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
224 RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);
225
226 /* FIXME: Create a Security Descriptor */
227
228 /* Initialize the Attributes */
229 InitializeObjectAttributes(&ObjectAttributes,
230 &CsrApiPortName,
231 0,
232 NULL,
233 NULL /* FIXME*/);
234
235 /* Create the Port Object */
236 Status = NtCreatePort(&CsrApiPort,
237 &ObjectAttributes,
238 sizeof(CSR_CONNECTION_INFO),
239 sizeof(CSR_API_MESSAGE),
240 16 * PAGE_SIZE);
241 if(!NT_SUCCESS(Status))
242 {
243
244 }
245
246 /* Create the event the Port Thread will use */
247 Status = NtCreateEvent(&hRequestEvent,
248 EVENT_ALL_ACCESS,
249 NULL,
250 SynchronizationEvent,
251 FALSE);
252 if(!NT_SUCCESS(Status))
253 {
254
255 }
256
257 /* Create the Request Thread */
258 Status = RtlCreateUserThread(NtCurrentProcess(),
259 NULL,
260 TRUE,
261 0,
262 0,
263 0,
264 (PVOID)CsrApiRequestThread,
265 (PVOID)hRequestEvent,
266 &hThread,
267 &ClientId);
268 if(!NT_SUCCESS(Status))
269 {
270
271 }
272
273 /* Add this as a static thread to CSRSRV */
274 CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread);
275
276 /* Get the Thread List Pointers */
277 ListHead = &CsrRootProcess->ThreadList;
278 NextEntry = ListHead->Flink;
279
280 /* Start looping the list */
281 while (NextEntry != ListHead)
282 {
283 /* Get the Thread */
284 ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
285
286 /* Start it up */
287 Status = NtResumeThread(ServerThread->ThreadHandle, NULL);
288
289 /* Is this a Server Thread? */
290 if (ServerThread->Flags & CsrThreadIsServerThread)
291 {
292 /* If so, then wait for it to initialize */
293 NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
294 }
295
296 /* Next thread */
297 NextEntry = NextEntry->Flink;
298 }
299
300 /* We don't need this anymore */
301 NtClose(hRequestEvent);
302
303 /* Return */
304 return Status;
305 }
306
307 /*++
308 * @name CsrApiRequestThread
309 *
310 * The CsrApiRequestThread routine handles incoming messages or connection
311 * requests on the CSR API LPC Port.
312 *
313 * @param Parameter
314 * System-default user-defined parameter. Unused.
315 *
316 * @return The thread exit code, if the thread is terminated.
317 *
318 * @remarks Before listening on the port, the routine will first attempt
319 * to connect to the user subsystem.
320 *
321 *--*/
322 NTSTATUS
323 NTAPI
324 CsrApiRequestThread(IN PVOID Parameter)
325 {
326 PTEB Teb = NtCurrentTeb();
327 LARGE_INTEGER TimeOut;
328 PCSR_THREAD CurrentThread;
329 NTSTATUS Status;
330 PCSR_API_MESSAGE ReplyMsg = NULL;
331 CSR_API_MESSAGE ReceiveMsg;
332 PCSR_THREAD CsrThread;
333 PCSR_PROCESS CsrProcess;
334 PHARDERROR_MSG HardErrorMsg;
335 PVOID PortContext;
336 ULONG MessageType;
337 ULONG i;
338 PCSR_SERVER_DLL ServerDll;
339 PCLIENT_DIED_MSG ClientDiedMsg;
340 PDBGKM_MSG DebugMessage;
341 ULONG ServerId, ApiId;
342 ULONG Reply;
343
344 /* Probably because of the way GDI is loaded, this has to be done here */
345 Teb->GdiClientPID = HandleToUlong(Teb->Cid.UniqueProcess);
346 Teb->GdiClientTID = HandleToUlong(Teb->Cid.UniqueThread);
347
348 /* Set up the timeout for the connect (30 seconds) */
349 TimeOut.QuadPart = -30 * 1000 * 1000 * 10;
350
351 /* Connect to user32 */
352 while (!CsrConnectToUser())
353 {
354 /* Keep trying until we get a response */
355 Teb->Win32ClientInfo[0] = 0;
356 NtDelayExecution(FALSE, &TimeOut);
357 }
358
359 /* Get our thread */
360 CurrentThread = Teb->CsrClientThread;
361
362 /* If we got an event... */
363 if (Parameter)
364 {
365 /* Set it, to let stuff waiting on us load */
366 NtSetEvent((HANDLE)Parameter, NULL);
367
368 /* Increase the Thread Counts */
369 InterlockedIncrement(&CsrpStaticThreadCount);
370 InterlockedIncrement(&CsrpDynamicThreadTotal);
371 }
372
373 /* Now start the loop */
374 while (TRUE)
375 {
376 /* Make sure the real CID is set */
377 Teb->RealClientId = Teb->Cid;
378
379 /* Wait for a message to come through */
380 Status = NtReplyWaitReceivePort(CsrApiPort,
381 &PortContext,
382 (PPORT_MESSAGE)ReplyMsg,
383 (PPORT_MESSAGE)&ReceiveMsg);
384
385 /* Check if we didn't get success */
386 if(Status != STATUS_SUCCESS)
387 {
388 /* If we only got a warning, keep going */
389 if (NT_SUCCESS(Status)) continue;
390
391 /* We failed big time, so start out fresh */
392 ReplyMsg = NULL;
393 continue;
394 }
395
396 /* Use whatever Client ID we got */
397 Teb->RealClientId = ReceiveMsg.Header.ClientId;
398
399 /* Get the Message Type */
400 MessageType = ReceiveMsg.Header.u2.s2.Type;
401
402 /* Handle connection requests */
403 if (MessageType == LPC_CONNECTION_REQUEST)
404 {
405 /* Handle the Connection Request */
406 CsrApiHandleConnectionRequest(&ReceiveMsg);
407 ReplyMsg = NULL;
408 continue;
409 }
410
411 /* It's some other kind of request. Get the lock for the lookup*/
412 CsrAcquireProcessLock();
413
414 /* Now do the lookup to get the CSR_THREAD */
415 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
416 &ReceiveMsg.Header.ClientId);
417
418 /* Did we find a thread? */
419 if(!CsrThread)
420 {
421 /* This wasn't a CSR Thread, release lock */
422 CsrReleaseProcessLock();
423
424 /* If this was an exception, handle it */
425 if (MessageType == LPC_EXCEPTION)
426 {
427 ReplyMsg = &ReceiveMsg;
428 ReplyMsg->Status = DBG_CONTINUE;
429 }
430 else if (MessageType == LPC_PORT_CLOSED ||
431 MessageType == LPC_CLIENT_DIED)
432 {
433 /* The Client or Port are gone, loop again */
434 ReplyMsg = NULL;
435 }
436 else if (MessageType == LPC_ERROR_EVENT)
437 {
438 /* If it's a hard error, handle this too */
439 HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
440
441 /* Default it to unhandled */
442 HardErrorMsg->Response = ResponseNotHandled;
443
444 /* Check if there are free api threads */
445 CsrCheckRequestThreads();
446 if (CsrpStaticThreadCount)
447 {
448 /* Loop every Server DLL */
449 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
450 {
451 /* Get the Server DLL */
452 ServerDll = CsrLoadedServerDll[i];
453
454 /* Check if it's valid and if it has a Hard Error Callback */
455 if (ServerDll && ServerDll->HardErrorCallback)
456 {
457 /* Call it */
458 (*ServerDll->HardErrorCallback)(CsrThread, HardErrorMsg);
459
460 /* If it's handled, get out of here */
461 if (HardErrorMsg->Response != ResponseNotHandled) break;
462 }
463 }
464 }
465
466 /* Increase the thread count */
467 InterlockedIncrement(&CsrpStaticThreadCount);
468
469 /* If the response was 0xFFFFFFFF, we'll ignore it */
470 if (HardErrorMsg->Response == 0xFFFFFFFF)
471 {
472 ReplyMsg = NULL;
473 }
474 else
475 {
476 ReplyMsg = &ReceiveMsg;
477 }
478 }
479 else if (MessageType == LPC_REQUEST)
480 {
481 /* This is an API Message coming from a non-CSR Thread */
482 ReplyMsg = &ReceiveMsg;
483 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
484 }
485 else if (MessageType == LPC_DATAGRAM)
486 {
487 /* This is an API call, get the Server ID */
488 ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg.Opcode);
489
490 /* Make sure that the ID is within limits, and the Server DLL loaded */
491 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
492 (!(ServerDll = CsrLoadedServerDll[ServerId])))
493 {
494 /* We are beyond the Maximum Server ID */
495 ReplyMsg = NULL;
496 }
497 else
498 {
499 /* Get the API ID */
500 ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode);
501
502 /* Normalize it with our Base ID */
503 ApiId -= ServerDll->ApiBase;
504
505 /* Make sure that the ID is within limits, and the entry exists */
506 if ((ApiId >= ServerDll->HighestApiSupported))
507 {
508 /* We are beyond the Maximum API ID, or it doesn't exist */
509 ReplyMsg = NULL;
510 }
511
512 /* Assume success */
513 ReceiveMsg.Status = STATUS_SUCCESS;
514
515 /* Validation complete, start SEH */
516 _SEH_TRY
517 {
518 /* Make sure we have enough threads */
519 CsrCheckRequestThreads();
520
521 /* Call the API and get the result */
522 ReplyMsg = NULL;
523 (ServerDll->DispatchTable[ApiId])(&ReceiveMsg, &Reply);
524
525 /* Increase the static thread count */
526 InterlockedIncrement(&CsrpStaticThreadCount);
527 }
528 _SEH_EXCEPT(CsrUnhandledExceptionFilter)
529 {
530 ReplyMsg = NULL;
531 }
532 _SEH_END;
533 }
534 }
535 else
536 {
537 /* Some other ignored message type */
538 ReplyMsg = NULL;
539 }
540
541 /* Keep going */
542 continue;
543 }
544
545 /* We have a valid thread, was this an LPC Request? */
546 if (MessageType != LPC_REQUEST)
547 {
548 /* It's not an API, check if the client died */
549 if (MessageType == LPC_CLIENT_DIED)
550 {
551 /* Get the information and check if it matches our thread */
552 ClientDiedMsg = (PCLIENT_DIED_MSG)&ReceiveMsg;
553 if (ClientDiedMsg->CreateTime.QuadPart == CsrThread->CreateTime.QuadPart)
554 {
555 /* Reference the thread */
556 CsrThread->ReferenceCount++;
557
558 /* Destroy the thread in the API Message */
559 CsrDestroyThread(&ReceiveMsg.Header.ClientId);
560
561 /* Check if the thread was actually ourselves */
562 if (CsrProcess->ThreadCount == 1)
563 {
564 /* Kill the process manually here */
565 CsrDestroyProcess(&CsrThread->ClientId, 0);
566 }
567
568 /* Remove our extra reference */
569 CsrLockedDereferenceThread(CsrThread);
570 }
571
572 /* Release the lock and keep looping */
573 CsrReleaseProcessLock();
574 ReplyMsg = NULL;
575 continue;
576 }
577
578 /* Reference the thread and release the lock */
579 CsrThread->ReferenceCount++;
580 CsrReleaseProcessLock();
581
582 /* Check if this was an exception */
583 if (MessageType == LPC_EXCEPTION)
584 {
585 /* Kill the process */
586 NtTerminateProcess(CsrProcess->ProcessHandle, STATUS_ABANDONED);
587
588 /* Destroy it from CSR */
589 CsrDestroyProcess(&ReceiveMsg.Header.ClientId, STATUS_ABANDONED);
590
591 /* Return a Debug Message */
592 DebugMessage = (PDBGKM_MSG)&ReceiveMsg;
593 DebugMessage->Status = DBG_CONTINUE;
594 ReplyMsg = &ReceiveMsg;
595
596 /* Remove our extra reference */
597 CsrDereferenceThread(CsrThread);
598 }
599 else if (MessageType == LPC_ERROR_EVENT)
600 {
601 /* If it's a hard error, handle this too */
602 HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
603
604 /* Default it to unhandled */
605 HardErrorMsg->Response = ResponseNotHandled;
606
607 /* Check if there are free api threads */
608 CsrCheckRequestThreads();
609 if (CsrpStaticThreadCount)
610 {
611 /* Loop every Server DLL */
612 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
613 {
614 /* Get the Server DLL */
615 ServerDll = CsrLoadedServerDll[i];
616
617 /* Check if it's valid and if it has a Hard Error Callback */
618 if (ServerDll && ServerDll->HardErrorCallback)
619 {
620 /* Call it */
621 (*ServerDll->HardErrorCallback)(CsrThread, HardErrorMsg);
622
623 /* If it's handled, get out of here */
624 if (HardErrorMsg->Response != ResponseNotHandled) break;
625 }
626 }
627 }
628
629 /* Increase the thread count */
630 InterlockedIncrement(&CsrpStaticThreadCount);
631
632 /* If the response was 0xFFFFFFFF, we'll ignore it */
633 if (HardErrorMsg->Response == 0xFFFFFFFF)
634 {
635 ReplyMsg = NULL;
636 }
637 else
638 {
639 CsrDereferenceThread(CsrThread);
640 ReplyMsg = &ReceiveMsg;
641 }
642 }
643 else
644 {
645 /* Something else */
646 CsrDereferenceThread(CsrThread);
647 ReplyMsg = NULL;
648 }
649
650 /* Keep looping */
651 continue;
652 }
653
654 /* We got an API Request */
655 CsrDereferenceThread(CsrThread);
656 CsrReleaseProcessLock();
657
658 /* FIXME: Handle the API */
659
660 }
661
662 /* We're out of the loop for some reason, terminate! */
663 NtTerminateThread(NtCurrentThread(), Status);
664 return Status;
665 }
666
667 /*++
668 * @name CsrApiHandleConnectionRequest
669 *
670 * The CsrApiHandleConnectionRequest routine handles and accepts a new
671 * connection request to the CSR API LPC Port.
672 *
673 * @param ApiMessage
674 * Pointer to the incoming CSR API Message which contains the
675 * connection request.
676 *
677 * @return STATUS_SUCCESS in case of success, or status code which caused
678 * the routine to error.
679 *
680 * @remarks This routine is responsible for attaching the Shared Section to
681 * new clients connecting to CSR.
682 *
683 *--*/
684 NTSTATUS
685 NTAPI
686 CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage)
687 {
688 PCSR_THREAD CsrThread = NULL;
689 PCSR_PROCESS CsrProcess = NULL;
690 NTSTATUS Status = STATUS_SUCCESS;
691 PCSR_CONNECTION_INFO ConnectInfo = &ApiMessage->ConnectionInfo;
692 BOOLEAN AllowConnection = FALSE;
693 REMOTE_PORT_VIEW RemotePortView;
694 HANDLE hPort;
695
696 /* Acquire the Process Lock */
697 CsrAcquireProcessLock();
698
699 /* Lookup the CSR Thread */
700 CsrThread = CsrLocateThreadByClientId(NULL, &ApiMessage->Header.ClientId);
701
702 /* Check if we have a thread */
703 if (CsrThread)
704 {
705 /* Get the Process */
706 CsrProcess = CsrThread->Process;
707
708 /* Make sure we have a Process as well */
709 if (CsrProcess)
710 {
711 /* Reference the Process */
712 CsrProcess->ReferenceCount++;
713
714 /* Release the lock */
715 CsrReleaseProcessLock();
716
717 /* Duplicate the Object Directory */
718 Status = NtDuplicateObject(NtCurrentProcess(),
719 CsrObjectDirectory,
720 CsrProcess->ProcessHandle,
721 &ConnectInfo->ObjectDirectory,
722 0,
723 0,
724 DUPLICATE_SAME_ACCESS |
725 DUPLICATE_SAME_ATTRIBUTES);
726
727 /* Acquire the lock */
728 CsrAcquireProcessLock();
729
730 /* Check for success */
731 if (NT_SUCCESS(Status))
732 {
733 /* Attach the Shared Section */
734 Status = CsrSrvAttachSharedSection(CsrProcess, ConnectInfo);
735
736 /* Check how this went */
737 if (NT_SUCCESS(Status)) AllowConnection = TRUE;
738 }
739
740 /* Dereference the project */
741 CsrProcess->ReferenceCount--;
742 }
743 }
744
745 /* Release the lock */
746 CsrReleaseProcessLock();
747
748 /* Setup the Port View Structure */
749 RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
750 RemotePortView.ViewSize = 0;
751 RemotePortView.ViewBase = NULL;
752
753 /* Save the Process ID */
754 ConnectInfo->ProcessId = NtCurrentTeb()->Cid.UniqueProcess;
755
756 /* Accept the Connection */
757 Status = NtAcceptConnectPort(&hPort,
758 AllowConnection ? UlongToPtr(CsrProcess->SequenceNumber) : 0,
759 &ApiMessage->Header,
760 AllowConnection,
761 NULL,
762 &RemotePortView);
763
764 /* Check if the connection was established, or if we allowed it */
765 if (NT_SUCCESS(Status) && AllowConnection)
766 {
767 /* Set some Port Data in the Process */
768 CsrProcess->ClientPort = hPort;
769 CsrProcess->ClientViewBase = (ULONG_PTR)RemotePortView.ViewBase;
770 CsrProcess->ClientViewBounds = (ULONG_PTR)((ULONG_PTR)RemotePortView.ViewBase +
771 (ULONG_PTR)RemotePortView.ViewSize);
772
773 /* Complete the connection */
774 Status = NtCompleteConnectPort(hPort);
775 }
776
777 /* The accept or complete could've failed, let debug builds know */
778 if (!NT_SUCCESS(Status))
779 {
780 DPRINT1("CSRSS: Failure to accept connection. Status: %lx\n", Status);
781 }
782
783 /* Return status to caller */
784 return Status;
785 }
786
787 /*++
788 * @name CsrSbApiRequestThread
789 *
790 * The CsrSbApiRequestThread routine handles incoming messages or connection
791 * requests on the SM API LPC Port.
792 *
793 * @param Parameter
794 * System-default user-defined parameter. Unused.
795 *
796 * @return The thread exit code, if the thread is terminated.
797 *
798 * @remarks Before listening on the port, the routine will first attempt
799 * to connect to the user subsystem.
800 *
801 *--*/
802 VOID
803 NTAPI
804 CsrSbApiRequestThread(IN PVOID Parameter)
805 {
806 NTSTATUS Status;
807 SB_API_MESSAGE ReceiveMsg;
808 PSB_API_MESSAGE ReplyMsg = NULL;
809 PVOID PortContext;
810 ULONG MessageType;
811
812 /* Start the loop */
813 while (TRUE)
814 {
815 /* Wait for a message to come in */
816 Status = NtReplyWaitReceivePort(CsrSbApiPort,
817 &PortContext,
818 (PPORT_MESSAGE)ReplyMsg,
819 (PPORT_MESSAGE)&ReceiveMsg);
820
821 /* Check if we didn't get success */
822 if(Status != STATUS_SUCCESS)
823 {
824 /* If we only got a warning, keep going */
825 if (NT_SUCCESS(Status)) continue;
826
827 /* We failed big time, so start out fresh */
828 ReplyMsg = NULL;
829 continue;
830 }
831
832 /* Save the message type */
833 MessageType = ReceiveMsg.Header.u2.s2.Type;
834
835 /* Check if this is a connection request */
836 if (MessageType == LPC_CONNECTION_REQUEST)
837 {
838 /* Handle connection request */
839 CsrSbApiHandleConnectionRequest(&ReceiveMsg);
840
841 /* Start over */
842 ReplyMsg = NULL;
843 continue;
844 }
845
846 /* Check if the port died */
847 if (MessageType == LPC_PORT_CLOSED)
848 {
849 /* Close the handle if we have one */
850 if (PortContext) NtClose((HANDLE)PortContext);
851
852 /* Client died, start over */
853 ReplyMsg = NULL;
854 continue;
855 }
856 else if (MessageType == LPC_CLIENT_DIED)
857 {
858 /* Client died, start over */
859 ReplyMsg = NULL;
860 continue;
861 }
862
863 /*
864 * It's an API Message, check if it's within limits. If it's not, the
865 * NT Behaviour is to set this to the Maximum API.
866 */
867 if (ReceiveMsg.Opcode > 4) ReceiveMsg.Opcode = 4;
868
869 /* Reuse the message */
870 ReplyMsg = &ReceiveMsg;
871
872 /* Make sure that the message is supported */
873 if (ReceiveMsg.Opcode < 4)
874 {
875 /* Call the API */
876 if (!(CsrServerSbApiDispatch[ReceiveMsg.Opcode])(&ReceiveMsg))
877 {
878 /* It failed, so return nothing */
879 ReplyMsg = NULL;
880 }
881 }
882 else
883 {
884 /* We don't support this API Number */
885 ReplyMsg->Status = STATUS_NOT_IMPLEMENTED;
886 }
887 }
888 }
889
890 /*++
891 * @name CsrSbApiHandleConnectionRequest
892 *
893 * The CsrSbApiHandleConnectionRequest routine handles and accepts a new
894 * connection request to the SM API LPC Port.
895 *
896 * @param ApiMessage
897 * Pointer to the incoming CSR API Message which contains the
898 * connection request.
899 *
900 * @return STATUS_SUCCESS in case of success, or status code which caused
901 * the routine to error.
902 *
903 * @remarks None.
904 *
905 *--*/
906 NTSTATUS
907 NTAPI
908 CsrSbApiHandleConnectionRequest(IN PSB_API_MESSAGE Message)
909 {
910 NTSTATUS Status;
911 REMOTE_PORT_VIEW RemotePortView;
912 HANDLE hPort;
913
914 /* Set the Port View Structure Length */
915 RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
916
917 /* Accept the connection */
918 Status = NtAcceptConnectPort(&hPort,
919 NULL,
920 (PPORT_MESSAGE)Message,
921 TRUE,
922 NULL,
923 &RemotePortView);
924
925 if (!NT_SUCCESS(Status))
926 {
927 DPRINT1("CSRSS: Sb Accept Connection failed %lx\n", Status);
928 return Status;
929 }
930
931 /* Complete the Connection */
932 if (!NT_SUCCESS(Status = NtCompleteConnectPort(hPort)))
933 {
934 DPRINT1("CSRSS: Sb Complete Connection failed %lx\n",Status);
935 }
936
937 /* Return status */
938 return Status;
939 }
940
941 /* PUBLIC FUNCTIONS **********************************************************/
942
943 /*++
944 * @name CsrCallServerFromServer
945 * @implemented NT4
946 *
947 * The CsrCallServerFromServer routine calls a CSR API from within a server.
948 * It avoids using LPC messages since the request isn't coming from a client.
949 *
950 * @param ReceiveMsg
951 * Pointer to the CSR API Message to send to the server.
952 *
953 * @param ReplyMsg
954 * Pointer to the CSR API Message to receive from the server.
955 *
956 * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
957 * if the opcode is invalid, or STATUS_ACCESS_VIOLATION if there
958 * was a problem executing the API.
959 *
960 * @remarks None.
961 *
962 *--*/
963 NTSTATUS
964 NTAPI
965 CsrCallServerFromServer(PCSR_API_MESSAGE ReceiveMsg,
966 PCSR_API_MESSAGE ReplyMsg)
967 {
968 ULONG ServerId;
969 PCSR_SERVER_DLL ServerDll;
970 ULONG ApiId;
971 ULONG Reply;
972 NTSTATUS Status;
973
974 /* Get the Server ID */
975 ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg->Opcode);
976
977 /* Make sure that the ID is within limits, and the Server DLL loaded */
978 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
979 (!(ServerDll = CsrLoadedServerDll[ServerId])))
980 {
981 /* We are beyond the Maximum Server ID */
982 ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
983 return STATUS_ILLEGAL_FUNCTION;
984 }
985 else
986 {
987 /* Get the API ID */
988 ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg->Opcode);
989
990 /* Normalize it with our Base ID */
991 ApiId -= ServerDll->ApiBase;
992
993 /* Make sure that the ID is within limits, and the entry exists */
994 if ((ApiId >= ServerDll->HighestApiSupported) ||
995 (ServerDll->ValidTable && !ServerDll->ValidTable[ApiId]))
996 {
997 /* We are beyond the Maximum API ID, or it doesn't exist */
998 ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
999 return STATUS_ILLEGAL_FUNCTION;
1000 }
1001 }
1002
1003 /* Validation complete, start SEH */
1004 _SEH_TRY
1005 {
1006 /* Call the API and get the result */
1007 Status = (ServerDll->DispatchTable[ApiId])(ReceiveMsg, &Reply);
1008
1009 /* Return the result, no matter what it is */
1010 ReplyMsg->Status = Status;
1011 }
1012 _SEH_HANDLE
1013 {
1014 /* If we got an exception, return access violation */
1015 ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
1016 }
1017 _SEH_END;
1018
1019 /* Return success */
1020 return STATUS_SUCCESS;
1021 }
1022
1023 /*++
1024 * @name CsrConnectToUser
1025 * @implemented NT4
1026 *
1027 * The CsrConnectToUser connects to the User subsystem.
1028 *
1029 * @param None
1030 *
1031 * @return A pointer to the CSR Thread
1032 *
1033 * @remarks None.
1034 *
1035 *--*/
1036 PCSR_THREAD
1037 NTAPI
1038 CsrConnectToUser(VOID)
1039 {
1040 NTSTATUS Status;
1041 ANSI_STRING DllName;
1042 UNICODE_STRING TempName;
1043 HANDLE hUser32;
1044 STRING StartupName;
1045 PTEB Teb = NtCurrentTeb();
1046 PCSR_THREAD CsrThread;
1047
1048 /* Check if we didn't already find it */
1049 if (!CsrClientThreadSetup)
1050 {
1051 /* Get the DLL Handle for user32.dll */
1052 RtlInitAnsiString(&DllName, "user32");
1053 RtlAnsiStringToUnicodeString(&TempName, &DllName, TRUE);
1054 Status = LdrGetDllHandle(NULL,
1055 NULL,
1056 &TempName,
1057 &hUser32);
1058 RtlFreeUnicodeString(&TempName);
1059
1060 /* If we got teh handle, get the Client Thread Startup Entrypoint */
1061 if (NT_SUCCESS(Status))
1062 {
1063 RtlInitAnsiString(&StartupName,"ClientThreadSetup");
1064 Status = LdrGetProcedureAddress(hUser32,
1065 &StartupName,
1066 0,
1067 (PVOID)&CsrClientThreadSetup);
1068 }
1069 }
1070
1071 /* Connect to user32 */
1072 CsrClientThreadSetup();
1073
1074 /* Save pointer to this thread in TEB */
1075 CsrThread = CsrLocateThreadInProcess(NULL, &Teb->Cid);
1076 if (CsrThread) Teb->CsrClientThread = CsrThread;
1077
1078 /* Return it */
1079 return CsrThread;
1080 }
1081
1082 /*++
1083 * @name CsrQueryApiPort
1084 * @implemented NT4
1085 *
1086 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1087 *
1088 * @param None.
1089 *
1090 * @return A handle to the port.
1091 *
1092 * @remarks None.
1093 *
1094 *--*/
1095 HANDLE
1096 NTAPI
1097 CsrQueryApiPort(VOID)
1098 {
1099 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
1100 return CsrApiPort;
1101 }
1102
1103 /*++
1104 * @name CsrCaptureArguments
1105 * @implemented NT5.1
1106 *
1107 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1108 * re-captures it into a server CSR Capture Buffer.
1109 *
1110 * @param CsrThread
1111 * Pointer to the CSR Thread performing the validation.
1112 *
1113 * @param ApiMessage
1114 * Pointer to the CSR API Message containing the Capture Buffer
1115 * that needs to be validated.
1116 *
1117 * @return TRUE if validation succeeded, FALSE otherwise.
1118 *
1119 * @remarks None.
1120 *
1121 *--*/
1122 BOOLEAN
1123 NTAPI
1124 CsrCaptureArguments(IN PCSR_THREAD CsrThread,
1125 IN PCSR_API_MESSAGE ApiMessage)
1126 {
1127 PCSR_CAPTURE_BUFFER LocalCaptureBuffer = NULL;
1128 ULONG LocalLength = 0;
1129 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer = NULL;
1130 SIZE_T BufferDistance = 0;
1131 ULONG PointerCount = 0;
1132 ULONG_PTR **PointerOffsets = NULL;
1133 ULONG_PTR *CurrentPointer = NULL;
1134
1135 /* Use SEH to make sure this is valid */
1136 _SEH_TRY
1137 {
1138 /* Get the buffer we got from whoever called NTDLL */
1139 LocalCaptureBuffer = ApiMessage->CsrCaptureData;
1140 LocalLength = LocalCaptureBuffer->Size;
1141
1142 /* Now check if the buffer is inside our mapped section */
1143 if (((ULONG_PTR)LocalCaptureBuffer < CsrThread->Process->ClientViewBase) ||
1144 (((ULONG_PTR)LocalCaptureBuffer + LocalLength) >= CsrThread->Process->ClientViewBounds))
1145 {
1146 /* Return failure */
1147 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1148 return FALSE;
1149 }
1150
1151 /* Check if the Length is valid */
1152 if (((LocalCaptureBuffer->PointerCount * 4 + sizeof(CSR_CAPTURE_BUFFER)) >
1153 LocalLength) ||(LocalLength > MAXWORD))
1154 {
1155 /* Return failure */
1156 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1157 return FALSE;
1158 }
1159 }
1160 _SEH_HANDLE
1161 {
1162 /* Return failure */
1163 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1164 return FALSE;
1165 } _SEH_END;
1166
1167 /* We validated the incoming buffer, now allocate the remote one */
1168 RemoteCaptureBuffer = RtlAllocateHeap(CsrHeap, 0, LocalLength);
1169 if (!RemoteCaptureBuffer)
1170 {
1171 /* We're out of memory */
1172 ApiMessage->Status = STATUS_NO_MEMORY;
1173 return FALSE;
1174 }
1175
1176 /* Copy the client's buffer */
1177 RtlMoveMemory(RemoteCaptureBuffer, LocalCaptureBuffer, LocalLength);
1178
1179 /* Copy the length */
1180 RemoteCaptureBuffer->Size = LocalLength;
1181
1182 /* Calculate the difference between our buffer and the client's */
1183 BufferDistance = (ULONG_PTR)RemoteCaptureBuffer - (ULONG_PTR)LocalCaptureBuffer;
1184
1185 /* Save the pointer count and offset pointer */
1186 PointerCount = RemoteCaptureBuffer->PointerCount;
1187 PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1);
1188
1189 /* Start the loop */
1190 while (PointerCount)
1191 {
1192 /* Get the current pointer */
1193 if ((CurrentPointer = *PointerOffsets++))
1194 {
1195 /* Add it to the CSR Message structure */
1196 CurrentPointer += (ULONG_PTR)ApiMessage;
1197
1198 /* Validate the bounds of the current pointer */
1199 if ((*CurrentPointer >= CsrThread->Process->ClientViewBase) &&
1200 (*CurrentPointer < CsrThread->Process->ClientViewBounds))
1201 {
1202 /* Modify the pointer to take into account its new position */
1203 *CurrentPointer += BufferDistance;
1204 }
1205 else
1206 {
1207 /* Invalid pointer, fail */
1208 ApiMessage->Status = (ULONG)STATUS_INVALID_PARAMETER;
1209 }
1210 }
1211
1212 /* Move to the next Pointer */
1213 PointerCount--;
1214 }
1215
1216 /* Check if we got success */
1217 if (ApiMessage->Status != STATUS_SUCCESS)
1218 {
1219 /* Failure. Free the buffer and return*/
1220 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1221 return FALSE;
1222 }
1223 else
1224 {
1225 /* Success, save the previous buffer */
1226 RemoteCaptureBuffer->PreviousCaptureBuffer = LocalCaptureBuffer;
1227 ApiMessage->CsrCaptureData = RemoteCaptureBuffer;
1228 }
1229
1230 /* Success */
1231 return TRUE;
1232 }
1233
1234 /*++
1235 * @name CsrReleaseCapturedArguments
1236 * @implemented NT5.1
1237 *
1238 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1239 * that was previously captured with CsrCaptureArguments.
1240 *
1241 * @param ApiMessage
1242 * Pointer to the CSR API Message containing the Capture Buffer
1243 * that needs to be released.
1244 *
1245 * @return None.
1246 *
1247 * @remarks None.
1248 *
1249 *--*/
1250 VOID
1251 NTAPI
1252 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
1253 {
1254 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer;
1255 PCSR_CAPTURE_BUFFER LocalCaptureBuffer;
1256 SIZE_T BufferDistance;
1257 ULONG PointerCount;
1258 ULONG_PTR **PointerOffsets;
1259 ULONG_PTR *CurrentPointer;
1260
1261 /* Get the capture buffers */
1262 RemoteCaptureBuffer = ApiMessage->CsrCaptureData;
1263 LocalCaptureBuffer = RemoteCaptureBuffer->PreviousCaptureBuffer;
1264
1265 /* Free the previous one */
1266 RemoteCaptureBuffer->PreviousCaptureBuffer = NULL;
1267
1268 /* Find out the difference between the two buffers */
1269 BufferDistance = (ULONG_PTR)LocalCaptureBuffer - (ULONG_PTR)RemoteCaptureBuffer;
1270
1271 /* Save the pointer count and offset pointer */
1272 PointerCount = RemoteCaptureBuffer->PointerCount;
1273 PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1);
1274
1275 /* Start the loop */
1276 while (PointerCount)
1277 {
1278 /* Get the current pointer */
1279 if ((CurrentPointer = *PointerOffsets++))
1280 {
1281 /* Add it to the CSR Message structure */
1282 CurrentPointer += (ULONG_PTR)ApiMessage;
1283
1284 /* Modify the pointer to take into account its new position */
1285 *CurrentPointer += BufferDistance;
1286 }
1287
1288 /* Move to the next Pointer */
1289 PointerCount--;
1290 }
1291
1292 /* Copy the data back */
1293 RtlMoveMemory(LocalCaptureBuffer,
1294 RemoteCaptureBuffer,
1295 RemoteCaptureBuffer->Size);
1296
1297 /* Free our allocated buffer */
1298 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1299 }
1300
1301 /*++
1302 * @name CsrValidateMessageBuffer
1303 * @implemented NT5.1
1304 *
1305 * The CsrValidateMessageBuffer routine validates a captured message buffer
1306 * present in the CSR Api Message
1307 *
1308 * @param ApiMessage
1309 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1310 *
1311 * @param Buffer
1312 * Pointer to the message buffer to validate.
1313 *
1314 * @param ArgumentSize
1315 * Size of the message to check.
1316 *
1317 * @param ArgumentCount
1318 * Number of messages to check.
1319 *
1320 * @return TRUE if validation suceeded, FALSE otherwise.
1321 *
1322 * @remarks None.
1323 *
1324 *--*/
1325 BOOLEAN
1326 NTAPI
1327 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage,
1328 IN PVOID *Buffer,
1329 IN ULONG ArgumentSize,
1330 IN ULONG ArgumentCount)
1331 {
1332 PCSR_CAPTURE_BUFFER CaptureBuffer = ApiMessage->CsrCaptureData;
1333 SIZE_T BufferDistance;
1334 ULONG PointerCount;
1335 ULONG_PTR **PointerOffsets;
1336 ULONG_PTR *CurrentPointer;
1337 ULONG i;
1338
1339 /* Make sure there are some arguments */
1340 if (!ArgumentCount) return FALSE;
1341
1342 /* Check if didn't get a buffer and there aren't any arguments to check */
1343 if (!(*Buffer) && (!(ArgumentCount * ArgumentSize))) return TRUE;
1344
1345 /* Check if we have no capture buffer */
1346 if (!CaptureBuffer)
1347 {
1348 /* In this case, check only the Process ID */
1349 if (NtCurrentTeb()->Cid.UniqueProcess ==
1350 ApiMessage->Header.ClientId.UniqueProcess)
1351 {
1352 /* There is a match, validation succeeded */
1353 return TRUE;
1354 }
1355 }
1356 else
1357 {
1358 /* Make sure that there is still space left in the buffer */
1359 if ((CaptureBuffer->Size - (ULONG_PTR)*Buffer + (ULONG_PTR)CaptureBuffer) <
1360 (ArgumentCount * ArgumentSize))
1361 {
1362 /* Find out the difference between the two buffers */
1363 BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage;
1364
1365 /* Save the pointer count */
1366 PointerCount = CaptureBuffer->PointerCount;
1367 PointerOffsets = (ULONG_PTR**)(CaptureBuffer + 1);
1368
1369 /* Start the loop */
1370 for (i = 0; i < PointerCount; i++)
1371 {
1372 /* Get the current pointer */
1373 CurrentPointer = *PointerOffsets++;
1374
1375 /* Check if its' equal to the difference */
1376 if (*CurrentPointer == BufferDistance) return TRUE;
1377 }
1378 }
1379 }
1380
1381 /* Failure */
1382 return FALSE;
1383 }
1384
1385 /*++
1386 * @name CsrValidateMessageString
1387 * @implemented NT5.1
1388 *
1389 * The CsrValidateMessageString validates a captured Wide-Character String
1390 * present in a CSR API Message.
1391 *
1392 * @param ApiMessage
1393 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1394 *
1395 * @param MessageString
1396 * Pointer to the buffer containing the string to validate.
1397 *
1398 * @return TRUE if validation suceeded, FALSE otherwise.
1399 *
1400 * @remarks None.
1401 *
1402 *--*/
1403 BOOLEAN
1404 NTAPI
1405 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage,
1406 IN LPWSTR *MessageString)
1407 {
1408 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
1409 return FALSE;
1410 }
1411
1412 /* EOF */