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)
10 /* INCLUDES *******************************************************************/
14 #include <ndk/kefuncs.h>
19 /* GLOBALS ********************************************************************/
21 BOOLEAN (*CsrClientThreadSetup
)(VOID
) = NULL
;
22 UNICODE_STRING CsrApiPortName
;
23 volatile ULONG CsrpStaticThreadCount
;
24 volatile ULONG CsrpDynamicThreadTotal
;
25 extern ULONG CsrMaxApiRequestThreads
;
27 /* FUNCTIONS ******************************************************************/
30 * @name CsrCallServerFromServer
33 * The CsrCallServerFromServer routine calls a CSR API from within a server.
34 * It avoids using LPC messages since the request isn't coming from a client.
37 * Pointer to the CSR API Message to send to the server.
40 * Pointer to the CSR API Message to receive from the server.
42 * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
43 * if the ApiNumber is invalid, or STATUS_ACCESS_VIOLATION if there
44 * was a problem executing the API.
51 CsrCallServerFromServer(IN PCSR_API_MESSAGE ReceiveMsg
,
52 IN OUT PCSR_API_MESSAGE ReplyMsg
)
55 PCSR_SERVER_DLL ServerDll
;
57 CSR_REPLY_CODE ReplyCode
= CsrReplyImmediately
;
59 /* Get the Server ID */
60 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
->ApiNumber
);
62 /* Make sure that the ID is within limits, and the Server DLL loaded */
63 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
64 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
66 /* We are beyond the Maximum Server ID */
67 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId
, ServerDll
);
68 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
69 return STATUS_ILLEGAL_FUNCTION
;
73 /* Get the API ID, normalized with our Base ID */
74 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
->ApiNumber
) - ServerDll
->ApiBase
;
76 /* Make sure that the ID is within limits, and the entry exists */
77 if ((ApiId
>= ServerDll
->HighestApiSupported
) ||
78 ((ServerDll
->ValidTable
) && !(ServerDll
->ValidTable
[ApiId
])))
80 /* We are beyond the Maximum API ID, or it doesn't exist */
81 DPRINT1("API: %d\n", ApiId
);
83 DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
84 "invalid API to call from the server.\n",
86 ((ServerDll
->NameTable
) && (ServerDll
->NameTable
[ApiId
])) ?
87 ServerDll
->NameTable
[ApiId
] : "*** UNKNOWN ***",
91 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
92 return STATUS_ILLEGAL_FUNCTION
;
99 DPRINT1("CSRSS: %s Api Request received from server process\n",
100 ServerDll
->NameTable
[ApiId
]);
104 /* Validation complete, start SEH */
107 /* Call the API, get the reply code and return the result */
108 ReplyMsg
->Status
= ServerDll
->DispatchTable
[ApiId
](ReceiveMsg
, &ReplyCode
);
110 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
112 /* If we got an exception, return access violation */
113 ReplyMsg
->Status
= STATUS_ACCESS_VIOLATION
;
118 return STATUS_SUCCESS
;
122 * @name CsrApiHandleConnectionRequest
124 * The CsrApiHandleConnectionRequest routine handles and accepts a new
125 * connection request to the CSR API LPC Port.
128 * Pointer to the incoming CSR API Message which contains the
129 * connection request.
131 * @return STATUS_SUCCESS in case of success, or status code which caused
132 * the routine to error.
134 * @remarks This routine is responsible for attaching the Shared Section to
135 * new clients connecting to CSR.
140 CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage
)
142 PCSR_THREAD CsrThread
= NULL
;
143 PCSR_PROCESS CsrProcess
= NULL
;
144 NTSTATUS Status
= STATUS_SUCCESS
;
145 PCSR_API_CONNECTINFO ConnectInfo
= &ApiMessage
->ConnectionInfo
;
146 BOOLEAN AllowConnection
= FALSE
;
147 REMOTE_PORT_VIEW RemotePortView
;
150 /* Acquire the Process Lock */
151 CsrAcquireProcessLock();
153 /* Lookup the CSR Thread */
154 CsrThread
= CsrLocateThreadByClientId(NULL
, &ApiMessage
->Header
.ClientId
);
156 /* Check if we have a thread */
159 /* Get the Process and make sure we have it as well */
160 CsrProcess
= CsrThread
->Process
;
163 /* Reference the Process */
164 CsrLockedReferenceProcess(CsrProcess
);
166 /* Attach the Shared Section */
167 Status
= CsrSrvAttachSharedSection(CsrProcess
, ConnectInfo
);
168 if (NT_SUCCESS(Status
))
170 /* Allow the connection and return debugging flag */
171 ConnectInfo
->DebugFlags
= CsrDebug
;
172 AllowConnection
= TRUE
;
175 /* Dereference the Process */
176 CsrLockedDereferenceProcess(CsrProcess
);
180 /* Release the Process Lock */
181 CsrReleaseProcessLock();
183 /* Setup the Port View Structure */
184 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
185 RemotePortView
.ViewSize
= 0;
186 RemotePortView
.ViewBase
= NULL
;
188 /* Save the Process ID */
189 ConnectInfo
->ServerProcessId
= NtCurrentTeb()->ClientId
.UniqueProcess
;
191 /* Accept the Connection */
192 Status
= NtAcceptConnectPort(&ServerPort
,
193 AllowConnection
? UlongToPtr(CsrProcess
->SequenceNumber
) : 0,
198 if (!NT_SUCCESS(Status
))
200 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status
);
202 else if (AllowConnection
)
206 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
207 ApiMessage
->Header
.ClientId
.UniqueProcess
,
208 ApiMessage
->Header
.ClientId
.UniqueThread
,
209 RemotePortView
.ViewBase
,
210 RemotePortView
.ViewSize
);
213 /* Set some Port Data in the Process */
214 CsrProcess
->ClientPort
= ServerPort
;
215 CsrProcess
->ClientViewBase
= (ULONG_PTR
)RemotePortView
.ViewBase
;
216 CsrProcess
->ClientViewBounds
= (ULONG_PTR
)((ULONG_PTR
)RemotePortView
.ViewBase
+
217 (ULONG_PTR
)RemotePortView
.ViewSize
);
219 /* Complete the connection */
220 Status
= NtCompleteConnectPort(ServerPort
);
221 if (!NT_SUCCESS(Status
))
223 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status
);
228 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
229 ApiMessage
->Header
.ClientId
.UniqueProcess
,
230 ApiMessage
->Header
.ClientId
.UniqueThread
);
233 /* Return status to caller */
238 * @name CsrpCheckRequestThreads
240 * The CsrpCheckRequestThreads routine checks if there are no more threads
241 * to handle CSR API Requests, and creates a new thread if possible, to
246 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
247 * if a new thread couldn't be created.
254 CsrpCheckRequestThreads(VOID
)
260 /* Decrease the count, and see if we're out */
261 if (InterlockedDecrementUL(&CsrpStaticThreadCount
) == 0)
263 /* Check if we've still got space for a Dynamic Thread */
264 if (CsrpDynamicThreadTotal
< CsrMaxApiRequestThreads
)
266 /* Create a new dynamic thread */
267 Status
= RtlCreateUserThread(NtCurrentProcess(),
273 (PVOID
)CsrApiRequestThread
,
278 if (NT_SUCCESS(Status
))
280 /* Increase the thread counts */
281 InterlockedIncrementUL(&CsrpStaticThreadCount
);
282 InterlockedIncrementUL(&CsrpDynamicThreadTotal
);
284 /* Add a new server thread */
285 if (CsrAddStaticServerThread(hThread
,
287 CsrThreadIsServerThread
))
290 NtResumeThread(hThread
, NULL
);
294 /* Failed to create a new static thread */
295 InterlockedDecrementUL(&CsrpStaticThreadCount
);
296 InterlockedDecrementUL(&CsrpDynamicThreadTotal
);
299 DPRINT1("Failing\n");
300 NtTerminateThread(hThread
, 0);
304 return STATUS_UNSUCCESSFUL
;
311 return STATUS_SUCCESS
;
315 * @name CsrApiRequestThread
317 * The CsrApiRequestThread routine handles incoming messages or connection
318 * requests on the CSR API LPC Port.
321 * System-default user-defined parameter. Unused.
323 * @return The thread exit code, if the thread is terminated.
325 * @remarks Before listening on the port, the routine will first attempt
326 * to connect to the user subsystem.
331 CsrApiRequestThread(IN PVOID Parameter
)
333 PTEB Teb
= NtCurrentTeb();
334 LARGE_INTEGER TimeOut
;
335 PCSR_THREAD CurrentThread
, CsrThread
;
337 CSR_REPLY_CODE ReplyCode
;
338 PCSR_API_MESSAGE ReplyMsg
;
339 CSR_API_MESSAGE ReceiveMsg
;
340 PCSR_PROCESS CsrProcess
;
341 PHARDERROR_MSG HardErrorMsg
;
343 PCSR_SERVER_DLL ServerDll
;
344 PCLIENT_DIED_MSG ClientDiedMsg
;
345 PDBGKM_MSG DebugMessage
;
346 ULONG ServerId
, ApiId
, MessageType
, i
;
349 /* Setup LPC loop port and message */
351 ReplyPort
= CsrApiPort
;
353 /* Connect to user32 */
354 while (!CsrConnectToUser())
356 /* Set up the timeout for the connect (30 seconds) */
357 TimeOut
.QuadPart
= -30 * 1000 * 1000 * 10;
359 /* Keep trying until we get a response */
360 Teb
->Win32ClientInfo
[0] = 0;
361 NtDelayExecution(FALSE
, &TimeOut
);
365 CurrentThread
= Teb
->CsrClientThread
;
367 /* If we got an event... */
370 /* Set it, to let stuff waiting on us load */
371 Status
= NtSetEvent((HANDLE
)Parameter
, NULL
);
372 ASSERT(NT_SUCCESS(Status
));
374 /* Increase the Thread Counts */
375 InterlockedIncrementUL(&CsrpStaticThreadCount
);
376 InterlockedIncrementUL(&CsrpDynamicThreadTotal
);
379 /* Now start the loop */
382 /* Make sure the real CID is set */
383 Teb
->RealClientId
= Teb
->ClientId
;
386 if (Teb
->CountOfOwnedCriticalSections
)
388 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
389 Teb
->CountOfOwnedCriticalSections
);
390 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
391 &ReceiveMsg
, ReplyMsg
);
395 /* Wait for a message to come through */
396 Status
= NtReplyWaitReceivePort(ReplyPort
,
401 /* Check if we didn't get success */
402 if (Status
!= STATUS_SUCCESS
)
404 /* Was it a failure or another success code? */
405 if (!NT_SUCCESS(Status
))
407 /* Check for specific status cases */
408 if ((Status
!= STATUS_INVALID_CID
) &&
409 (Status
!= STATUS_UNSUCCESSFUL
) &&
410 ((Status
== STATUS_INVALID_HANDLE
) || (ReplyPort
== CsrApiPort
)))
412 /* Notify the debugger */
413 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
414 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort
, CsrApiPort
);
417 /* We failed big time, so start out fresh */
419 ReplyPort
= CsrApiPort
;
424 /* A strange "success" code, just try again */
425 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status
);
430 /* Use whatever Client ID we got */
431 Teb
->RealClientId
= ReceiveMsg
.Header
.ClientId
;
433 /* Get the Message Type */
434 MessageType
= ReceiveMsg
.Header
.u2
.s2
.Type
;
436 /* Handle connection requests */
437 if (MessageType
== LPC_CONNECTION_REQUEST
)
439 /* Handle the Connection Request */
440 CsrApiHandleConnectionRequest(&ReceiveMsg
);
443 ReplyPort
= CsrApiPort
;
447 /* It's some other kind of request. Get the lock for the lookup */
448 CsrAcquireProcessLock();
450 /* Now do the lookup to get the CSR_THREAD */
451 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
,
452 &ReceiveMsg
.Header
.ClientId
);
454 /* Did we find a thread? */
457 /* This wasn't a CSR Thread, release lock */
458 CsrReleaseProcessLock();
460 /* If this was an exception, handle it */
461 if (MessageType
== LPC_EXCEPTION
)
463 ReplyMsg
= &ReceiveMsg
;
464 ReplyPort
= CsrApiPort
;
465 ReplyMsg
->Status
= DBG_CONTINUE
;
467 else if (MessageType
== LPC_PORT_CLOSED
||
468 MessageType
== LPC_CLIENT_DIED
)
470 /* The Client or Port are gone, loop again */
472 ReplyPort
= CsrApiPort
;
474 else if (MessageType
== LPC_ERROR_EVENT
)
476 /* If it's a hard error, handle this too */
477 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
479 /* Default it to unhandled */
480 HardErrorMsg
->Response
= ResponseNotHandled
;
482 /* Check if there are free api threads */
483 CsrpCheckRequestThreads();
484 if (CsrpStaticThreadCount
)
486 /* Loop every Server DLL */
487 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
489 /* Get the Server DLL */
490 ServerDll
= CsrLoadedServerDll
[i
];
492 /* Check if it's valid and if it has a Hard Error Callback */
493 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
496 ServerDll
->HardErrorCallback(NULL
/* == CsrThread */, HardErrorMsg
);
498 /* If it's handled, get out of here */
499 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
504 /* Increase the thread count */
505 InterlockedIncrementUL(&CsrpStaticThreadCount
);
507 /* If the response was 0xFFFFFFFF, we'll ignore it */
508 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
511 ReplyPort
= CsrApiPort
;
515 ReplyMsg
= &ReceiveMsg
;
516 ReplyPort
= CsrApiPort
;
519 else if (MessageType
== LPC_REQUEST
)
521 /* This is an API Message coming from a non-CSR Thread */
522 ReplyMsg
= &ReceiveMsg
;
523 ReplyPort
= CsrApiPort
;
524 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
526 else if (MessageType
== LPC_DATAGRAM
)
528 /* This is an API call, get the Server ID */
529 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
531 /* Make sure that the ID is within limits, and the Server DLL loaded */
533 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
534 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
536 /* We are beyond the Maximum Server ID */
537 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
538 ServerId
, ServerDll
);
542 ReplyPort
= CsrApiPort
;
546 /* Get the API ID, normalized with our Base ID */
547 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
549 /* Make sure that the ID is within limits, and the entry exists */
550 if (ApiId
>= ServerDll
->HighestApiSupported
)
552 /* We are beyond the Maximum API ID, or it doesn't exist */
553 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
554 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
557 ReplyPort
= CsrApiPort
;
565 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
566 Teb
->ClientId
.UniqueThread
,
567 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
568 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
569 ServerDll
->NameTable
[ApiId
],
575 ReceiveMsg
.Status
= STATUS_SUCCESS
;
577 /* Validation complete, start SEH */
580 /* Make sure we have enough threads */
581 CsrpCheckRequestThreads();
583 /* Call the API and get the reply code */
585 ReplyPort
= CsrApiPort
;
586 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &ReplyCode
);
588 /* Increase the static thread count */
589 InterlockedIncrementUL(&CsrpStaticThreadCount
);
591 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
594 ReplyPort
= CsrApiPort
;
600 /* Some other ignored message type */
602 ReplyPort
= CsrApiPort
;
609 /* We have a valid thread, was this an LPC Request? */
610 if (MessageType
!= LPC_REQUEST
)
612 /* It's not an API, check if the client died */
613 if (MessageType
== LPC_CLIENT_DIED
)
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
)
619 /* Now we reply to the dying client */
620 ReplyPort
= CsrThread
->Process
->ClientPort
;
622 /* Reference the thread */
623 CsrLockedReferenceThread(CsrThread
);
625 /* Destroy the thread in the API Message */
626 CsrDestroyThread(&ReceiveMsg
.Header
.ClientId
);
628 /* Check if the thread was actually ourselves */
629 if (CsrProcess
->ThreadCount
== 1)
631 /* Kill the process manually here */
632 CsrDestroyProcess(&CsrThread
->ClientId
, 0);
635 /* Remove our extra reference */
636 CsrLockedDereferenceThread(CsrThread
);
639 /* Release the lock and keep looping */
640 CsrReleaseProcessLock();
643 ReplyPort
= CsrApiPort
;
647 /* Reference the thread and release the lock */
648 CsrLockedReferenceThread(CsrThread
);
649 CsrReleaseProcessLock();
651 /* Check if this was an exception */
652 if (MessageType
== LPC_EXCEPTION
)
654 /* Kill the process */
655 NtTerminateProcess(CsrProcess
->ProcessHandle
, STATUS_ABANDONED
);
657 /* Destroy it from CSR */
658 CsrDestroyProcess(&ReceiveMsg
.Header
.ClientId
, STATUS_ABANDONED
);
660 /* Return a Debug Message */
661 DebugMessage
= (PDBGKM_MSG
)&ReceiveMsg
;
662 DebugMessage
->ReturnedStatus
= DBG_CONTINUE
;
663 ReplyMsg
= &ReceiveMsg
;
664 ReplyPort
= CsrApiPort
;
666 /* Remove our extra reference */
667 CsrDereferenceThread(CsrThread
);
669 else if (MessageType
== LPC_ERROR_EVENT
)
671 /* If it's a hard error, handle this too */
672 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
674 /* Default it to unhandled */
675 HardErrorMsg
->Response
= ResponseNotHandled
;
677 /* Check if there are free api threads */
678 CsrpCheckRequestThreads();
679 if (CsrpStaticThreadCount
)
681 /* Loop every Server DLL */
682 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
684 /* Get the Server DLL */
685 ServerDll
= CsrLoadedServerDll
[i
];
687 /* Check if it's valid and if it has a Hard Error Callback */
688 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
691 ServerDll
->HardErrorCallback(CsrThread
, HardErrorMsg
);
693 /* If it's handled, get out of here */
694 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
699 /* Increase the thread count */
700 InterlockedIncrementUL(&CsrpStaticThreadCount
);
702 /* If the response was 0xFFFFFFFF, we'll ignore it */
703 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
706 ReplyPort
= CsrApiPort
;
710 CsrDereferenceThread(CsrThread
);
711 ReplyMsg
= &ReceiveMsg
;
712 ReplyPort
= CsrApiPort
;
718 CsrDereferenceThread(CsrThread
);
726 /* We got an API Request */
727 CsrLockedReferenceThread(CsrThread
);
728 CsrReleaseProcessLock();
730 /* This is an API call, get the Server ID */
731 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
733 /* Make sure that the ID is within limits, and the Server DLL loaded */
735 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
736 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
738 /* We are beyond the Maximum Server ID */
739 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
740 ServerId
, ServerDll
);
743 ReplyPort
= CsrApiPort
;
744 ReplyMsg
= &ReceiveMsg
;
745 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
746 CsrDereferenceThread(CsrThread
);
750 /* Get the API ID, normalized with our Base ID */
751 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
753 /* Make sure that the ID is within limits, and the entry exists */
754 if (ApiId
>= ServerDll
->HighestApiSupported
)
756 /* We are beyond the Maximum API ID, or it doesn't exist */
757 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
758 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
761 ReplyPort
= CsrApiPort
;
762 ReplyMsg
= &ReceiveMsg
;
763 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
764 CsrDereferenceThread(CsrThread
);
771 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x, Process %08x - %08x\n",
772 Teb
->ClientId
.UniqueThread
,
773 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
774 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
775 ServerDll
->NameTable
[ApiId
],
783 ReplyMsg
= &ReceiveMsg
;
784 ReceiveMsg
.Status
= STATUS_SUCCESS
;
786 /* Now we reply to a particular client */
787 ReplyPort
= CsrThread
->Process
->ClientPort
;
789 /* Check if there's a capture buffer */
790 if (ReceiveMsg
.CsrCaptureData
)
792 /* Capture the arguments */
793 if (!CsrCaptureArguments(CsrThread
, &ReceiveMsg
))
795 /* Ignore this message if we failed to get the arguments */
796 CsrDereferenceThread(CsrThread
);
801 /* Validation complete, start SEH */
804 /* Make sure we have enough threads */
805 CsrpCheckRequestThreads();
807 Teb
->CsrClientThread
= CsrThread
;
809 /* Call the API, get the reply code and return the result */
810 ReplyCode
= CsrReplyImmediately
;
811 ReplyMsg
->Status
= ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &ReplyCode
);
813 /* Increase the static thread count */
814 InterlockedIncrementUL(&CsrpStaticThreadCount
);
816 Teb
->CsrClientThread
= CurrentThread
;
818 if (ReplyCode
== CsrReplyAlreadySent
)
820 if (ReceiveMsg
.CsrCaptureData
)
822 CsrReleaseCapturedArguments(&ReceiveMsg
);
825 ReplyPort
= CsrApiPort
;
826 CsrDereferenceThread(CsrThread
);
828 else if (ReplyCode
== CsrReplyDeadClient
)
830 /* Reply to the death message */
831 NtReplyPort(ReplyPort
, &ReplyMsg
->Header
);
833 /* Reply back to the API port now */
835 ReplyPort
= CsrApiPort
;
837 CsrDereferenceThread(CsrThread
);
839 else if (ReplyCode
== CsrReplyPending
)
842 ReplyPort
= CsrApiPort
;
846 if (ReceiveMsg
.CsrCaptureData
)
848 CsrReleaseCapturedArguments(&ReceiveMsg
);
850 CsrDereferenceThread(CsrThread
);
853 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
856 ReplyPort
= CsrApiPort
;
861 /* We're out of the loop for some reason, terminate! */
862 NtTerminateThread(NtCurrentThread(), Status
);
867 * @name CsrApiPortInitialize
869 * The CsrApiPortInitialize routine initializes the LPC Port used for
870 * communications with the Client/Server Runtime (CSR) and initializes the
871 * static thread that will handle connection requests and APIs.
875 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
882 CsrApiPortInitialize(VOID
)
885 OBJECT_ATTRIBUTES ObjectAttributes
;
887 HANDLE hRequestEvent
, hThread
;
889 PLIST_ENTRY ListHead
, NextEntry
;
890 PCSR_THREAD ServerThread
;
892 /* Calculate how much space we'll need for the Port Name */
893 Size
= CsrDirectoryName
.Length
+ sizeof(CSR_PORT_NAME
) + sizeof(WCHAR
);
895 /* Create the buffer for it */
896 CsrApiPortName
.Buffer
= RtlAllocateHeap(CsrHeap
, 0, Size
);
897 if (!CsrApiPortName
.Buffer
) return STATUS_NO_MEMORY
;
899 /* Setup the rest of the empty string */
900 CsrApiPortName
.Length
= 0;
901 CsrApiPortName
.MaximumLength
= (USHORT
)Size
;
902 RtlAppendUnicodeStringToString(&CsrApiPortName
, &CsrDirectoryName
);
903 RtlAppendUnicodeToString(&CsrApiPortName
, UNICODE_PATH_SEP
);
904 RtlAppendUnicodeToString(&CsrApiPortName
, CSR_PORT_NAME
);
907 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName
);
908 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
909 sizeof(CSR_API_CONNECTINFO
), sizeof(CSR_API_MESSAGE
));
912 /* FIXME: Create a Security Descriptor */
914 /* Initialize the Attributes */
915 InitializeObjectAttributes(&ObjectAttributes
,
919 NULL
/* FIXME: Use the Security Descriptor */);
921 /* Create the Port Object */
922 Status
= NtCreatePort(&CsrApiPort
,
924 sizeof(CSR_API_CONNECTINFO
),
925 sizeof(CSR_API_MESSAGE
),
927 if (NT_SUCCESS(Status
))
929 /* Create the event the Port Thread will use */
930 Status
= NtCreateEvent(&hRequestEvent
,
933 SynchronizationEvent
,
935 if (NT_SUCCESS(Status
))
937 /* Create the Request Thread */
938 Status
= RtlCreateUserThread(NtCurrentProcess(),
944 (PVOID
)CsrApiRequestThread
,
945 (PVOID
)hRequestEvent
,
948 if (NT_SUCCESS(Status
))
950 /* Add this as a static thread to CSRSRV */
951 CsrAddStaticServerThread(hThread
, &ClientId
, CsrThreadIsServerThread
);
953 /* Get the Thread List Pointers */
954 ListHead
= &CsrRootProcess
->ThreadList
;
955 NextEntry
= ListHead
->Flink
;
957 /* Start looping the list */
958 while (NextEntry
!= ListHead
)
961 ServerThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
964 Status
= NtResumeThread(ServerThread
->ThreadHandle
, NULL
);
966 /* Is this a Server Thread? */
967 if (ServerThread
->Flags
& CsrThreadIsServerThread
)
969 /* If so, then wait for it to initialize */
970 Status
= NtWaitForSingleObject(hRequestEvent
, FALSE
, NULL
);
971 ASSERT(NT_SUCCESS(Status
));
975 NextEntry
= NextEntry
->Flink
;
978 /* We don't need this anymore */
979 NtClose(hRequestEvent
);
989 * @name CsrConnectToUser
992 * The CsrConnectToUser connects to the User subsystem.
996 * @return A pointer to the CSR Thread
1003 CsrConnectToUser(VOID
)
1006 ANSI_STRING DllName
;
1007 UNICODE_STRING TempName
;
1010 PTEB Teb
= NtCurrentTeb();
1011 PCSR_THREAD CsrThread
;
1014 /* Check if we didn't already find it */
1015 if (!CsrClientThreadSetup
)
1017 /* Get the DLL Handle for user32.dll */
1018 RtlInitAnsiString(&DllName
, "user32");
1019 RtlAnsiStringToUnicodeString(&TempName
, &DllName
, TRUE
);
1020 Status
= LdrGetDllHandle(NULL
,
1024 RtlFreeUnicodeString(&TempName
);
1026 /* If we got the handle, get the Client Thread Startup Entrypoint */
1027 if (NT_SUCCESS(Status
))
1029 RtlInitAnsiString(&StartupName
,"ClientThreadSetup");
1030 Status
= LdrGetProcedureAddress(hUser32
,
1033 (PVOID
)&CsrClientThreadSetup
);
1037 /* Connect to user32 */
1040 Connected
= CsrClientThreadSetup();
1042 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1049 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1053 /* Save pointer to this thread in TEB */
1054 CsrAcquireProcessLock();
1055 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1056 CsrReleaseProcessLock();
1057 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1064 * @name CsrQueryApiPort
1067 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1071 * @return A handle to the port.
1078 CsrQueryApiPort(VOID
)
1084 * @name CsrCaptureArguments
1085 * @implemented NT5.1
1087 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1088 * re-captures it into a server CSR Capture Buffer.
1091 * Pointer to the CSR Thread performing the validation.
1094 * Pointer to the CSR API Message containing the Capture Buffer
1095 * that needs to be validated.
1097 * @return TRUE if validation succeeded, FALSE otherwise.
1104 CsrCaptureArguments(IN PCSR_THREAD CsrThread
,
1105 IN PCSR_API_MESSAGE ApiMessage
)
1107 PCSR_CAPTURE_BUFFER LocalCaptureBuffer
= NULL
, RemoteCaptureBuffer
= NULL
;
1108 SIZE_T BufferDistance
;
1111 PULONG_PTR OffsetPointer
;
1112 ULONG_PTR CurrentOffset
;
1114 /* Use SEH to make sure this is valid */
1117 /* Get the buffer we got from whoever called NTDLL */
1118 LocalCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1119 Length
= LocalCaptureBuffer
->Size
;
1121 /* Now check if the buffer is inside our mapped section */
1122 if (((ULONG_PTR
)LocalCaptureBuffer
< CsrThread
->Process
->ClientViewBase
) ||
1123 (((ULONG_PTR
)LocalCaptureBuffer
+ Length
) >= CsrThread
->Process
->ClientViewBounds
))
1125 /* Return failure */
1126 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1127 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1128 _SEH2_YIELD(return FALSE
);
1131 /* Check if the Length is valid */
1132 if ((FIELD_OFFSET(CSR_CAPTURE_BUFFER
, PointerOffsetsArray
) +
1133 (LocalCaptureBuffer
->PointerCount
* sizeof(PVOID
)) > Length
) ||
1134 (LocalCaptureBuffer
->PointerCount
> MAXUSHORT
))
1136 /* Return failure */
1137 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer
);
1139 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1140 _SEH2_YIELD(return FALSE
);
1143 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1145 /* Return failure */
1146 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1147 _SEH2_YIELD(return FALSE
);
1150 /* We validated the incoming buffer, now allocate the remote one */
1151 RemoteCaptureBuffer
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, Length
);
1152 if (!RemoteCaptureBuffer
)
1154 /* We're out of memory */
1155 ApiMessage
->Status
= STATUS_NO_MEMORY
;
1159 /* Copy the client's buffer */
1160 RtlMoveMemory(RemoteCaptureBuffer
, LocalCaptureBuffer
, Length
);
1162 /* Calculate the difference between our buffer and the client's */
1163 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1166 * All the pointer offsets correspond to pointers which point
1167 * to the remote data buffer instead of the local one.
1169 PointerCount
= RemoteCaptureBuffer
->PointerCount
;
1170 OffsetPointer
= RemoteCaptureBuffer
->PointerOffsetsArray
;
1171 while (PointerCount
--)
1173 CurrentOffset
= *OffsetPointer
;
1175 if (CurrentOffset
!= 0)
1177 /* Get the pointer corresponding to the offset */
1178 CurrentOffset
+= (ULONG_PTR
)ApiMessage
;
1180 /* Validate the bounds of the current pointed pointer */
1181 if ((*(PULONG_PTR
)CurrentOffset
>= CsrThread
->Process
->ClientViewBase
) &&
1182 (*(PULONG_PTR
)CurrentOffset
< CsrThread
->Process
->ClientViewBounds
))
1184 /* Modify the pointed pointer to take into account its new position */
1185 *(PULONG_PTR
)CurrentOffset
+= BufferDistance
;
1189 /* Invalid pointer, fail */
1190 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1192 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1199 /* Check if we got success */
1200 if (ApiMessage
->Status
!= STATUS_SUCCESS
)
1202 /* Failure. Free the buffer and return */
1203 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1208 /* Success, save the previous buffer and use the remote capture buffer */
1209 RemoteCaptureBuffer
->PreviousCaptureBuffer
= LocalCaptureBuffer
;
1210 ApiMessage
->CsrCaptureData
= RemoteCaptureBuffer
;
1218 * @name CsrReleaseCapturedArguments
1219 * @implemented NT5.1
1221 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1222 * that was previously captured with CsrCaptureArguments.
1225 * Pointer to the CSR API Message containing the Capture Buffer
1226 * that needs to be released.
1235 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage
)
1237 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer
, LocalCaptureBuffer
;
1238 SIZE_T BufferDistance
;
1240 PULONG_PTR OffsetPointer
;
1241 ULONG_PTR CurrentOffset
;
1243 /* Get the remote capture buffer */
1244 RemoteCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1246 /* Do not continue if there is no captured buffer */
1247 if (!RemoteCaptureBuffer
) return;
1249 /* If there is one, get the corresponding local capture buffer */
1250 LocalCaptureBuffer
= RemoteCaptureBuffer
->PreviousCaptureBuffer
;
1252 /* Free the previous one and use again the local capture buffer */
1253 RemoteCaptureBuffer
->PreviousCaptureBuffer
= NULL
;
1254 ApiMessage
->CsrCaptureData
= LocalCaptureBuffer
;
1256 /* Calculate the difference between our buffer and the client's */
1257 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1260 * All the pointer offsets correspond to pointers which point
1261 * to the local data buffer instead of the remote one (revert
1262 * the logic of CsrCaptureArguments).
1264 PointerCount
= RemoteCaptureBuffer
->PointerCount
;
1265 OffsetPointer
= RemoteCaptureBuffer
->PointerOffsetsArray
;
1266 while (PointerCount
--)
1268 CurrentOffset
= *OffsetPointer
;
1270 if (CurrentOffset
!= 0)
1272 /* Get the pointer corresponding to the offset */
1273 CurrentOffset
+= (ULONG_PTR
)ApiMessage
;
1275 /* Modify the pointed pointer to take into account its new position */
1276 *(PULONG_PTR
)CurrentOffset
-= BufferDistance
;
1282 /* Copy the data back */
1283 RtlMoveMemory(LocalCaptureBuffer
, RemoteCaptureBuffer
, RemoteCaptureBuffer
->Size
);
1285 /* Free our allocated buffer */
1286 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1290 * @name CsrValidateMessageBuffer
1291 * @implemented NT5.1
1293 * The CsrValidateMessageBuffer routine validates a captured message buffer
1294 * present in the CSR Api Message
1297 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1300 * Pointer to the message buffer to validate.
1302 * @param ElementCount
1303 * Number of elements contained in the message buffer.
1305 * @param ElementSize
1306 * Size of each element.
1308 * @return TRUE if validation succeeded, FALSE otherwise.
1315 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage
,
1317 IN ULONG ElementCount
,
1318 IN ULONG ElementSize
)
1320 PCSR_CAPTURE_BUFFER CaptureBuffer
= ApiMessage
->CsrCaptureData
;
1321 SIZE_T BufferDistance
= (ULONG_PTR
)Buffer
- (ULONG_PTR
)ApiMessage
;
1323 PULONG_PTR OffsetPointer
;
1326 * Check whether we have a valid buffer pointer, elements
1327 * of non-trivial size and that we don't overflow.
1329 if (!Buffer
|| ElementSize
== 0 ||
1330 (ULONGLONG
)ElementCount
* ElementSize
> (ULONGLONG
)0xFFFFFFFF)
1335 /* Check if didn't get a buffer and there aren't any arguments to check */
1336 // if (!*Buffer && (ElementCount * ElementSize == 0))
1337 if (!*Buffer
&& ElementCount
== 0) // Here ElementSize != 0 therefore only ElementCount can be == 0
1340 /* Check if we have no capture buffer */
1344 * In this case, check only the Process ID
1345 * and if there is a match, we succeed.
1347 if (NtCurrentTeb()->ClientId
.UniqueProcess
==
1348 ApiMessage
->Header
.ClientId
.UniqueProcess
)
1355 /* Make sure that there is still space left in the buffer */
1356 if ((CaptureBuffer
->Size
- (ULONG_PTR
)*Buffer
+ (ULONG_PTR
)CaptureBuffer
) >=
1357 (ElementCount
* ElementSize
))
1359 /* Perform the validation test */
1360 PointerCount
= CaptureBuffer
->PointerCount
;
1361 OffsetPointer
= CaptureBuffer
->PointerOffsetsArray
;
1362 while (PointerCount
--)
1365 * The pointer offset must be equal to the delta between
1366 * the addresses of the buffer and of the API message.
1368 if (*OffsetPointer
== BufferDistance
)
1378 DPRINT1("CSRSRV: Bad message buffer %p\n", ApiMessage
);
1384 * @name CsrValidateMessageString
1385 * @implemented NT5.1
1387 * The CsrValidateMessageString validates a captured Wide-Character String
1388 * present in a CSR API Message.
1391 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1393 * @param MessageString
1394 * Pointer to the buffer containing the string to validate.
1396 * @return TRUE if validation succeeded, FALSE otherwise.
1403 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage
,
1404 IN LPWSTR
*MessageString
)
1408 return CsrValidateMessageBuffer(ApiMessage
,
1409 (PVOID
*)MessageString
,
1410 wcslen(*MessageString
) + 1,