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