2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Client/Server Runtime SubSystem
4 * FILE: subsystems/win32/csrsrv/api.c
5 * PURPOSE: CSR Server DLL API LPC Implementation
6 * "\windows\ApiPort" port process management functions
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 BOOLEAN (*CsrClientThreadSetup
)(VOID
) = NULL
;
20 UNICODE_STRING CsrApiPortName
;
21 volatile LONG CsrpStaticThreadCount
;
22 volatile LONG CsrpDynamicThreadTotal
;
23 extern ULONG CsrMaxApiRequestThreads
;
25 /* FUNCTIONS ******************************************************************/
28 * @name CsrCallServerFromServer
31 * The CsrCallServerFromServer routine calls a CSR API from within a server.
32 * It avoids using LPC messages since the request isn't coming from a client.
35 * Pointer to the CSR API Message to send to the server.
38 * Pointer to the CSR API Message to receive from the server.
40 * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
41 * if the ApiNumber is invalid, or STATUS_ACCESS_VIOLATION if there
42 * was a problem executing the API.
49 CsrCallServerFromServer(IN PCSR_API_MESSAGE ReceiveMsg
,
50 IN OUT PCSR_API_MESSAGE ReplyMsg
)
53 PCSR_SERVER_DLL ServerDll
;
58 /* Get the Server ID */
59 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
->ApiNumber
);
61 /* Make sure that the ID is within limits, and the Server DLL loaded */
62 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
63 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
65 /* We are beyond the Maximum Server ID */
66 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId
, ServerDll
);
67 ReplyMsg
->Status
= (ULONG
)STATUS_ILLEGAL_FUNCTION
;
68 return STATUS_ILLEGAL_FUNCTION
;
72 /* Get the API ID, normalized with our Base ID */
73 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
->ApiNumber
) - ServerDll
->ApiBase
;
75 /* Make sure that the ID is within limits, and the entry exists */
76 if ((ApiId
>= ServerDll
->HighestApiSupported
) ||
77 ((ServerDll
->ValidTable
) && !(ServerDll
->ValidTable
[ApiId
])))
79 /* We are beyond the Maximum API ID, or it doesn't exist */
80 DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
81 "invalid API to call from the server.\n",
82 ServerDll
->ValidTable
[ApiId
],
83 ((ServerDll
->NameTable
) && (ServerDll
->NameTable
[ApiId
])) ?
84 ServerDll
->NameTable
[ApiId
] : "*** UNKNOWN ***", &ServerDll
->Name
);
86 ReplyMsg
->Status
= (ULONG
)STATUS_ILLEGAL_FUNCTION
;
87 return STATUS_ILLEGAL_FUNCTION
;
93 DPRINT1("CSRSS: %s Api Request received from server process\n",
94 ServerDll
->NameTable
[ApiId
]);
97 /* Validation complete, start SEH */
100 /* Call the API and get the result */
101 /// CsrApiCallHandler(ReplyMsg, /*ProcessData*/ &ReplyCode); ///
102 Status
= (ServerDll
->DispatchTable
[ApiId
])(ReceiveMsg
, &Reply
);
104 /* Return the result, no matter what it is */
105 ReplyMsg
->Status
= Status
;
107 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
109 /* If we got an exception, return access violation */
110 ReplyMsg
->Status
= STATUS_ACCESS_VIOLATION
;
115 return STATUS_SUCCESS
;
119 * @name CsrApiHandleConnectionRequest
121 * The CsrApiHandleConnectionRequest routine handles and accepts a new
122 * connection request to the CSR API LPC Port.
125 * Pointer to the incoming CSR API Message which contains the
126 * connection request.
128 * @return STATUS_SUCCESS in case of success, or status code which caused
129 * the routine to error.
131 * @remarks This routine is responsible for attaching the Shared Section to
132 * new clients connecting to CSR.
137 CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage
)
139 PCSR_THREAD CsrThread
= NULL
;
140 PCSR_PROCESS CsrProcess
= NULL
;
141 NTSTATUS Status
= STATUS_SUCCESS
;
142 PCSR_CONNECTION_INFO ConnectInfo
= &ApiMessage
->ConnectionInfo
;
143 BOOLEAN AllowConnection
= FALSE
;
144 REMOTE_PORT_VIEW RemotePortView
;
147 /* Acquire the Process Lock */
148 CsrAcquireProcessLock();
150 /* Lookup the CSR Thread */
151 CsrThread
= CsrLocateThreadByClientId(NULL
, &ApiMessage
->Header
.ClientId
);
153 /* Check if we have a thread */
156 /* Get the Process */
157 CsrProcess
= CsrThread
->Process
;
159 /* Make sure we have a Process as well */
162 /* Reference the Process */
163 CsrLockedReferenceProcess(CsrThread
->Process
);
165 /* Release the lock */
166 CsrReleaseProcessLock();
168 /* Duplicate the Object Directory */
169 Status
= NtDuplicateObject(NtCurrentProcess(),
171 CsrProcess
->ProcessHandle
,
172 &ConnectInfo
->ObjectDirectory
,
175 DUPLICATE_SAME_ACCESS
|
176 DUPLICATE_SAME_ATTRIBUTES
);
178 /* Acquire the lock */
179 CsrAcquireProcessLock();
181 /* Check for success */
182 if (NT_SUCCESS(Status
))
184 /* Attach the Shared Section */
185 Status
= CsrSrvAttachSharedSection(CsrProcess
, ConnectInfo
);
187 /* Check how this went */
188 if (NT_SUCCESS(Status
)) AllowConnection
= TRUE
;
191 /* Dereference the project */
192 CsrLockedDereferenceProcess(CsrProcess
);
196 /* Release the lock */
197 CsrReleaseProcessLock();
199 /* Setup the Port View Structure */
200 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
201 RemotePortView
.ViewSize
= 0;
202 RemotePortView
.ViewBase
= NULL
;
204 /* Save the Process ID */
205 ConnectInfo
->ProcessId
= NtCurrentTeb()->ClientId
.UniqueProcess
;
207 /* Accept the Connection */
208 Status
= NtAcceptConnectPort(&hPort
,
209 AllowConnection
? UlongToPtr(CsrProcess
->SequenceNumber
) : 0,
214 if (!NT_SUCCESS(Status
))
216 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status
);
218 else if (AllowConnection
)
222 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
223 ApiMessage
->Header
.ClientId
.UniqueProcess
,
224 ApiMessage
->Header
.ClientId
.UniqueThread
,
225 RemotePortView
.ViewBase
,
226 RemotePortView
.ViewSize
);
229 /* Set some Port Data in the Process */
230 CsrProcess
->ClientPort
= hPort
;
231 CsrProcess
->ClientViewBase
= (ULONG_PTR
)RemotePortView
.ViewBase
;
232 CsrProcess
->ClientViewBounds
= (ULONG_PTR
)((ULONG_PTR
)RemotePortView
.ViewBase
+
233 (ULONG_PTR
)RemotePortView
.ViewSize
);
235 /* Complete the connection */
236 Status
= NtCompleteConnectPort(hPort
);
237 if (!NT_SUCCESS(Status
))
239 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status
);
244 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
245 ApiMessage
->Header
.ClientId
.UniqueProcess
,
246 ApiMessage
->Header
.ClientId
.UniqueThread
);
249 /* Return status to caller */
253 // TODO: See CsrApiHandleConnectionRequest
255 CsrpHandleConnectionRequest(PPORT_MESSAGE Request
)
258 HANDLE ServerPort
= NULL
;//, ServerThread = NULL;
259 PCSR_PROCESS ProcessData
= NULL
;
260 REMOTE_PORT_VIEW RemotePortView
;
261 // CLIENT_ID ClientId;
262 BOOLEAN AllowConnection
= FALSE
;
263 PCSR_CONNECTION_INFO ConnectInfo
;
266 DPRINT1("CSR: %s: Handling: %p\n", __FUNCTION__
, Request
);
268 ConnectInfo
= (PCSR_CONNECTION_INFO
)(Request
+ 1);
270 /* Save the process ID */
271 RtlZeroMemory(ConnectInfo
, sizeof(CSR_CONNECTION_INFO
));
273 CsrLockProcessByClientId(Request
->ClientId
.UniqueProcess
, &ProcessData
);
276 DPRINT1("CSRSRV: Unknown process: %lx. Will be rejecting connection\n",
277 Request
->ClientId
.UniqueProcess
);
280 if ((ProcessData
) && (ProcessData
!= CsrRootProcess
))
282 /* Attach the Shared Section */
283 Status
= CsrSrvAttachSharedSection(ProcessData
, ConnectInfo
);
284 if (NT_SUCCESS(Status
))
286 DPRINT1("Connection ok\n");
287 AllowConnection
= TRUE
;
291 DPRINT1("Shared section map failed: %lx\n", Status
);
294 else if (ProcessData
== CsrRootProcess
)
296 AllowConnection
= TRUE
;
299 /* Release the process */
300 if (ProcessData
) CsrUnlockProcess(ProcessData
);
302 /* Setup the Port View Structure */
303 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
304 RemotePortView
.ViewSize
= 0;
305 RemotePortView
.ViewBase
= NULL
;
307 /* Save the Process ID */
308 ConnectInfo
->ProcessId
= NtCurrentTeb()->ClientId
.UniqueProcess
;
310 Status
= NtAcceptConnectPort(&ServerPort
,
311 AllowConnection
? UlongToPtr(ProcessData
->SequenceNumber
) : 0,
316 if (!NT_SUCCESS(Status
))
318 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status
);
320 else if (AllowConnection
)
324 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
325 Request
->ClientId
.UniqueProcess
,
326 Request
->ClientId
.UniqueThread
,
327 RemotePortView
.ViewBase
,
328 RemotePortView
.ViewSize
);
331 /* Set some Port Data in the Process */
332 ProcessData
->ClientPort
= ServerPort
;
333 ProcessData
->ClientViewBase
= (ULONG_PTR
)RemotePortView
.ViewBase
;
334 ProcessData
->ClientViewBounds
= (ULONG_PTR
)((ULONG_PTR
)RemotePortView
.ViewBase
+
335 (ULONG_PTR
)RemotePortView
.ViewSize
);
337 /* Complete the connection */
338 Status
= NtCompleteConnectPort(ServerPort
);
339 if (!NT_SUCCESS(Status
))
341 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status
);
346 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
347 Request
->ClientId
.UniqueProcess
,
348 Request
->ClientId
.UniqueThread
);
355 * @name CsrpCheckRequestThreads
357 * The CsrpCheckRequestThreads routine checks if there are no more threads
358 * to handle CSR API Requests, and creates a new thread if possible, to
363 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
364 * if a new thread couldn't be created.
371 CsrpCheckRequestThreads(VOID
)
377 /* Decrease the count, and see if we're out */
378 if (!(_InterlockedDecrement(&CsrpStaticThreadCount
)))
380 /* Check if we've still got space for a Dynamic Thread */
381 if (CsrpDynamicThreadTotal
< CsrMaxApiRequestThreads
)
383 /* Create a new dynamic thread */
384 Status
= RtlCreateUserThread(NtCurrentProcess(),
390 (PVOID
)CsrApiRequestThread
,
395 if (NT_SUCCESS(Status
))
397 /* Increase the thread counts */
398 _InterlockedIncrement(&CsrpStaticThreadCount
);
399 _InterlockedIncrement(&CsrpDynamicThreadTotal
);
401 /* Add a new server thread */
402 if (CsrAddStaticServerThread(hThread
,
404 CsrThreadIsServerThread
))
407 NtResumeThread(hThread
, NULL
);
411 /* Failed to create a new static thread */
412 _InterlockedDecrement(&CsrpStaticThreadCount
);
413 _InterlockedDecrement(&CsrpDynamicThreadTotal
);
416 DPRINT1("Failing\n");
417 NtTerminateThread(hThread
, 0);
421 return STATUS_UNSUCCESSFUL
;
428 return STATUS_SUCCESS
;
432 * @name CsrApiRequestThread
434 * The CsrApiRequestThread routine handles incoming messages or connection
435 * requests on the CSR API LPC Port.
438 * System-default user-defined parameter. Unused.
440 * @return The thread exit code, if the thread is terminated.
442 * @remarks Before listening on the port, the routine will first attempt
443 * to connect to the user subsystem.
448 CsrApiRequestThread(IN PVOID Parameter
)
450 PTEB Teb
= NtCurrentTeb();
451 LARGE_INTEGER TimeOut
;
452 PCSR_THREAD CurrentThread
, CsrThread
;
454 PCSR_API_MESSAGE ReplyMsg
;
455 CSR_API_MESSAGE ReceiveMsg
;
456 PCSR_PROCESS CsrProcess
;
457 PHARDERROR_MSG HardErrorMsg
;
459 PCSR_SERVER_DLL ServerDll
;
460 PCLIENT_DIED_MSG ClientDiedMsg
;
461 PDBGKM_MSG DebugMessage
;
462 ULONG ServerId
, ApiId
, Reply
, MessageType
, i
;
465 /* Setup LPC loop port and message */
467 ReplyPort
= CsrApiPort
;
469 /* Connect to user32 */
470 while (!CsrConnectToUser())
472 /* Set up the timeout for the connect (30 seconds) */
473 TimeOut
.QuadPart
= -30 * 1000 * 1000 * 10;
475 /* Keep trying until we get a response */
476 Teb
->Win32ClientInfo
[0] = 0;
477 NtDelayExecution(FALSE
, &TimeOut
);
481 CurrentThread
= Teb
->CsrClientThread
;
483 /* If we got an event... */
486 /* Set it, to let stuff waiting on us load */
487 Status
= NtSetEvent((HANDLE
)Parameter
, NULL
);
488 ASSERT(NT_SUCCESS(Status
));
490 /* Increase the Thread Counts */
491 _InterlockedIncrement(&CsrpStaticThreadCount
);
492 _InterlockedIncrement(&CsrpDynamicThreadTotal
);
495 /* Now start the loop */
498 /* Make sure the real CID is set */
499 Teb
->RealClientId
= Teb
->ClientId
;
502 if (Teb
->CountOfOwnedCriticalSections
)
504 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
505 Teb
->CountOfOwnedCriticalSections
);
506 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
507 &ReceiveMsg
, ReplyMsg
);
511 /* Wait for a message to come through */
512 Status
= NtReplyWaitReceivePort(ReplyPort
,
517 /* Check if we didn't get success */
518 if (Status
!= STATUS_SUCCESS
)
520 /* Was it a failure or another success code? */
521 if (!NT_SUCCESS(Status
))
523 /* Check for specific status cases */
524 if ((Status
!= STATUS_INVALID_CID
) &&
525 (Status
!= STATUS_UNSUCCESSFUL
) &&
526 ((Status
== STATUS_INVALID_HANDLE
) || (ReplyPort
== CsrApiPort
)))
528 /* Notify the debugger */
529 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
530 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort
, CsrApiPort
);
533 /* We failed big time, so start out fresh */
535 ReplyPort
= CsrApiPort
;
540 /* A bizare "success" code, just try again */
541 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status
);
546 /* Use whatever Client ID we got */
547 Teb
->RealClientId
= ReceiveMsg
.Header
.ClientId
;
549 /* Get the Message Type */
550 MessageType
= ReceiveMsg
.Header
.u2
.s2
.Type
;
552 /* Handle connection requests */
553 if (MessageType
== LPC_CONNECTION_REQUEST
)
555 /* Handle the Connection Request */
556 CsrApiHandleConnectionRequest(&ReceiveMsg
);
557 ReplyPort
= CsrApiPort
;
562 /* It's some other kind of request. Get the lock for the lookup */
563 CsrAcquireProcessLock();
565 /* Now do the lookup to get the CSR_THREAD */
566 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
,
567 &ReceiveMsg
.Header
.ClientId
);
569 /* Did we find a thread? */
572 /* This wasn't a CSR Thread, release lock */
573 CsrReleaseProcessLock();
575 /* If this was an exception, handle it */
576 if (MessageType
== LPC_EXCEPTION
)
578 ReplyMsg
= &ReceiveMsg
;
579 ReplyPort
= CsrApiPort
;
580 ReplyMsg
->Status
= DBG_CONTINUE
;
582 else if (MessageType
== LPC_PORT_CLOSED
||
583 MessageType
== LPC_CLIENT_DIED
)
585 /* The Client or Port are gone, loop again */
587 ReplyPort
= CsrApiPort
;
589 else if (MessageType
== LPC_ERROR_EVENT
)
591 /* If it's a hard error, handle this too */
592 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
594 /* Default it to unhandled */
595 HardErrorMsg
->Response
= ResponseNotHandled
;
597 /* Check if there are free api threads */
598 CsrpCheckRequestThreads();
599 if (CsrpStaticThreadCount
)
601 /* Loop every Server DLL */
602 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
604 /* Get the Server DLL */
605 ServerDll
= CsrLoadedServerDll
[i
];
607 /* Check if it's valid and if it has a Hard Error Callback */
608 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
611 ServerDll
->HardErrorCallback(NULL
/* CsrThread == NULL */, HardErrorMsg
);
613 /* If it's handled, get out of here */
614 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
619 /* Increase the thread count */
620 _InterlockedIncrement(&CsrpStaticThreadCount
);
622 /* If the response was 0xFFFFFFFF, we'll ignore it */
623 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
626 ReplyPort
= CsrApiPort
;
630 ReplyMsg
= &ReceiveMsg
;
633 else if (MessageType
== LPC_REQUEST
)
635 /* This is an API Message coming from a non-CSR Thread */
636 ReplyMsg
= &ReceiveMsg
;
637 ReplyPort
= CsrApiPort
;
638 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
640 else if (MessageType
== LPC_DATAGRAM
)
642 /* This is an API call, get the Server ID */
643 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
645 /* Make sure that the ID is within limits, and the Server DLL loaded */
647 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
648 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
650 /* We are beyond the Maximum Server ID */
651 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
652 ServerId
, ServerDll
);
654 ReplyPort
= CsrApiPort
;
659 /* Get the API ID, normalized with our Base ID */
660 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
662 /* Make sure that the ID is within limits, and the entry exists */
663 if (ApiId
>= ServerDll
->HighestApiSupported
)
665 /* We are beyond the Maximum API ID, or it doesn't exist */
666 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
667 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
669 ReplyPort
= CsrApiPort
;
676 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
677 Teb
->ClientId
.UniqueThread
,
678 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
679 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
680 ServerDll
->NameTable
[ApiId
],
685 ReceiveMsg
.Status
= STATUS_SUCCESS
;
687 /* Validation complete, start SEH */
690 /* Make sure we have enough threads */
691 CsrpCheckRequestThreads();
693 /* Call the API and get the result */
695 ReplyPort
= CsrApiPort
;
696 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &Reply
);
698 /* Increase the static thread count */
699 _InterlockedIncrement(&CsrpStaticThreadCount
);
701 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
704 ReplyPort
= CsrApiPort
;
710 /* Some other ignored message type */
712 ReplyPort
= CsrApiPort
;
719 /* We have a valid thread, was this an LPC Request? */
720 if (MessageType
!= LPC_REQUEST
)
722 /* It's not an API, check if the client died */
723 if (MessageType
== LPC_CLIENT_DIED
)
725 /* Get the information and check if it matches our thread */
726 ClientDiedMsg
= (PCLIENT_DIED_MSG
)&ReceiveMsg
;
727 if (ClientDiedMsg
->CreateTime
.QuadPart
== CsrThread
->CreateTime
.QuadPart
)
729 /* Reference the thread */
730 CsrLockedReferenceThread(CsrThread
);
732 /* Destroy the thread in the API Message */
733 CsrDestroyThread(&ReceiveMsg
.Header
.ClientId
);
735 /* Check if the thread was actually ourselves */
736 if (CsrProcess
->ThreadCount
== 1)
738 /* Kill the process manually here */
739 CsrDestroyProcess(&CsrThread
->ClientId
, 0);
742 /* Remove our extra reference */
743 CsrLockedDereferenceThread(CsrThread
);
746 /* Release the lock and keep looping */
747 CsrReleaseProcessLock();
749 ReplyPort
= CsrApiPort
;
753 /* Reference the thread and release the lock */
754 CsrLockedReferenceThread(CsrThread
);
755 CsrReleaseProcessLock();
757 /* Check if this was an exception */
758 if (MessageType
== LPC_EXCEPTION
)
760 /* Kill the process */
761 NtTerminateProcess(CsrProcess
->ProcessHandle
, STATUS_ABANDONED
);
763 /* Destroy it from CSR */
764 CsrDestroyProcess(&ReceiveMsg
.Header
.ClientId
, STATUS_ABANDONED
);
766 /* Return a Debug Message */
767 DebugMessage
= (PDBGKM_MSG
)&ReceiveMsg
;
768 DebugMessage
->ReturnedStatus
= DBG_CONTINUE
;
769 ReplyMsg
= &ReceiveMsg
;
770 ReplyPort
= CsrApiPort
;
772 /* Remove our extra reference */
773 CsrDereferenceThread(CsrThread
);
775 else if (MessageType
== LPC_ERROR_EVENT
)
777 /* If it's a hard error, handle this too */
778 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
780 /* Default it to unhandled */
781 HardErrorMsg
->Response
= ResponseNotHandled
;
783 /* Check if there are free api threads */
784 CsrpCheckRequestThreads();
785 if (CsrpStaticThreadCount
)
787 /* Loop every Server DLL */
788 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
790 /* Get the Server DLL */
791 ServerDll
= CsrLoadedServerDll
[i
];
793 /* Check if it's valid and if it has a Hard Error Callback */
794 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
797 ServerDll
->HardErrorCallback(CsrThread
, HardErrorMsg
);
799 /* If it's handled, get out of here */
800 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
805 /* Increase the thread count */
806 _InterlockedIncrement(&CsrpStaticThreadCount
);
808 /* If the response was 0xFFFFFFFF, we'll ignore it */
809 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
812 ReplyPort
= CsrApiPort
;
816 CsrDereferenceThread(CsrThread
);
817 ReplyMsg
= &ReceiveMsg
;
818 ReplyPort
= CsrApiPort
;
824 CsrDereferenceThread(CsrThread
);
832 /* We got an API Request */
833 CsrLockedReferenceThread(CsrThread
);
834 CsrReleaseProcessLock();
836 /* This is an API call, get the Server ID */
837 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
839 /* Make sure that the ID is within limits, and the Server DLL loaded */
841 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
842 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
844 /* We are beyond the Maximum Server ID */
845 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
846 ServerId
, ServerDll
);
849 ReplyPort
= CsrApiPort
;
850 ReplyMsg
= &ReceiveMsg
;
851 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
852 CsrDereferenceThread(CsrThread
);
856 /* Get the API ID, normalized with our Base ID */
857 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
859 /* Make sure that the ID is within limits, and the entry exists */
860 if (ApiId
>= ServerDll
->HighestApiSupported
)
862 /* We are beyond the Maximum API ID, or it doesn't exist */
863 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
864 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
867 ReplyPort
= CsrApiPort
;
868 ReplyMsg
= &ReceiveMsg
;
869 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
870 CsrDereferenceThread(CsrThread
);
876 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
877 Teb
->ClientId
.UniqueThread
,
878 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
879 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
880 ServerDll
->NameTable
[ApiId
],
885 ReplyMsg
= &ReceiveMsg
;
886 ReceiveMsg
.Status
= STATUS_SUCCESS
;
888 /* Now we reply to a particular client */
889 ReplyPort
= CsrThread
->Process
->ClientPort
;
891 /* Check if there's a capture buffer */
892 if (ReceiveMsg
.CsrCaptureData
)
894 /* Capture the arguments */
895 if (!CsrCaptureArguments(CsrThread
, &ReceiveMsg
))
897 /* Ignore this message if we failed to get the arguments */
898 CsrDereferenceThread(CsrThread
);
903 /* Validation complete, start SEH */
906 /* Make sure we have enough threads */
907 CsrpCheckRequestThreads();
909 Teb
->CsrClientThread
= CsrThread
;
911 /* Call the API and get the result */
913 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &Reply
);
915 /* Increase the static thread count */
916 _InterlockedIncrement(&CsrpStaticThreadCount
);
918 Teb
->CsrClientThread
= CurrentThread
;
923 if (ReceiveMsg
.CsrCaptureData
)
925 CsrReleaseCapturedArguments(&ReceiveMsg
);
927 CsrDereferenceThread(CsrThread
);
928 ReplyPort
= CsrApiPort
;
932 NtReplyPort(ReplyPort
, &ReplyMsg
->Header
);
933 ReplyPort
= CsrApiPort
;
935 CsrDereferenceThread(CsrThread
);
939 ReplyPort
= CsrApiPort
;
944 if (ReceiveMsg
.CsrCaptureData
)
946 CsrReleaseCapturedArguments(&ReceiveMsg
);
948 CsrDereferenceThread(CsrThread
);
951 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
954 ReplyPort
= CsrApiPort
;
959 /* We're out of the loop for some reason, terminate! */
960 NtTerminateThread(NtCurrentThread(), Status
);
965 * @name CsrApiPortInitialize
967 * The CsrApiPortInitialize routine initializes the LPC Port used for
968 * communications with the Client/Server Runtime (CSR) and initializes the
969 * static thread that will handle connection requests and APIs.
973 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
981 CsrApiPortInitialize(VOID
)
984 OBJECT_ATTRIBUTES ObjectAttributes
;
986 HANDLE hRequestEvent
, hThread
;
988 PLIST_ENTRY ListHead
, NextEntry
;
989 PCSR_THREAD ServerThread
;
991 /* Calculate how much space we'll need for the Port Name */
992 Size
= CsrDirectoryName
.Length
+ sizeof(CSR_PORT_NAME
) + sizeof(WCHAR
);
994 /* Create the buffer for it */
995 CsrApiPortName
.Buffer
= RtlAllocateHeap(CsrHeap
, 0, Size
);
996 if (!CsrApiPortName
.Buffer
) return STATUS_NO_MEMORY
;
998 /* Setup the rest of the empty string */
999 CsrApiPortName
.Length
= 0;
1000 CsrApiPortName
.MaximumLength
= (USHORT
)Size
;
1001 RtlAppendUnicodeStringToString(&CsrApiPortName
, &CsrDirectoryName
);
1002 RtlAppendUnicodeToString(&CsrApiPortName
, UNICODE_PATH_SEP
);
1003 RtlAppendUnicodeToString(&CsrApiPortName
, CSR_PORT_NAME
);
1006 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName
);
1007 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
1008 sizeof(CSR_CONNECTION_INFO
), sizeof(CSR_API_MESSAGE
));
1011 /* FIXME: Create a Security Descriptor */
1013 /* Initialize the Attributes */
1014 InitializeObjectAttributes(&ObjectAttributes
,
1020 /* Create the Port Object */
1021 Status
= NtCreatePort(&CsrApiPort
,
1023 LPC_MAX_DATA_LENGTH
, // HACK: the real value is: sizeof(CSR_CONNECTION_INFO),
1024 LPC_MAX_MESSAGE_LENGTH
, // HACK: the real value is: sizeof(CSR_API_MESSAGE),
1026 if (NT_SUCCESS(Status
))
1028 /* Create the event the Port Thread will use */
1029 Status
= NtCreateEvent(&hRequestEvent
,
1032 SynchronizationEvent
,
1034 if (NT_SUCCESS(Status
))
1036 /* Create the Request Thread */
1037 Status
= RtlCreateUserThread(NtCurrentProcess(),
1043 (PVOID
)CsrApiRequestThread
,
1044 (PVOID
)hRequestEvent
,
1047 if (NT_SUCCESS(Status
))
1049 /* Add this as a static thread to CSRSRV */
1050 CsrAddStaticServerThread(hThread
, &ClientId
, CsrThreadIsServerThread
);
1052 /* Get the Thread List Pointers */
1053 ListHead
= &CsrRootProcess
->ThreadList
;
1054 NextEntry
= ListHead
->Flink
;
1056 /* Start looping the list */
1057 while (NextEntry
!= ListHead
)
1059 /* Get the Thread */
1060 ServerThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
1063 Status
= NtResumeThread(ServerThread
->ThreadHandle
, NULL
);
1065 /* Is this a Server Thread? */
1066 if (ServerThread
->Flags
& CsrThreadIsServerThread
)
1068 /* If so, then wait for it to initialize */
1069 Status
= NtWaitForSingleObject(hRequestEvent
, FALSE
, NULL
);
1070 ASSERT(NT_SUCCESS(Status
));
1074 NextEntry
= NextEntry
->Flink
;
1077 /* We don't need this anymore */
1078 NtClose(hRequestEvent
);
1088 * @name CsrConnectToUser
1091 * The CsrConnectToUser connects to the User subsystem.
1095 * @return A pointer to the CSR Thread
1102 CsrConnectToUser(VOID
)
1104 #if 0 // This code is OK, however it is ClientThreadSetup which sucks.
1106 ANSI_STRING DllName
;
1107 UNICODE_STRING TempName
;
1110 PTEB Teb
= NtCurrentTeb();
1111 PCSR_THREAD CsrThread
;
1114 /* Check if we didn't already find it */
1115 if (!CsrClientThreadSetup
)
1117 /* Get the DLL Handle for user32.dll */
1118 RtlInitAnsiString(&DllName
, "user32");
1119 RtlAnsiStringToUnicodeString(&TempName
, &DllName
, TRUE
);
1120 Status
= LdrGetDllHandle(NULL
,
1124 RtlFreeUnicodeString(&TempName
);
1126 /* If we got the handle, get the Client Thread Startup Entrypoint */
1127 if (NT_SUCCESS(Status
))
1129 RtlInitAnsiString(&StartupName
,"ClientThreadSetup");
1130 Status
= LdrGetProcedureAddress(hUser32
,
1133 (PVOID
)&CsrClientThreadSetup
);
1137 /* Connect to user32 */
1140 Connected
= CsrClientThreadSetup();
1142 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1149 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1153 /* Save pointer to this thread in TEB */
1154 CsrAcquireProcessLock();
1155 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1156 CsrReleaseProcessLock();
1157 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1164 PTEB Teb
= NtCurrentTeb();
1165 PCSR_THREAD CsrThread
;
1167 /* Save pointer to this thread in TEB */
1168 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1169 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1177 * @name CsrQueryApiPort
1180 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1184 * @return A handle to the port.
1191 CsrQueryApiPort(VOID
)
1193 DPRINT("CSRSRV: %s called\n", __FUNCTION__
);
1198 * @name CsrCaptureArguments
1199 * @implemented NT5.1
1201 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1202 * re-captures it into a server CSR Capture Buffer.
1205 * Pointer to the CSR Thread performing the validation.
1208 * Pointer to the CSR API Message containing the Capture Buffer
1209 * that needs to be validated.
1211 * @return TRUE if validation succeeded, FALSE otherwise.
1218 CsrCaptureArguments(IN PCSR_THREAD CsrThread
,
1219 IN PCSR_API_MESSAGE ApiMessage
)
1221 PCSR_CAPTURE_BUFFER LocalCaptureBuffer
= NULL
, RemoteCaptureBuffer
= NULL
;
1222 SIZE_T BufferDistance
;
1226 /* Use SEH to make sure this is valid */
1229 /* Get the buffer we got from whoever called NTDLL */
1230 LocalCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1231 Length
= LocalCaptureBuffer
->Size
;
1233 /* Now check if the buffer is inside our mapped section */
1234 if (((ULONG_PTR
)LocalCaptureBuffer
< CsrThread
->Process
->ClientViewBase
) ||
1235 (((ULONG_PTR
)LocalCaptureBuffer
+ Length
) >= CsrThread
->Process
->ClientViewBounds
))
1237 /* Return failure */
1238 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1239 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1240 _SEH2_YIELD(return FALSE
);
1243 /* Check if the Length is valid */
1244 if ((FIELD_OFFSET(CSR_CAPTURE_BUFFER
, PointerOffsetsArray
) +
1245 (LocalCaptureBuffer
->PointerCount
* sizeof(PVOID
)) > Length
) ||
1248 /* Return failure */
1249 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer
);
1251 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1252 _SEH2_YIELD(return FALSE
);
1255 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1257 /* Return failure */
1258 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1259 _SEH2_YIELD(return FALSE
);
1262 /* We validated the incoming buffer, now allocate the remote one */
1263 RemoteCaptureBuffer
= RtlAllocateHeap(CsrHeap
, 0, Length
);
1264 if (!RemoteCaptureBuffer
)
1266 /* We're out of memory */
1267 ApiMessage
->Status
= STATUS_NO_MEMORY
;
1271 /* Copy the client's buffer */
1272 RtlMoveMemory(RemoteCaptureBuffer
, LocalCaptureBuffer
, Length
);
1274 /* Calculate the difference between our buffer and the client's */
1275 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1278 * Convert all the pointer offsets into real pointers, and make
1279 * them point to the remote data buffer instead of the local one.
1281 for (i
= 0 ; i
< RemoteCaptureBuffer
->PointerCount
; ++i
)
1283 if (RemoteCaptureBuffer
->PointerOffsetsArray
[i
] != 0)
1285 RemoteCaptureBuffer
->PointerOffsetsArray
[i
] += (ULONG_PTR
)ApiMessage
;
1287 /* Validate the bounds of the current pointer */
1288 if ((*(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] >= CsrThread
->Process
->ClientViewBase
) &&
1289 (*(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] < CsrThread
->Process
->ClientViewBounds
))
1291 /* Modify the pointer to take into account its new position */
1292 *(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] += BufferDistance
;
1296 /* Invalid pointer, fail */
1297 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1299 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1304 /* Check if we got success */
1305 if (ApiMessage
->Status
!= STATUS_SUCCESS
)
1307 /* Failure. Free the buffer and return*/
1308 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1313 /* Success, save the previous buffer */
1314 RemoteCaptureBuffer
->PreviousCaptureBuffer
= LocalCaptureBuffer
;
1315 ApiMessage
->CsrCaptureData
= RemoteCaptureBuffer
;
1323 * @name CsrReleaseCapturedArguments
1324 * @implemented NT5.1
1326 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1327 * that was previously captured with CsrCaptureArguments.
1330 * Pointer to the CSR API Message containing the Capture Buffer
1331 * that needs to be released.
1340 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage
)
1342 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer
, LocalCaptureBuffer
;
1343 SIZE_T BufferDistance
;
1346 /* Get the capture buffers */
1347 RemoteCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1348 LocalCaptureBuffer
= RemoteCaptureBuffer
->PreviousCaptureBuffer
;
1350 /* Do not continue if there is no captured buffer */
1351 if (!RemoteCaptureBuffer
) return;
1353 /* Free the previous one */
1354 RemoteCaptureBuffer
->PreviousCaptureBuffer
= NULL
;
1356 /* Calculate the difference between our buffer and the client's */
1357 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1360 * Convert back all the pointers into pointer offsets, and make them
1361 * point to the local data buffer instead of the remote one (revert
1362 * the logic of CsrCaptureArguments).
1364 for (i
= 0 ; i
< RemoteCaptureBuffer
->PointerCount
; ++i
)
1366 if (RemoteCaptureBuffer
->PointerOffsetsArray
[i
] != 0)
1368 *(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] -= BufferDistance
;
1369 RemoteCaptureBuffer
->PointerOffsetsArray
[i
] -= (ULONG_PTR
)ApiMessage
;
1373 /* Copy the data back */
1374 RtlMoveMemory(LocalCaptureBuffer
, RemoteCaptureBuffer
, RemoteCaptureBuffer
->Size
);
1376 /* Free our allocated buffer */
1377 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1382 * @name CsrValidateMessageBuffer
1383 * @implemented NT5.1
1385 * The CsrValidateMessageBuffer routine validates a captured message buffer
1386 * present in the CSR Api Message
1389 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1392 * Pointer to the message buffer to validate.
1394 * @param ElementCount
1395 * Number of elements contained in the message buffer.
1397 * @param ElementSize
1398 * Size of each element.
1400 * @return TRUE if validation suceeded, FALSE otherwise.
1407 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage
,
1409 IN ULONG ElementCount
,
1410 IN ULONG ElementSize
)
1412 PCSR_CAPTURE_BUFFER CaptureBuffer
= ApiMessage
->CsrCaptureData
;
1413 // SIZE_T BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage;
1417 * Check whether we have a valid buffer pointer, elements
1418 * of non-trivial size and that we don't overflow.
1420 if (!Buffer
|| ElementSize
== 0 ||
1421 (ULONGLONG
)ElementCount
* ElementSize
> (ULONGLONG
)0xFFFFFFFF)
1426 /* Check if didn't get a buffer and there aren't any arguments to check */
1427 // if (!*Buffer && (ElementCount * ElementSize == 0))
1428 if (!*Buffer
&& ElementCount
== 0) // Here ElementSize != 0 therefore only ElementCount can be == 0
1431 /* Check if we have no capture buffer */
1435 * In this case, check only the Process ID
1436 * and if there is a match, we succeed.
1438 if (NtCurrentTeb()->ClientId
.UniqueProcess
==
1439 ApiMessage
->Header
.ClientId
.UniqueProcess
)
1446 /* Make sure that there is still space left in the buffer */
1447 if ((CaptureBuffer
->Size
- (ULONG_PTR
)*Buffer
+ (ULONG_PTR
)CaptureBuffer
) >=
1448 (ElementCount
* ElementSize
))
1450 for (i
= 0 ; i
< CaptureBuffer
->PointerCount
; ++i
)
1453 * If the pointer offset is in fact equal to the
1454 * real address of the buffer then it's OK.
1456 if (CaptureBuffer
->PointerOffsetsArray
[i
] == (ULONG_PTR
)Buffer
/* BufferDistance + (ULONG_PTR)ApiMessage */)
1465 DPRINT1("CSRSRV: Bad message buffer %p\n", ApiMessage
);
1470 /*** This is what we have in consrv/server.c ***
1472 /\* Ensure that a captured buffer is safe to access *\/
1474 Win32CsrValidateBuffer(PCSR_PROCESS ProcessData, PVOID Buffer,
1475 SIZE_T NumElements, SIZE_T ElementSize)
1477 /\* Check that the following conditions are true:
1478 * 1. The start of the buffer is somewhere within the process's
1479 * shared memory section view.
1480 * 2. The remaining space in the view is at least as large as the buffer.
1481 * (NB: Please don't try to "optimize" this by using multiplication
1482 * instead of division; remember that 2147483648 * 2 = 0.)
1483 * 3. The buffer is DWORD-aligned.
1485 ULONG_PTR Offset = (BYTE *)Buffer - (BYTE *)ProcessData->ClientViewBase;
1486 if (Offset >= ProcessData->ClientViewBounds
1487 || NumElements > (ProcessData->ClientViewBounds - Offset) / ElementSize
1488 || (Offset & (sizeof(DWORD) - 1)) != 0)
1490 DPRINT1("Invalid buffer %p(%u*%u); section view is %p(%u)\n",
1491 Buffer, NumElements, ElementSize,
1492 ProcessData->ClientViewBase, ProcessData->ClientViewBounds);
1498 ***********************************************/
1501 * @name CsrValidateMessageString
1502 * @implemented NT5.1
1504 * The CsrValidateMessageString validates a captured Wide-Character String
1505 * present in a CSR API Message.
1508 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1510 * @param MessageString
1511 * Pointer to the buffer containing the string to validate.
1513 * @return TRUE if validation suceeded, FALSE otherwise.
1520 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage
,
1521 IN LPWSTR
*MessageString
)
1525 return CsrValidateMessageBuffer(ApiMessage
,
1526 (PVOID
*)MessageString
,
1527 wcslen(*MessageString
) + 1,