branch update for HEAD-2003050101
[reactos.git] / subsys / system / winlogon / winlogon.c
1 /* $Id$
2  * 
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            services/winlogon/winlogon.c
6  * PURPOSE:         Logon 
7  * PROGRAMMER:      David Welch (welch@cwcom.net)
8  * UPDATE HISTORY:
9  *                  Created 22/05/98
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntos.h>
15 #include <windows.h>
16 #include <stdio.h>
17 #include <lsass/ntsecapi.h>
18 #include <wchar.h>
19
20 #include "setup.h"
21
22 #define NDEBUG
23 #include <debug.h>
24
25 /* GLOBALS ******************************************************************/
26
27 HWINSTA InteractiveWindowStation;   /* WinSta0 */
28 HDESK ApplicationDesktop;           /* WinSta0\Default */
29 HDESK WinlogonDesktop;              /* WinSta0\Winlogon */
30 HDESK ScreenSaverDesktop;           /* WinSta0\Screen-Saver */
31
32 /* FUNCTIONS *****************************************************************/
33
34 static void PrintString (char* fmt,...)
35 {
36    char buffer[512];
37    va_list ap;
38
39    va_start(ap, fmt);
40    vsprintf(buffer, fmt, ap);
41    va_end(ap);
42
43    OutputDebugString(buffer);
44 }
45
46
47 static BOOLEAN StartServices(VOID)
48 {
49    HANDLE ServicesInitEvent;
50    BOOLEAN Result;
51    STARTUPINFO StartupInfo;
52    PROCESS_INFORMATION ProcessInformation;
53    CHAR CommandLine[MAX_PATH];
54    DWORD Count;
55
56    /* Start the service control manager (services.exe) */   
57    GetSystemDirectory(CommandLine, MAX_PATH);
58    strcat(CommandLine, "\\services.exe");
59       
60    StartupInfo.cb = sizeof(StartupInfo);
61    StartupInfo.lpReserved = NULL;
62    StartupInfo.lpDesktop = NULL;
63    StartupInfo.lpTitle = NULL;
64    StartupInfo.dwFlags = 0;
65    StartupInfo.cbReserved2 = 0;
66    StartupInfo.lpReserved2 = 0;
67    
68    PrintString("WL: Creating new process - \"services.exe\".\n");
69
70    Result = CreateProcess(CommandLine,
71                           NULL,
72                           NULL,
73                           NULL,
74                           FALSE,
75                           DETACHED_PROCESS,
76                           NULL,
77                           NULL,
78                           &StartupInfo,
79                           &ProcessInformation);
80    if (!Result)
81      {
82         PrintString("WL: Failed to execute services\n");
83         return FALSE;
84      }
85    
86    /* wait for event creation (by SCM) for max. 20 seconds */
87    for (Count = 0; Count < 20; Count++)
88      {
89         Sleep(1000);
90    
91         //DbgPrint("WL: Attempting to open event \"SvcctrlStartEvent_A3725DX\"\n");
92         ServicesInitEvent = OpenEvent(EVENT_ALL_ACCESS, //SYNCHRONIZE,
93                                       FALSE,
94                                       "SvcctrlStartEvent_A3725DX");
95         if (ServicesInitEvent != NULL)
96           {
97              break;
98           }
99      }
100    
101    if (ServicesInitEvent == NULL)
102      {
103         DbgPrint("WL: Failed to open event \"SvcctrlStartEvent_A3725DX\"\n");
104         return FALSE;
105      }
106
107    /* wait for event signalization */
108    //DbgPrint("WL: Waiting forever on event handle: %x\n", ServicesInitEvent);
109    WaitForSingleObject(ServicesInitEvent, INFINITE);
110    //DbgPrint("WL: Closing event object \"SvcctrlStartEvent_A3725DX\"\n");
111    CloseHandle(ServicesInitEvent);
112    DbgPrint("WL: StartServices() Done.\n");
113       
114    return TRUE;
115 }
116
117 static BOOLEAN StartLsass(VOID)
118 {
119    HANDLE LsassInitEvent;
120    BOOLEAN Result;
121    STARTUPINFO StartupInfo;
122    PROCESS_INFORMATION ProcessInformation;
123    CHAR CommandLine[MAX_PATH];
124    
125    LsassInitEvent = CreateEvent(NULL,
126                                 TRUE,
127                                 FALSE,
128                                 "\\LsassInitDone");
129    
130    if (LsassInitEvent == NULL)
131      {
132         DbgPrint("WL: Failed to create lsass notification event\n");
133         return(FALSE);
134      }
135    
136    /* Start the local security authority subsystem (lsass.exe) */
137    
138    GetSystemDirectory(CommandLine, MAX_PATH);
139    strcat(CommandLine, "\\lsass.exe");
140    
141    StartupInfo.cb = sizeof(StartupInfo);
142    StartupInfo.lpReserved = NULL;
143    StartupInfo.lpDesktop = NULL;
144    StartupInfo.lpTitle = NULL;
145    StartupInfo.dwFlags = 0;
146    StartupInfo.cbReserved2 = 0;
147    StartupInfo.lpReserved2 = 0;
148    
149    Result = CreateProcess(CommandLine,
150                           NULL,
151                           NULL,
152                           NULL,
153                           FALSE,
154                           DETACHED_PROCESS,
155                           NULL,
156                           NULL,
157                           &StartupInfo,
158                           &ProcessInformation);
159    if (!Result)
160      {
161         DbgPrint("WL: Failed to execute lsass\n");
162         return(FALSE);
163      }
164    
165    DPRINT("WL: Waiting for lsass\n");
166    WaitForSingleObject(LsassInitEvent, INFINITE);
167    CloseHandle(LsassInitEvent);
168    
169    return(TRUE);
170 }
171
172 static BOOLEAN OpenRegistryKey(HANDLE *WinLogonKey)
173 {
174    return ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
175                                         _T("SOFTWARE\\ReactOS\\Windows NT\\CurrentVersion\\WinLogon"),
176                                         0,
177                                         KEY_QUERY_VALUE,
178                                         WinLogonKey);
179 }
180
181 static BOOLEAN StartProcess(PCHAR ValueName)
182 {
183    BOOL StartIt;
184    HANDLE WinLogonKey;
185    DWORD Type;
186    DWORD Size;
187    DWORD StartValue;
188
189    StartIt = TRUE;
190    if (OpenRegistryKey(&WinLogonKey))
191      {
192         Size = sizeof(DWORD);
193         if (ERROR_SUCCESS == RegQueryValueEx(WinLogonKey,
194                                              ValueName,
195                                              NULL,
196                                              &Type,
197                                              (LPBYTE) &StartValue,
198                                              &Size))
199            {
200            if (REG_DWORD == Type)
201              {
202                 StartIt = (0 != StartValue);
203              }
204            }
205         RegCloseKey(WinLogonKey);
206      }
207
208    return StartIt;
209 }
210
211 static PCHAR GetShell(PCHAR CommandLine)
212 {
213    HANDLE WinLogonKey;
214    BOOL GotCommandLine;
215    DWORD Type;
216    DWORD Size;
217    CHAR Shell[_MAX_PATH];
218
219    GotCommandLine = FALSE;
220    if (OpenRegistryKey(&WinLogonKey))
221      {
222         Size = MAX_PATH;
223         if (ERROR_SUCCESS == RegQueryValueEx(WinLogonKey,
224                                              _T("Shell"),
225                                              NULL,
226                                              &Type,
227                                              (LPBYTE) Shell,
228                                              &Size))
229            {
230            if (REG_EXPAND_SZ == Type)
231              {
232                 ExpandEnvironmentStrings(Shell, CommandLine, _MAX_PATH);
233                 GotCommandLine = TRUE;
234              }
235            else if (REG_SZ == Type)
236              {
237                 strcpy(CommandLine, Shell);
238                 GotCommandLine = TRUE;
239              }
240            }
241         RegCloseKey(WinLogonKey);
242      }
243
244    if (! GotCommandLine)
245      {
246         GetSystemDirectory(CommandLine, MAX_PATH - 10);
247         strcat(CommandLine, "\\cmd.exe");
248      }
249
250    return CommandLine;
251 }
252
253 static BOOL DoLoginUser(PCHAR Name, PCHAR Password)
254 {
255    PROCESS_INFORMATION ProcessInformation;
256    STARTUPINFO StartupInfo;
257    BOOLEAN Result;
258    CHAR CommandLine[MAX_PATH];
259    CHAR CurrentDirectory[MAX_PATH];
260
261    GetWindowsDirectory(CurrentDirectory, MAX_PATH);
262
263    StartupInfo.cb = sizeof(StartupInfo);
264    StartupInfo.lpReserved = NULL;
265    StartupInfo.lpDesktop = NULL;
266    StartupInfo.lpTitle = NULL;
267    StartupInfo.dwFlags = 0;
268    StartupInfo.cbReserved2 = 0;
269    StartupInfo.lpReserved2 = 0;
270    
271    Result = CreateProcess(NULL,
272                           GetShell(CommandLine),
273                           NULL,
274                           NULL,
275                           FALSE,
276                           DETACHED_PROCESS,
277                           NULL,
278                           CurrentDirectory,
279                           &StartupInfo,
280                           &ProcessInformation);
281    if (!Result)
282      {
283         DbgPrint("WL: Failed to execute user shell %s\n", CommandLine);
284         return FALSE;
285      }
286    WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
287    CloseHandle( ProcessInformation.hProcess );
288    CloseHandle( ProcessInformation.hThread );
289
290    return TRUE;
291 }
292
293 int STDCALL
294 WinMain(HINSTANCE hInstance,
295         HINSTANCE hPrevInstance,
296         LPSTR lpCmdLine,
297         int nShowCmd)
298 {
299 #if 0
300   LSA_STRING ProcessName;
301   NTSTATUS Status;
302   HANDLE LsaHandle;
303   LSA_OPERATIONAL_MODE Mode;
304 #endif
305   CHAR LoginPrompt[] = "login:";
306   CHAR PasswordPrompt[] = "password:";
307   DWORD Result;
308   CHAR LoginName[255];
309   CHAR Password[255];
310   BOOL Success;
311   ULONG i;
312   NTSTATUS Status;
313   
314   /*
315    * FIXME: Create a security descriptor with
316    *        one ACE containing the Winlogon SID
317    */
318   
319   /*
320    * Create the interactive window station
321    */
322    InteractiveWindowStation = 
323      CreateWindowStationW(L"WinSta0", 0, GENERIC_ALL, NULL);
324    if (InteractiveWindowStation == NULL)
325      {
326        DbgPrint("WL: Failed to create window station (0x%X)\n", GetLastError());
327        NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, 0, 0);
328        ExitProcess(1);
329      }
330    
331    /*
332     * Set the process window station
333     */
334    SetProcessWindowStation(InteractiveWindowStation);
335
336    /*
337     * Create the application desktop
338     */
339    ApplicationDesktop = 
340      CreateDesktopW(L"Default",
341                     NULL,
342                     NULL,
343                     0,      /* FIXME: Set some flags */
344                     GENERIC_ALL,
345                     NULL); 
346
347    /*
348     * Create the winlogon desktop
349     */
350    WinlogonDesktop = CreateDesktopW(L"Winlogon",
351                                     NULL,
352                                     NULL,
353                                     0,      /* FIXME: Set some flags */
354                                     GENERIC_ALL,
355                                     NULL);  
356    
357    /*
358     * Create the screen saver desktop
359     */
360    ScreenSaverDesktop = CreateDesktopW(L"Screen-Saver",
361                                        NULL,
362                                        NULL,
363                                        0,      /* FIXME: Set some flags */
364                                        GENERIC_ALL,
365                                        NULL);  
366    
367    /*
368     * Switch to winlogon desktop
369     */
370    /* FIXME: Do start up in the application desktop for now. */
371    Status = NtSetInformationProcess(NtCurrentProcess(),
372                                     ProcessDesktop,
373                                     &ApplicationDesktop,
374                                     sizeof(ApplicationDesktop));
375    if (!NT_SUCCESS(Status))
376      {
377        DbgPrint("WL: Cannot set default desktop for winlogon.\n");
378      }
379    SetThreadDesktop(ApplicationDesktop);
380    Success = SwitchDesktop(ApplicationDesktop);
381    if (!Success)
382      {
383        DbgPrint("WL: Cannot switch to Winlogon desktop (0x%X)\n", GetLastError());
384      }
385
386    AllocConsole();
387    SetConsoleTitle( "Winlogon" );
388
389   /* Check for pending setup */
390   if (GetSetupType () != 0)
391     {
392       DPRINT ("Winlogon: CheckForSetup() in setup mode\n");
393
394       /* Run setup and reboot when done */
395       RunSetup ();
396
397 //      NtShutdownSystem (ShutdownReboot);
398       NtShutdownSystem (ShutdownNoReboot);
399       ExitProcess (0);
400       return 0;
401     }
402
403    /* start system processes (services.exe & lsass.exe) */
404    if (StartProcess("StartServices"))
405      {
406         if (!StartServices())
407           {
408              DbgPrint("WL: Failed to start Services (0x%X)\n", GetLastError());
409           }
410      }
411 #if 0
412    if (StartProcess("StartLsass"))
413      {
414         if (!StartLsass())
415           {
416              DbgPrint("WL: Failed to start LSASS (0x%X)\n", GetLastError());
417           }
418      }
419 #endif
420    
421    /* FIXME: What name does the real WinLogon use? */
422 #if 0
423    RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"WinLogon");
424    Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
425    if (!NT_SUCCESS(Status))
426      {
427         DbgPrint("WL: Failed to connect to LSASS\n");
428         return(1);
429      }
430 #endif
431    
432    /* FIXME: Create a window class and associate a Winlogon
433     *        window procedure with it.
434     *        Register SAS with the window.
435     *        Register for logoff notification
436     */
437    
438    /* Main loop */
439 #if 0
440    /* Display login prompt */
441    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),
442                 LoginPrompt,
443                 strlen(LoginPrompt),  // wcslen(LoginPrompt),
444                 &Result,
445                 NULL);
446    i = 0;
447    do
448      {
449        ReadConsole(GetStdHandle(STD_INPUT_HANDLE),
450                    &LoginName[i],
451                    1,
452                    &Result,
453                    NULL);
454        i++;
455      } while (LoginName[i - 1] != '\n');
456    LoginName[i - 1] = 0;
457        
458    /* Display password prompt */
459    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),
460                 PasswordPrompt,
461                 strlen(PasswordPrompt),  // wcslen(PasswordPrompt),
462                 &Result,
463                 NULL);
464    i = 0;
465    do
466      {
467        ReadConsole(GetStdHandle(STD_INPUT_HANDLE),
468                    &Password[i],
469                    1,
470                    &Result,
471                    NULL);
472        i++;
473      } while (Password[i - 1] != '\n');
474    Password[i - 1] =0;
475 #endif
476
477    if (! DoLoginUser(LoginName, Password))
478      {
479      }
480
481    NtShutdownSystem(ShutdownNoReboot);
482    
483    ExitProcess(0);
484    
485    return 0;
486 }