[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 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 pgContext->Password = HeapAlloc(GetProcessHeap(),
875 HEAP_ZERO_MEMORY,
876 (wcslen(Password) + 1) * sizeof(WCHAR));
877 if (pgContext->Password != NULL)
878 wcscpy(pgContext->Password, Password);
879
880 NotifyBootConfigStatus(TRUE);
881 }
882 }
883
884 cleanup:
885 if (WinLogonKey != NULL)
886 RegCloseKey(WinLogonKey);
887 HeapFree(GetProcessHeap(), 0, AutoLogon);
888 HeapFree(GetProcessHeap(), 0, AutoCount);
889 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride);
890 HeapFree(GetProcessHeap(), 0, UserName);
891 HeapFree(GetProcessHeap(), 0, Domain);
892 HeapFree(GetProcessHeap(), 0, Password);
893 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n",
894 pgContext->AutoLogonState, result);
895 return result;
896 }
897
898 /*
899 * @implemented
900 */
901 VOID WINAPI
902 WlxDisplaySASNotice(
903 IN PVOID pWlxContext)
904 {
905 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
906
907 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext);
908
909 if (GetSystemMetrics(SM_REMOTESESSION))
910 {
911 /* User is remotely logged on. Don't display a notice */
912 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
913 return;
914 }
915
916 if (pgContext->bAutoAdminLogon == TRUE)
917 {
918 /* Don't display the window, we want to do an automatic logon */
919 pgContext->AutoLogonState = AUTOLOGON_ONCE;
920 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
921 return;
922 }
923 else
924 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
925
926 if (pgContext->bDisableCAD == TRUE)
927 {
928 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
929 return;
930 }
931
932 pGinaUI->DisplaySASNotice(pgContext);
933
934 TRACE("WlxDisplaySASNotice() done\n");
935 }
936
937 /*
938 * @implemented
939 */
940 INT WINAPI
941 WlxLoggedOutSAS(
942 IN PVOID pWlxContext,
943 IN DWORD dwSasType,
944 OUT PLUID pAuthenticationId,
945 IN OUT PSID pLogonSid,
946 OUT PDWORD pdwOptions,
947 OUT PHANDLE phToken,
948 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
949 OUT PVOID *pProfile)
950 {
951 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
952 INT res;
953
954 TRACE("WlxLoggedOutSAS()\n");
955
956 UNREFERENCED_PARAMETER(dwSasType);
957 UNREFERENCED_PARAMETER(pLogonSid);
958
959 pgContext->pAuthenticationId = pAuthenticationId;
960 pgContext->pdwOptions = pdwOptions;
961 pgContext->pMprNotifyInfo = pMprNotifyInfo;
962 pgContext->pProfile = pProfile;
963
964 if (0 == GetSystemMetrics(SM_REMOTESESSION) &&
965 DoAutoLogon(pgContext))
966 {
967 /* User is local and registry contains information
968 * to log on him automatically */
969 *phToken = pgContext->UserToken;
970 return WLX_SAS_ACTION_LOGON;
971 }
972
973 res = pGinaUI->LoggedOutSAS(pgContext);
974 *phToken = pgContext->UserToken;
975 return res;
976 }
977
978 /*
979 * @implemented
980 */
981 int WINAPI
982 WlxWkstaLockedSAS(
983 PVOID pWlxContext,
984 DWORD dwSasType)
985 {
986 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
987
988 TRACE("WlxWkstaLockedSAS()\n");
989
990 UNREFERENCED_PARAMETER(dwSasType);
991
992 return pGinaUI->LockedSAS(pgContext);
993 }
994
995
996 /*
997 * @implemented
998 */
999 VOID
1000 WINAPI
1001 WlxDisplayLockedNotice(PVOID pWlxContext)
1002 {
1003 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
1004
1005 TRACE("WlxDisplayLockedNotice()\n");
1006
1007 if (pgContext->bDisableCAD == TRUE)
1008 {
1009 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
1010 return;
1011 }
1012
1013 pGinaUI->DisplayLockedNotice(pgContext);
1014 }
1015
1016
1017 /*
1018 * @implemented
1019 */
1020 BOOL WINAPI
1021 WlxIsLogoffOk(
1022 PVOID pWlxContext)
1023 {
1024 TRACE("WlxIsLogoffOk()\n");
1025 UNREFERENCED_PARAMETER(pWlxContext);
1026 return TRUE;
1027 }
1028
1029 BOOL WINAPI
1030 DllMain(
1031 IN HINSTANCE hinstDLL,
1032 IN DWORD dwReason,
1033 IN LPVOID lpvReserved)
1034 {
1035 UNREFERENCED_PARAMETER(lpvReserved);
1036
1037 if (dwReason == DLL_PROCESS_ATTACH)
1038 {
1039 hDllInstance = hinstDLL;
1040
1041 RtlAllocateAndInitializeSid(&SystemAuthority,
1042 2,
1043 SECURITY_BUILTIN_DOMAIN_RID,
1044 DOMAIN_ALIAS_RID_ADMINS,
1045 SECURITY_NULL_RID,
1046 SECURITY_NULL_RID,
1047 SECURITY_NULL_RID,
1048 SECURITY_NULL_RID,
1049 SECURITY_NULL_RID,
1050 SECURITY_NULL_RID,
1051 &AdminSid);
1052
1053 }
1054 else if (dwReason == DLL_PROCESS_DETACH)
1055 {
1056 if (AdminSid != NULL)
1057 RtlFreeSid(AdminSid);
1058 }
1059
1060 return TRUE;
1061 }