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