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