[MSGINA] Close the LSA handle on shutdown
[reactos.git] / dll / win32 / msgina / msgina.c
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 /* Close the user token */
1028 CloseHandle(pgContext->UserToken);
1029 pgContext->UserToken = NULL;
1030 }
1031
1032
1033 /*
1034 * @implemented
1035 */
1036 VOID WINAPI
1037 WlxShutdown(
1038 PVOID pWlxContext,
1039 DWORD ShutdownType)
1040 {
1041 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
1042 NTSTATUS Status;
1043
1044 TRACE("WlxShutdown(%p %lx)\n", pWlxContext, ShutdownType);
1045
1046 /* Close the LSA handle */
1047 pgContext->AuthenticationPackage = 0;
1048 Status = LsaDeregisterLogonProcess(pgContext->LsaHandle);
1049 if (!NT_SUCCESS(Status))
1050 {
1051 ERR("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status);
1052 }
1053 }
1054
1055
1056 BOOL WINAPI
1057 DllMain(
1058 IN HINSTANCE hinstDLL,
1059 IN DWORD dwReason,
1060 IN LPVOID lpvReserved)
1061 {
1062 UNREFERENCED_PARAMETER(lpvReserved);
1063
1064 if (dwReason == DLL_PROCESS_ATTACH)
1065 {
1066 hDllInstance = hinstDLL;
1067
1068 RtlAllocateAndInitializeSid(&SystemAuthority,
1069 2,
1070 SECURITY_BUILTIN_DOMAIN_RID,
1071 DOMAIN_ALIAS_RID_ADMINS,
1072 SECURITY_NULL_RID,
1073 SECURITY_NULL_RID,
1074 SECURITY_NULL_RID,
1075 SECURITY_NULL_RID,
1076 SECURITY_NULL_RID,
1077 SECURITY_NULL_RID,
1078 &AdminSid);
1079
1080 }
1081 else if (dwReason == DLL_PROCESS_DETACH)
1082 {
1083 if (AdminSid != NULL)
1084 RtlFreeSid(AdminSid);
1085 }
1086
1087 return TRUE;
1088 }