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 WINE_DEFAULT_DEBUG_CHANNEL(msgina
);
31 HINSTANCE hDllInstance
;
33 extern GINA_UI GinaGraphicalUI
;
34 extern GINA_UI GinaTextUI
;
35 static PGINA_UI pGinaUI
;
42 IN DWORD dwWinlogonVersion
,
43 OUT PDWORD pdwDllVersion
)
45 TRACE("WlxNegotiate(%lx, %p)\n", dwWinlogonVersion
, pdwDllVersion
);
47 if(!pdwDllVersion
|| (dwWinlogonVersion
< WLX_VERSION_1_3
))
50 *pdwDllVersion
= WLX_VERSION_1_3
;
67 return ERROR_INVALID_PARAMETER
;
70 rc
= RegQueryValueExW(hKey
, pszKey
, NULL
, &dwType
, NULL
, &cbData
);
71 if (rc
!= ERROR_SUCCESS
)
74 return ERROR_FILE_NOT_FOUND
;
75 Value
= HeapAlloc(GetProcessHeap(), 0, cbData
+ sizeof(WCHAR
));
77 return ERROR_NOT_ENOUGH_MEMORY
;
78 rc
= RegQueryValueExW(hKey
, pszKey
, NULL
, NULL
, (LPBYTE
)Value
, &cbData
);
79 if (rc
!= ERROR_SUCCESS
)
81 HeapFree(GetProcessHeap(), 0, Value
);
84 /* NULL-terminate the string */
85 Value
[cbData
/ sizeof(WCHAR
)] = '\0';
94 HKEY ControlKey
= NULL
;
95 LPWSTR SystemStartOptions
= NULL
;
96 LPWSTR CurrentOption
, NextOption
; /* Pointers into SystemStartOptions */
97 BOOL ConsoleBoot
= FALSE
;
102 L
"SYSTEM\\CurrentControlSet\\Control",
107 rc
= ReadRegSzKey(ControlKey
, L
"SystemStartOptions", &SystemStartOptions
);
108 if (rc
!= ERROR_SUCCESS
)
111 /* Check for CONSOLE switch in SystemStartOptions */
112 CurrentOption
= SystemStartOptions
;
113 while (CurrentOption
)
115 NextOption
= wcschr(CurrentOption
, L
' ');
118 if (wcsicmp(CurrentOption
, L
"CONSOLE") == 0)
120 TRACE("Found %S. Switching to console boot\n", CurrentOption
);
124 CurrentOption
= NextOption
? NextOption
+ 1 : NULL
;
129 pGinaUI
= &GinaTextUI
;
131 pGinaUI
= &GinaGraphicalUI
;
133 if (ControlKey
!= NULL
)
134 RegCloseKey(ControlKey
);
135 HeapFree(GetProcessHeap(), 0, SystemStartOptions
);
146 PVOID pWinlogonFunctions
,
149 PGINA_CONTEXT pgContext
;
151 UNREFERENCED_PARAMETER(pvReserved
);
153 pgContext
= (PGINA_CONTEXT
)LocalAlloc(LMEM_FIXED
| LMEM_ZEROINIT
, sizeof(GINA_CONTEXT
));
156 WARN("LocalAlloc() failed\n");
160 /* Return the context to winlogon */
161 *pWlxContext
= (PVOID
)pgContext
;
162 pgContext
->hDllInstance
= hDllInstance
;
164 /* Save pointer to dispatch table */
165 pgContext
->pWlxFuncs
= (PWLX_DISPATCH_VERSION_1_3
)pWinlogonFunctions
;
167 /* Save the winlogon handle used to call the dispatch functions */
168 pgContext
->hWlx
= hWlx
;
170 /* Save window station */
171 pgContext
->station
= lpWinsta
;
173 /* Clear status window handle */
174 pgContext
->hStatusWindow
= 0;
176 /* Notify winlogon that we will use the default SAS */
177 pgContext
->pWlxFuncs
->WlxUseCtrlAltDel(hWlx
);
179 /* Locates the authentification package */
180 //LsaRegisterLogonProcess(...);
182 /* Check autologon settings the first time */
183 pgContext
->AutoLogonState
= AUTOLOGON_CHECK_REGISTRY
;
186 return pGinaUI
->Initialize(pgContext
);
194 WlxScreenSaverNotify(
201 DWORD bufferSize
= sizeof(szBuffer
);
202 DWORD varType
= REG_SZ
;
205 TRACE("(%p %p)\n", pWlxContext
, pSecure
);
211 * HKLM\Software\Policies\Microsoft\Windows\Control Panel\Desktop : ScreenSaverIsSecure
213 * HKCU\Control Panel\Desktop : ScreenSaverIsSecure
216 rc
= RegOpenKeyExW(HKEY_CURRENT_USER
,
217 L
"Control Panel\\Desktop",
221 TRACE("RegOpenKeyExW: %ld\n", rc
);
222 if (rc
== ERROR_SUCCESS
)
224 rc
= RegQueryValueExW(hKey
,
225 L
"ScreenSaverIsSecure",
231 TRACE("RegQueryValueExW: %ld\n", rc
);
233 if (rc
== ERROR_SUCCESS
)
235 TRACE("szBuffer: \"%S\"\n", szBuffer
);
236 *pSecure
= _wtoi(szBuffer
);
242 TRACE("*pSecure: %ld\n", *pSecure
);
256 PWSTR pszDesktopName
,
260 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
261 STARTUPINFOW StartupInfo
;
262 PROCESS_INFORMATION ProcessInformation
;
263 WCHAR CurrentDirectory
[MAX_PATH
];
268 len
= GetWindowsDirectoryW(CurrentDirectory
, MAX_PATH
);
269 if (len
== 0 || len
> MAX_PATH
)
271 ERR("GetWindowsDirectoryW() failed\n");
275 ret
= DuplicateTokenEx(pgContext
->UserToken
, MAXIMUM_ALLOWED
, NULL
, SecurityImpersonation
, TokenPrimary
, &hAppToken
);
278 ERR("DuplicateTokenEx() failed with error %lu\n", GetLastError());
282 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
283 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
284 StartupInfo
.cb
= sizeof(StartupInfo
);
285 StartupInfo
.lpTitle
= pszCmdLine
;
286 StartupInfo
.dwFlags
= STARTF_USESHOWWINDOW
;
287 StartupInfo
.wShowWindow
= SW_SHOW
;
288 StartupInfo
.lpDesktop
= pszDesktopName
;
290 len
= GetWindowsDirectoryW(CurrentDirectory
, MAX_PATH
);
291 if (len
== 0 || len
> MAX_PATH
)
293 ERR("GetWindowsDirectoryW() failed\n");
296 ret
= CreateProcessAsUserW(
303 CREATE_UNICODE_ENVIRONMENT
,
307 &ProcessInformation
);
308 CloseHandle(ProcessInformation
.hProcess
);
309 CloseHandle(ProcessInformation
.hThread
);
310 CloseHandle(hAppToken
);
312 ERR("CreateProcessAsUserW() failed with error %lu\n", GetLastError());
320 WlxActivateUserShell(
322 PWSTR pszDesktopName
,
323 PWSTR pszMprLogonScript
,
327 DWORD BufSize
, ValueType
;
328 WCHAR pszUserInitApp
[MAX_PATH
+ 1];
329 WCHAR pszExpUserInitApp
[MAX_PATH
];
333 TRACE("WlxActivateUserShell()\n");
335 UNREFERENCED_PARAMETER(pszMprLogonScript
);
337 /* Get the path of userinit */
340 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
344 if (rc
!= ERROR_SUCCESS
)
346 WARN("RegOpenKeyExW() failed with error %lu\n", rc
);
350 /* Query userinit application */
351 BufSize
= sizeof(pszUserInitApp
) - sizeof(UNICODE_NULL
);
352 rc
= RegQueryValueExW(
357 (LPBYTE
)pszUserInitApp
,
360 if (rc
!= ERROR_SUCCESS
|| (ValueType
!= REG_SZ
&& ValueType
!= REG_EXPAND_SZ
))
362 WARN("RegQueryValueExW() failed with error %lu\n", rc
);
365 pszUserInitApp
[MAX_PATH
] = UNICODE_NULL
;
367 len
= ExpandEnvironmentStringsW(pszUserInitApp
, pszExpUserInitApp
, MAX_PATH
);
370 WARN("ExpandEnvironmentStringsW() failed. Required size %lu\n", len
);
374 /* Start userinit app */
375 return WlxStartApplication(pWlxContext
, pszDesktopName
, pEnvironment
, pszExpUserInitApp
);
387 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
388 INT SasAction
= WLX_SAS_ACTION_NONE
;
390 TRACE("WlxLoggedOnSAS(0x%lx)\n", dwSasType
);
392 UNREFERENCED_PARAMETER(pReserved
);
396 case WLX_SAS_TYPE_CTRL_ALT_DEL
:
397 case WLX_SAS_TYPE_TIMEOUT
:
399 SasAction
= pGinaUI
->LoggedOnSAS(pgContext
, dwSasType
);
402 case WLX_SAS_TYPE_SC_INSERT
:
404 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_INSERT not supported!\n");
407 case WLX_SAS_TYPE_SC_REMOVE
:
409 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_REMOVE not supported!\n");
414 WARN("WlxLoggedOnSAS: Unknown SasType: 0x%x\n", dwSasType
);
426 WlxDisplayStatusMessage(
427 IN PVOID pWlxContext
,
433 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
435 TRACE("WlxDisplayStatusMessage(\"%S\")\n", pMessage
);
437 return pGinaUI
->DisplayStatusMessage(pgContext
, hDesktop
, dwOptions
, pTitle
, pMessage
);
444 WlxRemoveStatusMessage(
445 IN PVOID pWlxContext
)
447 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
449 TRACE("WlxRemoveStatusMessage()\n");
451 return pGinaUI
->RemoveStatusMessage(pgContext
);
455 DuplicationString(PWSTR Str
)
460 if (Str
== NULL
) return NULL
;
462 cb
= (wcslen(Str
) + 1) * sizeof(WCHAR
);
463 if ((NewStr
= LocalAlloc(LMEM_FIXED
, cb
)))
464 memcpy(NewStr
, Str
, cb
);
470 IN OUT PGINA_CONTEXT pgContext
,
475 LPWSTR ProfilePath
= NULL
;
476 LPWSTR lpEnvironment
= NULL
;
477 TOKEN_STATISTICS Stats
;
478 PWLX_PROFILE_V2_0 pProfile
= NULL
;
479 DWORD cbStats
, cbSize
;
483 if (!LogonUserW(UserName
, Domain
, Password
,
484 LOGON32_LOGON_INTERACTIVE
,
485 LOGON32_PROVIDER_DEFAULT
,
486 &pgContext
->UserToken
))
488 WARN("LogonUserW() failed\n");
492 /* Store the logon time in the context */
493 GetLocalTime(&pgContext
->LogonTime
);
495 /* Store user and domain in the context */
496 wcscpy(pgContext
->UserName
, UserName
);
497 if (Domain
== NULL
|| wcslen(Domain
) == 0)
500 GetComputerNameW(pgContext
->Domain
, &dwLength
);
504 wcscpy(pgContext
->Domain
, Domain
);
507 /* Get profile path */
509 bResult
= GetProfilesDirectoryW(NULL
, &cbSize
);
510 if (!bResult
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
512 ProfilePath
= HeapAlloc(GetProcessHeap(), 0, cbSize
* sizeof(WCHAR
));
515 WARN("HeapAlloc() failed\n");
518 bResult
= GetProfilesDirectoryW(ProfilePath
, &cbSize
);
522 WARN("GetUserProfileDirectoryW() failed\n");
526 /* Allocate memory for profile */
527 pProfile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WLX_PROFILE_V2_0
));
530 WARN("HeapAlloc() failed\n");
533 pProfile
->dwType
= WLX_PROFILE_TYPE_V2_0
;
534 pProfile
->pszProfile
= ProfilePath
;
536 lpEnvironment
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
537 (wcslen(pgContext
->Domain
)+ 14 + 1) * sizeof(WCHAR
));
540 WARN("HeapAlloc() failed\n");
544 wsprintfW(lpEnvironment
, L
"LOGONSERVER=\\\\%s", pgContext
->Domain
);
546 pProfile
->pszEnvironment
= lpEnvironment
;
548 if (!GetTokenInformation(pgContext
->UserToken
,
551 sizeof(TOKEN_STATISTICS
),
554 WARN("Couldn't get Authentication id from user token!\n");
558 *pgContext
->pAuthenticationId
= Stats
.AuthenticationId
;
559 pgContext
->pMprNotifyInfo
->pszUserName
= DuplicationString(UserName
);
560 pgContext
->pMprNotifyInfo
->pszDomain
= DuplicationString(Domain
);
561 pgContext
->pMprNotifyInfo
->pszPassword
= DuplicationString(Password
);
562 pgContext
->pMprNotifyInfo
->pszOldPassword
= NULL
;
563 *pgContext
->pdwOptions
= 0;
564 *pgContext
->pProfile
= pProfile
;
570 HeapFree(GetProcessHeap(), 0, pProfile
->pszEnvironment
);
572 HeapFree(GetProcessHeap(), 0, pProfile
);
573 HeapFree(GetProcessHeap(), 0, ProfilePath
);
579 IN PGINA_CONTEXT pgContext
)
581 HKEY WinLogonKey
= NULL
;
582 LPWSTR AutoLogon
= NULL
;
583 LPWSTR AutoCount
= NULL
;
584 LPWSTR IgnoreShiftOverride
= NULL
;
585 LPWSTR UserName
= NULL
;
586 LPWSTR DomainName
= NULL
;
587 LPWSTR Password
= NULL
;
591 TRACE("DoAutoLogon(): AutoLogonState = %lu\n",
592 pgContext
->AutoLogonState
);
594 if (pgContext
->AutoLogonState
== AUTOLOGON_DISABLED
)
599 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
603 if (rc
!= ERROR_SUCCESS
)
606 if (pgContext
->AutoLogonState
== AUTOLOGON_CHECK_REGISTRY
)
608 /* Set it by default to disabled, we might reenable it again later */
609 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
611 rc
= ReadRegSzKey(WinLogonKey
, L
"AutoAdminLogon", &AutoLogon
);
612 if (rc
!= ERROR_SUCCESS
)
614 if (wcscmp(AutoLogon
, L
"1") != 0)
617 rc
= ReadRegSzKey(WinLogonKey
, L
"AutoLogonCount", &AutoCount
);
618 if (rc
== ERROR_SUCCESS
&& wcscmp(AutoCount
, L
"0") == 0)
620 else if (rc
!= ERROR_FILE_NOT_FOUND
)
623 rc
= ReadRegSzKey(WinLogonKey
, L
"IgnoreShiftOverride", &UserName
);
624 if (rc
== ERROR_SUCCESS
)
626 if (wcscmp(AutoLogon
, L
"1") != 0 && GetKeyState(VK_SHIFT
) < 0)
629 else if (GetKeyState(VK_SHIFT
) < 0)
631 /* User pressed SHIFT */
635 pgContext
->AutoLogonState
= AUTOLOGON_ONCE
;
638 else /* pgContext->AutoLogonState == AUTOLOGON_ONCE */
640 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
642 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultUserName", &UserName
);
643 if (rc
!= ERROR_SUCCESS
)
645 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultDomainName", &DomainName
);
646 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
648 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultPassword", &Password
);
649 if (rc
!= ERROR_SUCCESS
)
652 result
= DoLoginTasks(pgContext
, UserName
, DomainName
, Password
);
655 NotifyBootConfigStatus(TRUE
);
659 if (WinLogonKey
!= NULL
)
660 RegCloseKey(WinLogonKey
);
661 HeapFree(GetProcessHeap(), 0, AutoLogon
);
662 HeapFree(GetProcessHeap(), 0, AutoCount
);
663 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride
);
664 HeapFree(GetProcessHeap(), 0, UserName
);
665 HeapFree(GetProcessHeap(), 0, DomainName
);
666 HeapFree(GetProcessHeap(), 0, Password
);
667 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n",
668 pgContext
->AutoLogonState
, result
);
677 IN PVOID pWlxContext
)
679 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
681 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext
);
683 if (GetSystemMetrics(SM_REMOTESESSION
))
685 /* User is remotely logged on. Don't display a notice */
686 pgContext
->pWlxFuncs
->WlxSasNotify(pgContext
->hWlx
, WLX_SAS_TYPE_CTRL_ALT_DEL
);
690 if (DoAutoLogon(pgContext
))
692 /* Don't display the window, we want to do an automatic logon */
693 pgContext
->AutoLogonState
= AUTOLOGON_ONCE
;
694 pgContext
->pWlxFuncs
->WlxSasNotify(pgContext
->hWlx
, WLX_SAS_TYPE_CTRL_ALT_DEL
);
698 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
700 pGinaUI
->DisplaySASNotice(pgContext
);
702 TRACE("WlxDisplaySASNotice() done\n");
710 IN PVOID pWlxContext
,
712 OUT PLUID pAuthenticationId
,
713 IN OUT PSID pLogonSid
,
714 OUT PDWORD pdwOptions
,
716 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo
,
719 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
722 TRACE("WlxLoggedOutSAS()\n");
724 UNREFERENCED_PARAMETER(dwSasType
);
725 UNREFERENCED_PARAMETER(pLogonSid
);
727 pgContext
->pAuthenticationId
= pAuthenticationId
;
728 pgContext
->pdwOptions
= pdwOptions
;
729 pgContext
->pMprNotifyInfo
= pMprNotifyInfo
;
730 pgContext
->pProfile
= pProfile
;
732 if (0 == GetSystemMetrics(SM_REMOTESESSION
) &&
733 DoAutoLogon(pgContext
))
735 /* User is local and registry contains information
736 * to log on him automatically */
737 *phToken
= pgContext
->UserToken
;
738 return WLX_SAS_ACTION_LOGON
;
741 res
= pGinaUI
->LoggedOutSAS(pgContext
);
742 *phToken
= pgContext
->UserToken
;
754 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
756 TRACE("WlxWkstaLockedSAS()\n");
758 UNREFERENCED_PARAMETER(dwSasType
);
760 return pGinaUI
->LockedSAS(pgContext
);
769 WlxDisplayLockedNotice(PVOID pWlxContext
)
771 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
773 TRACE("WlxDisplayLockedNotice()\n");
775 pGinaUI
->DisplayLockedNotice(pgContext
);
786 TRACE("WlxIsLogoffOk()\n");
787 UNREFERENCED_PARAMETER(pWlxContext
);
793 IN HINSTANCE hinstDLL
,
795 IN LPVOID lpvReserved
)
797 UNREFERENCED_PARAMETER(lpvReserved
);
799 if (dwReason
== DLL_PROCESS_ATTACH
)
800 hDllInstance
= hinstDLL
;