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