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