reactos/dll/win32/msgina/gui.c

1353 lines
37 KiB
C

/*
* PROJECT: ReactOS msgina.dll
* FILE: dll/win32/msgina/gui.c
* PURPOSE: ReactOS Logon GINA DLL
* PROGRAMMER: Hervé Poussineau (hpoussin@reactos.org)
*/
#include "msgina.h"
#include <wingdi.h>
#include <winnls.h>
#include <winreg.h>
typedef struct _DISPLAYSTATUSMSG
{
PGINA_CONTEXT Context;
HDESK hDesktop;
DWORD dwOptions;
PWSTR pTitle;
PWSTR pMessage;
HANDLE StartupEvent;
} DISPLAYSTATUSMSG, *PDISPLAYSTATUSMSG;
typedef struct _LEGALNOTICEDATA
{
LPWSTR pszCaption;
LPWSTR pszText;
} LEGALNOTICEDATA, *PLEGALNOTICEDATA;
static BOOL
GUIInitialize(
IN OUT PGINA_CONTEXT pgContext)
{
TRACE("GUIInitialize(%p)\n", pgContext);
return TRUE;
}
static INT_PTR CALLBACK
StatusMessageWindowProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
switch (uMsg)
{
case WM_INITDIALOG:
{
PDISPLAYSTATUSMSG msg = (PDISPLAYSTATUSMSG)lParam;
if (!msg)
return FALSE;
msg->Context->hStatusWindow = hwndDlg;
if (msg->pTitle)
SetWindowTextW(hwndDlg, msg->pTitle);
SetDlgItemTextW(hwndDlg, IDC_STATUSLABEL, msg->pMessage);
SetEvent(msg->StartupEvent);
return TRUE;
}
}
return FALSE;
}
static DWORD WINAPI
StartupWindowThread(LPVOID lpParam)
{
HDESK hDesk;
PDISPLAYSTATUSMSG msg = (PDISPLAYSTATUSMSG)lpParam;
/* When SetThreadDesktop is called the system closes the desktop handle when needed
so we have to create a new handle because this handle may still be in use by winlogon */
if (!DuplicateHandle ( GetCurrentProcess(),
msg->hDesktop,
GetCurrentProcess(),
(HANDLE*)&hDesk,
0,
FALSE,
DUPLICATE_SAME_ACCESS))
{
ERR("Duplicating handle failed!\n");
HeapFree(GetProcessHeap(), 0, lpParam);
return FALSE;
}
if(!SetThreadDesktop(hDesk))
{
ERR("Setting thread desktop failed!\n");
HeapFree(GetProcessHeap(), 0, lpParam);
return FALSE;
}
DialogBoxParamW(
hDllInstance,
MAKEINTRESOURCEW(IDD_STATUSWINDOW_DLG),
GetDesktopWindow(),
StatusMessageWindowProc,
(LPARAM)lpParam);
HeapFree(GetProcessHeap(), 0, lpParam);
return TRUE;
}
static BOOL
GUIDisplayStatusMessage(
IN PGINA_CONTEXT pgContext,
IN HDESK hDesktop,
IN DWORD dwOptions,
IN PWSTR pTitle,
IN PWSTR pMessage)
{
PDISPLAYSTATUSMSG msg;
HANDLE Thread;
DWORD ThreadId;
TRACE("GUIDisplayStatusMessage(%ws)\n", pMessage);
if (!pgContext->hStatusWindow)
{
/*
* If everything goes correctly, 'msg' is freed
* by the 'StartupWindowThread' thread.
*/
msg = (PDISPLAYSTATUSMSG)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(*msg));
if(!msg)
return FALSE;
msg->Context = pgContext;
msg->dwOptions = dwOptions;
msg->pTitle = pTitle;
msg->pMessage = pMessage;
msg->hDesktop = hDesktop;
msg->StartupEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
if (!msg->StartupEvent)
{
HeapFree(GetProcessHeap(), 0, msg);
return FALSE;
}
Thread = CreateThread(NULL,
0,
StartupWindowThread,
(PVOID)msg,
0,
&ThreadId);
if (Thread)
{
/* 'msg' will be freed by 'StartupWindowThread' */
CloseHandle(Thread);
WaitForSingleObject(msg->StartupEvent, INFINITE);
CloseHandle(msg->StartupEvent);
return TRUE;
}
else
{
/*
* The 'StartupWindowThread' thread couldn't be created,
* so we need to free the allocated 'msg'.
*/
HeapFree(GetProcessHeap(), 0, msg);
}
return FALSE;
}
if (pTitle)
SetWindowTextW(pgContext->hStatusWindow, pTitle);
SetDlgItemTextW(pgContext->hStatusWindow, IDC_STATUSLABEL, pMessage);
return TRUE;
}
static BOOL
GUIRemoveStatusMessage(
IN PGINA_CONTEXT pgContext)
{
if (pgContext->hStatusWindow)
{
EndDialog(pgContext->hStatusWindow, 0);
pgContext->hStatusWindow = NULL;
}
return TRUE;
}
static INT_PTR CALLBACK
EmptyWindowProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam)
{
PGINA_CONTEXT pgContext;
pgContext = (PGINA_CONTEXT)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
switch (uMsg)
{
case WM_INITDIALOG:
{
pgContext = (PGINA_CONTEXT)lParam;
SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pgContext);
/* Draw the logo bitmap */
pgContext->hBitmap = LoadImageW(pgContext->hDllInstance, MAKEINTRESOURCEW(IDI_ROSLOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
return TRUE;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
if (pgContext->hBitmap)
{
BeginPaint(hwndDlg, &ps);
DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pgContext->hBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
EndPaint(hwndDlg, &ps);
}
return TRUE;
}
case WM_DESTROY:
{
DeleteObject(pgContext->hBitmap);
return TRUE;
}
}
return FALSE;
}
static VOID
GUIDisplaySASNotice(
IN OUT PGINA_CONTEXT pgContext)
{
TRACE("GUIDisplaySASNotice()\n");
/* Display the notice window */
pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx,
pgContext->hDllInstance,
MAKEINTRESOURCEW(IDD_NOTICE_DLG),
GetDesktopWindow(),
EmptyWindowProc,
(LPARAM)pgContext);
}
/* Get the text contained in a textbox. Allocates memory in pText
* to contain the text. Returns TRUE in case of success */
static BOOL
GetTextboxText(
IN HWND hwndDlg,
IN INT TextboxId,
OUT LPWSTR *pText)
{
LPWSTR Text;
int Count;
Count = GetWindowTextLength(GetDlgItem(hwndDlg, TextboxId));
Text = HeapAlloc(GetProcessHeap(), 0, (Count + 1) * sizeof(WCHAR));
if (!Text)
return FALSE;
if (Count != GetWindowTextW(GetDlgItem(hwndDlg, TextboxId), Text, Count + 1))
{
HeapFree(GetProcessHeap(), 0, Text);
return FALSE;
}
*pText = Text;
return TRUE;
}
static
INT
ResourceMessageBox(
IN PGINA_CONTEXT pgContext,
IN HWND hwnd,
IN UINT uType,
IN UINT uCaption,
IN UINT uText)
{
WCHAR szCaption[256];
WCHAR szText[256];
LoadStringW(pgContext->hDllInstance, uCaption, szCaption, _countof(szCaption));
LoadStringW(pgContext->hDllInstance, uText, szText, _countof(szText));
return pgContext->pWlxFuncs->WlxMessageBox(pgContext->hWlx,
hwnd,
szText,
szCaption,
uType);
}
static
BOOL
DoChangePassword(
IN PGINA_CONTEXT pgContext,
IN HWND hwndDlg)
{
WCHAR UserName[256];
WCHAR Domain[256];
WCHAR OldPassword[256];
WCHAR NewPassword1[256];
WCHAR NewPassword2[256];
PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer = NULL;
PMSV1_0_CHANGEPASSWORD_RESPONSE ResponseBuffer = NULL;
ULONG RequestBufferSize;
ULONG ResponseBufferSize = 0;
LPWSTR Ptr;
BOOL res = FALSE;
NTSTATUS ProtocolStatus;
NTSTATUS Status;
GetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_USERNAME, UserName, _countof(UserName));
GetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_DOMAIN, Domain, _countof(Domain));
GetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_OLDPWD, OldPassword, _countof(OldPassword));
GetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_NEWPWD1, NewPassword1, _countof(NewPassword1));
GetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_NEWPWD2, NewPassword2, _countof(NewPassword2));
/* Compare the two passwords and fail if they do not match */
if (wcscmp(NewPassword1, NewPassword2) != 0)
{
ResourceMessageBox(pgContext,
hwndDlg,
MB_OK | MB_ICONEXCLAMATION,
IDS_CHANGEPWDTITLE,
IDS_NONMATCHINGPASSWORDS);
return FALSE;
}
/* Calculate the request buffer size */
RequestBufferSize = sizeof(MSV1_0_CHANGEPASSWORD_REQUEST) +
((wcslen(Domain) + 1) * sizeof(WCHAR)) +
((wcslen(UserName) + 1) * sizeof(WCHAR)) +
((wcslen(OldPassword) + 1) * sizeof(WCHAR)) +
((wcslen(NewPassword1) + 1) * sizeof(WCHAR));
/* Allocate the request buffer */
RequestBuffer = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
RequestBufferSize);
if (RequestBuffer == NULL)
{
ERR("HeapAlloc failed\n");
return FALSE;
}
/* Initialize the request buffer */
RequestBuffer->MessageType = MsV1_0ChangePassword;
RequestBuffer->Impersonating = TRUE;
Ptr = (LPWSTR)((ULONG_PTR)RequestBuffer + sizeof(MSV1_0_CHANGEPASSWORD_REQUEST));
/* Pack the domain name */
RequestBuffer->DomainName.Length = wcslen(Domain) * sizeof(WCHAR);
RequestBuffer->DomainName.MaximumLength = RequestBuffer->DomainName.Length + sizeof(WCHAR);
RequestBuffer->DomainName.Buffer = Ptr;
RtlCopyMemory(RequestBuffer->DomainName.Buffer,
Domain,
RequestBuffer->DomainName.MaximumLength);
Ptr = (LPWSTR)((ULONG_PTR)Ptr + RequestBuffer->DomainName.MaximumLength);
/* Pack the user name */
RequestBuffer->AccountName.Length = wcslen(UserName) * sizeof(WCHAR);
RequestBuffer->AccountName.MaximumLength = RequestBuffer->AccountName.Length + sizeof(WCHAR);
RequestBuffer->AccountName.Buffer = Ptr;
RtlCopyMemory(RequestBuffer->AccountName.Buffer,
UserName,
RequestBuffer->AccountName.MaximumLength);
Ptr = (LPWSTR)((ULONG_PTR)Ptr + RequestBuffer->AccountName.MaximumLength);
/* Pack the old password */
RequestBuffer->OldPassword.Length = wcslen(OldPassword) * sizeof(WCHAR);
RequestBuffer->OldPassword.MaximumLength = RequestBuffer->OldPassword.Length + sizeof(WCHAR);
RequestBuffer->OldPassword.Buffer = Ptr;
RtlCopyMemory(RequestBuffer->OldPassword.Buffer,
OldPassword,
RequestBuffer->OldPassword.MaximumLength);
Ptr = (LPWSTR)((ULONG_PTR)Ptr + RequestBuffer->OldPassword.MaximumLength);
/* Pack the new password */
RequestBuffer->NewPassword.Length = wcslen(NewPassword1) * sizeof(WCHAR);
RequestBuffer->NewPassword.MaximumLength = RequestBuffer->NewPassword.Length + sizeof(WCHAR);
RequestBuffer->NewPassword.Buffer = Ptr;
RtlCopyMemory(RequestBuffer->NewPassword.Buffer,
NewPassword1,
RequestBuffer->NewPassword.MaximumLength);
/* Connect to the LSA server */
if (!ConnectToLsa(pgContext))
{
ERR("ConnectToLsa() failed\n");
goto done;
}
/* Call the authentication package */
Status = LsaCallAuthenticationPackage(pgContext->LsaHandle,
pgContext->AuthenticationPackage,
RequestBuffer,
RequestBufferSize,
(PVOID*)&ResponseBuffer,
&ResponseBufferSize,
&ProtocolStatus);
if (!NT_SUCCESS(Status))
{
ERR("LsaCallAuthenticationPackage failed (Status 0x%08lx)\n", Status);
goto done;
}
if (!NT_SUCCESS(ProtocolStatus))
{
TRACE("LsaCallAuthenticationPackage failed (ProtocolStatus 0x%08lx)\n", ProtocolStatus);
goto done;
}
res = TRUE;
ResourceMessageBox(pgContext,
hwndDlg,
MB_OK | MB_ICONINFORMATION,
IDS_CHANGEPWDTITLE,
IDS_PASSWORDCHANGED);
if ((wcscmp(UserName, pgContext->UserName) == 0) &&
(wcscmp(Domain, pgContext->Domain) == 0) &&
(wcscmp(OldPassword, pgContext->Password) == 0))
{
ZeroMemory(pgContext->Password, sizeof(pgContext->Password));
wcscpy(pgContext->Password, NewPassword1);
}
done:
if (RequestBuffer != NULL)
HeapFree(GetProcessHeap(), 0, RequestBuffer);
if (ResponseBuffer != NULL)
LsaFreeReturnBuffer(ResponseBuffer);
return res;
}
static INT_PTR CALLBACK
ChangePasswordDialogProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam)
{
PGINA_CONTEXT pgContext;
pgContext = (PGINA_CONTEXT)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
switch (uMsg)
{
case WM_INITDIALOG:
{
pgContext = (PGINA_CONTEXT)lParam;
SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pgContext);
SetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_USERNAME, pgContext->UserName);
SendDlgItemMessageW(hwndDlg, IDC_CHANGEPWD_DOMAIN, CB_ADDSTRING, 0, (LPARAM)pgContext->Domain);
SendDlgItemMessageW(hwndDlg, IDC_CHANGEPWD_DOMAIN, CB_SETCURSEL, 0, 0);
SetFocus(GetDlgItem(hwndDlg, IDC_CHANGEPWD_OLDPWD));
return TRUE;
}
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
if (DoChangePassword(pgContext, hwndDlg))
{
EndDialog(hwndDlg, TRUE);
}
else
{
SetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_NEWPWD1, NULL);
SetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_NEWPWD2, NULL);
SetFocus(GetDlgItem(hwndDlg, IDC_CHANGEPWD_OLDPWD));
}
return TRUE;
case IDCANCEL:
EndDialog(hwndDlg, FALSE);
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hwndDlg, FALSE);
return TRUE;
}
return FALSE;
}
static VOID
OnInitSecurityDlg(HWND hwnd,
PGINA_CONTEXT pgContext)
{
WCHAR Buffer1[256];
WCHAR Buffer2[256];
WCHAR Buffer3[256];
WCHAR Buffer4[512];
LoadStringW(pgContext->hDllInstance, IDS_LOGONMSG, Buffer1, _countof(Buffer1));
wsprintfW(Buffer2, L"%s\\%s", pgContext->Domain, pgContext->UserName);
wsprintfW(Buffer4, Buffer1, Buffer2);
SetDlgItemTextW(hwnd, IDC_LOGONMSG, Buffer4);
LoadStringW(pgContext->hDllInstance, IDS_LOGONDATE, Buffer1, _countof(Buffer1));
GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE,
(SYSTEMTIME*)&pgContext->LogonTime, NULL, Buffer2, _countof(Buffer2));
GetTimeFormatW(LOCALE_USER_DEFAULT, 0,
(SYSTEMTIME*)&pgContext->LogonTime, NULL, Buffer3, _countof(Buffer3));
wsprintfW(Buffer4, Buffer1, Buffer2, Buffer3);
SetDlgItemTextW(hwnd, IDC_LOGONDATE, Buffer4);
if (pgContext->bAutoAdminLogon)
EnableWindow(GetDlgItem(hwnd, IDC_LOGOFF), FALSE);
}
static BOOL
OnChangePassword(
IN HWND hwnd,
IN PGINA_CONTEXT pgContext)
{
INT res;
TRACE("OnChangePassword()\n");
res = pgContext->pWlxFuncs->WlxDialogBoxParam(
pgContext->hWlx,
pgContext->hDllInstance,
MAKEINTRESOURCEW(IDD_CHANGE_PASSWORD),
hwnd,
ChangePasswordDialogProc,
(LPARAM)pgContext);
TRACE("Result: %x\n", res);
return FALSE;
}
static INT_PTR CALLBACK
LogOffDialogProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDYES:
EndDialog(hwndDlg, IDYES);
return TRUE;
case IDNO:
EndDialog(hwndDlg, IDNO);
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hwndDlg, IDNO);
return TRUE;
}
return FALSE;
}
static
INT
OnLogOff(
IN HWND hwndDlg,
IN PGINA_CONTEXT pgContext)
{
return pgContext->pWlxFuncs->WlxDialogBoxParam(
pgContext->hWlx,
pgContext->hDllInstance,
MAKEINTRESOURCEW(IDD_LOGOFF_DLG),
hwndDlg,
LogOffDialogProc,
(LPARAM)pgContext);
}
static
INT
OnShutDown(
IN HWND hwndDlg,
IN PGINA_CONTEXT pgContext)
{
INT ret;
DWORD ShutdownOptions;
if (ImpersonateLoggedOnUser(pgContext->UserToken))
{
pgContext->nShutdownAction = LoadShutdownSelState();
ShutdownOptions = GetAllowedShutdownOptions();
RevertToSelf();
}
else
{
ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
pgContext->nShutdownAction = 0;
ShutdownOptions = 0;
}
ret = ShutdownDialog(hwndDlg, ShutdownOptions, pgContext);
if (ret == IDOK)
{
if (ImpersonateLoggedOnUser(pgContext->UserToken))
{
SaveShutdownSelState(pgContext->nShutdownAction);
RevertToSelf();
}
else
{
ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
}
}
return ret;
}
static INT_PTR CALLBACK
LoggedOnWindowProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam)
{
PGINA_CONTEXT pgContext;
pgContext = (PGINA_CONTEXT)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
switch (uMsg)
{
case WM_INITDIALOG:
{
pgContext = (PGINA_CONTEXT)lParam;
SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pgContext);
OnInitSecurityDlg(hwndDlg, (PGINA_CONTEXT)lParam);
SetFocus(GetDlgItem(hwndDlg, IDNO));
return TRUE;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_LOCK:
EndDialog(hwndDlg, WLX_SAS_ACTION_LOCK_WKSTA);
return TRUE;
case IDC_LOGOFF:
if (OnLogOff(hwndDlg, pgContext) == IDYES)
EndDialog(hwndDlg, WLX_SAS_ACTION_LOGOFF);
return TRUE;
case IDC_SHUTDOWN:
if (OnShutDown(hwndDlg, pgContext) == IDOK)
EndDialog(hwndDlg, pgContext->nShutdownAction);
return TRUE;
case IDC_CHANGEPWD:
if (OnChangePassword(hwndDlg, pgContext))
EndDialog(hwndDlg, WLX_SAS_ACTION_PWD_CHANGED);
return TRUE;
case IDC_TASKMGR:
EndDialog(hwndDlg, WLX_SAS_ACTION_TASKLIST);
return TRUE;
case IDCANCEL:
EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
return TRUE;
}
break;
}
case WM_CLOSE:
{
EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
return TRUE;
}
}
return FALSE;
}
static INT
GUILoggedOnSAS(
IN OUT PGINA_CONTEXT pgContext,
IN DWORD dwSasType)
{
INT result;
TRACE("GUILoggedOnSAS()\n");
if (dwSasType != WLX_SAS_TYPE_CTRL_ALT_DEL)
{
/* Nothing to do for WLX_SAS_TYPE_TIMEOUT ; the dialog will
* close itself thanks to the use of WlxDialogBoxParam */
return WLX_SAS_ACTION_NONE;
}
pgContext->pWlxFuncs->WlxSwitchDesktopToWinlogon(
pgContext->hWlx);
result = pgContext->pWlxFuncs->WlxDialogBoxParam(
pgContext->hWlx,
pgContext->hDllInstance,
MAKEINTRESOURCEW(IDD_LOGGEDON_DLG),
GetDesktopWindow(),
LoggedOnWindowProc,
(LPARAM)pgContext);
if (result < WLX_SAS_ACTION_LOGON ||
result > WLX_SAS_ACTION_SWITCH_CONSOLE)
{
result = WLX_SAS_ACTION_NONE;
}
if (result == WLX_SAS_ACTION_NONE)
{
pgContext->pWlxFuncs->WlxSwitchDesktopToUser(
pgContext->hWlx);
}
return result;
}
static
BOOL
DoLogon(
IN HWND hwndDlg,
IN OUT PGINA_CONTEXT pgContext)
{
LPWSTR UserName = NULL;
LPWSTR Password = NULL;
LPWSTR Domain = NULL;
BOOL result = FALSE;
NTSTATUS Status, SubStatus = STATUS_SUCCESS;
if (GetTextboxText(hwndDlg, IDC_USERNAME, &UserName) && *UserName == '\0')
goto done;
if (GetTextboxText(hwndDlg, IDC_LOGON_TO, &Domain) && *Domain == '\0')
goto done;
if (!GetTextboxText(hwndDlg, IDC_PASSWORD, &Password))
goto done;
Status = DoLoginTasks(pgContext, UserName, Domain, Password, &SubStatus);
if (Status == STATUS_LOGON_FAILURE)
{
ResourceMessageBox(pgContext,
hwndDlg,
MB_OK | MB_ICONEXCLAMATION,
IDS_LOGONTITLE,
IDS_LOGONWRONGUSERORPWD);
goto done;
}
else if (Status == STATUS_ACCOUNT_RESTRICTION)
{
TRACE("DoLoginTasks failed! Status 0x%08lx SubStatus 0x%08lx\n", Status, SubStatus);
if (SubStatus == STATUS_ACCOUNT_DISABLED)
{
ResourceMessageBox(pgContext,
hwndDlg,
MB_OK | MB_ICONEXCLAMATION,
IDS_LOGONTITLE,
IDS_LOGONUSERDISABLED);
goto done;
}
else if (SubStatus == STATUS_ACCOUNT_LOCKED_OUT)
{
TRACE("Account locked!\n");
pgContext->pWlxFuncs->WlxMessageBox(pgContext->hWlx,
hwndDlg,
L"Account locked!",
L"Logon error",
MB_OK | MB_ICONERROR);
goto done;
}
else if ((SubStatus == STATUS_PASSWORD_MUST_CHANGE) ||
(SubStatus == STATUS_PASSWORD_EXPIRED))
{
if (SubStatus == STATUS_PASSWORD_MUST_CHANGE)
ResourceMessageBox(pgContext,
hwndDlg,
MB_OK | MB_ICONSTOP,
IDS_LOGONTITLE,
IDS_PASSWORDMUSTCHANGE);
else
ResourceMessageBox(pgContext,
hwndDlg,
MB_OK | MB_ICONSTOP,
IDS_LOGONTITLE,
IDS_PASSWORDEXPIRED);
if (!OnChangePassword(hwndDlg,
pgContext))
goto done;
Status = DoLoginTasks(pgContext,
pgContext->UserName,
pgContext->Domain,
pgContext->Password,
&SubStatus);
if (!NT_SUCCESS(Status))
{
TRACE("Login after password change failed! (Status 0x%08lx)\n", Status);
goto done;
}
}
else
{
TRACE("Other error!\n");
pgContext->pWlxFuncs->WlxMessageBox(pgContext->hWlx,
hwndDlg,
L"Other error!",
L"Logon error",
MB_OK | MB_ICONERROR);
goto done;
}
}
else if (!NT_SUCCESS(Status))
{
TRACE("DoLoginTasks failed! Status 0x%08lx\n", Status);
goto done;
}
if (!CreateProfile(pgContext, UserName, Domain, Password))
{
ERR("Failed to create the profile!\n");
goto done;
}
ZeroMemory(pgContext->Password, sizeof(pgContext->Password));
wcscpy(pgContext->Password, Password);
result = TRUE;
done:
if (UserName != NULL)
HeapFree(GetProcessHeap(), 0, UserName);
if (Password != NULL)
HeapFree(GetProcessHeap(), 0, Password);
if (Domain != NULL)
HeapFree(GetProcessHeap(), 0, Domain);
return result;
}
static
VOID
SetDomainComboBox(
HWND hwndDomainComboBox,
PGINA_CONTEXT pgContext)
{
WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwComputerNameLength;
LONG lIndex = 0;
LONG lFindIndex;
SendMessageW(hwndDomainComboBox, CB_RESETCONTENT, 0, 0);
dwComputerNameLength = _countof(szComputerName);
if (GetComputerNameW(szComputerName, &dwComputerNameLength))
{
lIndex = SendMessageW(hwndDomainComboBox, CB_ADDSTRING, 0, (LPARAM)szComputerName);
}
if (wcslen(pgContext->Domain) != 0)
{
lFindIndex = SendMessageW(hwndDomainComboBox, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)pgContext->Domain);
if (lFindIndex == CB_ERR)
{
lIndex = SendMessageW(hwndDomainComboBox, CB_ADDSTRING, 0, (LPARAM)pgContext->Domain);
}
else
{
lIndex = lFindIndex;
}
}
SendMessageW(hwndDomainComboBox, CB_SETCURSEL, lIndex, 0);
}
static INT_PTR CALLBACK
LoggedOutWindowProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam)
{
PGINA_CONTEXT pgContext;
pgContext = (PGINA_CONTEXT)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
switch (uMsg)
{
case WM_INITDIALOG:
{
/* FIXME: take care of NoDomainUI */
pgContext = (PGINA_CONTEXT)lParam;
SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pgContext);
if (!pgContext->bDontDisplayLastUserName)
SetDlgItemTextW(hwndDlg, IDC_USERNAME, pgContext->UserName);
if (pgContext->bDisableCAD)
EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE);
if (!pgContext->bShutdownWithoutLogon)
EnableWindow(GetDlgItem(hwndDlg, IDC_SHUTDOWN), FALSE);
SetDomainComboBox(GetDlgItem(hwndDlg, IDC_LOGON_TO), pgContext);
SetFocus(GetDlgItem(hwndDlg, pgContext->bDontDisplayLastUserName ? IDC_USERNAME : IDC_PASSWORD));
/* Draw the logo bitmap */
pgContext->hBitmap = LoadImageW(pgContext->hDllInstance, MAKEINTRESOURCEW(IDI_ROSLOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
return TRUE;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
if (pgContext->hBitmap)
{
BeginPaint(hwndDlg, &ps);
DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pgContext->hBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
EndPaint(hwndDlg, &ps);
}
return TRUE;
}
case WM_DESTROY:
DeleteObject(pgContext->hBitmap);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
if (DoLogon(hwndDlg, pgContext))
EndDialog(hwndDlg, WLX_SAS_ACTION_LOGON);
return TRUE;
case IDCANCEL:
EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
return TRUE;
case IDC_SHUTDOWN:
if (OnShutDown(hwndDlg, pgContext) == IDOK)
EndDialog(hwndDlg, pgContext->nShutdownAction);
return TRUE;
}
break;
}
return FALSE;
}
static
INT_PTR
CALLBACK
LegalNoticeDialogProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam)
{
PLEGALNOTICEDATA pLegalNotice;
switch (uMsg)
{
case WM_INITDIALOG:
pLegalNotice = (PLEGALNOTICEDATA)lParam;
SetWindowTextW(hwndDlg, pLegalNotice->pszCaption);
SetDlgItemTextW(hwndDlg, IDC_LEGALNOTICE_TEXT, pLegalNotice->pszText);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
EndDialog(hwndDlg, 0);
return TRUE;
case IDCANCEL:
EndDialog(hwndDlg, 0);
return TRUE;
}
break;
}
return FALSE;
}
static INT
GUILoggedOutSAS(
IN OUT PGINA_CONTEXT pgContext)
{
LEGALNOTICEDATA LegalNotice = {NULL, NULL};
HKEY hKey = NULL;
LONG rc;
int result;
TRACE("GUILoggedOutSAS()\n");
rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
0,
KEY_QUERY_VALUE,
&hKey);
if (rc == ERROR_SUCCESS)
{
ReadRegSzValue(hKey,
L"LegalNoticeCaption",
&LegalNotice.pszCaption);
ReadRegSzValue(hKey,
L"LegalNoticeText",
&LegalNotice.pszText);
RegCloseKey(hKey);
}
if (LegalNotice.pszCaption != NULL && wcslen(LegalNotice.pszCaption) != 0 &&
LegalNotice.pszText != NULL && wcslen(LegalNotice.pszText) != 0)
{
pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx,
pgContext->hDllInstance,
MAKEINTRESOURCEW(IDD_LEGALNOTICE_DLG),
GetDesktopWindow(),
LegalNoticeDialogProc,
(LPARAM)&LegalNotice);
}
if (LegalNotice.pszCaption != NULL)
HeapFree(GetProcessHeap(), 0, LegalNotice.pszCaption);
if (LegalNotice.pszText != NULL)
HeapFree(GetProcessHeap(), 0, LegalNotice.pszText);
result = pgContext->pWlxFuncs->WlxDialogBoxParam(
pgContext->hWlx,
pgContext->hDllInstance,
MAKEINTRESOURCEW(IDD_LOGGEDOUT_DLG),
GetDesktopWindow(),
LoggedOutWindowProc,
(LPARAM)pgContext);
if (result >= WLX_SAS_ACTION_LOGON &&
result <= WLX_SAS_ACTION_SWITCH_CONSOLE)
{
WARN("WlxLoggedOutSAS() returns 0x%x\n", result);
return result;
}
WARN("WlxDialogBoxParam() failed (0x%x)\n", result);
return WLX_SAS_ACTION_NONE;
}
static VOID
SetLockMessage(HWND hwnd,
INT nDlgItem,
PGINA_CONTEXT pgContext)
{
WCHAR Buffer1[256];
WCHAR Buffer2[256];
WCHAR Buffer3[512];
LoadStringW(pgContext->hDllInstance, IDS_LOCKMSG, Buffer1, _countof(Buffer1));
wsprintfW(Buffer2, L"%s\\%s", pgContext->Domain, pgContext->UserName);
wsprintfW(Buffer3, Buffer1, Buffer2);
SetDlgItemTextW(hwnd, nDlgItem, Buffer3);
}
static
BOOL
DoUnlock(
IN HWND hwndDlg,
IN PGINA_CONTEXT pgContext,
OUT LPINT Action)
{
WCHAR Buffer1[256];
WCHAR Buffer2[256];
LPWSTR UserName = NULL;
LPWSTR Password = NULL;
BOOL res = FALSE;
if (GetTextboxText(hwndDlg, IDC_USERNAME, &UserName) && *UserName == '\0')
{
HeapFree(GetProcessHeap(), 0, UserName);
return FALSE;
}
if (GetTextboxText(hwndDlg, IDC_PASSWORD, &Password))
{
if (UserName != NULL && Password != NULL &&
wcscmp(UserName, pgContext->UserName) == 0 &&
wcscmp(Password, pgContext->Password) == 0)
{
*Action = WLX_SAS_ACTION_UNLOCK_WKSTA;
res = TRUE;
}
else if (wcscmp(UserName, pgContext->UserName) == 0 &&
wcscmp(Password, pgContext->Password) != 0)
{
/* Wrong Password */
LoadStringW(pgContext->hDllInstance, IDS_LOCKEDWRONGPASSWORD, Buffer2, _countof(Buffer2));
LoadStringW(pgContext->hDllInstance, IDS_COMPUTERLOCKED, Buffer1, _countof(Buffer1));
MessageBoxW(hwndDlg, Buffer2, Buffer1, MB_OK | MB_ICONERROR);
}
else
{
/* Wrong user name */
if (DoAdminUnlock(pgContext, UserName, NULL, Password))
{
*Action = WLX_SAS_ACTION_UNLOCK_WKSTA;
res = TRUE;
}
else
{
LoadStringW(pgContext->hDllInstance, IDS_LOCKEDWRONGUSER, Buffer1, _countof(Buffer1));
wsprintfW(Buffer2, Buffer1, pgContext->Domain, pgContext->UserName);
LoadStringW(pgContext->hDllInstance, IDS_COMPUTERLOCKED, Buffer1, _countof(Buffer1));
MessageBoxW(hwndDlg, Buffer2, Buffer1, MB_OK | MB_ICONERROR);
}
}
}
if (UserName != NULL)
HeapFree(GetProcessHeap(), 0, UserName);
if (Password != NULL)
HeapFree(GetProcessHeap(), 0, Password);
return res;
}
static
INT_PTR
CALLBACK
UnlockWindowProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam)
{
PGINA_CONTEXT pgContext;
INT result = WLX_SAS_ACTION_NONE;
pgContext = (PGINA_CONTEXT)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
switch (uMsg)
{
case WM_INITDIALOG:
{
pgContext = (PGINA_CONTEXT)lParam;
SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pgContext);
SetLockMessage(hwndDlg, IDC_LOCKMSG, pgContext);
SetDlgItemTextW(hwndDlg, IDC_USERNAME, pgContext->UserName);
SetFocus(GetDlgItem(hwndDlg, IDC_PASSWORD));
if (pgContext->bDisableCAD)
EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE);
/* Draw the logo bitmap */
pgContext->hBitmap = LoadImageW(pgContext->hDllInstance, MAKEINTRESOURCEW(IDI_ROSLOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
return TRUE;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
if (pgContext->hBitmap)
{
BeginPaint(hwndDlg, &ps);
DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pgContext->hBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
EndPaint(hwndDlg, &ps);
}
return TRUE;
}
case WM_DESTROY:
DeleteObject(pgContext->hBitmap);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
if (DoUnlock(hwndDlg, pgContext, &result))
EndDialog(hwndDlg, result);
return TRUE;
case IDCANCEL:
EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
return TRUE;
}
break;
}
return FALSE;
}
static INT
GUILockedSAS(
IN OUT PGINA_CONTEXT pgContext)
{
int result;
TRACE("GUILockedSAS()\n");
result = pgContext->pWlxFuncs->WlxDialogBoxParam(
pgContext->hWlx,
pgContext->hDllInstance,
MAKEINTRESOURCEW(IDD_UNLOCK_DLG),
GetDesktopWindow(),
UnlockWindowProc,
(LPARAM)pgContext);
if (result >= WLX_SAS_ACTION_LOGON &&
result <= WLX_SAS_ACTION_SWITCH_CONSOLE)
{
WARN("GUILockedSAS() returns 0x%x\n", result);
return result;
}
WARN("GUILockedSAS() failed (0x%x)\n", result);
return WLX_SAS_ACTION_NONE;
}
static INT_PTR CALLBACK
LockedWindowProc(
IN HWND hwndDlg,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam)
{
PGINA_CONTEXT pgContext;
pgContext = (PGINA_CONTEXT)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
switch (uMsg)
{
case WM_INITDIALOG:
{
pgContext = (PGINA_CONTEXT)lParam;
SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pgContext);
/* Draw the logo bitmap */
pgContext->hBitmap = LoadImageW(pgContext->hDllInstance, MAKEINTRESOURCEW(IDI_ROSLOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
SetLockMessage(hwndDlg, IDC_LOCKMSG, pgContext);
return TRUE;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
if (pgContext->hBitmap)
{
BeginPaint(hwndDlg, &ps);
DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pgContext->hBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
EndPaint(hwndDlg, &ps);
}
return TRUE;
}
case WM_DESTROY:
{
DeleteObject(pgContext->hBitmap);
return TRUE;
}
}
return FALSE;
}
static VOID
GUIDisplayLockedNotice(
IN OUT PGINA_CONTEXT pgContext)
{
TRACE("GUIdisplayLockedNotice()\n");
pgContext->pWlxFuncs->WlxDialogBoxParam(
pgContext->hWlx,
pgContext->hDllInstance,
MAKEINTRESOURCEW(IDD_LOCKED_DLG),
GetDesktopWindow(),
LockedWindowProc,
(LPARAM)pgContext);
}
GINA_UI GinaGraphicalUI = {
GUIInitialize,
GUIDisplayStatusMessage,
GUIRemoveStatusMessage,
GUIDisplaySASNotice,
GUILoggedOnSAS,
GUILoggedOutSAS,
GUILockedSAS,
GUIDisplayLockedNotice,
};