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