6974725befc36709737b28310d4888ce723cbc0c
[reactos.git] / dll / win32 / msgina / msgina.c
1 /*
2 * ReactOS GINA
3 * Copyright (C) 2003-2004, 2006 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * PROJECT: ReactOS msgina.dll
21 * FILE: dll/win32/msgina/msgina.c
22 * PURPOSE: ReactOS Logon GINA DLL
23 * PROGRAMMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
24 * Hervé Poussineau (hpoussin@reactos.org)
25 */
26
27 #include "msgina.h"
28
29 #include <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 LONG
61 ReadRegSzValue(
62 IN HKEY hKey,
63 IN LPCWSTR pszValue,
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, pszValue, 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, pszValue, 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 ReadRegDwordValue(
98 IN HKEY hKey,
99 IN LPCWSTR pszValue,
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, pszValue, 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 = ReadRegSzValue(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 = ReadRegSzValue(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 = ReadRegDwordValue(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 = ReadRegSzValue(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 = ReadRegSzValue(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 NTSTATUS
690 DoLoginTasks(
691 IN OUT PGINA_CONTEXT pgContext,
692 IN PWSTR UserName,
693 IN PWSTR Domain,
694 IN PWSTR Password,
695 OUT PNTSTATUS SubStatus)
696 {
697 NTSTATUS Status;
698
699 Status = ConnectToLsa(pgContext);
700 if (!NT_SUCCESS(Status))
701 {
702 WARN("ConnectToLsa() failed (Status 0x%08lx)\n", Status);
703 return Status;
704 }
705
706 Status = MyLogonUser(pgContext->LsaHandle,
707 pgContext->AuthenticationPackage,
708 UserName,
709 Domain,
710 Password,
711 &pgContext->UserToken,
712 SubStatus);
713 if (!NT_SUCCESS(Status))
714 {
715 WARN("MyLogonUser() failed (Status 0x%08lx)\n", Status);
716 }
717
718 return Status;
719 }
720
721
722 BOOL
723 CreateProfile(
724 IN OUT PGINA_CONTEXT pgContext,
725 IN PWSTR UserName,
726 IN PWSTR Domain,
727 IN PWSTR Password)
728 {
729 LPWSTR ProfilePath = NULL;
730 LPWSTR lpEnvironment = NULL;
731 TOKEN_STATISTICS Stats;
732 PWLX_PROFILE_V2_0 pProfile = NULL;
733 DWORD cbStats, cbSize;
734 DWORD dwLength;
735 BOOL bResult;
736
737 /* Store the logon time in the context */
738 GetLocalTime(&pgContext->LogonTime);
739
740 /* Store user and domain in the context */
741 wcscpy(pgContext->UserName, UserName);
742 if (Domain == NULL || wcslen(Domain) == 0)
743 {
744 dwLength = 256;
745 GetComputerNameW(pgContext->Domain, &dwLength);
746 }
747 else
748 {
749 wcscpy(pgContext->Domain, Domain);
750 }
751
752 /* Get profile path */
753 cbSize = 0;
754 bResult = GetProfilesDirectoryW(NULL, &cbSize);
755 if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
756 {
757 ProfilePath = HeapAlloc(GetProcessHeap(), 0, cbSize * sizeof(WCHAR));
758 if (!ProfilePath)
759 {
760 WARN("HeapAlloc() failed\n");
761 goto cleanup;
762 }
763 bResult = GetProfilesDirectoryW(ProfilePath, &cbSize);
764 }
765 if (!bResult)
766 {
767 WARN("GetUserProfileDirectoryW() failed\n");
768 goto cleanup;
769 }
770
771 /* Allocate memory for profile */
772 pProfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WLX_PROFILE_V2_0));
773 if (!pProfile)
774 {
775 WARN("HeapAlloc() failed\n");
776 goto cleanup;
777 }
778 pProfile->dwType = WLX_PROFILE_TYPE_V2_0;
779 pProfile->pszProfile = ProfilePath;
780
781 lpEnvironment = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
782 (wcslen(pgContext->Domain)+ 14 + 1) * sizeof(WCHAR));
783 if (!lpEnvironment)
784 {
785 WARN("HeapAlloc() failed\n");
786 goto cleanup;
787 }
788
789 wsprintfW(lpEnvironment, L"LOGONSERVER=\\\\%s", pgContext->Domain);
790
791 pProfile->pszEnvironment = lpEnvironment;
792
793 if (!GetTokenInformation(pgContext->UserToken,
794 TokenStatistics,
795 (PVOID)&Stats,
796 sizeof(TOKEN_STATISTICS),
797 &cbStats))
798 {
799 WARN("Couldn't get Authentication id from user token!\n");
800 goto cleanup;
801 }
802
803 *pgContext->pAuthenticationId = Stats.AuthenticationId;
804 pgContext->pMprNotifyInfo->pszUserName = DuplicationString(UserName);
805 pgContext->pMprNotifyInfo->pszDomain = DuplicationString(Domain);
806 pgContext->pMprNotifyInfo->pszPassword = DuplicationString(Password);
807 pgContext->pMprNotifyInfo->pszOldPassword = NULL;
808 *pgContext->pdwOptions = 0;
809 *pgContext->pProfile = pProfile;
810 return TRUE;
811
812 cleanup:
813 if (pProfile)
814 {
815 HeapFree(GetProcessHeap(), 0, pProfile->pszEnvironment);
816 }
817 HeapFree(GetProcessHeap(), 0, pProfile);
818 HeapFree(GetProcessHeap(), 0, ProfilePath);
819 return FALSE;
820 }
821
822
823 static BOOL
824 DoAutoLogon(
825 IN PGINA_CONTEXT pgContext)
826 {
827 HKEY WinLogonKey = NULL;
828 LPWSTR AutoLogon = NULL;
829 LPWSTR AutoCount = NULL;
830 LPWSTR IgnoreShiftOverride = NULL;
831 LPWSTR UserName = NULL;
832 LPWSTR Domain = NULL;
833 LPWSTR Password = NULL;
834 BOOL result = FALSE;
835 LONG rc;
836 NTSTATUS Status;
837 NTSTATUS SubStatus = STATUS_SUCCESS;
838
839 TRACE("DoAutoLogon(): AutoLogonState = %lu\n",
840 pgContext->AutoLogonState);
841
842 if (pgContext->AutoLogonState == AUTOLOGON_DISABLED)
843 return FALSE;
844
845 rc = RegOpenKeyExW(
846 HKEY_LOCAL_MACHINE,
847 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
848 0,
849 KEY_QUERY_VALUE,
850 &WinLogonKey);
851 if (rc != ERROR_SUCCESS)
852 goto cleanup;
853
854 if (pgContext->AutoLogonState == AUTOLOGON_CHECK_REGISTRY)
855 {
856 /* Set it by default to disabled, we might reenable it again later */
857 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
858
859 rc = ReadRegSzValue(WinLogonKey, L"AutoAdminLogon", &AutoLogon);
860 if (rc != ERROR_SUCCESS)
861 goto cleanup;
862 if (wcscmp(AutoLogon, L"1") != 0)
863 goto cleanup;
864
865 rc = ReadRegSzValue(WinLogonKey, L"AutoLogonCount", &AutoCount);
866 if (rc == ERROR_SUCCESS && wcscmp(AutoCount, L"0") == 0)
867 goto cleanup;
868 else if (rc != ERROR_FILE_NOT_FOUND)
869 goto cleanup;
870
871 rc = ReadRegSzValue(WinLogonKey, L"IgnoreShiftOverride", &UserName);
872 if (rc == ERROR_SUCCESS)
873 {
874 if (wcscmp(AutoLogon, L"1") != 0 && GetKeyState(VK_SHIFT) < 0)
875 goto cleanup;
876 }
877 else if (GetKeyState(VK_SHIFT) < 0)
878 {
879 /* User pressed SHIFT */
880 goto cleanup;
881 }
882
883 pgContext->AutoLogonState = AUTOLOGON_ONCE;
884 result = TRUE;
885 }
886 else /* pgContext->AutoLogonState == AUTOLOGON_ONCE */
887 {
888 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
889
890 rc = ReadRegSzValue(WinLogonKey, L"DefaultUserName", &UserName);
891 if (rc != ERROR_SUCCESS)
892 goto cleanup;
893 rc = ReadRegSzValue(WinLogonKey, L"DefaultDomain", &Domain);
894 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
895 goto cleanup;
896 rc = ReadRegSzValue(WinLogonKey, L"DefaultPassword", &Password);
897 if (rc != ERROR_SUCCESS)
898 goto cleanup;
899
900 Status = DoLoginTasks(pgContext, UserName, Domain, Password, &SubStatus);
901 if (!NT_SUCCESS(Status))
902 {
903 /* FIXME: Handle errors!!! */
904 result = FALSE;
905 goto cleanup;
906 }
907
908 result = CreateProfile(pgContext, UserName, Domain, Password);
909 if (result == TRUE)
910 {
911 ZeroMemory(pgContext->Password, 256 * sizeof(WCHAR));
912 wcscpy(pgContext->Password, Password);
913
914 NotifyBootConfigStatus(TRUE);
915 }
916 }
917
918 cleanup:
919 if (WinLogonKey != NULL)
920 RegCloseKey(WinLogonKey);
921 HeapFree(GetProcessHeap(), 0, AutoLogon);
922 HeapFree(GetProcessHeap(), 0, AutoCount);
923 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride);
924 HeapFree(GetProcessHeap(), 0, UserName);
925 HeapFree(GetProcessHeap(), 0, Domain);
926 HeapFree(GetProcessHeap(), 0, Password);
927 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n",
928 pgContext->AutoLogonState, result);
929 return result;
930 }
931
932 /*
933 * @implemented
934 */
935 VOID WINAPI
936 WlxDisplaySASNotice(
937 IN PVOID pWlxContext)
938 {
939 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
940
941 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext);
942
943 if (GetSystemMetrics(SM_REMOTESESSION))
944 {
945 /* User is remotely logged on. Don't display a notice */
946 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
947 return;
948 }
949
950 if (pgContext->bAutoAdminLogon == TRUE)
951 {
952 /* Don't display the window, we want to do an automatic logon */
953 pgContext->AutoLogonState = AUTOLOGON_ONCE;
954 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
955 return;
956 }
957 else
958 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
959
960 if (pgContext->bDisableCAD == TRUE)
961 {
962 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
963 return;
964 }
965
966 pGinaUI->DisplaySASNotice(pgContext);
967
968 TRACE("WlxDisplaySASNotice() done\n");
969 }
970
971 /*
972 * @implemented
973 */
974 INT WINAPI
975 WlxLoggedOutSAS(
976 IN PVOID pWlxContext,
977 IN DWORD dwSasType,
978 OUT PLUID pAuthenticationId,
979 IN OUT PSID pLogonSid,
980 OUT PDWORD pdwOptions,
981 OUT PHANDLE phToken,
982 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
983 OUT PVOID *pProfile)
984 {
985 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
986 INT res;
987
988 TRACE("WlxLoggedOutSAS()\n");
989
990 UNREFERENCED_PARAMETER(dwSasType);
991 UNREFERENCED_PARAMETER(pLogonSid);
992
993 pgContext->pAuthenticationId = pAuthenticationId;
994 pgContext->pdwOptions = pdwOptions;
995 pgContext->pMprNotifyInfo = pMprNotifyInfo;
996 pgContext->pProfile = pProfile;
997
998 if (0 == GetSystemMetrics(SM_REMOTESESSION) &&
999 DoAutoLogon(pgContext))
1000 {
1001 /* User is local and registry contains information
1002 * to log on him automatically */
1003 *phToken = pgContext->UserToken;
1004 return WLX_SAS_ACTION_LOGON;
1005 }
1006
1007 res = pGinaUI->LoggedOutSAS(pgContext);
1008 *phToken = pgContext->UserToken;
1009 return res;
1010 }
1011
1012 /*
1013 * @implemented
1014 */
1015 int WINAPI
1016 WlxWkstaLockedSAS(
1017 PVOID pWlxContext,
1018 DWORD dwSasType)
1019 {
1020 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
1021
1022 TRACE("WlxWkstaLockedSAS()\n");
1023
1024 UNREFERENCED_PARAMETER(dwSasType);
1025
1026 return pGinaUI->LockedSAS(pgContext);
1027 }
1028
1029
1030 /*
1031 * @implemented
1032 */
1033 VOID
1034 WINAPI
1035 WlxDisplayLockedNotice(PVOID pWlxContext)
1036 {
1037 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
1038
1039 TRACE("WlxDisplayLockedNotice()\n");
1040
1041 if (pgContext->bDisableCAD == TRUE)
1042 {
1043 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
1044 return;
1045 }
1046
1047 pGinaUI->DisplayLockedNotice(pgContext);
1048 }
1049
1050
1051 /*
1052 * @implemented
1053 */
1054 BOOL WINAPI
1055 WlxIsLogoffOk(
1056 PVOID pWlxContext)
1057 {
1058 TRACE("WlxIsLogoffOk()\n");
1059 UNREFERENCED_PARAMETER(pWlxContext);
1060 return TRUE;
1061 }
1062
1063 BOOL WINAPI
1064 DllMain(
1065 IN HINSTANCE hinstDLL,
1066 IN DWORD dwReason,
1067 IN LPVOID lpvReserved)
1068 {
1069 UNREFERENCED_PARAMETER(lpvReserved);
1070
1071 if (dwReason == DLL_PROCESS_ATTACH)
1072 {
1073 hDllInstance = hinstDLL;
1074
1075 RtlAllocateAndInitializeSid(&SystemAuthority,
1076 2,
1077 SECURITY_BUILTIN_DOMAIN_RID,
1078 DOMAIN_ALIAS_RID_ADMINS,
1079 SECURITY_NULL_RID,
1080 SECURITY_NULL_RID,
1081 SECURITY_NULL_RID,
1082 SECURITY_NULL_RID,
1083 SECURITY_NULL_RID,
1084 SECURITY_NULL_RID,
1085 &AdminSid);
1086
1087 }
1088 else if (dwReason == DLL_PROCESS_DETACH)
1089 {
1090 if (AdminSid != NULL)
1091 RtlFreeSid(AdminSid);
1092 }
1093
1094 return TRUE;
1095 }