2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Client/Server Runtime SubSystem
4 * FILE: subsystems/win32/csrsrv/server.c
5 * PURPOSE: CSR Server DLL Server Functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES *******************************************************************/
16 /* DATA ***********************************************************************/
18 PCSR_API_ROUTINE CsrServerApiDispatchTable
[CsrpMaxApiNumber
] =
23 CsrSrvIdentifyAlertableThread
,
24 CsrSrvSetPriorityClass
27 BOOLEAN CsrServerApiServerValidTable
[CsrpMaxApiNumber
] =
36 PCHAR CsrServerApiNameTable
[CsrpMaxApiNumber
] =
41 "IdentifyAlertableThread",
45 PCSR_SERVER_DLL CsrLoadedServerDll
[CSR_SERVER_DLL_MAX
];
46 PVOID CsrSrvSharedSectionHeap
;
47 PVOID CsrSrvSharedSectionBase
;
48 PVOID
*CsrSrvSharedStaticServerData
;
49 ULONG CsrSrvSharedSectionSize
;
50 HANDLE CsrSrvSharedSection
;
52 /* PRIVATE FUNCTIONS **********************************************************/
55 * @name CsrServerDllInitialization
58 * The CsrServerDllInitialization is the initialization routine for
59 * the this Server DLL.
61 * @param LoadedServerDll
62 * Pointer to the CSR Server DLL structure representing this Server DLL.
64 * @return STATUS_SUCCESS.
69 CSR_SERVER_DLL_INIT(CsrServerDllInitialization
)
71 /* Setup the DLL Object */
72 LoadedServerDll
->ApiBase
= 0;
73 LoadedServerDll
->HighestApiSupported
= CsrpMaxApiNumber
;
74 LoadedServerDll
->DispatchTable
= CsrServerApiDispatchTable
;
75 LoadedServerDll
->ValidTable
= CsrServerApiServerValidTable
;
76 LoadedServerDll
->NameTable
= CsrServerApiNameTable
;
77 LoadedServerDll
->SizeOfProcessData
= 0;
78 LoadedServerDll
->ConnectCallback
= NULL
;
79 LoadedServerDll
->DisconnectCallback
= NULL
;
82 return STATUS_SUCCESS
;
86 * @name CsrLoadServerDll
89 * The CsrLoadServerDll routine loads a CSR Server DLL and calls its entrypoint
92 * Pointer to the CSR Server DLL to load and call.
95 * Pointer to the name of the server's initialization function. If
96 * this parameter is NULL, the default ServerDllInitialize will be
99 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
107 CsrLoadServerDll(IN PCHAR DllString
,
108 IN PCHAR EntryPoint OPTIONAL
,
113 UNICODE_STRING TempString
, ErrorString
;
114 ULONG_PTR Parameters
[2];
115 HANDLE hServerDll
= NULL
;
117 PCSR_SERVER_DLL ServerDll
;
118 STRING EntryPointString
;
119 PCSR_SERVER_DLL_INIT_CALLBACK ServerDllInitProcedure
;
122 DPRINT1("CsrLoadServerDll(%s, 0x%p, %lu)\n", DllString
, EntryPoint
, ServerId
);
124 /* Check if it's beyond the maximum we support */
125 if (ServerId
>= CSR_SERVER_DLL_MAX
) return STATUS_TOO_MANY_NAMES
;
127 /* Check if it's already been loaded */
128 if (CsrLoadedServerDll
[ServerId
]) return STATUS_INVALID_PARAMETER
;
130 /* Convert the name to Unicode */
131 ASSERT(DllString
!= NULL
);
132 RtlInitAnsiString(&DllName
, DllString
);
133 Status
= RtlAnsiStringToUnicodeString(&TempString
, &DllName
, TRUE
);
134 if (!NT_SUCCESS(Status
)) return Status
;
136 /* If we are loading ourselves, don't actually load us */
137 if (ServerId
!= CSRSRV_SERVERDLL_INDEX
)
140 Status
= LdrLoadDll(NULL
, 0, &TempString
, &hServerDll
);
141 if (!NT_SUCCESS(Status
))
143 /* Setup error parameters */
144 Parameters
[0] = (ULONG_PTR
)&TempString
;
145 Parameters
[1] = (ULONG_PTR
)&ErrorString
;
146 RtlInitUnicodeString(&ErrorString
, L
"Default Load Path");
148 /* Send a hard error */
149 NtRaiseHardError(Status
,
157 /* Get rid of the string */
158 RtlFreeUnicodeString(&TempString
);
159 if (!NT_SUCCESS(Status
)) return Status
;
162 /* Allocate a CSR DLL Object */
163 Size
= sizeof(CSR_SERVER_DLL
) + DllName
.MaximumLength
;
164 ServerDll
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, Size
);
167 if (hServerDll
) LdrUnloadDll(hServerDll
);
168 return STATUS_NO_MEMORY
;
171 /* Set up the Object */
172 ServerDll
->Length
= Size
;
173 ServerDll
->SharedSection
= CsrSrvSharedSectionHeap
; // Send to the server dll our shared heap pointer.
174 ServerDll
->Event
= CsrInitializationEvent
;
175 ServerDll
->Name
.Length
= DllName
.Length
;
176 ServerDll
->Name
.MaximumLength
= DllName
.MaximumLength
;
177 ServerDll
->Name
.Buffer
= (PCHAR
)(ServerDll
+ 1);
180 strncpy(ServerDll
->Name
.Buffer
, DllName
.Buffer
, DllName
.Length
);
182 ServerDll
->ServerId
= ServerId
;
183 ServerDll
->ServerHandle
= hServerDll
;
185 /* Now get the entrypoint */
188 /* Initialize a string for the entrypoint, or use the default */
189 RtlInitAnsiString(&EntryPointString
,
190 EntryPoint
? EntryPoint
: "ServerDllInitialization");
192 /* Get a pointer to it */
193 Status
= LdrGetProcedureAddress(hServerDll
,
196 (PVOID
)&ServerDllInitProcedure
);
200 /* No handle, so we are loading ourselves */
201 ServerDllInitProcedure
= CsrServerDllInitialization
;
202 Status
= STATUS_SUCCESS
;
205 /* Check if we got the pointer, and call it */
206 if (NT_SUCCESS(Status
))
208 /* Get the result from the Server DLL */
209 Status
= ServerDllInitProcedure(ServerDll
);
210 if (NT_SUCCESS(Status
))
213 * Add this Server's Per-Process Data Size to the total that each
216 CsrTotalPerProcessDataLength
+= ServerDll
->SizeOfProcessData
;
218 /* Save the pointer in our list */
219 CsrLoadedServerDll
[ServerDll
->ServerId
] = ServerDll
;
221 /* Does it use our generic heap? */
222 if (ServerDll
->SharedSection
!= CsrSrvSharedSectionHeap
)
224 /* No, save the pointer to its shared section in our list */
225 CsrSrvSharedStaticServerData
[ServerDll
->ServerId
] = ServerDll
->SharedSection
;
230 /* Use shared failure code */
237 /* Server Init failed, unload it */
238 if (hServerDll
) LdrUnloadDll(hServerDll
);
240 /* Delete the Object */
241 RtlFreeHeap(CsrHeap
, 0, ServerDll
);
244 /* Return to caller */
249 * @name CsrSrvClientConnect
251 * The CsrSrvClientConnect CSR API handles a new connection to a server DLL.
254 * Pointer to the CSR API Message for this request.
257 * Optional reply to this request.
259 * @return STATUS_SUCCESS in case of success, STATUS_INVALID_PARAMETER
260 * or STATUS_TOO_MANY_NAMES in case of failure.
265 CSR_API(CsrSrvClientConnect
)
268 PCSR_CLIENT_CONNECT ClientConnect
= &ApiMessage
->Data
.CsrClientConnect
;
269 PCSR_SERVER_DLL ServerDll
;
270 PCSR_PROCESS CurrentProcess
= CsrGetClientThread()->Process
;
272 /* Set default reply */
273 *ReplyCode
= CsrReplyImmediately
;
275 /* Validate the ServerID */
276 if (ClientConnect
->ServerId
>= CSR_SERVER_DLL_MAX
)
278 return STATUS_TOO_MANY_NAMES
;
280 else if (!CsrLoadedServerDll
[ClientConnect
->ServerId
])
282 return STATUS_INVALID_PARAMETER
;
285 /* Validate the Message Buffer */
286 if (!(CsrValidateMessageBuffer(ApiMessage
,
287 &ClientConnect
->ConnectionInfo
,
288 ClientConnect
->ConnectionInfoSize
,
291 /* Fail due to buffer overflow or other invalid buffer */
292 return STATUS_INVALID_PARAMETER
;
295 /* Load the Server DLL */
296 ServerDll
= CsrLoadedServerDll
[ClientConnect
->ServerId
];
298 /* Check if it has a Connect Callback */
299 if (ServerDll
->ConnectCallback
)
301 /* Call the callback */
302 Status
= ServerDll
->ConnectCallback(CurrentProcess
,
303 ClientConnect
->ConnectionInfo
,
304 &ClientConnect
->ConnectionInfoSize
);
309 Status
= STATUS_SUCCESS
;
317 * @name CsrSrvCreateSharedSection
319 * The CsrSrvCreateSharedSection creates the Shared Section that all CSR Server
320 * DLLs and Clients can use to share data.
322 * @param ParameterValue
323 * Specially formatted string from our registry command-line which
324 * specifies various arguments for the shared section.
326 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
334 CsrSrvCreateSharedSection(IN PCHAR ParameterValue
)
336 PCHAR SizeValue
= ParameterValue
;
339 LARGE_INTEGER SectionSize
;
341 PPEB Peb
= NtCurrentPeb();
343 /* If there's no parameter, fail */
344 if (!ParameterValue
) return STATUS_INVALID_PARAMETER
;
346 /* Find the first comma, and null terminate */
349 if (*SizeValue
== ',')
351 *SizeValue
++ = ANSI_NULL
;
360 /* Make sure it's valid */
361 if (!*SizeValue
) return STATUS_INVALID_PARAMETER
;
363 /* Convert it to an integer */
364 Status
= RtlCharToInteger(SizeValue
, 0, &Size
);
365 if (!NT_SUCCESS(Status
)) return Status
;
367 /* Multiply by 1024 entries and round to page size */
368 CsrSrvSharedSectionSize
= ROUND_UP(Size
* 1024, CsrNtSysInfo
.PageSize
);
370 /* Create the Secion */
371 SectionSize
.LowPart
= CsrSrvSharedSectionSize
;
372 SectionSize
.HighPart
= 0;
373 Status
= NtCreateSection(&CsrSrvSharedSection
,
377 PAGE_EXECUTE_READWRITE
,
378 SEC_BASED
| SEC_RESERVE
,
380 if (!NT_SUCCESS(Status
)) return Status
;
382 /* Map the section */
383 Status
= NtMapViewOfSection(CsrSrvSharedSection
,
385 &CsrSrvSharedSectionBase
,
392 PAGE_EXECUTE_READWRITE
);
393 if (!NT_SUCCESS(Status
))
396 NtClose(CsrSrvSharedSection
);
400 /* FIXME: Write the value to registry */
402 /* The Heap is the same place as the Base */
403 CsrSrvSharedSectionHeap
= CsrSrvSharedSectionBase
;
405 /* Create the heap */
406 if (!(RtlCreateHeap(HEAP_ZERO_MEMORY
| HEAP_CLASS_7
,
407 CsrSrvSharedSectionHeap
,
408 CsrSrvSharedSectionSize
,
413 /* Failure, unmap section and return */
414 NtUnmapViewOfSection(NtCurrentProcess(), CsrSrvSharedSectionBase
);
415 NtClose(CsrSrvSharedSection
);
416 return STATUS_NO_MEMORY
;
419 /* Now allocate space from the heap for the Shared Data */
420 CsrSrvSharedStaticServerData
= RtlAllocateHeap(CsrSrvSharedSectionHeap
,
422 CSR_SERVER_DLL_MAX
* sizeof(PVOID
));
423 if (!CsrSrvSharedStaticServerData
) return STATUS_NO_MEMORY
;
425 /* Write the values to the PEB */
426 Peb
->ReadOnlySharedMemoryBase
= CsrSrvSharedSectionBase
;
427 Peb
->ReadOnlySharedMemoryHeap
= CsrSrvSharedSectionHeap
;
428 Peb
->ReadOnlyStaticServerData
= CsrSrvSharedStaticServerData
;
431 return STATUS_SUCCESS
;
435 * @name CsrSrvAttachSharedSection
437 * The CsrSrvAttachSharedSection maps the CSR Shared Section into a new
438 * CSR Process' address space, and returns the pointers to the section
439 * through the Connection Info structure.
442 * Pointer to the CSR Process that is attempting a connection.
445 * Pointer to the CSR Connection Info structure for the incoming
448 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
456 CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL
,
457 OUT PCSR_CONNECTION_INFO ConnectInfo
)
462 /* Check if we have a process */
465 /* Map the section into this process */
466 DPRINT("CSR Process Handle: %p. CSR Process: %p\n", CsrProcess
->ProcessHandle
, CsrProcess
);
467 Status
= NtMapViewOfSection(CsrSrvSharedSection
,
468 CsrProcess
->ProcessHandle
,
469 &CsrSrvSharedSectionBase
,
477 if (!NT_SUCCESS(Status
)) return Status
;
480 /* Write the values in the Connection Info structure */
481 ConnectInfo
->SharedSectionBase
= CsrSrvSharedSectionBase
;
482 ConnectInfo
->SharedSectionHeap
= CsrSrvSharedSectionHeap
;
483 ConnectInfo
->SharedSectionData
= CsrSrvSharedStaticServerData
;
486 return STATUS_SUCCESS
;
490 * @name CsrSrvIdentifyAlertableThread
493 * The CsrSrvIdentifyAlertableThread CSR API marks a CSR Thread as alertable.
496 * Pointer to the CSR API Message for this request.
499 * Pointer to an optional reply to this request.
501 * @return STATUS_SUCCESS.
506 CSR_API(CsrSrvIdentifyAlertableThread
)
508 PCSR_THREAD CsrThread
= CsrGetClientThread();
510 /* Set the alertable flag */
511 CsrThread
->Flags
|= CsrThreadAlertable
;
514 return STATUS_SUCCESS
;
518 * @name CsrSrvSetPriorityClass
521 * The CsrSrvSetPriorityClass CSR API is deprecated.
524 * Pointer to the CSR API Message for this request.
527 * Pointer to an optional reply to this request.
529 * @return STATUS_SUCCESS.
534 CSR_API(CsrSrvSetPriorityClass
)
537 return STATUS_SUCCESS
;
541 * @name CsrSrvUnusedFunction
544 * The CsrSrvUnusedFunction CSR API is a stub for deprecated APIs.
546 * The CsrSrvSetPriorityClass CSR API is deprecated.
549 * Pointer to the CSR API Message for this request.
552 * Pointer to an optional reply to this request.
554 * @return STATUS_INVALID_PARAMETER.
556 * @remarks CsrSrvSetPriorityClass does not use this stub because it must
560 CSR_API(CsrSrvUnusedFunction
)
563 return STATUS_INVALID_PARAMETER
;
566 /* PUBLIC FUNCTIONS ***********************************************************/
569 * @name CsrSetCallingSpooler
572 * the CsrSetCallingSpooler routine is deprecated.
579 * @remarks This routine was used in archaic versions of NT for Printer Drivers.
584 CsrSetCallingSpooler(ULONG Reserved
)
591 * @name CsrUnhandledExceptionFilter
594 * The CsrUnhandledExceptionFilter routine handles all exceptions
595 * within SEH-protected blocks.
597 * @param ExceptionPointers
598 * System-defined Argument.
600 * @return EXCEPTION_EXECUTE_HANDLER.
605 EXCEPTION_DISPOSITION
607 CsrUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo
)
609 SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo
;
610 EXCEPTION_DISPOSITION Result
= EXCEPTION_EXECUTE_HANDLER
;
613 UNICODE_STRING ErrorSource
;
614 ULONG_PTR ErrorParameters
[4];
617 /* Check if a debugger is installed */
618 Status
= NtQuerySystemInformation(SystemKernelDebuggerInformation
,
620 sizeof(DebuggerInfo
),
623 /* Check if this is Session 0, and the Debugger is Enabled */
624 if ((NtCurrentPeb()->SessionId
) && (NT_SUCCESS(Status
)) &&
625 (DebuggerInfo
.KernelDebuggerEnabled
))
627 /* Call the Unhandled Exception Filter */
628 if ((Result
= RtlUnhandledExceptionFilter(ExceptionInfo
)) !=
629 EXCEPTION_CONTINUE_EXECUTION
)
631 /* We're going to raise an error. Get Shutdown Privilege first */
632 Status
= RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
,
637 /* Use the Process token if that failed */
638 if (Status
== STATUS_NO_TOKEN
)
640 Status
= RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
,
646 /* Initialize our Name String */
647 RtlInitUnicodeString(&ErrorSource
, L
"Windows SubSystem");
649 /* Set the parameters */
650 ErrorParameters
[0] = (ULONG_PTR
)&ErrorSource
;
651 ErrorParameters
[1] = ExceptionInfo
->ExceptionRecord
->ExceptionCode
;
652 ErrorParameters
[2] = (ULONG_PTR
)ExceptionInfo
->ExceptionRecord
->ExceptionAddress
;
653 ErrorParameters
[3] = (ULONG_PTR
)ExceptionInfo
->ContextRecord
;
656 Status
= NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
660 OptionShutdownSystem
,
664 /* Just terminate us */
665 NtTerminateProcess(NtCurrentProcess(),
666 ExceptionInfo
->ExceptionRecord
->ExceptionCode
);