// UMDialog.cpp : implementation file // Author: J. Eckhardt, ECO Kommunikation // Copyright (c) 1997-1999 Microsoft Corporation // // History: // Changes // Yuri Khramov // 01-jun-99: DisplayName key used in the Dialog (Localization) // 11-jun-99: DlgHasClosed code changed to work with app closure // 15-jun-99: Timer delay increased 1000ms // // Bug fixes and Changes Anil Kumar 1999 //--------------------------------------------------------------------- #include // MFC core and standard components #include // MFC extensions #include "UManDlg.h" #include "UMDialog.h" #include "UMAbout.h" #include "_UMDlg.h" #include "_UMClnt.h" #include "_UMTool.h" #include "UMS_Ctrl.h" #include "w95trace.h" #include #include #include #include #include "deskswitch.c" #include "ManageShellLinks.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // -------------------------------------------- // constants #define IDC_ABOUT 10 #define UPDATE_CLIENT_LIST_TIMER 1 // -------------------------------------------- // variables static DWORD g_cClients = 0; static umclient_tsp g_rgClients = NULL; static DWORD s_dwStartMode = START_BY_OTHER; static BOOL s_fShowWarningAgain = TRUE; extern CUMDlgApp theApp; // -------------------------------------------- // C prototypes static BOOL InitClientData(void); static BOOL StartClientsOnShow(); static BOOL WriteClientData(BOOL fRunningSecure); static BOOL IsStartAuto(); static BOOL CantStopClient(umclient_tsp client); static int GetClientNameFromAccelerator(WPARAM wVK); extern "C" BOOL StartAppAsUser( LPCTSTR appPath, LPTSTR cmdLine, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); // Help ID's for context sensitive help DWORD g_rgHelpIds[] = { IDC_NAME_STATUS, 3, IDC_START, 1001, IDC_STOP, 1002, IDC_START_AT_LOGON, 1003, // TODO UE needs to update CS help IDC_START_WITH_UM, 1004, IDC_START_ON_LOCK, 1005, // TODO UE needs to add to CS help IDOK, 1100, IDCANCEL, 1200, ID_HELP, 1300, }; // --------------------------------------------------------------- extern "C"{ //-------------------------------- HWND g_hWndDlg = NULL; HWND aboutWnd = NULL; static HANDLE s_hDlgThread = NULL; static HDESK s_hdeskSave = 0; static HDESK s_hdeskInput = 0; // UnassignDesktop gets called after the thread has exited to // close desktop handles opened in AssignDesktop. inline void UnassignDesktop() { if (s_hdeskInput) { CloseDesktop(s_hdeskInput); s_hdeskInput = 0; } } BOOL AssignDesktop(DWORD dwThreadId) { s_hdeskSave = GetThreadDesktop(dwThreadId); s_hdeskInput = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED); if (!s_hdeskInput) { s_hdeskInput = OpenDesktop(_TEXT("Winlogon"),0,FALSE,MAXIMUM_ALLOWED); } if (s_hdeskInput) { BOOL fSet = SetThreadDesktop(s_hdeskInput); } return (s_hdeskInput)?TRUE:FALSE; } //-------------------------------- DWORD UManDlgThread(LPVOID /* UNUSED */ in) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); UMDialog dlg; // assign thread to the input desktop (have to do // this here so it works on the winlogon desktop) if (AssignDesktop(GetCurrentThreadId())) { // initialize COM *after* assign to input desktop // because CoInitialize creates a hidden window on // the current desktop. CoInitialize(NULL); InitCommonControls(); if (InitClientData()) { Sleep(10); dlg.DoModal(); if (g_rgClients) { VirtualFree(g_rgClients,0,MEM_RELEASE); g_rgClients = NULL; } g_cClients = 0; g_hWndDlg = NULL; s_hDlgThread = NULL; } CoUninitialize(); // uninitialize COM } return 1; } void StopDialog() { if (aboutWnd) { EndDialog(aboutWnd,0); aboutWnd = NULL; Sleep(10); } if (g_hWndDlg) { ::PostMessage(g_hWndDlg, WM_CLOSE, 0, 0); g_hWndDlg = NULL; Sleep(10); UnassignDesktop(); } if (g_rgClients) { VirtualFree(g_rgClients,0,MEM_RELEASE); g_rgClients = NULL; } g_cClients = 0; } //-------------------------------- #if defined(_X86_) __declspec (dllexport) #endif // UManDlg - Opens or closes the utilman dialog. // // fShowDlg - TRUE if dialog should be shown, FALSE if dialog should be closed // fWaitForDlgClose - TRUE if the function should not return until the dialog // is closed or a desktop switch happens else FALSE. // dwVersion - The utilman version // // returns TRUE if the dialog was opened or closed // returns FALSE if the dialog could not be opened or it wasn't open // BOOL UManDlg(BOOL fShowDlg, BOOL fWaitForDlgClose, DWORD dwVersion) { BOOL fRv = FALSE; if (dwVersion != UMANDLG_VERSION) return FALSE; AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (fShowDlg) { if (!s_hDlgThread) { s_hDlgThread = CreateThread(NULL, 0, UManDlgThread, NULL, 0, NULL); } else { SetForegroundWindow((aboutWnd)?aboutWnd:g_hWndDlg); } if (s_hDlgThread && fWaitForDlgClose) { // This code is executed on the default desktop for the following cases: // // 1. Utilman #1 run from the start menu // 2. Utilman #2 run from the start menu (utilman #1 is SYSTEM) // 3. Utilman #2 run by utilman #1 in user's context // // Wait for either the dialog to close or a desktop switch then return. // This will end this instance of utilman. If there is a utilman // running as SYSTEM it will bring up the dialog on the other desktop. HANDLE rghEvents[2]; rghEvents[0] = s_hDlgThread; rghEvents[1] = OpenEvent(SYNCHRONIZE, FALSE, __TEXT("WinSta0_DesktopSwitch")); while (TRUE) { DWORD dwObj = MsgWaitForMultipleObjects(2, rghEvents, FALSE, INFINITE, QS_ALLINPUT ); switch (dwObj) { case WAIT_OBJECT_0 + 1: // the desktop is changing; close the dialog StopDialog(); // intentional fall thru to cleanup code case WAIT_OBJECT_0: // the thread exited; clean up and return CloseHandle(s_hDlgThread); s_hDlgThread = 0; CloseHandle(rghEvents[1]); return TRUE; break; default: // process messages { MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } break; } } } } else { // This code is executed when utilman is running on the secure desktop. In // that case, utilman brings up the dialog as a thread from its process. // When the desktop switch is detected utilman calls this function to close // the dialog. It will be restarted again on the new desktop. fRv = (g_hWndDlg && s_hDlgThread); StopDialog(); } return fRv; } BOOL IsDialogUp() { return (g_hWndDlg && s_hDlgThread)?TRUE:FALSE; } }//extern "C" ///////////////////////////////////////////////////////////////////////////// // CWarningDlg dialog CWarningDlg::CWarningDlg(CWnd* pParent /*=NULL*/) : CDialog(CWarningDlg::IDD, pParent) { //{{AFX_DATA_INIT(CWarningDlg) m_fDontWarnAgain = TRUE; //}}AFX_DATA_INIT } void CWarningDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CWarningDlg) DDX_Check(pDX, IDC_CHK_WARN, m_fDontWarnAgain); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CWarningDlg, CDialog) //{{AFX_MSG_MAP(CWarningDlg) // NOTE: the ClassWizard will add message map macros here //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CWarningDlg message handlers ///////////////////////////////////////////////////////////////////////////// // UMDialog dialog // -------------------------------------------- UMDialog::UMDialog(CWnd* pParent /*=NULL*/) : CDialog(UMDialog::IDD, pParent) , m_fRunningSecure(FALSE) { m_szUMStr.LoadString(IDS_UM); //{{AFX_DATA_INIT(UMDialog) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } UMDialog::~UMDialog() { m_lbClientList.Detach(); } // -------------------------------------------- void UMDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(UMDialog) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } // -------------------------------------------- BEGIN_MESSAGE_MAP(UMDialog, CDialog) //{{AFX_MSG_MAP(UMDialog) ON_WM_CLOSE() ON_BN_CLICKED(IDC_START, OnStart) ON_BN_CLICKED(IDC_STOP, OnStop) ON_WM_TIMER() ON_WM_HELPINFO() ON_COMMAND( ID_HELP, OnHelp ) ON_LBN_SELCHANGE(IDC_NAME_STATUS, OnSelchangeNameStatus) ON_BN_CLICKED(IDC_START_AT_LOGON, OnStartAtLogon) ON_BN_CLICKED(IDC_START_WITH_UM, OnStartWithUm) ON_WM_CONTEXTMENU() ON_MESSAGE(WM_SYSCOMMAND,OnSysCommand) ON_BN_CLICKED(IDC_START_ON_LOCK, OnStartOnLock) ON_WM_SHOWWINDOW() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // UMDialog message handlers BOOL UMDialog::PreTranslateMessage(MSG* pMsg) { // Override that allows use of function keys to launch applets when on // the logon desktop. Only pay attention to key up to avoid dup calls. if (m_fRunningSecure && WM_KEYUP == pMsg->message) { int iClient = GetClientNameFromAccelerator(pMsg->wParam); if (iClient >= 0) { m_lbClientList.SelectString(-1, g_rgClients[iClient].machine.DisplayName); OnStart(); return TRUE; } } return CDialog::PreTranslateMessage(pMsg); } BOOL UMDialog::OnInitDialog() { CDialog::OnInitDialog(); // set the flag indicating if we are running in secure mode desktop_ts desktop; QueryCurrentDesktop(&desktop, TRUE); m_fRunningSecure = RunSecure(desktop.type); if (s_fShowWarningAgain && s_dwStartMode == START_BY_MENU) { CWarningDlg dlgWarn; dlgWarn.m_fDontWarnAgain = !s_fShowWarningAgain; dlgWarn.DoModal(); s_fShowWarningAgain = !dlgWarn.m_fDontWarnAgain; } g_hWndDlg = m_hWnd; // change system menu CMenu *hSysMenu = GetSystemMenu(FALSE); if (hSysMenu) { CString str; hSysMenu->AppendMenu(MF_SEPARATOR); str.LoadString(IDS_ABOUT_STRING); hSysMenu->AppendMenu(MF_STRING,IDC_ABOUT,LPCTSTR(str)); } // handle any "start when utility manager starts" applets StartClientsOnShow(); // attach ListBox to member data and populate w/list of applications m_lbClientList.Attach(GetDlgItem(IDC_NAME_STATUS)->m_hWnd); ListClients(); // Disable Help button if we are at WinLogon because the help // dialog supports "Jump to URL..." exposing security risk. // The m_fRunningSecure variable is TRUE if UI shouldn't expose help. if (m_fRunningSecure) { EnableDlgItem(ID_HELP, FALSE, IDOK); } // Disable "Start when UtilMan starts" unless user is an admin // and we are running in non-secure mode. if (s_dwStartMode != START_BY_MENU) { GetDlgItem(IDC_START_WITH_UM)->EnableWindow(IsAdmin() && !m_fRunningSecure); } // Bring dialog to top and center on desktop window RECT rectUmanDlg,rectDesktop; GetDesktopWindow()->GetWindowRect(&rectDesktop); GetWindowRect(&rectUmanDlg); long lDlgWidth = rectUmanDlg.right - rectUmanDlg.left; long lDlgHieght = rectUmanDlg.bottom - rectUmanDlg.top; if (!m_fRunningSecure) { rectUmanDlg.left = (rectDesktop.right - lDlgWidth)/2; rectUmanDlg.top = (rectDesktop.bottom - lDlgHieght)/2; } else { rectUmanDlg.left = rectDesktop.left + (long)(lDlgWidth/10); rectUmanDlg.top = rectDesktop.bottom - lDlgHieght - (long)(lDlgHieght/10); } // This looks a bit odd (SetForegroundWindow should also be activating // the window) but if you don't call SetActiveWindow on the secure // desktop then the second, etc... WinKey+U will bring up UM hidden // behind the welcome "screen". SetActiveWindow(); SetForegroundWindow(); SetWindowPos(&wndTopMost,rectUmanDlg.left,rectUmanDlg.top,0,0,SWP_NOSIZE); if (!m_fRunningSecure) { // on default desktop the above SetWindowPos makes the dialog initially // on top and this call allows other apps to then be on top. SetWindowPos(&wndNoTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); } // start checking every so often to see if we need to update our display SetTimer(UPDATE_CLIENT_LIST_TIMER, 3000, NULL); return TRUE; // return TRUE unless you set the focus to a control } // ----------------------------------------------------- void UMDialog::OnSysCommand(UINT nID,LPARAM lParam) { if (nID == IDC_ABOUT) { UMAbout dlg; dlg.DoModal(); aboutWnd = NULL; } else { CDialog::OnSysCommand(nID,lParam); } }//UMDialog::OnSysCommand // ------------------------------------ // -------------------------------------------- // CanStartOnLockedDesktop - returns TRUE if applets can // be configured to be auto-started on the secure desktop // inline BOOL CanStartOnLockedDesktop(int iWhichClient, BOOL fRunningSecure) { // user can ask for auto start on secure desktop if they are logged on, the // applet is OK'd to run on the secure desktop and the machine isn't using // fast user switching (FUS) (w/FUS Ctrl+Alt+Del disconnects the user session // rather than switching desktops). BOOL fCanStartOnLockedDesktop = ( !fRunningSecure && g_rgClients[iWhichClient].user.fCanRunSecure && CanLockDesktopWithoutDisconnect() )?TRUE:FALSE; return fCanStartOnLockedDesktop; } // -------------------------------------------- // OnSelchangeNameStatus is called when the user navigates the list // box items by clicking with the mouse or using up/down arrows. // void UMDialog::OnSelchangeNameStatus() { // Get the currently selected item and update the controls for // the currently selected item. int iSel; if (GetSelectedClient((int)g_cClients, iSel)) { // Group box label CString str(g_rgClients[iSel].machine.DisplayName); CString optStr; optStr.Format(IDS_OPTIONS, str); GetDlgItem(IDC_OPTIONS)->SetWindowText(optStr); // only enable options when started via WinKey+U if (s_dwStartMode != START_BY_MENU) { // Disable "start at logon" at secure desktop to avoid mischief if (!m_fRunningSecure) { GetDlgItem(IDC_START_AT_LOGON)->EnableWindow(TRUE); } else { // this may be set in an upgrade situation; clear it g_rgClients[iSel].user.fStartAtLogon = FALSE; GetDlgItem(IDC_START_AT_LOGON)->EnableWindow(FALSE); } // Enable "start on locked desktop" if at default desktop and // when applet can run on secure desktop if (CanStartOnLockedDesktop(iSel, m_fRunningSecure)) { GetDlgItem(IDC_START_ON_LOCK)->EnableWindow(TRUE); } else { // this may be set in an upgrade situation; clear it g_rgClients[iSel].user.fStartOnLockDesktop = FALSE; GetDlgItem(IDC_START_ON_LOCK)->EnableWindow(FALSE); } // Start option checkboxes CheckDlgButton(IDC_START_AT_LOGON, (g_rgClients[iSel].user.fStartAtLogon)?TRUE:FALSE); CheckDlgButton(IDC_START_ON_LOCK, (g_rgClients[iSel].user.fStartOnLockDesktop)?TRUE:FALSE); CheckDlgButton(IDC_START_WITH_UM, (g_rgClients[iSel].user.fStartWithUtilityManager)?TRUE:FALSE); } else { GetDlgItem(IDC_START_AT_LOGON)->EnableWindow(FALSE); GetDlgItem(IDC_START_ON_LOCK)->EnableWindow(FALSE); GetDlgItem(IDC_START_WITH_UM)->EnableWindow(FALSE); CheckDlgButton(IDC_START_AT_LOGON, FALSE); CheckDlgButton(IDC_START_ON_LOCK, FALSE); CheckDlgButton(IDC_START_WITH_UM, FALSE); } // Start and stop buttons DWORD dwState = g_rgClients[iSel].state; if ((dwState == UM_CLIENT_RUNNING) && (g_rgClients[iSel].runCount >= g_rgClients[iSel].machine.MaxRunCount)) EnableDlgItem(IDC_START, FALSE, IDC_NAME_STATUS); else EnableDlgItem(IDC_START, TRUE, IDC_NAME_STATUS); if ((dwState == UM_CLIENT_NOT_RUNNING) || CantStopClient(&g_rgClients[iSel])) EnableDlgItem(IDC_STOP, FALSE, IDC_NAME_STATUS); else EnableDlgItem(IDC_STOP, TRUE, IDC_NAME_STATUS); }// else ignore selections not in a valid range } // -------------------------------------------- void UMDialog::OnClose() { // behave like cancel CDialog::OnClose(); }//UMDialog::OnClose // -------------------------------------------- // OnStart is called when the Start button is clicked. It starts // the client ap then lets the timer update saved state. // void UMDialog::OnStart() { int iSel; if (GetSelectedClient((int)g_cClients, iSel)) { if (StartClient(m_hWnd, &g_rgClients[iSel])) { KillTimer(UPDATE_CLIENT_LIST_TIMER); EnableDlgItem(IDC_STOP, TRUE, IDC_NAME_STATUS); ListClients(); SetTimer(UPDATE_CLIENT_LIST_TIMER, 3000, NULL); if (g_rgClients[iSel].runCount+1 >= g_rgClients[iSel].machine.MaxRunCount) EnableDlgItem(IDC_START, FALSE, IDC_STOP); } else if (g_rgClients[iSel].runCount < g_rgClients[iSel].machine.MaxRunCount) { // Unable to start CString str; str.LoadString((m_fRunningSecure)?IDS_SECUREMODE:IDS_ERRSTART); MessageBox(str, m_szUMStr, MB_OK); } } } // -------------------------------------------- // OnStop is called when the Stop button is clicked. It stops // the client ap then lets the timer update saved state. // void UMDialog::OnStop() { int iSel; if (GetSelectedClient((int)g_cClients, iSel)) { if (StopClient(&g_rgClients[iSel])) { KillTimer(UPDATE_CLIENT_LIST_TIMER); GetDlgItem(IDC_START)->EnableWindow(TRUE); ListClients(); EnableDlgItem(IDC_STOP, FALSE, IDOK); SetTimer(UPDATE_CLIENT_LIST_TIMER, 3000, NULL); } else { // Unable to stop CString str; str.LoadString(IDS_ERRSTOP); MessageBox(str, m_szUMStr, MB_OK); } } } void UMDialog::SaveCurrentState() { int iSel; if (GetSelectedClient((int)g_cClients, iSel)) { g_rgClients[iSel].user.fStartAtLogon = (IsDlgButtonChecked(IDC_START_AT_LOGON))?TRUE:FALSE; g_rgClients[iSel].user.fStartWithUtilityManager = (IsDlgButtonChecked(IDC_START_WITH_UM))?TRUE:FALSE; g_rgClients[iSel].user.fStartOnLockDesktop = (IsDlgButtonChecked(IDC_START_ON_LOCK))?TRUE:FALSE; } } // -------------------------------------------- // OnOK is called when the user clicks the OK button to // dismiss the UtilMan dialog. // void UMDialog::OnOK() { SaveCurrentState(); WriteClientData(m_fRunningSecure); CDialog::OnOK(); }//UMDialog::OnOK // ---------------------------------------------------------------------------- // OnTimer is called to check the status of client apps that are displayed // in the UI. This keeps the UI consistent with the running client app's. // void UMDialog::OnTimer(UINT nIDEvent) { if (nIDEvent == UPDATE_CLIENT_LIST_TIMER) { UINT uiElapsed = 3000; KillTimer(UPDATE_CLIENT_LIST_TIMER); // get current status and pick up new apps if (CheckStatus(g_rgClients, g_cClients)) { ListClients(); // something has changed - update the UI uiElapsed = 500; } SetTimer(UPDATE_CLIENT_LIST_TIMER, uiElapsed, NULL); } CDialog::OnTimer(nIDEvent); } // -------------------------------------------- // OnHelpInfo provides context sensitive help. It only does // this if not on the WinLogon desktop. // BOOL UMDialog::OnHelpInfo(HELPINFO* pHelpInfo) { if (m_fRunningSecure) return FALSE; if ( pHelpInfo->iCtrlId == IDC_OPTIONS ) return TRUE; ::WinHelp((HWND)pHelpInfo->hItemHandle, __TEXT("utilmgr.hlp"), HELP_WM_HELP, (DWORD_PTR) (LPSTR) g_rgHelpIds); return TRUE; } // -------------------------------------------- // OnHelpInfo provides context sensitive help when the user // right-clicks the dialog. It only does this if not on the // WinLogon desktop. // void UMDialog::OnContextMenu(CWnd* pWnd, CPoint point) { if (m_fRunningSecure) return; ::WinHelp(pWnd->m_hWnd, __TEXT("utilmgr.hlp"), HELP_CONTEXTMENU , (DWORD_PTR) (LPSTR) g_rgHelpIds); } // -------------------------------------------- // OnHelp provides standard help. It only does this if not // on the WinLogon desktop. // void UMDialog::OnHelp() { if (m_fRunningSecure) return; ::HtmlHelp(m_hWnd , TEXT("utilmgr.chm"), HH_DISPLAY_TOPIC, 0); } // ---------------------------------- void UMDialog::EnableDlgItem(DWORD dwEnableMe, BOOL fEnable, DWORD dwFocusHere) { // when disabling a control that currently has focs switch it to dwFocusHere if (!fEnable && (GetFocus() == GetDlgItem(dwEnableMe))) GetDlgItem(dwFocusHere)->SetFocus(); GetDlgItem(dwEnableMe)->EnableWindow(fEnable); } void UMDialog::SetStateStr(int iClient) { switch (g_rgClients[iClient].state) { case UM_CLIENT_NOT_RUNNING: m_szStateStr.Format(IDS_NOT_RUNNING, g_rgClients[iClient].machine.DisplayName); break; case UM_CLIENT_RUNNING: m_szStateStr.Format(IDS_RUNNING, g_rgClients[iClient].machine.DisplayName); break; case UM_CLIENT_NOT_RESPONDING: m_szStateStr.Format(IDS_NOT_RESPONDING, g_rgClients[iClient].machine.DisplayName); break; default: m_szStateStr.Empty(); break; } } // -------------------------------------------- void UMDialog::ListClients() { // Re-do the client list box with latest state info int iCurSel = m_lbClientList.GetCurSel(); if (iCurSel == LB_ERR) iCurSel = 0; m_lbClientList.ResetContent(); for (DWORD i = 0; i < g_cClients; i++) { SetStateStr(i); if (!m_szStateStr.IsEmpty()) { m_lbClientList.AddString(m_szStateStr); } } m_lbClientList.SetCurSel(iCurSel); // Refresh button states in case they've changed // (this happens on desktop switch) OnSelchangeNameStatus(); } // -------------------------------------------- // UpdateClientState updates the client list box with the current state // of the application (running, not running, not responding) // void UMDialog::UpdateClientState(int iSel) { SetStateStr(iSel); m_lbClientList.DeleteString(iSel); m_lbClientList.InsertString(iSel, m_szStateStr); m_lbClientList.SetCurSel(iSel); } // -------------------------------------------- // OnStartAtLogon updates the state of the client in memory when the // Start with Windows checkbox is checked or unchecked. // void UMDialog::OnStartAtLogon() { SaveCurrentState(); } // -------------------------------------------- // OnStartWithUm updates the state of the client in memory when the // Start with Utility Manager checkbox is checked or unchecked. // void UMDialog::OnStartWithUm() { SaveCurrentState(); } // -------------------------------------------- // OnStartOnLock updates the state of the client in memory when the // Start when I lock my desktop checkbox is checked or unchecked. // void UMDialog::OnStartOnLock() { SaveCurrentState(); } // -------------------------------------------- // OnShowWindow // This was added for a timing problem where utilman came up running in the system context on the users desktop // this code here makes sure that that cannot happen by cheching right when the dialog is about to appear // void UMDialog::OnShowWindow(BOOL bShow, UINT nStatus) { HDESK hdesk; SID *desktopSID = NULL; hdesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED); // this is expected to fail for the winlogon desktop and thats ok if (hdesk) { TCHAR desktopName[NAME_LEN]; DWORD nl, SIDLen = 0; if (!GetUserObjectInformation(hdesk, UOI_NAME, desktopName, NAME_LEN, &nl)) goto StopDialog; if (!GetUserObjectInformation(hdesk, UOI_USER_SID, desktopSID, 0, &SIDLen)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto StopDialog; } if (SIDLen > 0 && !lstrcmpi(desktopName, TEXT("Default"))) { desktopSID = (SID*)new BYTE[SIDLen]; if (!desktopSID) goto StopDialog; if (!GetUserObjectInformation(hdesk, UOI_USER_SID, desktopSID, SIDLen, &SIDLen)) goto StopDialog; BOOL fError; HANDLE hUserToken = GetUserAccessToken(TRUE, &fError); if (fError) goto StopDialog; // We get a token only if there is a logged on user. // If there is not then we can come up as system with no worries. if (!hUserToken) goto LetDialogComeup; BOOL fStatus = FALSE; BOOL fIsInteractiveUser = FALSE; PSID psidInteractive = InteractiveUserSid(TRUE); if (!psidInteractive) goto StopDialog; fStatus = CheckTokenMembership(hUserToken, psidInteractive, &fIsInteractiveUser); //If the logged on user is the interactive user and we are running as system then it is a // security risk to show UI. This can happen when rappidly switching desktops. if ( fStatus && fIsInteractiveUser && IsSystem()) goto StopDialog; } } LetDialogComeup: if (desktopSID) delete [] desktopSID; return; StopDialog: StopDialog(); if (desktopSID) delete [] desktopSID; } ///////////////////////////////////////////////////////////////////////////// // C code //----------------------------------------------------------------- __inline void ReplaceDisplayName(LPTSTR szName, int iRID) { TCHAR szBuf[MAX_APPLICATION_NAME_LEN]; if (LoadString(AfxGetInstanceHandle(), iRID, szBuf, MAX_APPLICATION_NAME_LEN)) lstrcpy(szName, szBuf); } void SetLocalizedDisplayName() { // Make localization easier; don't require them to localize registry entries. // Instead, replace our copy with the localized version. This appears to be // duplicate code to that in umanrun.c however, that part of the code always // runs as system and therefore the DisplayName is set to the default system // language. This part of the code (the UI) runs as the logged on user when // there is one so these resources will be the user's language. The resources // and associated code should be removed from utilman.exe and this code and // resources (from umandlg.dll) should be used. for (DWORD i=0;idwStartMode; // capture the Utilman start mode s_fShowWarningAgain = pHdr->fShowWarningAgain; // and warning dialog flag if (!pHdr->numberOfClients) { goto Cleanup; } c = (umclient_tsp)AccessIndependentMemory( UMC_CLIENT_FILE, sizeof(umclient_ts)*pHdr->numberOfClients, FILE_MAP_READ, &accessID2); if (!c) { goto Cleanup; } g_rgClients = (umclient_tsp)VirtualAlloc(NULL, sizeof(umclient_ts)*pHdr->numberOfClients, MEM_RESERVE,PAGE_READWRITE); if (!g_rgClients) { goto Cleanup; } if (!VirtualAlloc(g_rgClients, sizeof(umclient_ts)*pHdr->numberOfClients, MEM_COMMIT, PAGE_READWRITE)) { goto Cleanup; } fRv = TRUE; g_cClients = pHdr->numberOfClients; memcpy(g_rgClients,c,sizeof(umclient_ts)*pHdr->numberOfClients); SetLocalizedDisplayName(); Cleanup: if (pHdr) { UnAccessIndependentMemory(pHdr, accessID); } if (c) { UnAccessIndependentMemory(c, accessID2); } if (!fRv && g_rgClients) { VirtualFree(g_rgClients, 0, MEM_RELEASE); g_rgClients = NULL; g_cClients = 0; } } // "Start when I log on" is per-user setting so get that // each time the dialog is brought up CManageShellLinks CManageLinks(STARTUP_FOLDER); for (DWORD i=0;ifShowWarningAgain = s_fShowWarningAgain; UnAccessIndependentMemory(pHdr, accessID); } } // ---------------------------------- // WriteClientData - save settings to the registry // static BOOL WriteClientData(BOOL fRunningSecure) { // It only makes sense to do this if there are any applets being managed // (shouldn't get here) and if there is a logged on user (otherwise the // settings cannot be changed) if (!g_cClients || !g_rgClients || fRunningSecure) return TRUE; // The SYSTEM instance of utilman needs to be updated in case the user // changed any options. This is so subsequent instances of the UI will // get the correct options without having to read the registry. CopyHeaderData(); CopyClientData(); // // Write utilman settings data. Put "Start when UtilMan starts" in HKLM, // "Start when I lock desktop" in HKCU, and "Start when I log on" into // a startup link in the logged on user's shell folder. // // "Start when UtilMan starts" settings... (only for admins) DWORD i; if (IsWindowEnabled(GetDlgItem(g_hWndDlg, IDC_START_WITH_UM))) { HKEY hHKLM; DWORD dwRv = RegCreateKeyEx(HKEY_LOCAL_MACHINE , UM_REGISTRY_KEY , 0 , NULL , REG_OPTION_NON_VOLATILE , KEY_ALL_ACCESS, NULL , &hHKLM, NULL); if (dwRv == ERROR_SUCCESS) { for (i = 0; i < g_cClients; i++) { RegSetUMDwordValue( hHKLM , g_rgClients[i].machine.ApplicationName , UMR_VALUE_STARTUM , g_rgClients[i].user.fStartWithUtilityManager); } RegCloseKey(hHKLM); } } // // "Start when I lock my desktop" settings... (any logged on user) // and Don't show me the warning anymore setting // WriteUserRegData(HKEY_CURRENT_USER, IsWindowEnabled(GetDlgItem(g_hWndDlg, IDC_START_ON_LOCK))); // // manage shell folder link updates (logged on user only) // if (IsWindowEnabled(GetDlgItem(g_hWndDlg, IDC_START_AT_LOGON))) { CManageShellLinks CManageLinks(STARTUP_FOLDER); for (i = 0; i < g_cClients; i++) { LPTSTR pszAppName = g_rgClients[i].machine.ApplicationName; BOOL fLinkExists = CManageLinks.LinkExists(pszAppName); // if should start at logon and there isn't a link then create one // and if shouldn't start at logon and there is a link then delete it if (g_rgClients[i].user.fStartAtLogon && !fLinkExists) { TCHAR pszAppPath[MAX_PATH]; LPTSTR pszApp = 0; // Following is TRUE *only* if pszAppPath is non-null string value if (GetClientApplicationPath(pszAppName , pszAppPath , MAX_PATH)) { TCHAR pszFullPath[MAX_PATH*2+1]; // path + filename TCHAR pszStartIn[MAX_PATH]; int ctch, ctchAppPath = lstrlen(pszAppPath); // if pszAppPath is just base name and extension then prepend system path if (wcscspn(pszAppPath, TEXT("\\")) != (size_t)ctchAppPath || wcscspn(pszAppPath, TEXT(":")) != (size_t)ctchAppPath) { TCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR]; _wsplitpath(pszAppPath, szDrive, szDir, NULL, NULL); lstrcpy(pszStartIn, szDrive); lstrcat(pszStartIn, szDir); pszApp = pszAppPath; } else { ctch = GetSystemDirectory(pszStartIn, MAX_PATH); lstrcpy(pszFullPath, pszStartIn); // save path to build full path if (ctch + ctchAppPath + 2 > MAX_PATH*2) { DBPRINTF(TEXT("WriteClientData: Path is too short!\r\n")); } else { if (*(pszFullPath + ctch - 1) != '\\') lstrcat(pszFullPath, TEXT("\\")); lstrcat(pszFullPath, pszAppPath); pszApp = pszFullPath; } } if (pszApp) { // remove ending '\' from StartIn path ctch = lstrlen(pszStartIn) - 1; if (*(pszStartIn + ctch) == '\\') *(pszStartIn + ctch) = 0; CManageLinks.CreateLink( pszAppName , pszApp , pszStartIn , g_rgClients[i].machine.DisplayName , TEXT("/UM")); } } } else if (!g_rgClients[i].user.fStartAtLogon && fLinkExists) { CManageLinks.RemoveLink(pszAppName); } } } return TRUE; } // -------------------------------------------- static BOOL CantStopClient(umclient_tsp client) { switch (client->machine.ApplicationType) { case APPLICATION_TYPE_APPLICATION: break; case APPLICATION_TYPE_SERVICE: { SERVICE_STATUS ssStatus; SC_HANDLE hService; SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (!hSCM) return TRUE; hService = OpenService(hSCM, client->machine.ApplicationName, SERVICE_ALL_ACCESS); CloseServiceHandle(hSCM); if (!hService) return TRUE; if (!QueryServiceStatus(hService, &ssStatus) || !(ssStatus.dwControlsAccepted & SERVICE_ACCEPT_STOP)) { CloseServiceHandle(hService); return TRUE; } CloseServiceHandle(hService); break; } } return FALSE; }//CantStopClient // We don't want UtilMan to startType to be Automatic // It should only be made Automatic if it is required, When the user // selects "Start when NT starts" through the GUI :a-anilk static BOOL IsStartAuto() { #ifdef NEVER // MICW Don't start service anymore at logon because of TS DWORD nClient; for(nClient = 0; nClient < g_cClients; nClient++) { if ( g_rgClients[nClient].user.fStartAtLogon == TRUE ) return TRUE; } #endif return FALSE; } static int GetClientNameFromAccelerator(WPARAM wVK) { for (int i=0;i<(int)g_cClients;i++) if (g_rgClients[i].machine.AcceleratorKey == wVK) return i; return -1; } static BOOL StartClientsOnShow() { BOOL fOK = TRUE; for (int i=0;i<(int)g_cClients;i++) { if ( g_rgClients[i].user.fStartWithUtilityManager && !StartClient(g_hWndDlg, &g_rgClients[i])) fOK = FALSE; } return fOK; }