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 CMDCONS 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
);
195 PWSTR pszDesktopName
,
199 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
200 STARTUPINFOW StartupInfo
;
201 PROCESS_INFORMATION ProcessInformation
;
202 WCHAR CurrentDirectory
[MAX_PATH
];
207 len
= GetWindowsDirectoryW(CurrentDirectory
, MAX_PATH
);
208 if (len
== 0 || len
> MAX_PATH
)
210 WARN("GetWindowsDirectoryW() failed\n");
214 ret
= DuplicateTokenEx(pgContext
->UserToken
, MAXIMUM_ALLOWED
, NULL
, SecurityImpersonation
, TokenPrimary
, &hAppToken
);
217 WARN("DuplicateTokenEx() failed with error %lu\n", GetLastError());
221 ZeroMemory(&StartupInfo
, sizeof(STARTUPINFOW
));
222 ZeroMemory(&ProcessInformation
, sizeof(PROCESS_INFORMATION
));
223 StartupInfo
.cb
= sizeof(STARTUPINFOW
);
224 StartupInfo
.lpTitle
= pszCmdLine
;
225 StartupInfo
.dwX
= StartupInfo
.dwY
= StartupInfo
.dwXSize
= StartupInfo
.dwYSize
= 0L;
226 StartupInfo
.dwFlags
= 0;
227 StartupInfo
.wShowWindow
= SW_SHOW
;
228 StartupInfo
.lpDesktop
= pszDesktopName
;
230 len
= GetWindowsDirectoryW(CurrentDirectory
, MAX_PATH
);
231 if (len
== 0 || len
> MAX_PATH
)
233 WARN("GetWindowsDirectoryW() failed\n");
236 ret
= CreateProcessAsUserW(
243 CREATE_UNICODE_ENVIRONMENT
,
247 &ProcessInformation
);
248 CloseHandle(ProcessInformation
.hProcess
);
249 CloseHandle(ProcessInformation
.hThread
);
250 CloseHandle(hAppToken
);
252 WARN("CreateProcessAsUserW() failed with error %lu\n", GetLastError());
260 WlxActivateUserShell(
262 PWSTR pszDesktopName
,
263 PWSTR pszMprLogonScript
,
267 DWORD BufSize
, ValueType
;
268 WCHAR pszUserInitApp
[MAX_PATH
+ 1];
269 WCHAR pszExpUserInitApp
[MAX_PATH
];
273 TRACE("WlxActivateUserShell()\n");
275 UNREFERENCED_PARAMETER(pszMprLogonScript
);
277 /* Get the path of userinit */
280 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
284 if (rc
!= ERROR_SUCCESS
)
286 WARN("RegOpenKeyExW() failed with error %lu\n", rc
);
290 /* Query userinit application */
291 BufSize
= sizeof(pszUserInitApp
) - sizeof(UNICODE_NULL
);
292 rc
= RegQueryValueExW(
297 (LPBYTE
)pszUserInitApp
,
300 if (rc
!= ERROR_SUCCESS
|| (ValueType
!= REG_SZ
&& ValueType
!= REG_EXPAND_SZ
))
302 WARN("RegQueryValueExW() failed with error %lu\n", rc
);
305 pszUserInitApp
[MAX_PATH
] = UNICODE_NULL
;
307 len
= ExpandEnvironmentStringsW(pszUserInitApp
, pszExpUserInitApp
, MAX_PATH
);
310 WARN("ExpandEnvironmentStringsW() failed. Required size %lu\n", len
);
314 /* Start userinit app */
315 return WlxStartApplication(pWlxContext
, pszDesktopName
, pEnvironment
, pszExpUserInitApp
);
327 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
328 INT SasAction
= WLX_SAS_ACTION_NONE
;
330 TRACE("WlxLoggedOnSAS(0x%lx)\n", dwSasType
);
332 UNREFERENCED_PARAMETER(pReserved
);
336 case WLX_SAS_TYPE_CTRL_ALT_DEL
:
337 case WLX_SAS_TYPE_TIMEOUT
:
339 SasAction
= pGinaUI
->LoggedOnSAS(pgContext
, dwSasType
);
342 case WLX_SAS_TYPE_SC_INSERT
:
344 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_INSERT not supported!\n");
347 case WLX_SAS_TYPE_SC_REMOVE
:
349 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_REMOVE not supported!\n");
354 WARN("WlxLoggedOnSAS: Unknown SasType: 0x%x\n", dwSasType
);
366 WlxDisplayStatusMessage(
367 IN PVOID pWlxContext
,
373 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
375 TRACE("WlxDisplayStatusMessage(\"%S\")\n", pMessage
);
377 return pGinaUI
->DisplayStatusMessage(pgContext
, hDesktop
, dwOptions
, pTitle
, pMessage
);
384 WlxRemoveStatusMessage(
385 IN PVOID pWlxContext
)
387 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
389 TRACE("WlxRemoveStatusMessage()\n");
391 return pGinaUI
->RemoveStatusMessage(pgContext
);
395 DuplicationString(PWSTR Str
)
400 if (Str
== NULL
) return NULL
;
402 cb
= (wcslen(Str
) + 1) * sizeof(WCHAR
);
403 if ((NewStr
= LocalAlloc(LMEM_FIXED
, cb
)))
404 memcpy(NewStr
, Str
, cb
);
410 IN OUT PGINA_CONTEXT pgContext
,
415 LPWSTR ProfilePath
= NULL
;
416 LPWSTR lpEnvironment
= NULL
;
417 TOKEN_STATISTICS Stats
;
418 PWLX_PROFILE_V2_0 pProfile
= NULL
;
419 DWORD cbStats
, cbSize
;
422 if (!LogonUserW(UserName
, Domain
, Password
,
423 LOGON32_LOGON_INTERACTIVE
,
424 LOGON32_PROVIDER_DEFAULT
,
425 &pgContext
->UserToken
))
427 WARN("LogonUserW() failed\n");
431 /* Get profile path */
433 bResult
= GetProfilesDirectoryW(NULL
, &cbSize
);
434 if (!bResult
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
436 ProfilePath
= HeapAlloc(GetProcessHeap(), 0, cbSize
* sizeof(WCHAR
));
439 WARN("HeapAlloc() failed\n");
442 bResult
= GetProfilesDirectoryW(ProfilePath
, &cbSize
);
446 WARN("GetUserProfileDirectoryW() failed\n");
450 /* Allocate memory for profile */
451 pProfile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WLX_PROFILE_V2_0
));
454 WARN("HeapAlloc() failed\n");
457 pProfile
->dwType
= WLX_PROFILE_TYPE_V2_0
;
458 pProfile
->pszProfile
= ProfilePath
;
460 lpEnvironment
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, 32 * sizeof(WCHAR
));
463 WARN("HeapAlloc() failed\n");
466 wcscpy(lpEnvironment
, L
"LOGONSERVER=\\\\Test");
468 pProfile
->pszEnvironment
= lpEnvironment
;
470 if (!GetTokenInformation(pgContext
->UserToken
,
473 sizeof(TOKEN_STATISTICS
),
476 WARN("Couldn't get Authentication id from user token!\n");
480 *pgContext
->pAuthenticationId
= Stats
.AuthenticationId
;
481 pgContext
->pMprNotifyInfo
->pszUserName
= DuplicationString(UserName
);
482 pgContext
->pMprNotifyInfo
->pszDomain
= DuplicationString(Domain
);
483 pgContext
->pMprNotifyInfo
->pszPassword
= DuplicationString(Password
);
484 pgContext
->pMprNotifyInfo
->pszOldPassword
= NULL
;
485 *pgContext
->pdwOptions
= 0;
486 *pgContext
->pProfile
= pProfile
;
492 HeapFree(GetProcessHeap(), 0, pProfile
->pszEnvironment
);
494 HeapFree(GetProcessHeap(), 0, pProfile
);
495 HeapFree(GetProcessHeap(), 0, ProfilePath
);
501 IN PGINA_CONTEXT pgContext
)
503 HKEY WinLogonKey
= NULL
;
504 LPWSTR AutoLogon
= NULL
;
505 LPWSTR AutoCount
= NULL
;
506 LPWSTR IgnoreShiftOverride
= NULL
;
507 LPWSTR UserName
= NULL
;
508 LPWSTR DomainName
= NULL
;
509 LPWSTR Password
= NULL
;
513 TRACE("DoAutoLogon(): AutoLogonState = %lu\n",
514 pgContext
->AutoLogonState
);
516 if (pgContext
->AutoLogonState
== AUTOLOGON_DISABLED
)
521 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
525 if (rc
!= ERROR_SUCCESS
)
528 if (pgContext
->AutoLogonState
== AUTOLOGON_CHECK_REGISTRY
)
530 /* Set it by default to disabled, we might reenable it again later */
531 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
533 rc
= ReadRegSzKey(WinLogonKey
, L
"AutoAdminLogon", &AutoLogon
);
534 if (rc
!= ERROR_SUCCESS
)
536 if (wcscmp(AutoLogon
, L
"1") != 0)
539 rc
= ReadRegSzKey(WinLogonKey
, L
"AutoLogonCount", &AutoCount
);
540 if (rc
== ERROR_SUCCESS
&& wcscmp(AutoCount
, L
"0") == 0)
542 else if (rc
!= ERROR_FILE_NOT_FOUND
)
545 rc
= ReadRegSzKey(WinLogonKey
, L
"IgnoreShiftOverride", &UserName
);
546 if (rc
== ERROR_SUCCESS
)
548 if (wcscmp(AutoLogon
, L
"1") != 0 && GetKeyState(VK_SHIFT
) < 0)
551 else if (GetKeyState(VK_SHIFT
) < 0)
553 /* User pressed SHIFT */
557 pgContext
->AutoLogonState
= AUTOLOGON_ONCE
;
560 else /* pgContext->AutoLogonState == AUTOLOGON_ONCE */
562 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
564 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultUserName", &UserName
);
565 if (rc
!= ERROR_SUCCESS
)
567 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultDomainName", &DomainName
);
568 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
570 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultPassword", &Password
);
571 if (rc
!= ERROR_SUCCESS
)
574 result
= DoLoginTasks(pgContext
, UserName
, DomainName
, Password
);
577 NotifyBootConfigStatus(TRUE
);
581 if (WinLogonKey
!= NULL
)
582 RegCloseKey(WinLogonKey
);
583 HeapFree(GetProcessHeap(), 0, AutoLogon
);
584 HeapFree(GetProcessHeap(), 0, AutoCount
);
585 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride
);
586 HeapFree(GetProcessHeap(), 0, UserName
);
587 HeapFree(GetProcessHeap(), 0, DomainName
);
588 HeapFree(GetProcessHeap(), 0, Password
);
589 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n",
590 pgContext
->AutoLogonState
, result
);
599 IN PVOID pWlxContext
)
601 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
603 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext
);
605 if (GetSystemMetrics(SM_REMOTESESSION
))
607 /* User is remotely logged on. Don't display a notice */
608 pgContext
->pWlxFuncs
->WlxSasNotify(pgContext
->hWlx
, WLX_SAS_TYPE_CTRL_ALT_DEL
);
612 if (DoAutoLogon(pgContext
))
614 /* Don't display the window, we want to do an automatic logon */
615 pgContext
->AutoLogonState
= AUTOLOGON_ONCE
;
616 pgContext
->pWlxFuncs
->WlxSasNotify(pgContext
->hWlx
, WLX_SAS_TYPE_CTRL_ALT_DEL
);
620 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
622 pGinaUI
->DisplaySASNotice(pgContext
);
624 TRACE("WlxDisplaySASNotice() done\n");
632 IN PVOID pWlxContext
,
634 OUT PLUID pAuthenticationId
,
635 IN OUT PSID pLogonSid
,
636 OUT PDWORD pdwOptions
,
638 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo
,
641 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
644 TRACE("WlxLoggedOutSAS()\n");
646 UNREFERENCED_PARAMETER(dwSasType
);
647 UNREFERENCED_PARAMETER(pLogonSid
);
649 pgContext
->pAuthenticationId
= pAuthenticationId
;
650 pgContext
->pdwOptions
= pdwOptions
;
651 pgContext
->pMprNotifyInfo
= pMprNotifyInfo
;
652 pgContext
->pProfile
= pProfile
;
654 if (0 == GetSystemMetrics(SM_REMOTESESSION
) &&
655 DoAutoLogon(pgContext
))
657 /* User is local and registry contains information
658 * to log on him automatically */
659 *phToken
= pgContext
->UserToken
;
660 return WLX_SAS_ACTION_LOGON
;
663 res
= pGinaUI
->LoggedOutSAS(pgContext
);
664 *phToken
= pgContext
->UserToken
;
676 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
678 TRACE("WlxWkstaLockedSAS()\n");
680 UNREFERENCED_PARAMETER(dwSasType
);
682 return pGinaUI
->LockedSAS(pgContext
);
692 TRACE("WlxIsLogoffOk()\n");
693 UNREFERENCED_PARAMETER(pWlxContext
);
699 IN HINSTANCE hinstDLL
,
701 IN LPVOID lpvReserved
)
703 UNREFERENCED_PARAMETER(lpvReserved
);
705 if (dwReason
== DLL_PROCESS_ATTACH
)
706 hDllInstance
= hinstDLL
;