xref: /reactos/dll/win32/msgina/msgina.c (revision 84344399)
1 /*
2  *  ReactOS GINA
3  *  Copyright (C) 2003-2004, 2006 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * PROJECT:         ReactOS msgina.dll
21  * FILE:            dll/win32/msgina/msgina.c
22  * PURPOSE:         ReactOS Logon GINA DLL
23  * PROGRAMMER:      Thomas Weidenmueller (w3seek@users.sourceforge.net)
24  *                  Hervé Poussineau (hpoussin@reactos.org)
25  */
26 
27 #include "msgina.h"
28 
29 #include <winsvc.h>
30 #include <userenv.h>
31 #include <ndk/sefuncs.h>
32 
33 HINSTANCE hDllInstance;
34 
35 extern GINA_UI GinaGraphicalUI;
36 extern GINA_UI GinaTextUI;
37 static PGINA_UI pGinaUI;
38 static SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
39 static PSID AdminSid;
40 
41 /*
42  * @implemented
43  */
44 BOOL WINAPI
45 WlxNegotiate(
46     IN DWORD dwWinlogonVersion,
47     OUT PDWORD pdwDllVersion)
48 {
49     TRACE("WlxNegotiate(%lx, %p)\n", dwWinlogonVersion, pdwDllVersion);
50 
51     if(!pdwDllVersion || (dwWinlogonVersion < WLX_VERSION_1_3))
52         return FALSE;
53 
54     *pdwDllVersion = WLX_VERSION_1_3;
55 
56     return TRUE;
57 }
58 
59 LONG
60 ReadRegSzValue(
61     IN HKEY hKey,
62     IN LPCWSTR pszValue,
63     OUT LPWSTR* pValue)
64 {
65     LONG rc;
66     DWORD dwType;
67     DWORD cbData = 0;
68     LPWSTR Value;
69 
70     if (!pValue)
71         return ERROR_INVALID_PARAMETER;
72 
73     *pValue = NULL;
74     rc = RegQueryValueExW(hKey, pszValue, NULL, &dwType, NULL, &cbData);
75     if (rc != ERROR_SUCCESS)
76         return rc;
77     if (dwType != REG_SZ)
78         return ERROR_FILE_NOT_FOUND;
79     Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
80     if (!Value)
81         return ERROR_NOT_ENOUGH_MEMORY;
82     rc = RegQueryValueExW(hKey, pszValue, NULL, NULL, (LPBYTE)Value, &cbData);
83     if (rc != ERROR_SUCCESS)
84     {
85         HeapFree(GetProcessHeap(), 0, Value);
86         return rc;
87     }
88     /* NULL-terminate the string */
89     Value[cbData / sizeof(WCHAR)] = '\0';
90 
91     *pValue = Value;
92     return ERROR_SUCCESS;
93 }
94 
95 static LONG
96 ReadRegDwordValue(
97     IN HKEY hKey,
98     IN LPCWSTR pszValue,
99     OUT LPDWORD pValue)
100 {
101     LONG rc;
102     DWORD dwType;
103     DWORD cbData;
104     DWORD dwValue;
105 
106     if (!pValue)
107         return ERROR_INVALID_PARAMETER;
108 
109     cbData = sizeof(DWORD);
110     rc = RegQueryValueExW(hKey, pszValue, NULL, &dwType, (LPBYTE)&dwValue, &cbData);
111     if (rc == ERROR_SUCCESS && dwType == REG_DWORD)
112         *pValue = dwValue;
113 
114     return ERROR_SUCCESS;
115 }
116 
117 static VOID
118 ChooseGinaUI(VOID)
119 {
120     HKEY ControlKey = NULL;
121     LPWSTR SystemStartOptions = NULL;
122     LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
123     BOOL ConsoleBoot = FALSE;
124     LONG rc;
125 
126     rc = RegOpenKeyExW(
127         HKEY_LOCAL_MACHINE,
128         L"SYSTEM\\CurrentControlSet\\Control",
129         0,
130         KEY_QUERY_VALUE,
131         &ControlKey);
132 
133     rc = ReadRegSzValue(ControlKey, L"SystemStartOptions", &SystemStartOptions);
134     if (rc != ERROR_SUCCESS)
135         goto cleanup;
136 
137     /* Check for CONSOLE switch in SystemStartOptions */
138     CurrentOption = SystemStartOptions;
139     while (CurrentOption)
140     {
141         NextOption = wcschr(CurrentOption, L' ');
142         if (NextOption)
143             *NextOption = L'\0';
144         if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
145         {
146             TRACE("Found %S. Switching to console boot\n", CurrentOption);
147             ConsoleBoot = TRUE;
148             goto cleanup;
149         }
150         CurrentOption = NextOption ? NextOption + 1 : NULL;
151     }
152 
153 cleanup:
154     if (ConsoleBoot)
155         pGinaUI = &GinaTextUI;
156     else
157         pGinaUI = &GinaGraphicalUI;
158 
159     if (ControlKey != NULL)
160         RegCloseKey(ControlKey);
161     HeapFree(GetProcessHeap(), 0, SystemStartOptions);
162 }
163 
164 
165 static
166 BOOL
167 GetRegistrySettings(PGINA_CONTEXT pgContext)
168 {
169     HKEY hKey = NULL;
170     LPWSTR lpAutoAdminLogon = NULL;
171     LPWSTR lpDontDisplayLastUserName = NULL;
172     LPWSTR lpShutdownWithoutLogon = NULL;
173     LPWSTR lpIgnoreShiftOverride = NULL;
174     DWORD dwDisableCAD = 0;
175     DWORD dwSize;
176     LONG rc;
177 
178     rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
179                        L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
180                        0,
181                        KEY_QUERY_VALUE,
182                        &hKey);
183     if (rc != ERROR_SUCCESS)
184     {
185         WARN("RegOpenKeyExW() failed with error %lu\n", rc);
186         return FALSE;
187     }
188 
189     rc = ReadRegSzValue(hKey,
190                         L"AutoAdminLogon",
191                         &lpAutoAdminLogon);
192     if (rc == ERROR_SUCCESS)
193     {
194         if (wcscmp(lpAutoAdminLogon, L"1") == 0)
195             pgContext->bAutoAdminLogon = TRUE;
196     }
197 
198     TRACE("bAutoAdminLogon: %s\n", pgContext->bAutoAdminLogon ? "TRUE" : "FALSE");
199 
200     rc = ReadRegDwordValue(hKey,
201                            L"DisableCAD",
202                            &dwDisableCAD);
203     if (rc == ERROR_SUCCESS)
204     {
205         if (dwDisableCAD != 0)
206             pgContext->bDisableCAD = TRUE;
207     }
208 
209     TRACE("bDisableCAD: %s\n", pgContext->bDisableCAD ? "TRUE" : "FALSE");
210 
211     pgContext->bShutdownWithoutLogon = TRUE;
212     rc = ReadRegSzValue(hKey,
213                         L"ShutdownWithoutLogon",
214                         &lpShutdownWithoutLogon);
215     if (rc == ERROR_SUCCESS)
216     {
217         if (wcscmp(lpShutdownWithoutLogon, L"0") == 0)
218             pgContext->bShutdownWithoutLogon = FALSE;
219     }
220 
221     rc = ReadRegSzValue(hKey,
222                         L"DontDisplayLastUserName",
223                         &lpDontDisplayLastUserName);
224     if (rc == ERROR_SUCCESS)
225     {
226         if (wcscmp(lpDontDisplayLastUserName, L"1") == 0)
227             pgContext->bDontDisplayLastUserName = TRUE;
228     }
229 
230     rc = ReadRegSzValue(hKey,
231                         L"IgnoreShiftOverride",
232                         &lpIgnoreShiftOverride);
233     if (rc == ERROR_SUCCESS)
234     {
235         if (wcscmp(lpIgnoreShiftOverride, L"1") == 0)
236             pgContext->bIgnoreShiftOverride = TRUE;
237     }
238 
239     dwSize = sizeof(pgContext->UserName);
240     rc = RegQueryValueExW(hKey,
241                           L"DefaultUserName",
242                           NULL,
243                           NULL,
244                           (LPBYTE)&pgContext->UserName,
245                           &dwSize);
246 
247     dwSize = sizeof(pgContext->DomainName);
248     rc = RegQueryValueExW(hKey,
249                           L"DefaultDomainName",
250                           NULL,
251                           NULL,
252                           (LPBYTE)&pgContext->DomainName,
253                           &dwSize);
254 
255     dwSize = sizeof(pgContext->Password);
256     rc = RegQueryValueExW(hKey,
257                           L"DefaultPassword",
258                           NULL,
259                           NULL,
260                           (LPBYTE)&pgContext->Password,
261                           &dwSize);
262 
263     if (lpIgnoreShiftOverride != NULL)
264         HeapFree(GetProcessHeap(), 0, lpIgnoreShiftOverride);
265 
266     if (lpShutdownWithoutLogon != NULL)
267         HeapFree(GetProcessHeap(), 0, lpShutdownWithoutLogon);
268 
269     if (lpDontDisplayLastUserName != NULL)
270         HeapFree(GetProcessHeap(), 0, lpDontDisplayLastUserName);
271 
272     if (lpAutoAdminLogon != NULL)
273         HeapFree(GetProcessHeap(), 0, lpAutoAdminLogon);
274 
275     if (hKey != NULL)
276         RegCloseKey(hKey);
277 
278     return TRUE;
279 }
280 
281 typedef DWORD (WINAPI *pThemeWait)(DWORD dwTimeout);
282 typedef BOOL (WINAPI *pThemeWatch)(void);
283 
284 static void
285 InitThemeSupport(VOID)
286 {
287     HMODULE hDll = LoadLibraryW(L"shsvcs.dll");
288     pThemeWait themeWait;
289     pThemeWatch themeWatch;
290 
291     if(!hDll)
292         return;
293 
294     themeWait = (pThemeWait) GetProcAddress(hDll, (LPCSTR)2);
295     themeWatch = (pThemeWatch) GetProcAddress(hDll, (LPCSTR)1);
296 
297     if(themeWait && themeWatch)
298     {
299         themeWait(5000);
300         themeWatch();
301     }
302 }
303 
304 /*
305  * @implemented
306  */
307 BOOL WINAPI
308 WlxInitialize(
309     LPWSTR lpWinsta,
310     HANDLE hWlx,
311     PVOID  pvReserved,
312     PVOID  pWinlogonFunctions,
313     PVOID  *pWlxContext)
314 {
315     PGINA_CONTEXT pgContext;
316 
317     UNREFERENCED_PARAMETER(pvReserved);
318 
319     InitThemeSupport();
320 
321     pgContext = (PGINA_CONTEXT)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(GINA_CONTEXT));
322     if(!pgContext)
323     {
324         WARN("LocalAlloc() failed\n");
325         return FALSE;
326     }
327 
328     if (!GetRegistrySettings(pgContext))
329     {
330         WARN("GetRegistrySettings() failed\n");
331         LocalFree(pgContext);
332         return FALSE;
333     }
334 
335     /* Return the context to winlogon */
336     *pWlxContext = (PVOID)pgContext;
337     pgContext->hDllInstance = hDllInstance;
338 
339     /* Save pointer to dispatch table */
340     pgContext->pWlxFuncs = (PWLX_DISPATCH_VERSION_1_3)pWinlogonFunctions;
341 
342     /* Save the winlogon handle used to call the dispatch functions */
343     pgContext->hWlx = hWlx;
344 
345     /* Save window station */
346     pgContext->station = lpWinsta;
347 
348     /* Clear status window handle */
349     pgContext->hStatusWindow = NULL;
350 
351     /* Notify winlogon that we will use the default SAS */
352     pgContext->pWlxFuncs->WlxUseCtrlAltDel(hWlx);
353 
354     /* Locates the authentication package */
355     //LsaRegisterLogonProcess(...);
356 
357     pgContext->nShutdownAction = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
358 
359     ChooseGinaUI();
360     return pGinaUI->Initialize(pgContext);
361 }
362 
363 /*
364  * @implemented
365  */
366 BOOL
367 WINAPI
368 WlxScreenSaverNotify(
369     PVOID pWlxContext,
370     BOOL  *pSecure)
371 {
372 #if 0
373     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
374     WCHAR szBuffer[2];
375     HKEY hKeyCurrentUser, hKey;
376     DWORD bufferSize = sizeof(szBuffer);
377     DWORD varType = REG_SZ;
378     LONG rc;
379 
380     TRACE("(%p %p)\n", pWlxContext, pSecure);
381 
382     *pSecure = TRUE;
383 
384     /*
385      * Policy setting:
386      *    HKLM\Software\Policies\Microsoft\Windows\Control Panel\Desktop : ScreenSaverIsSecure
387      * User setting:
388      *    HKCU\Control Panel\Desktop : ScreenSaverIsSecure
389      */
390 
391     if (!ImpersonateLoggedOnUser(pgContext->UserToken))
392     {
393         ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
394         *pSecure = FALSE;
395         return TRUE;
396     }
397 
398     /* Open the current user HKCU key */
399     rc = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
400     TRACE("RegOpenCurrentUser: %ld\n", rc);
401     if (rc == ERROR_SUCCESS)
402     {
403         /* Open the subkey */
404         rc = RegOpenKeyExW(hKeyCurrentUser,
405                            L"Control Panel\\Desktop",
406                            0,
407                            KEY_QUERY_VALUE,
408                            &hKey);
409         TRACE("RegOpenKeyExW: %ld\n", rc);
410         RegCloseKey(hKeyCurrentUser);
411     }
412 
413     /* Read the value */
414     if (rc == ERROR_SUCCESS)
415     {
416         rc = RegQueryValueExW(hKey,
417                               L"ScreenSaverIsSecure",
418                               NULL,
419                               &varType,
420                               (LPBYTE)szBuffer,
421                               &bufferSize);
422 
423         TRACE("RegQueryValueExW: %ld\n", rc);
424 
425         if (rc == ERROR_SUCCESS)
426         {
427             TRACE("szBuffer: \"%S\"\n", szBuffer);
428             *pSecure = _wtoi(szBuffer);
429         }
430 
431         RegCloseKey(hKey);
432     }
433 
434     /* Revert the impersonation */
435     RevertToSelf();
436 
437     TRACE("*pSecure: %ld\n", *pSecure);
438 #endif
439 
440     *pSecure = FALSE;
441 
442     return TRUE;
443 }
444 
445 /*
446  * @implemented
447  */
448 BOOL WINAPI
449 WlxStartApplication(
450     PVOID pWlxContext,
451     PWSTR pszDesktopName,
452     PVOID pEnvironment,
453     PWSTR pszCmdLine)
454 {
455     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
456     STARTUPINFOW StartupInfo;
457     PROCESS_INFORMATION ProcessInformation;
458     WCHAR CurrentDirectory[MAX_PATH];
459     HANDLE hAppToken;
460     UINT len;
461     BOOL ret;
462 
463     len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH);
464     if (len == 0 || len > MAX_PATH)
465     {
466         ERR("GetWindowsDirectoryW() failed\n");
467         return FALSE;
468     }
469 
470     ret = DuplicateTokenEx(pgContext->UserToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hAppToken);
471     if (!ret)
472     {
473         ERR("DuplicateTokenEx() failed with error %lu\n", GetLastError());
474         return FALSE;
475     }
476 
477     ZeroMemory(&StartupInfo, sizeof(StartupInfo));
478     ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
479     StartupInfo.cb = sizeof(StartupInfo);
480     StartupInfo.lpTitle = pszCmdLine;
481     StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
482     StartupInfo.wShowWindow = SW_SHOW;
483     StartupInfo.lpDesktop = pszDesktopName;
484 
485     len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH);
486     if (len == 0 || len > MAX_PATH)
487     {
488         ERR("GetWindowsDirectoryW() failed\n");
489         return FALSE;
490     }
491     ret = CreateProcessAsUserW(
492         hAppToken,
493         pszCmdLine,
494         NULL,
495         NULL,
496         NULL,
497         FALSE,
498         CREATE_UNICODE_ENVIRONMENT,
499         pEnvironment,
500         CurrentDirectory,
501         &StartupInfo,
502         &ProcessInformation);
503     CloseHandle(ProcessInformation.hProcess);
504     CloseHandle(ProcessInformation.hThread);
505     CloseHandle(hAppToken);
506     if (!ret)
507         ERR("CreateProcessAsUserW() failed with error %lu\n", GetLastError());
508     return ret;
509 }
510 
511 /*
512  * @implemented
513  */
514 BOOL WINAPI
515 WlxActivateUserShell(
516     PVOID pWlxContext,
517     PWSTR pszDesktopName,
518     PWSTR pszMprLogonScript,
519     PVOID pEnvironment)
520 {
521     HKEY hKey;
522     DWORD BufSize, ValueType;
523     WCHAR pszUserInitApp[MAX_PATH + 1];
524     WCHAR pszExpUserInitApp[MAX_PATH];
525     DWORD len;
526     LONG rc;
527 
528     TRACE("WlxActivateUserShell()\n");
529 
530     UNREFERENCED_PARAMETER(pszMprLogonScript);
531 
532     /* Get the path of userinit */
533     rc = RegOpenKeyExW(
534         HKEY_LOCAL_MACHINE,
535         L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
536         0,
537         KEY_QUERY_VALUE,
538         &hKey);
539     if (rc != ERROR_SUCCESS)
540     {
541         WARN("RegOpenKeyExW() failed with error %lu\n", rc);
542         return FALSE;
543     }
544 
545     /* Query userinit application */
546     BufSize = sizeof(pszUserInitApp) - sizeof(UNICODE_NULL);
547     rc = RegQueryValueExW(
548         hKey,
549         L"Userinit",
550         NULL,
551         &ValueType,
552         (LPBYTE)pszUserInitApp,
553         &BufSize);
554     RegCloseKey(hKey);
555     if (rc != ERROR_SUCCESS || (ValueType != REG_SZ && ValueType != REG_EXPAND_SZ))
556     {
557         WARN("RegQueryValueExW() failed with error %lu\n", rc);
558         return FALSE;
559     }
560     pszUserInitApp[MAX_PATH] = UNICODE_NULL;
561 
562     len = ExpandEnvironmentStringsW(pszUserInitApp, pszExpUserInitApp, MAX_PATH);
563     if (len > MAX_PATH)
564     {
565         WARN("ExpandEnvironmentStringsW() failed. Required size %lu\n", len);
566         return FALSE;
567     }
568 
569     /* Start userinit app */
570     return WlxStartApplication(pWlxContext, pszDesktopName, pEnvironment, pszExpUserInitApp);
571 }
572 
573 /*
574  * @implemented
575  */
576 int WINAPI
577 WlxLoggedOnSAS(
578     PVOID pWlxContext,
579     DWORD dwSasType,
580     PVOID pReserved)
581 {
582     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
583     INT SasAction = WLX_SAS_ACTION_NONE;
584 
585     TRACE("WlxLoggedOnSAS(0x%lx)\n", dwSasType);
586 
587     UNREFERENCED_PARAMETER(pReserved);
588 
589     switch (dwSasType)
590     {
591         case WLX_SAS_TYPE_CTRL_ALT_DEL:
592         case WLX_SAS_TYPE_TIMEOUT:
593         {
594             SasAction = pGinaUI->LoggedOnSAS(pgContext, dwSasType);
595             break;
596         }
597         case WLX_SAS_TYPE_SC_INSERT:
598         {
599             FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_INSERT not supported!\n");
600             break;
601         }
602         case WLX_SAS_TYPE_SC_REMOVE:
603         {
604             FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_REMOVE not supported!\n");
605             break;
606         }
607         default:
608         {
609             WARN("WlxLoggedOnSAS: Unknown SasType: 0x%x\n", dwSasType);
610             break;
611         }
612     }
613 
614     return SasAction;
615 }
616 
617 /*
618  * @implemented
619  */
620 BOOL WINAPI
621 WlxDisplayStatusMessage(
622     IN PVOID pWlxContext,
623     IN HDESK hDesktop,
624     IN DWORD dwOptions,
625     IN PWSTR pTitle,
626     IN PWSTR pMessage)
627 {
628     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
629 
630     TRACE("WlxDisplayStatusMessage(\"%S\")\n", pMessage);
631 
632     return pGinaUI->DisplayStatusMessage(pgContext, hDesktop, dwOptions, pTitle, pMessage);
633 }
634 
635 /*
636  * @implemented
637  */
638 BOOL WINAPI
639 WlxRemoveStatusMessage(
640     IN PVOID pWlxContext)
641 {
642     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
643 
644     TRACE("WlxRemoveStatusMessage()\n");
645 
646     return pGinaUI->RemoveStatusMessage(pgContext);
647 }
648 
649 static PWSTR
650 DuplicationString(PWSTR Str)
651 {
652     DWORD cb;
653     PWSTR NewStr;
654 
655     if (Str == NULL) return NULL;
656 
657     cb = (wcslen(Str) + 1) * sizeof(WCHAR);
658     if ((NewStr = LocalAlloc(LMEM_FIXED, cb)))
659         memcpy(NewStr, Str, cb);
660     return NewStr;
661 }
662 
663 
664 BOOL
665 DoAdminUnlock(
666     IN PGINA_CONTEXT pgContext,
667     IN PWSTR UserName,
668     IN PWSTR Domain,
669     IN PWSTR Password)
670 {
671     HANDLE hToken = NULL;
672     PTOKEN_GROUPS Groups = NULL;
673     BOOL bIsAdmin = FALSE;
674     ULONG Size;
675     ULONG i;
676     NTSTATUS Status;
677     NTSTATUS SubStatus = STATUS_SUCCESS;
678 
679     TRACE("(%S %S %S)\n", UserName, Domain, Password);
680 
681     Status = ConnectToLsa(pgContext);
682     if (!NT_SUCCESS(Status))
683     {
684         WARN("ConnectToLsa() failed\n");
685         return FALSE;
686     }
687 
688     Status = MyLogonUser(pgContext->LsaHandle,
689                          pgContext->AuthenticationPackage,
690                          UserName,
691                          Domain,
692                          Password,
693                          &pgContext->UserToken,
694                          &SubStatus);
695     if (!NT_SUCCESS(Status))
696     {
697         WARN("MyLogonUser() failed\n");
698         return FALSE;
699     }
700 
701     Status = NtQueryInformationToken(hToken,
702                                      TokenGroups,
703                                      NULL,
704                                      0,
705                                      &Size);
706     if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL))
707     {
708         TRACE("NtQueryInformationToken() failed (Status 0x%08lx)\n", Status);
709         goto done;
710     }
711 
712     Groups = HeapAlloc(GetProcessHeap(), 0, Size);
713     if (Groups == NULL)
714     {
715         TRACE("HeapAlloc() failed\n");
716         goto done;
717     }
718 
719     Status = NtQueryInformationToken(hToken,
720                                      TokenGroups,
721                                      Groups,
722                                      Size,
723                                      &Size);
724     if (!NT_SUCCESS(Status))
725     {
726         TRACE("NtQueryInformationToken() failed (Status 0x%08lx)\n", Status);
727         goto done;
728     }
729 
730     for (i = 0; i < Groups->GroupCount; i++)
731     {
732         if (RtlEqualSid(Groups->Groups[i].Sid, AdminSid))
733         {
734             TRACE("Member of Admins group\n");
735             bIsAdmin = TRUE;
736             break;
737         }
738     }
739 
740 done:
741     if (Groups != NULL)
742         HeapFree(GetProcessHeap(), 0, Groups);
743 
744     if (hToken != NULL)
745         CloseHandle(hToken);
746 
747     return bIsAdmin;
748 }
749 
750 
751 NTSTATUS
752 DoLoginTasks(
753     IN OUT PGINA_CONTEXT pgContext,
754     IN PWSTR UserName,
755     IN PWSTR Domain,
756     IN PWSTR Password,
757     OUT PNTSTATUS SubStatus)
758 {
759     NTSTATUS Status;
760 
761     Status = ConnectToLsa(pgContext);
762     if (!NT_SUCCESS(Status))
763     {
764         WARN("ConnectToLsa() failed (Status 0x%08lx)\n", Status);
765         return Status;
766     }
767 
768     Status = MyLogonUser(pgContext->LsaHandle,
769                          pgContext->AuthenticationPackage,
770                          UserName,
771                          Domain,
772                          Password,
773                          &pgContext->UserToken,
774                          SubStatus);
775     if (!NT_SUCCESS(Status))
776     {
777         WARN("MyLogonUser() failed (Status 0x%08lx)\n", Status);
778     }
779 
780     return Status;
781 }
782 
783 
784 BOOL
785 CreateProfile(
786     IN OUT PGINA_CONTEXT pgContext,
787     IN PWSTR UserName,
788     IN PWSTR Domain,
789     IN PWSTR Password)
790 {
791     LPWSTR ProfilePath = NULL;
792     LPWSTR lpEnvironment = NULL;
793     TOKEN_STATISTICS Stats;
794     PWLX_PROFILE_V2_0 pProfile = NULL;
795     DWORD cbStats, cbSize;
796     DWORD dwLength;
797     BOOL bResult;
798 
799     /* Store the logon time in the context */
800     GetLocalTime(&pgContext->LogonTime);
801 
802     /* Store user and domain in the context */
803     wcscpy(pgContext->UserName, UserName);
804     if (Domain == NULL || wcslen(Domain) == 0)
805     {
806         dwLength = _countof(pgContext->DomainName);
807         GetComputerNameW(pgContext->DomainName, &dwLength);
808     }
809     else
810     {
811         wcscpy(pgContext->DomainName, Domain);
812     }
813 
814     /* Get profile path */
815     cbSize = 0;
816     bResult = GetProfilesDirectoryW(NULL, &cbSize);
817     if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
818     {
819         ProfilePath = HeapAlloc(GetProcessHeap(), 0, cbSize * sizeof(WCHAR));
820         if (!ProfilePath)
821         {
822             WARN("HeapAlloc() failed\n");
823             goto cleanup;
824         }
825         bResult = GetProfilesDirectoryW(ProfilePath, &cbSize);
826     }
827     if (!bResult)
828     {
829         WARN("GetUserProfileDirectoryW() failed\n");
830         goto cleanup;
831     }
832 
833     /* Allocate memory for profile */
834     pProfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WLX_PROFILE_V2_0));
835     if (!pProfile)
836     {
837         WARN("HeapAlloc() failed\n");
838         goto cleanup;
839     }
840     pProfile->dwType = WLX_PROFILE_TYPE_V2_0;
841     pProfile->pszProfile = ProfilePath;
842 
843     cbSize = sizeof(L"LOGONSERVER=\\\\") +
844              wcslen(pgContext->DomainName) * sizeof(WCHAR) +
845              sizeof(UNICODE_NULL);
846     lpEnvironment = HeapAlloc(GetProcessHeap(), 0, cbSize);
847     if (!lpEnvironment)
848     {
849         WARN("HeapAlloc() failed\n");
850         goto cleanup;
851     }
852 
853     StringCbPrintfW(lpEnvironment, cbSize, L"LOGONSERVER=\\\\%ls", pgContext->DomainName);
854     ASSERT(wcslen(lpEnvironment) == cbSize / sizeof(WCHAR) - 2);
855     lpEnvironment[cbSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
856 
857     pProfile->pszEnvironment = lpEnvironment;
858 
859     if (!GetTokenInformation(pgContext->UserToken,
860                              TokenStatistics,
861                              &Stats,
862                              sizeof(Stats),
863                              &cbStats))
864     {
865         WARN("Couldn't get Authentication id from user token!\n");
866         goto cleanup;
867     }
868 
869     *pgContext->pAuthenticationId = Stats.AuthenticationId;
870     pgContext->pMprNotifyInfo->pszUserName = DuplicationString(UserName);
871     pgContext->pMprNotifyInfo->pszDomain = DuplicationString(Domain);
872     pgContext->pMprNotifyInfo->pszPassword = DuplicationString(Password);
873     pgContext->pMprNotifyInfo->pszOldPassword = NULL;
874     *pgContext->pdwOptions = 0;
875     *pgContext->pProfile = pProfile;
876     return TRUE;
877 
878 cleanup:
879     if (pProfile)
880     {
881         HeapFree(GetProcessHeap(), 0, pProfile->pszEnvironment);
882     }
883     HeapFree(GetProcessHeap(), 0, pProfile);
884     HeapFree(GetProcessHeap(), 0, ProfilePath);
885     return FALSE;
886 }
887 
888 
889 /*
890  * @implemented
891  */
892 VOID WINAPI
893 WlxDisplaySASNotice(
894     IN PVOID pWlxContext)
895 {
896     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
897 
898     TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext);
899 
900     if (GetSystemMetrics(SM_REMOTESESSION))
901     {
902         /* User is remotely logged on. Don't display a notice */
903         pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
904         return;
905     }
906 
907     if (pgContext->bAutoAdminLogon)
908     {
909         if (pgContext->bIgnoreShiftOverride ||
910             (GetKeyState(VK_SHIFT) >= 0))
911         {
912             /* Don't display the window, we want to do an automatic logon */
913             pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
914             return;
915         }
916 
917         pgContext->bAutoAdminLogon = FALSE;
918     }
919 
920     if (pgContext->bDisableCAD)
921     {
922         pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
923         return;
924     }
925 
926     pGinaUI->DisplaySASNotice(pgContext);
927 
928     TRACE("WlxDisplaySASNotice() done\n");
929 }
930 
931 /*
932  * @implemented
933  */
934 INT WINAPI
935 WlxLoggedOutSAS(
936     IN PVOID pWlxContext,
937     IN DWORD dwSasType,
938     OUT PLUID pAuthenticationId,
939     IN OUT PSID pLogonSid,
940     OUT PDWORD pdwOptions,
941     OUT PHANDLE phToken,
942     OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
943     OUT PVOID *pProfile)
944 {
945     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
946     INT res;
947 
948     TRACE("WlxLoggedOutSAS()\n");
949 
950     UNREFERENCED_PARAMETER(dwSasType);
951     UNREFERENCED_PARAMETER(pLogonSid);
952 
953     pgContext->pAuthenticationId = pAuthenticationId;
954     pgContext->pdwOptions = pdwOptions;
955     pgContext->pMprNotifyInfo = pMprNotifyInfo;
956     pgContext->pProfile = pProfile;
957 
958 
959     res = pGinaUI->LoggedOutSAS(pgContext);
960     *phToken = pgContext->UserToken;
961     return res;
962 }
963 
964 /*
965  * @implemented
966  */
967 int WINAPI
968 WlxWkstaLockedSAS(
969     PVOID pWlxContext,
970     DWORD dwSasType)
971 {
972     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
973 
974     TRACE("WlxWkstaLockedSAS()\n");
975 
976     UNREFERENCED_PARAMETER(dwSasType);
977 
978     return pGinaUI->LockedSAS(pgContext);
979 }
980 
981 
982 /*
983  * @implemented
984  */
985 VOID
986 WINAPI
987 WlxDisplayLockedNotice(PVOID pWlxContext)
988 {
989     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
990 
991     TRACE("WlxDisplayLockedNotice()\n");
992 
993     if (pgContext->bDisableCAD)
994     {
995         pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
996         return;
997     }
998 
999     pGinaUI->DisplayLockedNotice(pgContext);
1000 }
1001 
1002 
1003 /*
1004  * @implemented
1005  */
1006 BOOL WINAPI
1007 WlxIsLogoffOk(
1008     PVOID pWlxContext)
1009 {
1010     TRACE("WlxIsLogoffOk()\n");
1011     UNREFERENCED_PARAMETER(pWlxContext);
1012     return TRUE;
1013 }
1014 
1015 
1016 /*
1017  * @implemented
1018  */
1019 VOID WINAPI
1020 WlxLogoff(
1021     PVOID pWlxContext)
1022 {
1023     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
1024 
1025     TRACE("WlxLogoff(%p)\n", pWlxContext);
1026 
1027     /* Delete the password */
1028     ZeroMemory(pgContext->Password, sizeof(pgContext->Password));
1029 
1030     /* Close the user token */
1031     CloseHandle(pgContext->UserToken);
1032     pgContext->UserToken = NULL;
1033 }
1034 
1035 
1036 /*
1037  * @implemented
1038  */
1039 VOID WINAPI
1040 WlxShutdown(
1041     PVOID pWlxContext,
1042     DWORD ShutdownType)
1043 {
1044     PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
1045     NTSTATUS Status;
1046 
1047     TRACE("WlxShutdown(%p %lx)\n", pWlxContext, ShutdownType);
1048 
1049     /* Close the LSA handle */
1050     pgContext->AuthenticationPackage = 0;
1051     Status = LsaDeregisterLogonProcess(pgContext->LsaHandle);
1052     if (!NT_SUCCESS(Status))
1053     {
1054         ERR("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status);
1055     }
1056 }
1057 
1058 
1059 BOOL WINAPI
1060 DllMain(
1061     IN HINSTANCE hinstDLL,
1062     IN DWORD dwReason,
1063     IN LPVOID lpvReserved)
1064 {
1065     UNREFERENCED_PARAMETER(lpvReserved);
1066 
1067     if (dwReason == DLL_PROCESS_ATTACH)
1068     {
1069         hDllInstance = hinstDLL;
1070 
1071         RtlAllocateAndInitializeSid(&SystemAuthority,
1072                                     2,
1073                                     SECURITY_BUILTIN_DOMAIN_RID,
1074                                     DOMAIN_ALIAS_RID_ADMINS,
1075                                     SECURITY_NULL_RID,
1076                                     SECURITY_NULL_RID,
1077                                     SECURITY_NULL_RID,
1078                                     SECURITY_NULL_RID,
1079                                     SECURITY_NULL_RID,
1080                                     SECURITY_NULL_RID,
1081                                     &AdminSid);
1082 
1083     }
1084     else if (dwReason == DLL_PROCESS_DETACH)
1085     {
1086         if (AdminSid != NULL)
1087             RtlFreeSid(AdminSid);
1088     }
1089 
1090     return TRUE;
1091 }
1092