2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR Sub System
4 * FILE: subsys/csr/csrsrv/server.c
5 * PURPOSE: CSR Server DLL Server Functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES ******************************************************************/
15 /* DATA **********************************************************************/
17 PCSR_API_ROUTINE CsrServerApiDispatchTable
[5] =
22 CsrSrvIdentifyAlertableThread
,
23 CsrSrvSetPriorityClass
26 BOOLEAN CsrServerApiServerValidTable
[5] =
35 PCHAR CsrServerApiNameTable
[5] =
40 "IdentifyAlertableThread",
44 PCSR_SERVER_DLL CsrLoadedServerDll
[CSR_SERVER_DLL_MAX
];
45 PVOID CsrSrvSharedSectionHeap
;
46 PVOID CsrSrvSharedSectionBase
;
47 PVOID
*CsrSrvSharedStaticServerData
;
48 ULONG CsrSrvSharedSectionSize
;
49 HANDLE CsrSrvSharedSection
;
51 /* PRIVATE FUNCTIONS**********************************************************/
54 * @name CsrLoadServerDll
57 * The CsrLoadServerDll routine loads a CSR Server DLL and calls its entrypoint
60 * Pointer to the CSR Server DLL to load and call.
63 * Pointer to the name of the server's initialization function. If
64 * this parameter is NULL, the default ServerDllInitialize will be
67 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
75 CsrLoadServerDll(IN PCHAR DllString
,
76 IN PCHAR EntryPoint OPTIONAL
,
81 UNICODE_STRING TempString
;
82 HANDLE hServerDll
= NULL
;
84 PCSR_SERVER_DLL ServerDll
;
85 STRING EntryPointString
;
86 PCSR_SERVER_DLL_INIT_CALLBACK ServerDllInitProcedure
;
88 /* Check if it's beyond the maximum we support */
89 if (ServerId
>= CSR_SERVER_DLL_MAX
) return(STATUS_TOO_MANY_NAMES
);
91 /* Check if it's already been loaded */
92 if (CsrLoadedServerDll
[ServerId
]) return(STATUS_INVALID_PARAMETER
);
94 /* Convert the name to Unicode */
95 RtlInitAnsiString(&DllName
, DllString
);
96 Status
= RtlAnsiStringToUnicodeString(&TempString
, &DllName
, TRUE
);
98 /* If we are loading ourselves, don't actually load us */
99 if (ServerId
!= CSR_SRV_SERVER
)
102 Status
= LdrLoadDll(NULL
, 0, &TempString
, &hServerDll
);
104 /* Get rid of the string */
105 RtlFreeUnicodeString(&TempString
);
106 if (!NT_SUCCESS(Status
))
112 /* Allocate a CSR DLL Object */
113 Size
= sizeof(CSR_SERVER_DLL
) + DllName
.MaximumLength
;
114 if (!(ServerDll
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, Size
)))
116 if (hServerDll
) LdrUnloadDll(hServerDll
);
117 return STATUS_NO_MEMORY
;
120 /* Set up the Object */
121 ServerDll
->Length
= Size
;
122 ServerDll
->SharedSection
= CsrSrvSharedSectionHeap
;
123 ServerDll
->Event
= CsrInitializationEvent
;
124 ServerDll
->Name
.Length
= DllName
.Length
;
125 ServerDll
->Name
.MaximumLength
= DllName
.MaximumLength
;
126 ServerDll
->Name
.Buffer
= (PCHAR
)(ServerDll
+ 1);
129 strncpy(ServerDll
->Name
.Buffer
, DllName
.Buffer
, DllName
.Length
);
131 ServerDll
->ServerId
= ServerId
;
132 ServerDll
->ServerHandle
= hServerDll
;
134 /* Now get the entrypoint */
137 /* Initialize a string for the entrypoint, or use the default */
138 RtlInitAnsiString(&EntryPointString
,
139 !(EntryPoint
) ? "ServerDllInitialization" :
142 /* Get a pointer to it */
143 Status
= LdrGetProcedureAddress(hServerDll
,
146 (PVOID
)&ServerDllInitProcedure
);
150 /* No handle, so we are loading ourselves */
151 ServerDllInitProcedure
= CsrServerDllInitialization
;
152 Status
= STATUS_SUCCESS
;
155 /* Check if we got the pointer, and call it */
156 if (NT_SUCCESS(Status
))
158 /* Get the result from the Server DLL */
159 Status
= (*ServerDllInitProcedure
)(ServerDll
);
161 /* Check for Success */
162 if (NT_SUCCESS(Status
))
165 * Add this Server's Per-Process Data Size to the total that each
168 CsrTotalPerProcessDataLength
+= ServerDll
->SizeOfProcessData
;
170 /* Save the pointer in our list */
171 CsrLoadedServerDll
[ServerDll
->ServerId
] = ServerDll
;
173 /* Does it use our generic heap? */
174 if (ServerDll
->SharedSection
!= CsrSrvSharedSectionHeap
)
176 /* No, save the pointer to its shared section in our list */
177 CsrSrvSharedStaticServerData
[ServerDll
->ServerId
] = ServerDll
->SharedSection
;
182 /* Use shared failure code */
189 /* Server Init failed, unload it */
190 if (hServerDll
) LdrUnloadDll(hServerDll
);
192 /* Delete the Object */
193 RtlFreeHeap(CsrHeap
, 0, ServerDll
);
196 /* Return to caller */
201 * @name CsrServerDllInitialization
204 * The CsrServerDllInitialization is the initialization routine for
205 * the this Server DLL.
207 * @param LoadedServerDll
208 * Pointer to the CSR Server DLL structure representing this Server DLL.
210 * @return STATUS_SUCCESS.
217 CsrServerDllInitialization(IN PCSR_SERVER_DLL LoadedServerDll
)
219 /* Setup the DLL Object */
220 LoadedServerDll
->ApiBase
= 0;
221 LoadedServerDll
->HighestApiSupported
= 5;
222 LoadedServerDll
->DispatchTable
= CsrServerApiDispatchTable
;
223 LoadedServerDll
->ValidTable
= CsrServerApiServerValidTable
;
224 LoadedServerDll
->NameTable
= CsrServerApiNameTable
;
225 LoadedServerDll
->SizeOfProcessData
= 0;
226 LoadedServerDll
->ConnectCallback
= NULL
;
227 LoadedServerDll
->DisconnectCallback
= NULL
;
230 return STATUS_SUCCESS
;
234 * @name CsrSrvClientConnect
236 * The CsrSrvClientConnect CSR API handles a new connection to a server DLL.
239 * Pointer to the CSR API Message for this request.
242 * Optional reply to this request.
244 * @return STATUS_SUCCESS in case of success, STATUS_INVALID_PARAMETER
245 * or STATUS_TOO_MANY_NAMES in case of failure.
252 CsrSrvClientConnect(IN OUT PCSR_API_MESSAGE ApiMessage
,
253 IN OUT PULONG Reply OPTIONAL
)
256 PCSR_CLIENT_CONNECT ClientConnect
;
257 PCSR_SERVER_DLL ServerDll
;
259 /* Load the Message, set default reply */
260 ClientConnect
= (PCSR_CLIENT_CONNECT
)&ApiMessage
->CsrClientConnect
;
263 /* Validate the ServerID */
264 if (ClientConnect
->ServerId
>= CSR_SERVER_DLL_MAX
)
266 return STATUS_TOO_MANY_NAMES
;
268 else if (!(CsrLoadedServerDll
[ClientConnect
->ServerId
]))
270 return STATUS_INVALID_PARAMETER
;
273 /* Validate the Message Buffer */
274 if (!(CsrValidateMessageBuffer(ApiMessage
,
275 ClientConnect
->ConnectionInfo
,
276 ClientConnect
->ConnectionInfoSize
,
279 /* Fail due to buffer overflow or other invalid buffer */
280 return STATUS_INVALID_PARAMETER
;
283 /* Load the Server DLL */
284 ServerDll
= CsrLoadedServerDll
[ClientConnect
->ServerId
];
286 /* Check if it has a Connect Callback */
287 if (ServerDll
->ConnectCallback
)
289 /* Call the callback */
290 Status
= (ServerDll
->ConnectCallback
)(((PCSR_THREAD
)NtCurrentTeb()->CsrClientThread
)->Process
,
291 ClientConnect
->ConnectionInfo
,
292 &ClientConnect
->ConnectionInfoSize
);
297 Status
= STATUS_SUCCESS
;
305 * @name CsrSrvCreateSharedSection
307 * The CsrSrvCreateSharedSection creates the Shared Section that all CSR Server
308 * DLLs and Clients can use to share data.
310 * @param ParameterValue
311 * Specially formatted string from our registry command-line which
312 * specifies various arguments for the shared section.
314 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
322 CsrSrvCreateSharedSection(IN PCHAR ParameterValue
)
324 PCHAR SizeValue
= ParameterValue
;
327 LARGE_INTEGER SectionSize
;
329 PPEB Peb
= NtCurrentPeb();
331 /* Find the first comma, and null terminate */
334 if (*SizeValue
== ',')
345 /* Make sure it's valid */
346 if (!*SizeValue
) return(STATUS_INVALID_PARAMETER
);
348 /* Convert it to an integer */
349 Status
= RtlCharToInteger(SizeValue
,
352 if (!NT_SUCCESS(Status
)) return Status
;
354 /* Multiply by 1024 entries and round to page size */
355 CsrSrvSharedSectionSize
= ROUND_UP(Size
* 1024, CsrNtSysInfo
.PageSize
);
357 /* Create the Secion */
358 SectionSize
.LowPart
= CsrSrvSharedSectionSize
;
359 SectionSize
.HighPart
= 0;
360 Status
= NtCreateSection(&CsrSrvSharedSection
,
364 PAGE_EXECUTE_READWRITE
,
365 SEC_BASED
| SEC_RESERVE
,
367 if (!NT_SUCCESS(Status
)) return Status
;
369 /* Map the section */
370 Status
= NtMapViewOfSection(CsrSrvSharedSection
,
372 &CsrSrvSharedSectionBase
,
379 PAGE_EXECUTE_READWRITE
);
380 if(!NT_SUCCESS(Status
))
383 NtClose(CsrSrvSharedSection
);
387 /* FIXME: Write the value to registry */
389 /* The Heap is the same place as the Base */
390 CsrSrvSharedSectionHeap
= CsrSrvSharedSectionBase
;
392 /* Create the heap */
393 if (!(RtlCreateHeap(HEAP_ZERO_MEMORY
,
394 CsrSrvSharedSectionHeap
,
395 CsrSrvSharedSectionSize
,
400 /* Failure, unmap section and return */
401 NtUnmapViewOfSection(NtCurrentProcess(),
402 CsrSrvSharedSectionBase
);
403 NtClose(CsrSrvSharedSection
);
404 return STATUS_NO_MEMORY
;
407 /* Now allocate space from the heap for the Shared Data */
408 CsrSrvSharedStaticServerData
= RtlAllocateHeap(CsrSrvSharedSectionHeap
,
413 /* Write the values to the PEB */
414 Peb
->ReadOnlySharedMemoryBase
= CsrSrvSharedSectionBase
;
415 Peb
->ReadOnlySharedMemoryHeap
= CsrSrvSharedSectionHeap
;
416 Peb
->ReadOnlyStaticServerData
= CsrSrvSharedStaticServerData
;
419 return STATUS_SUCCESS
;
423 * @name CsrSrvAttachSharedSection
425 * The CsrSrvAttachSharedSection maps the CSR Shared Section into a new
426 * CSR Process' address space, and returns the pointers to the section
427 * through the Connection Info structure.
430 * Pointer to the CSR Process that is attempting a connection.
433 * Pointer to the CSR Connection Info structure for the incoming
436 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
444 CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL
,
445 OUT PCSR_CONNECTION_INFO ConnectInfo
)
450 /* Check if we have a process */
453 /* Map the sectio into this process */
454 Status
= NtMapViewOfSection(CsrSrvSharedSection
,
455 CsrProcess
->ProcessHandle
,
456 &CsrSrvSharedSectionBase
,
464 if (!NT_SUCCESS(Status
)) return Status
;
467 /* Write the values in the Connection Info structure */
468 ConnectInfo
->SharedSectionBase
= CsrSrvSharedSectionBase
;
469 ConnectInfo
->SharedSectionHeap
= CsrSrvSharedSectionHeap
;
470 ConnectInfo
->SharedSectionData
= CsrSrvSharedStaticServerData
;
473 return STATUS_SUCCESS
;
477 * @name CsrSrvIdentifyAlertableThread
480 * The CsrSrvIdentifyAlertableThread CSR API marks a CSR Thread as alertable.
483 * Pointer to the CSR API Message for this request.
486 * Pointer to an optional reply to this request.
488 * @return STATUS_SUCCESS.
495 CsrSrvIdentifyAlertableThread(IN OUT PCSR_API_MESSAGE ApiMessage
,
498 PCSR_THREAD CsrThread
= NtCurrentTeb()->CsrClientThread
;
500 /* Set the alertable flag */
501 CsrThread
->Flags
|= CsrThreadAltertable
;
504 return STATUS_SUCCESS
;
508 * @name CsrSrvSetPriorityClass
511 * The CsrSrvSetPriorityClass CSR API is deprecated.
514 * Pointer to the CSR API Message for this request.
517 * Pointer to an optional reply to this request.
519 * @return STATUS_SUCCESS.
526 CsrSrvSetPriorityClass(IN OUT PCSR_API_MESSAGE ApiMessage
,
530 return STATUS_SUCCESS
;
534 * @name CsrSrvUnusedFunction
537 * The CsrSrvUnusedFunction CSR API is a stub for deprecated APIs.
539 * The CsrSrvSetPriorityClass CSR API is deprecated.
542 * Pointer to the CSR API Message for this request.
545 * Pointer to an optional reply to this request.
547 * @return STATUS_INVALID_PARAMETER.
549 * @remarks CsrSrvSetPriorityClass does not use this stub because it must
555 CsrSrvUnusedFunction(IN OUT PCSR_API_MESSAGE ApiMessage
,
559 return STATUS_INVALID_PARAMETER
;
562 /* PUBLIC FUNCTIONS***********************************************************/
565 * @name CsrSetCallingSpooler
568 * the CsrSetCallingSpooler routine is deprecated.
575 * @remarks This routine was used in archaic versions of NT for Printer Drivers.
580 CsrSetCallingSpooler(ULONG Reserved
)
587 * @name CsrUnhandledExceptionFilter
590 * The CsrUnhandledExceptionFilter routine handles all exceptions
591 * within SEH-protected blocks.
593 * @param ExceptionPointers
594 * System-defined Argument.
596 * @return EXCEPTION_EXECUTE_HANDLER.
601 _SEH_FILTER(CsrUnhandledExceptionFilter
)
603 struct _EXCEPTION_POINTERS
*ExceptionInfo
= _SEH_GetExceptionPointers();
604 SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo
;
605 EXCEPTION_DISPOSITION Result
= EXCEPTION_EXECUTE_HANDLER
;
608 UNICODE_STRING ErrorSource
;
609 ULONG_PTR ErrorParameters
[4];
612 /* Check if a debugger is installed */
613 Status
= NtQuerySystemInformation(SystemKernelDebuggerInformation
,
615 sizeof(DebuggerInfo
),
618 /* Check if this is Session 0, and the Debugger is Enabled */
619 if ((NtCurrentPeb()->SessionId
) && (NT_SUCCESS(Status
)) &&
620 (DebuggerInfo
.KernelDebuggerEnabled
))
622 /* Call the Unhandled Exception Filter */
623 if ((Result
= RtlUnhandledExceptionFilter(ExceptionInfo
)) !=
624 EXCEPTION_CONTINUE_EXECUTION
)
626 /* We're going to raise an error. Get Shutdown Privilege first */
627 Status
= RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
,
632 /* Use the Process token if that failed */
633 if (Status
== STATUS_NO_TOKEN
)
635 Status
= RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
,
641 /* Initialize our Name String */
642 RtlInitUnicodeString(&ErrorSource
, L
"Windows SubSystem");
644 /* Set the parameters */
645 ErrorParameters
[0] = PtrToUlong(&ErrorSource
);
646 ErrorParameters
[1] = ExceptionInfo
->ExceptionRecord
->ExceptionCode
;
647 ErrorParameters
[2] = PtrToUlong(ExceptionInfo
->ExceptionRecord
->ExceptionAddress
);
648 ErrorParameters
[3] = PtrToUlong(ExceptionInfo
->ContextRecord
);
651 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
655 OptionShutdownSystem
,
659 /* Just terminate us */
660 NtTerminateProcess(NtCurrentProcess(),
661 ExceptionInfo
->ExceptionRecord
->ExceptionCode
);