3 * Copyright (C) 2003-2004, 2006 ReactOS Team
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.
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.
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.
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)
29 HINSTANCE hDllInstance
;
31 extern GINA_UI GinaGraphicalUI
;
32 extern GINA_UI GinaTextUI
;
33 static PGINA_UI pGinaUI
;
40 IN DWORD dwWinlogonVersion
,
41 OUT PDWORD pdwDllVersion
)
43 TRACE("WlxNegotiate(%lx, %p)\n", dwWinlogonVersion
, pdwDllVersion
);
45 if(!pdwDllVersion
|| (dwWinlogonVersion
< WLX_VERSION_1_3
))
48 *pdwDllVersion
= WLX_VERSION_1_3
;
65 return ERROR_INVALID_PARAMETER
;
68 rc
= RegQueryValueExW(hKey
, pszKey
, NULL
, &dwType
, NULL
, &cbData
);
69 if (rc
!= ERROR_SUCCESS
)
72 return ERROR_FILE_NOT_FOUND
;
73 Value
= HeapAlloc(GetProcessHeap(), 0, cbData
+ sizeof(WCHAR
));
75 return ERROR_NOT_ENOUGH_MEMORY
;
76 rc
= RegQueryValueExW(hKey
, pszKey
, NULL
, NULL
, (LPBYTE
)Value
, &cbData
);
77 if (rc
!= ERROR_SUCCESS
)
79 HeapFree(GetProcessHeap(), 0, Value
);
82 /* NULL-terminate the string */
83 Value
[cbData
/ sizeof(WCHAR
)] = '\0';
92 HKEY ControlKey
= NULL
;
93 LPWSTR SystemStartOptions
= NULL
;
94 LPWSTR CurrentOption
, NextOption
; /* Pointers into SystemStartOptions */
95 BOOL ConsoleBoot
= FALSE
;
100 L
"SYSTEM\\CurrentControlSet\\Control",
105 rc
= ReadRegSzKey(ControlKey
, L
"SystemStartOptions", &SystemStartOptions
);
106 if (rc
!= ERROR_SUCCESS
)
109 /* Check for CONSOLE switch in SystemStartOptions */
110 CurrentOption
= SystemStartOptions
;
111 while (CurrentOption
)
113 NextOption
= wcschr(CurrentOption
, L
' ');
116 if (wcsicmp(CurrentOption
, L
"CONSOLE") == 0)
118 TRACE("Found %S. Switching to console boot\n", CurrentOption
);
122 CurrentOption
= NextOption
? NextOption
+ 1 : NULL
;
127 pGinaUI
= &GinaTextUI
;
129 pGinaUI
= &GinaGraphicalUI
;
131 if (ControlKey
!= NULL
)
132 RegCloseKey(ControlKey
);
133 HeapFree(GetProcessHeap(), 0, SystemStartOptions
);
144 PVOID pWinlogonFunctions
,
147 PGINA_CONTEXT pgContext
;
149 UNREFERENCED_PARAMETER(pvReserved
);
151 pgContext
= (PGINA_CONTEXT
)LocalAlloc(LMEM_FIXED
| LMEM_ZEROINIT
, sizeof(GINA_CONTEXT
));
154 WARN("LocalAlloc() failed\n");
158 /* Return the context to winlogon */
159 *pWlxContext
= (PVOID
)pgContext
;
160 pgContext
->hDllInstance
= hDllInstance
;
162 /* Save pointer to dispatch table */
163 pgContext
->pWlxFuncs
= (PWLX_DISPATCH_VERSION_1_3
)pWinlogonFunctions
;
165 /* Save the winlogon handle used to call the dispatch functions */
166 pgContext
->hWlx
= hWlx
;
168 /* Save window station */
169 pgContext
->station
= lpWinsta
;
171 /* Clear status window handle */
172 pgContext
->hStatusWindow
= 0;
174 /* Notify winlogon that we will use the default SAS */
175 pgContext
->pWlxFuncs
->WlxUseCtrlAltDel(hWlx
);
177 /* Locates the authentification package */
178 //LsaRegisterLogonProcess(...);
180 /* Check autologon settings the first time */
181 pgContext
->AutoLogonState
= AUTOLOGON_CHECK_REGISTRY
;
184 return pGinaUI
->Initialize(pgContext
);
192 WlxScreenSaverNotify(
199 DWORD bufferSize
= sizeof(szBuffer
);
200 DWORD varType
= REG_SZ
;
203 TRACE("(%p %p)\n", pWlxContext
, pSecure
);
209 * HKLM\Software\Policies\Microsoft\Windows\Control Panel\Desktop : ScreenSaverIsSecure
211 * HKCU\Control Panel\Desktop : ScreenSaverIsSecure
214 rc
= RegOpenKeyExW(HKEY_CURRENT_USER
,
215 L
"Control Panel\\Desktop",
219 TRACE("RegOpenKeyExW: %ld\n", rc
);
220 if (rc
== ERROR_SUCCESS
)
222 rc
= RegQueryValueExW(hKey
,
223 L
"ScreenSaverIsSecure",
229 TRACE("RegQueryValueExW: %ld\n", rc
);
231 if (rc
== ERROR_SUCCESS
)
233 TRACE("szBuffer: \"%S\"\n", szBuffer
);
234 *pSecure
= _wtoi(szBuffer
);
240 TRACE("*pSecure: %ld\n", *pSecure
);
254 PWSTR pszDesktopName
,
258 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
259 STARTUPINFOW StartupInfo
;
260 PROCESS_INFORMATION ProcessInformation
;
261 WCHAR CurrentDirectory
[MAX_PATH
];
266 len
= GetWindowsDirectoryW(CurrentDirectory
, MAX_PATH
);
267 if (len
== 0 || len
> MAX_PATH
)
269 ERR("GetWindowsDirectoryW() failed\n");
273 ret
= DuplicateTokenEx(pgContext
->UserToken
, MAXIMUM_ALLOWED
, NULL
, SecurityImpersonation
, TokenPrimary
, &hAppToken
);
276 ERR("DuplicateTokenEx() failed with error %lu\n", GetLastError());
280 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
281 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
282 StartupInfo
.cb
= sizeof(StartupInfo
);
283 StartupInfo
.lpTitle
= pszCmdLine
;
284 StartupInfo
.dwFlags
= STARTF_USESHOWWINDOW
;
285 StartupInfo
.wShowWindow
= SW_SHOW
;
286 StartupInfo
.lpDesktop
= pszDesktopName
;
288 len
= GetWindowsDirectoryW(CurrentDirectory
, MAX_PATH
);
289 if (len
== 0 || len
> MAX_PATH
)
291 ERR("GetWindowsDirectoryW() failed\n");
294 ret
= CreateProcessAsUserW(
301 CREATE_UNICODE_ENVIRONMENT
,
305 &ProcessInformation
);
306 CloseHandle(ProcessInformation
.hProcess
);
307 CloseHandle(ProcessInformation
.hThread
);
308 CloseHandle(hAppToken
);
310 ERR("CreateProcessAsUserW() failed with error %lu\n", GetLastError());
318 WlxActivateUserShell(
320 PWSTR pszDesktopName
,
321 PWSTR pszMprLogonScript
,
325 DWORD BufSize
, ValueType
;
326 WCHAR pszUserInitApp
[MAX_PATH
+ 1];
327 WCHAR pszExpUserInitApp
[MAX_PATH
];
331 TRACE("WlxActivateUserShell()\n");
333 UNREFERENCED_PARAMETER(pszMprLogonScript
);
335 /* Get the path of userinit */
338 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
342 if (rc
!= ERROR_SUCCESS
)
344 WARN("RegOpenKeyExW() failed with error %lu\n", rc
);
348 /* Query userinit application */
349 BufSize
= sizeof(pszUserInitApp
) - sizeof(UNICODE_NULL
);
350 rc
= RegQueryValueExW(
355 (LPBYTE
)pszUserInitApp
,
358 if (rc
!= ERROR_SUCCESS
|| (ValueType
!= REG_SZ
&& ValueType
!= REG_EXPAND_SZ
))
360 WARN("RegQueryValueExW() failed with error %lu\n", rc
);
363 pszUserInitApp
[MAX_PATH
] = UNICODE_NULL
;
365 len
= ExpandEnvironmentStringsW(pszUserInitApp
, pszExpUserInitApp
, MAX_PATH
);
368 WARN("ExpandEnvironmentStringsW() failed. Required size %lu\n", len
);
372 /* Start userinit app */
373 return WlxStartApplication(pWlxContext
, pszDesktopName
, pEnvironment
, pszExpUserInitApp
);
385 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
386 INT SasAction
= WLX_SAS_ACTION_NONE
;
388 TRACE("WlxLoggedOnSAS(0x%lx)\n", dwSasType
);
390 UNREFERENCED_PARAMETER(pReserved
);
394 case WLX_SAS_TYPE_CTRL_ALT_DEL
:
395 case WLX_SAS_TYPE_TIMEOUT
:
397 SasAction
= pGinaUI
->LoggedOnSAS(pgContext
, dwSasType
);
400 case WLX_SAS_TYPE_SC_INSERT
:
402 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_INSERT not supported!\n");
405 case WLX_SAS_TYPE_SC_REMOVE
:
407 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_REMOVE not supported!\n");
412 WARN("WlxLoggedOnSAS: Unknown SasType: 0x%x\n", dwSasType
);
424 WlxDisplayStatusMessage(
425 IN PVOID pWlxContext
,
431 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
433 TRACE("WlxDisplayStatusMessage(\"%S\")\n", pMessage
);
435 return pGinaUI
->DisplayStatusMessage(pgContext
, hDesktop
, dwOptions
, pTitle
, pMessage
);
442 WlxRemoveStatusMessage(
443 IN PVOID pWlxContext
)
445 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
447 TRACE("WlxRemoveStatusMessage()\n");
449 return pGinaUI
->RemoveStatusMessage(pgContext
);
453 DuplicationString(PWSTR Str
)
458 if (Str
== NULL
) return NULL
;
460 cb
= (wcslen(Str
) + 1) * sizeof(WCHAR
);
461 if ((NewStr
= LocalAlloc(LMEM_FIXED
, cb
)))
462 memcpy(NewStr
, Str
, cb
);
468 IN OUT PGINA_CONTEXT pgContext
,
473 LPWSTR ProfilePath
= NULL
;
474 LPWSTR lpEnvironment
= NULL
;
475 TOKEN_STATISTICS Stats
;
476 PWLX_PROFILE_V2_0 pProfile
= NULL
;
477 DWORD cbStats
, cbSize
;
481 if (!LogonUserW(UserName
, Domain
, Password
,
482 LOGON32_LOGON_INTERACTIVE
,
483 LOGON32_PROVIDER_DEFAULT
,
484 &pgContext
->UserToken
))
486 WARN("LogonUserW() failed\n");
490 /* Store the logon time in the context */
491 GetLocalTime(&pgContext
->LogonTime
);
493 /* Store user and domain in the context */
494 wcscpy(pgContext
->UserName
, UserName
);
495 if (Domain
== NULL
|| wcslen(Domain
) == 0)
498 GetComputerNameW(pgContext
->Domain
, &dwLength
);
502 wcscpy(pgContext
->Domain
, Domain
);
505 /* Get profile path */
507 bResult
= GetProfilesDirectoryW(NULL
, &cbSize
);
508 if (!bResult
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
510 ProfilePath
= HeapAlloc(GetProcessHeap(), 0, cbSize
* sizeof(WCHAR
));
513 WARN("HeapAlloc() failed\n");
516 bResult
= GetProfilesDirectoryW(ProfilePath
, &cbSize
);
520 WARN("GetUserProfileDirectoryW() failed\n");
524 /* Allocate memory for profile */
525 pProfile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WLX_PROFILE_V2_0
));
528 WARN("HeapAlloc() failed\n");
531 pProfile
->dwType
= WLX_PROFILE_TYPE_V2_0
;
532 pProfile
->pszProfile
= ProfilePath
;
534 lpEnvironment
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
535 (wcslen(pgContext
->Domain
)+ 14 + 1) * sizeof(WCHAR
));
538 WARN("HeapAlloc() failed\n");
542 wsprintfW(lpEnvironment
, L
"LOGONSERVER=\\\\%s", pgContext
->Domain
);
544 pProfile
->pszEnvironment
= lpEnvironment
;
546 if (!GetTokenInformation(pgContext
->UserToken
,
549 sizeof(TOKEN_STATISTICS
),
552 WARN("Couldn't get Authentication id from user token!\n");
556 *pgContext
->pAuthenticationId
= Stats
.AuthenticationId
;
557 pgContext
->pMprNotifyInfo
->pszUserName
= DuplicationString(UserName
);
558 pgContext
->pMprNotifyInfo
->pszDomain
= DuplicationString(Domain
);
559 pgContext
->pMprNotifyInfo
->pszPassword
= DuplicationString(Password
);
560 pgContext
->pMprNotifyInfo
->pszOldPassword
= NULL
;
561 *pgContext
->pdwOptions
= 0;
562 *pgContext
->pProfile
= pProfile
;
568 HeapFree(GetProcessHeap(), 0, pProfile
->pszEnvironment
);
570 HeapFree(GetProcessHeap(), 0, pProfile
);
571 HeapFree(GetProcessHeap(), 0, ProfilePath
);
579 IN PGINA_CONTEXT pgContext
)
581 HKEY WinLogonKey
= NULL
;
582 LPWSTR AutoLogon
= NULL
;
586 if (pgContext
->AutoLogonState
== AUTOLOGON_DISABLED
)
589 rc
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
590 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
594 if (rc
!= ERROR_SUCCESS
)
597 rc
= ReadRegSzKey(WinLogonKey
,
601 if (rc
!= ERROR_SUCCESS
)
604 if (wcscmp(AutoLogon
, L
"1") == 0)
608 if (WinLogonKey
!= NULL
)
609 RegCloseKey(WinLogonKey
);
610 HeapFree(GetProcessHeap(), 0, AutoLogon
);
618 IN PGINA_CONTEXT pgContext
)
620 HKEY WinLogonKey
= NULL
;
621 LPWSTR AutoLogon
= NULL
;
622 LPWSTR AutoCount
= NULL
;
623 LPWSTR IgnoreShiftOverride
= NULL
;
624 LPWSTR UserName
= NULL
;
625 LPWSTR DomainName
= NULL
;
626 LPWSTR Password
= NULL
;
630 TRACE("DoAutoLogon(): AutoLogonState = %lu\n",
631 pgContext
->AutoLogonState
);
633 if (pgContext
->AutoLogonState
== AUTOLOGON_DISABLED
)
638 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
642 if (rc
!= ERROR_SUCCESS
)
645 if (pgContext
->AutoLogonState
== AUTOLOGON_CHECK_REGISTRY
)
647 /* Set it by default to disabled, we might reenable it again later */
648 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
650 rc
= ReadRegSzKey(WinLogonKey
, L
"AutoAdminLogon", &AutoLogon
);
651 if (rc
!= ERROR_SUCCESS
)
653 if (wcscmp(AutoLogon
, L
"1") != 0)
656 rc
= ReadRegSzKey(WinLogonKey
, L
"AutoLogonCount", &AutoCount
);
657 if (rc
== ERROR_SUCCESS
&& wcscmp(AutoCount
, L
"0") == 0)
659 else if (rc
!= ERROR_FILE_NOT_FOUND
)
662 rc
= ReadRegSzKey(WinLogonKey
, L
"IgnoreShiftOverride", &UserName
);
663 if (rc
== ERROR_SUCCESS
)
665 if (wcscmp(AutoLogon
, L
"1") != 0 && GetKeyState(VK_SHIFT
) < 0)
668 else if (GetKeyState(VK_SHIFT
) < 0)
670 /* User pressed SHIFT */
674 pgContext
->AutoLogonState
= AUTOLOGON_ONCE
;
677 else /* pgContext->AutoLogonState == AUTOLOGON_ONCE */
679 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
681 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultUserName", &UserName
);
682 if (rc
!= ERROR_SUCCESS
)
684 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultDomainName", &DomainName
);
685 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
687 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultPassword", &Password
);
688 if (rc
!= ERROR_SUCCESS
)
691 result
= DoLoginTasks(pgContext
, UserName
, DomainName
, Password
);
694 NotifyBootConfigStatus(TRUE
);
698 if (WinLogonKey
!= NULL
)
699 RegCloseKey(WinLogonKey
);
700 HeapFree(GetProcessHeap(), 0, AutoLogon
);
701 HeapFree(GetProcessHeap(), 0, AutoCount
);
702 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride
);
703 HeapFree(GetProcessHeap(), 0, UserName
);
704 HeapFree(GetProcessHeap(), 0, DomainName
);
705 HeapFree(GetProcessHeap(), 0, Password
);
706 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n",
707 pgContext
->AutoLogonState
, result
);
716 IN PVOID pWlxContext
)
718 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
720 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext
);
722 if (GetSystemMetrics(SM_REMOTESESSION
))
724 /* User is remotely logged on. Don't display a notice */
725 pgContext
->pWlxFuncs
->WlxSasNotify(pgContext
->hWlx
, WLX_SAS_TYPE_CTRL_ALT_DEL
);
729 if (CheckAutoAdminLogon(pgContext
))
731 /* Don't display the window, we want to do an automatic logon */
732 pgContext
->AutoLogonState
= AUTOLOGON_ONCE
;
733 pgContext
->pWlxFuncs
->WlxSasNotify(pgContext
->hWlx
, WLX_SAS_TYPE_CTRL_ALT_DEL
);
737 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
739 pGinaUI
->DisplaySASNotice(pgContext
);
741 TRACE("WlxDisplaySASNotice() done\n");
749 IN PVOID pWlxContext
,
751 OUT PLUID pAuthenticationId
,
752 IN OUT PSID pLogonSid
,
753 OUT PDWORD pdwOptions
,
755 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo
,
758 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
761 TRACE("WlxLoggedOutSAS()\n");
763 UNREFERENCED_PARAMETER(dwSasType
);
764 UNREFERENCED_PARAMETER(pLogonSid
);
766 pgContext
->pAuthenticationId
= pAuthenticationId
;
767 pgContext
->pdwOptions
= pdwOptions
;
768 pgContext
->pMprNotifyInfo
= pMprNotifyInfo
;
769 pgContext
->pProfile
= pProfile
;
771 if (0 == GetSystemMetrics(SM_REMOTESESSION
) &&
772 DoAutoLogon(pgContext
))
774 /* User is local and registry contains information
775 * to log on him automatically */
776 *phToken
= pgContext
->UserToken
;
777 return WLX_SAS_ACTION_LOGON
;
780 res
= pGinaUI
->LoggedOutSAS(pgContext
);
781 *phToken
= pgContext
->UserToken
;
793 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
795 TRACE("WlxWkstaLockedSAS()\n");
797 UNREFERENCED_PARAMETER(dwSasType
);
799 return pGinaUI
->LockedSAS(pgContext
);
808 WlxDisplayLockedNotice(PVOID pWlxContext
)
810 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
812 TRACE("WlxDisplayLockedNotice()\n");
814 pGinaUI
->DisplayLockedNotice(pgContext
);
825 TRACE("WlxIsLogoffOk()\n");
826 UNREFERENCED_PARAMETER(pWlxContext
);
832 IN HINSTANCE hinstDLL
,
834 IN LPVOID lpvReserved
)
836 UNREFERENCED_PARAMETER(lpvReserved
);
838 if (dwReason
== DLL_PROCESS_ATTACH
)
839 hDllInstance
= hinstDLL
;