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 *******************************************************************/
13 #include <ndk/mmfuncs.h>
18 /* DATA ***********************************************************************/
20 PCSR_SERVER_DLL CsrLoadedServerDll
[CSR_SERVER_DLL_MAX
];
21 PVOID CsrSrvSharedSectionHeap
= NULL
;
22 PVOID CsrSrvSharedSectionBase
= NULL
;
23 PVOID
*CsrSrvSharedStaticServerData
= NULL
;
24 ULONG CsrSrvSharedSectionSize
= 0;
25 HANDLE CsrSrvSharedSection
= NULL
;
27 PCSR_API_ROUTINE CsrServerApiDispatchTable
[CsrpMaxApiNumber
] =
32 CsrSrvIdentifyAlertableThread
,
33 CsrSrvSetPriorityClass
36 BOOLEAN CsrServerApiServerValidTable
[CsrpMaxApiNumber
] =
46 * On Windows Server 2003, CSR Servers contain
47 * the API Names Table only in Debug Builds.
50 PCHAR CsrServerApiNameTable
[CsrpMaxApiNumber
] =
55 "IdentifyAlertableThread",
60 /* PRIVATE FUNCTIONS **********************************************************/
63 * @name CsrServerDllInitialization
66 * The CsrServerDllInitialization is the initialization routine
67 * for this Server DLL.
69 * @param LoadedServerDll
70 * Pointer to the CSR Server DLL structure representing this Server DLL.
72 * @return STATUS_SUCCESS.
77 CSR_SERVER_DLL_INIT(CsrServerDllInitialization
)
79 /* Setup the DLL Object */
80 LoadedServerDll
->ApiBase
= CSRSRV_FIRST_API_NUMBER
;
81 LoadedServerDll
->HighestApiSupported
= CsrpMaxApiNumber
;
82 LoadedServerDll
->DispatchTable
= CsrServerApiDispatchTable
;
83 LoadedServerDll
->ValidTable
= CsrServerApiServerValidTable
;
85 LoadedServerDll
->NameTable
= CsrServerApiNameTable
;
87 LoadedServerDll
->SizeOfProcessData
= 0;
88 LoadedServerDll
->ConnectCallback
= NULL
;
89 LoadedServerDll
->DisconnectCallback
= NULL
;
92 return STATUS_SUCCESS
;
96 * @name CsrLoadServerDll
99 * The CsrLoadServerDll routine loads a CSR Server DLL and calls its entrypoint.
102 * Pointer to the CSR Server DLL to load and call.
105 * Pointer to the name of the server's initialization function.
106 * If this parameter is NULL, the default ServerDllInitialize
109 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
116 CsrLoadServerDll(IN PCHAR DllString
,
117 IN PCHAR EntryPoint OPTIONAL
,
122 UNICODE_STRING TempString
, ErrorString
;
123 ULONG_PTR Parameters
[2];
124 HANDLE hServerDll
= NULL
;
126 PCSR_SERVER_DLL ServerDll
;
127 STRING EntryPointString
;
128 PCSR_SERVER_DLL_INIT_CALLBACK ServerDllInitProcedure
;
131 /* Check if it's beyond the maximum we support */
132 if (ServerId
>= CSR_SERVER_DLL_MAX
) return STATUS_TOO_MANY_NAMES
;
134 /* Check if it's already been loaded */
135 if (CsrLoadedServerDll
[ServerId
]) return STATUS_INVALID_PARAMETER
;
137 /* Convert the name to Unicode */
138 ASSERT(DllString
!= NULL
);
139 RtlInitAnsiString(&DllName
, DllString
);
140 Status
= RtlAnsiStringToUnicodeString(&TempString
, &DllName
, TRUE
);
141 if (!NT_SUCCESS(Status
)) return Status
;
143 /* If we are loading ourselves, don't actually load us */
144 if (ServerId
!= CSRSRV_SERVERDLL_INDEX
)
147 Status
= LdrLoadDll(NULL
, 0, &TempString
, &hServerDll
);
148 if (!NT_SUCCESS(Status
))
150 /* Setup error parameters */
151 Parameters
[0] = (ULONG_PTR
)&TempString
;
152 Parameters
[1] = (ULONG_PTR
)&ErrorString
;
153 RtlInitUnicodeString(&ErrorString
, L
"Default Load Path");
155 /* Send a hard error */
156 NtRaiseHardError(Status
,
164 /* Get rid of the string */
165 RtlFreeUnicodeString(&TempString
);
166 if (!NT_SUCCESS(Status
)) return Status
;
169 /* Allocate a CSR DLL Object */
170 Size
= sizeof(CSR_SERVER_DLL
) + DllName
.MaximumLength
;
171 ServerDll
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, Size
);
174 if (hServerDll
) LdrUnloadDll(hServerDll
);
175 return STATUS_NO_MEMORY
;
178 /* Set up the Object */
179 ServerDll
->Length
= Size
;
180 ServerDll
->SizeOfProcessData
= 0;
181 ServerDll
->SharedSection
= CsrSrvSharedSectionHeap
; // Send to the server dll our shared heap pointer.
182 ServerDll
->Name
.Length
= DllName
.Length
;
183 ServerDll
->Name
.MaximumLength
= DllName
.MaximumLength
;
184 ServerDll
->Name
.Buffer
= (PCHAR
)(ServerDll
+ 1);
187 strncpy(ServerDll
->Name
.Buffer
, DllName
.Buffer
, DllName
.Length
);
189 ServerDll
->ServerId
= ServerId
;
190 ServerDll
->ServerHandle
= hServerDll
;
192 /* Now get the entrypoint */
195 /* Initialize a string for the entrypoint, or use the default */
196 RtlInitAnsiString(&EntryPointString
,
197 EntryPoint
? EntryPoint
: "ServerDllInitialization");
199 /* Get a pointer to it */
200 Status
= LdrGetProcedureAddress(hServerDll
,
203 (PVOID
)&ServerDllInitProcedure
);
207 /* No handle, so we are loading ourselves */
209 RtlInitAnsiString(&EntryPointString
, "CsrServerDllInitialization");
211 ServerDllInitProcedure
= CsrServerDllInitialization
;
212 Status
= STATUS_SUCCESS
;
215 /* Check if we got the pointer, and call it */
216 if (NT_SUCCESS(Status
))
218 /* Call the Server DLL entrypoint */
221 Status
= ServerDllInitProcedure(ServerDll
);
223 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
225 Status
= _SEH2_GetExceptionCode();
227 DPRINT1("CSRSS: Exception 0x%lx while calling Server DLL entrypoint %Z!%Z()\n",
228 Status
, &DllName
, &EntryPointString
);
233 if (NT_SUCCESS(Status
))
236 * Add this Server's Per-Process Data Size to the total that each
239 CsrTotalPerProcessDataLength
+= ServerDll
->SizeOfProcessData
;
241 /* Save the pointer in our list */
242 CsrLoadedServerDll
[ServerDll
->ServerId
] = ServerDll
;
244 /* Does it use our generic heap? */
245 if (ServerDll
->SharedSection
!= CsrSrvSharedSectionHeap
)
247 /* No, save the pointer to its shared section in our list */
248 CsrSrvSharedStaticServerData
[ServerDll
->ServerId
] = ServerDll
->SharedSection
;
253 if (!NT_SUCCESS(Status
))
255 /* Server Init failed, unload it */
256 if (hServerDll
) LdrUnloadDll(hServerDll
);
258 /* Delete the Object */
259 RtlFreeHeap(CsrHeap
, 0, ServerDll
);
262 /* Return to caller */
267 * @name CsrSrvClientConnect
269 * The CsrSrvClientConnect CSR API handles a new connection to a server DLL.
272 * Pointer to the CSR API Message for this request.
275 * Optional reply to this request.
277 * @return STATUS_SUCCESS in case of success, STATUS_INVALID_PARAMETER
278 * or STATUS_TOO_MANY_NAMES in case of failure.
283 CSR_API(CsrSrvClientConnect
)
286 PCSR_CLIENT_CONNECT ClientConnect
= &ApiMessage
->Data
.CsrClientConnect
;
287 PCSR_SERVER_DLL ServerDll
;
288 PCSR_PROCESS CurrentProcess
= CsrGetClientThread()->Process
;
290 /* Set default reply */
291 *ReplyCode
= CsrReplyImmediately
;
293 /* Validate the ServerID */
294 if (ClientConnect
->ServerId
>= CSR_SERVER_DLL_MAX
)
296 return STATUS_TOO_MANY_NAMES
;
298 else if (!CsrLoadedServerDll
[ClientConnect
->ServerId
])
300 return STATUS_INVALID_PARAMETER
;
303 /* Validate the Message Buffer */
304 if (!(CsrValidateMessageBuffer(ApiMessage
,
305 &ClientConnect
->ConnectionInfo
,
306 ClientConnect
->ConnectionInfoSize
,
309 /* Fail due to buffer overflow or other invalid buffer */
310 return STATUS_INVALID_PARAMETER
;
313 /* Load the Server DLL */
314 ServerDll
= CsrLoadedServerDll
[ClientConnect
->ServerId
];
316 /* Check if it has a Connect Callback */
317 if (ServerDll
->ConnectCallback
)
319 /* Call the callback */
320 Status
= ServerDll
->ConnectCallback(CurrentProcess
,
321 ClientConnect
->ConnectionInfo
,
322 &ClientConnect
->ConnectionInfoSize
);
327 Status
= STATUS_SUCCESS
;
335 * @name CsrSrvCreateSharedSection
337 * The CsrSrvCreateSharedSection creates the Shared Section that all
338 * CSR Server DLLs and Clients can use to share data.
340 * @param ParameterValue
341 * Specially formatted string from our registry command-line which
342 * specifies various arguments for the shared section.
344 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
351 CsrSrvCreateSharedSection(IN PCHAR ParameterValue
)
353 PCHAR SizeValue
= ParameterValue
;
356 LARGE_INTEGER SectionSize
;
358 PPEB Peb
= NtCurrentPeb();
360 /* If there's no parameter, fail */
361 if (!ParameterValue
) return STATUS_INVALID_PARAMETER
;
363 /* Find the first comma, and null terminate */
366 if (*SizeValue
== ',')
368 *SizeValue
++ = ANSI_NULL
;
377 /* Make sure it's valid */
378 if (!*SizeValue
) return STATUS_INVALID_PARAMETER
;
380 /* Convert it to an integer */
381 Status
= RtlCharToInteger(SizeValue
, 0, &Size
);
382 if (!NT_SUCCESS(Status
)) return Status
;
384 /* Multiply by 1024 entries and round to page size */
385 CsrSrvSharedSectionSize
= ROUND_UP(Size
* 1024, CsrNtSysInfo
.PageSize
);
387 /* Create the Secion */
388 SectionSize
.LowPart
= CsrSrvSharedSectionSize
;
389 SectionSize
.HighPart
= 0;
390 Status
= NtCreateSection(&CsrSrvSharedSection
,
394 PAGE_EXECUTE_READWRITE
,
395 SEC_BASED
| SEC_RESERVE
,
397 if (!NT_SUCCESS(Status
)) return Status
;
399 /* Map the section */
400 Status
= NtMapViewOfSection(CsrSrvSharedSection
,
402 &CsrSrvSharedSectionBase
,
409 PAGE_EXECUTE_READWRITE
);
410 if (!NT_SUCCESS(Status
))
413 NtClose(CsrSrvSharedSection
);
417 /* FIXME: Write the value to registry */
419 /* The Heap is the same place as the Base */
420 CsrSrvSharedSectionHeap
= CsrSrvSharedSectionBase
;
422 /* Create the heap */
423 if (!(RtlCreateHeap(HEAP_ZERO_MEMORY
| HEAP_CLASS_7
,
424 CsrSrvSharedSectionHeap
,
425 CsrSrvSharedSectionSize
,
430 /* Failure, unmap section and return */
431 NtUnmapViewOfSection(NtCurrentProcess(), CsrSrvSharedSectionBase
);
432 NtClose(CsrSrvSharedSection
);
433 return STATUS_NO_MEMORY
;
436 /* Now allocate space from the heap for the Shared Data */
437 CsrSrvSharedStaticServerData
= RtlAllocateHeap(CsrSrvSharedSectionHeap
,
439 CSR_SERVER_DLL_MAX
* sizeof(PVOID
));
440 if (!CsrSrvSharedStaticServerData
) return STATUS_NO_MEMORY
;
442 /* Write the values to the PEB */
443 Peb
->ReadOnlySharedMemoryBase
= CsrSrvSharedSectionBase
;
444 Peb
->ReadOnlySharedMemoryHeap
= CsrSrvSharedSectionHeap
;
445 Peb
->ReadOnlyStaticServerData
= CsrSrvSharedStaticServerData
;
448 return STATUS_SUCCESS
;
452 * @name CsrSrvAttachSharedSection
454 * The CsrSrvAttachSharedSection maps the CSR Shared Section into a new
455 * CSR Process' address space, and returns the pointers to the section
456 * through the Connection Info structure.
459 * Pointer to the CSR Process that is attempting a connection.
462 * Pointer to the CSR Connection Info structure for the incoming
465 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
472 CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL
,
473 OUT PCSR_API_CONNECTINFO ConnectInfo
)
478 /* Check if we have a process */
481 /* Map the section into this process */
482 Status
= NtMapViewOfSection(CsrSrvSharedSection
,
483 CsrProcess
->ProcessHandle
,
484 &CsrSrvSharedSectionBase
,
492 if (!NT_SUCCESS(Status
)) return Status
;
495 /* Write the values in the Connection Info structure */
496 ConnectInfo
->SharedSectionBase
= CsrSrvSharedSectionBase
;
497 ConnectInfo
->SharedSectionHeap
= CsrSrvSharedSectionHeap
;
498 ConnectInfo
->SharedStaticServerData
= CsrSrvSharedStaticServerData
;
501 return STATUS_SUCCESS
;
505 * @name CsrSrvIdentifyAlertableThread
508 * The CsrSrvIdentifyAlertableThread CSR API marks a CSR Thread as alertable.
511 * Pointer to the CSR API Message for this request.
514 * Pointer to an optional reply to this request.
516 * @return STATUS_SUCCESS.
521 CSR_API(CsrSrvIdentifyAlertableThread
)
523 PCSR_THREAD CsrThread
= CsrGetClientThread();
525 /* Set the alertable flag */
526 CsrThread
->Flags
|= CsrThreadAlertable
;
529 return STATUS_SUCCESS
;
533 * @name CsrSrvSetPriorityClass
536 * The CsrSrvSetPriorityClass CSR API is deprecated.
539 * Pointer to the CSR API Message for this request.
542 * Pointer to an optional reply to this request.
544 * @return STATUS_SUCCESS.
549 CSR_API(CsrSrvSetPriorityClass
)
552 return STATUS_SUCCESS
;
556 * @name CsrSrvUnusedFunction
559 * The CsrSrvUnusedFunction CSR API is a stub for deprecated APIs.
561 * The CsrSrvSetPriorityClass CSR API is deprecated.
564 * Pointer to the CSR API Message for this request.
567 * Pointer to an optional reply to this request.
569 * @return STATUS_INVALID_PARAMETER.
571 * @remarks CsrSrvSetPriorityClass does not use this stub because
572 * it must return success.
575 CSR_API(CsrSrvUnusedFunction
)
578 return STATUS_INVALID_PARAMETER
;
581 /* PUBLIC FUNCTIONS ***********************************************************/
584 * @name CsrSetCallingSpooler
587 * the CsrSetCallingSpooler routine is deprecated.
594 * @remarks This routine was used in archaic versions of NT for Printer Drivers.
599 CsrSetCallingSpooler(ULONG Reserved
)
606 * @name CsrUnhandledExceptionFilter
609 * The CsrUnhandledExceptionFilter routine handles all exceptions
610 * within SEH-protected blocks.
612 * @param ExceptionPointers
613 * System-defined Argument.
615 * @return EXCEPTION_EXECUTE_HANDLER.
620 EXCEPTION_DISPOSITION
622 CsrUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo
)
624 SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo
;
625 EXCEPTION_DISPOSITION Result
= EXCEPTION_EXECUTE_HANDLER
;
628 UNICODE_STRING ErrorSource
;
629 ULONG_PTR ErrorParameters
[4];
632 DPRINT1("CsrUnhandledExceptionFilter called\n");
634 /* Check if a debugger is installed */
635 Status
= NtQuerySystemInformation(SystemKernelDebuggerInformation
,
637 sizeof(DebuggerInfo
),
640 /* Check if this is Session 0, and the Debugger is Enabled */
641 if ((NtCurrentPeb()->SessionId
!= 0) && (NT_SUCCESS(Status
)) &&
642 (DebuggerInfo
.KernelDebuggerEnabled
))
644 /* Call the Unhandled Exception Filter */
645 Result
= RtlUnhandledExceptionFilter(ExceptionInfo
);
646 if (Result
!= EXCEPTION_CONTINUE_EXECUTION
)
648 /* We're going to raise an error. Get Shutdown Privilege first */
649 Status
= RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
,
654 /* Use the Process token if that failed */
655 if (Status
== STATUS_NO_TOKEN
)
657 Status
= RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
,
662 if (!NT_SUCCESS(Status
))
664 DPRINT1("CsrUnhandledExceptionFilter(): RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE) failed, Status = 0x%08lx\n", Status
);
668 /* Initialize our Name String */
669 RtlInitUnicodeString(&ErrorSource
, L
"Windows SubSystem");
671 /* Set the parameters */
672 ErrorParameters
[0] = (ULONG_PTR
)&ErrorSource
;
673 ErrorParameters
[1] = ExceptionInfo
->ExceptionRecord
->ExceptionCode
;
674 ErrorParameters
[2] = (ULONG_PTR
)ExceptionInfo
->ExceptionRecord
->ExceptionAddress
;
675 ErrorParameters
[3] = (ULONG_PTR
)ExceptionInfo
->ContextRecord
;
678 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
,
682 OptionShutdownSystem
,
687 /* Just terminate us */
688 NtTerminateProcess(NtCurrentProcess(),
689 ExceptionInfo
->ExceptionRecord
->ExceptionCode
);