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