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(&ServerPort
,
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
= ServerPort
;
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(ServerPort
);
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 */
254 * @name CsrpCheckRequestThreads
256 * The CsrpCheckRequestThreads routine checks if there are no more threads
257 * to handle CSR API Requests, and creates a new thread if possible, to
262 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
263 * if a new thread couldn't be created.
270 CsrpCheckRequestThreads(VOID
)
276 /* Decrease the count, and see if we're out */
277 if (!(_InterlockedDecrement(&CsrpStaticThreadCount
)))
279 /* Check if we've still got space for a Dynamic Thread */
280 if (CsrpDynamicThreadTotal
< CsrMaxApiRequestThreads
)
282 /* Create a new dynamic thread */
283 Status
= RtlCreateUserThread(NtCurrentProcess(),
289 (PVOID
)CsrApiRequestThread
,
294 if (NT_SUCCESS(Status
))
296 /* Increase the thread counts */
297 _InterlockedIncrement(&CsrpStaticThreadCount
);
298 _InterlockedIncrement(&CsrpDynamicThreadTotal
);
300 /* Add a new server thread */
301 if (CsrAddStaticServerThread(hThread
,
303 CsrThreadIsServerThread
))
306 NtResumeThread(hThread
, NULL
);
310 /* Failed to create a new static thread */
311 _InterlockedDecrement(&CsrpStaticThreadCount
);
312 _InterlockedDecrement(&CsrpDynamicThreadTotal
);
315 DPRINT1("Failing\n");
316 NtTerminateThread(hThread
, 0);
320 return STATUS_UNSUCCESSFUL
;
327 return STATUS_SUCCESS
;
331 * @name CsrApiRequestThread
333 * The CsrApiRequestThread routine handles incoming messages or connection
334 * requests on the CSR API LPC Port.
337 * System-default user-defined parameter. Unused.
339 * @return The thread exit code, if the thread is terminated.
341 * @remarks Before listening on the port, the routine will first attempt
342 * to connect to the user subsystem.
347 CsrApiRequestThread(IN PVOID Parameter
)
349 PTEB Teb
= NtCurrentTeb();
350 LARGE_INTEGER TimeOut
;
351 PCSR_THREAD CurrentThread
, CsrThread
;
353 PCSR_API_MESSAGE ReplyMsg
;
354 CSR_API_MESSAGE ReceiveMsg
;
355 PCSR_PROCESS CsrProcess
;
356 PHARDERROR_MSG HardErrorMsg
;
358 PCSR_SERVER_DLL ServerDll
;
359 PCLIENT_DIED_MSG ClientDiedMsg
;
360 PDBGKM_MSG DebugMessage
;
361 ULONG ServerId
, ApiId
, Reply
, MessageType
, i
;
364 /* Setup LPC loop port and message */
366 ReplyPort
= CsrApiPort
;
368 /* Connect to user32 */
369 while (!CsrConnectToUser())
371 /* Set up the timeout for the connect (30 seconds) */
372 TimeOut
.QuadPart
= -30 * 1000 * 1000 * 10;
374 /* Keep trying until we get a response */
375 Teb
->Win32ClientInfo
[0] = 0;
376 NtDelayExecution(FALSE
, &TimeOut
);
380 CurrentThread
= Teb
->CsrClientThread
;
382 /* If we got an event... */
385 /* Set it, to let stuff waiting on us load */
386 Status
= NtSetEvent((HANDLE
)Parameter
, NULL
);
387 ASSERT(NT_SUCCESS(Status
));
389 /* Increase the Thread Counts */
390 _InterlockedIncrement(&CsrpStaticThreadCount
);
391 _InterlockedIncrement(&CsrpDynamicThreadTotal
);
394 /* Now start the loop */
397 /* Make sure the real CID is set */
398 Teb
->RealClientId
= Teb
->ClientId
;
401 if (Teb
->CountOfOwnedCriticalSections
)
403 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
404 Teb
->CountOfOwnedCriticalSections
);
405 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
406 &ReceiveMsg
, ReplyMsg
);
410 /* Wait for a message to come through */
411 Status
= NtReplyWaitReceivePort(ReplyPort
,
416 /* Check if we didn't get success */
417 if (Status
!= STATUS_SUCCESS
)
419 /* Was it a failure or another success code? */
420 if (!NT_SUCCESS(Status
))
422 /* Check for specific status cases */
423 if ((Status
!= STATUS_INVALID_CID
) &&
424 (Status
!= STATUS_UNSUCCESSFUL
) &&
425 ((Status
== STATUS_INVALID_HANDLE
) || (ReplyPort
== CsrApiPort
)))
427 /* Notify the debugger */
428 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
429 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort
, CsrApiPort
);
432 /* We failed big time, so start out fresh */
434 ReplyPort
= CsrApiPort
;
439 /* A bizare "success" code, just try again */
440 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status
);
445 /* Use whatever Client ID we got */
446 Teb
->RealClientId
= ReceiveMsg
.Header
.ClientId
;
448 /* Get the Message Type */
449 MessageType
= ReceiveMsg
.Header
.u2
.s2
.Type
;
451 /* Handle connection requests */
452 if (MessageType
== LPC_CONNECTION_REQUEST
)
454 /* Handle the Connection Request */
455 CsrApiHandleConnectionRequest(&ReceiveMsg
);
456 ReplyPort
= CsrApiPort
;
461 /* It's some other kind of request. Get the lock for the lookup */
462 CsrAcquireProcessLock();
464 /* Now do the lookup to get the CSR_THREAD */
465 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
,
466 &ReceiveMsg
.Header
.ClientId
);
468 /* Did we find a thread? */
471 /* This wasn't a CSR Thread, release lock */
472 CsrReleaseProcessLock();
474 /* If this was an exception, handle it */
475 if (MessageType
== LPC_EXCEPTION
)
477 ReplyMsg
= &ReceiveMsg
;
478 ReplyPort
= CsrApiPort
;
479 ReplyMsg
->Status
= DBG_CONTINUE
;
481 else if (MessageType
== LPC_PORT_CLOSED
||
482 MessageType
== LPC_CLIENT_DIED
)
484 /* The Client or Port are gone, loop again */
486 ReplyPort
= CsrApiPort
;
488 else if (MessageType
== LPC_ERROR_EVENT
)
490 /* If it's a hard error, handle this too */
491 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
493 /* Default it to unhandled */
494 HardErrorMsg
->Response
= ResponseNotHandled
;
496 /* Check if there are free api threads */
497 CsrpCheckRequestThreads();
498 if (CsrpStaticThreadCount
)
500 /* Loop every Server DLL */
501 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
503 /* Get the Server DLL */
504 ServerDll
= CsrLoadedServerDll
[i
];
506 /* Check if it's valid and if it has a Hard Error Callback */
507 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
510 ServerDll
->HardErrorCallback(NULL
/* CsrThread == NULL */, HardErrorMsg
);
512 /* If it's handled, get out of here */
513 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
518 /* Increase the thread count */
519 _InterlockedIncrement(&CsrpStaticThreadCount
);
521 /* If the response was 0xFFFFFFFF, we'll ignore it */
522 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
525 ReplyPort
= CsrApiPort
;
529 ReplyMsg
= &ReceiveMsg
;
532 else if (MessageType
== LPC_REQUEST
)
534 /* This is an API Message coming from a non-CSR Thread */
535 ReplyMsg
= &ReceiveMsg
;
536 ReplyPort
= CsrApiPort
;
537 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
539 else if (MessageType
== LPC_DATAGRAM
)
541 /* This is an API call, get the Server ID */
542 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
544 /* Make sure that the ID is within limits, and the Server DLL loaded */
546 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
547 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
549 /* We are beyond the Maximum Server ID */
550 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
551 ServerId
, ServerDll
);
553 ReplyPort
= CsrApiPort
;
558 /* Get the API ID, normalized with our Base ID */
559 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
561 /* Make sure that the ID is within limits, and the entry exists */
562 if (ApiId
>= ServerDll
->HighestApiSupported
)
564 /* We are beyond the Maximum API ID, or it doesn't exist */
565 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
566 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
568 ReplyPort
= CsrApiPort
;
575 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
576 Teb
->ClientId
.UniqueThread
,
577 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
578 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
579 ServerDll
->NameTable
[ApiId
],
584 ReceiveMsg
.Status
= STATUS_SUCCESS
;
586 /* Validation complete, start SEH */
589 /* Make sure we have enough threads */
590 CsrpCheckRequestThreads();
592 /* Call the API and get the result */
594 ReplyPort
= CsrApiPort
;
595 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &Reply
);
597 /* Increase the static thread count */
598 _InterlockedIncrement(&CsrpStaticThreadCount
);
600 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
603 ReplyPort
= CsrApiPort
;
609 /* Some other ignored message type */
611 ReplyPort
= CsrApiPort
;
618 /* We have a valid thread, was this an LPC Request? */
619 if (MessageType
!= LPC_REQUEST
)
621 /* It's not an API, check if the client died */
622 if (MessageType
== LPC_CLIENT_DIED
)
624 /* Get the information and check if it matches our thread */
625 ClientDiedMsg
= (PCLIENT_DIED_MSG
)&ReceiveMsg
;
626 if (ClientDiedMsg
->CreateTime
.QuadPart
== CsrThread
->CreateTime
.QuadPart
)
628 /* Reference the thread */
629 CsrLockedReferenceThread(CsrThread
);
631 /* Destroy the thread in the API Message */
632 CsrDestroyThread(&ReceiveMsg
.Header
.ClientId
);
634 /* Check if the thread was actually ourselves */
635 if (CsrProcess
->ThreadCount
== 1)
637 /* Kill the process manually here */
638 CsrDestroyProcess(&CsrThread
->ClientId
, 0);
641 /* Remove our extra reference */
642 CsrLockedDereferenceThread(CsrThread
);
645 /* Release the lock and keep looping */
646 CsrReleaseProcessLock();
648 ReplyPort
= CsrApiPort
;
652 /* Reference the thread and release the lock */
653 CsrLockedReferenceThread(CsrThread
);
654 CsrReleaseProcessLock();
656 /* Check if this was an exception */
657 if (MessageType
== LPC_EXCEPTION
)
659 /* Kill the process */
660 NtTerminateProcess(CsrProcess
->ProcessHandle
, STATUS_ABANDONED
);
662 /* Destroy it from CSR */
663 CsrDestroyProcess(&ReceiveMsg
.Header
.ClientId
, STATUS_ABANDONED
);
665 /* Return a Debug Message */
666 DebugMessage
= (PDBGKM_MSG
)&ReceiveMsg
;
667 DebugMessage
->ReturnedStatus
= DBG_CONTINUE
;
668 ReplyMsg
= &ReceiveMsg
;
669 ReplyPort
= CsrApiPort
;
671 /* Remove our extra reference */
672 CsrDereferenceThread(CsrThread
);
674 else if (MessageType
== LPC_ERROR_EVENT
)
676 /* If it's a hard error, handle this too */
677 HardErrorMsg
= (PHARDERROR_MSG
)&ReceiveMsg
;
679 /* Default it to unhandled */
680 HardErrorMsg
->Response
= ResponseNotHandled
;
682 /* Check if there are free api threads */
683 CsrpCheckRequestThreads();
684 if (CsrpStaticThreadCount
)
686 /* Loop every Server DLL */
687 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
689 /* Get the Server DLL */
690 ServerDll
= CsrLoadedServerDll
[i
];
692 /* Check if it's valid and if it has a Hard Error Callback */
693 if ((ServerDll
) && (ServerDll
->HardErrorCallback
))
696 ServerDll
->HardErrorCallback(CsrThread
, HardErrorMsg
);
698 /* If it's handled, get out of here */
699 if (HardErrorMsg
->Response
!= ResponseNotHandled
) break;
704 /* Increase the thread count */
705 _InterlockedIncrement(&CsrpStaticThreadCount
);
707 /* If the response was 0xFFFFFFFF, we'll ignore it */
708 if (HardErrorMsg
->Response
== 0xFFFFFFFF)
711 ReplyPort
= CsrApiPort
;
715 CsrDereferenceThread(CsrThread
);
716 ReplyMsg
= &ReceiveMsg
;
717 ReplyPort
= CsrApiPort
;
723 CsrDereferenceThread(CsrThread
);
731 /* We got an API Request */
732 CsrLockedReferenceThread(CsrThread
);
733 CsrReleaseProcessLock();
735 /* This is an API call, get the Server ID */
736 ServerId
= CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg
.ApiNumber
);
738 /* Make sure that the ID is within limits, and the Server DLL loaded */
740 if ((ServerId
>= CSR_SERVER_DLL_MAX
) ||
741 (!(ServerDll
= CsrLoadedServerDll
[ServerId
])))
743 /* We are beyond the Maximum Server ID */
744 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
745 ServerId
, ServerDll
);
748 ReplyPort
= CsrApiPort
;
749 ReplyMsg
= &ReceiveMsg
;
750 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
751 CsrDereferenceThread(CsrThread
);
755 /* Get the API ID, normalized with our Base ID */
756 ApiId
= CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
) - ServerDll
->ApiBase
;
758 /* Make sure that the ID is within limits, and the entry exists */
759 if (ApiId
>= ServerDll
->HighestApiSupported
)
761 /* We are beyond the Maximum API ID, or it doesn't exist */
762 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
763 CSR_API_NUMBER_TO_API_ID(ReceiveMsg
.ApiNumber
),
766 ReplyPort
= CsrApiPort
;
767 ReplyMsg
= &ReceiveMsg
;
768 ReplyMsg
->Status
= STATUS_ILLEGAL_FUNCTION
;
769 CsrDereferenceThread(CsrThread
);
775 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
776 Teb
->ClientId
.UniqueThread
,
777 ReceiveMsg
.Header
.ClientId
.UniqueProcess
,
778 ReceiveMsg
.Header
.ClientId
.UniqueThread
,
779 ServerDll
->NameTable
[ApiId
],
784 ReplyMsg
= &ReceiveMsg
;
785 ReceiveMsg
.Status
= STATUS_SUCCESS
;
787 /* Now we reply to a particular client */
788 ReplyPort
= CsrThread
->Process
->ClientPort
;
790 /* Check if there's a capture buffer */
791 if (ReceiveMsg
.CsrCaptureData
)
793 /* Capture the arguments */
794 if (!CsrCaptureArguments(CsrThread
, &ReceiveMsg
))
796 /* Ignore this message if we failed to get the arguments */
797 CsrDereferenceThread(CsrThread
);
802 /* Validation complete, start SEH */
805 /* Make sure we have enough threads */
806 CsrpCheckRequestThreads();
808 Teb
->CsrClientThread
= CsrThread
;
810 /* Call the API and get the result */
812 ServerDll
->DispatchTable
[ApiId
](&ReceiveMsg
, &Reply
);
814 /* Increase the static thread count */
815 _InterlockedIncrement(&CsrpStaticThreadCount
);
817 Teb
->CsrClientThread
= CurrentThread
;
822 if (ReceiveMsg
.CsrCaptureData
)
824 CsrReleaseCapturedArguments(&ReceiveMsg
);
826 CsrDereferenceThread(CsrThread
);
827 ReplyPort
= CsrApiPort
;
831 NtReplyPort(ReplyPort
, &ReplyMsg
->Header
);
832 ReplyPort
= CsrApiPort
;
834 CsrDereferenceThread(CsrThread
);
838 ReplyPort
= CsrApiPort
;
843 if (ReceiveMsg
.CsrCaptureData
)
845 CsrReleaseCapturedArguments(&ReceiveMsg
);
847 CsrDereferenceThread(CsrThread
);
850 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
853 ReplyPort
= CsrApiPort
;
858 /* We're out of the loop for some reason, terminate! */
859 NtTerminateThread(NtCurrentThread(), Status
);
864 * @name CsrApiPortInitialize
866 * The CsrApiPortInitialize routine initializes the LPC Port used for
867 * communications with the Client/Server Runtime (CSR) and initializes the
868 * static thread that will handle connection requests and APIs.
872 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
880 CsrApiPortInitialize(VOID
)
883 OBJECT_ATTRIBUTES ObjectAttributes
;
885 HANDLE hRequestEvent
, hThread
;
887 PLIST_ENTRY ListHead
, NextEntry
;
888 PCSR_THREAD ServerThread
;
890 /* Calculate how much space we'll need for the Port Name */
891 Size
= CsrDirectoryName
.Length
+ sizeof(CSR_PORT_NAME
) + sizeof(WCHAR
);
893 /* Create the buffer for it */
894 CsrApiPortName
.Buffer
= RtlAllocateHeap(CsrHeap
, 0, Size
);
895 if (!CsrApiPortName
.Buffer
) return STATUS_NO_MEMORY
;
897 /* Setup the rest of the empty string */
898 CsrApiPortName
.Length
= 0;
899 CsrApiPortName
.MaximumLength
= (USHORT
)Size
;
900 RtlAppendUnicodeStringToString(&CsrApiPortName
, &CsrDirectoryName
);
901 RtlAppendUnicodeToString(&CsrApiPortName
, UNICODE_PATH_SEP
);
902 RtlAppendUnicodeToString(&CsrApiPortName
, CSR_PORT_NAME
);
905 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName
);
906 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
907 sizeof(CSR_CONNECTION_INFO
), sizeof(CSR_API_MESSAGE
));
910 /* FIXME: Create a Security Descriptor */
912 /* Initialize the Attributes */
913 InitializeObjectAttributes(&ObjectAttributes
,
919 /* Create the Port Object */
920 Status
= NtCreatePort(&CsrApiPort
,
922 LPC_MAX_DATA_LENGTH
, // HACK: the real value is: sizeof(CSR_CONNECTION_INFO),
923 LPC_MAX_MESSAGE_LENGTH
, // HACK: the real value is: sizeof(CSR_API_MESSAGE),
925 if (NT_SUCCESS(Status
))
927 /* Create the event the Port Thread will use */
928 Status
= NtCreateEvent(&hRequestEvent
,
931 SynchronizationEvent
,
933 if (NT_SUCCESS(Status
))
935 /* Create the Request Thread */
936 Status
= RtlCreateUserThread(NtCurrentProcess(),
942 (PVOID
)CsrApiRequestThread
,
943 (PVOID
)hRequestEvent
,
946 if (NT_SUCCESS(Status
))
948 /* Add this as a static thread to CSRSRV */
949 CsrAddStaticServerThread(hThread
, &ClientId
, CsrThreadIsServerThread
);
951 /* Get the Thread List Pointers */
952 ListHead
= &CsrRootProcess
->ThreadList
;
953 NextEntry
= ListHead
->Flink
;
955 /* Start looping the list */
956 while (NextEntry
!= ListHead
)
959 ServerThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
962 Status
= NtResumeThread(ServerThread
->ThreadHandle
, NULL
);
964 /* Is this a Server Thread? */
965 if (ServerThread
->Flags
& CsrThreadIsServerThread
)
967 /* If so, then wait for it to initialize */
968 Status
= NtWaitForSingleObject(hRequestEvent
, FALSE
, NULL
);
969 ASSERT(NT_SUCCESS(Status
));
973 NextEntry
= NextEntry
->Flink
;
976 /* We don't need this anymore */
977 NtClose(hRequestEvent
);
987 * @name CsrConnectToUser
990 * The CsrConnectToUser connects to the User subsystem.
994 * @return A pointer to the CSR Thread
1001 CsrConnectToUser(VOID
)
1003 #if 0 // This code is OK, however it is ClientThreadSetup which sucks.
1005 ANSI_STRING DllName
;
1006 UNICODE_STRING TempName
;
1009 PTEB Teb
= NtCurrentTeb();
1010 PCSR_THREAD CsrThread
;
1013 /* Check if we didn't already find it */
1014 if (!CsrClientThreadSetup
)
1016 /* Get the DLL Handle for user32.dll */
1017 RtlInitAnsiString(&DllName
, "user32");
1018 RtlAnsiStringToUnicodeString(&TempName
, &DllName
, TRUE
);
1019 Status
= LdrGetDllHandle(NULL
,
1023 RtlFreeUnicodeString(&TempName
);
1025 /* If we got the handle, get the Client Thread Startup Entrypoint */
1026 if (NT_SUCCESS(Status
))
1028 RtlInitAnsiString(&StartupName
,"ClientThreadSetup");
1029 Status
= LdrGetProcedureAddress(hUser32
,
1032 (PVOID
)&CsrClientThreadSetup
);
1036 /* Connect to user32 */
1039 Connected
= CsrClientThreadSetup();
1041 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1048 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1052 /* Save pointer to this thread in TEB */
1053 CsrAcquireProcessLock();
1054 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1055 CsrReleaseProcessLock();
1056 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1063 PTEB Teb
= NtCurrentTeb();
1064 PCSR_THREAD CsrThread
;
1066 /* Save pointer to this thread in TEB */
1067 CsrThread
= CsrLocateThreadInProcess(NULL
, &Teb
->ClientId
);
1068 if (CsrThread
) Teb
->CsrClientThread
= CsrThread
;
1076 * @name CsrQueryApiPort
1079 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1083 * @return A handle to the port.
1090 CsrQueryApiPort(VOID
)
1092 DPRINT("CSRSRV: %s called\n", __FUNCTION__
);
1097 * @name CsrCaptureArguments
1098 * @implemented NT5.1
1100 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1101 * re-captures it into a server CSR Capture Buffer.
1104 * Pointer to the CSR Thread performing the validation.
1107 * Pointer to the CSR API Message containing the Capture Buffer
1108 * that needs to be validated.
1110 * @return TRUE if validation succeeded, FALSE otherwise.
1117 CsrCaptureArguments(IN PCSR_THREAD CsrThread
,
1118 IN PCSR_API_MESSAGE ApiMessage
)
1120 PCSR_CAPTURE_BUFFER LocalCaptureBuffer
= NULL
, RemoteCaptureBuffer
= NULL
;
1121 SIZE_T BufferDistance
;
1125 /* Use SEH to make sure this is valid */
1128 /* Get the buffer we got from whoever called NTDLL */
1129 LocalCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1130 Length
= LocalCaptureBuffer
->Size
;
1132 /* Now check if the buffer is inside our mapped section */
1133 if (((ULONG_PTR
)LocalCaptureBuffer
< CsrThread
->Process
->ClientViewBase
) ||
1134 (((ULONG_PTR
)LocalCaptureBuffer
+ Length
) >= CsrThread
->Process
->ClientViewBounds
))
1136 /* Return failure */
1137 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1138 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1139 _SEH2_YIELD(return FALSE
);
1142 /* Check if the Length is valid */
1143 if ((FIELD_OFFSET(CSR_CAPTURE_BUFFER
, PointerOffsetsArray
) +
1144 (LocalCaptureBuffer
->PointerCount
* sizeof(PVOID
)) > Length
) ||
1147 /* Return failure */
1148 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer
);
1150 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1151 _SEH2_YIELD(return FALSE
);
1154 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1156 /* Return failure */
1157 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1158 _SEH2_YIELD(return FALSE
);
1161 /* We validated the incoming buffer, now allocate the remote one */
1162 RemoteCaptureBuffer
= RtlAllocateHeap(CsrHeap
, 0, Length
);
1163 if (!RemoteCaptureBuffer
)
1165 /* We're out of memory */
1166 ApiMessage
->Status
= STATUS_NO_MEMORY
;
1170 /* Copy the client's buffer */
1171 RtlMoveMemory(RemoteCaptureBuffer
, LocalCaptureBuffer
, Length
);
1173 /* Calculate the difference between our buffer and the client's */
1174 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1177 * Convert all the pointer offsets into real pointers, and make
1178 * them point to the remote data buffer instead of the local one.
1180 for (i
= 0 ; i
< RemoteCaptureBuffer
->PointerCount
; ++i
)
1182 if (RemoteCaptureBuffer
->PointerOffsetsArray
[i
] != 0)
1184 RemoteCaptureBuffer
->PointerOffsetsArray
[i
] += (ULONG_PTR
)ApiMessage
;
1186 /* Validate the bounds of the current pointer */
1187 if ((*(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] >= CsrThread
->Process
->ClientViewBase
) &&
1188 (*(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] < CsrThread
->Process
->ClientViewBounds
))
1190 /* Modify the pointer to take into account its new position */
1191 *(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] += BufferDistance
;
1195 /* Invalid pointer, fail */
1196 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1198 ApiMessage
->Status
= STATUS_INVALID_PARAMETER
;
1203 /* Check if we got success */
1204 if (ApiMessage
->Status
!= STATUS_SUCCESS
)
1206 /* Failure. Free the buffer and return*/
1207 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1212 /* Success, save the previous buffer */
1213 RemoteCaptureBuffer
->PreviousCaptureBuffer
= LocalCaptureBuffer
;
1214 ApiMessage
->CsrCaptureData
= RemoteCaptureBuffer
;
1222 * @name CsrReleaseCapturedArguments
1223 * @implemented NT5.1
1225 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1226 * that was previously captured with CsrCaptureArguments.
1229 * Pointer to the CSR API Message containing the Capture Buffer
1230 * that needs to be released.
1239 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage
)
1241 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer
, LocalCaptureBuffer
;
1242 SIZE_T BufferDistance
;
1245 /* Get the capture buffers */
1246 RemoteCaptureBuffer
= ApiMessage
->CsrCaptureData
;
1247 LocalCaptureBuffer
= RemoteCaptureBuffer
->PreviousCaptureBuffer
;
1249 /* Do not continue if there is no captured buffer */
1250 if (!RemoteCaptureBuffer
) return;
1252 /* Free the previous one */
1253 RemoteCaptureBuffer
->PreviousCaptureBuffer
= NULL
;
1255 /* Calculate the difference between our buffer and the client's */
1256 BufferDistance
= (ULONG_PTR
)RemoteCaptureBuffer
- (ULONG_PTR
)LocalCaptureBuffer
;
1259 * Convert back all the pointers into pointer offsets, and make them
1260 * point to the local data buffer instead of the remote one (revert
1261 * the logic of CsrCaptureArguments).
1263 for (i
= 0 ; i
< RemoteCaptureBuffer
->PointerCount
; ++i
)
1265 if (RemoteCaptureBuffer
->PointerOffsetsArray
[i
] != 0)
1267 *(PULONG_PTR
)RemoteCaptureBuffer
->PointerOffsetsArray
[i
] -= BufferDistance
;
1268 RemoteCaptureBuffer
->PointerOffsetsArray
[i
] -= (ULONG_PTR
)ApiMessage
;
1272 /* Copy the data back */
1273 RtlMoveMemory(LocalCaptureBuffer
, RemoteCaptureBuffer
, RemoteCaptureBuffer
->Size
);
1275 /* Free our allocated buffer */
1276 RtlFreeHeap(CsrHeap
, 0, RemoteCaptureBuffer
);
1281 * @name CsrValidateMessageBuffer
1282 * @implemented NT5.1
1284 * The CsrValidateMessageBuffer routine validates a captured message buffer
1285 * present in the CSR Api Message
1288 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1291 * Pointer to the message buffer to validate.
1293 * @param ElementCount
1294 * Number of elements contained in the message buffer.
1296 * @param ElementSize
1297 * Size of each element.
1299 * @return TRUE if validation suceeded, FALSE otherwise.
1306 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage
,
1308 IN ULONG ElementCount
,
1309 IN ULONG ElementSize
)
1311 PCSR_CAPTURE_BUFFER CaptureBuffer
= ApiMessage
->CsrCaptureData
;
1312 // SIZE_T BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage;
1316 * Check whether we have a valid buffer pointer, elements
1317 * of non-trivial size and that we don't overflow.
1319 if (!Buffer
|| ElementSize
== 0 ||
1320 (ULONGLONG
)ElementCount
* ElementSize
> (ULONGLONG
)0xFFFFFFFF)
1325 /* Check if didn't get a buffer and there aren't any arguments to check */
1326 // if (!*Buffer && (ElementCount * ElementSize == 0))
1327 if (!*Buffer
&& ElementCount
== 0) // Here ElementSize != 0 therefore only ElementCount can be == 0
1330 /* Check if we have no capture buffer */
1334 * In this case, check only the Process ID
1335 * and if there is a match, we succeed.
1337 if (NtCurrentTeb()->ClientId
.UniqueProcess
==
1338 ApiMessage
->Header
.ClientId
.UniqueProcess
)
1345 /* Make sure that there is still space left in the buffer */
1346 if ((CaptureBuffer
->Size
- (ULONG_PTR
)*Buffer
+ (ULONG_PTR
)CaptureBuffer
) >=
1347 (ElementCount
* ElementSize
))
1349 for (i
= 0 ; i
< CaptureBuffer
->PointerCount
; ++i
)
1352 * If the pointer offset is in fact equal to the
1353 * real address of the buffer then it's OK.
1355 if (CaptureBuffer
->PointerOffsetsArray
[i
] == (ULONG_PTR
)Buffer
/* BufferDistance + (ULONG_PTR)ApiMessage */)
1364 DPRINT1("CSRSRV: Bad message buffer %p\n", ApiMessage
);
1369 /*** This is what we have in consrv/server.c ***
1371 /\* Ensure that a captured buffer is safe to access *\/
1373 Win32CsrValidateBuffer(PCSR_PROCESS ProcessData, PVOID Buffer,
1374 SIZE_T NumElements, SIZE_T ElementSize)
1376 /\* Check that the following conditions are true:
1377 * 1. The start of the buffer is somewhere within the process's
1378 * shared memory section view.
1379 * 2. The remaining space in the view is at least as large as the buffer.
1380 * (NB: Please don't try to "optimize" this by using multiplication
1381 * instead of division; remember that 2147483648 * 2 = 0.)
1382 * 3. The buffer is DWORD-aligned.
1384 ULONG_PTR Offset = (BYTE *)Buffer - (BYTE *)ProcessData->ClientViewBase;
1385 if (Offset >= ProcessData->ClientViewBounds
1386 || NumElements > (ProcessData->ClientViewBounds - Offset) / ElementSize
1387 || (Offset & (sizeof(DWORD) - 1)) != 0)
1389 DPRINT1("Invalid buffer %p(%u*%u); section view is %p(%u)\n",
1390 Buffer, NumElements, ElementSize,
1391 ProcessData->ClientViewBase, ProcessData->ClientViewBounds);
1397 ***********************************************/
1400 * @name CsrValidateMessageString
1401 * @implemented NT5.1
1403 * The CsrValidateMessageString validates a captured Wide-Character String
1404 * present in a CSR API Message.
1407 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1409 * @param MessageString
1410 * Pointer to the buffer containing the string to validate.
1412 * @return TRUE if validation suceeded, FALSE otherwise.
1419 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage
,
1420 IN LPWSTR
*MessageString
)
1424 return CsrValidateMessageBuffer(ApiMessage
,
1425 (PVOID
*)MessageString
,
1426 wcslen(*MessageString
) + 1,