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 CallHardError(IN PCSR_THREAD ThreadData
,
29 IN PHARDERROR_MSG HardErrorMessage
);
35 CsrHandleHardError(IN PCSR_THREAD ThreadData
,
36 IN OUT PHARDERROR_MSG Message
)
38 DPRINT1("CSR: received hard error %lx\n", Message
->Status
);
40 /* Call the hard error handler in win32csr */
41 CallHardError(ThreadData
, Message
);
46 * @name CsrCallServerFromServer
49 * The CsrCallServerFromServer routine calls a CSR API from within a server.
50 * It avoids using LPC messages since the request isn't coming from a client.
53 * Pointer to the CSR API Message to send to the server.
56 * Pointer to the CSR API Message to receive from the server.
58 * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
59 * if the ApiNumber is invalid, or STATUS_ACCESS_VIOLATION if there
60 * was a problem executing the API.
67 CsrCallServerFromServer(IN PCSR_API_MESSAGE ReceiveMsg
,
68 IN OUT PCSR_API_MESSAGE ReplyMsg
)
71 PCSR_SERVER_DLL ServerDll
;
76 /* Get the Server ID */
77 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
->ApiNumber
);
79 /* Make sure that the ID is within limits, and the Server DLL loaded */
80 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
81 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
83 /* We are beyond the Maximum Server ID */
84 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId
, ServerDll
);
85 ReplyMsg
->Status
= (ULONG
)STATUS_ILLEGAL_FUNCTION
;
86 return STATUS_ILLEGAL_FUNCTION
;
90 /* Get the API ID, normalized with our Base ID */
91 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
->ApiNumber
) - ServerDll
->ApiBase
;
93 /* Make sure that the ID is within limits, and the entry exists */
94 if ((ApiId
>= ServerDll
->HighestApiSupported
) ||
95 ((ServerDll
->ValidTable
) && !(ServerDll
->ValidTable
[ApiId
])))
97 /* We are beyond the Maximum API ID, or it doesn't exist */
98 DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
99 "invalid API to call from the server.\n",
100 ServerDll
->ValidTable
[ApiId
],
101 ((ServerDll
->NameTable
) && (ServerDll
->NameTable
[ApiId
])) ?
102 ServerDll
->NameTable
[ApiId
] : "*** UNKNOWN ***", &ServerDll
->Name
);
104 ReplyMsg
->Status
= (ULONG
)STATUS_ILLEGAL_FUNCTION
;
105 return STATUS_ILLEGAL_FUNCTION
;
111 DPRINT1("CSRSS: %s Api Request received from server process\n",
112 ServerDll
->NameTable
[ApiId
]);
115 /* Validation complete, start SEH */
118 /* Call the API and get the result */
119 /// CsrApiCallHandler(ReplyMsg, /*ProcessData*/ &ReplyCode); ///
120 Status
= (ServerDll
->DispatchTable
[ApiId
])(ReceiveMsg
, &Reply
);
122 /* Return the result, no matter what it is */
123 ReplyMsg
->Status
= Status
;
125 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
127 /* If we got an exception, return access violation */
128 ReplyMsg
->Status
= STATUS_ACCESS_VIOLATION
;
133 return STATUS_SUCCESS
;
137 * @name CsrApiHandleConnectionRequest
139 * The CsrApiHandleConnectionRequest routine handles and accepts a new
140 * connection request to the CSR API LPC Port.
143 * Pointer to the incoming CSR API Message which contains the
144 * connection request.
146 * @return STATUS_SUCCESS in case of success, or status code which caused
147 * the routine to error.
149 * @remarks This routine is responsible for attaching the Shared Section to
150 * new clients connecting to CSR.
155 CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage
)
157 PCSR_THREAD CsrThread
= NULL
;
158 PCSR_PROCESS CsrProcess
= NULL
;
159 NTSTATUS Status
= STATUS_SUCCESS
;
160 PCSR_CONNECTION_INFO ConnectInfo
= &ApiMessage
->ConnectionInfo
;
161 BOOLEAN AllowConnection
= FALSE
;
162 REMOTE_PORT_VIEW RemotePortView
;
165 /* Acquire the Process Lock */
166 CsrAcquireProcessLock();
168 /* Lookup the CSR Thread */
169 CsrThread
= CsrLocateThreadByClientId(NULL
, &ApiMessage
->Header
.ClientId
);
171 /* Check if we have a thread */
174 /* Get the Process */
175 CsrProcess
= CsrThread
->Process
;
177 /* Make sure we have a Process as well */
180 /* Reference the Process */
181 CsrLockedReferenceProcess(CsrThread
->Process
);
183 /* Release the lock */
184 CsrReleaseProcessLock();
186 /* Duplicate the Object Directory */
187 Status
= NtDuplicateObject(NtCurrentProcess(),
189 CsrProcess
->ProcessHandle
,
190 &ConnectInfo
->ObjectDirectory
,
193 DUPLICATE_SAME_ACCESS
|
194 DUPLICATE_SAME_ATTRIBUTES
);
196 /* Acquire the lock */
197 CsrAcquireProcessLock();
199 /* Check for success */
200 if (NT_SUCCESS(Status
))
202 /* Attach the Shared Section */
203 Status
= CsrSrvAttachSharedSection(CsrProcess
, ConnectInfo
);
205 /* Check how this went */
206 if (NT_SUCCESS(Status
)) AllowConnection
= TRUE
;
209 /* Dereference the project */
210 CsrLockedDereferenceProcess(CsrProcess
);
214 /* Release the lock */
215 CsrReleaseProcessLock();
217 /* Setup the Port View Structure */
218 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
219 RemotePortView
.ViewSize
= 0;
220 RemotePortView
.ViewBase
= NULL
;
222 /* Save the Process ID */
223 ConnectInfo
->ProcessId
= NtCurrentTeb()->ClientId
.UniqueProcess
;
225 /* Accept the Connection */
226 Status
= NtAcceptConnectPort(&hPort
,
227 AllowConnection
? UlongToPtr(CsrProcess
->SequenceNumber
) : 0,
232 if (!NT_SUCCESS(Status
))
234 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status
);
236 else if (AllowConnection
)
240 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
241 ApiMessage
->Header
.ClientId
.UniqueProcess
,
242 ApiMessage
->Header
.ClientId
.UniqueThread
,
243 RemotePortView
.ViewBase
,
244 RemotePortView
.ViewSize
);
247 /* Set some Port Data in the Process */
248 CsrProcess
->ClientPort
= hPort
;
249 CsrProcess
->ClientViewBase
= (ULONG_PTR
)RemotePortView
.ViewBase
;
250 CsrProcess
->ClientViewBounds
= (ULONG_PTR
)((ULONG_PTR
)RemotePortView
.ViewBase
+
251 (ULONG_PTR
)RemotePortView
.ViewSize
);
253 /* Complete the connection */
254 Status
= NtCompleteConnectPort(hPort
);
255 if (!NT_SUCCESS(Status
))
257 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status
);
262 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
263 ApiMessage
->Header
.ClientId
.UniqueProcess
,
264 ApiMessage
->Header
.ClientId
.UniqueThread
);
267 /* Return status to caller */
271 // TODO: See CsrApiHandleConnectionRequest
273 CsrpHandleConnectionRequest(PPORT_MESSAGE Request
)
276 HANDLE ServerPort
= NULL
;//, ServerThread = NULL;
277 PCSR_PROCESS ProcessData
= NULL
;
278 REMOTE_PORT_VIEW RemotePortView
;
279 // CLIENT_ID ClientId;
280 BOOLEAN AllowConnection
= FALSE
;
281 PCSR_CONNECTION_INFO ConnectInfo
;
284 DPRINT1("CSR: %s: Handling: %p\n", __FUNCTION__
, Request
);
286 ConnectInfo
= (PCSR_CONNECTION_INFO
)(Request
+ 1);
288 /* Save the process ID */
289 RtlZeroMemory(ConnectInfo
, sizeof(CSR_CONNECTION_INFO
));
291 CsrLockProcessByClientId(Request
->ClientId
.UniqueProcess
, &ProcessData
);
294 DPRINT1("CSRSRV: Unknown process: %lx. Will be rejecting connection\n",
295 Request
->ClientId
.UniqueProcess
);
298 if ((ProcessData
) && (ProcessData
!= CsrRootProcess
))
300 /* Attach the Shared Section */
301 Status
= CsrSrvAttachSharedSection(ProcessData
, ConnectInfo
);
302 if (NT_SUCCESS(Status
))
304 DPRINT1("Connection ok\n");
305 AllowConnection
= TRUE
;
309 DPRINT1("Shared section map failed: %lx\n", Status
);
312 else if (ProcessData
== CsrRootProcess
)
314 AllowConnection
= TRUE
;
317 /* Release the process */
318 if (ProcessData
) CsrUnlockProcess(ProcessData
);
320 /* Setup the Port View Structure */
321 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
322 RemotePortView
.ViewSize
= 0;
323 RemotePortView
.ViewBase
= NULL
;
325 /* Save the Process ID */
326 ConnectInfo
->ProcessId
= NtCurrentTeb()->ClientId
.UniqueProcess
;
328 Status
= NtAcceptConnectPort(&ServerPort
,
329 AllowConnection
? UlongToPtr(ProcessData
->SequenceNumber
) : 0,
334 if (!NT_SUCCESS(Status
))
336 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status
);
338 else if (AllowConnection
)
342 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
343 Request
->ClientId
.UniqueProcess
,
344 Request
->ClientId
.UniqueThread
,
345 RemotePortView
.ViewBase
,
346 RemotePortView
.ViewSize
);
349 /* Set some Port Data in the Process */
350 ProcessData
->ClientPort
= ServerPort
;
351 ProcessData
->ClientViewBase
= (ULONG_PTR
)RemotePortView
.ViewBase
;
352 ProcessData
->ClientViewBounds
= (ULONG_PTR
)((ULONG_PTR
)RemotePortView
.ViewBase
+
353 (ULONG_PTR
)RemotePortView
.ViewSize
);
355 /* Complete the connection */
356 Status
= NtCompleteConnectPort(ServerPort
);
357 if (!NT_SUCCESS(Status
))
359 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status
);
364 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
365 Request
->ClientId
.UniqueProcess
,
366 Request
->ClientId
.UniqueThread
);
373 * @name CsrpCheckRequestThreads
375 * The CsrpCheckRequestThreads routine checks if there are no more threads
376 * to handle CSR API Requests, and creates a new thread if possible, to
381 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
382 * if a new thread couldn't be created.
389 CsrpCheckRequestThreads(VOID
)
395 /* Decrease the count, and see if we're out */
396 if (!(_InterlockedDecrement(&CsrpStaticThreadCount
)))
398 /* Check if we've still got space for a Dynamic Thread */
399 if (CsrpDynamicThreadTotal
< CsrMaxApiRequestThreads
)
401 /* Create a new dynamic thread */
402 Status
= RtlCreateUserThread(NtCurrentProcess(),
408 (PVOID
)CsrApiRequestThread
,
413 if (NT_SUCCESS(Status
))
415 /* Increase the thread counts */
416 _InterlockedIncrement(&CsrpStaticThreadCount
);
417 _InterlockedIncrement(&CsrpDynamicThreadTotal
);
419 /* Add a new server thread */
420 if (CsrAddStaticServerThread(hThread
,
422 CsrThreadIsServerThread
))
425 NtResumeThread(hThread
, NULL
);
429 /* Failed to create a new static thread */
430 _InterlockedDecrement(&CsrpStaticThreadCount
);
431 _InterlockedDecrement(&CsrpDynamicThreadTotal
);
434 DPRINT1("Failing\n");
435 NtTerminateThread(hThread
, 0);
439 return STATUS_UNSUCCESSFUL
;
446 return STATUS_SUCCESS
;
450 * @name CsrApiRequestThread
452 * The CsrApiRequestThread routine handles incoming messages or connection
453 * requests on the CSR API LPC Port.
456 * System-default user-defined parameter. Unused.
458 * @return The thread exit code, if the thread is terminated.
460 * @remarks Before listening on the port, the routine will first attempt
461 * to connect to the user subsystem.
466 CsrApiRequestThread(IN PVOID Parameter
)
468 PTEB Teb
= NtCurrentTeb();
469 LARGE_INTEGER TimeOut
;
470 PCSR_THREAD CurrentThread
, CsrThread
;
472 PCSR_API_MESSAGE ReplyMsg
;
473 CSR_API_MESSAGE ReceiveMsg
;
474 PCSR_PROCESS CsrProcess
;
475 PHARDERROR_MSG HardErrorMsg
;
477 PCSR_SERVER_DLL ServerDll
;
478 PCLIENT_DIED_MSG ClientDiedMsg
;
479 PDBGKM_MSG DebugMessage
;
480 ULONG ServerId
, ApiId
, Reply
, MessageType
, i
;
483 /* Setup LPC loop port and message */
485 ReplyPort
= CsrApiPort
;
487 /* Connect to user32 */
488 while (!CsrConnectToUser())
490 /* Set up the timeout for the connect (30 seconds) */
491 TimeOut
.QuadPart
= -30 * 1000 * 1000 * 10;
493 /* Keep trying until we get a response */
494 Teb
->Win32ClientInfo
[0] = 0;
495 NtDelayExecution(FALSE
, &TimeOut
);
499 CurrentThread
= Teb
->CsrClientThread
;
501 /* If we got an event... */
504 /* Set it, to let stuff waiting on us load */
505 Status
= NtSetEvent((HANDLE
)Parameter
, NULL
);
506 ASSERT(NT_SUCCESS(Status
));
508 /* Increase the Thread Counts */
509 _InterlockedIncrement(&CsrpStaticThreadCount
);
510 _InterlockedIncrement(&CsrpDynamicThreadTotal
);
513 /* Now start the loop */
516 /* Make sure the real CID is set */
517 Teb
->RealClientId
= Teb
->ClientId
;
520 if (Teb
->CountOfOwnedCriticalSections
)
522 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
523 Teb
->CountOfOwnedCriticalSections
);
524 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
525 &ReceiveMsg
, ReplyMsg
);
529 /* Wait for a message to come through */
530 Status
= NtReplyWaitReceivePort(ReplyPort
,
535 /* Check if we didn't get success */
536 if (Status
!= STATUS_SUCCESS
)
538 /* Was it a failure or another success code? */
539 if (!NT_SUCCESS(Status
))
541 /* Check for specific status cases */
542 if ((Status
!= STATUS_INVALID_CID
) &&
543 (Status
!= STATUS_UNSUCCESSFUL
) &&
544 ((Status
== STATUS_INVALID_HANDLE
) || (ReplyPort
== CsrApiPort
)))
546 /* Notify the debugger */
547 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
548 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort
, CsrApiPort
);
551 /* We failed big time, so start out fresh */
553 ReplyPort
= CsrApiPort
;
558 /* A bizare "success" code, just try again */
559 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status
);
564 /* Use whatever Client ID we got */
565 Teb
->RealClientId
= ReceiveMsg
.Header
.ClientId
;
567 /* Get the Message Type */
568 MessageType
= ReceiveMsg
.Header
.u2
.s2
.Type
;
570 /* Handle connection requests */
571 if (MessageType
== LPC_CONNECTION_REQUEST
)
573 /* Handle the Connection Request */
574 CsrApiHandleConnectionRequest(&ReceiveMsg
);
575 ReplyPort
= CsrApiPort
;
580 /* It's some other kind of request. Get the lock for the lookup */
581 CsrAcquireProcessLock();
583 /* Now do the lookup to get the CSR_THREAD */
584 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
,
585 &ReceiveMsg
.Header
.ClientId
);
587 /* Did we find a thread? */
590 /* This wasn't a CSR Thread, release lock */
591 CsrReleaseProcessLock();
593 /* If this was an exception, handle it */
594 if (MessageType
== LPC_EXCEPTION
)
596 ReplyMsg
= &ReceiveMsg
;
597 ReplyPort
= CsrApiPort
;
598 ReplyMsg
->Status
= DBG_CONTINUE
;
600 else if (MessageType
== LPC_PORT_CLOSED
||
601 MessageType
== LPC_CLIENT_DIED
)
603 /* The Client or Port are gone, loop again */
605 ReplyPort
= CsrApiPort
;
607 else if (MessageType
== LPC_ERROR_EVENT
)
609 /* If it's a hard error, handle this too */
610 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
612 /* Default it to unhandled */
613 HardErrorMsg
->Response
= ResponseNotHandled
;
615 /* Check if there are free api threads */
616 CsrpCheckRequestThreads();
617 if (CsrpStaticThreadCount
)
619 /* Loop every Server DLL */
620 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
622 /* Get the Server DLL */
623 ServerDll
= CsrLoadedServerDll
[i
];
625 /* Check if it's valid and if it has a Hard Error Callback */
626 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
629 ServerDll
->HardErrorCallback(NULL
/* CsrThread */, HardErrorMsg
);
631 /* If it's handled, get out of here */
632 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
637 /* Increase the thread count */
638 _InterlockedIncrement(&CsrpStaticThreadCount
);
640 /* If the response was 0xFFFFFFFF, we'll ignore it */
641 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
644 ReplyPort
= CsrApiPort
;
648 ReplyMsg
= &ReceiveMsg
;
651 else if (MessageType
== LPC_REQUEST
)
653 /* This is an API Message coming from a non-CSR Thread */
654 ReplyMsg
= &ReceiveMsg
;
655 ReplyPort
= CsrApiPort
;
656 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
658 else if (MessageType
== LPC_DATAGRAM
)
660 /* This is an API call, get the Server ID */
661 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
663 /* Make sure that the ID is within limits, and the Server DLL loaded */
665 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
666 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
668 /* We are beyond the Maximum Server ID */
669 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
670 ServerId
, ServerDll
);
672 ReplyPort
= CsrApiPort
;
677 /* Get the API ID, normalized with our Base ID */
678 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
680 /* Make sure that the ID is within limits, and the entry exists */
681 if (ApiId
>= ServerDll
->HighestApiSupported
)
683 /* We are beyond the Maximum API ID, or it doesn't exist */
684 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
685 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
687 ReplyPort
= CsrApiPort
;
694 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
695 Teb
->ClientId
.UniqueThread
,
696 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
697 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
698 ServerDll
->NameTable
[ApiId
],
703 ReceiveMsg
.Status
= STATUS_SUCCESS
;
705 /* Validation complete, start SEH */
708 /* Make sure we have enough threads */
709 CsrpCheckRequestThreads();
711 /* Call the API and get the result */
713 ReplyPort
= CsrApiPort
;
714 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &Reply
);
716 /* Increase the static thread count */
717 _InterlockedIncrement(&CsrpStaticThreadCount
);
719 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
722 ReplyPort
= CsrApiPort
;
728 /* Some other ignored message type */
730 ReplyPort
= CsrApiPort
;
737 /* We have a valid thread, was this an LPC Request? */
738 if (MessageType
!= LPC_REQUEST
)
740 /* It's not an API, check if the client died */
741 if (MessageType
== LPC_CLIENT_DIED
)
743 /* Get the information and check if it matches our thread */
744 ClientDiedMsg
= (PCLIENT_DIED_MSG
)&ReceiveMsg
;
745 if (ClientDiedMsg
->CreateTime
.QuadPart
== CsrThread
->CreateTime
.QuadPart
)
747 /* Reference the thread */
748 CsrLockedReferenceThread(CsrThread
);
750 /* Destroy the thread in the API Message */
751 CsrDestroyThread(&ReceiveMsg
.Header
.ClientId
);
753 /* Check if the thread was actually ourselves */
754 if (CsrProcess
->ThreadCount
== 1)
756 /* Kill the process manually here */
757 CsrDestroyProcess(&CsrThread
->ClientId
, 0);
760 /* Remove our extra reference */
761 CsrLockedDereferenceThread(CsrThread
);
764 /* Release the lock and keep looping */
765 CsrReleaseProcessLock();
767 ReplyPort
= CsrApiPort
;
771 /* Reference the thread and release the lock */
772 CsrLockedReferenceThread(CsrThread
);
773 CsrReleaseProcessLock();
775 /* Check if this was an exception */
776 if (MessageType
== LPC_EXCEPTION
)
778 /* Kill the process */
779 NtTerminateProcess(CsrProcess
->ProcessHandle
, STATUS_ABANDONED
);
781 /* Destroy it from CSR */
782 CsrDestroyProcess(&ReceiveMsg
.Header
.ClientId
, STATUS_ABANDONED
);
784 /* Return a Debug Message */
785 DebugMessage
= (PDBGKM_MSG
)&ReceiveMsg
;
786 DebugMessage
->ReturnedStatus
= DBG_CONTINUE
;
787 ReplyMsg
= &ReceiveMsg
;
788 ReplyPort
= CsrApiPort
;
790 /* Remove our extra reference */
791 CsrDereferenceThread(CsrThread
);
793 else if (MessageType
== LPC_ERROR_EVENT
)
795 /* If it's a hard error, handle this too */
796 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
798 /* Default it to unhandled */
799 HardErrorMsg
->Response
= ResponseNotHandled
;
801 /* Check if there are free api threads */
802 CsrpCheckRequestThreads();
803 if (CsrpStaticThreadCount
)
805 /* Loop every Server DLL */
806 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
808 /* Get the Server DLL */
809 ServerDll
= CsrLoadedServerDll
[i
];
811 /* Check if it's valid and if it has a Hard Error Callback */
812 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
815 ServerDll
->HardErrorCallback(CsrThread
, HardErrorMsg
);
817 /* If it's handled, get out of here */
818 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
823 /* Increase the thread count */
824 _InterlockedIncrement(&CsrpStaticThreadCount
);
826 /* If the response was 0xFFFFFFFF, we'll ignore it */
827 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
830 ReplyPort
= CsrApiPort
;
834 CsrDereferenceThread(CsrThread
);
835 ReplyMsg
= &ReceiveMsg
;
836 ReplyPort
= CsrApiPort
;
842 CsrDereferenceThread(CsrThread
);
850 /* We got an API Request */
851 CsrLockedReferenceThread(CsrThread
);
852 CsrReleaseProcessLock();
854 /* This is an API call, get the Server ID */
855 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
857 /* Make sure that the ID is within limits, and the Server DLL loaded */
859 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
860 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
862 /* We are beyond the Maximum Server ID */
863 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
864 ServerId
, ServerDll
);
867 ReplyPort
= CsrApiPort
;
868 ReplyMsg
= &ReceiveMsg
;
869 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
870 CsrDereferenceThread(CsrThread
);
874 /* Get the API ID, normalized with our Base ID */
875 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
877 /* Make sure that the ID is within limits, and the entry exists */
878 if (ApiId
>= ServerDll
->HighestApiSupported
)
880 /* We are beyond the Maximum API ID, or it doesn't exist */
881 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
882 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
885 ReplyPort
= CsrApiPort
;
886 ReplyMsg
= &ReceiveMsg
;
887 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
888 CsrDereferenceThread(CsrThread
);
894 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
895 Teb
->ClientId
.UniqueThread
,
896 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
897 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
898 ServerDll
->NameTable
[ApiId
],
903 ReplyMsg
= &ReceiveMsg
;
904 ReceiveMsg
.Status
= STATUS_SUCCESS
;
906 /* Now we reply to a particular client */
907 ReplyPort
= CsrThread
->Process
->ClientPort
;
909 /* Check if there's a capture buffer */
910 if (ReceiveMsg
.CsrCaptureData
)
912 /* Capture the arguments */
913 if (!CsrCaptureArguments(CsrThread
, &ReceiveMsg
))
915 /* Ignore this message if we failed to get the arguments */
916 CsrDereferenceThread(CsrThread
);
921 /* Validation complete, start SEH */
924 /* Make sure we have enough threads */
925 CsrpCheckRequestThreads();
927 Teb
->CsrClientThread
= CsrThread
;
929 /* Call the API and get the result */
931 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &Reply
);
933 /* Increase the static thread count */
934 _InterlockedIncrement(&CsrpStaticThreadCount
);
936 Teb
->CsrClientThread
= CurrentThread
;
941 if (ReceiveMsg
.CsrCaptureData
)
943 CsrReleaseCapturedArguments(&ReceiveMsg
);
945 CsrDereferenceThread(CsrThread
);
946 ReplyPort
= CsrApiPort
;
950 NtReplyPort(ReplyPort
, &ReplyMsg
->Header
);
951 ReplyPort
= CsrApiPort
;
953 CsrDereferenceThread(CsrThread
);
957 ReplyPort
= CsrApiPort
;
962 if (ReceiveMsg
.CsrCaptureData
)
964 CsrReleaseCapturedArguments(&ReceiveMsg
);
966 CsrDereferenceThread(CsrThread
);
969 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
972 ReplyPort
= CsrApiPort
;
977 /* We're out of the loop for some reason, terminate! */
978 NtTerminateThread(NtCurrentThread(), Status
);
983 * @name CsrApiPortInitialize
985 * The CsrApiPortInitialize routine initializes the LPC Port used for
986 * communications with the Client/Server Runtime (CSR) and initializes the
987 * static thread that will handle connection requests and APIs.
991 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
999 CsrApiPortInitialize(VOID
)
1002 OBJECT_ATTRIBUTES ObjectAttributes
;
1004 HANDLE hRequestEvent
, hThread
;
1006 PLIST_ENTRY ListHead
, NextEntry
;
1007 PCSR_THREAD ServerThread
;
1009 /* Calculate how much space we'll need for the Port Name */
1010 Size
= CsrDirectoryName
.Length
+ sizeof(CSR_PORT_NAME
) + sizeof(WCHAR
);
1012 /* Create the buffer for it */
1013 CsrApiPortName
.Buffer
= RtlAllocateHeap(CsrHeap
, 0, Size
);
1014 if (!CsrApiPortName
.Buffer
) return STATUS_NO_MEMORY
;
1016 /* Setup the rest of the empty string */
1017 CsrApiPortName
.Length
= 0;
1018 CsrApiPortName
.MaximumLength
= (USHORT
)Size
;
1019 RtlAppendUnicodeStringToString(&CsrApiPortName
, &CsrDirectoryName
);
1020 RtlAppendUnicodeToString(&CsrApiPortName
, UNICODE_PATH_SEP
);
1021 RtlAppendUnicodeToString(&CsrApiPortName
, CSR_PORT_NAME
);
1024 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName
);
1025 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
1026 sizeof(CSR_CONNECTION_INFO
), sizeof(CSR_API_MESSAGE
));
1029 /* FIXME: Create a Security Descriptor */
1031 /* Initialize the Attributes */
1032 InitializeObjectAttributes(&ObjectAttributes
,
1038 /* Create the Port Object */
1039 Status
= NtCreatePort(&CsrApiPort
,
1041 LPC_MAX_DATA_LENGTH
, // HACK: the real value is: sizeof(CSR_CONNECTION_INFO),
1042 LPC_MAX_MESSAGE_LENGTH
, // HACK: the real value is: sizeof(CSR_API_MESSAGE),
1044 if (NT_SUCCESS(Status
))
1046 /* Create the event the Port Thread will use */
1047 Status
= NtCreateEvent(&hRequestEvent
,
1050 SynchronizationEvent
,
1052 if (NT_SUCCESS(Status
))
1054 /* Create the Request Thread */
1055 Status
= RtlCreateUserThread(NtCurrentProcess(),
1061 (PVOID
)CsrApiRequestThread
,
1062 (PVOID
)hRequestEvent
,
1065 if (NT_SUCCESS(Status
))
1067 /* Add this as a static thread to CSRSRV */
1068 CsrAddStaticServerThread(hThread
, &ClientId
, CsrThreadIsServerThread
);
1070 /* Get the Thread List Pointers */
1071 ListHead
= &CsrRootProcess
->ThreadList
;
1072 NextEntry
= ListHead
->Flink
;
1074 /* Start looping the list */
1075 while (NextEntry
!= ListHead
)
1077 /* Get the Thread */
1078 ServerThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
1081 Status
= NtResumeThread(ServerThread
->ThreadHandle
, NULL
);
1083 /* Is this a Server Thread? */
1084 if (ServerThread
->Flags
& CsrThreadIsServerThread
)
1086 /* If so, then wait for it to initialize */
1087 Status
= NtWaitForSingleObject(hRequestEvent
, FALSE
, NULL
);
1088 ASSERT(NT_SUCCESS(Status
));
1092 NextEntry
= NextEntry
->Flink
;
1095 /* We don't need this anymore */
1096 NtClose(hRequestEvent
);
1106 * @name CsrConnectToUser
1109 * The CsrConnectToUser connects to the User subsystem.
1113 * @return A pointer to the CSR Thread
1120 CsrConnectToUser(VOID
)
1122 #if 0 // This code is OK, however it is ClientThreadSetup which sucks.
1124 ANSI_STRING DllName
;
1125 UNICODE_STRING TempName
;
1128 PTEB Teb
= NtCurrentTeb();
1129 PCSR_THREAD CsrThread
;
1132 /* Check if we didn't already find it */
1133 if (!CsrClientThreadSetup
)
1135 /* Get the DLL Handle for user32.dll */
1136 RtlInitAnsiString(&DllName
, "user32");
1137 RtlAnsiStringToUnicodeString(&TempName
, &DllName
, TRUE
);
1138 Status
= LdrGetDllHandle(NULL
,
1142 RtlFreeUnicodeString(&TempName
);
1144 /* If we got teh handle, get the Client Thread Startup Entrypoint */
1145 if (NT_SUCCESS(Status
))
1147 RtlInitAnsiString(&StartupName
,"ClientThreadSetup");
1148 Status
= LdrGetProcedureAddress(hUser32
,
1151 (PVOID
)&CsrClientThreadSetup
);
1155 /* Connect to user32 */
1158 Connected
= CsrClientThreadSetup();
1160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1167 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1171 /* Save pointer to this thread in TEB */
1172 CsrAcquireProcessLock();
1173 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1174 CsrReleaseProcessLock();
1175 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1182 PTEB Teb
= NtCurrentTeb();
1183 PCSR_THREAD CsrThread
;
1185 /* Save pointer to this thread in TEB */
1186 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1187 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1195 * @name CsrQueryApiPort
1198 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1202 * @return A handle to the port.
1209 CsrQueryApiPort(VOID
)
1211 DPRINT("CSRSRV: %s called\n", __FUNCTION__
);
1216 * @name CsrCaptureArguments
1217 * @implemented NT5.1
1219 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1220 * re-captures it into a server CSR Capture Buffer.
1223 * Pointer to the CSR Thread performing the validation.
1226 * Pointer to the CSR API Message containing the Capture Buffer
1227 * that needs to be validated.
1229 * @return TRUE if validation succeeded, FALSE otherwise.
1236 CsrCaptureArguments(IN PCSR_THREAD CsrThread
,
1237 IN PCSR_API_MESSAGE ApiMessage
)
1239 PCSR_CAPTURE_BUFFER LocalCaptureBuffer
= NULL
, RemoteCaptureBuffer
= NULL
;
1240 SIZE_T BufferDistance
;
1244 /* Use SEH to make sure this is valid */
1247 /* Get the buffer we got from whoever called NTDLL */
1248 LocalCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1249 Length
= LocalCaptureBuffer
->Size
;
1251 /* Now check if the buffer is inside our mapped section */
1252 if (((ULONG_PTR
)LocalCaptureBuffer
< CsrThread
->Process
->ClientViewBase
) ||
1253 (((ULONG_PTR
)LocalCaptureBuffer
+ Length
) >= CsrThread
->Process
->ClientViewBounds
))
1255 /* Return failure */
1256 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1257 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1258 _SEH2_YIELD(return FALSE
);
1261 /* Check if the Length is valid */
1262 if ((FIELD_OFFSET(CSR_CAPTURE_BUFFER
, PointerOffsetsArray
) +
1263 (LocalCaptureBuffer
->PointerCount
* sizeof(PVOID
)) > Length
) ||
1266 /* Return failure */
1267 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer
);
1269 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1270 _SEH2_YIELD(return FALSE
);
1273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1275 /* Return failure */
1276 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1277 _SEH2_YIELD(return FALSE
);
1280 /* We validated the incoming buffer, now allocate the remote one */
1281 RemoteCaptureBuffer
= RtlAllocateHeap(CsrHeap
, 0, Length
);
1282 if (!RemoteCaptureBuffer
)
1284 /* We're out of memory */
1285 ApiMessage
->Status
= STATUS_NO_MEMORY
;
1289 /* Copy the client's buffer */
1290 RtlMoveMemory(RemoteCaptureBuffer
, LocalCaptureBuffer
, Length
);
1292 /* Calculate the difference between our buffer and the client's */
1293 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1296 * Convert all the pointer offsets into real pointers, and make
1297 * them point to the remote data buffer instead of the local one.
1299 for (i
= 0 ; i
< RemoteCaptureBuffer
->PointerCount
; ++i
)
1301 if (RemoteCaptureBuffer
->PointerOffsetsArray
[i
] != 0)
1303 RemoteCaptureBuffer
->PointerOffsetsArray
[i
] += (ULONG_PTR
)ApiMessage
;
1305 /* Validate the bounds of the current pointer */
1306 if ((*(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] >= CsrThread
->Process
->ClientViewBase
) &&
1307 (*(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] < CsrThread
->Process
->ClientViewBounds
))
1309 /* Modify the pointer to take into account its new position */
1310 *(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] += BufferDistance
;
1314 /* Invalid pointer, fail */
1315 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1317 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1322 /* Check if we got success */
1323 if (ApiMessage
->Status
!= STATUS_SUCCESS
)
1325 /* Failure. Free the buffer and return*/
1326 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1331 /* Success, save the previous buffer */
1332 RemoteCaptureBuffer
->PreviousCaptureBuffer
= LocalCaptureBuffer
;
1333 ApiMessage
->CsrCaptureData
= RemoteCaptureBuffer
;
1341 * @name CsrReleaseCapturedArguments
1342 * @implemented NT5.1
1344 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1345 * that was previously captured with CsrCaptureArguments.
1348 * Pointer to the CSR API Message containing the Capture Buffer
1349 * that needs to be released.
1358 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage
)
1360 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer
, LocalCaptureBuffer
;
1361 SIZE_T BufferDistance
;
1364 /* Get the capture buffers */
1365 RemoteCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1366 LocalCaptureBuffer
= RemoteCaptureBuffer
->PreviousCaptureBuffer
;
1368 /* Do not continue if there is no captured buffer */
1369 if (!RemoteCaptureBuffer
) return;
1371 /* Free the previous one */
1372 RemoteCaptureBuffer
->PreviousCaptureBuffer
= NULL
;
1374 /* Calculate the difference between our buffer and the client's */
1375 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1378 * Convert back all the pointers into pointer offsets, and make them
1379 * point to the local data buffer instead of the remote one (revert
1380 * the logic of CsrCaptureArguments).
1382 for (i
= 0 ; i
< RemoteCaptureBuffer
->PointerCount
; ++i
)
1384 if (RemoteCaptureBuffer
->PointerOffsetsArray
[i
] != 0)
1386 *(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] -= BufferDistance
;
1387 RemoteCaptureBuffer
->PointerOffsetsArray
[i
] -= (ULONG_PTR
)ApiMessage
;
1391 /* Copy the data back */
1392 RtlMoveMemory(LocalCaptureBuffer
, RemoteCaptureBuffer
, RemoteCaptureBuffer
->Size
);
1394 /* Free our allocated buffer */
1395 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1400 * @name CsrValidateMessageBuffer
1401 * @implemented NT5.1
1403 * The CsrValidateMessageBuffer routine validates a captured message buffer
1404 * present in the CSR Api Message
1407 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1410 * Pointer to the message buffer to validate.
1412 * @param ElementCount
1413 * Number of elements contained in the message buffer.
1415 * @param ElementSize
1416 * Size of each element.
1418 * @return TRUE if validation suceeded, FALSE otherwise.
1425 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage
,
1427 IN ULONG ElementCount
,
1428 IN ULONG ElementSize
)
1430 PCSR_CAPTURE_BUFFER CaptureBuffer
= ApiMessage
->CsrCaptureData
;
1431 // SIZE_T BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage;
1435 * Check whether we have a valid buffer pointer, elements
1436 * of non-trivial size and that we don't overflow.
1438 if (!Buffer
|| ElementSize
== 0 ||
1439 (ULONGLONG
)ElementCount
* ElementSize
> (ULONGLONG
)0xFFFFFFFF)
1444 /* Check if didn't get a buffer and there aren't any arguments to check */
1445 // if (!*Buffer && (ElementCount * ElementSize == 0))
1446 if (!*Buffer
&& ElementCount
== 0) // Here ElementSize != 0 therefore only ElementCount can be == 0
1449 /* Check if we have no capture buffer */
1453 * In this case, check only the Process ID
1454 * and if there is a match, we succeed.
1456 if (NtCurrentTeb()->ClientId
.UniqueProcess
==
1457 ApiMessage
->Header
.ClientId
.UniqueProcess
)
1464 /* Make sure that there is still space left in the buffer */
1465 if ((CaptureBuffer
->Size
- (ULONG_PTR
)*Buffer
+ (ULONG_PTR
)CaptureBuffer
) >=
1466 (ElementCount
* ElementSize
))
1468 for (i
= 0 ; i
< CaptureBuffer
->PointerCount
; ++i
)
1471 * If the pointer offset is in fact equal to the
1472 * real address of the buffer then it's OK.
1474 if (CaptureBuffer
->PointerOffsetsArray
[i
] == (ULONG_PTR
)Buffer
/* BufferDistance + (ULONG_PTR)ApiMessage */)
1483 DPRINT1("CSRSRV: Bad message buffer %p\n", ApiMessage
);
1488 /*** This is what we have in consrv/server.c ***
1490 /\* Ensure that a captured buffer is safe to access *\/
1492 Win32CsrValidateBuffer(PCSR_PROCESS ProcessData, PVOID Buffer,
1493 SIZE_T NumElements, SIZE_T ElementSize)
1495 /\* Check that the following conditions are true:
1496 * 1. The start of the buffer is somewhere within the process's
1497 * shared memory section view.
1498 * 2. The remaining space in the view is at least as large as the buffer.
1499 * (NB: Please don't try to "optimize" this by using multiplication
1500 * instead of division; remember that 2147483648 * 2 = 0.)
1501 * 3. The buffer is DWORD-aligned.
1503 ULONG_PTR Offset = (BYTE *)Buffer - (BYTE *)ProcessData->ClientViewBase;
1504 if (Offset >= ProcessData->ClientViewBounds
1505 || NumElements > (ProcessData->ClientViewBounds - Offset) / ElementSize
1506 || (Offset & (sizeof(DWORD) - 1)) != 0)
1508 DPRINT1("Invalid buffer %p(%u*%u); section view is %p(%u)\n",
1509 Buffer, NumElements, ElementSize,
1510 ProcessData->ClientViewBase, ProcessData->ClientViewBounds);
1516 ***********************************************/
1519 * @name CsrValidateMessageString
1520 * @implemented NT5.1
1522 * The CsrValidateMessageString validates a captured Wide-Character String
1523 * present in a CSR API Message.
1526 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1528 * @param MessageString
1529 * Pointer to the buffer containing the string to validate.
1531 * @return TRUE if validation suceeded, FALSE otherwise.
1538 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage
,
1539 IN LPWSTR
*MessageString
)
1543 return CsrValidateMessageBuffer(ApiMessage
,
1544 (PVOID
*)MessageString
,
1545 wcslen(*MessageString
) + 1,