windows-nt/Source/XPSP1/NT/ds/security/gina/msgina/options.c
2020-09-26 16:20:57 +08:00

707 lines
20 KiB
C

/****************************** Module Header ******************************\
* Module Name: options.c
*
* Copyright (c) 1991, Microsoft Corporation
*
* Implementation of functions to support security options dialog.
*
* History:
* 12-05-91 Davidc Created.
\***************************************************************************/
#include "msgina.h"
#include "shtdnp.h"
#include <stdio.h>
#include <wchar.h>
#pragma hdrstop
#define CTRL_TASKLIST_SHELL
#define LPTSTR LPWSTR
#define BOOLIFY(expr) (!!(expr))
//
// Private prototypes
//
INT_PTR WINAPI
OptionsDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
);
BOOL OptionsDlgInit(HWND);
INT_PTR WINAPI
EndWindowsSessionDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
);
/******************************************************************************
*
* HandleFailedDisconnect
*
* Tell the user why the disconnect from the current Logon failed.
*
* ENTRY:
* hDlg (input)
* This dialog's window handle.
* SessionId (input)
* The user's current SessionId.
*
* EXIT:
*
******************************************************************************/
VOID
HandleFailedDisconnect( HWND hDlg,
ULONG SessionId,
PGLOBALS pGlobals )
{
DWORD Error;
TCHAR Buffer1[MAX_STRING_BYTES];
TCHAR Buffer2[MAX_STRING_BYTES];
TCHAR Buffer3[MAX_STRING_BYTES];
Error = GetLastError();
switch (Error) {
default:
LoadString( hDllInstance, IDS_MULTIUSER_UNEXPECTED_DISCONNECT_FAILURE,
Buffer1, MAX_STRING_BYTES );
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, Error, 0, Buffer3, MAX_STRING_BYTES, NULL );
_snwprintf(Buffer2, MAX_STRING_BYTES, Buffer1, SessionId, Buffer3);
LoadString( hDllInstance, IDS_MULTIUSER_DISCONNECT_FAILED,
Buffer1, MAX_STRING_BYTES );
TimeoutMessageBoxlpstr( hDlg, pGlobals, Buffer2,
Buffer1,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT );
break;
}
}
/***************************************************************************\
* SecurityOptions
*
* Show the user the security options dialog and do what they ask.
*
* Returns:
* MSGINA_DLG_SUCCESS if everything went OK and the user wants to continue
* DLG_LOCK_WORKSTAION if the user chooses to lock the workstation
* DLG_INTERRUPTED() - this is a set of possible interruptions (see winlogon.h)
* MSGINA_DLG_FAILURE if the dialog cannot be brought up.
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
INT_PTR
SecurityOptions(
PGLOBALS pGlobals)
{
int Result;
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, OPTIONS_TIMEOUT);
Result = pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx,
hDllInstance,
(LPTSTR)IDD_OPTIONS_DIALOG,
NULL,
OptionsDlgProc,
(LPARAM) pGlobals);
if (Result == WLX_DLG_INPUT_TIMEOUT)
{
Result = MSGINA_DLG_SUCCESS;
}
return(Result);
}
/***************************************************************************\
*
* FUNCTION: OptionsDlgProc
*
* PURPOSE: Processes messages for Security options dialog
*
\***************************************************************************/
INT_PTR WINAPI
OptionsDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
INT_PTR Result;
HANDLE UserHandle;
NTSTATUS Status;
BOOL EnableResult;
BOOL ControlKey;
switch (message) {
case WM_INITDIALOG:
SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
if (!OptionsDlgInit(hDlg))
{
EndDialog(hDlg, MSGINA_DLG_FAILURE);
}
return(TRUE);
case WLX_WM_SAS:
//
// If this is someone hitting C-A-D, swallow it.
//
if (wParam == WLX_SAS_TYPE_CTRL_ALT_DEL)
{
return(TRUE);
}
//
// Other SAS's (like timeout), return FALSE and let winlogon
// deal with it.
//
DebugLog((DEB_TRACE, "Received SAS event %d, which we're letting winlogon cope with\n", wParam));
return(FALSE);
case WM_COMMAND:
ControlKey = (GetKeyState(VK_LCONTROL) < 0) ||
(GetKeyState(VK_RCONTROL) < 0) ;
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hDlg, MSGINA_DLG_SUCCESS);
return TRUE;
case IDD_OPTIONS_CHANGEPWD:
Result = ChangePassword(hDlg,
pGlobals,
pGlobals->UserName,
pGlobals->Domain,
CHANGEPWD_OPTION_ALL );
if (DLG_INTERRUPTED(Result))
{
EndDialog(hDlg, Result);
}
return(TRUE);
case IDD_OPTIONS_LOCK:
EndDialog(hDlg, MSGINA_DLG_LOCK_WORKSTATION);
return(TRUE);
case IDD_OPTIONS_LOGOFF:
if (ControlKey)
{
Result = TimeoutMessageBox(hDlg,
pGlobals,
IDS_LOGOFF_LOSE_CHANGES,
IDS_LOGOFF_TITLE,
MB_OKCANCEL | MB_DEFBUTTON2 | MB_ICONSTOP,
TIMEOUT_CURRENT);
if (Result == MSGINA_DLG_SUCCESS)
{
EndDialog(hDlg, MSGINA_DLG_FORCE_LOGOFF);
}
}
else
{
//
// Confirm the user really knows what they're doing.
//
Result = pWlxFuncs->WlxDialogBoxParam(
pGlobals->hGlobalWlx,
hDllInstance,
MAKEINTRESOURCE(IDD_LOGOFFWINDOWS_DIALOG),
hDlg,
EndWindowsSessionDlgProc,
(LPARAM)pGlobals);
if (Result == MSGINA_DLG_SUCCESS)
{
EndDialog(hDlg, MSGINA_DLG_USER_LOGOFF);
}
}
return(TRUE);
case IDD_OPTIONS_SHUTDOWN:
//
// If they held down Ctrl while selecting shutdown - then
// we'll do a quick and dirty reboot.
// i.e. we skip the call to ExitWindows
//
if ( ControlKey && TestUserPrivilege(pGlobals->UserProcessData.UserToken, SE_SHUTDOWN_PRIVILEGE))
{
//
// Check they know what they're doing
//
Result = TimeoutMessageBox(hDlg,
pGlobals,
IDS_REBOOT_LOSE_CHANGES,
IDS_EMERGENCY_SHUTDOWN,
MB_OKCANCEL | MB_DEFBUTTON2 | MB_ICONSTOP,
TIMEOUT_CURRENT);
if (Result == MSGINA_DLG_SUCCESS)
{
//
// Impersonate the user for the shutdown call
//
UserHandle = ImpersonateUser( &pGlobals->UserProcessData, NULL );
ASSERT(UserHandle != NULL);
if ( UserHandle )
{
//
// Enable the shutdown privilege
// This should always succeed - we are either system or a user who
// successfully passed the privilege check in ExitWindowsEx.
//
EnableResult = EnablePrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE);
ASSERT(EnableResult);
//
// Do the final system shutdown pass (reboot). Note, if
// the privilege was not enabled, the API will reject this
// call.
//
Status = NtShutdownSystem(ShutdownReboot);
}
}
if (Result != MSGINA_DLG_FAILURE)
{
EndDialog(hDlg, Result);
}
return(TRUE);
}
//
// This is a normal shutdown request
//
// Check they know what they're doing and find
// out if they want to reboot too.
//
Result = WinlogonShutdownDialog(hDlg, pGlobals, 0);
// Pre-filter the Disconnect option and handle
// it now since it may fail
if (Result == MSGINA_DLG_DISCONNECT)
{
if ( pWlxFuncs->WlxDisconnect() )
{
Result = MSGINA_DLG_SUCCESS;
}
else
{
HandleFailedDisconnect(hDlg, pGlobals->MuGlobals.SessionId, pGlobals);
Result = MSGINA_DLG_FAILURE;
}
}
if (Result != MSGINA_DLG_FAILURE)
{
EndDialog(hDlg, Result);
}
return(TRUE);
case IDD_OPTIONS_TASKLIST:
EndDialog(hDlg, MSGINA_DLG_TASKLIST);
//
// Tickle the messenger so it will display any queue'd messages.
// (This call is a kind of NoOp).
//
NetMessageNameDel(NULL,L"");
return(TRUE);
break;
}
case WM_ERASEBKGND:
return PaintBranding(hDlg, (HDC)wParam, 0, FALSE, FALSE, COLOR_BTNFACE);
case WM_QUERYNEWPALETTE:
return BrandingQueryNewPalete(hDlg);
case WM_PALETTECHANGED:
return BrandingPaletteChanged(hDlg, (HWND)wParam);
}
// We didn't process the message
return(FALSE);
}
/****************************************************************************
FUNCTION: OptionsDlgInit
PURPOSE: Handles initialization of security options dialog
RETURNS: TRUE on success, FALSE on failure
****************************************************************************/
BOOL OptionsDlgInit(
HWND hDlg)
{
PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA);
TCHAR Buffer1[MAX_STRING_BYTES];
TCHAR Buffer2[MAX_STRING_BYTES];
BOOL Result;
DWORD dwValue, dwType;
HKEY hkeyPolicy;
DWORD cbData;
HANDLE hImpersonateUser = NULL;
USHORT Flags = FT_TIME|FT_DATE;
LCID locale;
SetWelcomeCaption( hDlg );
//
// Set the logon info text
//
if (pGlobals->Domain[0] == TEXT('\0') )
{
//
// there is no domain name
//
if ( lstrlen(pGlobals->UserFullName) == 0)
{
//
// There is no full name
//
LoadString(hDllInstance, IDS_LOGON_EMAIL_NAME_NFN_INFO, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->UserName);
}
else
{
LoadString(hDllInstance, IDS_LOGON_EMAIL_NAME_INFO, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1,
pGlobals->UserFullName,
pGlobals->UserName);
}
}
else
{
if ( lstrlen(pGlobals->UserFullName) == 0)
{
//
// There is no full name
//
LoadString(hDllInstance, IDS_LOGON_NAME_NFN_INFO, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->Domain,
pGlobals->UserName);
}
else
{
LoadString(hDllInstance, IDS_LOGON_NAME_INFO, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->UserFullName,
pGlobals->Domain,
pGlobals->UserName);
}
}
SetDlgItemText(hDlg, IDD_OPTIONS_LOGON_NAME_INFO, Buffer2);
//
// Set the logon time/date - but do it as the logged on user
//
hImpersonateUser = ImpersonateUser(&pGlobals->UserProcessData, NULL);
locale = GetUserDefaultLCID();
if (((PRIMARYLANGID(LANGIDFROMLCID(locale)) == LANG_ARABIC)
|| (PRIMARYLANGID(LANGIDFROMLCID(locale)) == LANG_HEBREW)))
{
// Get the real item windows ExStyle.
HWND hWnd = GetDlgItem(hDlg, IDD_OPTIONS_LOGON_DATE);
DWORD dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
if ((BOOLIFY(dwExStyle & WS_EX_RTLREADING)) != (BOOLIFY(dwExStyle & WS_EX_LAYOUTRTL)))
Flags |= FT_RTL;
else
Flags |= FT_LTR;
}
Result = FormatTime(&pGlobals->LogonTime, Buffer1, sizeof(Buffer1) / sizeof(Buffer1[0]), Flags);
if (hImpersonateUser)
{
StopImpersonating(hImpersonateUser);
}
ASSERT(Result);
SetDlgItemText(hDlg, IDD_OPTIONS_LOGON_DATE, Buffer1);
//
// Check if DisableLockWorkstation is set for the entire machine
//
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY,
0, KEY_READ, &hkeyPolicy) == ERROR_SUCCESS)
{
dwValue = 0;
cbData = sizeof(dwValue);
RegQueryValueEx(hkeyPolicy, DISABLE_LOCK_WKSTA,
0, &dwType, (LPBYTE)&dwValue, &cbData);
if (dwValue)
{
EnableDlgItem(hDlg, IDD_OPTIONS_LOCK, FALSE);
}
RegCloseKey(hkeyPolicy);
}
//
// Smart card only users can't change the password
//
if (pGlobals->Profile && (pGlobals->Profile->UserFlags & UF_SMARTCARD_REQUIRED))
{
EnableDlgItem(hDlg, IDD_OPTIONS_CHANGEPWD, FALSE);
}
//
// Check for policy and then disable corresponding options
//
if (OpenHKeyCurrentUser(pGlobals)) {
if (RegOpenKeyEx(pGlobals->UserProcessData.hCurrentUser,
WINLOGON_POLICY_KEY,
0, KEY_READ, &hkeyPolicy) == ERROR_SUCCESS)
{
dwValue = 0;
cbData = sizeof(dwValue);
RegQueryValueEx(hkeyPolicy, DISABLE_LOCK_WKSTA,
0, &dwType, (LPBYTE)&dwValue, &cbData);
if (dwValue)
{
EnableDlgItem(hDlg, IDD_OPTIONS_LOCK, FALSE);
}
dwValue = 0;
cbData = sizeof(dwValue);
RegQueryValueEx(hkeyPolicy, DISABLE_TASK_MGR,
0, &dwType, (LPBYTE)&dwValue, &cbData);
if (dwValue)
{
EnableDlgItem(hDlg, IDD_OPTIONS_TASKLIST, FALSE);
ShowDlgItem(hDlg, IDD_OPTIONS_TASKMGR_TEXT, FALSE);
}
dwValue = 0;
cbData = sizeof(dwValue);
RegQueryValueEx(hkeyPolicy, DISABLE_CHANGE_PASSWORD,
0, &dwType, (LPBYTE)&dwValue, &cbData);
if (dwValue)
{
EnableDlgItem(hDlg, IDD_OPTIONS_CHANGEPWD, FALSE);
}
RegCloseKey(hkeyPolicy);
}
if (RegOpenKeyEx(pGlobals->UserProcessData.hCurrentUser, EXPLORER_POLICY_KEY,
0, KEY_READ, &hkeyPolicy) == ERROR_SUCCESS)
{
dwValue = 0;
cbData = sizeof(dwValue);
RegQueryValueEx(hkeyPolicy, NOLOGOFF,
0, &dwType, (LPBYTE)&dwValue, &cbData);
if (dwValue)
{
EnableDlgItem(hDlg, IDD_OPTIONS_LOGOFF, FALSE);
}
dwValue = 0;
cbData = sizeof(dwValue);
RegQueryValueEx(hkeyPolicy, NOCLOSE,
0, &dwType, (LPBYTE)&dwValue, &cbData);
//
// If this is not the system console, check the appropriate key in registry
//
if ( !g_Console ) {
if (!TestUserPrivilege(pGlobals->UserProcessData.UserToken, SE_SHUTDOWN_PRIVILEGE)) {
RegQueryValueEx(hkeyPolicy, NODISCONNECT,
0, &dwType, (LPBYTE)&dwValue, &cbData);
}
}
if (dwValue)
{
EnableDlgItem(hDlg, IDD_OPTIONS_SHUTDOWN, FALSE);
}
RegCloseKey(hkeyPolicy);
}
CloseHKeyCurrentUser(pGlobals);
}
// Position ourselves nicely
SizeForBranding(hDlg, FALSE);
CentreWindow(hDlg);
return TRUE;
}
/***************************************************************************\
* FUNCTION: EndWindowsSessionDlgProc
*
* PURPOSE: Processes messages for Logging off Windows Nt confirmation dialog
*
* RETURNS: MSGINA_DLG_SUCCESS - The user wants to logoff.
* MSGINA_DLG_FAILURE - The user doesn't want to logoff.
* DLG_INTERRUPTED() - a set defined in winlogon.h
*
* HISTORY:
*
* 05-17-92 Davidc Created.
*
\***************************************************************************/
INT_PTR WINAPI
EndWindowsSessionDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
switch (message)
{
case WM_INITDIALOG:
{
HICON hIcon;
SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
// Load the 48 x 48 version of the logoff icon
hIcon = LoadImage (hDllInstance, MAKEINTRESOURCE(IDI_STLOGOFF),
IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
if (hIcon)
{
SendDlgItemMessage (hDlg, IDD_LOGOFFICON, STM_SETICON, (WPARAM) hIcon, 0);
}
// Position ourselves nicely
CentreWindow(hDlg);
}
return(TRUE);
case WLX_WM_SAS:
//
// If this is someone hitting C-A-D, swallow it.
//
if (wParam == WLX_SAS_TYPE_CTRL_ALT_DEL)
{
return(TRUE);
}
//
// Other SAS's (like timeout), return FALSE and let winlogon
// deal with it.
//
return(FALSE);
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
EndDialog(hDlg, MSGINA_DLG_SUCCESS);
return(TRUE);
case IDCANCEL:
EndDialog(hDlg, MSGINA_DLG_FAILURE);
return(TRUE);
}
break;
}
// We didn't process the message
return(FALSE);
}