[MSV1_0]
[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 ChooseGinaUI();
317 return pGinaUI->Initialize(pgContext);
318 }
319
320 /*
321 * @implemented
322 */
323 BOOL
324 WINAPI
325 WlxScreenSaverNotify(
326 PVOID pWlxContext,
327 BOOL *pSecure)
328 {
329 #if 0
330 WCHAR szBuffer[2];
331 HKEY hKey;
332 DWORD bufferSize = sizeof(szBuffer);
333 DWORD varType = REG_SZ;
334 LONG rc;
335
336 TRACE("(%p %p)\n", pWlxContext, pSecure);
337
338 *pSecure = TRUE;
339
340 /*
341 * Policy setting:
342 * HKLM\Software\Policies\Microsoft\Windows\Control Panel\Desktop : ScreenSaverIsSecure
343 * User setting:
344 * HKCU\Control Panel\Desktop : ScreenSaverIsSecure
345 */
346
347 rc = RegOpenKeyExW(HKEY_CURRENT_USER,
348 L"Control Panel\\Desktop",
349 0,
350 KEY_QUERY_VALUE,
351 &hKey);
352 TRACE("RegOpenKeyExW: %ld\n", rc);
353 if (rc == ERROR_SUCCESS)
354 {
355 rc = RegQueryValueExW(hKey,
356 L"ScreenSaverIsSecure",
357 NULL,
358 &varType,
359 (LPBYTE)szBuffer,
360 &bufferSize);
361
362 TRACE("RegQueryValueExW: %ld\n", rc);
363
364 if (rc == ERROR_SUCCESS)
365 {
366 TRACE("szBuffer: \"%S\"\n", szBuffer);
367 *pSecure = _wtoi(szBuffer);
368 }
369
370 RegCloseKey(hKey);
371 }
372
373 TRACE("*pSecure: %ld\n", *pSecure);
374 #endif
375
376 *pSecure = FALSE;
377
378 return TRUE;
379 }
380
381 /*
382 * @implemented
383 */
384 BOOL WINAPI
385 WlxStartApplication(
386 PVOID pWlxContext,
387 PWSTR pszDesktopName,
388 PVOID pEnvironment,
389 PWSTR pszCmdLine)
390 {
391 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
392 STARTUPINFOW StartupInfo;
393 PROCESS_INFORMATION ProcessInformation;
394 WCHAR CurrentDirectory[MAX_PATH];
395 HANDLE hAppToken;
396 UINT len;
397 BOOL ret;
398
399 len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH);
400 if (len == 0 || len > MAX_PATH)
401 {
402 ERR("GetWindowsDirectoryW() failed\n");
403 return FALSE;
404 }
405
406 ret = DuplicateTokenEx(pgContext->UserToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hAppToken);
407 if (!ret)
408 {
409 ERR("DuplicateTokenEx() failed with error %lu\n", GetLastError());
410 return FALSE;
411 }
412
413 ZeroMemory(&StartupInfo, sizeof(StartupInfo));
414 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
415 StartupInfo.cb = sizeof(StartupInfo);
416 StartupInfo.lpTitle = pszCmdLine;
417 StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
418 StartupInfo.wShowWindow = SW_SHOW;
419 StartupInfo.lpDesktop = pszDesktopName;
420
421 len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH);
422 if (len == 0 || len > MAX_PATH)
423 {
424 ERR("GetWindowsDirectoryW() failed\n");
425 return FALSE;
426 }
427 ret = CreateProcessAsUserW(
428 hAppToken,
429 pszCmdLine,
430 NULL,
431 NULL,
432 NULL,
433 FALSE,
434 CREATE_UNICODE_ENVIRONMENT,
435 pEnvironment,
436 CurrentDirectory,
437 &StartupInfo,
438 &ProcessInformation);
439 CloseHandle(ProcessInformation.hProcess);
440 CloseHandle(ProcessInformation.hThread);
441 CloseHandle(hAppToken);
442 if (!ret)
443 ERR("CreateProcessAsUserW() failed with error %lu\n", GetLastError());
444 return ret;
445 }
446
447 /*
448 * @implemented
449 */
450 BOOL WINAPI
451 WlxActivateUserShell(
452 PVOID pWlxContext,
453 PWSTR pszDesktopName,
454 PWSTR pszMprLogonScript,
455 PVOID pEnvironment)
456 {
457 HKEY hKey;
458 DWORD BufSize, ValueType;
459 WCHAR pszUserInitApp[MAX_PATH + 1];
460 WCHAR pszExpUserInitApp[MAX_PATH];
461 DWORD len;
462 LONG rc;
463
464 TRACE("WlxActivateUserShell()\n");
465
466 UNREFERENCED_PARAMETER(pszMprLogonScript);
467
468 /* Get the path of userinit */
469 rc = RegOpenKeyExW(
470 HKEY_LOCAL_MACHINE,
471 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
472 0,
473 KEY_QUERY_VALUE,
474 &hKey);
475 if (rc != ERROR_SUCCESS)
476 {
477 WARN("RegOpenKeyExW() failed with error %lu\n", rc);
478 return FALSE;
479 }
480
481 /* Query userinit application */
482 BufSize = sizeof(pszUserInitApp) - sizeof(UNICODE_NULL);
483 rc = RegQueryValueExW(
484 hKey,
485 L"Userinit",
486 NULL,
487 &ValueType,
488 (LPBYTE)pszUserInitApp,
489 &BufSize);
490 RegCloseKey(hKey);
491 if (rc != ERROR_SUCCESS || (ValueType != REG_SZ && ValueType != REG_EXPAND_SZ))
492 {
493 WARN("RegQueryValueExW() failed with error %lu\n", rc);
494 return FALSE;
495 }
496 pszUserInitApp[MAX_PATH] = UNICODE_NULL;
497
498 len = ExpandEnvironmentStringsW(pszUserInitApp, pszExpUserInitApp, MAX_PATH);
499 if (len > MAX_PATH)
500 {
501 WARN("ExpandEnvironmentStringsW() failed. Required size %lu\n", len);
502 return FALSE;
503 }
504
505 /* Start userinit app */
506 return WlxStartApplication(pWlxContext, pszDesktopName, pEnvironment, pszExpUserInitApp);
507 }
508
509 /*
510 * @implemented
511 */
512 int WINAPI
513 WlxLoggedOnSAS(
514 PVOID pWlxContext,
515 DWORD dwSasType,
516 PVOID pReserved)
517 {
518 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
519 INT SasAction = WLX_SAS_ACTION_NONE;
520
521 TRACE("WlxLoggedOnSAS(0x%lx)\n", dwSasType);
522
523 UNREFERENCED_PARAMETER(pReserved);
524
525 switch (dwSasType)
526 {
527 case WLX_SAS_TYPE_CTRL_ALT_DEL:
528 case WLX_SAS_TYPE_TIMEOUT:
529 {
530 SasAction = pGinaUI->LoggedOnSAS(pgContext, dwSasType);
531 break;
532 }
533 case WLX_SAS_TYPE_SC_INSERT:
534 {
535 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_INSERT not supported!\n");
536 break;
537 }
538 case WLX_SAS_TYPE_SC_REMOVE:
539 {
540 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_REMOVE not supported!\n");
541 break;
542 }
543 default:
544 {
545 WARN("WlxLoggedOnSAS: Unknown SasType: 0x%x\n", dwSasType);
546 break;
547 }
548 }
549
550 return SasAction;
551 }
552
553 /*
554 * @implemented
555 */
556 BOOL WINAPI
557 WlxDisplayStatusMessage(
558 IN PVOID pWlxContext,
559 IN HDESK hDesktop,
560 IN DWORD dwOptions,
561 IN PWSTR pTitle,
562 IN PWSTR pMessage)
563 {
564 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
565
566 TRACE("WlxDisplayStatusMessage(\"%S\")\n", pMessage);
567
568 return pGinaUI->DisplayStatusMessage(pgContext, hDesktop, dwOptions, pTitle, pMessage);
569 }
570
571 /*
572 * @implemented
573 */
574 BOOL WINAPI
575 WlxRemoveStatusMessage(
576 IN PVOID pWlxContext)
577 {
578 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
579
580 TRACE("WlxRemoveStatusMessage()\n");
581
582 return pGinaUI->RemoveStatusMessage(pgContext);
583 }
584
585 static PWSTR
586 DuplicationString(PWSTR Str)
587 {
588 DWORD cb;
589 PWSTR NewStr;
590
591 if (Str == NULL) return NULL;
592
593 cb = (wcslen(Str) + 1) * sizeof(WCHAR);
594 if ((NewStr = LocalAlloc(LMEM_FIXED, cb)))
595 memcpy(NewStr, Str, cb);
596 return NewStr;
597 }
598
599
600 BOOL
601 DoAdminUnlock(
602 IN PGINA_CONTEXT pgContext,
603 IN PWSTR UserName,
604 IN PWSTR Domain,
605 IN PWSTR Password)
606 {
607 HANDLE hToken = NULL;
608 PTOKEN_GROUPS Groups = NULL;
609 BOOL bIsAdmin = FALSE;
610 ULONG Size;
611 ULONG i;
612 NTSTATUS Status;
613
614 TRACE("(%S %S %S)\n", UserName, Domain, Password);
615
616 if (!ConnectToLsa(pgContext))
617 return FALSE;
618
619 if (!MyLogonUser(pgContext->LsaHandle,
620 pgContext->AuthenticationPackage,
621 UserName,
622 Domain,
623 Password,
624 &pgContext->UserToken))
625 {
626 WARN("LogonUserW() failed\n");
627 return FALSE;
628 }
629
630 Status = NtQueryInformationToken(hToken,
631 TokenGroups,
632 NULL,
633 0,
634 &Size);
635 if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL))
636 {
637 TRACE("NtQueryInformationToken() failed (Status 0x%08lx)\n", Status);
638 goto done;
639 }
640
641 Groups = HeapAlloc(GetProcessHeap(), 0, Size);
642 if (Groups == NULL)
643 {
644 TRACE("HeapAlloc() failed\n");
645 goto done;
646 }
647
648 Status = NtQueryInformationToken(hToken,
649 TokenGroups,
650 Groups,
651 Size,
652 &Size);
653 if (!NT_SUCCESS(Status))
654 {
655 TRACE("NtQueryInformationToken() failed (Status 0x%08lx)\n", Status);
656 goto done;
657 }
658
659 for (i = 0; i < Groups->GroupCount; i++)
660 {
661 if (RtlEqualSid(Groups->Groups[i].Sid, AdminSid))
662 {
663 TRACE("Member of Admins group\n");
664 bIsAdmin = TRUE;
665 break;
666 }
667 }
668
669 done:
670 if (Groups != NULL)
671 HeapFree(GetProcessHeap(), 0, Groups);
672
673 if (hToken != NULL)
674 CloseHandle(hToken);
675
676 return bIsAdmin;
677 }
678
679
680 BOOL
681 DoLoginTasks(
682 IN OUT PGINA_CONTEXT pgContext,
683 IN PWSTR UserName,
684 IN PWSTR Domain,
685 IN PWSTR Password)
686 {
687 LPWSTR ProfilePath = NULL;
688 LPWSTR lpEnvironment = NULL;
689 TOKEN_STATISTICS Stats;
690 PWLX_PROFILE_V2_0 pProfile = NULL;
691 DWORD cbStats, cbSize;
692 DWORD dwLength;
693 BOOL bResult;
694
695 if (!ConnectToLsa(pgContext))
696 return FALSE;
697
698 if (!MyLogonUser(pgContext->LsaHandle,
699 pgContext->AuthenticationPackage,
700 UserName,
701 Domain,
702 Password,
703 &pgContext->UserToken))
704 {
705 WARN("LogonUserW() failed\n");
706 goto cleanup;
707 }
708
709 /* Store the logon time in the context */
710 GetLocalTime(&pgContext->LogonTime);
711
712 /* Store user and domain in the context */
713 wcscpy(pgContext->UserName, UserName);
714 if (Domain == NULL || wcslen(Domain) == 0)
715 {
716 dwLength = 256;
717 GetComputerNameW(pgContext->Domain, &dwLength);
718 }
719 else
720 {
721 wcscpy(pgContext->Domain, Domain);
722 }
723
724 /* Get profile path */
725 cbSize = 0;
726 bResult = GetProfilesDirectoryW(NULL, &cbSize);
727 if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
728 {
729 ProfilePath = HeapAlloc(GetProcessHeap(), 0, cbSize * sizeof(WCHAR));
730 if (!ProfilePath)
731 {
732 WARN("HeapAlloc() failed\n");
733 goto cleanup;
734 }
735 bResult = GetProfilesDirectoryW(ProfilePath, &cbSize);
736 }
737 if (!bResult)
738 {
739 WARN("GetUserProfileDirectoryW() failed\n");
740 goto cleanup;
741 }
742
743 /* Allocate memory for profile */
744 pProfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WLX_PROFILE_V2_0));
745 if (!pProfile)
746 {
747 WARN("HeapAlloc() failed\n");
748 goto cleanup;
749 }
750 pProfile->dwType = WLX_PROFILE_TYPE_V2_0;
751 pProfile->pszProfile = ProfilePath;
752
753 lpEnvironment = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
754 (wcslen(pgContext->Domain)+ 14 + 1) * sizeof(WCHAR));
755 if (!lpEnvironment)
756 {
757 WARN("HeapAlloc() failed\n");
758 goto cleanup;
759 }
760
761 wsprintfW(lpEnvironment, L"LOGONSERVER=\\\\%s", pgContext->Domain);
762
763 pProfile->pszEnvironment = lpEnvironment;
764
765 if (!GetTokenInformation(pgContext->UserToken,
766 TokenStatistics,
767 (PVOID)&Stats,
768 sizeof(TOKEN_STATISTICS),
769 &cbStats))
770 {
771 WARN("Couldn't get Authentication id from user token!\n");
772 goto cleanup;
773 }
774
775 *pgContext->pAuthenticationId = Stats.AuthenticationId;
776 pgContext->pMprNotifyInfo->pszUserName = DuplicationString(UserName);
777 pgContext->pMprNotifyInfo->pszDomain = DuplicationString(Domain);
778 pgContext->pMprNotifyInfo->pszPassword = DuplicationString(Password);
779 pgContext->pMprNotifyInfo->pszOldPassword = NULL;
780 *pgContext->pdwOptions = 0;
781 *pgContext->pProfile = pProfile;
782 return TRUE;
783
784 cleanup:
785 if (pProfile)
786 {
787 HeapFree(GetProcessHeap(), 0, pProfile->pszEnvironment);
788 }
789 HeapFree(GetProcessHeap(), 0, pProfile);
790 HeapFree(GetProcessHeap(), 0, ProfilePath);
791 return FALSE;
792 }
793
794
795 static BOOL
796 DoAutoLogon(
797 IN PGINA_CONTEXT pgContext)
798 {
799 HKEY WinLogonKey = NULL;
800 LPWSTR AutoLogon = NULL;
801 LPWSTR AutoCount = NULL;
802 LPWSTR IgnoreShiftOverride = NULL;
803 LPWSTR UserName = NULL;
804 LPWSTR Domain = NULL;
805 LPWSTR Password = NULL;
806 BOOL result = FALSE;
807 LONG rc;
808
809 TRACE("DoAutoLogon(): AutoLogonState = %lu\n",
810 pgContext->AutoLogonState);
811
812 if (pgContext->AutoLogonState == AUTOLOGON_DISABLED)
813 return FALSE;
814
815 rc = RegOpenKeyExW(
816 HKEY_LOCAL_MACHINE,
817 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
818 0,
819 KEY_QUERY_VALUE,
820 &WinLogonKey);
821 if (rc != ERROR_SUCCESS)
822 goto cleanup;
823
824 if (pgContext->AutoLogonState == AUTOLOGON_CHECK_REGISTRY)
825 {
826 /* Set it by default to disabled, we might reenable it again later */
827 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
828
829 rc = ReadRegSzKey(WinLogonKey, L"AutoAdminLogon", &AutoLogon);
830 if (rc != ERROR_SUCCESS)
831 goto cleanup;
832 if (wcscmp(AutoLogon, L"1") != 0)
833 goto cleanup;
834
835 rc = ReadRegSzKey(WinLogonKey, L"AutoLogonCount", &AutoCount);
836 if (rc == ERROR_SUCCESS && wcscmp(AutoCount, L"0") == 0)
837 goto cleanup;
838 else if (rc != ERROR_FILE_NOT_FOUND)
839 goto cleanup;
840
841 rc = ReadRegSzKey(WinLogonKey, L"IgnoreShiftOverride", &UserName);
842 if (rc == ERROR_SUCCESS)
843 {
844 if (wcscmp(AutoLogon, L"1") != 0 && GetKeyState(VK_SHIFT) < 0)
845 goto cleanup;
846 }
847 else if (GetKeyState(VK_SHIFT) < 0)
848 {
849 /* User pressed SHIFT */
850 goto cleanup;
851 }
852
853 pgContext->AutoLogonState = AUTOLOGON_ONCE;
854 result = TRUE;
855 }
856 else /* pgContext->AutoLogonState == AUTOLOGON_ONCE */
857 {
858 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
859
860 rc = ReadRegSzKey(WinLogonKey, L"DefaultUserName", &UserName);
861 if (rc != ERROR_SUCCESS)
862 goto cleanup;
863 rc = ReadRegSzKey(WinLogonKey, L"DefaultDomain", &Domain);
864 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
865 goto cleanup;
866 rc = ReadRegSzKey(WinLogonKey, L"DefaultPassword", &Password);
867 if (rc != ERROR_SUCCESS)
868 goto cleanup;
869
870 result = DoLoginTasks(pgContext, UserName, Domain, Password);
871
872 if (result == TRUE)
873 {
874 ZeroMemory(pgContext->Password, 256 * sizeof(WCHAR));
875 wcscpy(pgContext->Password, Password);
876
877 NotifyBootConfigStatus(TRUE);
878 }
879 }
880
881 cleanup:
882 if (WinLogonKey != NULL)
883 RegCloseKey(WinLogonKey);
884 HeapFree(GetProcessHeap(), 0, AutoLogon);
885 HeapFree(GetProcessHeap(), 0, AutoCount);
886 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride);
887 HeapFree(GetProcessHeap(), 0, UserName);
888 HeapFree(GetProcessHeap(), 0, Domain);
889 HeapFree(GetProcessHeap(), 0, Password);
890 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n",
891 pgContext->AutoLogonState, result);
892 return result;
893 }
894
895 /*
896 * @implemented
897 */
898 VOID WINAPI
899 WlxDisplaySASNotice(
900 IN PVOID pWlxContext)
901 {
902 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
903
904 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext);
905
906 if (GetSystemMetrics(SM_REMOTESESSION))
907 {
908 /* User is remotely logged on. Don't display a notice */
909 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
910 return;
911 }
912
913 if (pgContext->bAutoAdminLogon == TRUE)
914 {
915 /* Don't display the window, we want to do an automatic logon */
916 pgContext->AutoLogonState = AUTOLOGON_ONCE;
917 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
918 return;
919 }
920 else
921 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
922
923 if (pgContext->bDisableCAD == TRUE)
924 {
925 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
926 return;
927 }
928
929 pGinaUI->DisplaySASNotice(pgContext);
930
931 TRACE("WlxDisplaySASNotice() done\n");
932 }
933
934 /*
935 * @implemented
936 */
937 INT WINAPI
938 WlxLoggedOutSAS(
939 IN PVOID pWlxContext,
940 IN DWORD dwSasType,
941 OUT PLUID pAuthenticationId,
942 IN OUT PSID pLogonSid,
943 OUT PDWORD pdwOptions,
944 OUT PHANDLE phToken,
945 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
946 OUT PVOID *pProfile)
947 {
948 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
949 INT res;
950
951 TRACE("WlxLoggedOutSAS()\n");
952
953 UNREFERENCED_PARAMETER(dwSasType);
954 UNREFERENCED_PARAMETER(pLogonSid);
955
956 pgContext->pAuthenticationId = pAuthenticationId;
957 pgContext->pdwOptions = pdwOptions;
958 pgContext->pMprNotifyInfo = pMprNotifyInfo;
959 pgContext->pProfile = pProfile;
960
961 if (0 == GetSystemMetrics(SM_REMOTESESSION) &&
962 DoAutoLogon(pgContext))
963 {
964 /* User is local and registry contains information
965 * to log on him automatically */
966 *phToken = pgContext->UserToken;
967 return WLX_SAS_ACTION_LOGON;
968 }
969
970 res = pGinaUI->LoggedOutSAS(pgContext);
971 *phToken = pgContext->UserToken;
972 return res;
973 }
974
975 /*
976 * @implemented
977 */
978 int WINAPI
979 WlxWkstaLockedSAS(
980 PVOID pWlxContext,
981 DWORD dwSasType)
982 {
983 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
984
985 TRACE("WlxWkstaLockedSAS()\n");
986
987 UNREFERENCED_PARAMETER(dwSasType);
988
989 return pGinaUI->LockedSAS(pgContext);
990 }
991
992
993 /*
994 * @implemented
995 */
996 VOID
997 WINAPI
998 WlxDisplayLockedNotice(PVOID pWlxContext)
999 {
1000 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
1001
1002 TRACE("WlxDisplayLockedNotice()\n");
1003
1004 if (pgContext->bDisableCAD == TRUE)
1005 {
1006 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
1007 return;
1008 }
1009
1010 pGinaUI->DisplayLockedNotice(pgContext);
1011 }
1012
1013
1014 /*
1015 * @implemented
1016 */
1017 BOOL WINAPI
1018 WlxIsLogoffOk(
1019 PVOID pWlxContext)
1020 {
1021 TRACE("WlxIsLogoffOk()\n");
1022 UNREFERENCED_PARAMETER(pWlxContext);
1023 return TRUE;
1024 }
1025
1026 BOOL WINAPI
1027 DllMain(
1028 IN HINSTANCE hinstDLL,
1029 IN DWORD dwReason,
1030 IN LPVOID lpvReserved)
1031 {
1032 UNREFERENCED_PARAMETER(lpvReserved);
1033
1034 if (dwReason == DLL_PROCESS_ATTACH)
1035 {
1036 hDllInstance = hinstDLL;
1037
1038 RtlAllocateAndInitializeSid(&SystemAuthority,
1039 2,
1040 SECURITY_BUILTIN_DOMAIN_RID,
1041 DOMAIN_ALIAS_RID_ADMINS,
1042 SECURITY_NULL_RID,
1043 SECURITY_NULL_RID,
1044 SECURITY_NULL_RID,
1045 SECURITY_NULL_RID,
1046 SECURITY_NULL_RID,
1047 SECURITY_NULL_RID,
1048 &AdminSid);
1049
1050 }
1051 else if (dwReason == DLL_PROCESS_DETACH)
1052 {
1053 if (AdminSid != NULL)
1054 RtlFreeSid(AdminSid);
1055 }
1056
1057 return TRUE;
1058 }