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 ULONG CsrpStaticThreadCount
;
22 volatile ULONG 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
= 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("API: %d\n", ApiId
);
81 DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
82 "invalid API to call from the server.\n",
84 ((ServerDll
->NameTable
) && (ServerDll
->NameTable
[ApiId
])) ?
85 ServerDll
->NameTable
[ApiId
] : "*** UNKNOWN ***",
89 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
90 return STATUS_ILLEGAL_FUNCTION
;
97 DPRINT1("CSRSS: %s Api Request received from server process\n",
98 ServerDll
->NameTable
[ApiId
]);
102 /* Validation complete, start SEH */
105 /* Call the API, get the reply code and return the result */
106 ReplyMsg
->Status
= ServerDll
->DispatchTable
[ApiId
](ReceiveMsg
, &ReplyCode
);
108 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
110 /* If we got an exception, return access violation */
111 ReplyMsg
->Status
= STATUS_ACCESS_VIOLATION
;
116 return STATUS_SUCCESS
;
120 * @name CsrApiHandleConnectionRequest
122 * The CsrApiHandleConnectionRequest routine handles and accepts a new
123 * connection request to the CSR API LPC Port.
126 * Pointer to the incoming CSR API Message which contains the
127 * connection request.
129 * @return STATUS_SUCCESS in case of success, or status code which caused
130 * the routine to error.
132 * @remarks This routine is responsible for attaching the Shared Section to
133 * new clients connecting to CSR.
138 CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage
)
140 PCSR_THREAD CsrThread
= NULL
;
141 PCSR_PROCESS CsrProcess
= NULL
;
142 NTSTATUS Status
= STATUS_SUCCESS
;
143 PCSR_API_CONNECTINFO ConnectInfo
= &ApiMessage
->ConnectionInfo
;
144 BOOLEAN AllowConnection
= FALSE
;
145 REMOTE_PORT_VIEW RemotePortView
;
148 /* Acquire the Process Lock */
149 CsrAcquireProcessLock();
151 /* Lookup the CSR Thread */
152 CsrThread
= CsrLocateThreadByClientId(NULL
, &ApiMessage
->Header
.ClientId
);
154 /* Check if we have a thread */
157 /* Get the Process */
158 CsrProcess
= CsrThread
->Process
;
160 /* Make sure we have a Process as well */
163 /* Reference the Process */
164 CsrLockedReferenceProcess(CsrProcess
);
166 /* Release the lock */
167 CsrReleaseProcessLock();
169 /* Duplicate the Object Directory */
170 Status
= NtDuplicateObject(NtCurrentProcess(),
172 CsrProcess
->ProcessHandle
,
173 &ConnectInfo
->ObjectDirectory
,
176 DUPLICATE_SAME_ACCESS
|
177 DUPLICATE_SAME_ATTRIBUTES
);
179 /* Acquire the lock */
180 CsrAcquireProcessLock();
182 /* Check for success */
183 if (NT_SUCCESS(Status
))
185 /* Attach the Shared Section */
186 Status
= CsrSrvAttachSharedSection(CsrProcess
, ConnectInfo
);
188 /* Check how this went */
189 if (NT_SUCCESS(Status
))
191 /* Allow the connection, and return debugging flag */
192 ConnectInfo
->DebugFlags
= CsrDebug
;
193 AllowConnection
= TRUE
;
197 /* Dereference the project */
198 CsrLockedDereferenceProcess(CsrProcess
);
202 /* Release the lock */
203 CsrReleaseProcessLock();
205 /* Setup the Port View Structure */
206 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
207 RemotePortView
.ViewSize
= 0;
208 RemotePortView
.ViewBase
= NULL
;
210 /* Save the Process ID */
211 ConnectInfo
->ServerProcessId
= NtCurrentTeb()->ClientId
.UniqueProcess
;
213 /* Accept the Connection */
214 Status
= NtAcceptConnectPort(&ServerPort
,
215 AllowConnection
? UlongToPtr(CsrProcess
->SequenceNumber
) : 0,
220 if (!NT_SUCCESS(Status
))
222 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status
);
224 else if (AllowConnection
)
228 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
229 ApiMessage
->Header
.ClientId
.UniqueProcess
,
230 ApiMessage
->Header
.ClientId
.UniqueThread
,
231 RemotePortView
.ViewBase
,
232 RemotePortView
.ViewSize
);
235 /* Set some Port Data in the Process */
236 CsrProcess
->ClientPort
= ServerPort
;
237 CsrProcess
->ClientViewBase
= (ULONG_PTR
)RemotePortView
.ViewBase
;
238 CsrProcess
->ClientViewBounds
= (ULONG_PTR
)((ULONG_PTR
)RemotePortView
.ViewBase
+
239 (ULONG_PTR
)RemotePortView
.ViewSize
);
241 /* Complete the connection */
242 Status
= NtCompleteConnectPort(ServerPort
);
243 if (!NT_SUCCESS(Status
))
245 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status
);
250 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
251 ApiMessage
->Header
.ClientId
.UniqueProcess
,
252 ApiMessage
->Header
.ClientId
.UniqueThread
);
255 /* Return status to caller */
260 * @name CsrpCheckRequestThreads
262 * The CsrpCheckRequestThreads routine checks if there are no more threads
263 * to handle CSR API Requests, and creates a new thread if possible, to
268 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
269 * if a new thread couldn't be created.
276 CsrpCheckRequestThreads(VOID
)
282 /* Decrease the count, and see if we're out */
283 if (InterlockedDecrementUL(&CsrpStaticThreadCount
) == 0)
285 /* Check if we've still got space for a Dynamic Thread */
286 if (CsrpDynamicThreadTotal
< CsrMaxApiRequestThreads
)
288 /* Create a new dynamic thread */
289 Status
= RtlCreateUserThread(NtCurrentProcess(),
295 (PVOID
)CsrApiRequestThread
,
300 if (NT_SUCCESS(Status
))
302 /* Increase the thread counts */
303 InterlockedIncrementUL(&CsrpStaticThreadCount
);
304 InterlockedIncrementUL(&CsrpDynamicThreadTotal
);
306 /* Add a new server thread */
307 if (CsrAddStaticServerThread(hThread
,
309 CsrThreadIsServerThread
))
312 NtResumeThread(hThread
, NULL
);
316 /* Failed to create a new static thread */
317 InterlockedDecrementUL(&CsrpStaticThreadCount
);
318 InterlockedDecrementUL(&CsrpDynamicThreadTotal
);
321 DPRINT1("Failing\n");
322 NtTerminateThread(hThread
, 0);
326 return STATUS_UNSUCCESSFUL
;
333 return STATUS_SUCCESS
;
337 * @name CsrApiRequestThread
339 * The CsrApiRequestThread routine handles incoming messages or connection
340 * requests on the CSR API LPC Port.
343 * System-default user-defined parameter. Unused.
345 * @return The thread exit code, if the thread is terminated.
347 * @remarks Before listening on the port, the routine will first attempt
348 * to connect to the user subsystem.
353 CsrApiRequestThread(IN PVOID Parameter
)
355 PTEB Teb
= NtCurrentTeb();
356 LARGE_INTEGER TimeOut
;
357 PCSR_THREAD CurrentThread
, CsrThread
;
359 CSR_REPLY_CODE ReplyCode
;
360 PCSR_API_MESSAGE ReplyMsg
;
361 CSR_API_MESSAGE ReceiveMsg
;
362 PCSR_PROCESS CsrProcess
;
363 PHARDERROR_MSG HardErrorMsg
;
365 PCSR_SERVER_DLL ServerDll
;
366 PCLIENT_DIED_MSG ClientDiedMsg
;
367 PDBGKM_MSG DebugMessage
;
368 ULONG ServerId
, ApiId
, MessageType
, i
;
371 /* Setup LPC loop port and message */
373 ReplyPort
= CsrApiPort
;
375 /* Connect to user32 */
376 while (!CsrConnectToUser())
378 /* Set up the timeout for the connect (30 seconds) */
379 TimeOut
.QuadPart
= -30 * 1000 * 1000 * 10;
381 /* Keep trying until we get a response */
382 Teb
->Win32ClientInfo
[0] = 0;
383 NtDelayExecution(FALSE
, &TimeOut
);
387 CurrentThread
= Teb
->CsrClientThread
;
389 /* If we got an event... */
392 /* Set it, to let stuff waiting on us load */
393 Status
= NtSetEvent((HANDLE
)Parameter
, NULL
);
394 ASSERT(NT_SUCCESS(Status
));
396 /* Increase the Thread Counts */
397 InterlockedIncrementUL(&CsrpStaticThreadCount
);
398 InterlockedIncrementUL(&CsrpDynamicThreadTotal
);
401 /* Now start the loop */
404 /* Make sure the real CID is set */
405 Teb
->RealClientId
= Teb
->ClientId
;
408 if (Teb
->CountOfOwnedCriticalSections
)
410 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
411 Teb
->CountOfOwnedCriticalSections
);
412 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
413 &ReceiveMsg
, ReplyMsg
);
417 /* Wait for a message to come through */
418 Status
= NtReplyWaitReceivePort(ReplyPort
,
423 /* Check if we didn't get success */
424 if (Status
!= STATUS_SUCCESS
)
426 /* Was it a failure or another success code? */
427 if (!NT_SUCCESS(Status
))
429 /* Check for specific status cases */
430 if ((Status
!= STATUS_INVALID_CID
) &&
431 (Status
!= STATUS_UNSUCCESSFUL
) &&
432 ((Status
== STATUS_INVALID_HANDLE
) || (ReplyPort
== CsrApiPort
)))
434 /* Notify the debugger */
435 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
436 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort
, CsrApiPort
);
439 /* We failed big time, so start out fresh */
441 ReplyPort
= CsrApiPort
;
446 /* A strange "success" code, just try again */
447 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status
);
452 /* Use whatever Client ID we got */
453 Teb
->RealClientId
= ReceiveMsg
.Header
.ClientId
;
455 /* Get the Message Type */
456 MessageType
= ReceiveMsg
.Header
.u2
.s2
.Type
;
458 /* Handle connection requests */
459 if (MessageType
== LPC_CONNECTION_REQUEST
)
461 /* Handle the Connection Request */
462 CsrApiHandleConnectionRequest(&ReceiveMsg
);
465 ReplyPort
= CsrApiPort
;
469 /* It's some other kind of request. Get the lock for the lookup */
470 CsrAcquireProcessLock();
472 /* Now do the lookup to get the CSR_THREAD */
473 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
,
474 &ReceiveMsg
.Header
.ClientId
);
476 /* Did we find a thread? */
479 /* This wasn't a CSR Thread, release lock */
480 CsrReleaseProcessLock();
482 /* If this was an exception, handle it */
483 if (MessageType
== LPC_EXCEPTION
)
485 ReplyMsg
= &ReceiveMsg
;
486 ReplyPort
= CsrApiPort
;
487 ReplyMsg
->Status
= DBG_CONTINUE
;
489 else if (MessageType
== LPC_PORT_CLOSED
||
490 MessageType
== LPC_CLIENT_DIED
)
492 /* The Client or Port are gone, loop again */
494 ReplyPort
= CsrApiPort
;
496 else if (MessageType
== LPC_ERROR_EVENT
)
498 /* If it's a hard error, handle this too */
499 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
501 /* Default it to unhandled */
502 HardErrorMsg
->Response
= ResponseNotHandled
;
504 /* Check if there are free api threads */
505 CsrpCheckRequestThreads();
506 if (CsrpStaticThreadCount
)
508 /* Loop every Server DLL */
509 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
511 /* Get the Server DLL */
512 ServerDll
= CsrLoadedServerDll
[i
];
514 /* Check if it's valid and if it has a Hard Error Callback */
515 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
518 ServerDll
->HardErrorCallback(NULL
/* == CsrThread */, HardErrorMsg
);
520 /* If it's handled, get out of here */
521 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
526 /* Increase the thread count */
527 InterlockedIncrementUL(&CsrpStaticThreadCount
);
529 /* If the response was 0xFFFFFFFF, we'll ignore it */
530 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
533 ReplyPort
= CsrApiPort
;
537 ReplyMsg
= &ReceiveMsg
;
538 ReplyPort
= CsrApiPort
;
541 else if (MessageType
== LPC_REQUEST
)
543 /* This is an API Message coming from a non-CSR Thread */
544 ReplyMsg
= &ReceiveMsg
;
545 ReplyPort
= CsrApiPort
;
546 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
548 else if (MessageType
== LPC_DATAGRAM
)
550 /* This is an API call, get the Server ID */
551 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
553 /* Make sure that the ID is within limits, and the Server DLL loaded */
555 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
556 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
558 /* We are beyond the Maximum Server ID */
559 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
560 ServerId
, ServerDll
);
564 ReplyPort
= CsrApiPort
;
568 /* Get the API ID, normalized with our Base ID */
569 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
571 /* Make sure that the ID is within limits, and the entry exists */
572 if (ApiId
>= ServerDll
->HighestApiSupported
)
574 /* We are beyond the Maximum API ID, or it doesn't exist */
575 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
576 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
579 ReplyPort
= CsrApiPort
;
587 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
588 Teb
->ClientId
.UniqueThread
,
589 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
590 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
591 ServerDll
->NameTable
[ApiId
],
597 ReceiveMsg
.Status
= STATUS_SUCCESS
;
599 /* Validation complete, start SEH */
602 /* Make sure we have enough threads */
603 CsrpCheckRequestThreads();
605 /* Call the API and get the reply code */
607 ReplyPort
= CsrApiPort
;
608 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &ReplyCode
);
610 /* Increase the static thread count */
611 InterlockedIncrementUL(&CsrpStaticThreadCount
);
613 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
616 ReplyPort
= CsrApiPort
;
622 /* Some other ignored message type */
624 ReplyPort
= CsrApiPort
;
631 /* We have a valid thread, was this an LPC Request? */
632 if (MessageType
!= LPC_REQUEST
)
634 /* It's not an API, check if the client died */
635 if (MessageType
== LPC_CLIENT_DIED
)
637 /* Get the information and check if it matches our thread */
638 ClientDiedMsg
= (PCLIENT_DIED_MSG
)&ReceiveMsg
;
639 if (ClientDiedMsg
->CreateTime
.QuadPart
== CsrThread
->CreateTime
.QuadPart
)
641 /* Now we reply to the dying client */
642 ReplyPort
= CsrThread
->Process
->ClientPort
;
644 /* Reference the thread */
645 CsrLockedReferenceThread(CsrThread
);
647 /* Destroy the thread in the API Message */
648 CsrDestroyThread(&ReceiveMsg
.Header
.ClientId
);
650 /* Check if the thread was actually ourselves */
651 if (CsrProcess
->ThreadCount
== 1)
653 /* Kill the process manually here */
654 CsrDestroyProcess(&CsrThread
->ClientId
, 0);
657 /* Remove our extra reference */
658 CsrLockedDereferenceThread(CsrThread
);
661 /* Release the lock and keep looping */
662 CsrReleaseProcessLock();
665 ReplyPort
= CsrApiPort
;
669 /* Reference the thread and release the lock */
670 CsrLockedReferenceThread(CsrThread
);
671 CsrReleaseProcessLock();
673 /* Check if this was an exception */
674 if (MessageType
== LPC_EXCEPTION
)
676 /* Kill the process */
677 NtTerminateProcess(CsrProcess
->ProcessHandle
, STATUS_ABANDONED
);
679 /* Destroy it from CSR */
680 CsrDestroyProcess(&ReceiveMsg
.Header
.ClientId
, STATUS_ABANDONED
);
682 /* Return a Debug Message */
683 DebugMessage
= (PDBGKM_MSG
)&ReceiveMsg
;
684 DebugMessage
->ReturnedStatus
= DBG_CONTINUE
;
685 ReplyMsg
= &ReceiveMsg
;
686 ReplyPort
= CsrApiPort
;
688 /* Remove our extra reference */
689 CsrDereferenceThread(CsrThread
);
691 else if (MessageType
== LPC_ERROR_EVENT
)
693 /* If it's a hard error, handle this too */
694 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
696 /* Default it to unhandled */
697 HardErrorMsg
->Response
= ResponseNotHandled
;
699 /* Check if there are free api threads */
700 CsrpCheckRequestThreads();
701 if (CsrpStaticThreadCount
)
703 /* Loop every Server DLL */
704 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
706 /* Get the Server DLL */
707 ServerDll
= CsrLoadedServerDll
[i
];
709 /* Check if it's valid and if it has a Hard Error Callback */
710 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
713 ServerDll
->HardErrorCallback(CsrThread
, HardErrorMsg
);
715 /* If it's handled, get out of here */
716 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
721 /* Increase the thread count */
722 InterlockedIncrementUL(&CsrpStaticThreadCount
);
724 /* If the response was 0xFFFFFFFF, we'll ignore it */
725 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
728 ReplyPort
= CsrApiPort
;
732 CsrDereferenceThread(CsrThread
);
733 ReplyMsg
= &ReceiveMsg
;
734 ReplyPort
= CsrApiPort
;
740 CsrDereferenceThread(CsrThread
);
748 /* We got an API Request */
749 CsrLockedReferenceThread(CsrThread
);
750 CsrReleaseProcessLock();
752 /* This is an API call, get the Server ID */
753 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
755 /* Make sure that the ID is within limits, and the Server DLL loaded */
757 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
758 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
760 /* We are beyond the Maximum Server ID */
761 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
762 ServerId
, ServerDll
);
765 ReplyPort
= CsrApiPort
;
766 ReplyMsg
= &ReceiveMsg
;
767 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
768 CsrDereferenceThread(CsrThread
);
772 /* Get the API ID, normalized with our Base ID */
773 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
775 /* Make sure that the ID is within limits, and the entry exists */
776 if (ApiId
>= ServerDll
->HighestApiSupported
)
778 /* We are beyond the Maximum API ID, or it doesn't exist */
779 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
780 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
783 ReplyPort
= CsrApiPort
;
784 ReplyMsg
= &ReceiveMsg
;
785 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
786 CsrDereferenceThread(CsrThread
);
793 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x, Process %08x - %08x\n",
794 Teb
->ClientId
.UniqueThread
,
795 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
796 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
797 ServerDll
->NameTable
[ApiId
],
805 ReplyMsg
= &ReceiveMsg
;
806 ReceiveMsg
.Status
= STATUS_SUCCESS
;
808 /* Now we reply to a particular client */
809 ReplyPort
= CsrThread
->Process
->ClientPort
;
811 /* Check if there's a capture buffer */
812 if (ReceiveMsg
.CsrCaptureData
)
814 /* Capture the arguments */
815 if (!CsrCaptureArguments(CsrThread
, &ReceiveMsg
))
817 /* Ignore this message if we failed to get the arguments */
818 CsrDereferenceThread(CsrThread
);
823 /* Validation complete, start SEH */
826 /* Make sure we have enough threads */
827 CsrpCheckRequestThreads();
829 Teb
->CsrClientThread
= CsrThread
;
831 /* Call the API, get the reply code and return the result */
832 ReplyCode
= CsrReplyImmediately
;
833 ReplyMsg
->Status
= ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &ReplyCode
);
835 /* Increase the static thread count */
836 InterlockedIncrementUL(&CsrpStaticThreadCount
);
838 Teb
->CsrClientThread
= CurrentThread
;
840 if (ReplyCode
== CsrReplyAlreadySent
)
842 if (ReceiveMsg
.CsrCaptureData
)
844 CsrReleaseCapturedArguments(&ReceiveMsg
);
847 ReplyPort
= CsrApiPort
;
848 CsrDereferenceThread(CsrThread
);
850 else if (ReplyCode
== CsrReplyDeadClient
)
852 /* Reply to the death message */
853 NtReplyPort(ReplyPort
, &ReplyMsg
->Header
);
855 /* Reply back to the API port now */
857 ReplyPort
= CsrApiPort
;
859 CsrDereferenceThread(CsrThread
);
861 else if (ReplyCode
== CsrReplyPending
)
864 ReplyPort
= CsrApiPort
;
868 if (ReceiveMsg
.CsrCaptureData
)
870 CsrReleaseCapturedArguments(&ReceiveMsg
);
872 CsrDereferenceThread(CsrThread
);
875 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
878 ReplyPort
= CsrApiPort
;
883 /* We're out of the loop for some reason, terminate! */
884 NtTerminateThread(NtCurrentThread(), Status
);
889 * @name CsrApiPortInitialize
891 * The CsrApiPortInitialize routine initializes the LPC Port used for
892 * communications with the Client/Server Runtime (CSR) and initializes the
893 * static thread that will handle connection requests and APIs.
897 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
904 CsrApiPortInitialize(VOID
)
907 OBJECT_ATTRIBUTES ObjectAttributes
;
909 HANDLE hRequestEvent
, hThread
;
911 PLIST_ENTRY ListHead
, NextEntry
;
912 PCSR_THREAD ServerThread
;
914 /* Calculate how much space we'll need for the Port Name */
915 Size
= CsrDirectoryName
.Length
+ sizeof(CSR_PORT_NAME
) + sizeof(WCHAR
);
917 /* Create the buffer for it */
918 CsrApiPortName
.Buffer
= RtlAllocateHeap(CsrHeap
, 0, Size
);
919 if (!CsrApiPortName
.Buffer
) return STATUS_NO_MEMORY
;
921 /* Setup the rest of the empty string */
922 CsrApiPortName
.Length
= 0;
923 CsrApiPortName
.MaximumLength
= (USHORT
)Size
;
924 RtlAppendUnicodeStringToString(&CsrApiPortName
, &CsrDirectoryName
);
925 RtlAppendUnicodeToString(&CsrApiPortName
, UNICODE_PATH_SEP
);
926 RtlAppendUnicodeToString(&CsrApiPortName
, CSR_PORT_NAME
);
929 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName
);
930 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
931 sizeof(CSR_API_CONNECTINFO
), sizeof(CSR_API_MESSAGE
));
934 /* FIXME: Create a Security Descriptor */
936 /* Initialize the Attributes */
937 InitializeObjectAttributes(&ObjectAttributes
,
941 NULL
/* FIXME: Use the Security Descriptor */);
943 /* Create the Port Object */
944 Status
= NtCreatePort(&CsrApiPort
,
946 sizeof(CSR_API_CONNECTINFO
),
947 sizeof(CSR_API_MESSAGE
),
949 if (NT_SUCCESS(Status
))
951 /* Create the event the Port Thread will use */
952 Status
= NtCreateEvent(&hRequestEvent
,
955 SynchronizationEvent
,
957 if (NT_SUCCESS(Status
))
959 /* Create the Request Thread */
960 Status
= RtlCreateUserThread(NtCurrentProcess(),
966 (PVOID
)CsrApiRequestThread
,
967 (PVOID
)hRequestEvent
,
970 if (NT_SUCCESS(Status
))
972 /* Add this as a static thread to CSRSRV */
973 CsrAddStaticServerThread(hThread
, &ClientId
, CsrThreadIsServerThread
);
975 /* Get the Thread List Pointers */
976 ListHead
= &CsrRootProcess
->ThreadList
;
977 NextEntry
= ListHead
->Flink
;
979 /* Start looping the list */
980 while (NextEntry
!= ListHead
)
983 ServerThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
986 Status
= NtResumeThread(ServerThread
->ThreadHandle
, NULL
);
988 /* Is this a Server Thread? */
989 if (ServerThread
->Flags
& CsrThreadIsServerThread
)
991 /* If so, then wait for it to initialize */
992 Status
= NtWaitForSingleObject(hRequestEvent
, FALSE
, NULL
);
993 ASSERT(NT_SUCCESS(Status
));
997 NextEntry
= NextEntry
->Flink
;
1000 /* We don't need this anymore */
1001 NtClose(hRequestEvent
);
1011 * @name CsrConnectToUser
1014 * The CsrConnectToUser connects to the User subsystem.
1018 * @return A pointer to the CSR Thread
1025 CsrConnectToUser(VOID
)
1028 ANSI_STRING DllName
;
1029 UNICODE_STRING TempName
;
1032 PTEB Teb
= NtCurrentTeb();
1033 PCSR_THREAD CsrThread
;
1036 /* Check if we didn't already find it */
1037 if (!CsrClientThreadSetup
)
1039 /* Get the DLL Handle for user32.dll */
1040 RtlInitAnsiString(&DllName
, "user32");
1041 RtlAnsiStringToUnicodeString(&TempName
, &DllName
, TRUE
);
1042 Status
= LdrGetDllHandle(NULL
,
1046 RtlFreeUnicodeString(&TempName
);
1048 /* If we got the handle, get the Client Thread Startup Entrypoint */
1049 if (NT_SUCCESS(Status
))
1051 RtlInitAnsiString(&StartupName
,"ClientThreadSetup");
1052 Status
= LdrGetProcedureAddress(hUser32
,
1055 (PVOID
)&CsrClientThreadSetup
);
1059 /* Connect to user32 */
1062 Connected
= CsrClientThreadSetup();
1064 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1071 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1075 /* Save pointer to this thread in TEB */
1076 CsrAcquireProcessLock();
1077 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1078 CsrReleaseProcessLock();
1079 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
)
1106 * @name CsrCaptureArguments
1107 * @implemented NT5.1
1109 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1110 * re-captures it into a server CSR Capture Buffer.
1113 * Pointer to the CSR Thread performing the validation.
1116 * Pointer to the CSR API Message containing the Capture Buffer
1117 * that needs to be validated.
1119 * @return TRUE if validation succeeded, FALSE otherwise.
1126 CsrCaptureArguments(IN PCSR_THREAD CsrThread
,
1127 IN PCSR_API_MESSAGE ApiMessage
)
1129 PCSR_CAPTURE_BUFFER LocalCaptureBuffer
= NULL
, RemoteCaptureBuffer
= NULL
;
1130 SIZE_T BufferDistance
;
1133 PULONG_PTR OffsetPointer
;
1134 ULONG_PTR CurrentOffset
;
1136 /* Use SEH to make sure this is valid */
1139 /* Get the buffer we got from whoever called NTDLL */
1140 LocalCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1141 Length
= LocalCaptureBuffer
->Size
;
1143 /* Now check if the buffer is inside our mapped section */
1144 if (((ULONG_PTR
)LocalCaptureBuffer
< CsrThread
->Process
->ClientViewBase
) ||
1145 (((ULONG_PTR
)LocalCaptureBuffer
+ Length
) >= CsrThread
->Process
->ClientViewBounds
))
1147 /* Return failure */
1148 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1149 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1150 _SEH2_YIELD(return FALSE
);
1153 /* Check if the Length is valid */
1154 if ((FIELD_OFFSET(CSR_CAPTURE_BUFFER
, PointerOffsetsArray
) +
1155 (LocalCaptureBuffer
->PointerCount
* sizeof(PVOID
)) > Length
) ||
1158 /* Return failure */
1159 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer
);
1161 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1162 _SEH2_YIELD(return FALSE
);
1165 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1167 /* Return failure */
1168 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1169 _SEH2_YIELD(return FALSE
);
1172 /* We validated the incoming buffer, now allocate the remote one */
1173 RemoteCaptureBuffer
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, Length
);
1174 if (!RemoteCaptureBuffer
)
1176 /* We're out of memory */
1177 ApiMessage
->Status
= STATUS_NO_MEMORY
;
1181 /* Copy the client's buffer */
1182 RtlMoveMemory(RemoteCaptureBuffer
, LocalCaptureBuffer
, Length
);
1184 /* Calculate the difference between our buffer and the client's */
1185 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1188 * All the pointer offsets correspond to pointers which point
1189 * to the remote data buffer instead of the local one.
1191 PointerCount
= RemoteCaptureBuffer
->PointerCount
;
1192 OffsetPointer
= RemoteCaptureBuffer
->PointerOffsetsArray
;
1193 while (PointerCount
--)
1195 CurrentOffset
= *OffsetPointer
;
1197 if (CurrentOffset
!= 0)
1199 /* Get the pointer corresponding to the offset */
1200 CurrentOffset
+= (ULONG_PTR
)ApiMessage
;
1202 /* Validate the bounds of the current pointed pointer */
1203 if ((*(PULONG_PTR
)CurrentOffset
>= CsrThread
->Process
->ClientViewBase
) &&
1204 (*(PULONG_PTR
)CurrentOffset
< CsrThread
->Process
->ClientViewBounds
))
1206 /* Modify the pointed pointer to take into account its new position */
1207 *(PULONG_PTR
)CurrentOffset
+= BufferDistance
;
1211 /* Invalid pointer, fail */
1212 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1214 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1221 /* Check if we got success */
1222 if (ApiMessage
->Status
!= STATUS_SUCCESS
)
1224 /* Failure. Free the buffer and return */
1225 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1230 /* Success, save the previous buffer and use the remote capture buffer */
1231 RemoteCaptureBuffer
->PreviousCaptureBuffer
= LocalCaptureBuffer
;
1232 ApiMessage
->CsrCaptureData
= RemoteCaptureBuffer
;
1240 * @name CsrReleaseCapturedArguments
1241 * @implemented NT5.1
1243 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1244 * that was previously captured with CsrCaptureArguments.
1247 * Pointer to the CSR API Message containing the Capture Buffer
1248 * that needs to be released.
1257 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage
)
1259 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer
, LocalCaptureBuffer
;
1260 SIZE_T BufferDistance
;
1262 PULONG_PTR OffsetPointer
;
1263 ULONG_PTR CurrentOffset
;
1265 /* Get the remote capture buffer */
1266 RemoteCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1268 /* Do not continue if there is no captured buffer */
1269 if (!RemoteCaptureBuffer
) return;
1271 /* If there is one, get the corresponding local capture buffer */
1272 LocalCaptureBuffer
= RemoteCaptureBuffer
->PreviousCaptureBuffer
;
1274 /* Free the previous one and use again the local capture buffer */
1275 RemoteCaptureBuffer
->PreviousCaptureBuffer
= NULL
;
1276 ApiMessage
->CsrCaptureData
= LocalCaptureBuffer
;
1278 /* Calculate the difference between our buffer and the client's */
1279 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1282 * All the pointer offsets correspond to pointers which point
1283 * to the local data buffer instead of the remote one (revert
1284 * the logic of CsrCaptureArguments).
1286 PointerCount
= RemoteCaptureBuffer
->PointerCount
;
1287 OffsetPointer
= RemoteCaptureBuffer
->PointerOffsetsArray
;
1288 while (PointerCount
--)
1290 CurrentOffset
= *OffsetPointer
;
1292 if (CurrentOffset
!= 0)
1294 /* Get the pointer corresponding to the offset */
1295 CurrentOffset
+= (ULONG_PTR
)ApiMessage
;
1297 /* Modify the pointed pointer to take into account its new position */
1298 *(PULONG_PTR
)CurrentOffset
-= BufferDistance
;
1304 /* Copy the data back */
1305 RtlMoveMemory(LocalCaptureBuffer
, RemoteCaptureBuffer
, RemoteCaptureBuffer
->Size
);
1307 /* Free our allocated buffer */
1308 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1312 * @name CsrValidateMessageBuffer
1313 * @implemented NT5.1
1315 * The CsrValidateMessageBuffer routine validates a captured message buffer
1316 * present in the CSR Api Message
1319 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1322 * Pointer to the message buffer to validate.
1324 * @param ElementCount
1325 * Number of elements contained in the message buffer.
1327 * @param ElementSize
1328 * Size of each element.
1330 * @return TRUE if validation succeeded, FALSE otherwise.
1337 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage
,
1339 IN ULONG ElementCount
,
1340 IN ULONG ElementSize
)
1342 PCSR_CAPTURE_BUFFER CaptureBuffer
= ApiMessage
->CsrCaptureData
;
1343 SIZE_T BufferDistance
= (ULONG_PTR
)Buffer
- (ULONG_PTR
)ApiMessage
;
1345 PULONG_PTR OffsetPointer
;
1348 * Check whether we have a valid buffer pointer, elements
1349 * of non-trivial size and that we don't overflow.
1351 if (!Buffer
|| ElementSize
== 0 ||
1352 (ULONGLONG
)ElementCount
* ElementSize
> (ULONGLONG
)0xFFFFFFFF)
1357 /* Check if didn't get a buffer and there aren't any arguments to check */
1358 // if (!*Buffer && (ElementCount * ElementSize == 0))
1359 if (!*Buffer
&& ElementCount
== 0) // Here ElementSize != 0 therefore only ElementCount can be == 0
1362 /* Check if we have no capture buffer */
1366 * In this case, check only the Process ID
1367 * and if there is a match, we succeed.
1369 if (NtCurrentTeb()->ClientId
.UniqueProcess
==
1370 ApiMessage
->Header
.ClientId
.UniqueProcess
)
1377 /* Make sure that there is still space left in the buffer */
1378 if ((CaptureBuffer
->Size
- (ULONG_PTR
)*Buffer
+ (ULONG_PTR
)CaptureBuffer
) >=
1379 (ElementCount
* ElementSize
))
1381 /* Perform the validation test */
1382 PointerCount
= CaptureBuffer
->PointerCount
;
1383 OffsetPointer
= CaptureBuffer
->PointerOffsetsArray
;
1384 while (PointerCount
--)
1387 * The pointer offset must be equal to the delta between
1388 * the addresses of the buffer and of the API message.
1390 if (*OffsetPointer
== BufferDistance
)
1400 DPRINT1("CSRSRV: Bad message buffer %p\n", ApiMessage
);
1406 * @name CsrValidateMessageString
1407 * @implemented NT5.1
1409 * The CsrValidateMessageString validates a captured Wide-Character String
1410 * present in a CSR API Message.
1413 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1415 * @param MessageString
1416 * Pointer to the buffer containing the string to validate.
1418 * @return TRUE if validation succeeded, FALSE otherwise.
1425 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage
,
1426 IN LPWSTR
*MessageString
)
1430 return CsrValidateMessageBuffer(ApiMessage
,
1431 (PVOID
*)MessageString
,
1432 wcslen(*MessageString
) + 1,