3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/winlogon/winlogon.c
7 * PROGRAMMER: David Welch (welch@cwcom.net)
12 /* INCLUDES *****************************************************************/
18 #define SUPPORT_CONSOLESTART 1
21 /* GLOBALS ******************************************************************/
24 LoadGina(PMSGINAFUNCTIONS Functions
, DWORD
*DllVersion
);
28 SessionLoop(PWLSESSION Session
);
32 WlxCreateWindowStationAndDesktops(PWLSESSION Session
);
34 HINSTANCE hAppInstance
;
35 PWLSESSION WLSession
= NULL
;
37 #if SUPPORT_CONSOLESTART
38 BOOL StartConsole
= TRUE
;
41 /* FUNCTIONS *****************************************************************/
44 PrintString (WCHAR
* fmt
,...)
50 wsprintf(buffer
, fmt
, ap
);
53 OutputDebugString(buffer
);
58 ShutdownComputerProc (HWND hwndDlg
,
67 switch(LOWORD(wParam
))
69 case IDC_BTNSHTDOWNCOMPUTER
:
70 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
77 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
78 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
88 HANDLE ServicesInitEvent
;
90 STARTUPINFO StartupInfo
;
91 PROCESS_INFORMATION ProcessInformation
;
93 WCHAR ServiceString
[] = L
"services.exe";
95 /* Start the service control manager (services.exe) */
97 StartupInfo
.cb
= sizeof(StartupInfo
);
98 StartupInfo
.lpReserved
= NULL
;
99 StartupInfo
.lpDesktop
= NULL
;
100 StartupInfo
.lpTitle
= NULL
;
101 StartupInfo
.dwFlags
= 0;
102 StartupInfo
.cbReserved2
= 0;
103 StartupInfo
.lpReserved2
= 0;
106 PrintString(L
"WL: Creating new process - \"services.exe\".\n");
109 Result
= CreateProcess(NULL
,
118 &ProcessInformation
);
121 PrintString(L
"WL: Failed to execute services\n");
125 /* wait for event creation (by SCM) for max. 20 seconds */
126 for (Count
= 0; Count
< 20; Count
++)
130 //DbgPrint("WL: Attempting to open event \"SvcctrlStartEvent_A3725DX\"\n");
131 ServicesInitEvent
= OpenEvent(EVENT_ALL_ACCESS
, //SYNCHRONIZE,
133 L
"SvcctrlStartEvent_A3725DX");
134 if (ServicesInitEvent
!= NULL
)
140 if (ServicesInitEvent
== NULL
)
142 DbgPrint("WL: Failed to open event \"SvcctrlStartEvent_A3725DX\"\n");
146 /* wait for event signalization */
147 //DbgPrint("WL: Waiting forever on event handle: %x\n", ServicesInitEvent);
148 WaitForSingleObject(ServicesInitEvent
, INFINITE
);
149 //DbgPrint("WL: Closing event object \"SvcctrlStartEvent_A3725DX\"\n");
150 CloseHandle(ServicesInitEvent
);
151 //DbgPrint("WL: StartServices() Done.\n");
160 HANDLE LsassInitEvent
;
162 STARTUPINFO StartupInfo
;
163 PROCESS_INFORMATION ProcessInformation
;
165 LsassInitEvent
= CreateEvent(NULL
,
170 if (LsassInitEvent
== NULL
)
172 DbgPrint("WL: Failed to create lsass notification event\n");
176 /* Start the local security authority subsystem (lsass.exe) */
178 StartupInfo
.cb
= sizeof(StartupInfo
);
179 StartupInfo
.lpReserved
= NULL
;
180 StartupInfo
.lpDesktop
= NULL
;
181 StartupInfo
.lpTitle
= NULL
;
182 StartupInfo
.dwFlags
= 0;
183 StartupInfo
.cbReserved2
= 0;
184 StartupInfo
.lpReserved2
= 0;
186 Result
= CreateProcess(L
"lsass.exe",
195 &ProcessInformation
);
198 DbgPrint("WL: Failed to execute lsass\n");
202 DPRINT("WL: Waiting for lsass\n");
203 WaitForSingleObject(LsassInitEvent
, INFINITE
);
204 CloseHandle(LsassInitEvent
);
212 OpenRegistryKey (HKEY
*WinLogonKey
)
214 return ERROR_SUCCESS
== RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
215 L
"SOFTWARE\\ReactOS\\Windows NT\\CurrentVersion\\WinLogon",
222 static BOOLEAN
StartProcess(PWCHAR ValueName
)
231 if (OpenRegistryKey(&WinLogonKey
))
233 Size
= sizeof(DWORD
);
234 if (ERROR_SUCCESS
== RegQueryValueEx(WinLogonKey
,
238 (LPBYTE
) &StartValue
,
241 if (REG_DWORD
== Type
)
243 StartIt
= (0 != StartValue
);
246 RegCloseKey(WinLogonKey
);
253 static BOOL RestartShell(void)
256 DWORD Type, Size, Value;
258 if(OpenRegistryKey(&WinLogonKey))
260 Size = sizeof(DWORD);
261 if(ERROR_SUCCESS == RegQueryValueEx(WinLogonKey,
268 if(Type == REG_DWORD)
270 RegCloseKey(WinLogonKey);
274 RegCloseKey(WinLogonKey);
281 RegisterHotKeys(VOID
)
283 RegisterHotKey(NULL
, 0, MOD_ALT
| MOD_CONTROL
, VK_DELETE
);
287 UnregisterHotKeys(VOID
)
289 UnregisterHotKey(NULL
, 0);
293 HandleHotKey(MSG
*Msg
)
295 DbgPrint("HOTKEY: Got hot key (%d)\n", Msg
->wParam
);
298 if (Msg
->wParam
== 0)
300 STARTUPINFO StartupInfo
;
301 PROCESS_INFORMATION ProcessInformation
;
303 StartupInfo
.cb
= sizeof(StartupInfo
);
304 StartupInfo
.lpReserved
= NULL
;
305 StartupInfo
.lpDesktop
= NULL
;
306 StartupInfo
.lpTitle
= NULL
;
307 StartupInfo
.dwFlags
= 0;
308 StartupInfo
.cbReserved2
= 0;
309 StartupInfo
.lpReserved2
= 0;
317 CREATE_NEW_PROCESS_GROUP
| DETACHED_PROCESS
,
321 &ProcessInformation
);
323 CloseHandle (ProcessInformation
.hProcess
);
324 CloseHandle (ProcessInformation
.hThread
);
328 #if SUPPORT_CONSOLESTART
329 static BOOL
StartIntoGUI(VOID
)
332 DWORD Type
, Size
, Value
;
334 if(OpenRegistryKey(&WinLogonKey
))
336 Size
= sizeof(DWORD
);
337 if(ERROR_SUCCESS
== RegQueryValueEx(WinLogonKey
,
344 if(Type
== REG_DWORD
)
346 RegCloseKey(WinLogonKey
);
350 RegCloseKey(WinLogonKey
);
357 GetUserInit (WCHAR
*CommandLine
)
363 WCHAR Shell
[_MAX_PATH
];
365 GotCommandLine
= FALSE
;
366 if (OpenRegistryKey(&WinLogonKey
))
369 if (ERROR_SUCCESS
== RegQueryValueEx(WinLogonKey
,
376 if (REG_EXPAND_SZ
== Type
)
378 ExpandEnvironmentStrings(Shell
, CommandLine
, _MAX_PATH
);
379 GotCommandLine
= TRUE
;
381 else if (REG_SZ
== Type
)
383 wcscpy(CommandLine
, Shell
);
384 GotCommandLine
= TRUE
;
387 RegCloseKey(WinLogonKey
);
390 if (! GotCommandLine
)
392 GetSystemDirectory(CommandLine
, MAX_PATH
- 15);
393 wcscat(CommandLine
, L
"\\userinit.exe");
401 DoLogonUser (PWCHAR Name
,
404 PROCESS_INFORMATION ProcessInformation
;
405 STARTUPINFO StartupInfo
;
406 WCHAR CommandLine
[MAX_PATH
];
407 WCHAR CurrentDirectory
[MAX_PATH
];
409 PROFILEINFOW ProfileInfo
;
411 LPVOID lpEnvironment
= NULL
;
414 Result
= LogonUserW (Name
,
417 LOGON32_LOGON_INTERACTIVE
,
418 LOGON32_PROVIDER_DEFAULT
,
422 DbgPrint ("WL: LogonUserW() failed\n");
423 RtlDestroyEnvironment (lpEnvironment
);
427 /* Load the user profile */
428 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
429 ProfileInfo
.dwFlags
= 0;
430 ProfileInfo
.lpUserName
= Name
;
431 ProfileInfo
.lpProfilePath
= NULL
;
432 ProfileInfo
.lpDefaultPath
= NULL
;
433 ProfileInfo
.lpServerName
= NULL
;
434 ProfileInfo
.lpPolicyPath
= NULL
;
435 ProfileInfo
.hProfile
= NULL
;
437 if (!LoadUserProfileW (hToken
,
440 DbgPrint ("WL: LoadUserProfileW() failed\n");
441 CloseHandle (hToken
);
442 RtlDestroyEnvironment (lpEnvironment
);
446 if (!CreateEnvironmentBlock (&lpEnvironment
,
450 DbgPrint ("WL: CreateEnvironmentBlock() failed\n");
454 if (ImpersonateLoggedOnUser(hToken
))
456 UpdatePerUserSystemParameters(0, TRUE
);
460 GetWindowsDirectoryW (CurrentDirectory
, MAX_PATH
);
462 StartupInfo
.cb
= sizeof(StartupInfo
);
463 StartupInfo
.lpReserved
= NULL
;
464 StartupInfo
.lpDesktop
= NULL
;
465 StartupInfo
.lpTitle
= NULL
;
466 StartupInfo
.dwFlags
= 0;
467 StartupInfo
.cbReserved2
= 0;
468 StartupInfo
.lpReserved2
= 0;
470 Result
= CreateProcessAsUserW (hToken
,
472 GetUserInit (CommandLine
),
476 CREATE_UNICODE_ENVIRONMENT
,
480 &ProcessInformation
);
483 DbgPrint ("WL: Failed to execute user shell %s\n", CommandLine
);
484 if (ImpersonateLoggedOnUser(hToken
))
486 UpdatePerUserSystemParameters(0, FALSE
);
489 UnloadUserProfile (hToken
,
490 ProfileInfo
.hProfile
);
491 CloseHandle (hToken
);
492 DestroyEnvironmentBlock (lpEnvironment
);
498 while (WaitForSingleObject (ProcessInformation
.hProcess
, 100) != WAIT_OBJECT_0
)
500 if (PeekMessage(&Msg
, 0, 0, 0, PM_REMOVE
))
502 if (Msg
.message
== WM_HOTKEY
)
504 TranslateMessage(&Msg
);
505 DispatchMessage(&Msg
);
511 CloseHandle (ProcessInformation
.hProcess
);
512 CloseHandle (ProcessInformation
.hThread
);
514 if (ImpersonateLoggedOnUser(hToken
))
516 UpdatePerUserSystemParameters(0, FALSE
);
520 /* Unload user profile */
521 UnloadUserProfile (hToken
,
522 ProfileInfo
.hProfile
);
524 CloseHandle (hToken
);
526 RtlDestroyEnvironment (lpEnvironment
);
533 WinMain(HINSTANCE hInstance
,
534 HINSTANCE hPrevInstance
,
538 #if SUPPORT_CONSOLESTART
539 // WCHAR LoginName[255];
540 // WCHAR Password[255];
543 LSA_STRING ProcessName
, PackageName
;
545 LSA_OPERATIONAL_MODE Mode
;
546 ULONG AuthenticationPackage
;
549 hAppInstance
= hInstance
;
551 if(!RegisterLogonProcess(GetCurrentProcessId(), TRUE
))
553 DbgPrint("WL: Could not register logon process\n");
554 NtShutdownSystem(ShutdownNoReboot
);
560 if (StartProcess(L
"StartLsass"))
564 DbgPrint("WL: Failed to start LSASS (0x%X)\n", GetLastError());
569 if(!(WLSession
= MsGinaInit()))
571 DbgPrint("WL: Failed to initialize msgina.dll\n");
572 NtShutdownSystem(ShutdownNoReboot
);
577 WLSession
->LogonStatus
= LOGON_INITIALIZING
;
579 if(!WlxCreateWindowStationAndDesktops(WLSession
))
581 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED
, 0, 0, 0, 0, 0);
587 * Switch to winlogon desktop
589 /* FIXME: Do start up in the application desktop for now. */
590 SetThreadDesktop(WLSession
->ApplicationDesktop
);
591 if(!SwitchDesktop(WLSession
->ApplicationDesktop
))
593 DbgPrint("WL: Cannot switch to Winlogon desktop (0x%X)\n", GetLastError());
596 /* Check for pending setup */
597 if (GetSetupType () != 0)
599 DPRINT ("Winlogon: CheckForSetup() in setup mode\n");
601 /* Run setup and reboot when done */
604 NtShutdownSystem(ShutdownReboot
);
609 #if SUPPORT_CONSOLESTART
610 StartConsole
= !StartIntoGUI();
612 if(!InitializeSAS(WLSession
))
614 DbgPrint("WL: Failed to initialize SAS\n");
622 /* real winlogon uses "Winlogon" */
623 RtlInitUnicodeString((PUNICODE_STRING
)&ProcessName
, L
"Winlogon");
624 Status
= LsaRegisterLogonProcess(&ProcessName
, &LsaHandle
, &Mode
);
625 if (!NT_SUCCESS(Status
))
629 case STATUS_PORT_CONNECTION_REFUSED
:
630 /* FIXME - we don't have the 'SeTcbPrivilege' pivilege, so set it or call
631 LsaAddAccountRights() and try again */
632 DbgPrint("WL: LsaRegisterLogonProcess() returned STATUS_PORT_CONNECTION_REFUSED\n");
634 case STATUS_NAME_TOO_LONG
:
635 DbgPrint("WL: LsaRegisterLogonProcess() returned STATUS_NAME_TOO_LONG\n");
638 DbgPrint("WL: Failed to connect to LSASS\n");
644 RtlInitUnicodeString((PUNICODE_STRING
)&PackageName
, L
"Kerberos");
645 Status
= LsaLookupAuthenticationPackage(LsaHandle
, &PackageName
, &AuthenticationPackage
);
646 if (!NT_SUCCESS(Status
))
648 LsaDeregisterLogonProcess(LsaHandle
);
649 DbgPrint("WL: Failed to lookup authentication package\n");
654 /* FIXME: Create a window class and associate a Winlogon
655 * window procedure with it.
656 * Register SAS with the window.
657 * Register for logoff notification
662 /* Display login prompt */
663 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE
),
665 strlen(LoginPrompt
), // wcslen(LoginPrompt),
671 ReadConsole(GetStdHandle(STD_INPUT_HANDLE
),
677 } while (LoginName
[i
- 1] != '\n');
678 LoginName
[i
- 1] = 0;
680 /* Display password prompt */
681 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE
),
683 strlen(PasswordPrompt
), // wcslen(PasswordPrompt),
689 ReadConsole(GetStdHandle(STD_INPUT_HANDLE
),
695 } while (Password
[i
- 1] != '\n');
699 #if SUPPORT_CONSOLESTART
702 // if (! DoLogonUser(LoginName, Password))
703 if (! DoLogonUser(L
"Administrator", L
"Secret"))
707 NtShutdownSystem(ShutdownNoReboot
);
716 SessionLoop(WLSession
);
720 /* FIXME - Flush disks and registry, ... */
722 if(WLSession
->LogonStatus
== LOGON_SHUTDOWN
)
724 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
725 switch(DialogBox(hInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), 0, ShutdownComputerProc
))
727 case IDC_BTNSHTDOWNCOMPUTER
:
728 NtShutdownSystem(ShutdownReboot
);
731 NtShutdownSystem(ShutdownNoReboot
);
738 DbgPrint("WL: LogonStatus != LOGON_SHUTDOWN!!!\n");
741 #if SUPPORT_CONSOLESTART
749 DisplayStatusMessage(PWLSESSION Session
, HDESK hDesktop
, DWORD dwOptions
, PWSTR pTitle
, PWSTR pMessage
)
751 if(Session
->SuppressStatus
)
756 #if SUPPORT_CONSOLESTART
761 DbgPrint("WL-Status: %ws\n", pMessage
);
767 return Session
->MsGina
.Functions
.WlxDisplayStatusMessage(Session
->MsGina
.Context
, hDesktop
, dwOptions
, pTitle
, pMessage
);
773 WCHAR StatusMsg
[256];
775 LoadString(hAppInstance
, IDS_REACTOSISSTARTINGUP
, StatusMsg
, 256 * sizeof(WCHAR
));
776 DisplayStatusMessage(WLSession
, WLSession
->ApplicationDesktop
, 0, NULL
, StatusMsg
);
778 /* start system processes (services.exe & lsass.exe) */
779 if(StartProcess(L
"StartServices"))
783 DbgPrint("WL: Failed to start Services (0x%X)\n", GetLastError());
791 DoLogin(PWLSESSION Session
)
793 DWORD WlxAction
, Options
;
794 WLX_MPR_NOTIFY_INFO MprNotifyInfo
;
795 PWLX_PROFILE_V2_0 Profile
;
796 PSID LogonSid
= NULL
;
799 /* FIXME - Create a Logon Sid
800 if(!(LogonSid = CreateUserLogonSid(NULL)))
802 return WLX_SAS_ACTION_NONE;
807 WlxAction
= Session
->MsGina
.Functions
.WlxLoggedOutSAS(Session
->MsGina
.Context
,
820 SessionLoop(PWLSESSION Session
)
822 //WCHAR StatusMsg[256];
823 // HANDLE hShutdownEvent;
827 WlxAction
= WLX_SAS_ACTION_NONE
;
828 Session
->LogonStatus
= LOGON_NONE
;
829 while(WlxAction
== WLX_SAS_ACTION_NONE
)
831 RemoveStatusMessage(Session
);
832 if(Session
->LogonStatus
== LOGON_NONE
)
834 Session
->LogonStatus
= LOGON_SHOWINGLOGON
;
835 /* we're ready to display a logon window,
836 don't timeout dialogboxes here */
837 WlxSetTimeout(Session
->MsGina
.Context
, 0);
838 Session
->SuppressStatus
= TRUE
;
839 /* tell msgina to show a window telling the user one can logon */
840 #if SUPPORT_CONSOLESTART
843 DisplaySASNotice(Session
);
844 Session
->SuppressStatus
= FALSE
;
846 if(Session
->SASAction
== WLX_SAS_ACTION_LOGOFF
)
848 /* the system wants to log off here */
849 Session
->LogonStatus
= LOGON_SHUTDOWN
;
854 WlxAction
= DoLogin(Session
);
855 if(WlxAction
== WLX_SAS_ACTION_LOGOFF
)
857 /* the user doesn't want to login, instead pressed cancel
858 we should display the window again so one can logon again */
859 /* FIXME - disconnect any connections in case we did a remote logon */
860 DbgPrint("WL: DoLogin failed\n");
861 WlxAction
= WLX_SAS_ACTION_NONE
;
863 if(WlxAction
== WLX_SAS_ACTION_NONE
)
865 if(Session
->SASAction
== WLX_SAS_ACTION_LOGOFF
)
867 /* system is about to shut down, leave the main loop */
868 Session
->LogonStatus
= LOGON_SHUTDOWN
;
871 Session
->LogonStatus
= LOGON_NONE
;
875 /* FIXME - don't leave the loop when suspending the computer */
876 if(WLX_SUSPENDING(WlxAction
))
878 Session
->LogonStatus
= LOGON_NONE
;
879 WlxAction
= WLX_SAS_ACTION_NONE
;
880 /* don't leave the loop */
884 if(WLX_SHUTTINGDOWN(WlxAction
))
886 Session
->LogonStatus
= LOGON_SHUTDOWN
;
887 /* leave the loop here */
891 /* Message loop for the SAS window */
892 while(GetMessage(&Msg
, 0, 0, 0))
894 if (Msg
.message
== WM_HOTKEY
)
896 TranslateMessage(&Msg
);
897 DispatchMessage(&Msg
);
901 LoadString(hAppInstance, IDS_PREPARENETWORKCONNECTIONS, StatusMsg, 256 * sizeof(WCHAR));
902 MsGinaInst->Functions->WlxDisplayStatusMessage(MsGinaInst->Context,
911 LoadString(hAppInstance, IDS_APPLYINGCOMPUTERSETTINGS, StatusMsg, 256 * sizeof(WCHAR));
912 MsGinaInst->Functions->WlxDisplayStatusMessage(MsGinaInst->Context,
921 MsGinaInst->Functions->WlxRemoveStatusMessage(MsGinaInst->Context);
922 MsGinaInst->Functions->WlxRemoveStatusMessage(MsGinaInst->Context);
923 MsGinaInst->Functions->WlxRemoveStatusMessage(MsGinaInst->Context);
928 LoadString(hAppInstance, IDS_LOADINGYOURPERSONALSETTINGS, StatusMsg, 256 * sizeof(WCHAR));
929 MsGinaInst->Functions->WlxDisplayStatusMessage(MsGinaInst->Context,
937 LoadString(hAppInstance, IDS_APPLYINGYOURPERSONALSETTINGS, StatusMsg, 256 * sizeof(WCHAR));
938 MsGinaInst->Functions->WlxDisplayStatusMessage(MsGinaInst->Context,
947 MsGinaInst->Functions->WlxRemoveStatusMessage(MsGinaInst->Context);
948 MsGinaInst->Functions->WlxRemoveStatusMessage(MsGinaInst->Context);
950 if(!MsGinaInst->Functions->WlxActivateUserShell(MsGinaInst->Context,
955 LoadString(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, 256 * sizeof(WCHAR));
956 MessageBox(0, StatusMsg, NULL, MB_ICONERROR);
957 SetEvent(hShutdownEvent);
961 WaitForSingleObject(hShutdownEvent, INFINITE);
962 CloseHandle(hShutdownEvent);
964 LoadString(hAppInstance, IDS_SAVEYOURSETTINGS, StatusMsg, 256 * sizeof(WCHAR));
965 MsGinaInst->Functions->WlxDisplayStatusMessage(MsGinaInst->Context,
974 MsGinaInst->Functions->WlxShutdown(MsGinaInst->Context, WLX_SAS_ACTION_SHUTDOWN);
976 LoadString(hAppInstance, IDS_REACTOSISSHUTTINGDOWN, StatusMsg, 256 * sizeof(WCHAR));
977 MsGinaInst->Functions->WlxDisplayStatusMessage(MsGinaInst->Context,
986 MsGinaInst->Functions->WlxRemoveStatusMessage(MsGinaInst->Context);
987 MsGinaInst->Functions->WlxRemoveStatusMessage(MsGinaInst->Context);