c20ec56e091308f21935f609db4bd326daeaad20
[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 ReplyCode
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 CSR_API(CsrSrvClientConnect)
266 {
267 NTSTATUS Status;
268 PCSR_CLIENT_CONNECT ClientConnect = &ApiMessage->Data.CsrClientConnect;
269 PCSR_SERVER_DLL ServerDll;
270 PCSR_PROCESS CurrentProcess = CsrGetClientThread()->Process;
271
272 /* Set default reply */
273 *ReplyCode = CsrReplyImmediately;
274
275 /* Validate the ServerID */
276 if (ClientConnect->ServerId >= CSR_SERVER_DLL_MAX)
277 {
278 return STATUS_TOO_MANY_NAMES;
279 }
280 else if (!CsrLoadedServerDll[ClientConnect->ServerId])
281 {
282 return STATUS_INVALID_PARAMETER;
283 }
284
285 /* Validate the Message Buffer */
286 if (!(CsrValidateMessageBuffer(ApiMessage,
287 &ClientConnect->ConnectionInfo,
288 ClientConnect->ConnectionInfoSize,
289 sizeof(BYTE))))
290 {
291 /* Fail due to buffer overflow or other invalid buffer */
292 return STATUS_INVALID_PARAMETER;
293 }
294
295 /* Load the Server DLL */
296 ServerDll = CsrLoadedServerDll[ClientConnect->ServerId];
297
298 /* Check if it has a Connect Callback */
299 if (ServerDll->ConnectCallback)
300 {
301 /* Call the callback */
302 Status = ServerDll->ConnectCallback(CurrentProcess,
303 ClientConnect->ConnectionInfo,
304 &ClientConnect->ConnectionInfoSize);
305 }
306 else
307 {
308 /* Assume success */
309 Status = STATUS_SUCCESS;
310 }
311
312 /* Return status */
313 return Status;
314 }
315
316 /*++
317 * @name CsrSrvCreateSharedSection
318 *
319 * The CsrSrvCreateSharedSection creates the Shared Section that all CSR Server
320 * DLLs and Clients can use to share data.
321 *
322 * @param ParameterValue
323 * Specially formatted string from our registry command-line which
324 * specifies various arguments for the shared section.
325 *
326 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
327 * otherwise.
328 *
329 * @remarks None.
330 *
331 *--*/
332 NTSTATUS
333 NTAPI
334 CsrSrvCreateSharedSection(IN PCHAR ParameterValue)
335 {
336 PCHAR SizeValue = ParameterValue;
337 ULONG Size;
338 NTSTATUS Status;
339 LARGE_INTEGER SectionSize;
340 ULONG ViewSize = 0;
341 PPEB Peb = NtCurrentPeb();
342
343 /* If there's no parameter, fail */
344 if (!ParameterValue) return STATUS_INVALID_PARAMETER;
345
346 /* Find the first comma, and null terminate */
347 while (*SizeValue)
348 {
349 if (*SizeValue == ',')
350 {
351 *SizeValue++ = ANSI_NULL;
352 break;
353 }
354 else
355 {
356 SizeValue++;
357 }
358 }
359
360 /* Make sure it's valid */
361 if (!*SizeValue) return STATUS_INVALID_PARAMETER;
362
363 /* Convert it to an integer */
364 Status = RtlCharToInteger(SizeValue, 0, &Size);
365 if (!NT_SUCCESS(Status)) return Status;
366
367 /* Multiply by 1024 entries and round to page size */
368 CsrSrvSharedSectionSize = ROUND_UP(Size * 1024, CsrNtSysInfo.PageSize);
369
370 /* Create the Secion */
371 SectionSize.LowPart = CsrSrvSharedSectionSize;
372 SectionSize.HighPart = 0;
373 Status = NtCreateSection(&CsrSrvSharedSection,
374 SECTION_ALL_ACCESS,
375 NULL,
376 &SectionSize,
377 PAGE_EXECUTE_READWRITE,
378 SEC_BASED | SEC_RESERVE,
379 NULL);
380 if (!NT_SUCCESS(Status)) return Status;
381
382 /* Map the section */
383 Status = NtMapViewOfSection(CsrSrvSharedSection,
384 NtCurrentProcess(),
385 &CsrSrvSharedSectionBase,
386 0,
387 0,
388 NULL,
389 &ViewSize,
390 ViewUnmap,
391 MEM_TOP_DOWN,
392 PAGE_EXECUTE_READWRITE);
393 if (!NT_SUCCESS(Status))
394 {
395 /* Fail */
396 NtClose(CsrSrvSharedSection);
397 return Status;
398 }
399
400 /* FIXME: Write the value to registry */
401
402 /* The Heap is the same place as the Base */
403 CsrSrvSharedSectionHeap = CsrSrvSharedSectionBase;
404
405 /* Create the heap */
406 if (!(RtlCreateHeap(HEAP_ZERO_MEMORY | HEAP_CLASS_7,
407 CsrSrvSharedSectionHeap,
408 CsrSrvSharedSectionSize,
409 PAGE_SIZE,
410 0,
411 0)))
412 {
413 /* Failure, unmap section and return */
414 NtUnmapViewOfSection(NtCurrentProcess(), CsrSrvSharedSectionBase);
415 NtClose(CsrSrvSharedSection);
416 return STATUS_NO_MEMORY;
417 }
418
419 /* Now allocate space from the heap for the Shared Data */
420 CsrSrvSharedStaticServerData = RtlAllocateHeap(CsrSrvSharedSectionHeap,
421 HEAP_ZERO_MEMORY,
422 CSR_SERVER_DLL_MAX * sizeof(PVOID));
423 if (!CsrSrvSharedStaticServerData) return STATUS_NO_MEMORY;
424
425 /* Write the values to the PEB */
426 Peb->ReadOnlySharedMemoryBase = CsrSrvSharedSectionBase;
427 Peb->ReadOnlySharedMemoryHeap = CsrSrvSharedSectionHeap;
428 Peb->ReadOnlyStaticServerData = CsrSrvSharedStaticServerData;
429
430 /* Return */
431 return STATUS_SUCCESS;
432 }
433
434 /*++
435 * @name CsrSrvAttachSharedSection
436 *
437 * The CsrSrvAttachSharedSection maps the CSR Shared Section into a new
438 * CSR Process' address space, and returns the pointers to the section
439 * through the Connection Info structure.
440 *
441 * @param CsrProcess
442 * Pointer to the CSR Process that is attempting a connection.
443 *
444 * @param ConnectInfo
445 * Pointer to the CSR Connection Info structure for the incoming
446 * connection.
447 *
448 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
449 * otherwise.
450 *
451 * @remarks None.
452 *
453 *--*/
454 NTSTATUS
455 NTAPI
456 CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL,
457 OUT PCSR_CONNECTION_INFO ConnectInfo)
458 {
459 NTSTATUS Status;
460 ULONG ViewSize = 0;
461
462 /* Check if we have a process */
463 if (CsrProcess)
464 {
465 /* Map the section into this process */
466 DPRINT("CSR Process Handle: %p. CSR Process: %p\n", CsrProcess->ProcessHandle, CsrProcess);
467 Status = NtMapViewOfSection(CsrSrvSharedSection,
468 CsrProcess->ProcessHandle,
469 &CsrSrvSharedSectionBase,
470 0,
471 0,
472 NULL,
473 &ViewSize,
474 ViewUnmap,
475 SEC_NO_CHANGE,
476 PAGE_EXECUTE_READ);
477 if (!NT_SUCCESS(Status)) return Status;
478 }
479
480 /* Write the values in the Connection Info structure */
481 ConnectInfo->SharedSectionBase = CsrSrvSharedSectionBase;
482 ConnectInfo->SharedSectionHeap = CsrSrvSharedSectionHeap;
483 ConnectInfo->SharedSectionData = CsrSrvSharedStaticServerData;
484
485 /* Return success */
486 return STATUS_SUCCESS;
487 }
488
489 /*++
490 * @name CsrSrvIdentifyAlertableThread
491 * @implemented NT4
492 *
493 * The CsrSrvIdentifyAlertableThread CSR API marks a CSR Thread as alertable.
494 *
495 * @param ApiMessage
496 * Pointer to the CSR API Message for this request.
497 *
498 * @param ReplyCode
499 * Pointer to an optional reply to this request.
500 *
501 * @return STATUS_SUCCESS.
502 *
503 * @remarks None.
504 *
505 *--*/
506 CSR_API(CsrSrvIdentifyAlertableThread)
507 {
508 PCSR_THREAD CsrThread = CsrGetClientThread();
509
510 /* Set the alertable flag */
511 CsrThread->Flags |= CsrThreadAlertable;
512
513 /* Return success */
514 return STATUS_SUCCESS;
515 }
516
517 /*++
518 * @name CsrSrvSetPriorityClass
519 * @implemented NT4
520 *
521 * The CsrSrvSetPriorityClass CSR API is deprecated.
522 *
523 * @param ApiMessage
524 * Pointer to the CSR API Message for this request.
525 *
526 * @param ReplyCode
527 * Pointer to an optional reply to this request.
528 *
529 * @return STATUS_SUCCESS.
530 *
531 * @remarks None.
532 *
533 *--*/
534 CSR_API(CsrSrvSetPriorityClass)
535 {
536 /* Deprecated */
537 return STATUS_SUCCESS;
538 }
539
540 /*++
541 * @name CsrSrvUnusedFunction
542 * @implemented NT4
543 *
544 * The CsrSrvUnusedFunction CSR API is a stub for deprecated APIs.
545 *
546 * The CsrSrvSetPriorityClass CSR API is deprecated.
547 *
548 * @param ApiMessage
549 * Pointer to the CSR API Message for this request.
550 *
551 * @param ReplyCode
552 * Pointer to an optional reply to this request.
553 *
554 * @return STATUS_INVALID_PARAMETER.
555 *
556 * @remarks CsrSrvSetPriorityClass does not use this stub because it must
557 * return success.
558 *
559 *--*/
560 CSR_API(CsrSrvUnusedFunction)
561 {
562 /* Deprecated */
563 return STATUS_INVALID_PARAMETER;
564 }
565
566 /* PUBLIC FUNCTIONS ***********************************************************/
567
568 /*++
569 * @name CsrSetCallingSpooler
570 * @implemented NT4
571 *
572 * the CsrSetCallingSpooler routine is deprecated.
573 *
574 * @param Reserved
575 * Deprecated
576 *
577 * @return None.
578 *
579 * @remarks This routine was used in archaic versions of NT for Printer Drivers.
580 *
581 *--*/
582 VOID
583 NTAPI
584 CsrSetCallingSpooler(ULONG Reserved)
585 {
586 /* Deprecated */
587 return;
588 }
589
590 /*++
591 * @name CsrUnhandledExceptionFilter
592 * @implemented NT5
593 *
594 * The CsrUnhandledExceptionFilter routine handles all exceptions
595 * within SEH-protected blocks.
596 *
597 * @param ExceptionPointers
598 * System-defined Argument.
599 *
600 * @return EXCEPTION_EXECUTE_HANDLER.
601 *
602 * @remarks None.
603 *
604 *--*/
605 EXCEPTION_DISPOSITION
606 NTAPI
607 CsrUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo)
608 {
609 SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo;
610 EXCEPTION_DISPOSITION Result = EXCEPTION_EXECUTE_HANDLER;
611 BOOLEAN OldValue;
612 NTSTATUS Status;
613 UNICODE_STRING ErrorSource;
614 ULONG_PTR ErrorParameters[4];
615 ULONG Response;
616
617 /* Check if a debugger is installed */
618 Status = NtQuerySystemInformation(SystemKernelDebuggerInformation,
619 &DebuggerInfo,
620 sizeof(DebuggerInfo),
621 NULL);
622
623 /* Check if this is Session 0, and the Debugger is Enabled */
624 if ((NtCurrentPeb()->SessionId) && (NT_SUCCESS(Status)) &&
625 (DebuggerInfo.KernelDebuggerEnabled))
626 {
627 /* Call the Unhandled Exception Filter */
628 if ((Result = RtlUnhandledExceptionFilter(ExceptionInfo)) !=
629 EXCEPTION_CONTINUE_EXECUTION)
630 {
631 /* We're going to raise an error. Get Shutdown Privilege first */
632 Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
633 TRUE,
634 TRUE,
635 &OldValue);
636
637 /* Use the Process token if that failed */
638 if (Status == STATUS_NO_TOKEN)
639 {
640 Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
641 TRUE,
642 FALSE,
643 &OldValue);
644 }
645
646 /* Initialize our Name String */
647 RtlInitUnicodeString(&ErrorSource, L"Windows SubSystem");
648
649 /* Set the parameters */
650 ErrorParameters[0] = (ULONG_PTR)&ErrorSource;
651 ErrorParameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode;
652 ErrorParameters[2] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress;
653 ErrorParameters[3] = (ULONG_PTR)ExceptionInfo->ContextRecord;
654
655 /* Bugcheck */
656 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
657 4,
658 1,
659 ErrorParameters,
660 OptionShutdownSystem,
661 &Response);
662 }
663
664 /* Just terminate us */
665 NtTerminateProcess(NtCurrentProcess(),
666 ExceptionInfo->ExceptionRecord->ExceptionCode);
667 }
668
669 return Result;
670 }
671
672 /* EOF */