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 *--*/ 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 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 *--*/ 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 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 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 *--*/ 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 *--*/ 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 *--*/ 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 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 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