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 */
82 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 ***",
89 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
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 ASSERT(!AllowConnection
|| (AllowConnection
&& CsrProcess
));
193 Status
= NtAcceptConnectPort(&ServerPort
,
194 AllowConnection
? UlongToPtr(CsrProcess
->SequenceNumber
) : 0,
199 if (!NT_SUCCESS(Status
))
201 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status
);
203 else if (AllowConnection
)
207 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
208 ApiMessage
->Header
.ClientId
.UniqueProcess
,
209 ApiMessage
->Header
.ClientId
.UniqueThread
,
210 RemotePortView
.ViewBase
,
211 RemotePortView
.ViewSize
);
214 /* Set some Port Data in the Process */
215 CsrProcess
->ClientPort
= ServerPort
;
216 CsrProcess
->ClientViewBase
= (ULONG_PTR
)RemotePortView
.ViewBase
;
217 CsrProcess
->ClientViewBounds
= (ULONG_PTR
)((ULONG_PTR
)RemotePortView
.ViewBase
+
218 (ULONG_PTR
)RemotePortView
.ViewSize
);
220 /* Complete the connection */
221 Status
= NtCompleteConnectPort(ServerPort
);
222 if (!NT_SUCCESS(Status
))
224 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status
);
229 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
230 ApiMessage
->Header
.ClientId
.UniqueProcess
,
231 ApiMessage
->Header
.ClientId
.UniqueThread
);
234 /* Return status to caller */
239 * @name CsrpCheckRequestThreads
241 * The CsrpCheckRequestThreads routine checks if there are no more threads
242 * to handle CSR API Requests, and creates a new thread if possible, to
247 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
248 * if a new thread couldn't be created.
255 CsrpCheckRequestThreads(VOID
)
261 /* Decrease the count, and see if we're out */
262 if (InterlockedDecrementUL(&CsrpStaticThreadCount
) == 0)
264 /* Check if we've still got space for a Dynamic Thread */
265 if (CsrpDynamicThreadTotal
< CsrMaxApiRequestThreads
)
267 /* Create a new dynamic thread */
268 Status
= RtlCreateUserThread(NtCurrentProcess(),
274 (PVOID
)CsrApiRequestThread
,
279 if (NT_SUCCESS(Status
))
281 /* Increase the thread counts */
282 InterlockedIncrementUL(&CsrpStaticThreadCount
);
283 InterlockedIncrementUL(&CsrpDynamicThreadTotal
);
285 /* Add a new server thread */
286 if (CsrAddStaticServerThread(hThread
,
288 CsrThreadIsServerThread
))
291 NtResumeThread(hThread
, NULL
);
295 /* Failed to create a new static thread */
296 InterlockedDecrementUL(&CsrpStaticThreadCount
);
297 InterlockedDecrementUL(&CsrpDynamicThreadTotal
);
300 DPRINT1("Failing\n");
301 NtTerminateThread(hThread
, 0);
305 return STATUS_UNSUCCESSFUL
;
312 return STATUS_SUCCESS
;
316 * @name CsrApiRequestThread
318 * The CsrApiRequestThread routine handles incoming messages or connection
319 * requests on the CSR API LPC Port.
322 * System-default user-defined parameter. Unused.
324 * @return The thread exit code, if the thread is terminated.
326 * @remarks Before listening on the port, the routine will first attempt
327 * to connect to the user subsystem.
332 CsrApiRequestThread(IN PVOID Parameter
)
334 PTEB Teb
= NtCurrentTeb();
335 LARGE_INTEGER TimeOut
;
336 PCSR_THREAD CurrentThread
, CsrThread
;
338 CSR_REPLY_CODE ReplyCode
;
339 PCSR_API_MESSAGE ReplyMsg
;
340 CSR_API_MESSAGE ReceiveMsg
;
341 PCSR_PROCESS CsrProcess
;
342 PHARDERROR_MSG HardErrorMsg
;
344 PCSR_SERVER_DLL ServerDll
;
345 PCLIENT_DIED_MSG ClientDiedMsg
;
346 PDBGKM_MSG DebugMessage
;
347 ULONG ServerId
, ApiId
, MessageType
, i
;
350 /* Setup LPC loop port and message */
352 ReplyPort
= CsrApiPort
;
354 /* Connect to user32 */
355 while (!CsrConnectToUser())
357 /* Set up the timeout for the connect (30 seconds) */
358 TimeOut
.QuadPart
= -30 * 1000 * 1000 * 10;
360 /* Keep trying until we get a response */
361 Teb
->Win32ClientInfo
[0] = 0;
362 NtDelayExecution(FALSE
, &TimeOut
);
366 CurrentThread
= Teb
->CsrClientThread
;
368 /* If we got an event... */
371 /* Set it, to let stuff waiting on us load */
372 Status
= NtSetEvent((HANDLE
)Parameter
, NULL
);
373 ASSERT(NT_SUCCESS(Status
));
375 /* Increase the Thread Counts */
376 InterlockedIncrementUL(&CsrpStaticThreadCount
);
377 InterlockedIncrementUL(&CsrpDynamicThreadTotal
);
380 /* Now start the loop */
383 /* Make sure the real CID is set */
384 Teb
->RealClientId
= Teb
->ClientId
;
388 if (Teb
->CountOfOwnedCriticalSections
)
390 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
391 Teb
->CountOfOwnedCriticalSections
);
392 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
393 &ReceiveMsg
, ReplyMsg
);
398 /* Wait for a message to come through */
399 Status
= NtReplyWaitReceivePort(ReplyPort
,
404 /* Check if we didn't get success */
405 if (Status
!= STATUS_SUCCESS
)
407 /* Was it a failure or another success code? */
408 if (!NT_SUCCESS(Status
))
411 /* Check for specific status cases */
412 if ((Status
!= STATUS_INVALID_CID
) &&
413 (Status
!= STATUS_UNSUCCESSFUL
) &&
414 ((Status
!= STATUS_INVALID_HANDLE
) || (ReplyPort
== CsrApiPort
)))
416 /* Notify the debugger */
417 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
418 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort
, CsrApiPort
);
422 /* We failed big time, so start out fresh */
424 ReplyPort
= CsrApiPort
;
429 /* A strange "success" code, just try again */
430 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status
);
435 // ASSERT(ReceiveMsg.Header.u1.s1.TotalLength >= sizeof(PORT_MESSAGE));
436 // ASSERT(ReceiveMsg.Header.u1.s1.TotalLength < sizeof(ReceiveMsg));
438 /* Use whatever Client ID we got */
439 Teb
->RealClientId
= ReceiveMsg
.Header
.ClientId
;
441 /* Get the Message Type */
442 MessageType
= ReceiveMsg
.Header
.u2
.s2
.Type
;
444 /* Handle connection requests */
445 if (MessageType
== LPC_CONNECTION_REQUEST
)
447 /* Handle the Connection Request */
448 CsrApiHandleConnectionRequest(&ReceiveMsg
);
451 ReplyPort
= CsrApiPort
;
455 /* It's some other kind of request. Get the lock for the lookup */
456 CsrAcquireProcessLock();
458 /* Now do the lookup to get the CSR_THREAD */
459 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
,
460 &ReceiveMsg
.Header
.ClientId
);
462 /* Did we find a thread? */
465 /* This wasn't a CSR Thread, release lock */
466 CsrReleaseProcessLock();
468 /* If this was an exception, handle it */
469 if (MessageType
== LPC_EXCEPTION
)
471 ReplyMsg
= &ReceiveMsg
;
472 ReplyPort
= CsrApiPort
;
473 ReplyMsg
->Status
= DBG_CONTINUE
;
475 else if (MessageType
== LPC_PORT_CLOSED
||
476 MessageType
== LPC_CLIENT_DIED
)
478 /* The Client or Port are gone, loop again */
480 ReplyPort
= CsrApiPort
;
482 else if (MessageType
== LPC_ERROR_EVENT
)
484 /* If it's a hard error, handle this too */
485 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
487 /* Default it to unhandled */
488 HardErrorMsg
->Response
= ResponseNotHandled
;
490 /* Check if there are free api threads */
491 CsrpCheckRequestThreads();
492 if (CsrpStaticThreadCount
)
494 /* Loop every Server DLL */
495 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
497 /* Get the Server DLL */
498 ServerDll
= CsrLoadedServerDll
[i
];
500 /* Check if it's valid and if it has a Hard Error Callback */
501 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
504 ServerDll
->HardErrorCallback(NULL
/* == CsrThread */, HardErrorMsg
);
506 /* If it's handled, get out of here */
507 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
512 /* Increase the thread count */
513 InterlockedIncrementUL(&CsrpStaticThreadCount
);
515 /* If the response was 0xFFFFFFFF, we'll ignore it */
516 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
519 ReplyPort
= CsrApiPort
;
523 ReplyMsg
= &ReceiveMsg
;
524 ReplyPort
= CsrApiPort
;
527 else if (MessageType
== LPC_REQUEST
)
529 /* This is an API Message coming from a non-CSR Thread */
530 ReplyMsg
= &ReceiveMsg
;
531 ReplyPort
= CsrApiPort
;
532 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
534 else if (MessageType
== LPC_DATAGRAM
)
536 /* This is an API call, get the Server ID */
537 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
539 /* Make sure that the ID is within limits, and the Server DLL loaded */
541 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
542 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
544 /* We are beyond the Maximum Server ID */
546 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
547 ServerId
, ServerDll
);
548 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
552 ReplyPort
= CsrApiPort
;
556 /* Get the API ID, normalized with our Base ID */
557 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
559 /* Make sure that the ID is within limits, and the entry exists */
560 if (ApiId
>= ServerDll
->HighestApiSupported
)
562 /* We are beyond the Maximum API ID, or it doesn't exist */
563 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
564 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
567 ReplyPort
= CsrApiPort
;
575 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
576 Teb
->ClientId
.UniqueThread
,
577 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
578 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
579 ServerDll
->NameTable
[ApiId
],
585 ReceiveMsg
.Status
= STATUS_SUCCESS
;
587 /* Validation complete, start SEH */
590 /* Make sure we have enough threads */
591 CsrpCheckRequestThreads();
593 /* Call the API and get the reply code */
595 ReplyPort
= CsrApiPort
;
596 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &ReplyCode
);
598 /* Increase the static thread count */
599 InterlockedIncrementUL(&CsrpStaticThreadCount
);
601 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
604 ReplyPort
= CsrApiPort
;
610 /* Some other ignored message type */
612 ReplyPort
= CsrApiPort
;
619 /* We have a valid thread, was this an LPC Request? */
620 if (MessageType
!= LPC_REQUEST
)
622 /* It's not an API, check if the client died */
623 if (MessageType
== LPC_CLIENT_DIED
)
625 /* Get the information and check if it matches our thread */
626 ClientDiedMsg
= (PCLIENT_DIED_MSG
)&ReceiveMsg
;
627 if (ClientDiedMsg
->CreateTime
.QuadPart
== CsrThread
->CreateTime
.QuadPart
)
629 /* Now we reply to the dying client */
630 ReplyPort
= CsrThread
->Process
->ClientPort
;
632 /* Reference the thread */
633 CsrLockedReferenceThread(CsrThread
);
635 /* Destroy the thread in the API Message */
636 CsrDestroyThread(&ReceiveMsg
.Header
.ClientId
);
638 /* Check if the thread was actually ourselves */
639 if (CsrProcess
->ThreadCount
== 1)
641 /* Kill the process manually here */
642 CsrDestroyProcess(&CsrThread
->ClientId
, 0);
645 /* Remove our extra reference */
646 CsrLockedDereferenceThread(CsrThread
);
649 /* Release the lock and keep looping */
650 CsrReleaseProcessLock();
653 ReplyPort
= CsrApiPort
;
657 /* Reference the thread and release the lock */
658 CsrLockedReferenceThread(CsrThread
);
659 CsrReleaseProcessLock();
661 /* Check if this was an exception */
662 if (MessageType
== LPC_EXCEPTION
)
664 /* Kill the process */
665 NtTerminateProcess(CsrProcess
->ProcessHandle
, STATUS_ABANDONED
);
667 /* Destroy it from CSR */
668 CsrDestroyProcess(&ReceiveMsg
.Header
.ClientId
, STATUS_ABANDONED
);
670 /* Return a Debug Message */
671 DebugMessage
= (PDBGKM_MSG
)&ReceiveMsg
;
672 DebugMessage
->ReturnedStatus
= DBG_CONTINUE
;
673 ReplyMsg
= &ReceiveMsg
;
674 ReplyPort
= CsrApiPort
;
676 /* Remove our extra reference */
677 CsrDereferenceThread(CsrThread
);
679 else if (MessageType
== LPC_ERROR_EVENT
)
681 /* If it's a hard error, handle this too */
682 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
684 /* Default it to unhandled */
685 HardErrorMsg
->Response
= ResponseNotHandled
;
687 /* Check if there are free api threads */
688 CsrpCheckRequestThreads();
689 if (CsrpStaticThreadCount
)
691 /* Loop every Server DLL */
692 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
694 /* Get the Server DLL */
695 ServerDll
= CsrLoadedServerDll
[i
];
697 /* Check if it's valid and if it has a Hard Error Callback */
698 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
701 ServerDll
->HardErrorCallback(CsrThread
, HardErrorMsg
);
703 /* If it's handled, get out of here */
704 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
709 /* Increase the thread count */
710 InterlockedIncrementUL(&CsrpStaticThreadCount
);
712 /* If the response was 0xFFFFFFFF, we'll ignore it */
713 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
716 ReplyPort
= CsrApiPort
;
720 CsrDereferenceThread(CsrThread
);
721 ReplyMsg
= &ReceiveMsg
;
722 ReplyPort
= CsrApiPort
;
728 CsrDereferenceThread(CsrThread
);
736 /* We got an API Request */
737 CsrLockedReferenceThread(CsrThread
);
738 CsrReleaseProcessLock();
740 /* This is an API call, get the Server ID */
741 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
743 /* Make sure that the ID is within limits, and the Server DLL loaded */
745 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
746 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
748 /* We are beyond the Maximum Server ID */
750 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
751 ServerId
, ServerDll
);
752 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
755 ReplyPort
= CsrApiPort
;
756 ReplyMsg
= &ReceiveMsg
;
757 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
758 CsrDereferenceThread(CsrThread
);
762 /* Get the API ID, normalized with our Base ID */
763 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
765 /* Make sure that the ID is within limits, and the entry exists */
766 if (ApiId
>= ServerDll
->HighestApiSupported
)
768 /* We are beyond the Maximum API ID, or it doesn't exist */
769 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
770 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
773 ReplyPort
= CsrApiPort
;
774 ReplyMsg
= &ReceiveMsg
;
775 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
776 CsrDereferenceThread(CsrThread
);
783 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x, Process %08x - %08x\n",
784 Teb
->ClientId
.UniqueThread
,
785 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
786 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
787 ServerDll
->NameTable
[ApiId
],
795 ReplyMsg
= &ReceiveMsg
;
796 ReceiveMsg
.Status
= STATUS_SUCCESS
;
798 /* Now we reply to a particular client */
799 ReplyPort
= CsrThread
->Process
->ClientPort
;
801 /* Check if there's a capture buffer */
802 if (ReceiveMsg
.CsrCaptureData
)
804 /* Capture the arguments */
805 if (!CsrCaptureArguments(CsrThread
, &ReceiveMsg
))
807 /* Ignore this message if we failed to get the arguments */
808 CsrDereferenceThread(CsrThread
);
813 /* Validation complete, start SEH */
816 /* Make sure we have enough threads */
817 CsrpCheckRequestThreads();
819 Teb
->CsrClientThread
= CsrThread
;
821 /* Call the API, get the reply code and return the result */
822 ReplyCode
= CsrReplyImmediately
;
823 ReplyMsg
->Status
= ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &ReplyCode
);
825 /* Increase the static thread count */
826 InterlockedIncrementUL(&CsrpStaticThreadCount
);
828 Teb
->CsrClientThread
= CurrentThread
;
830 if (ReplyCode
== CsrReplyAlreadySent
)
832 if (ReceiveMsg
.CsrCaptureData
)
834 CsrReleaseCapturedArguments(&ReceiveMsg
);
837 ReplyPort
= CsrApiPort
;
838 CsrDereferenceThread(CsrThread
);
840 else if (ReplyCode
== CsrReplyDeadClient
)
842 /* Reply to the death message */
844 Status2
= NtReplyPort(ReplyPort
, &ReplyMsg
->Header
);
845 if (!NT_SUCCESS(Status2
))
846 DPRINT1("CSRSS: Error while replying to the death message, Status 0x%lx\n", Status2
);
848 /* Reply back to the API port now */
850 ReplyPort
= CsrApiPort
;
851 CsrDereferenceThread(CsrThread
);
853 else if (ReplyCode
== CsrReplyPending
)
856 ReplyPort
= CsrApiPort
;
860 if (ReceiveMsg
.CsrCaptureData
)
862 CsrReleaseCapturedArguments(&ReceiveMsg
);
864 CsrDereferenceThread(CsrThread
);
867 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
870 ReplyPort
= CsrApiPort
;
875 /* We're out of the loop for some reason, terminate! */
876 NtTerminateThread(NtCurrentThread(), Status
);
881 * @name CsrApiPortInitialize
883 * The CsrApiPortInitialize routine initializes the LPC Port used for
884 * communications with the Client/Server Runtime (CSR) and initializes the
885 * static thread that will handle connection requests and APIs.
889 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
896 CsrApiPortInitialize(VOID
)
899 OBJECT_ATTRIBUTES ObjectAttributes
;
901 HANDLE hRequestEvent
, hThread
;
903 PLIST_ENTRY ListHead
, NextEntry
;
904 PCSR_THREAD ServerThread
;
906 /* Calculate how much space we'll need for the Port Name */
907 Size
= CsrDirectoryName
.Length
+ sizeof(CSR_PORT_NAME
) + sizeof(WCHAR
);
909 /* Create the buffer for it */
910 CsrApiPortName
.Buffer
= RtlAllocateHeap(CsrHeap
, 0, Size
);
911 if (!CsrApiPortName
.Buffer
) return STATUS_NO_MEMORY
;
913 /* Setup the rest of the empty string */
914 CsrApiPortName
.Length
= 0;
915 CsrApiPortName
.MaximumLength
= (USHORT
)Size
;
916 RtlAppendUnicodeStringToString(&CsrApiPortName
, &CsrDirectoryName
);
917 RtlAppendUnicodeToString(&CsrApiPortName
, UNICODE_PATH_SEP
);
918 RtlAppendUnicodeToString(&CsrApiPortName
, CSR_PORT_NAME
);
921 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName
);
922 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
923 sizeof(CSR_API_CONNECTINFO
), sizeof(CSR_API_MESSAGE
));
926 /* FIXME: Create a Security Descriptor */
928 /* Initialize the Attributes */
929 InitializeObjectAttributes(&ObjectAttributes
,
933 NULL
/* FIXME: Use the Security Descriptor */);
935 /* Create the Port Object */
936 Status
= NtCreatePort(&CsrApiPort
,
938 sizeof(CSR_API_CONNECTINFO
),
939 sizeof(CSR_API_MESSAGE
),
941 if (NT_SUCCESS(Status
))
943 /* Create the event the Port Thread will use */
944 Status
= NtCreateEvent(&hRequestEvent
,
947 SynchronizationEvent
,
949 if (NT_SUCCESS(Status
))
951 /* Create the Request Thread */
952 Status
= RtlCreateUserThread(NtCurrentProcess(),
958 (PVOID
)CsrApiRequestThread
,
959 (PVOID
)hRequestEvent
,
962 if (NT_SUCCESS(Status
))
964 /* Add this as a static thread to CSRSRV */
965 CsrAddStaticServerThread(hThread
, &ClientId
, CsrThreadIsServerThread
);
967 /* Get the Thread List Pointers */
968 ListHead
= &CsrRootProcess
->ThreadList
;
969 NextEntry
= ListHead
->Flink
;
971 /* Start looping the list */
972 while (NextEntry
!= ListHead
)
975 ServerThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
978 Status
= NtResumeThread(ServerThread
->ThreadHandle
, NULL
);
980 /* Is this a Server Thread? */
981 if (ServerThread
->Flags
& CsrThreadIsServerThread
)
983 /* If so, then wait for it to initialize */
984 Status
= NtWaitForSingleObject(hRequestEvent
, FALSE
, NULL
);
985 ASSERT(NT_SUCCESS(Status
));
989 NextEntry
= NextEntry
->Flink
;
992 /* We don't need this anymore */
993 NtClose(hRequestEvent
);
1003 * @name CsrConnectToUser
1006 * The CsrConnectToUser connects to the User subsystem.
1010 * @return A pointer to the CSR Thread
1017 CsrConnectToUser(VOID
)
1020 ANSI_STRING DllName
;
1021 UNICODE_STRING TempName
;
1024 PTEB Teb
= NtCurrentTeb();
1025 PCSR_THREAD CsrThread
;
1028 /* Check if we didn't already find it */
1029 if (!CsrClientThreadSetup
)
1031 /* Get the DLL Handle for user32.dll */
1032 RtlInitAnsiString(&DllName
, "user32");
1033 RtlAnsiStringToUnicodeString(&TempName
, &DllName
, TRUE
);
1034 Status
= LdrGetDllHandle(NULL
,
1038 RtlFreeUnicodeString(&TempName
);
1040 /* If we got the handle, get the Client Thread Startup Entrypoint */
1041 if (NT_SUCCESS(Status
))
1043 RtlInitAnsiString(&StartupName
,"ClientThreadSetup");
1044 Status
= LdrGetProcedureAddress(hUser32
,
1047 (PVOID
)&CsrClientThreadSetup
);
1051 /* Connect to user32 */
1054 Connected
= CsrClientThreadSetup();
1056 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1064 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1068 /* Save pointer to this thread in TEB */
1069 CsrAcquireProcessLock();
1070 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1071 CsrReleaseProcessLock();
1072 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1079 * @name CsrQueryApiPort
1082 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1086 * @return A handle to the port.
1093 CsrQueryApiPort(VOID
)
1099 * @name CsrCaptureArguments
1100 * @implemented NT5.1
1102 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1103 * re-captures it into a server CSR Capture Buffer.
1106 * Pointer to the CSR Thread performing the validation.
1109 * Pointer to the CSR API Message containing the Capture Buffer
1110 * that needs to be validated.
1112 * @return TRUE if validation succeeded, FALSE otherwise.
1119 CsrCaptureArguments(IN PCSR_THREAD CsrThread
,
1120 IN PCSR_API_MESSAGE ApiMessage
)
1122 PCSR_PROCESS CsrProcess
= CsrThread
->Process
;
1123 PCSR_CAPTURE_BUFFER ClientCaptureBuffer
, ServerCaptureBuffer
= NULL
;
1124 ULONG_PTR EndOfClientBuffer
;
1125 SIZE_T SizeOfBufferThroughOffsetsArray
;
1126 SIZE_T BufferDistance
;
1129 PULONG_PTR OffsetPointer
;
1130 ULONG_PTR CurrentOffset
;
1132 /* Get the buffer we got from whoever called NTDLL */
1133 ClientCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1135 /* Use SEH to validate and capture the client buffer */
1138 /* Check whether at least the buffer's header is inside our mapped section */
1139 if ( ((ULONG_PTR
)ClientCaptureBuffer
< CsrProcess
->ClientViewBase
) ||
1140 (((ULONG_PTR
)ClientCaptureBuffer
+ FIELD_OFFSET(CSR_CAPTURE_BUFFER
, PointerOffsetsArray
))
1141 >= CsrProcess
->ClientViewBounds
) )
1144 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView 1\n");
1145 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
1147 /* Return failure */
1148 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1149 _SEH2_YIELD(return FALSE
);
1152 /* Capture the buffer length */
1153 Length
= ((volatile CSR_CAPTURE_BUFFER
*)ClientCaptureBuffer
)->Size
;
1156 * Now check if the remaining of the buffer is inside our mapped section.
1157 * Take also care for any possible wrap-around of the buffer end-address.
1159 EndOfClientBuffer
= (ULONG_PTR
)ClientCaptureBuffer
+ Length
;
1160 if ( (EndOfClientBuffer
< (ULONG_PTR
)ClientCaptureBuffer
) ||
1161 (EndOfClientBuffer
>= CsrProcess
->ClientViewBounds
) )
1164 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView 2\n");
1165 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
1167 /* Return failure */
1168 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1169 _SEH2_YIELD(return FALSE
);
1172 /* Capture the pointer count */
1173 PointerCount
= ((volatile CSR_CAPTURE_BUFFER
*)ClientCaptureBuffer
)->PointerCount
;
1176 * Check whether the total buffer size and the pointer count are consistent
1177 * -- the array of offsets must be contained inside the buffer.
1179 SizeOfBufferThroughOffsetsArray
=
1180 FIELD_OFFSET(CSR_CAPTURE_BUFFER
, PointerOffsetsArray
) +
1181 (PointerCount
* sizeof(PVOID
));
1182 if ( (PointerCount
> MAXUSHORT
) ||
1183 (SizeOfBufferThroughOffsetsArray
> Length
) )
1186 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", ClientCaptureBuffer
);
1187 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
1189 /* Return failure */
1190 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1191 _SEH2_YIELD(return FALSE
);
1194 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1197 DPRINT1("*** CSRSS: Took exception during capture %x\n", _SEH2_GetExceptionCode());
1198 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
1200 /* Return failure */
1201 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1202 _SEH2_YIELD(return FALSE
);
1206 /* We validated the client buffer, now allocate the server buffer */
1207 ServerCaptureBuffer
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, Length
);
1208 if (!ServerCaptureBuffer
)
1210 /* We're out of memory */
1211 ApiMessage
->Status
= STATUS_NO_MEMORY
;
1216 * Copy the client's buffer and ensure we use the correct buffer length
1217 * and pointer count we captured and used for validation earlier on.
1221 RtlMoveMemory(ServerCaptureBuffer
, ClientCaptureBuffer
, Length
);
1223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1226 DPRINT1("*** CSRSS: Took exception during capture %x\n", _SEH2_GetExceptionCode());
1227 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
1229 /* Failure, free the buffer and return */
1230 RtlFreeHeap(CsrHeap
, 0, ServerCaptureBuffer
);
1231 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1232 _SEH2_YIELD(return FALSE
);
1236 ServerCaptureBuffer
->Size
= Length
;
1237 ServerCaptureBuffer
->PointerCount
= PointerCount
;
1239 /* Calculate the difference between our buffer and the client's */
1240 BufferDistance
= (ULONG_PTR
)ServerCaptureBuffer
- (ULONG_PTR
)ClientCaptureBuffer
;
1243 * All the pointer offsets correspond to pointers that point
1244 * to the server data buffer instead of the client one.
1246 // PointerCount = ServerCaptureBuffer->PointerCount;
1247 OffsetPointer
= ServerCaptureBuffer
->PointerOffsetsArray
;
1248 while (PointerCount
--)
1250 CurrentOffset
= *OffsetPointer
;
1252 if (CurrentOffset
!= 0)
1255 * Check whether the offset is pointer-aligned and whether
1256 * it points inside CSR_API_MESSAGE::Data.ApiMessageData.
1258 if ( ((CurrentOffset
& (sizeof(PVOID
)-1)) != 0) ||
1259 (CurrentOffset
< FIELD_OFFSET(CSR_API_MESSAGE
, Data
.ApiMessageData
)) ||
1260 (CurrentOffset
>= sizeof(CSR_API_MESSAGE
)) )
1263 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of message\n");
1264 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
1266 /* Invalid pointer, fail */
1267 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1271 /* Get the pointer corresponding to the offset */
1272 CurrentOffset
+= (ULONG_PTR
)ApiMessage
;
1274 /* Validate the bounds of the current pointed pointer */
1275 if ( (*(PULONG_PTR
)CurrentOffset
>= ((ULONG_PTR
)ClientCaptureBuffer
+
1276 SizeOfBufferThroughOffsetsArray
)) &&
1277 (*(PULONG_PTR
)CurrentOffset
<= (EndOfClientBuffer
- sizeof(PVOID
))) )
1279 /* Modify the pointed pointer to take into account its new position */
1280 *(PULONG_PTR
)CurrentOffset
+= BufferDistance
;
1285 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1286 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
1288 /* Invalid pointer, fail */
1289 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1297 /* Check if we got success */
1298 if (ApiMessage
->Status
!= STATUS_SUCCESS
)
1300 /* Failure, free the buffer and return */
1301 RtlFreeHeap(CsrHeap
, 0, ServerCaptureBuffer
);
1306 /* Success, save the previous buffer and use the server capture buffer */
1307 ServerCaptureBuffer
->PreviousCaptureBuffer
= ClientCaptureBuffer
;
1308 ApiMessage
->CsrCaptureData
= ServerCaptureBuffer
;
1316 * @name CsrReleaseCapturedArguments
1317 * @implemented NT5.1
1319 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1320 * that was previously captured with CsrCaptureArguments.
1323 * Pointer to the CSR API Message containing the Capture Buffer
1324 * that needs to be released.
1333 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage
)
1335 PCSR_CAPTURE_BUFFER ServerCaptureBuffer
, ClientCaptureBuffer
;
1336 SIZE_T BufferDistance
;
1338 PULONG_PTR OffsetPointer
;
1339 ULONG_PTR CurrentOffset
;
1341 /* Get the server capture buffer */
1342 ServerCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1344 /* Do not continue if there is no captured buffer */
1345 if (!ServerCaptureBuffer
) return;
1347 /* If there is one, get the corresponding client capture buffer */
1348 ClientCaptureBuffer
= ServerCaptureBuffer
->PreviousCaptureBuffer
;
1350 /* Free the previous one and use again the client capture buffer */
1351 ServerCaptureBuffer
->PreviousCaptureBuffer
= NULL
;
1352 ApiMessage
->CsrCaptureData
= ClientCaptureBuffer
;
1354 /* Calculate the difference between our buffer and the client's */
1355 BufferDistance
= (ULONG_PTR
)ServerCaptureBuffer
- (ULONG_PTR
)ClientCaptureBuffer
;
1358 * All the pointer offsets correspond to pointers that point
1359 * to the client data buffer instead of the server one (reverse
1360 * the logic of CsrCaptureArguments()).
1362 PointerCount
= ServerCaptureBuffer
->PointerCount
;
1363 OffsetPointer
= ServerCaptureBuffer
->PointerOffsetsArray
;
1364 while (PointerCount
--)
1366 CurrentOffset
= *OffsetPointer
;
1368 if (CurrentOffset
!= 0)
1370 /* Get the pointer corresponding to the offset */
1371 CurrentOffset
+= (ULONG_PTR
)ApiMessage
;
1373 /* Modify the pointed pointer to take into account its new position */
1374 *(PULONG_PTR
)CurrentOffset
-= BufferDistance
;
1380 /* Copy the data back into the client buffer */
1383 RtlMoveMemory(ClientCaptureBuffer
, ServerCaptureBuffer
, ServerCaptureBuffer
->Size
);
1385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1388 DPRINT1("*** CSRSS: Took exception during release %x\n", _SEH2_GetExceptionCode());
1389 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
1391 /* Return failure */
1392 ApiMessage
->Status
= _SEH2_GetExceptionCode();
1396 /* Free our allocated buffer */
1397 RtlFreeHeap(CsrHeap
, 0, ServerCaptureBuffer
);
1401 * @name CsrValidateMessageBuffer
1402 * @implemented NT5.1
1404 * The CsrValidateMessageBuffer routine validates a captured message buffer
1405 * present in the CSR Api Message
1408 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1411 * Pointer to the message buffer to validate.
1413 * @param ElementCount
1414 * Number of elements contained in the message buffer.
1416 * @param ElementSize
1417 * Size of each element.
1419 * @return TRUE if validation succeeded, FALSE otherwise.
1426 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage
,
1428 IN ULONG ElementCount
,
1429 IN ULONG ElementSize
)
1431 PCSR_CAPTURE_BUFFER CaptureBuffer
= ApiMessage
->CsrCaptureData
;
1432 SIZE_T BufferDistance
= (ULONG_PTR
)Buffer
- (ULONG_PTR
)ApiMessage
;
1434 PULONG_PTR OffsetPointer
;
1437 * Check whether we have a valid buffer pointer, elements
1438 * of non-trivial size and that we don't overflow.
1440 if (!Buffer
|| ElementSize
== 0 ||
1441 (ULONGLONG
)ElementCount
* ElementSize
> (ULONGLONG
)MAXULONG
)
1446 /* Check if didn't get a buffer and there aren't any arguments to check */
1447 // if (!*Buffer && (ElementCount * ElementSize == 0))
1448 if (!*Buffer
&& ElementCount
== 0) // Here ElementSize != 0 therefore only ElementCount can be == 0
1451 /* Check if we have no capture buffer */
1454 /* In this case, succeed only if the caller is CSRSS */
1455 if (NtCurrentTeb()->ClientId
.UniqueProcess
==
1456 ApiMessage
->Header
.ClientId
.UniqueProcess
)
1463 /* Make sure that there is still space left in the capture buffer */
1464 if ((CaptureBuffer
->Size
- (ULONG_PTR
)*Buffer
+ (ULONG_PTR
)CaptureBuffer
) >=
1465 (ElementCount
* ElementSize
))
1467 /* Perform the validation test */
1468 PointerCount
= CaptureBuffer
->PointerCount
;
1469 OffsetPointer
= CaptureBuffer
->PointerOffsetsArray
;
1470 while (PointerCount
--)
1473 * Find in the array, the pointer offset (from the
1474 * API message) that corresponds to the buffer.
1476 if (*OffsetPointer
== BufferDistance
)
1487 DPRINT1("CSRSRV: Bad message buffer %p\n", ApiMessage
);
1488 if (NtCurrentPeb()->BeingDebugged
) DbgBreakPoint();
1494 * @name CsrValidateMessageString
1495 * @implemented NT5.1
1497 * The CsrValidateMessageString validates a captured Wide-Character String
1498 * present in a CSR API Message.
1501 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1503 * @param MessageString
1504 * Pointer to the buffer containing the string to validate.
1506 * @return TRUE if validation succeeded, FALSE otherwise.
1513 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage
,
1514 IN PWSTR
*MessageString
)
1518 return CsrValidateMessageBuffer(ApiMessage
,
1519 (PVOID
*)MessageString
,
1520 wcslen(*MessageString
) + 1,