/****************************** 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 #include #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); }