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 #include <wine/debug.h>
31 WINE_DEFAULT_DEBUG_CHANNEL(msgina
);
33 HINSTANCE hDllInstance
;
35 extern GINA_UI GinaGraphicalUI
;
36 extern GINA_UI GinaTextUI
;
37 static PGINA_UI pGinaUI
;
44 IN DWORD dwWinlogonVersion
,
45 OUT PDWORD pdwDllVersion
)
47 TRACE("WlxNegotiate(%lx, %p)\n", dwWinlogonVersion
, pdwDllVersion
);
49 if(!pdwDllVersion
|| (dwWinlogonVersion
< WLX_VERSION_1_3
))
52 *pdwDllVersion
= WLX_VERSION_1_3
;
69 return ERROR_INVALID_PARAMETER
;
72 rc
= RegQueryValueExW(hKey
, pszKey
, NULL
, &dwType
, NULL
, &cbData
);
73 if (rc
!= ERROR_SUCCESS
)
76 return ERROR_FILE_NOT_FOUND
;
77 Value
= HeapAlloc(GetProcessHeap(), 0, cbData
+ sizeof(WCHAR
));
79 return ERROR_NOT_ENOUGH_MEMORY
;
80 rc
= RegQueryValueExW(hKey
, pszKey
, NULL
, NULL
, (LPBYTE
)Value
, &cbData
);
81 if (rc
!= ERROR_SUCCESS
)
83 HeapFree(GetProcessHeap(), 0, Value
);
86 /* NULL-terminate the string */
87 Value
[cbData
/ sizeof(WCHAR
)] = '\0';
96 HKEY ControlKey
= NULL
;
97 LPWSTR SystemStartOptions
= NULL
;
98 LPWSTR CurrentOption
, NextOption
; /* Pointers into SystemStartOptions */
99 BOOL ConsoleBoot
= FALSE
;
104 L
"SYSTEM\\CurrentControlSet\\Control",
109 rc
= ReadRegSzKey(ControlKey
, L
"SystemStartOptions", &SystemStartOptions
);
110 if (rc
!= ERROR_SUCCESS
)
113 /* Check for CMDCONS in SystemStartOptions */
114 CurrentOption
= SystemStartOptions
;
115 while (CurrentOption
)
117 NextOption
= wcschr(CurrentOption
, L
' ');
120 if (wcsicmp(CurrentOption
, L
"CONSOLE") == 0)
122 TRACE("Found %S. Switching to console boot\n", CurrentOption
);
126 CurrentOption
= NextOption
? NextOption
+ 1 : NULL
;
131 pGinaUI
= &GinaTextUI
;
133 pGinaUI
= &GinaGraphicalUI
;
135 if (ControlKey
!= NULL
)
136 RegCloseKey(ControlKey
);
137 HeapFree(GetProcessHeap(), 0, SystemStartOptions
);
148 PVOID pWinlogonFunctions
,
151 PGINA_CONTEXT pgContext
;
153 UNREFERENCED_PARAMETER(pvReserved
);
155 pgContext
= (PGINA_CONTEXT
)LocalAlloc(LMEM_FIXED
| LMEM_ZEROINIT
, sizeof(GINA_CONTEXT
));
158 WARN("LocalAlloc() failed\n");
162 /* Return the context to winlogon */
163 *pWlxContext
= (PVOID
)pgContext
;
164 pgContext
->hDllInstance
= hDllInstance
;
166 /* Save pointer to dispatch table */
167 pgContext
->pWlxFuncs
= (PWLX_DISPATCH_VERSION_1_3
)pWinlogonFunctions
;
169 /* Save the winlogon handle used to call the dispatch functions */
170 pgContext
->hWlx
= hWlx
;
172 /* Save window station */
173 pgContext
->station
= lpWinsta
;
175 /* Clear status window handle */
176 pgContext
->hStatusWindow
= 0;
178 /* Notify winlogon that we will use the default SAS */
179 pgContext
->pWlxFuncs
->WlxUseCtrlAltDel(hWlx
);
181 /* Locates the authentification package */
182 //LsaRegisterLogonProcess(...);
184 /* Check autologon settings the first time */
185 pgContext
->AutoLogonState
= AUTOLOGON_CHECK_REGISTRY
;
188 return pGinaUI
->Initialize(pgContext
);
197 PWSTR pszDesktopName
,
201 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
202 STARTUPINFOW StartupInfo
;
203 PROCESS_INFORMATION ProcessInformation
;
204 WCHAR CurrentDirectory
[MAX_PATH
];
209 len
= GetWindowsDirectoryW(CurrentDirectory
, MAX_PATH
);
210 if (len
== 0 || len
> MAX_PATH
)
212 WARN("GetWindowsDirectoryW() failed\n");
216 ret
= DuplicateTokenEx(pgContext
->UserToken
, MAXIMUM_ALLOWED
, NULL
, SecurityImpersonation
, TokenPrimary
, &hAppToken
);
219 WARN("DuplicateTokenEx() failed with error %lu\n", GetLastError());
223 ZeroMemory(&StartupInfo
, sizeof(STARTUPINFOW
));
224 ZeroMemory(&ProcessInformation
, sizeof(PROCESS_INFORMATION
));
225 StartupInfo
.cb
= sizeof(STARTUPINFOW
);
226 StartupInfo
.lpTitle
= pszCmdLine
;
227 StartupInfo
.dwX
= StartupInfo
.dwY
= StartupInfo
.dwXSize
= StartupInfo
.dwYSize
= 0L;
228 StartupInfo
.dwFlags
= 0;
229 StartupInfo
.wShowWindow
= SW_SHOW
;
230 StartupInfo
.lpDesktop
= pszDesktopName
;
232 len
= GetWindowsDirectoryW(CurrentDirectory
, MAX_PATH
);
233 if (len
== 0 || len
> MAX_PATH
)
235 WARN("GetWindowsDirectoryW() failed\n");
238 ret
= CreateProcessAsUserW(
245 CREATE_UNICODE_ENVIRONMENT
,
249 &ProcessInformation
);
250 CloseHandle(ProcessInformation
.hProcess
);
251 CloseHandle(ProcessInformation
.hThread
);
252 CloseHandle(hAppToken
);
254 WARN("CreateProcessAsUserW() failed with error %lu\n", GetLastError());
262 WlxActivateUserShell(
264 PWSTR pszDesktopName
,
265 PWSTR pszMprLogonScript
,
269 DWORD BufSize
, ValueType
;
270 WCHAR pszUserInitApp
[MAX_PATH
+ 1];
271 WCHAR pszExpUserInitApp
[MAX_PATH
];
275 TRACE("WlxActivateUserShell()\n");
277 UNREFERENCED_PARAMETER(pszMprLogonScript
);
279 /* Get the path of userinit */
282 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
286 if (rc
!= ERROR_SUCCESS
)
288 WARN("RegOpenKeyExW() failed with error %lu\n", rc
);
292 /* Query userinit application */
293 BufSize
= sizeof(pszUserInitApp
) - sizeof(UNICODE_NULL
);
294 rc
= RegQueryValueExW(
299 (LPBYTE
)pszUserInitApp
,
302 if (rc
!= ERROR_SUCCESS
|| (ValueType
!= REG_SZ
&& ValueType
!= REG_EXPAND_SZ
))
304 WARN("RegQueryValueExW() failed with error %lu\n", rc
);
307 pszUserInitApp
[MAX_PATH
] = UNICODE_NULL
;
309 len
= ExpandEnvironmentStringsW(pszUserInitApp
, pszExpUserInitApp
, MAX_PATH
);
312 WARN("ExpandEnvironmentStringsW() failed. Required size %lu\n", len
);
316 /* Start userinit app */
317 return WlxStartApplication(pWlxContext
, pszDesktopName
, pEnvironment
, pszExpUserInitApp
);
329 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
330 INT SasAction
= WLX_SAS_ACTION_NONE
;
332 TRACE("WlxLoggedOnSAS(0x%lx)\n", dwSasType
);
334 UNREFERENCED_PARAMETER(pReserved
);
338 case WLX_SAS_TYPE_CTRL_ALT_DEL
:
339 case WLX_SAS_TYPE_TIMEOUT
:
341 SasAction
= pGinaUI
->LoggedOnSAS(pgContext
, dwSasType
);
344 case WLX_SAS_TYPE_SC_INSERT
:
346 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_INSERT not supported!\n");
349 case WLX_SAS_TYPE_SC_REMOVE
:
351 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_REMOVE not supported!\n");
356 WARN("WlxLoggedOnSAS: Unknown SasType: 0x%x\n", dwSasType
);
368 WlxDisplayStatusMessage(
369 IN PVOID pWlxContext
,
375 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
377 TRACE("WlxDisplayStatusMessage(\"%S\")\n", pMessage
);
379 return pGinaUI
->DisplayStatusMessage(pgContext
, hDesktop
, dwOptions
, pTitle
, pMessage
);
386 WlxRemoveStatusMessage(
387 IN PVOID pWlxContext
)
389 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
391 TRACE("WlxRemoveStatusMessage()\n");
393 return pGinaUI
->RemoveStatusMessage(pgContext
);
397 DuplicationString(PWSTR Str
)
402 if (Str
== NULL
) return NULL
;
404 cb
= (wcslen(Str
) + 1) * sizeof(WCHAR
);
405 if ((NewStr
= LocalAlloc(LMEM_FIXED
, cb
)))
406 memcpy(NewStr
, Str
, cb
);
412 IN OUT PGINA_CONTEXT pgContext
,
417 LPWSTR ProfilePath
= NULL
;
418 TOKEN_STATISTICS Stats
;
419 PWLX_PROFILE_V1_0 pProfile
= NULL
;
420 DWORD cbStats
, cbSize
;
423 if (!LogonUserW(UserName
, Domain
, Password
,
424 LOGON32_LOGON_INTERACTIVE
,
425 LOGON32_PROVIDER_DEFAULT
,
426 &pgContext
->UserToken
))
428 WARN("LogonUserW() failed\n");
432 /* Get profile path */
434 bResult
= GetProfilesDirectoryW(NULL
, &cbSize
);
435 if (!bResult
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
437 ProfilePath
= HeapAlloc(GetProcessHeap(), 0, cbSize
* sizeof(WCHAR
));
440 WARN("HeapAlloc() failed\n");
443 bResult
= GetProfilesDirectoryW(ProfilePath
, &cbSize
);
447 WARN("GetUserProfileDirectoryW() failed\n");
451 /* Allocate memory for profile */
452 pProfile
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WLX_PROFILE_V1_0
));
455 WARN("HeapAlloc() failed\n");
458 pProfile
->dwType
= WLX_PROFILE_TYPE_V1_0
;
459 pProfile
->pszProfile
= ProfilePath
;
461 if (!GetTokenInformation(pgContext
->UserToken
,
464 sizeof(TOKEN_STATISTICS
),
467 WARN("Couldn't get Authentication id from user token!\n");
470 *pgContext
->pAuthenticationId
= Stats
.AuthenticationId
;
471 pgContext
->pMprNotifyInfo
->pszUserName
= DuplicationString(UserName
);
472 pgContext
->pMprNotifyInfo
->pszDomain
= DuplicationString(Domain
);
473 pgContext
->pMprNotifyInfo
->pszPassword
= DuplicationString(Password
);
474 pgContext
->pMprNotifyInfo
->pszOldPassword
= NULL
;
475 *pgContext
->pdwOptions
= 0;
476 *pgContext
->pProfile
= pProfile
;
480 HeapFree(GetProcessHeap(), 0, pProfile
);
481 HeapFree(GetProcessHeap(), 0, ProfilePath
);
487 IN PGINA_CONTEXT pgContext
)
489 HKEY WinLogonKey
= NULL
;
490 LPWSTR AutoLogon
= NULL
;
491 LPWSTR AutoCount
= NULL
;
492 LPWSTR IgnoreShiftOverride
= NULL
;
493 LPWSTR UserName
= NULL
;
494 LPWSTR DomainName
= NULL
;
495 LPWSTR Password
= NULL
;
499 TRACE("DoAutoLogon(): AutoLogonState = %lu\n",
500 pgContext
->AutoLogonState
);
502 if (pgContext
->AutoLogonState
== AUTOLOGON_DISABLED
)
507 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
511 if (rc
!= ERROR_SUCCESS
)
514 if (pgContext
->AutoLogonState
== AUTOLOGON_CHECK_REGISTRY
)
516 /* Set it by default to disabled, we might reenable it again later */
517 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
519 rc
= ReadRegSzKey(WinLogonKey
, L
"AutoAdminLogon", &AutoLogon
);
520 if (rc
!= ERROR_SUCCESS
)
522 if (wcscmp(AutoLogon
, L
"1") != 0)
525 rc
= ReadRegSzKey(WinLogonKey
, L
"AutoLogonCount", &AutoCount
);
526 if (rc
== ERROR_SUCCESS
&& wcscmp(AutoCount
, L
"0") == 0)
528 else if (rc
!= ERROR_FILE_NOT_FOUND
)
531 rc
= ReadRegSzKey(WinLogonKey
, L
"IgnoreShiftOverride", &UserName
);
532 if (rc
== ERROR_SUCCESS
)
534 if (wcscmp(AutoLogon
, L
"1") != 0 && GetKeyState(VK_SHIFT
) < 0)
537 else if (GetKeyState(VK_SHIFT
) < 0)
539 /* User pressed SHIFT */
543 pgContext
->AutoLogonState
= AUTOLOGON_ONCE
;
546 else /* pgContext->AutoLogonState == AUTOLOGON_ONCE */
548 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
550 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultUserName", &UserName
);
551 if (rc
!= ERROR_SUCCESS
)
553 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultDomainName", &DomainName
);
554 if (rc
!= ERROR_SUCCESS
&& rc
!= ERROR_FILE_NOT_FOUND
)
556 rc
= ReadRegSzKey(WinLogonKey
, L
"DefaultPassword", &Password
);
557 if (rc
!= ERROR_SUCCESS
)
560 result
= DoLoginTasks(pgContext
, UserName
, DomainName
, Password
);
564 if (WinLogonKey
!= NULL
)
565 RegCloseKey(WinLogonKey
);
566 HeapFree(GetProcessHeap(), 0, AutoLogon
);
567 HeapFree(GetProcessHeap(), 0, AutoCount
);
568 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride
);
569 HeapFree(GetProcessHeap(), 0, UserName
);
570 HeapFree(GetProcessHeap(), 0, DomainName
);
571 HeapFree(GetProcessHeap(), 0, Password
);
572 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n",
573 pgContext
->AutoLogonState
, result
);
582 IN PVOID pWlxContext
)
584 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
586 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext
);
588 if (GetSystemMetrics(SM_REMOTESESSION
))
590 /* User is remotely logged on. Don't display a notice */
591 pgContext
->pWlxFuncs
->WlxSasNotify(pgContext
->hWlx
, WLX_SAS_TYPE_CTRL_ALT_DEL
);
595 if (DoAutoLogon(pgContext
))
597 /* Don't display the window, we want to do an automatic logon */
598 pgContext
->AutoLogonState
= AUTOLOGON_ONCE
;
599 pgContext
->pWlxFuncs
->WlxSasNotify(pgContext
->hWlx
, WLX_SAS_TYPE_CTRL_ALT_DEL
);
603 pgContext
->AutoLogonState
= AUTOLOGON_DISABLED
;
605 pGinaUI
->DisplaySASNotice(pgContext
);
607 TRACE("WlxDisplaySASNotice() done\n");
615 IN PVOID pWlxContext
,
617 OUT PLUID pAuthenticationId
,
618 IN OUT PSID pLogonSid
,
619 OUT PDWORD pdwOptions
,
621 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo
,
624 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
627 TRACE("WlxLoggedOutSAS()\n");
629 UNREFERENCED_PARAMETER(dwSasType
);
630 UNREFERENCED_PARAMETER(pLogonSid
);
632 pgContext
->pAuthenticationId
= pAuthenticationId
;
633 pgContext
->pdwOptions
= pdwOptions
;
634 pgContext
->pMprNotifyInfo
= pMprNotifyInfo
;
635 pgContext
->pProfile
= pProfile
;
637 if (0 == GetSystemMetrics(SM_REMOTESESSION
) &&
638 DoAutoLogon(pgContext
))
640 /* User is local and registry contains information
641 * to log on him automatically */
642 *phToken
= pgContext
->UserToken
;
643 return WLX_SAS_ACTION_LOGON
;
646 res
= pGinaUI
->LoggedOutSAS(pgContext
);
647 *phToken
= pgContext
->UserToken
;
659 PGINA_CONTEXT pgContext
= (PGINA_CONTEXT
)pWlxContext
;
661 TRACE("WlxWkstaLockedSAS()\n");
663 UNREFERENCED_PARAMETER(dwSasType
);
665 return pGinaUI
->LockedSAS(pgContext
);
670 IN HINSTANCE hinstDLL
,
672 IN LPVOID lpvReserved
)
674 UNREFERENCED_PARAMETER(lpvReserved
);
676 if (dwReason
== DLL_PROCESS_ATTACH
)
677 hDllInstance
= hinstDLL
;