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