013c8bce44faba32e7fd765c98c7a795f4ca5572
[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 DWORD dwDisableCAD = 0;
174 DWORD dwSize;
175 LONG rc;
176
177 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
178 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
179 0,
180 KEY_QUERY_VALUE,
181 &hKey);
182 if (rc != ERROR_SUCCESS)
183 {
184 WARN("RegOpenKeyExW() failed with error %lu\n", rc);
185 return FALSE;
186 }
187
188 rc = ReadRegSzValue(hKey,
189 L"AutoAdminLogon",
190 &lpAutoAdminLogon);
191 if (rc == ERROR_SUCCESS)
192 {
193 if (wcscmp(lpAutoAdminLogon, L"1") == 0)
194 pgContext->bAutoAdminLogon = TRUE;
195 }
196
197 TRACE("bAutoAdminLogon: %s\n", pgContext->bAutoAdminLogon ? "TRUE" : "FALSE");
198
199 rc = ReadRegDwordValue(hKey,
200 L"DisableCAD",
201 &dwDisableCAD);
202 if (rc == ERROR_SUCCESS)
203 {
204 if (dwDisableCAD != 0)
205 pgContext->bDisableCAD = TRUE;
206 }
207
208 TRACE("bDisableCAD: %s\n", pgContext->bDisableCAD ? "TRUE" : "FALSE");
209
210 pgContext->bShutdownWithoutLogon = TRUE;
211 rc = ReadRegSzValue(hKey,
212 L"ShutdownWithoutLogon",
213 &lpShutdownWithoutLogon);
214 if (rc == ERROR_SUCCESS)
215 {
216 if (wcscmp(lpShutdownWithoutLogon, L"0") == 0)
217 pgContext->bShutdownWithoutLogon = FALSE;
218 }
219
220 rc = ReadRegSzValue(hKey,
221 L"DontDisplayLastUserName",
222 &lpDontDisplayLastUserName);
223 if (rc == ERROR_SUCCESS)
224 {
225 if (wcscmp(lpDontDisplayLastUserName, L"1") == 0)
226 pgContext->bDontDisplayLastUserName = TRUE;
227 }
228
229 dwSize = sizeof(pgContext->UserName);
230 rc = RegQueryValueExW(hKey,
231 L"DefaultUserName",
232 NULL,
233 NULL,
234 (LPBYTE)&pgContext->UserName,
235 &dwSize);
236
237 dwSize = sizeof(pgContext->Domain);
238 rc = RegQueryValueExW(hKey,
239 L"DefaultDomain",
240 NULL,
241 NULL,
242 (LPBYTE)&pgContext->Domain,
243 &dwSize);
244
245 if (lpShutdownWithoutLogon != NULL)
246 HeapFree(GetProcessHeap(), 0, lpShutdownWithoutLogon);
247
248 if (lpDontDisplayLastUserName != NULL)
249 HeapFree(GetProcessHeap(), 0, lpDontDisplayLastUserName);
250
251 if (lpAutoAdminLogon != NULL)
252 HeapFree(GetProcessHeap(), 0, lpAutoAdminLogon);
253
254 if (hKey != NULL)
255 RegCloseKey(hKey);
256
257 return TRUE;
258 }
259
260 typedef DWORD (WINAPI *pThemeWait)(DWORD dwTimeout);
261 typedef BOOL (WINAPI *pThemeWatch)(void);
262
263 static void
264 InitThemeSupport(VOID)
265 {
266 HMODULE hDll = LoadLibraryW(L"shsvcs.dll");
267 pThemeWait themeWait;
268 pThemeWatch themeWatch;
269
270 if(!hDll)
271 return;
272
273 themeWait = (pThemeWait) GetProcAddress(hDll, (LPCSTR)2);
274 themeWatch = (pThemeWatch) GetProcAddress(hDll, (LPCSTR)1);
275
276 if(themeWait && themeWatch)
277 {
278 themeWait(5000);
279 themeWatch();
280 }
281 }
282
283 /*
284 * @implemented
285 */
286 BOOL WINAPI
287 WlxInitialize(
288 LPWSTR lpWinsta,
289 HANDLE hWlx,
290 PVOID pvReserved,
291 PVOID pWinlogonFunctions,
292 PVOID *pWlxContext)
293 {
294 PGINA_CONTEXT pgContext;
295
296 UNREFERENCED_PARAMETER(pvReserved);
297
298 InitThemeSupport();
299
300 pgContext = (PGINA_CONTEXT)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(GINA_CONTEXT));
301 if(!pgContext)
302 {
303 WARN("LocalAlloc() failed\n");
304 return FALSE;
305 }
306
307 if (!GetRegistrySettings(pgContext))
308 {
309 WARN("GetRegistrySettings() failed\n");
310 LocalFree(pgContext);
311 return FALSE;
312 }
313
314 /* Return the context to winlogon */
315 *pWlxContext = (PVOID)pgContext;
316 pgContext->hDllInstance = hDllInstance;
317
318 /* Save pointer to dispatch table */
319 pgContext->pWlxFuncs = (PWLX_DISPATCH_VERSION_1_3)pWinlogonFunctions;
320
321 /* Save the winlogon handle used to call the dispatch functions */
322 pgContext->hWlx = hWlx;
323
324 /* Save window station */
325 pgContext->station = lpWinsta;
326
327 /* Clear status window handle */
328 pgContext->hStatusWindow = NULL;
329
330 /* Notify winlogon that we will use the default SAS */
331 pgContext->pWlxFuncs->WlxUseCtrlAltDel(hWlx);
332
333 /* Locates the authentication package */
334 //LsaRegisterLogonProcess(...);
335
336 /* Check autologon settings the first time */
337 pgContext->AutoLogonState = AUTOLOGON_CHECK_REGISTRY;
338
339 pgContext->nShutdownAction = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
340
341 ChooseGinaUI();
342 return pGinaUI->Initialize(pgContext);
343 }
344
345 /*
346 * @implemented
347 */
348 BOOL
349 WINAPI
350 WlxScreenSaverNotify(
351 PVOID pWlxContext,
352 BOOL *pSecure)
353 {
354 #if 0
355 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
356 WCHAR szBuffer[2];
357 HKEY hKeyCurrentUser, hKey;
358 DWORD bufferSize = sizeof(szBuffer);
359 DWORD varType = REG_SZ;
360 LONG rc;
361
362 TRACE("(%p %p)\n", pWlxContext, pSecure);
363
364 *pSecure = TRUE;
365
366 /*
367 * Policy setting:
368 * HKLM\Software\Policies\Microsoft\Windows\Control Panel\Desktop : ScreenSaverIsSecure
369 * User setting:
370 * HKCU\Control Panel\Desktop : ScreenSaverIsSecure
371 */
372
373 if (!ImpersonateLoggedOnUser(pgContext->UserToken))
374 {
375 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
376 *pSecure = FALSE;
377 return TRUE;
378 }
379
380 /* Open the current user HKCU key */
381 rc = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser);
382 TRACE("RegOpenCurrentUser: %ld\n", rc);
383 if (rc == ERROR_SUCCESS)
384 {
385 /* Open the subkey */
386 rc = RegOpenKeyExW(hKeyCurrentUser,
387 L"Control Panel\\Desktop",
388 0,
389 KEY_QUERY_VALUE,
390 &hKey);
391 TRACE("RegOpenKeyExW: %ld\n", rc);
392 RegCloseKey(hKeyCurrentUser);
393 }
394
395 /* Read the value */
396 if (rc == ERROR_SUCCESS)
397 {
398 rc = RegQueryValueExW(hKey,
399 L"ScreenSaverIsSecure",
400 NULL,
401 &varType,
402 (LPBYTE)szBuffer,
403 &bufferSize);
404
405 TRACE("RegQueryValueExW: %ld\n", rc);
406
407 if (rc == ERROR_SUCCESS)
408 {
409 TRACE("szBuffer: \"%S\"\n", szBuffer);
410 *pSecure = _wtoi(szBuffer);
411 }
412
413 RegCloseKey(hKey);
414 }
415
416 /* Revert the impersonation */
417 RevertToSelf();
418
419 TRACE("*pSecure: %ld\n", *pSecure);
420 #endif
421
422 *pSecure = FALSE;
423
424 return TRUE;
425 }
426
427 /*
428 * @implemented
429 */
430 BOOL WINAPI
431 WlxStartApplication(
432 PVOID pWlxContext,
433 PWSTR pszDesktopName,
434 PVOID pEnvironment,
435 PWSTR pszCmdLine)
436 {
437 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
438 STARTUPINFOW StartupInfo;
439 PROCESS_INFORMATION ProcessInformation;
440 WCHAR CurrentDirectory[MAX_PATH];
441 HANDLE hAppToken;
442 UINT len;
443 BOOL ret;
444
445 len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH);
446 if (len == 0 || len > MAX_PATH)
447 {
448 ERR("GetWindowsDirectoryW() failed\n");
449 return FALSE;
450 }
451
452 ret = DuplicateTokenEx(pgContext->UserToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hAppToken);
453 if (!ret)
454 {
455 ERR("DuplicateTokenEx() failed with error %lu\n", GetLastError());
456 return FALSE;
457 }
458
459 ZeroMemory(&StartupInfo, sizeof(StartupInfo));
460 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
461 StartupInfo.cb = sizeof(StartupInfo);
462 StartupInfo.lpTitle = pszCmdLine;
463 StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
464 StartupInfo.wShowWindow = SW_SHOW;
465 StartupInfo.lpDesktop = pszDesktopName;
466
467 len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH);
468 if (len == 0 || len > MAX_PATH)
469 {
470 ERR("GetWindowsDirectoryW() failed\n");
471 return FALSE;
472 }
473 ret = CreateProcessAsUserW(
474 hAppToken,
475 pszCmdLine,
476 NULL,
477 NULL,
478 NULL,
479 FALSE,
480 CREATE_UNICODE_ENVIRONMENT,
481 pEnvironment,
482 CurrentDirectory,
483 &StartupInfo,
484 &ProcessInformation);
485 CloseHandle(ProcessInformation.hProcess);
486 CloseHandle(ProcessInformation.hThread);
487 CloseHandle(hAppToken);
488 if (!ret)
489 ERR("CreateProcessAsUserW() failed with error %lu\n", GetLastError());
490 return ret;
491 }
492
493 /*
494 * @implemented
495 */
496 BOOL WINAPI
497 WlxActivateUserShell(
498 PVOID pWlxContext,
499 PWSTR pszDesktopName,
500 PWSTR pszMprLogonScript,
501 PVOID pEnvironment)
502 {
503 HKEY hKey;
504 DWORD BufSize, ValueType;
505 WCHAR pszUserInitApp[MAX_PATH + 1];
506 WCHAR pszExpUserInitApp[MAX_PATH];
507 DWORD len;
508 LONG rc;
509
510 TRACE("WlxActivateUserShell()\n");
511
512 UNREFERENCED_PARAMETER(pszMprLogonScript);
513
514 /* Get the path of userinit */
515 rc = RegOpenKeyExW(
516 HKEY_LOCAL_MACHINE,
517 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
518 0,
519 KEY_QUERY_VALUE,
520 &hKey);
521 if (rc != ERROR_SUCCESS)
522 {
523 WARN("RegOpenKeyExW() failed with error %lu\n", rc);
524 return FALSE;
525 }
526
527 /* Query userinit application */
528 BufSize = sizeof(pszUserInitApp) - sizeof(UNICODE_NULL);
529 rc = RegQueryValueExW(
530 hKey,
531 L"Userinit",
532 NULL,
533 &ValueType,
534 (LPBYTE)pszUserInitApp,
535 &BufSize);
536 RegCloseKey(hKey);
537 if (rc != ERROR_SUCCESS || (ValueType != REG_SZ && ValueType != REG_EXPAND_SZ))
538 {
539 WARN("RegQueryValueExW() failed with error %lu\n", rc);
540 return FALSE;
541 }
542 pszUserInitApp[MAX_PATH] = UNICODE_NULL;
543
544 len = ExpandEnvironmentStringsW(pszUserInitApp, pszExpUserInitApp, MAX_PATH);
545 if (len > MAX_PATH)
546 {
547 WARN("ExpandEnvironmentStringsW() failed. Required size %lu\n", len);
548 return FALSE;
549 }
550
551 /* Start userinit app */
552 return WlxStartApplication(pWlxContext, pszDesktopName, pEnvironment, pszExpUserInitApp);
553 }
554
555 /*
556 * @implemented
557 */
558 int WINAPI
559 WlxLoggedOnSAS(
560 PVOID pWlxContext,
561 DWORD dwSasType,
562 PVOID pReserved)
563 {
564 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
565 INT SasAction = WLX_SAS_ACTION_NONE;
566
567 TRACE("WlxLoggedOnSAS(0x%lx)\n", dwSasType);
568
569 UNREFERENCED_PARAMETER(pReserved);
570
571 switch (dwSasType)
572 {
573 case WLX_SAS_TYPE_CTRL_ALT_DEL:
574 case WLX_SAS_TYPE_TIMEOUT:
575 {
576 SasAction = pGinaUI->LoggedOnSAS(pgContext, dwSasType);
577 break;
578 }
579 case WLX_SAS_TYPE_SC_INSERT:
580 {
581 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_INSERT not supported!\n");
582 break;
583 }
584 case WLX_SAS_TYPE_SC_REMOVE:
585 {
586 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_REMOVE not supported!\n");
587 break;
588 }
589 default:
590 {
591 WARN("WlxLoggedOnSAS: Unknown SasType: 0x%x\n", dwSasType);
592 break;
593 }
594 }
595
596 return SasAction;
597 }
598
599 /*
600 * @implemented
601 */
602 BOOL WINAPI
603 WlxDisplayStatusMessage(
604 IN PVOID pWlxContext,
605 IN HDESK hDesktop,
606 IN DWORD dwOptions,
607 IN PWSTR pTitle,
608 IN PWSTR pMessage)
609 {
610 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
611
612 TRACE("WlxDisplayStatusMessage(\"%S\")\n", pMessage);
613
614 return pGinaUI->DisplayStatusMessage(pgContext, hDesktop, dwOptions, pTitle, pMessage);
615 }
616
617 /*
618 * @implemented
619 */
620 BOOL WINAPI
621 WlxRemoveStatusMessage(
622 IN PVOID pWlxContext)
623 {
624 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
625
626 TRACE("WlxRemoveStatusMessage()\n");
627
628 return pGinaUI->RemoveStatusMessage(pgContext);
629 }
630
631 static PWSTR
632 DuplicationString(PWSTR Str)
633 {
634 DWORD cb;
635 PWSTR NewStr;
636
637 if (Str == NULL) return NULL;
638
639 cb = (wcslen(Str) + 1) * sizeof(WCHAR);
640 if ((NewStr = LocalAlloc(LMEM_FIXED, cb)))
641 memcpy(NewStr, Str, cb);
642 return NewStr;
643 }
644
645
646 BOOL
647 DoAdminUnlock(
648 IN PGINA_CONTEXT pgContext,
649 IN PWSTR UserName,
650 IN PWSTR Domain,
651 IN PWSTR Password)
652 {
653 HANDLE hToken = NULL;
654 PTOKEN_GROUPS Groups = NULL;
655 BOOL bIsAdmin = FALSE;
656 ULONG Size;
657 ULONG i;
658 NTSTATUS Status;
659 NTSTATUS SubStatus = STATUS_SUCCESS;
660
661 TRACE("(%S %S %S)\n", UserName, Domain, Password);
662
663 Status = ConnectToLsa(pgContext);
664 if (!NT_SUCCESS(Status))
665 {
666 WARN("ConnectToLsa() failed\n");
667 return FALSE;
668 }
669
670 Status = MyLogonUser(pgContext->LsaHandle,
671 pgContext->AuthenticationPackage,
672 UserName,
673 Domain,
674 Password,
675 &pgContext->UserToken,
676 &SubStatus);
677 if (!NT_SUCCESS(Status))
678 {
679 WARN("MyLogonUser() failed\n");
680 return FALSE;
681 }
682
683 Status = NtQueryInformationToken(hToken,
684 TokenGroups,
685 NULL,
686 0,
687 &Size);
688 if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL))
689 {
690 TRACE("NtQueryInformationToken() failed (Status 0x%08lx)\n", Status);
691 goto done;
692 }
693
694 Groups = HeapAlloc(GetProcessHeap(), 0, Size);
695 if (Groups == NULL)
696 {
697 TRACE("HeapAlloc() failed\n");
698 goto done;
699 }
700
701 Status = NtQueryInformationToken(hToken,
702 TokenGroups,
703 Groups,
704 Size,
705 &Size);
706 if (!NT_SUCCESS(Status))
707 {
708 TRACE("NtQueryInformationToken() failed (Status 0x%08lx)\n", Status);
709 goto done;
710 }
711
712 for (i = 0; i < Groups->GroupCount; i++)
713 {
714 if (RtlEqualSid(Groups->Groups[i].Sid, AdminSid))
715 {
716 TRACE("Member of Admins group\n");
717 bIsAdmin = TRUE;
718 break;
719 }
720 }
721
722 done:
723 if (Groups != NULL)
724 HeapFree(GetProcessHeap(), 0, Groups);
725
726 if (hToken != NULL)
727 CloseHandle(hToken);
728
729 return bIsAdmin;
730 }
731
732
733 NTSTATUS
734 DoLoginTasks(
735 IN OUT PGINA_CONTEXT pgContext,
736 IN PWSTR UserName,
737 IN PWSTR Domain,
738 IN PWSTR Password,
739 OUT PNTSTATUS SubStatus)
740 {
741 NTSTATUS Status;
742
743 Status = ConnectToLsa(pgContext);
744 if (!NT_SUCCESS(Status))
745 {
746 WARN("ConnectToLsa() failed (Status 0x%08lx)\n", Status);
747 return Status;
748 }
749
750 Status = MyLogonUser(pgContext->LsaHandle,
751 pgContext->AuthenticationPackage,
752 UserName,
753 Domain,
754 Password,
755 &pgContext->UserToken,
756 SubStatus);
757 if (!NT_SUCCESS(Status))
758 {
759 WARN("MyLogonUser() failed (Status 0x%08lx)\n", Status);
760 }
761
762 return Status;
763 }
764
765
766 BOOL
767 CreateProfile(
768 IN OUT PGINA_CONTEXT pgContext,
769 IN PWSTR UserName,
770 IN PWSTR Domain,
771 IN PWSTR Password)
772 {
773 LPWSTR ProfilePath = NULL;
774 LPWSTR lpEnvironment = NULL;
775 TOKEN_STATISTICS Stats;
776 PWLX_PROFILE_V2_0 pProfile = NULL;
777 DWORD cbStats, cbSize;
778 DWORD dwLength;
779 BOOL bResult;
780
781 /* Store the logon time in the context */
782 GetLocalTime(&pgContext->LogonTime);
783
784 /* Store user and domain in the context */
785 wcscpy(pgContext->UserName, UserName);
786 if (Domain == NULL || wcslen(Domain) == 0)
787 {
788 dwLength = _countof(pgContext->Domain);
789 GetComputerNameW(pgContext->Domain, &dwLength);
790 }
791 else
792 {
793 wcscpy(pgContext->Domain, Domain);
794 }
795
796 /* Get profile path */
797 cbSize = 0;
798 bResult = GetProfilesDirectoryW(NULL, &cbSize);
799 if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
800 {
801 ProfilePath = HeapAlloc(GetProcessHeap(), 0, cbSize * sizeof(WCHAR));
802 if (!ProfilePath)
803 {
804 WARN("HeapAlloc() failed\n");
805 goto cleanup;
806 }
807 bResult = GetProfilesDirectoryW(ProfilePath, &cbSize);
808 }
809 if (!bResult)
810 {
811 WARN("GetUserProfileDirectoryW() failed\n");
812 goto cleanup;
813 }
814
815 /* Allocate memory for profile */
816 pProfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WLX_PROFILE_V2_0));
817 if (!pProfile)
818 {
819 WARN("HeapAlloc() failed\n");
820 goto cleanup;
821 }
822 pProfile->dwType = WLX_PROFILE_TYPE_V2_0;
823 pProfile->pszProfile = ProfilePath;
824
825 cbSize = sizeof(L"LOGONSERVER=\\\\") +
826 wcslen(pgContext->Domain) * sizeof(WCHAR) +
827 sizeof(UNICODE_NULL);
828 lpEnvironment = HeapAlloc(GetProcessHeap(), 0, cbSize);
829 if (!lpEnvironment)
830 {
831 WARN("HeapAlloc() failed\n");
832 goto cleanup;
833 }
834
835 StringCbPrintfW(lpEnvironment, cbSize, L"LOGONSERVER=\\\\%ls", pgContext->Domain);
836 ASSERT(wcslen(lpEnvironment) == cbSize / sizeof(WCHAR) - 2);
837 lpEnvironment[cbSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
838
839 pProfile->pszEnvironment = lpEnvironment;
840
841 if (!GetTokenInformation(pgContext->UserToken,
842 TokenStatistics,
843 &Stats,
844 sizeof(Stats),
845 &cbStats))
846 {
847 WARN("Couldn't get Authentication id from user token!\n");
848 goto cleanup;
849 }
850
851 *pgContext->pAuthenticationId = Stats.AuthenticationId;
852 pgContext->pMprNotifyInfo->pszUserName = DuplicationString(UserName);
853 pgContext->pMprNotifyInfo->pszDomain = DuplicationString(Domain);
854 pgContext->pMprNotifyInfo->pszPassword = DuplicationString(Password);
855 pgContext->pMprNotifyInfo->pszOldPassword = NULL;
856 *pgContext->pdwOptions = 0;
857 *pgContext->pProfile = pProfile;
858 return TRUE;
859
860 cleanup:
861 if (pProfile)
862 {
863 HeapFree(GetProcessHeap(), 0, pProfile->pszEnvironment);
864 }
865 HeapFree(GetProcessHeap(), 0, pProfile);
866 HeapFree(GetProcessHeap(), 0, ProfilePath);
867 return FALSE;
868 }
869
870
871 static BOOL
872 DoAutoLogon(
873 IN PGINA_CONTEXT pgContext)
874 {
875 HKEY WinLogonKey = NULL;
876 LPWSTR AutoLogon = NULL;
877 LPWSTR AutoCount = NULL;
878 LPWSTR IgnoreShiftOverride = NULL;
879 LPWSTR UserName = NULL;
880 LPWSTR Domain = NULL;
881 LPWSTR Password = NULL;
882 BOOL result = FALSE;
883 LONG rc;
884 NTSTATUS Status;
885 NTSTATUS SubStatus = STATUS_SUCCESS;
886
887 TRACE("DoAutoLogon(): AutoLogonState = %lu\n",
888 pgContext->AutoLogonState);
889
890 if (pgContext->AutoLogonState == AUTOLOGON_DISABLED)
891 return FALSE;
892
893 rc = RegOpenKeyExW(
894 HKEY_LOCAL_MACHINE,
895 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
896 0,
897 KEY_QUERY_VALUE,
898 &WinLogonKey);
899 if (rc != ERROR_SUCCESS)
900 goto cleanup;
901
902 if (pgContext->AutoLogonState == AUTOLOGON_CHECK_REGISTRY)
903 {
904 /* Set it by default to disabled, we might reenable it again later */
905 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
906
907 rc = ReadRegSzValue(WinLogonKey, L"AutoAdminLogon", &AutoLogon);
908 if (rc != ERROR_SUCCESS)
909 goto cleanup;
910 if (wcscmp(AutoLogon, L"1") != 0)
911 goto cleanup;
912
913 rc = ReadRegSzValue(WinLogonKey, L"AutoLogonCount", &AutoCount);
914 if (rc == ERROR_SUCCESS && wcscmp(AutoCount, L"0") == 0)
915 goto cleanup;
916 else if (rc != ERROR_FILE_NOT_FOUND)
917 goto cleanup;
918
919 rc = ReadRegSzValue(WinLogonKey, L"IgnoreShiftOverride", &UserName);
920 if (rc == ERROR_SUCCESS)
921 {
922 if (wcscmp(AutoLogon, L"1") != 0 && GetKeyState(VK_SHIFT) < 0)
923 goto cleanup;
924 }
925 else if (GetKeyState(VK_SHIFT) < 0)
926 {
927 /* User pressed SHIFT */
928 goto cleanup;
929 }
930
931 pgContext->AutoLogonState = AUTOLOGON_ONCE;
932 result = TRUE;
933 }
934 else /* pgContext->AutoLogonState == AUTOLOGON_ONCE */
935 {
936 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
937
938 rc = ReadRegSzValue(WinLogonKey, L"DefaultUserName", &UserName);
939 if (rc != ERROR_SUCCESS)
940 goto cleanup;
941 rc = ReadRegSzValue(WinLogonKey, L"DefaultDomain", &Domain);
942 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
943 goto cleanup;
944 rc = ReadRegSzValue(WinLogonKey, L"DefaultPassword", &Password);
945 if (rc != ERROR_SUCCESS)
946 goto cleanup;
947
948 Status = DoLoginTasks(pgContext, UserName, Domain, Password, &SubStatus);
949 if (!NT_SUCCESS(Status))
950 {
951 /* FIXME: Handle errors!!! */
952 result = FALSE;
953 goto cleanup;
954 }
955
956 result = CreateProfile(pgContext, UserName, Domain, Password);
957 if (result)
958 {
959 ZeroMemory(pgContext->Password, sizeof(pgContext->Password));
960 wcscpy(pgContext->Password, Password);
961
962 NotifyBootConfigStatus(TRUE);
963 }
964 }
965
966 cleanup:
967 if (WinLogonKey != NULL)
968 RegCloseKey(WinLogonKey);
969 HeapFree(GetProcessHeap(), 0, AutoLogon);
970 HeapFree(GetProcessHeap(), 0, AutoCount);
971 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride);
972 HeapFree(GetProcessHeap(), 0, UserName);
973 HeapFree(GetProcessHeap(), 0, Domain);
974 HeapFree(GetProcessHeap(), 0, Password);
975 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n",
976 pgContext->AutoLogonState, result);
977 return result;
978 }
979
980 /*
981 * @implemented
982 */
983 VOID WINAPI
984 WlxDisplaySASNotice(
985 IN PVOID pWlxContext)
986 {
987 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
988
989 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext);
990
991 if (GetSystemMetrics(SM_REMOTESESSION))
992 {
993 /* User is remotely logged on. Don't display a notice */
994 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
995 return;
996 }
997
998 if (pgContext->bAutoAdminLogon)
999 {
1000 /* Don't display the window, we want to do an automatic logon */
1001 pgContext->AutoLogonState = AUTOLOGON_ONCE;
1002 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
1003 return;
1004 }
1005 else
1006 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
1007
1008 if (pgContext->bDisableCAD)
1009 {
1010 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
1011 return;
1012 }
1013
1014 pGinaUI->DisplaySASNotice(pgContext);
1015
1016 TRACE("WlxDisplaySASNotice() done\n");
1017 }
1018
1019 /*
1020 * @implemented
1021 */
1022 INT WINAPI
1023 WlxLoggedOutSAS(
1024 IN PVOID pWlxContext,
1025 IN DWORD dwSasType,
1026 OUT PLUID pAuthenticationId,
1027 IN OUT PSID pLogonSid,
1028 OUT PDWORD pdwOptions,
1029 OUT PHANDLE phToken,
1030 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
1031 OUT PVOID *pProfile)
1032 {
1033 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
1034 INT res;
1035
1036 TRACE("WlxLoggedOutSAS()\n");
1037
1038 UNREFERENCED_PARAMETER(dwSasType);
1039 UNREFERENCED_PARAMETER(pLogonSid);
1040
1041 pgContext->pAuthenticationId = pAuthenticationId;
1042 pgContext->pdwOptions = pdwOptions;
1043 pgContext->pMprNotifyInfo = pMprNotifyInfo;
1044 pgContext->pProfile = pProfile;
1045
1046 if (0 == GetSystemMetrics(SM_REMOTESESSION) &&
1047 DoAutoLogon(pgContext))
1048 {
1049 /* User is local and registry contains information
1050 * to log on him automatically */
1051 *phToken = pgContext->UserToken;
1052 return WLX_SAS_ACTION_LOGON;
1053 }
1054
1055 res = pGinaUI->LoggedOutSAS(pgContext);
1056 *phToken = pgContext->UserToken;
1057 return res;
1058 }
1059
1060 /*
1061 * @implemented
1062 */
1063 int WINAPI
1064 WlxWkstaLockedSAS(
1065 PVOID pWlxContext,
1066 DWORD dwSasType)
1067 {
1068 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
1069
1070 TRACE("WlxWkstaLockedSAS()\n");
1071
1072 UNREFERENCED_PARAMETER(dwSasType);
1073
1074 return pGinaUI->LockedSAS(pgContext);
1075 }
1076
1077
1078 /*
1079 * @implemented
1080 */
1081 VOID
1082 WINAPI
1083 WlxDisplayLockedNotice(PVOID pWlxContext)
1084 {
1085 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
1086
1087 TRACE("WlxDisplayLockedNotice()\n");
1088
1089 if (pgContext->bDisableCAD)
1090 {
1091 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
1092 return;
1093 }
1094
1095 pGinaUI->DisplayLockedNotice(pgContext);
1096 }
1097
1098
1099 /*
1100 * @implemented
1101 */
1102 BOOL WINAPI
1103 WlxIsLogoffOk(
1104 PVOID pWlxContext)
1105 {
1106 TRACE("WlxIsLogoffOk()\n");
1107 UNREFERENCED_PARAMETER(pWlxContext);
1108 return TRUE;
1109 }
1110
1111 BOOL WINAPI
1112 DllMain(
1113 IN HINSTANCE hinstDLL,
1114 IN DWORD dwReason,
1115 IN LPVOID lpvReserved)
1116 {
1117 UNREFERENCED_PARAMETER(lpvReserved);
1118
1119 if (dwReason == DLL_PROCESS_ATTACH)
1120 {
1121 hDllInstance = hinstDLL;
1122
1123 RtlAllocateAndInitializeSid(&SystemAuthority,
1124 2,
1125 SECURITY_BUILTIN_DOMAIN_RID,
1126 DOMAIN_ALIAS_RID_ADMINS,
1127 SECURITY_NULL_RID,
1128 SECURITY_NULL_RID,
1129 SECURITY_NULL_RID,
1130 SECURITY_NULL_RID,
1131 SECURITY_NULL_RID,
1132 SECURITY_NULL_RID,
1133 &AdminSid);
1134
1135 }
1136 else if (dwReason == DLL_PROCESS_DETACH)
1137 {
1138 if (AdminSid != NULL)
1139 RtlFreeSid(AdminSid);
1140 }
1141
1142 return TRUE;
1143 }