[CSR]
[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_SERVER_DLL CsrLoadedServerDll[CSR_SERVER_DLL_MAX];
19 PVOID CsrSrvSharedSectionHeap = NULL;
20 PVOID CsrSrvSharedSectionBase = NULL;
21 PVOID *CsrSrvSharedStaticServerData = NULL;
22 ULONG CsrSrvSharedSectionSize = 0;
23 HANDLE CsrSrvSharedSection = NULL;
24
25 PCSR_API_ROUTINE CsrServerApiDispatchTable[CsrpMaxApiNumber] =
26 {
27 CsrSrvClientConnect,
28 CsrSrvUnusedFunction,
29 CsrSrvUnusedFunction,
30 CsrSrvIdentifyAlertableThread,
31 CsrSrvSetPriorityClass
32 };
33
34 BOOLEAN CsrServerApiServerValidTable[CsrpMaxApiNumber] =
35 {
36 TRUE,
37 FALSE,
38 TRUE,
39 TRUE,
40 TRUE
41 };
42
43 /*
44 * On Windows Server 2003, CSR Servers contain
45 * the API Names Table only in Debug Builds.
46 */
47 #ifdef CSR_DBG
48 PCHAR CsrServerApiNameTable[CsrpMaxApiNumber] =
49 {
50 "ClientConnect",
51 "ThreadConnect",
52 "ProfileControl",
53 "IdentifyAlertableThread",
54 "SetPriorityClass"
55 };
56 #endif
57
58 /* PRIVATE FUNCTIONS **********************************************************/
59
60 /*++
61 * @name CsrServerDllInitialization
62 * @implemented NT4
63 *
64 * The CsrServerDllInitialization is the initialization routine
65 * for this Server DLL.
66 *
67 * @param LoadedServerDll
68 * Pointer to the CSR Server DLL structure representing this Server DLL.
69 *
70 * @return STATUS_SUCCESS.
71 *
72 * @remarks None.
73 *
74 *--*/
75 CSR_SERVER_DLL_INIT(CsrServerDllInitialization)
76 {
77 /* Setup the DLL Object */
78 LoadedServerDll->ApiBase = CSRSRV_FIRST_API_NUMBER;
79 LoadedServerDll->HighestApiSupported = CsrpMaxApiNumber;
80 LoadedServerDll->DispatchTable = CsrServerApiDispatchTable;
81 LoadedServerDll->ValidTable = CsrServerApiServerValidTable;
82 #ifdef CSR_DBG
83 LoadedServerDll->NameTable = CsrServerApiNameTable;
84 #endif
85 LoadedServerDll->SizeOfProcessData = 0;
86 LoadedServerDll->ConnectCallback = NULL;
87 LoadedServerDll->DisconnectCallback = NULL;
88
89 /* All done */
90 return STATUS_SUCCESS;
91 }
92
93 /*++
94 * @name CsrLoadServerDll
95 * @implemented NT4
96 *
97 * The CsrLoadServerDll routine loads a CSR Server DLL and calls its entrypoint.
98 *
99 * @param DllString
100 * Pointer to the CSR Server DLL to load and call.
101 *
102 * @param EntryPoint
103 * Pointer to the name of the server's initialization function.
104 * If this parameter is NULL, the default ServerDllInitialize
105 * will be assumed.
106 *
107 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
108 *
109 * @remarks None.
110 *
111 *--*/
112 NTSTATUS
113 NTAPI
114 CsrLoadServerDll(IN PCHAR DllString,
115 IN PCHAR EntryPoint OPTIONAL,
116 IN ULONG ServerId)
117 {
118 NTSTATUS Status;
119 ANSI_STRING DllName;
120 UNICODE_STRING TempString, ErrorString;
121 ULONG_PTR Parameters[2];
122 HANDLE hServerDll = NULL;
123 ULONG Size;
124 PCSR_SERVER_DLL ServerDll;
125 STRING EntryPointString;
126 PCSR_SERVER_DLL_INIT_CALLBACK ServerDllInitProcedure;
127 ULONG Response;
128
129 /* Check if it's beyond the maximum we support */
130 if (ServerId >= CSR_SERVER_DLL_MAX) return STATUS_TOO_MANY_NAMES;
131
132 /* Check if it's already been loaded */
133 if (CsrLoadedServerDll[ServerId]) return STATUS_INVALID_PARAMETER;
134
135 /* Convert the name to Unicode */
136 ASSERT(DllString != NULL);
137 RtlInitAnsiString(&DllName, DllString);
138 Status = RtlAnsiStringToUnicodeString(&TempString, &DllName, TRUE);
139 if (!NT_SUCCESS(Status)) return Status;
140
141 /* If we are loading ourselves, don't actually load us */
142 if (ServerId != CSRSRV_SERVERDLL_INDEX)
143 {
144 /* Load the DLL */
145 Status = LdrLoadDll(NULL, 0, &TempString, &hServerDll);
146 if (!NT_SUCCESS(Status))
147 {
148 /* Setup error parameters */
149 Parameters[0] = (ULONG_PTR)&TempString;
150 Parameters[1] = (ULONG_PTR)&ErrorString;
151 RtlInitUnicodeString(&ErrorString, L"Default Load Path");
152
153 /* Send a hard error */
154 NtRaiseHardError(Status,
155 2,
156 3,
157 Parameters,
158 OptionOk,
159 &Response);
160 }
161
162 /* Get rid of the string */
163 RtlFreeUnicodeString(&TempString);
164 if (!NT_SUCCESS(Status)) return Status;
165 }
166
167 /* Allocate a CSR DLL Object */
168 Size = sizeof(CSR_SERVER_DLL) + DllName.MaximumLength;
169 ServerDll = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Size);
170 if (!ServerDll)
171 {
172 if (hServerDll) LdrUnloadDll(hServerDll);
173 return STATUS_NO_MEMORY;
174 }
175
176 /* Set up the Object */
177 ServerDll->Length = Size;
178 ServerDll->SizeOfProcessData = 0;
179 ServerDll->SharedSection = CsrSrvSharedSectionHeap; // Send to the server dll our shared heap pointer.
180 ServerDll->Name.Length = DllName.Length;
181 ServerDll->Name.MaximumLength = DllName.MaximumLength;
182 ServerDll->Name.Buffer = (PCHAR)(ServerDll + 1);
183 if (DllName.Length)
184 {
185 strncpy(ServerDll->Name.Buffer, DllName.Buffer, DllName.Length);
186 }
187 ServerDll->ServerId = ServerId;
188 ServerDll->ServerHandle = hServerDll;
189
190 /* Now get the entrypoint */
191 if (hServerDll)
192 {
193 /* Initialize a string for the entrypoint, or use the default */
194 RtlInitAnsiString(&EntryPointString,
195 EntryPoint ? EntryPoint : "ServerDllInitialization");
196
197 /* Get a pointer to it */
198 Status = LdrGetProcedureAddress(hServerDll,
199 &EntryPointString,
200 0,
201 (PVOID)&ServerDllInitProcedure);
202 }
203 else
204 {
205 /* No handle, so we are loading ourselves */
206 ServerDllInitProcedure = CsrServerDllInitialization;
207 Status = STATUS_SUCCESS;
208 }
209
210 /* Check if we got the pointer, and call it */
211 if (NT_SUCCESS(Status))
212 {
213 /* Get the result from the Server DLL */
214 Status = ServerDllInitProcedure(ServerDll);
215 if (NT_SUCCESS(Status))
216 {
217 /*
218 * Add this Server's Per-Process Data Size to the total that each
219 * process will need.
220 */
221 CsrTotalPerProcessDataLength += ServerDll->SizeOfProcessData;
222
223 /* Save the pointer in our list */
224 CsrLoadedServerDll[ServerDll->ServerId] = ServerDll;
225
226 /* Does it use our generic heap? */
227 if (ServerDll->SharedSection != CsrSrvSharedSectionHeap)
228 {
229 /* No, save the pointer to its shared section in our list */
230 CsrSrvSharedStaticServerData[ServerDll->ServerId] = ServerDll->SharedSection;
231 }
232 }
233 }
234
235 if (!NT_SUCCESS(Status))
236 {
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
320 * CSR Server 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 otherwise.
327 *
328 * @remarks None.
329 *
330 *--*/
331 NTSTATUS
332 NTAPI
333 CsrSrvCreateSharedSection(IN PCHAR ParameterValue)
334 {
335 PCHAR SizeValue = ParameterValue;
336 ULONG Size;
337 NTSTATUS Status;
338 LARGE_INTEGER SectionSize;
339 ULONG ViewSize = 0;
340 PPEB Peb = NtCurrentPeb();
341
342 /* If there's no parameter, fail */
343 if (!ParameterValue) return STATUS_INVALID_PARAMETER;
344
345 /* Find the first comma, and null terminate */
346 while (*SizeValue)
347 {
348 if (*SizeValue == ',')
349 {
350 *SizeValue++ = ANSI_NULL;
351 break;
352 }
353 else
354 {
355 SizeValue++;
356 }
357 }
358
359 /* Make sure it's valid */
360 if (!*SizeValue) return STATUS_INVALID_PARAMETER;
361
362 /* Convert it to an integer */
363 Status = RtlCharToInteger(SizeValue, 0, &Size);
364 if (!NT_SUCCESS(Status)) return Status;
365
366 /* Multiply by 1024 entries and round to page size */
367 CsrSrvSharedSectionSize = ROUND_UP(Size * 1024, CsrNtSysInfo.PageSize);
368
369 /* Create the Secion */
370 SectionSize.LowPart = CsrSrvSharedSectionSize;
371 SectionSize.HighPart = 0;
372 Status = NtCreateSection(&CsrSrvSharedSection,
373 SECTION_ALL_ACCESS,
374 NULL,
375 &SectionSize,
376 PAGE_EXECUTE_READWRITE,
377 SEC_BASED | SEC_RESERVE,
378 NULL);
379 if (!NT_SUCCESS(Status)) return Status;
380
381 /* Map the section */
382 Status = NtMapViewOfSection(CsrSrvSharedSection,
383 NtCurrentProcess(),
384 &CsrSrvSharedSectionBase,
385 0,
386 0,
387 NULL,
388 &ViewSize,
389 ViewUnmap,
390 MEM_TOP_DOWN,
391 PAGE_EXECUTE_READWRITE);
392 if (!NT_SUCCESS(Status))
393 {
394 /* Fail */
395 NtClose(CsrSrvSharedSection);
396 return Status;
397 }
398
399 /* FIXME: Write the value to registry */
400
401 /* The Heap is the same place as the Base */
402 CsrSrvSharedSectionHeap = CsrSrvSharedSectionBase;
403
404 /* Create the heap */
405 if (!(RtlCreateHeap(HEAP_ZERO_MEMORY | HEAP_CLASS_7,
406 CsrSrvSharedSectionHeap,
407 CsrSrvSharedSectionSize,
408 PAGE_SIZE,
409 0,
410 0)))
411 {
412 /* Failure, unmap section and return */
413 NtUnmapViewOfSection(NtCurrentProcess(), CsrSrvSharedSectionBase);
414 NtClose(CsrSrvSharedSection);
415 return STATUS_NO_MEMORY;
416 }
417
418 /* Now allocate space from the heap for the Shared Data */
419 CsrSrvSharedStaticServerData = RtlAllocateHeap(CsrSrvSharedSectionHeap,
420 HEAP_ZERO_MEMORY,
421 CSR_SERVER_DLL_MAX * sizeof(PVOID));
422 if (!CsrSrvSharedStaticServerData) return STATUS_NO_MEMORY;
423
424 /* Write the values to the PEB */
425 Peb->ReadOnlySharedMemoryBase = CsrSrvSharedSectionBase;
426 Peb->ReadOnlySharedMemoryHeap = CsrSrvSharedSectionHeap;
427 Peb->ReadOnlyStaticServerData = CsrSrvSharedStaticServerData;
428
429 /* Return */
430 return STATUS_SUCCESS;
431 }
432
433 /*++
434 * @name CsrSrvAttachSharedSection
435 *
436 * The CsrSrvAttachSharedSection maps the CSR Shared Section into a new
437 * CSR Process' address space, and returns the pointers to the section
438 * through the Connection Info structure.
439 *
440 * @param CsrProcess
441 * Pointer to the CSR Process that is attempting a connection.
442 *
443 * @param ConnectInfo
444 * Pointer to the CSR Connection Info structure for the incoming
445 * connection.
446 *
447 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
448 *
449 * @remarks None.
450 *
451 *--*/
452 NTSTATUS
453 NTAPI
454 CsrSrvAttachSharedSection(IN PCSR_PROCESS CsrProcess OPTIONAL,
455 OUT PCSR_API_CONNECTINFO ConnectInfo)
456 {
457 NTSTATUS Status;
458 ULONG ViewSize = 0;
459
460 /* Check if we have a process */
461 if (CsrProcess)
462 {
463 /* Map the section into this process */
464 Status = NtMapViewOfSection(CsrSrvSharedSection,
465 CsrProcess->ProcessHandle,
466 &CsrSrvSharedSectionBase,
467 0,
468 0,
469 NULL,
470 &ViewSize,
471 ViewUnmap,
472 SEC_NO_CHANGE,
473 PAGE_EXECUTE_READ);
474 if (!NT_SUCCESS(Status)) return Status;
475 }
476
477 /* Write the values in the Connection Info structure */
478 ConnectInfo->SharedSectionBase = CsrSrvSharedSectionBase;
479 ConnectInfo->SharedSectionHeap = CsrSrvSharedSectionHeap;
480 ConnectInfo->SharedStaticServerData = CsrSrvSharedStaticServerData;
481
482 /* Return success */
483 return STATUS_SUCCESS;
484 }
485
486 /*++
487 * @name CsrSrvIdentifyAlertableThread
488 * @implemented NT4
489 *
490 * The CsrSrvIdentifyAlertableThread CSR API marks a CSR Thread as alertable.
491 *
492 * @param ApiMessage
493 * Pointer to the CSR API Message for this request.
494 *
495 * @param ReplyCode
496 * Pointer to an optional reply to this request.
497 *
498 * @return STATUS_SUCCESS.
499 *
500 * @remarks None.
501 *
502 *--*/
503 CSR_API(CsrSrvIdentifyAlertableThread)
504 {
505 PCSR_THREAD CsrThread = CsrGetClientThread();
506
507 /* Set the alertable flag */
508 CsrThread->Flags |= CsrThreadAlertable;
509
510 /* Return success */
511 return STATUS_SUCCESS;
512 }
513
514 /*++
515 * @name CsrSrvSetPriorityClass
516 * @implemented NT4
517 *
518 * The CsrSrvSetPriorityClass CSR API is deprecated.
519 *
520 * @param ApiMessage
521 * Pointer to the CSR API Message for this request.
522 *
523 * @param ReplyCode
524 * Pointer to an optional reply to this request.
525 *
526 * @return STATUS_SUCCESS.
527 *
528 * @remarks None.
529 *
530 *--*/
531 CSR_API(CsrSrvSetPriorityClass)
532 {
533 /* Deprecated */
534 return STATUS_SUCCESS;
535 }
536
537 /*++
538 * @name CsrSrvUnusedFunction
539 * @implemented NT4
540 *
541 * The CsrSrvUnusedFunction CSR API is a stub for deprecated APIs.
542 *
543 * The CsrSrvSetPriorityClass CSR API is deprecated.
544 *
545 * @param ApiMessage
546 * Pointer to the CSR API Message for this request.
547 *
548 * @param ReplyCode
549 * Pointer to an optional reply to this request.
550 *
551 * @return STATUS_INVALID_PARAMETER.
552 *
553 * @remarks CsrSrvSetPriorityClass does not use this stub because
554 * it must return success.
555 *
556 *--*/
557 CSR_API(CsrSrvUnusedFunction)
558 {
559 /* Deprecated */
560 return STATUS_INVALID_PARAMETER;
561 }
562
563 /* PUBLIC FUNCTIONS ***********************************************************/
564
565 /*++
566 * @name CsrSetCallingSpooler
567 * @implemented NT4
568 *
569 * the CsrSetCallingSpooler routine is deprecated.
570 *
571 * @param Reserved
572 * Deprecated
573 *
574 * @return None.
575 *
576 * @remarks This routine was used in archaic versions of NT for Printer Drivers.
577 *
578 *--*/
579 VOID
580 NTAPI
581 CsrSetCallingSpooler(ULONG Reserved)
582 {
583 /* Deprecated */
584 return;
585 }
586
587 /*++
588 * @name CsrUnhandledExceptionFilter
589 * @implemented NT5
590 *
591 * The CsrUnhandledExceptionFilter routine handles all exceptions
592 * within SEH-protected blocks.
593 *
594 * @param ExceptionPointers
595 * System-defined Argument.
596 *
597 * @return EXCEPTION_EXECUTE_HANDLER.
598 *
599 * @remarks None.
600 *
601 *--*/
602 EXCEPTION_DISPOSITION
603 NTAPI
604 CsrUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo)
605 {
606 SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo;
607 EXCEPTION_DISPOSITION Result = EXCEPTION_EXECUTE_HANDLER;
608 BOOLEAN OldValue;
609 NTSTATUS Status;
610 UNICODE_STRING ErrorSource;
611 ULONG_PTR ErrorParameters[4];
612 ULONG Response;
613
614 DPRINT1("CsrUnhandledExceptionFilter called\n");
615
616 /* Check if a debugger is installed */
617 Status = NtQuerySystemInformation(SystemKernelDebuggerInformation,
618 &DebuggerInfo,
619 sizeof(DebuggerInfo),
620 NULL);
621
622 /* Check if this is Session 0, and the Debugger is Enabled */
623 if ((NtCurrentPeb()->SessionId != 0) && (NT_SUCCESS(Status)) &&
624 (DebuggerInfo.KernelDebuggerEnabled))
625 {
626 /* Call the Unhandled Exception Filter */
627 Result = RtlUnhandledExceptionFilter(ExceptionInfo);
628 if (Result != EXCEPTION_CONTINUE_EXECUTION)
629 {
630 /* We're going to raise an error. Get Shutdown Privilege first */
631 Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
632 TRUE,
633 TRUE,
634 &OldValue);
635
636 /* Use the Process token if that failed */
637 if (Status == STATUS_NO_TOKEN)
638 {
639 Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
640 TRUE,
641 FALSE,
642 &OldValue);
643 }
644
645 /* Initialize our Name String */
646 RtlInitUnicodeString(&ErrorSource, L"Windows SubSystem");
647
648 /* Set the parameters */
649 ErrorParameters[0] = (ULONG_PTR)&ErrorSource;
650 ErrorParameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode;
651 ErrorParameters[2] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress;
652 ErrorParameters[3] = (ULONG_PTR)ExceptionInfo->ContextRecord;
653
654 /* Bugcheck */
655 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
656 4,
657 1,
658 ErrorParameters,
659 OptionShutdownSystem,
660 &Response);
661 }
662
663 /* Just terminate us */
664 NtTerminateProcess(NtCurrentProcess(),
665 ExceptionInfo->ExceptionRecord->ExceptionCode);
666 }
667
668 return Result;
669 }
670
671 /* EOF */