Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensmss.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Windows-Compatible Session Manager 00003 * LICENSE: BSD 2-Clause License 00004 * FILE: base/system/smss/smss.c 00005 * PURPOSE: Main SMSS Code 00006 * PROGRAMMERS: Alex Ionescu 00007 */ 00008 00009 /* INCLUDES *******************************************************************/ 00010 00011 #include "smss.h" 00012 #define NDEBUG 00013 #include "debug.h" 00014 00015 /* GLOBALS ********************************************************************/ 00016 00017 UNICODE_STRING SmpSystemRoot; 00018 ULONG AttachedSessionId = -1; 00019 BOOLEAN SmpDebug, SmpEnableDots; 00020 HANDLE SmApiPort; 00021 HANDLE SmpInitialCommandProcessId; 00022 00023 /* FUNCTIONS ******************************************************************/ 00024 00025 /* GCC's incompetence strikes again */ 00026 VOID 00027 sprintf_nt(IN PCHAR Buffer, 00028 IN PCHAR Format, 00029 IN ...) 00030 { 00031 va_list ap; 00032 va_start(ap, Format); 00033 sprintf(Buffer, Format, ap); 00034 va_end(ap); 00035 } 00036 00037 NTSTATUS 00038 NTAPI 00039 SmpExecuteImage(IN PUNICODE_STRING FileName, 00040 IN PUNICODE_STRING Directory, 00041 IN PUNICODE_STRING CommandLine, 00042 IN ULONG MuSessionId, 00043 IN ULONG Flags, 00044 IN PRTL_USER_PROCESS_INFORMATION ProcessInformation) 00045 { 00046 PRTL_USER_PROCESS_INFORMATION ProcessInfo; 00047 NTSTATUS Status; 00048 RTL_USER_PROCESS_INFORMATION LocalProcessInfo; 00049 PRTL_USER_PROCESS_PARAMETERS ProcessParameters; 00050 00051 /* Use the input process information if we have it, otherwise use local */ 00052 ProcessInfo = ProcessInformation; 00053 if (!ProcessInfo) ProcessInfo = &LocalProcessInfo; 00054 00055 /* Create parameters for the target process */ 00056 Status = RtlCreateProcessParameters(&ProcessParameters, 00057 FileName, 00058 SmpDefaultLibPath.Length ? 00059 &SmpDefaultLibPath : NULL, 00060 Directory, 00061 CommandLine, 00062 SmpDefaultEnvironment, 00063 NULL, 00064 NULL, 00065 NULL, 00066 0); 00067 if (!NT_SUCCESS(Status)) 00068 { 00069 /* This is a pretty bad failure. ASSERT on checked builds and exit */ 00070 ASSERTMSG(NT_SUCCESS(Status), "RtlCreateProcessParameters"); 00071 DPRINT1("SMSS: RtlCreateProcessParameters failed for %wZ - Status == %lx\n", 00072 FileName, Status); 00073 return Status; 00074 } 00075 00076 /* Set the size field as required */ 00077 ProcessInfo->Size = sizeof(RTL_USER_PROCESS_INFORMATION); 00078 00079 /* Check if the debug flag was requested */ 00080 if (Flags & SMP_DEBUG_FLAG) 00081 { 00082 /* Write it in the process parameters */ 00083 ProcessParameters->DebugFlags = 1; 00084 } 00085 else 00086 { 00087 /* Otherwise inherit the flag that was passed to SMSS itself */ 00088 ProcessParameters->DebugFlags = SmpDebug; 00089 } 00090 00091 /* Subsystems get the first 1MB of memory reserved for DOS/IVT purposes */ 00092 if (Flags & SMP_SUBSYSTEM_FLAG) 00093 { 00094 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB; 00095 } 00096 00097 /* And always force NX for anything that SMSS launches */ 00098 ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_NX; 00099 00100 /* Now create the process */ 00101 Status = RtlCreateUserProcess(FileName, 00102 OBJ_CASE_INSENSITIVE, 00103 ProcessParameters, 00104 NULL, 00105 NULL, 00106 NULL, 00107 FALSE, 00108 NULL, 00109 NULL, 00110 ProcessInfo); 00111 RtlDestroyProcessParameters(ProcessParameters); 00112 if (!NT_SUCCESS(Status)) 00113 { 00114 /* If we couldn't create it, fail back to the caller */ 00115 DPRINT1("SMSS: Failed load of %wZ - Status == %lx\n", 00116 FileName, Status); 00117 return Status; 00118 } 00119 00120 /* Associate a session with this process */ 00121 Status = SmpSetProcessMuSessionId(ProcessInfo->ProcessHandle, MuSessionId); 00122 00123 /* If the application is deferred (suspended), there's nothing to do */ 00124 if (Flags & SMP_DEFERRED_FLAG) return Status; 00125 00126 /* Otherwise, get ready to start it, but make sure it's a native app */ 00127 if (ProcessInfo->ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE) 00128 { 00129 /* Resume it */ 00130 NtResumeThread(ProcessInfo->ThreadHandle, NULL); 00131 if (!(Flags & SMP_ASYNC_FLAG)) 00132 { 00133 /* Block on it unless Async was requested */ 00134 NtWaitForSingleObject(ProcessInfo->ThreadHandle, FALSE, NULL); 00135 } 00136 00137 /* It's up and running now, close our handles */ 00138 NtClose(ProcessInfo->ThreadHandle); 00139 NtClose(ProcessInfo->ProcessHandle); 00140 } 00141 else 00142 { 00143 /* This image is invalid, so kill it, close our handles, and fail */ 00144 Status = STATUS_INVALID_IMAGE_FORMAT; 00145 NtTerminateProcess(ProcessInfo->ProcessHandle, Status); 00146 NtWaitForSingleObject(ProcessInfo->ThreadHandle, 0, 0); 00147 NtClose(ProcessInfo->ThreadHandle); 00148 NtClose(ProcessInfo->ProcessHandle); 00149 DPRINT1("SMSS: Not an NT image - %wZ\n", FileName); 00150 } 00151 00152 /* Return the outcome of the process create */ 00153 return Status; 00154 } 00155 00156 NTSTATUS 00157 NTAPI 00158 SmpInvokeAutoChk(IN PUNICODE_STRING FileName, 00159 IN PUNICODE_STRING Directory, 00160 IN PUNICODE_STRING Arguments, 00161 IN ULONG Flags) 00162 { 00163 ANSI_STRING DestinationString; 00164 CHAR SourceString[256]; 00165 UNICODE_STRING Destination; 00166 WCHAR Buffer[1024]; 00167 BOOLEAN BootState, BootOkay, ShutdownOkay; 00168 00169 /* Check if autochk should show dots (if the user booted with /SOS) */ 00170 if (SmpQueryRegistrySosOption()) SmpEnableDots = FALSE; 00171 00172 /* Make sure autochk was actually found */ 00173 if (Flags & SMP_INVALID_PATH) 00174 { 00175 /* It wasn't, so create an error message to print on the screen */ 00176 sprintf_nt(SourceString, 00177 "%wZ program not found - skipping AUTOCHECK\n", 00178 FileName); 00179 RtlInitAnsiString(&DestinationString, SourceString); 00180 if (RtlAnsiStringToUnicodeString(&Destination, 00181 &DestinationString, 00182 TRUE)) 00183 { 00184 /* And show it */ 00185 NtDisplayString(&Destination); 00186 RtlFreeUnicodeString(&Destination); 00187 } 00188 } 00189 else 00190 { 00191 /* Autochk is there, so record the BSD state */ 00192 BootState = SmpSaveAndClearBootStatusData(&BootOkay, &ShutdownOkay); 00193 00194 /* Build the path to autochk and place its arguments */ 00195 RtlInitEmptyUnicodeString(&Destination, Buffer, sizeof(Buffer)); 00196 RtlAppendUnicodeStringToString(&Destination, FileName); 00197 RtlAppendUnicodeToString(&Destination, L" "); 00198 RtlAppendUnicodeStringToString(&Destination, Arguments); 00199 00200 /* Execute it */ 00201 SmpExecuteImage(FileName, 00202 Directory, 00203 &Destination, 00204 0, 00205 Flags & ~SMP_AUTOCHK_FLAG, 00206 NULL); 00207 00208 /* Restore the BSD state */ 00209 if (BootState) SmpRestoreBootStatusData(BootOkay, ShutdownOkay); 00210 } 00211 00212 /* We're all done! */ 00213 return STATUS_SUCCESS; 00214 } 00215 00216 NTSTATUS 00217 NTAPI 00218 SmpExecuteCommand(IN PUNICODE_STRING CommandLine, 00219 IN ULONG MuSessionId, 00220 OUT PHANDLE ProcessId, 00221 IN ULONG Flags) 00222 { 00223 NTSTATUS Status; 00224 UNICODE_STRING Arguments, Directory, FileName; 00225 00226 /* There's no longer a debugging subsystem */ 00227 if (Flags & SMP_DEBUG_FLAG) return STATUS_SUCCESS; 00228 00229 /* Parse the command line to see what execution flags are requested */ 00230 Status = SmpParseCommandLine(CommandLine, 00231 &Flags, 00232 &FileName, 00233 &Directory, 00234 &Arguments); 00235 if (!NT_SUCCESS(Status)) 00236 { 00237 /* Fail if we couldn't do that */ 00238 DPRINT1("SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n", 00239 CommandLine, Status); 00240 return Status; 00241 } 00242 00243 /* Check if autochk is requested */ 00244 if (Flags & SMP_AUTOCHK_FLAG) 00245 { 00246 /* Run it */ 00247 Status = SmpInvokeAutoChk(&FileName, &Directory, &Arguments, Flags); 00248 } 00249 else if (Flags & SMP_SUBSYSTEM_FLAG) 00250 { 00251 Status = SmpLoadSubSystem(&FileName, 00252 &Directory, 00253 CommandLine, 00254 MuSessionId, 00255 ProcessId, 00256 Flags); 00257 } 00258 else if (Flags & SMP_INVALID_PATH) 00259 { 00260 /* An invalid image was specified, fail */ 00261 DPRINT1("SMSS: Image file (%wZ) not found\n", &FileName); 00262 Status = STATUS_OBJECT_NAME_NOT_FOUND; 00263 } 00264 else 00265 { 00266 /* An actual image name was present -- execute it */ 00267 Status = SmpExecuteImage(&FileName, 00268 &Directory, 00269 CommandLine, 00270 MuSessionId, 00271 Flags, 00272 NULL); 00273 } 00274 00275 /* Free all the token parameters */ 00276 if (FileName.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, FileName.Buffer); 00277 if (Directory.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Directory.Buffer); 00278 if (Arguments.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Arguments.Buffer); 00279 00280 /* Return to the caller */ 00281 if (!NT_SUCCESS(Status)) 00282 { 00283 DPRINT1("SMSS: Command '%wZ' failed - Status == %x\n", 00284 CommandLine, Status); 00285 } 00286 return Status; 00287 } 00288 00289 NTSTATUS 00290 NTAPI 00291 SmpExecuteInitialCommand(IN ULONG MuSessionId, 00292 IN PUNICODE_STRING InitialCommand, 00293 IN HANDLE InitialCommandProcess, 00294 OUT PHANDLE ReturnPid) 00295 { 00296 NTSTATUS Status; 00297 RTL_USER_PROCESS_INFORMATION ProcessInfo; 00298 UNICODE_STRING Arguments, ImageFileDirectory, ImageFileName; 00299 ULONG Flags = 0; 00300 00301 /* Check if we haven't yet connected to ourselves */ 00302 if (!SmApiPort) 00303 { 00304 /* Connect to ourselves, as a client */ 00305 Status = SmConnectToSm(0, 0, 0, &SmApiPort); 00306 if (!NT_SUCCESS(Status)) 00307 { 00308 DPRINT1("SMSS: Unable to connect to SM - Status == %lx\n", Status); 00309 return Status; 00310 } 00311 } 00312 00313 /* Parse the initial command line */ 00314 Status = SmpParseCommandLine(InitialCommand, 00315 (PULONG)&Flags, 00316 &ImageFileName, 00317 &ImageFileDirectory, 00318 &Arguments); 00319 if (Flags & SMP_INVALID_PATH) 00320 { 00321 /* Fail if it doesn't exist */ 00322 DPRINT1("SMSS: Initial command image (%wZ) not found\n", &ImageFileName); 00323 if (ImageFileName.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileName.Buffer); 00324 return STATUS_OBJECT_NAME_NOT_FOUND; 00325 } 00326 00327 /* And fail if any other reason is also true */ 00328 if (!NT_SUCCESS(Status)) 00329 { 00330 DPRINT1("SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n", 00331 InitialCommand, Status); 00332 return Status; 00333 } 00334 00335 /* Execute the initial command -- but defer its full execution */ 00336 Status = SmpExecuteImage(&ImageFileName, 00337 &ImageFileDirectory, 00338 InitialCommand, 00339 MuSessionId, 00340 SMP_DEFERRED_FLAG, 00341 &ProcessInfo); 00342 00343 /* Free any buffers we had lying around */ 00344 if (ImageFileName.Buffer) 00345 { 00346 RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileName.Buffer); 00347 } 00348 if (ImageFileDirectory.Buffer) 00349 { 00350 RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileDirectory.Buffer); 00351 } 00352 if (Arguments.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Arguments.Buffer); 00353 00354 /* Bail out if we couldn't execute the initial command */ 00355 if (!NT_SUCCESS(Status)) return Status; 00356 00357 /* Now duplicate the handle to this process */ 00358 Status = NtDuplicateObject(NtCurrentProcess(), 00359 ProcessInfo.ProcessHandle, 00360 NtCurrentProcess(), 00361 InitialCommandProcess, 00362 PROCESS_ALL_ACCESS, 00363 0, 00364 0); 00365 if (!NT_SUCCESS(Status)) 00366 { 00367 /* Kill it utterly if duplication failed */ 00368 DPRINT1("SMSS: DupObject Failed. Status == %lx\n", Status); 00369 NtTerminateProcess(ProcessInfo.ProcessHandle, Status); 00370 NtResumeThread(ProcessInfo.ThreadHandle, NULL); 00371 NtClose(ProcessInfo.ThreadHandle); 00372 NtClose(ProcessInfo.ProcessHandle); 00373 return Status; 00374 } 00375 00376 /* Return PID to the caller, and set this as the initial command PID */ 00377 if (ReturnPid) *ReturnPid = ProcessInfo.ClientId.UniqueProcess; 00378 if (!MuSessionId) SmpInitialCommandProcessId = ProcessInfo.ClientId.UniqueProcess; 00379 00380 /* Now call our server execution function to wrap up its initialization */ 00381 Status = SmExecPgm(SmApiPort, &ProcessInfo, FALSE); 00382 if (!NT_SUCCESS(Status)) DPRINT1("SMSS: SmExecPgm Failed. Status == %lx\n", Status); 00383 return Status; 00384 } 00385 00386 NTSTATUS 00387 NTAPI 00388 SmpTerminate(IN PULONG_PTR Parameters, 00389 IN ULONG ParameterMask, 00390 IN ULONG ParameterCount) 00391 { 00392 NTSTATUS Status; 00393 BOOLEAN Old; 00394 ULONG Response; 00395 00396 /* Give the shutdown privilege to the thread */ 00397 if (RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, TRUE, &Old) == 00398 STATUS_NO_TOKEN) 00399 { 00400 /* Thread doesn't have a token, give it to the entire process */ 00401 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old); 00402 } 00403 00404 /* Take down the process/machine with a hard error */ 00405 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 00406 ParameterCount, 00407 ParameterMask, 00408 Parameters, 00409 OptionShutdownSystem, 00410 &Response); 00411 00412 /* Terminate the process if the hard error didn't already */ 00413 return NtTerminateProcess(NtCurrentProcess(), Status); 00414 } 00415 00416 LONG 00417 SmpUnhandledExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo) 00418 { 00419 ULONG_PTR Parameters[4]; 00420 UNICODE_STRING DestinationString; 00421 00422 /* Print and breakpoint into the debugger */ 00423 DbgPrint("SMSS: Unhandled exception - Status == %x IP == %x\n", 00424 ExceptionInfo->ExceptionRecord->ExceptionCode, 00425 ExceptionInfo->ExceptionRecord->ExceptionAddress); 00426 DbgPrint(" Memory Address: %x Read/Write: %x\n", 00427 ExceptionInfo->ExceptionRecord->ExceptionInformation[0], 00428 ExceptionInfo->ExceptionRecord->ExceptionInformation[1]); 00429 DbgBreakPoint(); 00430 00431 /* Build the hard error and terminate */ 00432 RtlInitUnicodeString(&DestinationString, L"Unhandled Exception in Session Manager"); 00433 Parameters[0] = (ULONG_PTR)&DestinationString; 00434 Parameters[1] = ExceptionInfo->ExceptionRecord->ExceptionCode; 00435 Parameters[2] = (ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress; 00436 Parameters[3] = (ULONG_PTR)ExceptionInfo->ContextRecord; 00437 SmpTerminate(Parameters, 1, RTL_NUMBER_OF(Parameters)); 00438 00439 /* We hould never get here */ 00440 ASSERT(FALSE); 00441 return EXCEPTION_EXECUTE_HANDLER; 00442 } 00443 00444 NTSTATUS 00445 _main(IN INT argc, 00446 IN PCHAR argv[], 00447 IN PCHAR envp[], 00448 IN ULONG DebugFlag) 00449 { 00450 NTSTATUS Status; 00451 KPRIORITY SetBasePriority; 00452 ULONG_PTR Parameters[4]; 00453 HANDLE Handles[2]; 00454 PVOID State; 00455 ULONG Flags; 00456 PROCESS_BASIC_INFORMATION ProcessInfo; 00457 UNICODE_STRING DbgString, InitialCommand; 00458 00459 /* Make us critical */ 00460 RtlSetProcessIsCritical(TRUE, NULL, FALSE); 00461 RtlSetThreadIsCritical(TRUE, NULL, FALSE); 00462 00463 /* Raise our priority */ 00464 SetBasePriority = 11; 00465 Status = NtSetInformationProcess(NtCurrentProcess(), 00466 ProcessBasePriority, 00467 (PVOID)&SetBasePriority, 00468 sizeof(SetBasePriority)); 00469 ASSERT(NT_SUCCESS(Status)); 00470 00471 /* Save the debug flag if it was passed */ 00472 if (DebugFlag) SmpDebug = DebugFlag; 00473 00474 /* Build the hard error parameters */ 00475 Parameters[0] = (ULONG_PTR)&DbgString; 00476 Parameters[1] = Parameters[2] = Parameters[3] = 0; 00477 00478 /* Enter SEH so we can terminate correctly if anything goes wrong */ 00479 _SEH2_TRY 00480 { 00481 /* Initialize SMSS */ 00482 Status = SmpInit(&InitialCommand, Handles); 00483 if (!NT_SUCCESS(Status)) 00484 { 00485 DPRINT1("SMSS: SmpInit return failure - Status == %x\n", Status); 00486 RtlInitUnicodeString(&DbgString, L"Session Manager Initialization"); 00487 Parameters[1] = Status; 00488 _SEH2_LEAVE; 00489 } 00490 00491 /* Get the global flags */ 00492 Status = NtQuerySystemInformation(SystemFlagsInformation, 00493 &Flags, 00494 sizeof(Flags), 00495 NULL); 00496 ASSERT(NT_SUCCESS(Status)); 00497 00498 /* Before executing the initial command check if the debug flag is on */ 00499 if (Flags & (FLG_DEBUG_INITIAL_COMMAND | FLG_DEBUG_INITIAL_COMMAND_EX)) 00500 { 00501 /* SMSS should launch ntsd with a few parameters at this point */ 00502 DPRINT1("Global Flags Set to SMSS Debugging: Not yet supported\n"); 00503 } 00504 00505 /* Execute the initial command (Winlogon.exe) */ 00506 Status = SmpExecuteInitialCommand(0, &InitialCommand, &Handles[1], NULL); 00507 if (!NT_SUCCESS(Status)) 00508 { 00509 /* Fail and raise a hard error */ 00510 DPRINT1("SMSS: Execute Initial Command failed\n"); 00511 RtlInitUnicodeString(&DbgString, 00512 L"Session Manager ExecuteInitialCommand"); 00513 Parameters[1] = Status; 00514 _SEH2_LEAVE; 00515 } 00516 00517 /* Check if we're already attached to a session */ 00518 Status = SmpAcquirePrivilege(SE_LOAD_DRIVER_PRIVILEGE, &State); 00519 if (AttachedSessionId != -1) 00520 { 00521 /* Detach from it, we should be in no session right now */ 00522 Status = NtSetSystemInformation(SystemSessionDetach, 00523 &AttachedSessionId, 00524 sizeof(AttachedSessionId)); 00525 ASSERT(NT_SUCCESS(Status)); 00526 AttachedSessionId = -1; 00527 } 00528 SmpReleasePrivilege(State); 00529 00530 /* Wait on either CSRSS or Winlogon to die */ 00531 Status = NtWaitForMultipleObjects(RTL_NUMBER_OF(Handles), 00532 Handles, 00533 WaitAny, 00534 FALSE, 00535 NULL); 00536 if (Status == STATUS_WAIT_0) 00537 { 00538 /* CSRSS is dead, get exit code and prepare for the hard error */ 00539 RtlInitUnicodeString(&DbgString, L"Windows SubSystem"); 00540 Status = NtQueryInformationProcess(Handles[0], 00541 ProcessBasicInformation, 00542 &ProcessInfo, 00543 sizeof(ProcessInfo), 00544 NULL); 00545 DPRINT1("SMSS: Windows subsystem terminated when it wasn't supposed to.\n"); 00546 } 00547 else 00548 { 00549 /* The initial command is dead or we have another failure */ 00550 RtlInitUnicodeString(&DbgString, L"Windows Logon Process"); 00551 if (Status == STATUS_WAIT_1) 00552 { 00553 /* Winlogon.exe got terminated, get its exit code */ 00554 Status = NtQueryInformationProcess(Handles[1], 00555 ProcessBasicInformation, 00556 &ProcessInfo, 00557 sizeof(ProcessInfo), 00558 NULL); 00559 } 00560 else 00561 { 00562 /* Something else satisfied our wait, so set the wait status */ 00563 ProcessInfo.ExitStatus = Status; 00564 Status = STATUS_SUCCESS; 00565 } 00566 DPRINT1("SMSS: Initial command '%wZ' terminated when it wasn't supposed to.\n", 00567 &InitialCommand); 00568 } 00569 00570 /* Check if NtQueryInformationProcess was successful */ 00571 if (NT_SUCCESS(Status)) 00572 { 00573 /* Then we must have a valid exit status in the structure, use it */ 00574 Parameters[1] = ProcessInfo.ExitStatus; 00575 } 00576 else 00577 { 00578 /* We really don't know what happened, so set a generic error */ 00579 Parameters[1] = STATUS_UNSUCCESSFUL; 00580 } 00581 } 00582 _SEH2_EXCEPT(SmpUnhandledExceptionFilter(_SEH2_GetExceptionInformation())) 00583 { 00584 /* The filter should never return here */ 00585 ASSERT(FALSE); 00586 } 00587 _SEH2_END; 00588 00589 /* Something in the init loop failed, terminate SMSS */ 00590 return SmpTerminate(Parameters, 1, RTL_NUMBER_OF(Parameters)); 00591 } 00592 00593 /* EOF */ Generated on Sat May 26 2012 04:17:45 for ReactOS by
1.7.6.1
|