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