4fa353679272d71e0be6b06f21687aab85ad6b38
[reactos.git] / subsystems / win32 / csrsrv / server.c
1 /*
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)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "srv.h"
12
13 #include <ndk/mmfuncs.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* DATA ***********************************************************************/
19
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;
26
27 PCSR_API_ROUTINE CsrServerApiDispatchTable[CsrpMaxApiNumber] =
28 {
29 CsrSrvClientConnect,
30 CsrSrvUnusedFunction,
31 CsrSrvUnusedFunction,
32 CsrSrvIdentifyAlertableThread,
33 CsrSrvSetPriorityClass
34 };
35
36 BOOLEAN CsrServerApiServerValidTable[CsrpMaxApiNumber] =
37 {
38 TRUE,
39 FALSE,
40 TRUE,
41 TRUE,
42 TRUE
43 };
44
45 /*
46 * On Windows Server 2003, CSR Servers contain
47 * the API Names Table only in Debug Builds.
48 */
49 #ifdef CSR_DBG
50 PCHAR CsrServerApiNameTable[CsrpMaxApiNumber] =
51 {
52 "ClientConnect",
53 "ThreadConnect",
54 "ProfileControl",
55 "IdentifyAlertableThread",
56 "SetPriorityClass"
57 };
58 #endif
59
60 /* PRIVATE FUNCTIONS **********************************************************/
61
62 /*++
63 * @name CsrServerDllInitialization
64 * @implemented NT4
65 *
66 * The CsrServerDllInitialization is the initialization routine
67 * for this Server DLL.
68 *
69 * @param LoadedServerDll
70 * Pointer to the CSR Server DLL structure representing this Server DLL.
71 *
72 * @return STATUS_SUCCESS.
73 *
74 * @remarks None.
75 *
76 *--*/
77 CSR_SERVER_DLL_INIT(CsrServerDllInitialization)
78 {
79 /* Setup the DLL Object */
80 LoadedServerDll->ApiBase = CSRSRV_FIRST_API_NUMBER;
81 LoadedServerDll->HighestApiSupported = CsrpMaxApiNumber;
82 LoadedServerDll->DispatchTable = CsrServerApiDispatchTable;
83 LoadedServerDll->ValidTable = CsrServerApiServerValidTable;
84 #ifdef CSR_DBG
85 LoadedServerDll->NameTable = CsrServerApiNameTable;
86 #endif
87 LoadedServerDll->SizeOfProcessData = 0;
88 LoadedServerDll->ConnectCallback = NULL;
89 LoadedServerDll->DisconnectCallback = NULL;
90
91 /* All done */
92 return STATUS_SUCCESS;
93 }
94
95 /*++
96 * @name CsrLoadServerDll
97 * @implemented NT4
98 *
99 * The CsrLoadServerDll routine loads a CSR Server DLL and calls its entrypoint.
100 *
101 * @param DllString
102 * Pointer to the CSR Server DLL to load and call.
103 *
104 * @param EntryPoint
105 * Pointer to the name of the server's initialization function.
106 * If this parameter is NULL, the default ServerDllInitialize
107 * will be assumed.
108 *
109 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
110 *
111 * @remarks None.
112 *
113 *--*/
114 NTSTATUS
115 NTAPI
116 CsrLoadServerDll(IN PCHAR DllString,
117 IN PCHAR EntryPoint OPTIONAL,
118 IN ULONG ServerId)
119 {
120 NTSTATUS Status;
121 ANSI_STRING DllName;
122 UNICODE_STRING TempString, ErrorString;
123 ULONG_PTR Parameters[2];
124 HANDLE hServerDll = NULL;
125 ULONG Size;
126 PCSR_SERVER_DLL ServerDll;
127 STRING EntryPointString;
128 PCSR_SERVER_DLL_INIT_CALLBACK ServerDllInitProcedure;
129 ULONG Response;
130
131 /* Check if it's beyond the maximum we support */
132 if (ServerId >= CSR_SERVER_DLL_MAX) return STATUS_TOO_MANY_NAMES;
133
134 /* Check if it's already been loaded */
135 if (CsrLoadedServerDll[ServerId]) return STATUS_INVALID_PARAMETER;
136
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;
142
143 /* If we are loading ourselves, don't actually load us */
144 if (ServerId != CSRSRV_SERVERDLL_INDEX)
145 {
146 /* Load the DLL */
147 Status = LdrLoadDll(NULL, 0, &TempString, &hServerDll);
148 if (!NT_SUCCESS(Status))
149 {
150 /* Setup error parameters */
151 Parameters[0] = (ULONG_PTR)&TempString;
152 Parameters[1] = (ULONG_PTR)&ErrorString;
153 RtlInitUnicodeString(&ErrorString, L"Default Load Path");
154
155 /* Send a hard error */
156 NtRaiseHardError(Status,
157 2,
158 3,
159 Parameters,
160 OptionOk,
161 &Response);
162 }
163
164 /* Get rid of the string */
165 RtlFreeUnicodeString(&TempString);
166 if (!NT_SUCCESS(Status)) return Status;
167 }
168
169 /* Allocate a CSR DLL Object */
170 Size = sizeof(CSR_SERVER_DLL) + DllName.MaximumLength;
171 ServerDll = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Size);
172 if (!ServerDll)
173 {
174 if (hServerDll) LdrUnloadDll(hServerDll);
175 return STATUS_NO_MEMORY;
176 }
177
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);
185 if (DllName.Length)
186 {
187 strncpy(ServerDll->Name.Buffer, DllName.Buffer, DllName.Length);
188 }
189 ServerDll->ServerId = ServerId;
190 ServerDll->ServerHandle = hServerDll;
191
192 /* Now get the entrypoint */
193 if (hServerDll)
194 {
195 /* Initialize a string for the entrypoint, or use the default */
196 RtlInitAnsiString(&EntryPointString,
197 EntryPoint ? EntryPoint : "ServerDllInitialization");
198
199 /* Get a pointer to it */
200 Status = LdrGetProcedureAddress(hServerDll,
201 &EntryPointString,
202 0,
203 (PVOID)&ServerDllInitProcedure);
204 }
205 else
206 {
207 /* No handle, so we are loading ourselves */
208 #ifdef CSR_DBG
209 RtlInitAnsiString(&EntryPointString, "CsrServerDllInitialization");
210 #endif
211 ServerDllInitProcedure = CsrServerDllInitialization;
212 Status = STATUS_SUCCESS;
213 }
214
215 /* Check if we got the pointer, and call it */
216 if (NT_SUCCESS(Status))
217 {
218 /* Call the Server DLL entrypoint */
219 _SEH2_TRY
220 {
221 Status = ServerDllInitProcedure(ServerDll);
222 }
223 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
224 {
225 Status = _SEH2_GetExceptionCode();
226 #ifdef CSR_DBG
227 DPRINT1("CSRSS: Exception 0x%lx while calling Server DLL entrypoint %Z!%Z()\n",
228 Status, &DllName, &EntryPointString);
229 #endif
230 }
231 _SEH2_END;
232
233 if (NT_SUCCESS(Status))
234 {
235 /*
236 * Add this Server's Per-Process Data Size to the total that each
237 * process will need.
238 */
239 CsrTotalPerProcessDataLength += ServerDll->SizeOfProcessData;
240
241 /* Save the pointer in our list */
242 CsrLoadedServerDll[ServerDll->ServerId] = ServerDll;
243
244 /* Does it use our generic heap? */
245 if (ServerDll->SharedSection != CsrSrvSharedSectionHeap)
246 {
247 /* No, save the pointer to its shared section in our list */
248 CsrSrvSharedStaticServerData[ServerDll->ServerId] = ServerDll->SharedSection;
249 }
250 }
251 }
252
253 if (!NT_SUCCESS(Status))
254 {
255 /* Server Init failed, unload it */
256 if (hServerDll) LdrUnloadDll(hServerDll);
257
258 /* Delete the Object */
259 RtlFreeHeap(CsrHeap, 0, ServerDll);
260 }
261
262 /* Return to caller */
263 return Status;
264 }
265
266 /*++
267 * @name CsrSrvClientConnect
268 *
269 * The CsrSrvClientConnect CSR API handles a new connection to a server DLL.
270 *
271 * @param ApiMessage
272 * Pointer to the CSR API Message for this request.
273 *
274 * @param ReplyCode
275 * Optional reply to this request.
276 *
277 * @return STATUS_SUCCESS in case of success, STATUS_INVALID_PARAMETER
278 * or STATUS_TOO_MANY_NAMES in case of failure.
279 *
280 * @remarks None.
281 *
282 *--*/
283 CSR_API(CsrSrvClientConnect)
284 {
285 NTSTATUS Status;
286 PCSR_CLIENT_CONNECT ClientConnect = &ApiMessage->Data.CsrClientConnect;
287 PCSR_SERVER_DLL ServerDll;
288 PCSR_PROCESS CurrentProcess = CsrGetClientThread()->Process;
289
290 /* Set default reply */
291 *ReplyCode = CsrReplyImmediately;
292
293 /* Validate the ServerID */
294 if (ClientConnect->ServerId >= CSR_SERVER_DLL_MAX)
295 {
296 return STATUS_TOO_MANY_NAMES;
297 }
298 else if (!CsrLoadedServerDll[ClientConnect->ServerId])
299 {
300 return STATUS_INVALID_PARAMETER;
301 }
302
303 /* Validate the Message Buffer */
304 if (!(CsrValidateMessageBuffer(ApiMessage,
305 &ClientConnect->ConnectionInfo,
306 ClientConnect->ConnectionInfoSize,
307 sizeof(BYTE))))
308 {
309 /* Fail due to buffer overflow or other invalid buffer */
310 return STATUS_INVALID_PARAMETER;
311 }
312
313 /* Load the Server DLL */
314 ServerDll = CsrLoadedServerDll[ClientConnect->ServerId];
315
316 /* Check if it has a Connect Callback */
317 if (ServerDll->ConnectCallback)
318 {
319 /* Call the callback */
320 Status = ServerDll->ConnectCallback(CurrentProcess,
321 ClientConnect->ConnectionInfo,
322 &ClientConnect->ConnectionInfoSize);
323 }
324 else
325 {
326 /* Assume success */
327 Status = STATUS_SUCCESS;
328 }
329
330 /* Return status */
331 return Status;
332 }
333
334 /*++
335 * @name CsrSrvCreateSharedSection
336 *
337 * The CsrSrvCreateSharedSection creates the Shared Section that all
338 * CSR Server DLLs and Clients can use to share data.
339 *
340 * @param ParameterValue
341 * Specially formatted string from our registry command-line which
342 * specifies various arguments for the shared section.
343 *
344 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
345 *
346 * @remarks None.
347 *
348 *--*/
349 NTSTATUS
350 NTAPI
351 CsrSrvCreateSharedSection(IN PCHAR ParameterValue)
352 {
353 PCHAR SizeValue = ParameterValue;
354 ULONG Size;
355 NTSTATUS Status;
356 LARGE_INTEGER SectionSize;
357 SIZE_T ViewSize = 0;
358 PPEB Peb = NtCurrentPeb();
359
360 /* If there's no parameter, fail */
361 if (!ParameterValue) return STATUS_INVALID_PARAMETER;
362
363 /* Find the first comma, and null terminate */
364 while (*SizeValue)
365 {
366 if (*SizeValue == ',')
367 {
368 *SizeValue++ = ANSI_NULL;
369 break;
370 }
371 else
372 {
373 SizeValue++;
374 }
375 }
376
377 /* Make sure it's valid */
378 if (!*SizeValue) return STATUS_INVALID_PARAMETER;
379
380 /* Convert it to an integer */
381 Status = RtlCharToInteger(SizeValue, 0, &Size);
382 if (!NT_SUCCESS(Status)) return Status;
383
384 /* Multiply by 1024 entries and round to page size */
385 CsrSrvSharedSectionSize = ROUND_UP(Size * 1024, CsrNtSysInfo.PageSize);
386
387 /* Create the Secion */
388 SectionSize.LowPart = CsrSrvSharedSectionSize;
389 SectionSize.HighPart = 0;
390 Status = NtCreateSection(&CsrSrvSharedSection,
391 SECTION_ALL_ACCESS,
392 NULL,
393 &SectionSize,
394 PAGE_EXECUTE_READWRITE,
395 SEC_BASED | SEC_RESERVE,
396 NULL);
397 if (!NT_SUCCESS(Status)) return Status;
398
399 /* Map the section */
400 Status = NtMapViewOfSection(CsrSrvSharedSection,
401 NtCurrentProcess(),
402 &CsrSrvSharedSectionBase,
403 0,
404 0,
405 NULL,
406 &ViewSize,
407 ViewUnmap,
408 MEM_TOP_DOWN,
409 PAGE_EXECUTE_READWRITE);
410 if (!NT_SUCCESS(Status))
411 {
412 /* Fail */
413 NtClose(CsrSrvSharedSection);
414 return Status;
415 }
416
417 /* FIXME: Write the value to registry */
418
419 /* The Heap is the same place as the Base */
420 CsrSrvSharedSectionHeap = CsrSrvSharedSectionBase;
421
422 /* Create the heap */
423 if (!(RtlCreateHeap(HEAP_ZERO_MEMORY | HEAP_CLASS_7,
424 CsrSrvSharedSectionHeap,
425 CsrSrvSharedSectionSize,
426 PAGE_SIZE,
427 0,
428 0)))
429 {
430 /* Failure, unmap section and return */
431 NtUnmapViewOfSection(NtCurrentProcess(), CsrSrvSharedSectionBase);
432 NtClose(CsrSrvSharedSection);
433 return STATUS_NO_MEMORY;
434 }
435
436 /* Now allocate space from the heap for the Shared Data */
437 CsrSrvSharedStaticServerData = RtlAllocateHeap(CsrSrvSharedSectionHeap,
438 HEAP_ZERO_MEMORY,
439 CSR_SERVER_DLL_MAX * sizeof(PVOID));
440 if (!CsrSrvSharedStaticServerData) return STATUS_NO_MEMORY;
441
442 /* Write the values to the PEB */
443 Peb->ReadOnlySharedMemoryBase = CsrSrvSharedSectionBase;
444 Peb->ReadOnlySharedMemoryHeap = CsrSrvSharedSectionHeap;
445 Peb->ReadOnlyStaticServerData = CsrSrvSharedStaticServerData;
446
447 /* Return */
448 return STATUS_SUCCESS;
449 }
450
451 /*++
452 * @name CsrSrvAttachSharedSection
453 *
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.
457 *
458 * @param CsrProcess
459 * Pointer to the CSR Process that is attempting a connection.
460 *
461 * @param ConnectInfo
462 * Pointer to the CSR Connection Info structure for the incoming
463 * connection.
464 *
465 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
466 *
467 * @remarks None.
468 *
469 *--*/
470 NTSTATUS
471 NTAPI
472 CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL,
473 OUT PCSR_API_CONNECTINFO ConnectInfo)
474 {
475 NTSTATUS Status;
476 SIZE_T ViewSize = 0;
477
478 /* Check if we have a process */
479 if (CsrProcess)
480 {
481 /* Map the section into this process */
482 Status = NtMapViewOfSection(CsrSrvSharedSection,
483 CsrProcess->ProcessHandle,
484 &CsrSrvSharedSectionBase,
485 0,
486 0,
487 NULL,
488 &ViewSize,
489 ViewUnmap,
490 SEC_NO_CHANGE,
491 PAGE_EXECUTE_READ);
492 if (!NT_SUCCESS(Status)) return Status;
493 }
494
495 /* Write the values in the Connection Info structure */
496 ConnectInfo->SharedSectionBase = CsrSrvSharedSectionBase;
497 ConnectInfo->SharedSectionHeap = CsrSrvSharedSectionHeap;
498 ConnectInfo->SharedStaticServerData = CsrSrvSharedStaticServerData;
499
500 /* Return success */
501 return STATUS_SUCCESS;
502 }
503
504 /*++
505 * @name CsrSrvIdentifyAlertableThread
506 * @implemented NT4
507 *
508 * The CsrSrvIdentifyAlertableThread CSR API marks a CSR Thread as alertable.
509 *
510 * @param ApiMessage
511 * Pointer to the CSR API Message for this request.
512 *
513 * @param ReplyCode
514 * Pointer to an optional reply to this request.
515 *
516 * @return STATUS_SUCCESS.
517 *
518 * @remarks None.
519 *
520 *--*/
521 CSR_API(CsrSrvIdentifyAlertableThread)
522 {
523 PCSR_THREAD CsrThread = CsrGetClientThread();
524
525 /* Set the alertable flag */
526 CsrThread->Flags |= CsrThreadAlertable;
527
528 /* Return success */
529 return STATUS_SUCCESS;
530 }
531
532 /*++
533 * @name CsrSrvSetPriorityClass
534 * @implemented NT4
535 *
536 * The CsrSrvSetPriorityClass CSR API is deprecated.
537 *
538 * @param ApiMessage
539 * Pointer to the CSR API Message for this request.
540 *
541 * @param ReplyCode
542 * Pointer to an optional reply to this request.
543 *
544 * @return STATUS_SUCCESS.
545 *
546 * @remarks None.
547 *
548 *--*/
549 CSR_API(CsrSrvSetPriorityClass)
550 {
551 /* Deprecated */
552 return STATUS_SUCCESS;
553 }
554
555 /*++
556 * @name CsrSrvUnusedFunction
557 * @implemented NT4
558 *
559 * The CsrSrvUnusedFunction CSR API is a stub for deprecated APIs.
560 *
561 * The CsrSrvSetPriorityClass CSR API is deprecated.
562 *
563 * @param ApiMessage
564 * Pointer to the CSR API Message for this request.
565 *
566 * @param ReplyCode
567 * Pointer to an optional reply to this request.
568 *
569 * @return STATUS_INVALID_PARAMETER.
570 *
571 * @remarks CsrSrvSetPriorityClass does not use this stub because
572 * it must return success.
573 *
574 *--*/
575 CSR_API(CsrSrvUnusedFunction)
576 {
577 /* Deprecated */
578 return STATUS_INVALID_PARAMETER;
579 }
580
581 /* PUBLIC FUNCTIONS ***********************************************************/
582
583 /*++
584 * @name CsrSetCallingSpooler
585 * @implemented NT4
586 *
587 * the CsrSetCallingSpooler routine is deprecated.
588 *
589 * @param Reserved
590 * Deprecated
591 *
592 * @return None.
593 *
594 * @remarks This routine was used in archaic versions of NT for Printer Drivers.
595 *
596 *--*/
597 VOID
598 NTAPI
599 CsrSetCallingSpooler(ULONG Reserved)
600 {
601 /* Deprecated */
602 return;
603 }
604
605 /*++
606 * @name CsrUnhandledExceptionFilter
607 * @implemented NT5
608 *
609 * The CsrUnhandledExceptionFilter routine handles all exceptions
610 * within SEH-protected blocks.
611 *
612 * @param ExceptionPointers
613 * System-defined Argument.
614 *
615 * @return EXCEPTION_EXECUTE_HANDLER.
616 *
617 * @remarks None.
618 *
619 *--*/
620 EXCEPTION_DISPOSITION
621 NTAPI
622 CsrUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo)
623 {
624 SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo;
625 EXCEPTION_DISPOSITION Result = EXCEPTION_EXECUTE_HANDLER;
626 BOOLEAN OldValue;
627 NTSTATUS Status;
628 UNICODE_STRING ErrorSource;
629 ULONG_PTR ErrorParameters[4];
630 ULONG Response;
631
632 DPRINT1("CsrUnhandledExceptionFilter called\n");
633
634 /* Check if a debugger is installed */
635 Status = NtQuerySystemInformation(SystemKernelDebuggerInformation,
636 &DebuggerInfo,
637 sizeof(DebuggerInfo),
638 NULL);
639
640 /* Check if this is Session 0, and the Debugger is Enabled */
641 if ((NtCurrentPeb()->SessionId != 0) && (NT_SUCCESS(Status)) &&
642 (DebuggerInfo.KernelDebuggerEnabled))
643 {
644 /* Call the Unhandled Exception Filter */
645 Result = RtlUnhandledExceptionFilter(ExceptionInfo);
646 if (Result != EXCEPTION_CONTINUE_EXECUTION)
647 {
648 /* We're going to raise an error. Get Shutdown Privilege first */
649 Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
650 TRUE,
651 TRUE,
652 &OldValue);
653
654 /* Use the Process token if that failed */
655 if (Status == STATUS_NO_TOKEN)
656 {
657 Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
658 TRUE,
659 FALSE,
660 &OldValue);
661 }
662
663 /* Initialize our Name String */
664 RtlInitUnicodeString(&ErrorSource, L"Windows SubSystem");
665
666 /* Set the parameters */
667 ErrorParameters[0] = (ULONG_PTR)&ErrorSource;
668 ErrorParameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode;
669 ErrorParameters[2] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress;
670 ErrorParameters[3] = (ULONG_PTR)ExceptionInfo->ContextRecord;
671
672 /* Bugcheck */
673 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
674 4,
675 1,
676 ErrorParameters,
677 OptionShutdownSystem,
678 &Response);
679 }
680
681 /* Just terminate us */
682 NtTerminateProcess(NtCurrentProcess(),
683 ExceptionInfo->ExceptionRecord->ExceptionCode);
684 }
685
686 return Result;
687 }
688
689 /* EOF */