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 *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 BOOLEAN (*CsrClientThreadSetup
)(VOID
) = NULL
;
20 UNICODE_STRING CsrApiPortName
;
21 volatile LONG CsrpStaticThreadCount
;
22 volatile LONG CsrpDynamicThreadTotal
;
23 extern ULONG CsrMaxApiRequestThreads
;
25 /* FUNCTIONS ******************************************************************/
28 * @name CsrCallServerFromServer
31 * The CsrCallServerFromServer routine calls a CSR API from within a server.
32 * It avoids using LPC messages since the request isn't coming from a client.
35 * Pointer to the CSR API Message to send to the server.
38 * Pointer to the CSR API Message to receive from the server.
40 * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
41 * if the ApiNumber is invalid, or STATUS_ACCESS_VIOLATION if there
42 * was a problem executing the API.
49 CsrCallServerFromServer(IN PCSR_API_MESSAGE ReceiveMsg
,
50 IN OUT PCSR_API_MESSAGE ReplyMsg
)
53 PCSR_SERVER_DLL ServerDll
;
55 CSR_REPLY_CODE ReplyCode
= CsrReplyImmediately
;
57 /* Get the Server ID */
58 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
->ApiNumber
);
60 /* Make sure that the ID is within limits, and the Server DLL loaded */
61 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
62 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
64 /* We are beyond the Maximum Server ID */
65 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId
, ServerDll
);
66 ReplyMsg
->Status
= (ULONG
)STATUS_ILLEGAL_FUNCTION
;
67 return STATUS_ILLEGAL_FUNCTION
;
71 /* Get the API ID, normalized with our Base ID */
72 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
->ApiNumber
) - ServerDll
->ApiBase
;
74 /* Make sure that the ID is within limits, and the entry exists */
75 if ((ApiId
>= ServerDll
->HighestApiSupported
) ||
76 ((ServerDll
->ValidTable
) && !(ServerDll
->ValidTable
[ApiId
])))
78 /* We are beyond the Maximum API ID, or it doesn't exist */
79 DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
80 "invalid API to call from the server.\n",
81 ServerDll
->ValidTable
[ApiId
],
82 ((ServerDll
->NameTable
) && (ServerDll
->NameTable
[ApiId
])) ?
83 ServerDll
->NameTable
[ApiId
] : "*** UNKNOWN ***", &ServerDll
->Name
);
85 ReplyMsg
->Status
= (ULONG
)STATUS_ILLEGAL_FUNCTION
;
86 return STATUS_ILLEGAL_FUNCTION
;
92 DPRINT1("CSRSS: %s Api Request received from server process\n",
93 ServerDll
->NameTable
[ApiId
]);
96 /* Validation complete, start SEH */
99 /* Call the API, get the reply code and return the result */
100 ReplyMsg
->Status
= ServerDll
->DispatchTable
[ApiId
](ReceiveMsg
, &ReplyCode
);
102 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
104 /* If we got an exception, return access violation */
105 ReplyMsg
->Status
= STATUS_ACCESS_VIOLATION
;
110 return STATUS_SUCCESS
;
114 * @name CsrApiHandleConnectionRequest
116 * The CsrApiHandleConnectionRequest routine handles and accepts a new
117 * connection request to the CSR API LPC Port.
120 * Pointer to the incoming CSR API Message which contains the
121 * connection request.
123 * @return STATUS_SUCCESS in case of success, or status code which caused
124 * the routine to error.
126 * @remarks This routine is responsible for attaching the Shared Section to
127 * new clients connecting to CSR.
132 CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage
)
134 PCSR_THREAD CsrThread
= NULL
;
135 PCSR_PROCESS CsrProcess
= NULL
;
136 NTSTATUS Status
= STATUS_SUCCESS
;
137 PCSR_CONNECTION_INFO ConnectInfo
= &ApiMessage
->ConnectionInfo
;
138 BOOLEAN AllowConnection
= FALSE
;
139 REMOTE_PORT_VIEW RemotePortView
;
142 /* Acquire the Process Lock */
143 CsrAcquireProcessLock();
145 /* Lookup the CSR Thread */
146 CsrThread
= CsrLocateThreadByClientId(NULL
, &ApiMessage
->Header
.ClientId
);
148 /* Check if we have a thread */
151 /* Get the Process */
152 CsrProcess
= CsrThread
->Process
;
154 /* Make sure we have a Process as well */
157 /* Reference the Process */
158 CsrLockedReferenceProcess(CsrThread
->Process
);
160 /* Release the lock */
161 CsrReleaseProcessLock();
163 /* Duplicate the Object Directory */
164 Status
= NtDuplicateObject(NtCurrentProcess(),
166 CsrProcess
->ProcessHandle
,
167 &ConnectInfo
->ObjectDirectory
,
170 DUPLICATE_SAME_ACCESS
|
171 DUPLICATE_SAME_ATTRIBUTES
);
173 /* Acquire the lock */
174 CsrAcquireProcessLock();
176 /* Check for success */
177 if (NT_SUCCESS(Status
))
179 /* Attach the Shared Section */
180 Status
= CsrSrvAttachSharedSection(CsrProcess
, ConnectInfo
);
182 /* Check how this went */
183 if (NT_SUCCESS(Status
)) AllowConnection
= TRUE
;
186 /* Dereference the project */
187 CsrLockedDereferenceProcess(CsrProcess
);
191 /* Release the lock */
192 CsrReleaseProcessLock();
194 /* Setup the Port View Structure */
195 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
196 RemotePortView
.ViewSize
= 0;
197 RemotePortView
.ViewBase
= NULL
;
199 /* Save the Process ID */
200 ConnectInfo
->ProcessId
= NtCurrentTeb()->ClientId
.UniqueProcess
;
202 /* Accept the Connection */
203 Status
= NtAcceptConnectPort(&ServerPort
,
204 AllowConnection
? UlongToPtr(CsrProcess
->SequenceNumber
) : 0,
209 if (!NT_SUCCESS(Status
))
211 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status
);
213 else if (AllowConnection
)
217 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
218 ApiMessage
->Header
.ClientId
.UniqueProcess
,
219 ApiMessage
->Header
.ClientId
.UniqueThread
,
220 RemotePortView
.ViewBase
,
221 RemotePortView
.ViewSize
);
224 /* Set some Port Data in the Process */
225 CsrProcess
->ClientPort
= ServerPort
;
226 CsrProcess
->ClientViewBase
= (ULONG_PTR
)RemotePortView
.ViewBase
;
227 CsrProcess
->ClientViewBounds
= (ULONG_PTR
)((ULONG_PTR
)RemotePortView
.ViewBase
+
228 (ULONG_PTR
)RemotePortView
.ViewSize
);
230 /* Complete the connection */
231 Status
= NtCompleteConnectPort(ServerPort
);
232 if (!NT_SUCCESS(Status
))
234 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status
);
239 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
240 ApiMessage
->Header
.ClientId
.UniqueProcess
,
241 ApiMessage
->Header
.ClientId
.UniqueThread
);
244 /* Return status to caller */
249 * @name CsrpCheckRequestThreads
251 * The CsrpCheckRequestThreads routine checks if there are no more threads
252 * to handle CSR API Requests, and creates a new thread if possible, to
257 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
258 * if a new thread couldn't be created.
265 CsrpCheckRequestThreads(VOID
)
271 /* Decrease the count, and see if we're out */
272 if (!(_InterlockedDecrement(&CsrpStaticThreadCount
)))
274 /* Check if we've still got space for a Dynamic Thread */
275 if (CsrpDynamicThreadTotal
< CsrMaxApiRequestThreads
)
277 /* Create a new dynamic thread */
278 Status
= RtlCreateUserThread(NtCurrentProcess(),
284 (PVOID
)CsrApiRequestThread
,
289 if (NT_SUCCESS(Status
))
291 /* Increase the thread counts */
292 _InterlockedIncrement(&CsrpStaticThreadCount
);
293 _InterlockedIncrement(&CsrpDynamicThreadTotal
);
295 /* Add a new server thread */
296 if (CsrAddStaticServerThread(hThread
,
298 CsrThreadIsServerThread
))
301 NtResumeThread(hThread
, NULL
);
305 /* Failed to create a new static thread */
306 _InterlockedDecrement(&CsrpStaticThreadCount
);
307 _InterlockedDecrement(&CsrpDynamicThreadTotal
);
310 DPRINT1("Failing\n");
311 NtTerminateThread(hThread
, 0);
315 return STATUS_UNSUCCESSFUL
;
322 return STATUS_SUCCESS
;
326 * @name CsrApiRequestThread
328 * The CsrApiRequestThread routine handles incoming messages or connection
329 * requests on the CSR API LPC Port.
332 * System-default user-defined parameter. Unused.
334 * @return The thread exit code, if the thread is terminated.
336 * @remarks Before listening on the port, the routine will first attempt
337 * to connect to the user subsystem.
342 CsrApiRequestThread(IN PVOID Parameter
)
344 PTEB Teb
= NtCurrentTeb();
345 LARGE_INTEGER TimeOut
;
346 PCSR_THREAD CurrentThread
, CsrThread
;
348 CSR_REPLY_CODE ReplyCode
;
349 PCSR_API_MESSAGE ReplyMsg
;
350 CSR_API_MESSAGE ReceiveMsg
;
351 PCSR_PROCESS CsrProcess
;
352 PHARDERROR_MSG HardErrorMsg
;
354 PCSR_SERVER_DLL ServerDll
;
355 PCLIENT_DIED_MSG ClientDiedMsg
;
356 PDBGKM_MSG DebugMessage
;
357 ULONG ServerId
, ApiId
, MessageType
, i
;
360 /* Setup LPC loop port and message */
362 ReplyPort
= CsrApiPort
;
364 /* Connect to user32 */
365 while (!CsrConnectToUser())
367 /* Set up the timeout for the connect (30 seconds) */
368 TimeOut
.QuadPart
= -30 * 1000 * 1000 * 10;
370 /* Keep trying until we get a response */
371 Teb
->Win32ClientInfo
[0] = 0;
372 NtDelayExecution(FALSE
, &TimeOut
);
376 CurrentThread
= Teb
->CsrClientThread
;
378 /* If we got an event... */
381 /* Set it, to let stuff waiting on us load */
382 Status
= NtSetEvent((HANDLE
)Parameter
, NULL
);
383 ASSERT(NT_SUCCESS(Status
));
385 /* Increase the Thread Counts */
386 _InterlockedIncrement(&CsrpStaticThreadCount
);
387 _InterlockedIncrement(&CsrpDynamicThreadTotal
);
390 /* Now start the loop */
393 /* Make sure the real CID is set */
394 Teb
->RealClientId
= Teb
->ClientId
;
397 if (Teb
->CountOfOwnedCriticalSections
)
399 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
400 Teb
->CountOfOwnedCriticalSections
);
401 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
402 &ReceiveMsg
, ReplyMsg
);
406 /* Wait for a message to come through */
407 Status
= NtReplyWaitReceivePort(ReplyPort
,
412 /* Check if we didn't get success */
413 if (Status
!= STATUS_SUCCESS
)
415 /* Was it a failure or another success code? */
416 if (!NT_SUCCESS(Status
))
418 /* Check for specific status cases */
419 if ((Status
!= STATUS_INVALID_CID
) &&
420 (Status
!= STATUS_UNSUCCESSFUL
) &&
421 ((Status
== STATUS_INVALID_HANDLE
) || (ReplyPort
== CsrApiPort
)))
423 /* Notify the debugger */
424 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
425 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort
, CsrApiPort
);
428 /* We failed big time, so start out fresh */
430 ReplyPort
= CsrApiPort
;
435 /* A bizare "success" code, just try again */
436 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status
);
441 /* Use whatever Client ID we got */
442 Teb
->RealClientId
= ReceiveMsg
.Header
.ClientId
;
444 /* Get the Message Type */
445 MessageType
= ReceiveMsg
.Header
.u2
.s2
.Type
;
447 /* Handle connection requests */
448 if (MessageType
== LPC_CONNECTION_REQUEST
)
450 /* Handle the Connection Request */
451 CsrApiHandleConnectionRequest(&ReceiveMsg
);
454 ReplyPort
= CsrApiPort
;
458 /* It's some other kind of request. Get the lock for the lookup */
459 CsrAcquireProcessLock();
461 /* Now do the lookup to get the CSR_THREAD */
462 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
,
463 &ReceiveMsg
.Header
.ClientId
);
465 /* Did we find a thread? */
468 /* This wasn't a CSR Thread, release lock */
469 CsrReleaseProcessLock();
471 /* If this was an exception, handle it */
472 if (MessageType
== LPC_EXCEPTION
)
474 ReplyMsg
= &ReceiveMsg
;
475 ReplyPort
= CsrApiPort
;
476 ReplyMsg
->Status
= DBG_CONTINUE
;
478 else if (MessageType
== LPC_PORT_CLOSED
||
479 MessageType
== LPC_CLIENT_DIED
)
481 /* The Client or Port are gone, loop again */
483 ReplyPort
= CsrApiPort
;
485 else if (MessageType
== LPC_ERROR_EVENT
)
487 /* If it's a hard error, handle this too */
488 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
490 /* Default it to unhandled */
491 HardErrorMsg
->Response
= ResponseNotHandled
;
493 /* Check if there are free api threads */
494 CsrpCheckRequestThreads();
495 if (CsrpStaticThreadCount
)
497 /* Loop every Server DLL */
498 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
500 /* Get the Server DLL */
501 ServerDll
= CsrLoadedServerDll
[i
];
503 /* Check if it's valid and if it has a Hard Error Callback */
504 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
507 ServerDll
->HardErrorCallback(NULL
/* == CsrThread */, HardErrorMsg
);
509 /* If it's handled, get out of here */
510 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
515 /* Increase the thread count */
516 _InterlockedIncrement(&CsrpStaticThreadCount
);
518 /* If the response was 0xFFFFFFFF, we'll ignore it */
519 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
522 ReplyPort
= CsrApiPort
;
526 ReplyMsg
= &ReceiveMsg
;
527 ReplyPort
= CsrApiPort
;
530 else if (MessageType
== LPC_REQUEST
)
532 /* This is an API Message coming from a non-CSR Thread */
533 ReplyMsg
= &ReceiveMsg
;
534 ReplyPort
= CsrApiPort
;
535 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
537 else if (MessageType
== LPC_DATAGRAM
)
539 /* This is an API call, get the Server ID */
540 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
542 /* Make sure that the ID is within limits, and the Server DLL loaded */
544 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
545 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
547 /* We are beyond the Maximum Server ID */
548 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
549 ServerId
, ServerDll
);
553 ReplyPort
= CsrApiPort
;
557 /* Get the API ID, normalized with our Base ID */
558 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
560 /* Make sure that the ID is within limits, and the entry exists */
561 if (ApiId
>= ServerDll
->HighestApiSupported
)
563 /* We are beyond the Maximum API ID, or it doesn't exist */
564 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
565 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
568 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
],
584 ReceiveMsg
.Status
= STATUS_SUCCESS
;
586 /* Validation complete, start SEH */
589 /* Make sure we have enough threads */
590 CsrpCheckRequestThreads();
592 /* Call the API and get the reply code */
594 ReplyPort
= CsrApiPort
;
595 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &ReplyCode
);
597 /* Increase the static thread count */
598 _InterlockedIncrement(&CsrpStaticThreadCount
);
600 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
603 ReplyPort
= CsrApiPort
;
609 /* Some other ignored message type */
611 ReplyPort
= CsrApiPort
;
618 /* We have a valid thread, was this an LPC Request? */
619 if (MessageType
!= LPC_REQUEST
)
621 /* It's not an API, check if the client died */
622 if (MessageType
== LPC_CLIENT_DIED
)
624 /* Get the information and check if it matches our thread */
625 ClientDiedMsg
= (PCLIENT_DIED_MSG
)&ReceiveMsg
;
626 if (ClientDiedMsg
->CreateTime
.QuadPart
== CsrThread
->CreateTime
.QuadPart
)
628 /* Now we reply to the dying client */
629 ReplyPort
= CsrThread
->Process
->ClientPort
;
631 /* Reference the thread */
632 CsrLockedReferenceThread(CsrThread
);
634 /* Destroy the thread in the API Message */
635 CsrDestroyThread(&ReceiveMsg
.Header
.ClientId
);
637 /* Check if the thread was actually ourselves */
638 if (CsrProcess
->ThreadCount
== 1)
640 /* Kill the process manually here */
641 CsrDestroyProcess(&CsrThread
->ClientId
, 0);
644 /* Remove our extra reference */
645 CsrLockedDereferenceThread(CsrThread
);
648 /* Release the lock and keep looping */
649 CsrReleaseProcessLock();
652 ReplyPort
= CsrApiPort
;
656 /* Reference the thread and release the lock */
657 CsrLockedReferenceThread(CsrThread
);
658 CsrReleaseProcessLock();
660 /* Check if this was an exception */
661 if (MessageType
== LPC_EXCEPTION
)
663 /* Kill the process */
664 NtTerminateProcess(CsrProcess
->ProcessHandle
, STATUS_ABANDONED
);
666 /* Destroy it from CSR */
667 CsrDestroyProcess(&ReceiveMsg
.Header
.ClientId
, STATUS_ABANDONED
);
669 /* Return a Debug Message */
670 DebugMessage
= (PDBGKM_MSG
)&ReceiveMsg
;
671 DebugMessage
->ReturnedStatus
= DBG_CONTINUE
;
672 ReplyMsg
= &ReceiveMsg
;
673 ReplyPort
= CsrApiPort
;
675 /* Remove our extra reference */
676 CsrDereferenceThread(CsrThread
);
678 else if (MessageType
== LPC_ERROR_EVENT
)
680 /* If it's a hard error, handle this too */
681 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
683 /* Default it to unhandled */
684 HardErrorMsg
->Response
= ResponseNotHandled
;
686 /* Check if there are free api threads */
687 CsrpCheckRequestThreads();
688 if (CsrpStaticThreadCount
)
690 /* Loop every Server DLL */
691 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
693 /* Get the Server DLL */
694 ServerDll
= CsrLoadedServerDll
[i
];
696 /* Check if it's valid and if it has a Hard Error Callback */
697 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
700 ServerDll
->HardErrorCallback(CsrThread
, HardErrorMsg
);
702 /* If it's handled, get out of here */
703 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
708 /* Increase the thread count */
709 _InterlockedIncrement(&CsrpStaticThreadCount
);
711 /* If the response was 0xFFFFFFFF, we'll ignore it */
712 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
715 ReplyPort
= CsrApiPort
;
719 CsrDereferenceThread(CsrThread
);
720 ReplyMsg
= &ReceiveMsg
;
721 ReplyPort
= CsrApiPort
;
727 CsrDereferenceThread(CsrThread
);
735 /* We got an API Request */
736 CsrLockedReferenceThread(CsrThread
);
737 CsrReleaseProcessLock();
739 /* This is an API call, get the Server ID */
740 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
742 /* Make sure that the ID is within limits, and the Server DLL loaded */
744 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
745 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
747 /* We are beyond the Maximum Server ID */
748 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
749 ServerId
, ServerDll
);
752 ReplyPort
= CsrApiPort
;
753 ReplyMsg
= &ReceiveMsg
;
754 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
755 CsrDereferenceThread(CsrThread
);
759 /* Get the API ID, normalized with our Base ID */
760 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
762 /* Make sure that the ID is within limits, and the entry exists */
763 if (ApiId
>= ServerDll
->HighestApiSupported
)
765 /* We are beyond the Maximum API ID, or it doesn't exist */
766 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
767 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
770 ReplyPort
= CsrApiPort
;
771 ReplyMsg
= &ReceiveMsg
;
772 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
773 CsrDereferenceThread(CsrThread
);
779 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x, Process %08x - %08x\n",
780 Teb
->ClientId
.UniqueThread
,
781 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
782 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
783 ServerDll
->NameTable
[ApiId
],
790 ReplyMsg
= &ReceiveMsg
;
791 ReceiveMsg
.Status
= STATUS_SUCCESS
;
793 /* Now we reply to a particular client */
794 ReplyPort
= CsrThread
->Process
->ClientPort
;
796 /* Check if there's a capture buffer */
797 if (ReceiveMsg
.CsrCaptureData
)
799 /* Capture the arguments */
800 if (!CsrCaptureArguments(CsrThread
, &ReceiveMsg
))
802 /* Ignore this message if we failed to get the arguments */
803 CsrDereferenceThread(CsrThread
);
808 /* Validation complete, start SEH */
811 /* Make sure we have enough threads */
812 CsrpCheckRequestThreads();
814 Teb
->CsrClientThread
= CsrThread
;
816 /* Call the API, get the reply code and return the result */
817 ReplyCode
= CsrReplyImmediately
;
818 ReplyMsg
->Status
= ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &ReplyCode
);
820 /* Increase the static thread count */
821 _InterlockedIncrement(&CsrpStaticThreadCount
);
823 Teb
->CsrClientThread
= CurrentThread
;
825 if (ReplyCode
== CsrReplyAlreadySent
)
827 if (ReceiveMsg
.CsrCaptureData
)
829 CsrReleaseCapturedArguments(&ReceiveMsg
);
832 ReplyPort
= CsrApiPort
;
833 CsrDereferenceThread(CsrThread
);
835 else if (ReplyCode
== CsrReplyDeadClient
)
837 /* Reply to the death message */
838 NtReplyPort(ReplyPort
, &ReplyMsg
->Header
);
840 /* Reply back to the API port now */
842 ReplyPort
= CsrApiPort
;
844 CsrDereferenceThread(CsrThread
);
846 else if (ReplyCode
== CsrReplyPending
)
849 ReplyPort
= CsrApiPort
;
853 if (ReceiveMsg
.CsrCaptureData
)
855 CsrReleaseCapturedArguments(&ReceiveMsg
);
857 CsrDereferenceThread(CsrThread
);
860 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
863 ReplyPort
= CsrApiPort
;
868 /* We're out of the loop for some reason, terminate! */
869 NtTerminateThread(NtCurrentThread(), Status
);
874 * @name CsrApiPortInitialize
876 * The CsrApiPortInitialize routine initializes the LPC Port used for
877 * communications with the Client/Server Runtime (CSR) and initializes the
878 * static thread that will handle connection requests and APIs.
882 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
890 CsrApiPortInitialize(VOID
)
893 OBJECT_ATTRIBUTES ObjectAttributes
;
895 HANDLE hRequestEvent
, hThread
;
897 PLIST_ENTRY ListHead
, NextEntry
;
898 PCSR_THREAD ServerThread
;
900 /* Calculate how much space we'll need for the Port Name */
901 Size
= CsrDirectoryName
.Length
+ sizeof(CSR_PORT_NAME
) + sizeof(WCHAR
);
903 /* Create the buffer for it */
904 CsrApiPortName
.Buffer
= RtlAllocateHeap(CsrHeap
, 0, Size
);
905 if (!CsrApiPortName
.Buffer
) return STATUS_NO_MEMORY
;
907 /* Setup the rest of the empty string */
908 CsrApiPortName
.Length
= 0;
909 CsrApiPortName
.MaximumLength
= (USHORT
)Size
;
910 RtlAppendUnicodeStringToString(&CsrApiPortName
, &CsrDirectoryName
);
911 RtlAppendUnicodeToString(&CsrApiPortName
, UNICODE_PATH_SEP
);
912 RtlAppendUnicodeToString(&CsrApiPortName
, CSR_PORT_NAME
);
915 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName
);
916 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
917 sizeof(CSR_CONNECTION_INFO
), sizeof(CSR_API_MESSAGE
));
920 /* FIXME: Create a Security Descriptor */
922 /* Initialize the Attributes */
923 InitializeObjectAttributes(&ObjectAttributes
,
927 NULL
/* FIXME: Use the Security Descriptor */);
929 /* Create the Port Object */
930 Status
= NtCreatePort(&CsrApiPort
,
932 sizeof(CSR_CONNECTION_INFO
),
933 sizeof(CSR_API_MESSAGE
),
935 if (NT_SUCCESS(Status
))
937 /* Create the event the Port Thread will use */
938 Status
= NtCreateEvent(&hRequestEvent
,
941 SynchronizationEvent
,
943 if (NT_SUCCESS(Status
))
945 /* Create the Request Thread */
946 Status
= RtlCreateUserThread(NtCurrentProcess(),
952 (PVOID
)CsrApiRequestThread
,
953 (PVOID
)hRequestEvent
,
956 if (NT_SUCCESS(Status
))
958 /* Add this as a static thread to CSRSRV */
959 CsrAddStaticServerThread(hThread
, &ClientId
, CsrThreadIsServerThread
);
961 /* Get the Thread List Pointers */
962 ListHead
= &CsrRootProcess
->ThreadList
;
963 NextEntry
= ListHead
->Flink
;
965 /* Start looping the list */
966 while (NextEntry
!= ListHead
)
969 ServerThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
972 Status
= NtResumeThread(ServerThread
->ThreadHandle
, NULL
);
974 /* Is this a Server Thread? */
975 if (ServerThread
->Flags
& CsrThreadIsServerThread
)
977 /* If so, then wait for it to initialize */
978 Status
= NtWaitForSingleObject(hRequestEvent
, FALSE
, NULL
);
979 ASSERT(NT_SUCCESS(Status
));
983 NextEntry
= NextEntry
->Flink
;
986 /* We don't need this anymore */
987 NtClose(hRequestEvent
);
997 * @name CsrConnectToUser
1000 * The CsrConnectToUser connects to the User subsystem.
1004 * @return A pointer to the CSR Thread
1011 CsrConnectToUser(VOID
)
1013 #if 0 // This code is OK, however it is ClientThreadSetup which sucks.
1015 ANSI_STRING DllName
;
1016 UNICODE_STRING TempName
;
1019 PTEB Teb
= NtCurrentTeb();
1020 PCSR_THREAD CsrThread
;
1023 /* Check if we didn't already find it */
1024 if (!CsrClientThreadSetup
)
1026 /* Get the DLL Handle for user32.dll */
1027 RtlInitAnsiString(&DllName
, "user32");
1028 RtlAnsiStringToUnicodeString(&TempName
, &DllName
, TRUE
);
1029 Status
= LdrGetDllHandle(NULL
,
1033 RtlFreeUnicodeString(&TempName
);
1035 /* If we got the handle, get the Client Thread Startup Entrypoint */
1036 if (NT_SUCCESS(Status
))
1038 RtlInitAnsiString(&StartupName
,"ClientThreadSetup");
1039 Status
= LdrGetProcedureAddress(hUser32
,
1042 (PVOID
)&CsrClientThreadSetup
);
1046 /* Connect to user32 */
1049 Connected
= CsrClientThreadSetup();
1051 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1058 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1062 /* Save pointer to this thread in TEB */
1063 CsrAcquireProcessLock();
1064 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1065 CsrReleaseProcessLock();
1066 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1073 PTEB Teb
= NtCurrentTeb();
1074 PCSR_THREAD CsrThread
;
1076 /* Save pointer to this thread in TEB */
1077 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1078 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1086 * @name CsrQueryApiPort
1089 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1093 * @return A handle to the port.
1100 CsrQueryApiPort(VOID
)
1102 DPRINT("CSRSRV: %s called\n", __FUNCTION__
);
1107 * @name CsrCaptureArguments
1108 * @implemented NT5.1
1110 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1111 * re-captures it into a server CSR Capture Buffer.
1114 * Pointer to the CSR Thread performing the validation.
1117 * Pointer to the CSR API Message containing the Capture Buffer
1118 * that needs to be validated.
1120 * @return TRUE if validation succeeded, FALSE otherwise.
1127 CsrCaptureArguments(IN PCSR_THREAD CsrThread
,
1128 IN PCSR_API_MESSAGE ApiMessage
)
1130 PCSR_CAPTURE_BUFFER LocalCaptureBuffer
= NULL
, RemoteCaptureBuffer
= NULL
;
1131 SIZE_T BufferDistance
;
1134 PULONG_PTR OffsetPointer
;
1135 ULONG_PTR CurrentOffset
;
1137 /* Use SEH to make sure this is valid */
1140 /* Get the buffer we got from whoever called NTDLL */
1141 LocalCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1142 Length
= LocalCaptureBuffer
->Size
;
1144 /* Now check if the buffer is inside our mapped section */
1145 if (((ULONG_PTR
)LocalCaptureBuffer
< CsrThread
->Process
->ClientViewBase
) ||
1146 (((ULONG_PTR
)LocalCaptureBuffer
+ Length
) >= CsrThread
->Process
->ClientViewBounds
))
1148 /* Return failure */
1149 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1150 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1151 _SEH2_YIELD(return FALSE
);
1154 /* Check if the Length is valid */
1155 if ((FIELD_OFFSET(CSR_CAPTURE_BUFFER
, PointerOffsetsArray
) +
1156 (LocalCaptureBuffer
->PointerCount
* sizeof(PVOID
)) > Length
) ||
1159 /* Return failure */
1160 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer
);
1162 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1163 _SEH2_YIELD(return FALSE
);
1166 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1168 /* Return failure */
1169 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1170 _SEH2_YIELD(return FALSE
);
1173 /* We validated the incoming buffer, now allocate the remote one */
1174 RemoteCaptureBuffer
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, Length
);
1175 if (!RemoteCaptureBuffer
)
1177 /* We're out of memory */
1178 ApiMessage
->Status
= STATUS_NO_MEMORY
;
1182 /* Copy the client's buffer */
1183 RtlMoveMemory(RemoteCaptureBuffer
, LocalCaptureBuffer
, Length
);
1185 /* Calculate the difference between our buffer and the client's */
1186 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1189 * All the pointer offsets correspond to pointers which point
1190 * to the remote data buffer instead of the local one.
1192 PointerCount
= RemoteCaptureBuffer
->PointerCount
;
1193 OffsetPointer
= RemoteCaptureBuffer
->PointerOffsetsArray
;
1194 while (PointerCount
--)
1196 CurrentOffset
= *OffsetPointer
;
1198 if (CurrentOffset
!= 0)
1200 /* Get the pointer corresponding to the offset */
1201 CurrentOffset
+= (ULONG_PTR
)ApiMessage
;
1203 /* Validate the bounds of the current pointed pointer */
1204 if ((*(PULONG_PTR
)CurrentOffset
>= CsrThread
->Process
->ClientViewBase
) &&
1205 (*(PULONG_PTR
)CurrentOffset
< CsrThread
->Process
->ClientViewBounds
))
1207 /* Modify the pointed pointer to take into account its new position */
1208 *(PULONG_PTR
)CurrentOffset
+= BufferDistance
;
1212 /* Invalid pointer, fail */
1213 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1215 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1222 /* Check if we got success */
1223 if (ApiMessage
->Status
!= STATUS_SUCCESS
)
1225 /* Failure. Free the buffer and return */
1226 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1231 /* Success, save the previous buffer and use the remote capture buffer */
1232 RemoteCaptureBuffer
->PreviousCaptureBuffer
= LocalCaptureBuffer
;
1233 ApiMessage
->CsrCaptureData
= RemoteCaptureBuffer
;
1241 * @name CsrReleaseCapturedArguments
1242 * @implemented NT5.1
1244 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1245 * that was previously captured with CsrCaptureArguments.
1248 * Pointer to the CSR API Message containing the Capture Buffer
1249 * that needs to be released.
1258 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage
)
1260 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer
, LocalCaptureBuffer
;
1261 SIZE_T BufferDistance
;
1263 PULONG_PTR OffsetPointer
;
1264 ULONG_PTR CurrentOffset
;
1266 /* Get the remote capture buffer */
1267 RemoteCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1269 /* Do not continue if there is no captured buffer */
1270 if (!RemoteCaptureBuffer
) return;
1272 /* If there is one, get the corresponding local capture buffer */
1273 LocalCaptureBuffer
= RemoteCaptureBuffer
->PreviousCaptureBuffer
;
1275 /* Free the previous one and use again the local capture buffer */
1276 RemoteCaptureBuffer
->PreviousCaptureBuffer
= NULL
;
1277 ApiMessage
->CsrCaptureData
= LocalCaptureBuffer
;
1279 /* Calculate the difference between our buffer and the client's */
1280 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1283 * All the pointer offsets correspond to pointers which point
1284 * to the local data buffer instead of the remote one (revert
1285 * the logic of CsrCaptureArguments).
1287 PointerCount
= RemoteCaptureBuffer
->PointerCount
;
1288 OffsetPointer
= RemoteCaptureBuffer
->PointerOffsetsArray
;
1289 while (PointerCount
--)
1291 CurrentOffset
= *OffsetPointer
;
1293 if (CurrentOffset
!= 0)
1295 /* Get the pointer corresponding to the offset */
1296 CurrentOffset
+= (ULONG_PTR
)ApiMessage
;
1298 /* Modify the pointed pointer to take into account its new position */
1299 *(PULONG_PTR
)CurrentOffset
-= BufferDistance
;
1305 /* Copy the data back */
1306 RtlMoveMemory(LocalCaptureBuffer
, RemoteCaptureBuffer
, RemoteCaptureBuffer
->Size
);
1308 /* Free our allocated buffer */
1309 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1314 * @name CsrValidateMessageBuffer
1315 * @implemented NT5.1
1317 * The CsrValidateMessageBuffer routine validates a captured message buffer
1318 * present in the CSR Api Message
1321 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1324 * Pointer to the message buffer to validate.
1326 * @param ElementCount
1327 * Number of elements contained in the message buffer.
1329 * @param ElementSize
1330 * Size of each element.
1332 * @return TRUE if validation succeeded, FALSE otherwise.
1339 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage
,
1341 IN ULONG ElementCount
,
1342 IN ULONG ElementSize
)
1344 PCSR_CAPTURE_BUFFER CaptureBuffer
= ApiMessage
->CsrCaptureData
;
1345 SIZE_T BufferDistance
= (ULONG_PTR
)Buffer
- (ULONG_PTR
)ApiMessage
;
1347 PULONG_PTR OffsetPointer
;
1350 * Check whether we have a valid buffer pointer, elements
1351 * of non-trivial size and that we don't overflow.
1353 if (!Buffer
|| ElementSize
== 0 ||
1354 (ULONGLONG
)ElementCount
* ElementSize
> (ULONGLONG
)0xFFFFFFFF)
1359 /* Check if didn't get a buffer and there aren't any arguments to check */
1360 // if (!*Buffer && (ElementCount * ElementSize == 0))
1361 if (!*Buffer
&& ElementCount
== 0) // Here ElementSize != 0 therefore only ElementCount can be == 0
1364 /* Check if we have no capture buffer */
1368 * In this case, check only the Process ID
1369 * and if there is a match, we succeed.
1371 if (NtCurrentTeb()->ClientId
.UniqueProcess
==
1372 ApiMessage
->Header
.ClientId
.UniqueProcess
)
1379 /* Make sure that there is still space left in the buffer */
1380 if ((CaptureBuffer
->Size
- (ULONG_PTR
)*Buffer
+ (ULONG_PTR
)CaptureBuffer
) >=
1381 (ElementCount
* ElementSize
))
1383 /* Perform the validation test */
1384 PointerCount
= CaptureBuffer
->PointerCount
;
1385 OffsetPointer
= CaptureBuffer
->PointerOffsetsArray
;
1386 while (PointerCount
--)
1389 * The pointer offset must be equal to the delta between
1390 * the addresses of the buffer and of the API message.
1392 if (*OffsetPointer
== BufferDistance
)
1402 DPRINT1("CSRSRV: Bad message buffer %p\n", ApiMessage
);
1407 /*** This is what we have in consrv/server.c ***
1409 /\* Ensure that a captured buffer is safe to access *\/
1411 Win32CsrValidateBuffer(PCSR_PROCESS ProcessData, PVOID Buffer,
1412 SIZE_T NumElements, SIZE_T ElementSize)
1414 /\* Check that the following conditions are true:
1415 * 1. The start of the buffer is somewhere within the process's
1416 * shared memory section view.
1417 * 2. The remaining space in the view is at least as large as the buffer.
1418 * (NB: Please don't try to "optimize" this by using multiplication
1419 * instead of division; remember that 2147483648 * 2 = 0.)
1420 * 3. The buffer is DWORD-aligned.
1422 ULONG_PTR Offset = (BYTE *)Buffer - (BYTE *)ProcessData->ClientViewBase;
1423 if (Offset >= ProcessData->ClientViewBounds
1424 || NumElements > (ProcessData->ClientViewBounds - Offset) / ElementSize
1425 || (Offset & (sizeof(DWORD) - 1)) != 0)
1427 DPRINT1("Invalid buffer %p(%u*%u); section view is %p(%u)\n",
1428 Buffer, NumElements, ElementSize,
1429 ProcessData->ClientViewBase, ProcessData->ClientViewBounds);
1435 ***********************************************/
1438 * @name CsrValidateMessageString
1439 * @implemented NT5.1
1441 * The CsrValidateMessageString validates a captured Wide-Character String
1442 * present in a CSR API Message.
1445 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1447 * @param MessageString
1448 * Pointer to the buffer containing the string to validate.
1450 * @return TRUE if validation succeeded, FALSE otherwise.
1457 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage
,
1458 IN LPWSTR
*MessageString
)
1462 return CsrValidateMessageBuffer(ApiMessage
,
1463 (PVOID
*)MessageString
,
1464 wcslen(*MessageString
) + 1,