[REACTOS]
[reactos.git] / reactos / deprecated / 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 volatile LONG CsrpStaticThreadCount;
25 volatile LONG CsrpDynamicThreadTotal;
26
27 /* PRIVATE FUNCTIONS *********************************************************/
28
29 /*++
30 * @name CsrpCheckRequestThreads
31 *
32 * The CsrpCheckRequestThreads 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 CsrpCheckRequestThreads(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 _InterlockedIncrement(&CsrpStaticThreadCount);
74 _InterlockedIncrement(&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 _InterlockedDecrement(&CsrpStaticThreadCount);
88 _InterlockedDecrement(&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 /* Create the buffer for it */
135 CsrSbApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
136 if (!CsrSbApiPortName.Buffer) return STATUS_NO_MEMORY;
137
138 /* Setup the rest of the empty string */
139 CsrSbApiPortName.Length = 0;
140 CsrSbApiPortName.MaximumLength = (USHORT)Size;
141
142 /* Now append the full port name */
143 RtlAppendUnicodeStringToString(&CsrSbApiPortName, &CsrDirectoryName);
144 RtlAppendUnicodeToString(&CsrSbApiPortName, UNICODE_PATH_SEP);
145 RtlAppendUnicodeToString(&CsrSbApiPortName, SB_PORT_NAME);
146 if (CsrDebug & 2) DPRINT1("CSRSS: Creating %wZ port and associated thread\n", &CsrSbApiPortName);
147
148 /* Create Security Descriptor for this Port */
149 Status = CsrCreateLocalSystemSD(&PortSd);
150 if (!NT_SUCCESS(Status)) return Status;
151
152 /* Initialize the Attributes */
153 InitializeObjectAttributes(&ObjectAttributes,
154 &CsrSbApiPortName,
155 0,
156 NULL,
157 PortSd);
158
159 /* Create the Port Object */
160 Status = NtCreatePort(&CsrSbApiPort,
161 &ObjectAttributes,
162 sizeof(SB_CONNECTION_INFO),
163 sizeof(SB_API_MSG),
164 32 * sizeof(SB_API_MSG));
165 if (PortSd) RtlFreeHeap(CsrHeap, 0, PortSd);
166
167 if (NT_SUCCESS(Status))
168 {
169 /* Create the Thread to handle the API Requests */
170 Status = RtlCreateUserThread(NtCurrentProcess(),
171 NULL,
172 TRUE,
173 0,
174 0,
175 0,
176 (PVOID)CsrSbApiRequestThread,
177 NULL,
178 &hRequestThread,
179 &ClientId);
180 if (NT_SUCCESS(Status))
181 {
182 /* Add it as a Static Server Thread */
183 CsrSbApiRequestThreadPtr = CsrAddStaticServerThread(hRequestThread,
184 &ClientId,
185 0);
186
187 /* Activate it */
188 Status = NtResumeThread(hRequestThread, NULL);
189 }
190 }
191
192 return Status;
193 }
194
195 /*++
196 * @name CsrApiPortInitialize
197 *
198 * The CsrApiPortInitialize routine initializes the LPC Port used for
199 * communications with the Client/Server Runtime (CSR) and initializes the
200 * static thread that will handle connection requests and APIs.
201 *
202 * @param None
203 *
204 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
205 * othwerwise.
206 *
207 * @remarks None.
208 *
209 *--*/
210 NTSTATUS
211 NTAPI
212 CsrApiPortInitialize(VOID)
213 {
214 ULONG Size;
215 OBJECT_ATTRIBUTES ObjectAttributes;
216 NTSTATUS Status;
217 HANDLE hRequestEvent, hThread;
218 CLIENT_ID ClientId;
219 PLIST_ENTRY ListHead, NextEntry;
220 PCSR_THREAD ServerThread;
221
222 /* Calculate how much space we'll need for the Port Name */
223 Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR);
224
225 /* Create the buffer for it */
226 CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
227 if (!CsrApiPortName.Buffer) return STATUS_NO_MEMORY;
228
229 /* Setup the rest of the empty string */
230 CsrApiPortName.Length = 0;
231 CsrApiPortName.MaximumLength = (USHORT)Size;
232 RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
233 RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
234 RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);
235 if (CsrDebug & 1)
236 {
237 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName);
238 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
239 sizeof(CSR_CONNECTION_INFO), sizeof(CSR_API_MESSAGE));
240 }
241
242 /* FIXME: Create a Security Descriptor */
243
244 /* Initialize the Attributes */
245 InitializeObjectAttributes(&ObjectAttributes,
246 &CsrApiPortName,
247 0,
248 NULL,
249 NULL /* FIXME*/);
250
251 /* Create the Port Object */
252 Status = NtCreatePort(&CsrApiPort,
253 &ObjectAttributes,
254 sizeof(CSR_CONNECTION_INFO),
255 sizeof(CSR_API_MESSAGE),
256 16 * PAGE_SIZE);
257 if (NT_SUCCESS(Status))
258 {
259 /* Create the event the Port Thread will use */
260 Status = NtCreateEvent(&hRequestEvent,
261 EVENT_ALL_ACCESS,
262 NULL,
263 SynchronizationEvent,
264 FALSE);
265 if (NT_SUCCESS(Status))
266 {
267 /* Create the Request Thread */
268 Status = RtlCreateUserThread(NtCurrentProcess(),
269 NULL,
270 TRUE,
271 0,
272 0,
273 0,
274 (PVOID)CsrApiRequestThread,
275 (PVOID)hRequestEvent,
276 &hThread,
277 &ClientId);
278 if (NT_SUCCESS(Status))
279 {
280 /* Add this as a static thread to CSRSRV */
281 CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread);
282
283 /* Get the Thread List Pointers */
284 ListHead = &CsrRootProcess->ThreadList;
285 NextEntry = ListHead->Flink;
286
287 /* Start looping the list */
288 while (NextEntry != ListHead)
289 {
290 /* Get the Thread */
291 ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
292
293 /* Start it up */
294 Status = NtResumeThread(ServerThread->ThreadHandle, NULL);
295
296 /* Is this a Server Thread? */
297 if (ServerThread->Flags & CsrThreadIsServerThread)
298 {
299 /* If so, then wait for it to initialize */
300 Status = NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
301 ASSERT(NT_SUCCESS(Status));
302 }
303
304 /* Next thread */
305 NextEntry = NextEntry->Flink;
306 }
307
308 /* We don't need this anymore */
309 NtClose(hRequestEvent);
310 }
311 }
312 }
313
314 /* Return */
315 return Status;
316 }
317
318 /*++
319 * @name CsrApiRequestThread
320 *
321 * The CsrApiRequestThread routine handles incoming messages or connection
322 * requests on the CSR API LPC Port.
323 *
324 * @param Parameter
325 * System-default user-defined parameter. Unused.
326 *
327 * @return The thread exit code, if the thread is terminated.
328 *
329 * @remarks Before listening on the port, the routine will first attempt
330 * to connect to the user subsystem.
331 *
332 *--*/
333 NTSTATUS
334 NTAPI
335 CsrApiRequestThread(IN PVOID Parameter)
336 {
337 PTEB Teb = NtCurrentTeb();
338 LARGE_INTEGER TimeOut;
339 PCSR_THREAD CurrentThread, CsrThread;
340 NTSTATUS Status;
341 PCSR_API_MESSAGE ReplyMsg;
342 CSR_API_MESSAGE ReceiveMsg;
343 PCSR_PROCESS CsrProcess;
344 PHARDERROR_MSG HardErrorMsg;
345 PVOID PortContext;
346 PCSR_SERVER_DLL ServerDll;
347 PCLIENT_DIED_MSG ClientDiedMsg;
348 PDBGKM_MSG DebugMessage;
349 ULONG ServerId, ApiId, Reply, MessageType, i;
350 HANDLE ReplyPort;
351
352 /* Setup LPC loop port and message */
353 ReplyMsg = NULL;
354 ReplyPort = CsrApiPort;
355
356 /* Connect to user32 */
357 while (!CsrConnectToUser())
358 {
359 /* Set up the timeout for the connect (30 seconds) */
360 TimeOut.QuadPart = -30 * 1000 * 1000 * 10;
361
362 /* Keep trying until we get a response */
363 Teb->Win32ClientInfo[0] = 0;
364 NtDelayExecution(FALSE, &TimeOut);
365 }
366
367 /* Get our thread */
368 CurrentThread = Teb->CsrClientThread;
369
370 /* If we got an event... */
371 if (Parameter)
372 {
373 /* Set it, to let stuff waiting on us load */
374 Status = NtSetEvent((HANDLE)Parameter, NULL);
375 ASSERT(NT_SUCCESS(Status));
376
377 /* Increase the Thread Counts */
378 _InterlockedIncrement(&CsrpStaticThreadCount);
379 _InterlockedIncrement(&CsrpDynamicThreadTotal);
380 }
381
382 /* Now start the loop */
383 while (TRUE)
384 {
385 /* Make sure the real CID is set */
386 Teb->RealClientId = Teb->ClientId;
387
388 /* Debug check */
389 if (Teb->CountOfOwnedCriticalSections)
390 {
391 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
392 Teb->CountOfOwnedCriticalSections);
393 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
394 &ReceiveMsg, ReplyMsg);
395 DbgBreakPoint();
396 }
397
398 /* Wait for a message to come through */
399 Status = NtReplyWaitReceivePort(ReplyPort,
400 &PortContext,
401 &ReplyMsg->Header,
402 &ReceiveMsg.Header);
403
404 /* Check if we didn't get success */
405 if (Status != STATUS_SUCCESS)
406 {
407 /* Was it a failure or another success code? */
408 if (!NT_SUCCESS(Status))
409 {
410 /* Check for specific status cases */
411 if ((Status != STATUS_INVALID_CID) &&
412 (Status != STATUS_UNSUCCESSFUL) &&
413 ((Status == STATUS_INVALID_HANDLE) || (ReplyPort == CsrApiPort)))
414 {
415 /* Notify the debugger */
416 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
417 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort, CsrApiPort);
418 }
419
420 /* We failed big time, so start out fresh */
421 ReplyMsg = NULL;
422 ReplyPort = CsrApiPort;
423 continue;
424 }
425 else
426 {
427 /* A bizare "success" code, just try again */
428 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status);
429 continue;
430 }
431 }
432
433 /* Use whatever Client ID we got */
434 Teb->RealClientId = ReceiveMsg.Header.ClientId;
435
436 /* Get the Message Type */
437 MessageType = ReceiveMsg.Header.u2.s2.Type;
438
439 /* Handle connection requests */
440 if (MessageType == LPC_CONNECTION_REQUEST)
441 {
442 /* Handle the Connection Request */
443 CsrApiHandleConnectionRequest(&ReceiveMsg);
444 ReplyPort = CsrApiPort;
445 ReplyMsg = NULL;
446 continue;
447 }
448
449 /* It's some other kind of request. Get the lock for the lookup */
450 CsrAcquireProcessLock();
451
452 /* Now do the lookup to get the CSR_THREAD */
453 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
454 &ReceiveMsg.Header.ClientId);
455
456 /* Did we find a thread? */
457 if (!CsrThread)
458 {
459 /* This wasn't a CSR Thread, release lock */
460 CsrReleaseProcessLock();
461
462 /* If this was an exception, handle it */
463 if (MessageType == LPC_EXCEPTION)
464 {
465 ReplyMsg = &ReceiveMsg;
466 ReplyPort = CsrApiPort;
467 ReplyMsg->Status = DBG_CONTINUE;
468 }
469 else if (MessageType == LPC_PORT_CLOSED ||
470 MessageType == LPC_CLIENT_DIED)
471 {
472 /* The Client or Port are gone, loop again */
473 ReplyMsg = NULL;
474 ReplyPort = CsrApiPort;
475 }
476 else if (MessageType == LPC_ERROR_EVENT)
477 {
478 /* If it's a hard error, handle this too */
479 HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
480
481 /* Default it to unhandled */
482 HardErrorMsg->Response = ResponseNotHandled;
483
484 /* Check if there are free api threads */
485 CsrpCheckRequestThreads();
486 if (CsrpStaticThreadCount)
487 {
488 /* Loop every Server DLL */
489 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
490 {
491 /* Get the Server DLL */
492 ServerDll = CsrLoadedServerDll[i];
493
494 /* Check if it's valid and if it has a Hard Error Callback */
495 if ((ServerDll) && (ServerDll->HardErrorCallback))
496 {
497 /* Call it */
498 ServerDll->HardErrorCallback(NULL, HardErrorMsg);
499
500 /* If it's handled, get out of here */
501 if (HardErrorMsg->Response != ResponseNotHandled) break;
502 }
503 }
504 }
505
506 /* Increase the thread count */
507 _InterlockedIncrement(&CsrpStaticThreadCount);
508
509 /* If the response was 0xFFFFFFFF, we'll ignore it */
510 if (HardErrorMsg->Response == 0xFFFFFFFF)
511 {
512 ReplyMsg = NULL;
513 ReplyPort = CsrApiPort;
514 }
515 else
516 {
517 ReplyMsg = &ReceiveMsg;
518 }
519 }
520 else if (MessageType == LPC_REQUEST)
521 {
522 /* This is an API Message coming from a non-CSR Thread */
523 ReplyMsg = &ReceiveMsg;
524 ReplyPort = CsrApiPort;
525 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
526 }
527 else if (MessageType == LPC_DATAGRAM)
528 {
529 /* This is an API call, get the Server ID */
530 ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg.Opcode);
531
532 /* Make sure that the ID is within limits, and the Server DLL loaded */
533 ServerDll = NULL;
534 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
535 (!(ServerDll = CsrLoadedServerDll[ServerId])))
536 {
537 /* We are beyond the Maximum Server ID */
538 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
539 ServerId, ServerDll);
540 DbgBreakPoint();
541 ReplyPort = CsrApiPort;
542 ReplyMsg = NULL;
543 continue;
544 }
545
546 /* Get the API ID */
547 ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode);
548
549 /* Normalize it with our Base ID */
550 ApiId -= ServerDll->ApiBase;
551
552 /* Make sure that the ID is within limits, and the entry exists */
553 if (ApiId >= ServerDll->HighestApiSupported)
554 {
555 /* We are beyond the Maximum API ID, or it doesn't exist */
556 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
557 CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode),
558 &ServerDll->Name);
559 ReplyPort = CsrApiPort;
560 ReplyMsg = NULL;
561 continue;
562 }
563
564 if (CsrDebug & 2)
565 {
566 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
567 Teb->ClientId.UniqueThread,
568 ReceiveMsg.Header.ClientId.UniqueProcess,
569 ReceiveMsg.Header.ClientId.UniqueThread,
570 ServerDll->NameTable[ApiId],
571 NULL);
572 }
573
574 /* Assume success */
575 ReceiveMsg.Status = STATUS_SUCCESS;
576
577 /* Validation complete, start SEH */
578 _SEH2_TRY
579 {
580 /* Make sure we have enough threads */
581 CsrpCheckRequestThreads();
582
583 /* Call the API and get the result */
584 ReplyMsg = NULL;
585 ReplyPort = CsrApiPort;
586 ServerDll->DispatchTable[ApiId](&ReceiveMsg, &Reply);
587
588 /* Increase the static thread count */
589 _InterlockedIncrement(&CsrpStaticThreadCount);
590 }
591 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
592 {
593 ReplyMsg = NULL;
594 ReplyPort = CsrApiPort;
595 }
596 _SEH2_END;
597 }
598 else
599 {
600 /* Some other ignored message type */
601 ReplyMsg = NULL;
602 ReplyPort = CsrApiPort;
603 }
604
605 /* Keep going */
606 continue;
607 }
608
609 /* We have a valid thread, was this an LPC Request? */
610 if (MessageType != LPC_REQUEST)
611 {
612 /* It's not an API, check if the client died */
613 if (MessageType == LPC_CLIENT_DIED)
614 {
615 /* Get the information and check if it matches our thread */
616 ClientDiedMsg = (PCLIENT_DIED_MSG)&ReceiveMsg;
617 if (ClientDiedMsg->CreateTime.QuadPart == CsrThread->CreateTime.QuadPart)
618 {
619 /* Reference the thread */
620 CsrLockedReferenceThread(CsrThread);
621
622 /* Destroy the thread in the API Message */
623 CsrDestroyThread(&ReceiveMsg.Header.ClientId);
624
625 /* Check if the thread was actually ourselves */
626 if (CsrProcess->ThreadCount == 1)
627 {
628 /* Kill the process manually here */
629 CsrDestroyProcess(&CsrThread->ClientId, 0);
630 }
631
632 /* Remove our extra reference */
633 CsrLockedDereferenceThread(CsrThread);
634 }
635
636 /* Release the lock and keep looping */
637 CsrReleaseProcessLock();
638 ReplyMsg = NULL;
639 ReplyPort = CsrApiPort;
640 continue;
641 }
642
643 /* Reference the thread and release the lock */
644 CsrLockedReferenceThread(CsrThread);
645 CsrReleaseProcessLock();
646
647 /* Check if this was an exception */
648 if (MessageType == LPC_EXCEPTION)
649 {
650 /* Kill the process */
651 NtTerminateProcess(CsrProcess->ProcessHandle, STATUS_ABANDONED);
652
653 /* Destroy it from CSR */
654 CsrDestroyProcess(&ReceiveMsg.Header.ClientId, STATUS_ABANDONED);
655
656 /* Return a Debug Message */
657 DebugMessage = (PDBGKM_MSG)&ReceiveMsg;
658 DebugMessage->ReturnedStatus = DBG_CONTINUE;
659 ReplyMsg = &ReceiveMsg;
660 ReplyPort = CsrApiPort;
661
662 /* Remove our extra reference */
663 CsrDereferenceThread(CsrThread);
664 }
665 else if (MessageType == LPC_ERROR_EVENT)
666 {
667 /* If it's a hard error, handle this too */
668 HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
669
670 /* Default it to unhandled */
671 HardErrorMsg->Response = ResponseNotHandled;
672
673 /* Check if there are free api threads */
674 CsrpCheckRequestThreads();
675 if (CsrpStaticThreadCount)
676 {
677 /* Loop every Server DLL */
678 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
679 {
680 /* Get the Server DLL */
681 ServerDll = CsrLoadedServerDll[i];
682
683 /* Check if it's valid and if it has a Hard Error Callback */
684 if ((ServerDll) && (ServerDll->HardErrorCallback))
685 {
686 /* Call it */
687 ServerDll->HardErrorCallback(CsrThread, HardErrorMsg);
688
689 /* If it's handled, get out of here */
690 if (HardErrorMsg->Response != ResponseNotHandled) break;
691 }
692 }
693 }
694
695 /* Increase the thread count */
696 _InterlockedIncrement(&CsrpStaticThreadCount);
697
698 /* If the response was 0xFFFFFFFF, we'll ignore it */
699 if (HardErrorMsg->Response == 0xFFFFFFFF)
700 {
701 ReplyMsg = NULL;
702 ReplyPort = CsrApiPort;
703 }
704 else
705 {
706 CsrDereferenceThread(CsrThread);
707 ReplyMsg = &ReceiveMsg;
708 ReplyPort = CsrApiPort;
709 }
710 }
711 else
712 {
713 /* Something else */
714 CsrDereferenceThread(CsrThread);
715 ReplyMsg = NULL;
716 }
717
718 /* Keep looping */
719 continue;
720 }
721
722 /* We got an API Request */
723 CsrLockedReferenceThread(CsrThread);
724 CsrReleaseProcessLock();
725
726 /* This is an API call, get the Server ID */
727 ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg.Opcode);
728
729 /* Make sure that the ID is within limits, and the Server DLL loaded */
730 ServerDll = NULL;
731 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
732 (!(ServerDll = CsrLoadedServerDll[ServerId])))
733 {
734 /* We are beyond the Maximum Server ID */
735 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
736 ServerId, ServerDll);
737 DbgBreakPoint();
738
739 ReplyPort = CsrApiPort;
740 ReplyMsg = &ReceiveMsg;
741 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
742 CsrDereferenceThread(CsrThread);
743 continue;
744 }
745
746 /* Get the API ID */
747 ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode);
748
749 /* Normalize it with our Base ID */
750 ApiId -= ServerDll->ApiBase;
751
752 /* Make sure that the ID is within limits, and the entry exists */
753 if (ApiId >= ServerDll->HighestApiSupported)
754 {
755 /* We are beyond the Maximum API ID, or it doesn't exist */
756 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
757 CSR_API_ID_FROM_OPCODE(ReceiveMsg.Opcode),
758 &ServerDll->Name);
759
760 ReplyPort = CsrApiPort;
761 ReplyMsg = &ReceiveMsg;
762 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
763 CsrDereferenceThread(CsrThread);
764 continue;
765 }
766
767 if (CsrDebug & 2)
768 {
769 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
770 Teb->ClientId.UniqueThread,
771 ReceiveMsg.Header.ClientId.UniqueProcess,
772 ReceiveMsg.Header.ClientId.UniqueThread,
773 ServerDll->NameTable[ApiId],
774 CsrThread);
775 }
776
777 /* Assume success */
778 ReplyMsg = &ReceiveMsg;
779 ReceiveMsg.Status = STATUS_SUCCESS;
780
781 /* Now we reply to a particular client */
782 ReplyPort = CsrThread->Process->ClientPort;
783
784 /* Check if there's a capture buffer */
785 if (ReceiveMsg.CsrCaptureData)
786 {
787 /* Capture the arguments */
788 if (!CsrCaptureArguments(CsrThread, &ReceiveMsg))
789 {
790 /* Ignore this message if we failed to get the arguments */
791 CsrDereferenceThread(CsrThread);
792 continue;
793 }
794 }
795
796 /* Validation complete, start SEH */
797 _SEH2_TRY
798 {
799 /* Make sure we have enough threads */
800 CsrpCheckRequestThreads();
801
802 Teb->CsrClientThread = CsrThread;
803
804 /* Call the API and get the result */
805 Reply = 0;
806 ServerDll->DispatchTable[ApiId](&ReceiveMsg, &Reply);
807
808 /* Increase the static thread count */
809 _InterlockedIncrement(&CsrpStaticThreadCount);
810
811 Teb->CsrClientThread = CurrentThread;
812
813 if (Reply == 3)
814 {
815 ReplyMsg = NULL;
816 if (ReceiveMsg.CsrCaptureData)
817 {
818 CsrReleaseCapturedArguments(&ReceiveMsg);
819 }
820 CsrDereferenceThread(CsrThread);
821 ReplyPort = CsrApiPort;
822 }
823 else if (Reply == 2)
824 {
825 NtReplyPort(ReplyPort, &ReplyMsg->Header);
826 ReplyPort = CsrApiPort;
827 ReplyMsg = NULL;
828 CsrDereferenceThread(CsrThread);
829 }
830 else if (Reply == 1)
831 {
832 ReplyPort = CsrApiPort;
833 ReplyMsg = NULL;
834 }
835 else
836 {
837 if (ReceiveMsg.CsrCaptureData)
838 {
839 CsrReleaseCapturedArguments(&ReceiveMsg);
840 }
841 CsrDereferenceThread(CsrThread);
842 }
843 }
844 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
845 {
846 ReplyMsg = NULL;
847 ReplyPort = CsrApiPort;
848 }
849 _SEH2_END;
850 }
851
852 /* We're out of the loop for some reason, terminate! */
853 NtTerminateThread(NtCurrentThread(), Status);
854 return Status;
855 }
856
857 /*++
858 * @name CsrApiHandleConnectionRequest
859 *
860 * The CsrApiHandleConnectionRequest routine handles and accepts a new
861 * connection request to the CSR API LPC Port.
862 *
863 * @param ApiMessage
864 * Pointer to the incoming CSR API Message which contains the
865 * connection request.
866 *
867 * @return STATUS_SUCCESS in case of success, or status code which caused
868 * the routine to error.
869 *
870 * @remarks This routine is responsible for attaching the Shared Section to
871 * new clients connecting to CSR.
872 *
873 *--*/
874 NTSTATUS
875 NTAPI
876 CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage)
877 {
878 PCSR_THREAD CsrThread = NULL;
879 PCSR_PROCESS CsrProcess = NULL;
880 NTSTATUS Status = STATUS_SUCCESS;
881 PCSR_CONNECTION_INFO ConnectInfo = &ApiMessage->ConnectionInfo;
882 BOOLEAN AllowConnection = FALSE;
883 REMOTE_PORT_VIEW RemotePortView;
884 HANDLE hPort;
885
886 /* Acquire the Process Lock */
887 CsrAcquireProcessLock();
888
889 /* Lookup the CSR Thread */
890 CsrThread = CsrLocateThreadByClientId(NULL, &ApiMessage->Header.ClientId);
891
892 /* Check if we have a thread */
893 if (CsrThread)
894 {
895 /* Get the Process */
896 CsrProcess = CsrThread->Process;
897
898 /* Make sure we have a Process as well */
899 if (CsrProcess)
900 {
901 /* Reference the Process */
902 CsrLockedReferenceProcess(CsrThread->Process);
903
904 /* Release the lock */
905 CsrReleaseProcessLock();
906
907 /* Duplicate the Object Directory */
908 Status = NtDuplicateObject(NtCurrentProcess(),
909 CsrObjectDirectory,
910 CsrProcess->ProcessHandle,
911 &ConnectInfo->ObjectDirectory,
912 0,
913 0,
914 DUPLICATE_SAME_ACCESS |
915 DUPLICATE_SAME_ATTRIBUTES);
916
917 /* Acquire the lock */
918 CsrAcquireProcessLock();
919
920 /* Check for success */
921 if (NT_SUCCESS(Status))
922 {
923 /* Attach the Shared Section */
924 Status = CsrSrvAttachSharedSection(CsrProcess, ConnectInfo);
925
926 /* Check how this went */
927 if (NT_SUCCESS(Status)) AllowConnection = TRUE;
928 }
929
930 /* Dereference the project */
931 CsrLockedDereferenceProcess(CsrProcess);
932 }
933 }
934
935 /* Release the lock */
936 CsrReleaseProcessLock();
937
938 /* Setup the Port View Structure */
939 RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
940 RemotePortView.ViewSize = 0;
941 RemotePortView.ViewBase = NULL;
942
943 /* Save the Process ID */
944 ConnectInfo->ProcessId = NtCurrentTeb()->ClientId.UniqueProcess;
945
946 /* Accept the Connection */
947 Status = NtAcceptConnectPort(&hPort,
948 AllowConnection ? UlongToPtr(CsrProcess->SequenceNumber) : 0,
949 &ApiMessage->Header,
950 AllowConnection,
951 NULL,
952 &RemotePortView);
953 if (!NT_SUCCESS(Status))
954 {
955 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status);
956 }
957 else if (AllowConnection)
958 {
959 if (CsrDebug & 2)
960 {
961 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
962 ApiMessage->Header.ClientId.UniqueProcess,
963 ApiMessage->Header.ClientId.UniqueThread,
964 RemotePortView.ViewBase,
965 RemotePortView.ViewSize);
966 }
967
968 /* Set some Port Data in the Process */
969 CsrProcess->ClientPort = hPort;
970 CsrProcess->ClientViewBase = (ULONG_PTR)RemotePortView.ViewBase;
971 CsrProcess->ClientViewBounds = (ULONG_PTR)((ULONG_PTR)RemotePortView.ViewBase +
972 (ULONG_PTR)RemotePortView.ViewSize);
973
974 /* Complete the connection */
975 Status = NtCompleteConnectPort(hPort);
976 if (!NT_SUCCESS(Status))
977 {
978 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status);
979 }
980 }
981 else
982 {
983 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
984 ApiMessage->Header.ClientId.UniqueProcess,
985 ApiMessage->Header.ClientId.UniqueThread);
986 }
987
988 /* Return status to caller */
989 return Status;
990 }
991
992 /*++
993 * @name CsrSbApiRequestThread
994 *
995 * The CsrSbApiRequestThread routine handles incoming messages or connection
996 * requests on the SM API LPC Port.
997 *
998 * @param Parameter
999 * System-default user-defined parameter. Unused.
1000 *
1001 * @return The thread exit code, if the thread is terminated.
1002 *
1003 * @remarks Before listening on the port, the routine will first attempt
1004 * to connect to the user subsystem.
1005 *
1006 *--*/
1007 VOID
1008 NTAPI
1009 CsrSbApiRequestThread(IN PVOID Parameter)
1010 {
1011 NTSTATUS Status;
1012 SB_API_MSG ReceiveMsg;
1013 PSB_API_MSG ReplyMsg = NULL;
1014 PVOID PortContext;
1015 ULONG MessageType;
1016
1017 /* Start the loop */
1018 while (TRUE)
1019 {
1020 /* Wait for a message to come in */
1021 Status = NtReplyWaitReceivePort(CsrSbApiPort,
1022 &PortContext,
1023 &ReplyMsg->h,
1024 &ReceiveMsg.h);
1025
1026 /* Check if we didn't get success */
1027 if (Status != STATUS_SUCCESS)
1028 {
1029 /* If we only got a warning, keep going */
1030 if (NT_SUCCESS(Status)) continue;
1031
1032 /* We failed big time, so start out fresh */
1033 ReplyMsg = NULL;
1034 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
1035 continue;
1036 }
1037
1038 /* Save the message type */
1039 MessageType = ReceiveMsg.h.u2.s2.Type;
1040
1041 /* Check if this is a connection request */
1042 if (MessageType == LPC_CONNECTION_REQUEST)
1043 {
1044 /* Handle connection request */
1045 CsrSbApiHandleConnectionRequest(&ReceiveMsg);
1046
1047 /* Start over */
1048 ReplyMsg = NULL;
1049 continue;
1050 }
1051
1052 /* Check if the port died */
1053 if (MessageType == LPC_PORT_CLOSED)
1054 {
1055 /* Close the handle if we have one */
1056 if (PortContext) NtClose((HANDLE)PortContext);
1057
1058 /* Client died, start over */
1059 ReplyMsg = NULL;
1060 continue;
1061 }
1062 else if (MessageType == LPC_CLIENT_DIED)
1063 {
1064 /* Client died, start over */
1065 ReplyMsg = NULL;
1066 continue;
1067 }
1068
1069 /*
1070 * It's an API Message, check if it's within limits. If it's not, the
1071 * NT Behaviour is to set this to the Maximum API.
1072 */
1073 if (ReceiveMsg.ApiNumber > SbpMaxApiNumber)
1074 {
1075 ReceiveMsg.ApiNumber = SbpMaxApiNumber;
1076 DPRINT1("CSRSS: %lx is invalid Sb ApiNumber\n", ReceiveMsg.ApiNumber);
1077 }
1078
1079 /* Reuse the message */
1080 ReplyMsg = &ReceiveMsg;
1081
1082 /* Make sure that the message is supported */
1083 if (ReceiveMsg.ApiNumber < SbpMaxApiNumber)
1084 {
1085 /* Call the API */
1086 if (!CsrServerSbApiDispatch[ReceiveMsg.ApiNumber](&ReceiveMsg))
1087 {
1088 /* It failed, so return nothing */
1089 ReplyMsg = NULL;
1090 }
1091 }
1092 else
1093 {
1094 /* We don't support this API Number */
1095 ReplyMsg->ReturnValue = STATUS_NOT_IMPLEMENTED;
1096 }
1097 }
1098 }
1099
1100 /*++
1101 * @name CsrSbApiHandleConnectionRequest
1102 *
1103 * The CsrSbApiHandleConnectionRequest routine handles and accepts a new
1104 * connection request to the SM API LPC Port.
1105 *
1106 * @param ApiMessage
1107 * Pointer to the incoming CSR API Message which contains the
1108 * connection request.
1109 *
1110 * @return STATUS_SUCCESS in case of success, or status code which caused
1111 * the routine to error.
1112 *
1113 * @remarks None.
1114 *
1115 *--*/
1116 NTSTATUS
1117 NTAPI
1118 CsrSbApiHandleConnectionRequest(IN PSB_API_MSG Message)
1119 {
1120 NTSTATUS Status;
1121 REMOTE_PORT_VIEW RemotePortView;
1122 HANDLE hPort;
1123
1124 /* Set the Port View Structure Length */
1125 RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
1126
1127 /* Accept the connection */
1128 Status = NtAcceptConnectPort(&hPort,
1129 NULL,
1130 (PPORT_MESSAGE)Message,
1131 TRUE,
1132 NULL,
1133 &RemotePortView);
1134 if (!NT_SUCCESS(Status))
1135 {
1136 DPRINT1("CSRSS: Sb Accept Connection failed %lx\n", Status);
1137 return Status;
1138 }
1139
1140 /* Complete the Connection */
1141 Status = NtCompleteConnectPort(hPort);
1142 if (!NT_SUCCESS(Status))
1143 {
1144 DPRINT1("CSRSS: Sb Complete Connection failed %lx\n",Status);
1145 }
1146
1147 /* Return status */
1148 return Status;
1149 }
1150
1151 /* PUBLIC FUNCTIONS **********************************************************/
1152
1153 /*++
1154 * @name CsrCallServerFromServer
1155 * @implemented NT4
1156 *
1157 * The CsrCallServerFromServer routine calls a CSR API from within a server.
1158 * It avoids using LPC messages since the request isn't coming from a client.
1159 *
1160 * @param ReceiveMsg
1161 * Pointer to the CSR API Message to send to the server.
1162 *
1163 * @param ReplyMsg
1164 * Pointer to the CSR API Message to receive from the server.
1165 *
1166 * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
1167 * if the opcode is invalid, or STATUS_ACCESS_VIOLATION if there
1168 * was a problem executing the API.
1169 *
1170 * @remarks None.
1171 *
1172 *--*/
1173 NTSTATUS
1174 NTAPI
1175 CsrCallServerFromServer(PCSR_API_MESSAGE ReceiveMsg,
1176 PCSR_API_MESSAGE ReplyMsg)
1177 {
1178 ULONG ServerId;
1179 PCSR_SERVER_DLL ServerDll;
1180 ULONG ApiId;
1181 ULONG Reply;
1182 NTSTATUS Status;
1183
1184 /* Get the Server ID */
1185 ServerId = CSR_SERVER_ID_FROM_OPCODE(ReceiveMsg->Opcode);
1186
1187 /* Make sure that the ID is within limits, and the Server DLL loaded */
1188 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
1189 (!(ServerDll = CsrLoadedServerDll[ServerId])))
1190 {
1191 /* We are beyond the Maximum Server ID */
1192 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId, ServerDll);
1193 ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
1194 return STATUS_ILLEGAL_FUNCTION;
1195 }
1196 else
1197 {
1198 /* Get the API ID */
1199 ApiId = CSR_API_ID_FROM_OPCODE(ReceiveMsg->Opcode);
1200
1201 /* Normalize it with our Base ID */
1202 ApiId -= ServerDll->ApiBase;
1203
1204 /* Make sure that the ID is within limits, and the entry exists */
1205 if ((ApiId >= ServerDll->HighestApiSupported) ||
1206 ((ServerDll->ValidTable) && !(ServerDll->ValidTable[ApiId])))
1207 {
1208 /* We are beyond the Maximum API ID, or it doesn't exist */
1209 DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
1210 "invalid API to call from the server.\n",
1211 ServerDll->ValidTable[ApiId],
1212 ((ServerDll->NameTable) && (ServerDll->NameTable[ApiId])) ?
1213 ServerDll->NameTable[ApiId] : "*** UNKNOWN ***", &ServerDll->Name);
1214 DbgBreakPoint();
1215 ReplyMsg->Status = (ULONG)STATUS_ILLEGAL_FUNCTION;
1216 return STATUS_ILLEGAL_FUNCTION;
1217 }
1218 }
1219
1220 if (CsrDebug & 2)
1221 {
1222 DPRINT1("CSRSS: %s Api Request received from server process\n",
1223 ServerDll->NameTable[ApiId]);
1224 }
1225
1226 /* Validation complete, start SEH */
1227 _SEH2_TRY
1228 {
1229 /* Call the API and get the result */
1230 Status = ServerDll->DispatchTable[ApiId](ReceiveMsg, &Reply);
1231
1232 /* Return the result, no matter what it is */
1233 ReplyMsg->Status = Status;
1234 }
1235 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1236 {
1237 /* If we got an exception, return access violation */
1238 ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
1239 }
1240 _SEH2_END;
1241
1242 /* Return success */
1243 return STATUS_SUCCESS;
1244 }
1245
1246 /*++
1247 * @name CsrConnectToUser
1248 * @implemented NT4
1249 *
1250 * The CsrConnectToUser connects to the User subsystem.
1251 *
1252 * @param None
1253 *
1254 * @return A pointer to the CSR Thread
1255 *
1256 * @remarks None.
1257 *
1258 *--*/
1259 PCSR_THREAD
1260 NTAPI
1261 CsrConnectToUser(VOID)
1262 {
1263 NTSTATUS Status;
1264 ANSI_STRING DllName;
1265 UNICODE_STRING TempName;
1266 HANDLE hUser32;
1267 STRING StartupName;
1268 PTEB Teb = NtCurrentTeb();
1269 PCSR_THREAD CsrThread;
1270 BOOLEAN Connected;
1271
1272 /* Check if we didn't already find it */
1273 if (!CsrClientThreadSetup)
1274 {
1275 /* Get the DLL Handle for user32.dll */
1276 RtlInitAnsiString(&DllName, "user32");
1277 RtlAnsiStringToUnicodeString(&TempName, &DllName, TRUE);
1278 Status = LdrGetDllHandle(NULL,
1279 NULL,
1280 &TempName,
1281 &hUser32);
1282 RtlFreeUnicodeString(&TempName);
1283
1284 /* If we got teh handle, get the Client Thread Startup Entrypoint */
1285 if (NT_SUCCESS(Status))
1286 {
1287 RtlInitAnsiString(&StartupName,"ClientThreadSetup");
1288 Status = LdrGetProcedureAddress(hUser32,
1289 &StartupName,
1290 0,
1291 (PVOID)&CsrClientThreadSetup);
1292 }
1293 }
1294
1295 /* Connect to user32 */
1296 _SEH2_TRY
1297 {
1298 Connected = CsrClientThreadSetup();
1299 }
1300 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1301 {
1302 Connected = FALSE;
1303 } _SEH2_END;
1304
1305 if (!Connected)
1306 {
1307 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1308 return NULL;
1309 }
1310
1311 /* Save pointer to this thread in TEB */
1312 CsrAcquireProcessLock();
1313 CsrThread = CsrLocateThreadInProcess(NULL, &Teb->ClientId);
1314 CsrReleaseProcessLock();
1315 if (CsrThread) Teb->CsrClientThread = CsrThread;
1316
1317 /* Return it */
1318 return CsrThread;
1319 }
1320
1321 /*++
1322 * @name CsrQueryApiPort
1323 * @implemented NT4
1324 *
1325 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1326 *
1327 * @param None.
1328 *
1329 * @return A handle to the port.
1330 *
1331 * @remarks None.
1332 *
1333 *--*/
1334 HANDLE
1335 NTAPI
1336 CsrQueryApiPort(VOID)
1337 {
1338 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
1339 return CsrApiPort;
1340 }
1341
1342 /*++
1343 * @name CsrCaptureArguments
1344 * @implemented NT5.1
1345 *
1346 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1347 * re-captures it into a server CSR Capture Buffer.
1348 *
1349 * @param CsrThread
1350 * Pointer to the CSR Thread performing the validation.
1351 *
1352 * @param ApiMessage
1353 * Pointer to the CSR API Message containing the Capture Buffer
1354 * that needs to be validated.
1355 *
1356 * @return TRUE if validation succeeded, FALSE otherwise.
1357 *
1358 * @remarks None.
1359 *
1360 *--*/
1361 BOOLEAN
1362 NTAPI
1363 CsrCaptureArguments(IN PCSR_THREAD CsrThread,
1364 IN PCSR_API_MESSAGE ApiMessage)
1365 {
1366 PCSR_CAPTURE_BUFFER LocalCaptureBuffer = NULL, RemoteCaptureBuffer = NULL;
1367 ULONG LocalLength = 0, PointerCount = 0;
1368 SIZE_T BufferDistance = 0;
1369 ULONG_PTR **PointerOffsets = NULL, *CurrentPointer = NULL;
1370
1371 /* Use SEH to make sure this is valid */
1372 _SEH2_TRY
1373 {
1374 /* Get the buffer we got from whoever called NTDLL */
1375 LocalCaptureBuffer = ApiMessage->CsrCaptureData;
1376 LocalLength = LocalCaptureBuffer->Size;
1377
1378 /* Now check if the buffer is inside our mapped section */
1379 if (((ULONG_PTR)LocalCaptureBuffer < CsrThread->Process->ClientViewBase) ||
1380 (((ULONG_PTR)LocalCaptureBuffer + LocalLength) >= CsrThread->Process->ClientViewBounds))
1381 {
1382 /* Return failure */
1383 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1384 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1385 _SEH2_YIELD(return FALSE);
1386 }
1387
1388 /* Check if the Length is valid */
1389 if (((LocalCaptureBuffer->PointerCount * 4 + sizeof(CSR_CAPTURE_BUFFER)) >
1390 LocalLength) ||(LocalLength > MAXWORD))
1391 {
1392 /* Return failure */
1393 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer);
1394 DbgBreakPoint();
1395 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1396 _SEH2_YIELD(return FALSE);
1397 }
1398 }
1399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1400 {
1401 /* Return failure */
1402 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1403 _SEH2_YIELD(return FALSE);
1404 } _SEH2_END;
1405
1406 /* We validated the incoming buffer, now allocate the remote one */
1407 RemoteCaptureBuffer = RtlAllocateHeap(CsrHeap, 0, LocalLength);
1408 if (!RemoteCaptureBuffer)
1409 {
1410 /* We're out of memory */
1411 ApiMessage->Status = STATUS_NO_MEMORY;
1412 return FALSE;
1413 }
1414
1415 /* Copy the client's buffer */
1416 RtlMoveMemory(RemoteCaptureBuffer, LocalCaptureBuffer, LocalLength);
1417
1418 /* Copy the length */
1419 RemoteCaptureBuffer->Size = LocalLength;
1420
1421 /* Calculate the difference between our buffer and the client's */
1422 BufferDistance = (ULONG_PTR)RemoteCaptureBuffer - (ULONG_PTR)LocalCaptureBuffer;
1423
1424 /* Save the pointer count and offset pointer */
1425 PointerCount = RemoteCaptureBuffer->PointerCount;
1426 PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1);
1427
1428 /* Start the loop */
1429 while (PointerCount)
1430 {
1431 /* Get the current pointer */
1432 if ((CurrentPointer = *PointerOffsets++))
1433 {
1434 /* Add it to the CSR Message structure */
1435 CurrentPointer += (ULONG_PTR)ApiMessage;
1436
1437 /* Validate the bounds of the current pointer */
1438 if ((*CurrentPointer >= CsrThread->Process->ClientViewBase) &&
1439 (*CurrentPointer < CsrThread->Process->ClientViewBounds))
1440 {
1441 /* Modify the pointer to take into account its new position */
1442 *CurrentPointer += BufferDistance;
1443 }
1444 else
1445 {
1446 /* Invalid pointer, fail */
1447 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1448 DbgBreakPoint();
1449 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1450 }
1451 }
1452
1453 /* Move to the next Pointer */
1454 PointerCount--;
1455 }
1456
1457 /* Check if we got success */
1458 if (ApiMessage->Status != STATUS_SUCCESS)
1459 {
1460 /* Failure. Free the buffer and return*/
1461 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1462 return FALSE;
1463 }
1464 else
1465 {
1466 /* Success, save the previous buffer */
1467 RemoteCaptureBuffer->PreviousCaptureBuffer = LocalCaptureBuffer;
1468 ApiMessage->CsrCaptureData = RemoteCaptureBuffer;
1469 }
1470
1471 /* Success */
1472 return TRUE;
1473 }
1474
1475 /*++
1476 * @name CsrReleaseCapturedArguments
1477 * @implemented NT5.1
1478 *
1479 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1480 * that was previously captured with CsrCaptureArguments.
1481 *
1482 * @param ApiMessage
1483 * Pointer to the CSR API Message containing the Capture Buffer
1484 * that needs to be released.
1485 *
1486 * @return None.
1487 *
1488 * @remarks None.
1489 *
1490 *--*/
1491 VOID
1492 NTAPI
1493 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
1494 {
1495 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer, LocalCaptureBuffer;
1496 SIZE_T BufferDistance;
1497 ULONG PointerCount;
1498 ULONG_PTR **PointerOffsets, *CurrentPointer;
1499
1500 /* Get the capture buffers */
1501 RemoteCaptureBuffer = ApiMessage->CsrCaptureData;
1502 LocalCaptureBuffer = RemoteCaptureBuffer->PreviousCaptureBuffer;
1503
1504 /* Free the previous one */
1505 RemoteCaptureBuffer->PreviousCaptureBuffer = NULL;
1506
1507 /* Find out the difference between the two buffers */
1508 BufferDistance = (ULONG_PTR)LocalCaptureBuffer - (ULONG_PTR)RemoteCaptureBuffer;
1509
1510 /* Save the pointer count and offset pointer */
1511 PointerCount = RemoteCaptureBuffer->PointerCount;
1512 PointerOffsets = (ULONG_PTR**)(RemoteCaptureBuffer + 1);
1513
1514 /* Start the loop */
1515 while (PointerCount)
1516 {
1517 /* Get the current pointer */
1518 CurrentPointer = *PointerOffsets++;
1519 if (CurrentPointer)
1520 {
1521 /* Add it to the CSR Message structure */
1522 CurrentPointer += (ULONG_PTR)ApiMessage;
1523
1524 /* Modify the pointer to take into account its new position */
1525 *CurrentPointer += BufferDistance;
1526 }
1527
1528 /* Move to the next Pointer */
1529 PointerCount--;
1530 }
1531
1532 /* Copy the data back */
1533 RtlMoveMemory(LocalCaptureBuffer, RemoteCaptureBuffer, RemoteCaptureBuffer->Size);
1534
1535 /* Free our allocated buffer */
1536 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1537 }
1538
1539 /*++
1540 * @name CsrValidateMessageBuffer
1541 * @implemented NT5.1
1542 *
1543 * The CsrValidateMessageBuffer routine validates a captured message buffer
1544 * present in the CSR Api Message
1545 *
1546 * @param ApiMessage
1547 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1548 *
1549 * @param Buffer
1550 * Pointer to the message buffer to validate.
1551 *
1552 * @param ArgumentSize
1553 * Size of the message to check.
1554 *
1555 * @param ArgumentCount
1556 * Number of messages to check.
1557 *
1558 * @return TRUE if validation suceeded, FALSE otherwise.
1559 *
1560 * @remarks None.
1561 *
1562 *--*/
1563 BOOLEAN
1564 NTAPI
1565 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage,
1566 IN PVOID *Buffer,
1567 IN ULONG ArgumentSize,
1568 IN ULONG ArgumentCount)
1569 {
1570 PCSR_CAPTURE_BUFFER CaptureBuffer = ApiMessage->CsrCaptureData;
1571 SIZE_T BufferDistance;
1572 ULONG PointerCount, i;
1573 ULONG_PTR **PointerOffsets, *CurrentPointer;
1574
1575 /* Make sure there are some arguments */
1576 if (!ArgumentCount) return FALSE;
1577
1578 /* Check if didn't get a buffer and there aren't any arguments to check */
1579 if (!(*Buffer) && (!(ArgumentCount * ArgumentSize))) return TRUE;
1580
1581 /* Check if we have no capture buffer */
1582 if (!CaptureBuffer)
1583 {
1584 /* In this case, check only the Process ID */
1585 if (NtCurrentTeb()->ClientId.UniqueProcess ==
1586 ApiMessage->Header.ClientId.UniqueProcess)
1587 {
1588 /* There is a match, validation succeeded */
1589 return TRUE;
1590 }
1591 }
1592 else
1593 {
1594 /* Make sure that there is still space left in the buffer */
1595 if ((CaptureBuffer->Size - (ULONG_PTR)*Buffer + (ULONG_PTR)CaptureBuffer) <
1596 (ArgumentCount * ArgumentSize))
1597 {
1598 /* Find out the difference between the two buffers */
1599 BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage;
1600
1601 /* Save the pointer count */
1602 PointerCount = CaptureBuffer->PointerCount;
1603 PointerOffsets = (ULONG_PTR**)(CaptureBuffer + 1);
1604
1605 /* Start the loop */
1606 for (i = 0; i < PointerCount; i++)
1607 {
1608 /* Get the current pointer */
1609 CurrentPointer = *PointerOffsets++;
1610
1611 /* Check if its' equal to the difference */
1612 if (*CurrentPointer == BufferDistance) return TRUE;
1613 }
1614 }
1615 }
1616
1617 /* Failure */
1618 DbgPrint("CSRSRV: Bad message buffer %p\n", ApiMessage);
1619 DbgBreakPoint();
1620 return FALSE;
1621 }
1622
1623 /*++
1624 * @name CsrValidateMessageString
1625 * @implemented NT5.1
1626 *
1627 * The CsrValidateMessageString validates a captured Wide-Character String
1628 * present in a CSR API Message.
1629 *
1630 * @param ApiMessage
1631 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1632 *
1633 * @param MessageString
1634 * Pointer to the buffer containing the string to validate.
1635 *
1636 * @return TRUE if validation suceeded, FALSE otherwise.
1637 *
1638 * @remarks None.
1639 *
1640 *--*/
1641 BOOLEAN
1642 NTAPI
1643 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage,
1644 IN LPWSTR *MessageString)
1645 {
1646 DPRINT1("CSRSRV: %s called\n", __FUNCTION__);
1647 return FALSE;
1648 }
1649
1650 /* EOF */