2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Client/Server Runtime SubSystem
4 * FILE: subsystems/win32/csrsrv/api.c
5 * PURPOSE: CSR Server DLL API LPC Implementation
6 * "\windows\ApiPort" port process management functions
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES *******************************************************************/
14 #include <ndk/kefuncs.h>
19 /* GLOBALS ********************************************************************/
21 BOOLEAN (*CsrClientThreadSetup
)(VOID
) = NULL
;
22 UNICODE_STRING CsrApiPortName
;
23 volatile ULONG CsrpStaticThreadCount
;
24 volatile ULONG CsrpDynamicThreadTotal
;
25 extern ULONG CsrMaxApiRequestThreads
;
27 /* FUNCTIONS ******************************************************************/
30 * @name CsrCallServerFromServer
33 * The CsrCallServerFromServer routine calls a CSR API from within a server.
34 * It avoids using LPC messages since the request isn't coming from a client.
37 * Pointer to the CSR API Message to send to the server.
40 * Pointer to the CSR API Message to receive from the server.
42 * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
43 * if the ApiNumber is invalid, or STATUS_ACCESS_VIOLATION if there
44 * was a problem executing the API.
51 CsrCallServerFromServer(IN PCSR_API_MESSAGE ReceiveMsg
,
52 IN OUT PCSR_API_MESSAGE ReplyMsg
)
55 PCSR_SERVER_DLL ServerDll
;
57 CSR_REPLY_CODE ReplyCode
= CsrReplyImmediately
;
59 /* Get the Server ID */
60 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
->ApiNumber
);
62 /* Make sure that the ID is within limits, and the Server DLL loaded */
63 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
64 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
66 /* We are beyond the Maximum Server ID */
67 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId
, ServerDll
);
68 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
69 return STATUS_ILLEGAL_FUNCTION
;
73 /* Get the API ID, normalized with our Base ID */
74 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
->ApiNumber
) - ServerDll
->ApiBase
;
76 /* Make sure that the ID is within limits, and the entry exists */
77 if ((ApiId
>= ServerDll
->HighestApiSupported
) ||
78 ((ServerDll
->ValidTable
) && !(ServerDll
->ValidTable
[ApiId
])))
80 /* We are beyond the Maximum API ID, or it doesn't exist */
81 DPRINT1("API: %d\n", ApiId
);
83 DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
84 "invalid API to call from the server.\n",
86 ((ServerDll
->NameTable
) && (ServerDll
->NameTable
[ApiId
])) ?
87 ServerDll
->NameTable
[ApiId
] : "*** UNKNOWN ***",
91 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
92 return STATUS_ILLEGAL_FUNCTION
;
99 DPRINT1("CSRSS: %s Api Request received from server process\n",
100 ServerDll
->NameTable
[ApiId
]);
104 /* Validation complete, start SEH */
107 /* Call the API, get the reply code and return the result */
108 ReplyMsg
->Status
= ServerDll
->DispatchTable
[ApiId
](ReceiveMsg
, &ReplyCode
);
110 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
112 /* If we got an exception, return access violation */
113 ReplyMsg
->Status
= STATUS_ACCESS_VIOLATION
;
118 return STATUS_SUCCESS
;
122 * @name CsrApiHandleConnectionRequest
124 * The CsrApiHandleConnectionRequest routine handles and accepts a new
125 * connection request to the CSR API LPC Port.
128 * Pointer to the incoming CSR API Message which contains the
129 * connection request.
131 * @return STATUS_SUCCESS in case of success, or status code which caused
132 * the routine to error.
134 * @remarks This routine is responsible for attaching the Shared Section to
135 * new clients connecting to CSR.
140 CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage
)
142 PCSR_THREAD CsrThread
= NULL
;
143 PCSR_PROCESS CsrProcess
= NULL
;
144 NTSTATUS Status
= STATUS_SUCCESS
;
145 PCSR_API_CONNECTINFO ConnectInfo
= &ApiMessage
->ConnectionInfo
;
146 BOOLEAN AllowConnection
= FALSE
;
147 REMOTE_PORT_VIEW RemotePortView
;
150 /* Acquire the Process Lock */
151 CsrAcquireProcessLock();
153 /* Lookup the CSR Thread */
154 CsrThread
= CsrLocateThreadByClientId(NULL
, &ApiMessage
->Header
.ClientId
);
156 /* Check if we have a thread */
159 /* Get the Process */
160 CsrProcess
= CsrThread
->Process
;
162 /* Make sure we have a Process as well */
165 /* Reference the Process */
166 CsrLockedReferenceProcess(CsrProcess
);
168 /* Release the lock */
169 CsrReleaseProcessLock();
171 /* Duplicate the Object Directory */
172 Status
= NtDuplicateObject(NtCurrentProcess(),
174 CsrProcess
->ProcessHandle
,
175 &ConnectInfo
->ObjectDirectory
,
178 DUPLICATE_SAME_ACCESS
|
179 DUPLICATE_SAME_ATTRIBUTES
);
181 /* Acquire the lock */
182 CsrAcquireProcessLock();
184 /* Check for success */
185 if (NT_SUCCESS(Status
))
187 /* Attach the Shared Section */
188 Status
= CsrSrvAttachSharedSection(CsrProcess
, ConnectInfo
);
190 /* Check how this went */
191 if (NT_SUCCESS(Status
))
193 /* Allow the connection, and return debugging flag */
194 ConnectInfo
->DebugFlags
= CsrDebug
;
195 AllowConnection
= TRUE
;
199 /* Dereference the project */
200 CsrLockedDereferenceProcess(CsrProcess
);
204 /* Release the lock */
205 CsrReleaseProcessLock();
207 /* Setup the Port View Structure */
208 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
209 RemotePortView
.ViewSize
= 0;
210 RemotePortView
.ViewBase
= NULL
;
212 /* Save the Process ID */
213 ConnectInfo
->ServerProcessId
= NtCurrentTeb()->ClientId
.UniqueProcess
;
215 /* Accept the Connection */
216 Status
= NtAcceptConnectPort(&ServerPort
,
217 AllowConnection
? UlongToPtr(CsrProcess
->SequenceNumber
) : 0,
222 if (!NT_SUCCESS(Status
))
224 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status
);
226 else if (AllowConnection
)
230 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
231 ApiMessage
->Header
.ClientId
.UniqueProcess
,
232 ApiMessage
->Header
.ClientId
.UniqueThread
,
233 RemotePortView
.ViewBase
,
234 RemotePortView
.ViewSize
);
237 /* Set some Port Data in the Process */
238 CsrProcess
->ClientPort
= ServerPort
;
239 CsrProcess
->ClientViewBase
= (ULONG_PTR
)RemotePortView
.ViewBase
;
240 CsrProcess
->ClientViewBounds
= (ULONG_PTR
)((ULONG_PTR
)RemotePortView
.ViewBase
+
241 (ULONG_PTR
)RemotePortView
.ViewSize
);
243 /* Complete the connection */
244 Status
= NtCompleteConnectPort(ServerPort
);
245 if (!NT_SUCCESS(Status
))
247 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status
);
252 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
253 ApiMessage
->Header
.ClientId
.UniqueProcess
,
254 ApiMessage
->Header
.ClientId
.UniqueThread
);
257 /* Return status to caller */
262 * @name CsrpCheckRequestThreads
264 * The CsrpCheckRequestThreads routine checks if there are no more threads
265 * to handle CSR API Requests, and creates a new thread if possible, to
270 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
271 * if a new thread couldn't be created.
278 CsrpCheckRequestThreads(VOID
)
284 /* Decrease the count, and see if we're out */
285 if (InterlockedDecrementUL(&CsrpStaticThreadCount
) == 0)
287 /* Check if we've still got space for a Dynamic Thread */
288 if (CsrpDynamicThreadTotal
< CsrMaxApiRequestThreads
)
290 /* Create a new dynamic thread */
291 Status
= RtlCreateUserThread(NtCurrentProcess(),
297 (PVOID
)CsrApiRequestThread
,
302 if (NT_SUCCESS(Status
))
304 /* Increase the thread counts */
305 InterlockedIncrementUL(&CsrpStaticThreadCount
);
306 InterlockedIncrementUL(&CsrpDynamicThreadTotal
);
308 /* Add a new server thread */
309 if (CsrAddStaticServerThread(hThread
,
311 CsrThreadIsServerThread
))
314 NtResumeThread(hThread
, NULL
);
318 /* Failed to create a new static thread */
319 InterlockedDecrementUL(&CsrpStaticThreadCount
);
320 InterlockedDecrementUL(&CsrpDynamicThreadTotal
);
323 DPRINT1("Failing\n");
324 NtTerminateThread(hThread
, 0);
328 return STATUS_UNSUCCESSFUL
;
335 return STATUS_SUCCESS
;
339 * @name CsrApiRequestThread
341 * The CsrApiRequestThread routine handles incoming messages or connection
342 * requests on the CSR API LPC Port.
345 * System-default user-defined parameter. Unused.
347 * @return The thread exit code, if the thread is terminated.
349 * @remarks Before listening on the port, the routine will first attempt
350 * to connect to the user subsystem.
355 CsrApiRequestThread(IN PVOID Parameter
)
357 PTEB Teb
= NtCurrentTeb();
358 LARGE_INTEGER TimeOut
;
359 PCSR_THREAD CurrentThread
, CsrThread
;
361 CSR_REPLY_CODE ReplyCode
;
362 PCSR_API_MESSAGE ReplyMsg
;
363 CSR_API_MESSAGE ReceiveMsg
;
364 PCSR_PROCESS CsrProcess
;
365 PHARDERROR_MSG HardErrorMsg
;
367 PCSR_SERVER_DLL ServerDll
;
368 PCLIENT_DIED_MSG ClientDiedMsg
;
369 PDBGKM_MSG DebugMessage
;
370 ULONG ServerId
, ApiId
, MessageType
, i
;
373 /* Setup LPC loop port and message */
375 ReplyPort
= CsrApiPort
;
377 /* Connect to user32 */
378 while (!CsrConnectToUser())
380 /* Set up the timeout for the connect (30 seconds) */
381 TimeOut
.QuadPart
= -30 * 1000 * 1000 * 10;
383 /* Keep trying until we get a response */
384 Teb
->Win32ClientInfo
[0] = 0;
385 NtDelayExecution(FALSE
, &TimeOut
);
389 CurrentThread
= Teb
->CsrClientThread
;
391 /* If we got an event... */
394 /* Set it, to let stuff waiting on us load */
395 Status
= NtSetEvent((HANDLE
)Parameter
, NULL
);
396 ASSERT(NT_SUCCESS(Status
));
398 /* Increase the Thread Counts */
399 InterlockedIncrementUL(&CsrpStaticThreadCount
);
400 InterlockedIncrementUL(&CsrpDynamicThreadTotal
);
403 /* Now start the loop */
406 /* Make sure the real CID is set */
407 Teb
->RealClientId
= Teb
->ClientId
;
410 if (Teb
->CountOfOwnedCriticalSections
)
412 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
413 Teb
->CountOfOwnedCriticalSections
);
414 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
415 &ReceiveMsg
, ReplyMsg
);
419 /* Wait for a message to come through */
420 Status
= NtReplyWaitReceivePort(ReplyPort
,
425 /* Check if we didn't get success */
426 if (Status
!= STATUS_SUCCESS
)
428 /* Was it a failure or another success code? */
429 if (!NT_SUCCESS(Status
))
431 /* Check for specific status cases */
432 if ((Status
!= STATUS_INVALID_CID
) &&
433 (Status
!= STATUS_UNSUCCESSFUL
) &&
434 ((Status
== STATUS_INVALID_HANDLE
) || (ReplyPort
== CsrApiPort
)))
436 /* Notify the debugger */
437 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
438 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort
, CsrApiPort
);
441 /* We failed big time, so start out fresh */
443 ReplyPort
= CsrApiPort
;
448 /* A strange "success" code, just try again */
449 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status
);
454 /* Use whatever Client ID we got */
455 Teb
->RealClientId
= ReceiveMsg
.Header
.ClientId
;
457 /* Get the Message Type */
458 MessageType
= ReceiveMsg
.Header
.u2
.s2
.Type
;
460 /* Handle connection requests */
461 if (MessageType
== LPC_CONNECTION_REQUEST
)
463 /* Handle the Connection Request */
464 CsrApiHandleConnectionRequest(&ReceiveMsg
);
467 ReplyPort
= CsrApiPort
;
471 /* It's some other kind of request. Get the lock for the lookup */
472 CsrAcquireProcessLock();
474 /* Now do the lookup to get the CSR_THREAD */
475 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
,
476 &ReceiveMsg
.Header
.ClientId
);
478 /* Did we find a thread? */
481 /* This wasn't a CSR Thread, release lock */
482 CsrReleaseProcessLock();
484 /* If this was an exception, handle it */
485 if (MessageType
== LPC_EXCEPTION
)
487 ReplyMsg
= &ReceiveMsg
;
488 ReplyPort
= CsrApiPort
;
489 ReplyMsg
->Status
= DBG_CONTINUE
;
491 else if (MessageType
== LPC_PORT_CLOSED
||
492 MessageType
== LPC_CLIENT_DIED
)
494 /* The Client or Port are gone, loop again */
496 ReplyPort
= CsrApiPort
;
498 else if (MessageType
== LPC_ERROR_EVENT
)
500 /* If it's a hard error, handle this too */
501 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
503 /* Default it to unhandled */
504 HardErrorMsg
->Response
= ResponseNotHandled
;
506 /* Check if there are free api threads */
507 CsrpCheckRequestThreads();
508 if (CsrpStaticThreadCount
)
510 /* Loop every Server DLL */
511 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
513 /* Get the Server DLL */
514 ServerDll
= CsrLoadedServerDll
[i
];
516 /* Check if it's valid and if it has a Hard Error Callback */
517 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
520 ServerDll
->HardErrorCallback(NULL
/* == CsrThread */, HardErrorMsg
);
522 /* If it's handled, get out of here */
523 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
528 /* Increase the thread count */
529 InterlockedIncrementUL(&CsrpStaticThreadCount
);
531 /* If the response was 0xFFFFFFFF, we'll ignore it */
532 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
535 ReplyPort
= CsrApiPort
;
539 ReplyMsg
= &ReceiveMsg
;
540 ReplyPort
= CsrApiPort
;
543 else if (MessageType
== LPC_REQUEST
)
545 /* This is an API Message coming from a non-CSR Thread */
546 ReplyMsg
= &ReceiveMsg
;
547 ReplyPort
= CsrApiPort
;
548 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
550 else if (MessageType
== LPC_DATAGRAM
)
552 /* This is an API call, get the Server ID */
553 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
555 /* Make sure that the ID is within limits, and the Server DLL loaded */
557 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
558 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
560 /* We are beyond the Maximum Server ID */
561 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
562 ServerId
, ServerDll
);
566 ReplyPort
= CsrApiPort
;
570 /* Get the API ID, normalized with our Base ID */
571 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
573 /* Make sure that the ID is within limits, and the entry exists */
574 if (ApiId
>= ServerDll
->HighestApiSupported
)
576 /* We are beyond the Maximum API ID, or it doesn't exist */
577 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
578 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
581 ReplyPort
= CsrApiPort
;
589 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
590 Teb
->ClientId
.UniqueThread
,
591 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
592 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
593 ServerDll
->NameTable
[ApiId
],
599 ReceiveMsg
.Status
= STATUS_SUCCESS
;
601 /* Validation complete, start SEH */
604 /* Make sure we have enough threads */
605 CsrpCheckRequestThreads();
607 /* Call the API and get the reply code */
609 ReplyPort
= CsrApiPort
;
610 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &ReplyCode
);
612 /* Increase the static thread count */
613 InterlockedIncrementUL(&CsrpStaticThreadCount
);
615 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
618 ReplyPort
= CsrApiPort
;
624 /* Some other ignored message type */
626 ReplyPort
= CsrApiPort
;
633 /* We have a valid thread, was this an LPC Request? */
634 if (MessageType
!= LPC_REQUEST
)
636 /* It's not an API, check if the client died */
637 if (MessageType
== LPC_CLIENT_DIED
)
639 /* Get the information and check if it matches our thread */
640 ClientDiedMsg
= (PCLIENT_DIED_MSG
)&ReceiveMsg
;
641 if (ClientDiedMsg
->CreateTime
.QuadPart
== CsrThread
->CreateTime
.QuadPart
)
643 /* Now we reply to the dying client */
644 ReplyPort
= CsrThread
->Process
->ClientPort
;
646 /* Reference the thread */
647 CsrLockedReferenceThread(CsrThread
);
649 /* Destroy the thread in the API Message */
650 CsrDestroyThread(&ReceiveMsg
.Header
.ClientId
);
652 /* Check if the thread was actually ourselves */
653 if (CsrProcess
->ThreadCount
== 1)
655 /* Kill the process manually here */
656 CsrDestroyProcess(&CsrThread
->ClientId
, 0);
659 /* Remove our extra reference */
660 CsrLockedDereferenceThread(CsrThread
);
663 /* Release the lock and keep looping */
664 CsrReleaseProcessLock();
667 ReplyPort
= CsrApiPort
;
671 /* Reference the thread and release the lock */
672 CsrLockedReferenceThread(CsrThread
);
673 CsrReleaseProcessLock();
675 /* Check if this was an exception */
676 if (MessageType
== LPC_EXCEPTION
)
678 /* Kill the process */
679 NtTerminateProcess(CsrProcess
->ProcessHandle
, STATUS_ABANDONED
);
681 /* Destroy it from CSR */
682 CsrDestroyProcess(&ReceiveMsg
.Header
.ClientId
, STATUS_ABANDONED
);
684 /* Return a Debug Message */
685 DebugMessage
= (PDBGKM_MSG
)&ReceiveMsg
;
686 DebugMessage
->ReturnedStatus
= DBG_CONTINUE
;
687 ReplyMsg
= &ReceiveMsg
;
688 ReplyPort
= CsrApiPort
;
690 /* Remove our extra reference */
691 CsrDereferenceThread(CsrThread
);
693 else if (MessageType
== LPC_ERROR_EVENT
)
695 /* If it's a hard error, handle this too */
696 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
698 /* Default it to unhandled */
699 HardErrorMsg
->Response
= ResponseNotHandled
;
701 /* Check if there are free api threads */
702 CsrpCheckRequestThreads();
703 if (CsrpStaticThreadCount
)
705 /* Loop every Server DLL */
706 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
708 /* Get the Server DLL */
709 ServerDll
= CsrLoadedServerDll
[i
];
711 /* Check if it's valid and if it has a Hard Error Callback */
712 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
715 ServerDll
->HardErrorCallback(CsrThread
, HardErrorMsg
);
717 /* If it's handled, get out of here */
718 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
723 /* Increase the thread count */
724 InterlockedIncrementUL(&CsrpStaticThreadCount
);
726 /* If the response was 0xFFFFFFFF, we'll ignore it */
727 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
730 ReplyPort
= CsrApiPort
;
734 CsrDereferenceThread(CsrThread
);
735 ReplyMsg
= &ReceiveMsg
;
736 ReplyPort
= CsrApiPort
;
742 CsrDereferenceThread(CsrThread
);
750 /* We got an API Request */
751 CsrLockedReferenceThread(CsrThread
);
752 CsrReleaseProcessLock();
754 /* This is an API call, get the Server ID */
755 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
757 /* Make sure that the ID is within limits, and the Server DLL loaded */
759 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
760 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
762 /* We are beyond the Maximum Server ID */
763 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
764 ServerId
, ServerDll
);
767 ReplyPort
= CsrApiPort
;
768 ReplyMsg
= &ReceiveMsg
;
769 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
770 CsrDereferenceThread(CsrThread
);
774 /* Get the API ID, normalized with our Base ID */
775 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
777 /* Make sure that the ID is within limits, and the entry exists */
778 if (ApiId
>= ServerDll
->HighestApiSupported
)
780 /* We are beyond the Maximum API ID, or it doesn't exist */
781 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
782 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
785 ReplyPort
= CsrApiPort
;
786 ReplyMsg
= &ReceiveMsg
;
787 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
788 CsrDereferenceThread(CsrThread
);
795 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x, Process %08x - %08x\n",
796 Teb
->ClientId
.UniqueThread
,
797 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
798 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
799 ServerDll
->NameTable
[ApiId
],
807 ReplyMsg
= &ReceiveMsg
;
808 ReceiveMsg
.Status
= STATUS_SUCCESS
;
810 /* Now we reply to a particular client */
811 ReplyPort
= CsrThread
->Process
->ClientPort
;
813 /* Check if there's a capture buffer */
814 if (ReceiveMsg
.CsrCaptureData
)
816 /* Capture the arguments */
817 if (!CsrCaptureArguments(CsrThread
, &ReceiveMsg
))
819 /* Ignore this message if we failed to get the arguments */
820 CsrDereferenceThread(CsrThread
);
825 /* Validation complete, start SEH */
828 /* Make sure we have enough threads */
829 CsrpCheckRequestThreads();
831 Teb
->CsrClientThread
= CsrThread
;
833 /* Call the API, get the reply code and return the result */
834 ReplyCode
= CsrReplyImmediately
;
835 ReplyMsg
->Status
= ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &ReplyCode
);
837 /* Increase the static thread count */
838 InterlockedIncrementUL(&CsrpStaticThreadCount
);
840 Teb
->CsrClientThread
= CurrentThread
;
842 if (ReplyCode
== CsrReplyAlreadySent
)
844 if (ReceiveMsg
.CsrCaptureData
)
846 CsrReleaseCapturedArguments(&ReceiveMsg
);
849 ReplyPort
= CsrApiPort
;
850 CsrDereferenceThread(CsrThread
);
852 else if (ReplyCode
== CsrReplyDeadClient
)
854 /* Reply to the death message */
855 NtReplyPort(ReplyPort
, &ReplyMsg
->Header
);
857 /* Reply back to the API port now */
859 ReplyPort
= CsrApiPort
;
861 CsrDereferenceThread(CsrThread
);
863 else if (ReplyCode
== CsrReplyPending
)
866 ReplyPort
= CsrApiPort
;
870 if (ReceiveMsg
.CsrCaptureData
)
872 CsrReleaseCapturedArguments(&ReceiveMsg
);
874 CsrDereferenceThread(CsrThread
);
877 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
880 ReplyPort
= CsrApiPort
;
885 /* We're out of the loop for some reason, terminate! */
886 NtTerminateThread(NtCurrentThread(), Status
);
891 * @name CsrApiPortInitialize
893 * The CsrApiPortInitialize routine initializes the LPC Port used for
894 * communications with the Client/Server Runtime (CSR) and initializes the
895 * static thread that will handle connection requests and APIs.
899 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
906 CsrApiPortInitialize(VOID
)
909 OBJECT_ATTRIBUTES ObjectAttributes
;
911 HANDLE hRequestEvent
, hThread
;
913 PLIST_ENTRY ListHead
, NextEntry
;
914 PCSR_THREAD ServerThread
;
916 /* Calculate how much space we'll need for the Port Name */
917 Size
= CsrDirectoryName
.Length
+ sizeof(CSR_PORT_NAME
) + sizeof(WCHAR
);
919 /* Create the buffer for it */
920 CsrApiPortName
.Buffer
= RtlAllocateHeap(CsrHeap
, 0, Size
);
921 if (!CsrApiPortName
.Buffer
) return STATUS_NO_MEMORY
;
923 /* Setup the rest of the empty string */
924 CsrApiPortName
.Length
= 0;
925 CsrApiPortName
.MaximumLength
= (USHORT
)Size
;
926 RtlAppendUnicodeStringToString(&CsrApiPortName
, &CsrDirectoryName
);
927 RtlAppendUnicodeToString(&CsrApiPortName
, UNICODE_PATH_SEP
);
928 RtlAppendUnicodeToString(&CsrApiPortName
, CSR_PORT_NAME
);
931 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName
);
932 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
933 sizeof(CSR_API_CONNECTINFO
), sizeof(CSR_API_MESSAGE
));
936 /* FIXME: Create a Security Descriptor */
938 /* Initialize the Attributes */
939 InitializeObjectAttributes(&ObjectAttributes
,
943 NULL
/* FIXME: Use the Security Descriptor */);
945 /* Create the Port Object */
946 Status
= NtCreatePort(&CsrApiPort
,
948 sizeof(CSR_API_CONNECTINFO
),
949 sizeof(CSR_API_MESSAGE
),
951 if (NT_SUCCESS(Status
))
953 /* Create the event the Port Thread will use */
954 Status
= NtCreateEvent(&hRequestEvent
,
957 SynchronizationEvent
,
959 if (NT_SUCCESS(Status
))
961 /* Create the Request Thread */
962 Status
= RtlCreateUserThread(NtCurrentProcess(),
968 (PVOID
)CsrApiRequestThread
,
969 (PVOID
)hRequestEvent
,
972 if (NT_SUCCESS(Status
))
974 /* Add this as a static thread to CSRSRV */
975 CsrAddStaticServerThread(hThread
, &ClientId
, CsrThreadIsServerThread
);
977 /* Get the Thread List Pointers */
978 ListHead
= &CsrRootProcess
->ThreadList
;
979 NextEntry
= ListHead
->Flink
;
981 /* Start looping the list */
982 while (NextEntry
!= ListHead
)
985 ServerThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
988 Status
= NtResumeThread(ServerThread
->ThreadHandle
, NULL
);
990 /* Is this a Server Thread? */
991 if (ServerThread
->Flags
& CsrThreadIsServerThread
)
993 /* If so, then wait for it to initialize */
994 Status
= NtWaitForSingleObject(hRequestEvent
, FALSE
, NULL
);
995 ASSERT(NT_SUCCESS(Status
));
999 NextEntry
= NextEntry
->Flink
;
1002 /* We don't need this anymore */
1003 NtClose(hRequestEvent
);
1013 * @name CsrConnectToUser
1016 * The CsrConnectToUser connects to the User subsystem.
1020 * @return A pointer to the CSR Thread
1027 CsrConnectToUser(VOID
)
1030 ANSI_STRING DllName
;
1031 UNICODE_STRING TempName
;
1034 PTEB Teb
= NtCurrentTeb();
1035 PCSR_THREAD CsrThread
;
1038 /* Check if we didn't already find it */
1039 if (!CsrClientThreadSetup
)
1041 /* Get the DLL Handle for user32.dll */
1042 RtlInitAnsiString(&DllName
, "user32");
1043 RtlAnsiStringToUnicodeString(&TempName
, &DllName
, TRUE
);
1044 Status
= LdrGetDllHandle(NULL
,
1048 RtlFreeUnicodeString(&TempName
);
1050 /* If we got the handle, get the Client Thread Startup Entrypoint */
1051 if (NT_SUCCESS(Status
))
1053 RtlInitAnsiString(&StartupName
,"ClientThreadSetup");
1054 Status
= LdrGetProcedureAddress(hUser32
,
1057 (PVOID
)&CsrClientThreadSetup
);
1061 /* Connect to user32 */
1064 Connected
= CsrClientThreadSetup();
1066 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1073 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1077 /* Save pointer to this thread in TEB */
1078 CsrAcquireProcessLock();
1079 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1080 CsrReleaseProcessLock();
1081 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1088 * @name CsrQueryApiPort
1091 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1095 * @return A handle to the port.
1102 CsrQueryApiPort(VOID
)
1108 * @name CsrCaptureArguments
1109 * @implemented NT5.1
1111 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1112 * re-captures it into a server CSR Capture Buffer.
1115 * Pointer to the CSR Thread performing the validation.
1118 * Pointer to the CSR API Message containing the Capture Buffer
1119 * that needs to be validated.
1121 * @return TRUE if validation succeeded, FALSE otherwise.
1128 CsrCaptureArguments(IN PCSR_THREAD CsrThread
,
1129 IN PCSR_API_MESSAGE ApiMessage
)
1131 PCSR_CAPTURE_BUFFER LocalCaptureBuffer
= NULL
, RemoteCaptureBuffer
= NULL
;
1132 SIZE_T BufferDistance
;
1135 PULONG_PTR OffsetPointer
;
1136 ULONG_PTR CurrentOffset
;
1138 /* Use SEH to make sure this is valid */
1141 /* Get the buffer we got from whoever called NTDLL */
1142 LocalCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1143 Length
= LocalCaptureBuffer
->Size
;
1145 /* Now check if the buffer is inside our mapped section */
1146 if (((ULONG_PTR
)LocalCaptureBuffer
< CsrThread
->Process
->ClientViewBase
) ||
1147 (((ULONG_PTR
)LocalCaptureBuffer
+ Length
) >= CsrThread
->Process
->ClientViewBounds
))
1149 /* Return failure */
1150 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1151 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1152 _SEH2_YIELD(return FALSE
);
1155 /* Check if the Length is valid */
1156 if ((FIELD_OFFSET(CSR_CAPTURE_BUFFER
, PointerOffsetsArray
) +
1157 (LocalCaptureBuffer
->PointerCount
* sizeof(PVOID
)) > Length
) ||
1158 (LocalCaptureBuffer
->PointerCount
> MAXUSHORT
))
1160 /* Return failure */
1161 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer
);
1163 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1164 _SEH2_YIELD(return FALSE
);
1167 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1169 /* Return failure */
1170 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1171 _SEH2_YIELD(return FALSE
);
1174 /* We validated the incoming buffer, now allocate the remote one */
1175 RemoteCaptureBuffer
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, Length
);
1176 if (!RemoteCaptureBuffer
)
1178 /* We're out of memory */
1179 ApiMessage
->Status
= STATUS_NO_MEMORY
;
1183 /* Copy the client's buffer */
1184 RtlMoveMemory(RemoteCaptureBuffer
, LocalCaptureBuffer
, Length
);
1186 /* Calculate the difference between our buffer and the client's */
1187 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1190 * All the pointer offsets correspond to pointers which point
1191 * to the remote data buffer instead of the local one.
1193 PointerCount
= RemoteCaptureBuffer
->PointerCount
;
1194 OffsetPointer
= RemoteCaptureBuffer
->PointerOffsetsArray
;
1195 while (PointerCount
--)
1197 CurrentOffset
= *OffsetPointer
;
1199 if (CurrentOffset
!= 0)
1201 /* Get the pointer corresponding to the offset */
1202 CurrentOffset
+= (ULONG_PTR
)ApiMessage
;
1204 /* Validate the bounds of the current pointed pointer */
1205 if ((*(PULONG_PTR
)CurrentOffset
>= CsrThread
->Process
->ClientViewBase
) &&
1206 (*(PULONG_PTR
)CurrentOffset
< CsrThread
->Process
->ClientViewBounds
))
1208 /* Modify the pointed pointer to take into account its new position */
1209 *(PULONG_PTR
)CurrentOffset
+= BufferDistance
;
1213 /* Invalid pointer, fail */
1214 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1216 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1223 /* Check if we got success */
1224 if (ApiMessage
->Status
!= STATUS_SUCCESS
)
1226 /* Failure. Free the buffer and return */
1227 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1232 /* Success, save the previous buffer and use the remote capture buffer */
1233 RemoteCaptureBuffer
->PreviousCaptureBuffer
= LocalCaptureBuffer
;
1234 ApiMessage
->CsrCaptureData
= RemoteCaptureBuffer
;
1242 * @name CsrReleaseCapturedArguments
1243 * @implemented NT5.1
1245 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1246 * that was previously captured with CsrCaptureArguments.
1249 * Pointer to the CSR API Message containing the Capture Buffer
1250 * that needs to be released.
1259 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage
)
1261 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer
, LocalCaptureBuffer
;
1262 SIZE_T BufferDistance
;
1264 PULONG_PTR OffsetPointer
;
1265 ULONG_PTR CurrentOffset
;
1267 /* Get the remote capture buffer */
1268 RemoteCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1270 /* Do not continue if there is no captured buffer */
1271 if (!RemoteCaptureBuffer
) return;
1273 /* If there is one, get the corresponding local capture buffer */
1274 LocalCaptureBuffer
= RemoteCaptureBuffer
->PreviousCaptureBuffer
;
1276 /* Free the previous one and use again the local capture buffer */
1277 RemoteCaptureBuffer
->PreviousCaptureBuffer
= NULL
;
1278 ApiMessage
->CsrCaptureData
= LocalCaptureBuffer
;
1280 /* Calculate the difference between our buffer and the client's */
1281 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1284 * All the pointer offsets correspond to pointers which point
1285 * to the local data buffer instead of the remote one (revert
1286 * the logic of CsrCaptureArguments).
1288 PointerCount
= RemoteCaptureBuffer
->PointerCount
;
1289 OffsetPointer
= RemoteCaptureBuffer
->PointerOffsetsArray
;
1290 while (PointerCount
--)
1292 CurrentOffset
= *OffsetPointer
;
1294 if (CurrentOffset
!= 0)
1296 /* Get the pointer corresponding to the offset */
1297 CurrentOffset
+= (ULONG_PTR
)ApiMessage
;
1299 /* Modify the pointed pointer to take into account its new position */
1300 *(PULONG_PTR
)CurrentOffset
-= BufferDistance
;
1306 /* Copy the data back */
1307 RtlMoveMemory(LocalCaptureBuffer
, RemoteCaptureBuffer
, RemoteCaptureBuffer
->Size
);
1309 /* Free our allocated buffer */
1310 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
);
1408 * @name CsrValidateMessageString
1409 * @implemented NT5.1
1411 * The CsrValidateMessageString validates a captured Wide-Character String
1412 * present in a CSR API Message.
1415 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1417 * @param MessageString
1418 * Pointer to the buffer containing the string to validate.
1420 * @return TRUE if validation succeeded, FALSE otherwise.
1427 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage
,
1428 IN LPWSTR
*MessageString
)
1432 return CsrValidateMessageBuffer(ApiMessage
,
1433 (PVOID
*)MessageString
,
1434 wcslen(*MessageString
) + 1,