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