//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 2000 // // File: updates.h // Definition of the Updates class // //-------------------------------------------------------------------------- #pragma once #include "wuauengi.h" #include "wuaulib.h" #include #include #include #include #include #include "pch.h" // functions IUpdates uses void HrUninit(void); HRESULT StartDownload(void); HRESULT PauseDownload(BOOL bPause); HRESULT GetUpdatesList(VARIANT *vList); HRESULT GetInstallXML(BSTR *pbstrCatalogXML, BSTR *pbstrDownloadXML); void saveSelection(VARIANT *selection); HRESULT GetDownloadStatus(UINT *pPercentage, DWORD *pdwnldStatus, BOOL fCareAboutConnection = TRUE); HRESULT GetInstallStatus(UINT *pNumFinished, DWORD *pStatus); HRESULT GetEvtHandles(AUEVTHANDLES *pAuEvtHandles); DWORD AvailableSessions(void); BOOL IsSessionAUEnabledAdmin(DWORD dwSessionId); ///////////////////////////////////////////////////////////////////////////// // Updates class Updates : public IUpdates { public: HANDLE m_hEngineMutex; Updates(); ~Updates(); BOOL m_fInitializeSecurity(void); HRESULT m_AccessCheckClient(void); HRESULT GetServiceHandles(); DWORD ProcessState(); BOOL CheckConnection(); // IUnknown STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(ULONG, Release)(void); // IClassFactory STDMETHOD(CreateInstance)(IUnknown*,REFIID,void**); STDMETHOD(LockServer)(BOOL); // IUpdates STDMETHOD(get_State)(/*[out, retval]*/ AUSTATE *pAuState); STDMETHOD(get_Option)(/*[out, retval]*/ AUOPTION * pAuOpt); STDMETHOD(put_Option)(/*[in]*/ AUOPTION auopt); STDMETHOD(GetUpdatesList)(/*[out]*/ VARIANT *pUpdates); STDMETHOD(SaveSelections)(/*[in]*/ VARIANT vUpdates); STDMETHOD(StartDownload)(void); STDMETHOD(GetDownloadStatus)(/*[out]*/ UINT *, /*[out]*/ DWORD *); STDMETHOD(SetDownloadPaused)(/*[in]*/ BOOL bPaused); STDMETHOD(ConfigureAU)(); STDMETHOD(AvailableSessions(/*[out]*/ UINT *pcSess)); STDMETHOD(get_EvtHandles(/*[in]*/DWORD dwCltProcId, /*[out]*/ AUEVTHANDLES *pauevtHandles)); STDMETHOD(ClientMessage(/*[in]*/ UINT msg)); //STDMETHOD(PingStatus(/*[in]*/ StatusEntry se)); STDMETHOD(GetNotifyData(/*[out]*/ CLIENT_NOTIFY_DATA *pNotifyData)); STDMETHOD(GetInstallXML(/*[out]*/ BSTR *pbstrCatalogXML, /*[out]*/ BSTR *pbstrDownloadXML)); STDMETHOD(LogEvent(/*[in]*/ WORD wType, /*[in]*/ WORD wCategory, /*[in]*/ DWORD dwEventID, /*[in]*/ VARIANT vItems)); private: SECURITY_DESCRIPTOR m_AdminSecurityDesc; static GENERIC_MAPPING m_AdminGenericMapping; PSID m_pAdminSid; PACL m_pAdminAcl; long m_refs; }; class CLIENT_HANDLES { public: CLIENT_HANDLES(void){ InitHandle(); } ~CLIENT_HANDLES(void){ Reset(TRUE); } BOOL fRebootWarningMode() { return m_fRebootWarningMode; } void StopClients(BOOL fRelaunch) { if (m_fRebootWarningMode) { DEBUGMSG("WUAUENG told %d CLIENT(S) to exit", m_dwRebootWarningClientNum); if (NULL != m_hClientExitEvt) { SetEvent(m_hClientExitEvt); } } else { if (fClient()) { if (fRelaunch) { DEBUGMSG("WUAUENG told WUAUCLT to relaunch"); NotifyClient(NOTIFY_RELAUNCH_CLIENT); } else { DEBUGMSG("WUAUENG told WUAUCLT to exit"); NotifyClient(NOTIFY_STOP_CLIENT); } } else { DEBUGMSG("WARNING: StopClients() : no existing client"); } } } void ClientAddTrayIcon(void) { if (m_fRebootWarningMode || m_fAsLocalSystem) { DEBUGMSG("WARNING: ClientAddTrayIcon() called in wrong mode"); return; } if (fClient()) { NotifyClient(NOTIFY_ADD_TRAYICON); } } void ClientRemoveTrayIcon(void) { if (m_fRebootWarningMode || m_fAsLocalSystem) { DEBUGMSG("WARNING: ClientRemoveTrayIcon() called in wrong mode"); return; } if (fClient()) { NotifyClient(NOTIFY_REMOVE_TRAYICON); } } void ClientStateChange(void) { if (m_fRebootWarningMode || m_fAsLocalSystem) { DEBUGMSG("WARNING: ClientStateChange() called in wrong mode"); return; } NotifyClient(NOTIFY_STATE_CHANGE); } void ClientShowInstallWarning(void){ if (m_fRebootWarningMode || m_fAsLocalSystem) { DEBUGMSG("WARNING: ClientShowInstallWarning() called in wrong mode"); return; } if (fClient()) { NotifyClient(NOTIFY_SHOW_INSTALLWARNING); } } void ResetClient(void) { if (m_fRebootWarningMode || m_fAsLocalSystem) { DEBUGMSG("WARNING: ResetClient() called in wrong mode"); return; } if (fClient()) { NotifyClient(NOTIFY_RESET); } } //checking existence of client(s) BOOL fClient(void) { if (m_fRebootWarningMode) { return m_dwRebootWarningClientNum > 0; } else { return (-1 != m_dwProcId) && (NULL != m_hClientProcess); } } void SetHandle(PROCESS_INFORMATION & ProcessInfo, BOOL fAsLocalSystem) { m_fRebootWarningMode = FALSE; m_fAsLocalSystem = fAsLocalSystem; m_dwProcId = ProcessInfo.dwProcessId; m_hClientProcess = ProcessInfo.hProcess; SafeCloseHandle(ProcessInfo.hThread); } BOOL AddHandle(PROCESS_INFORMATION & ProcessInfo) { HANDLE *pTmp; m_fRebootWarningMode = TRUE; SafeCloseHandle(ProcessInfo.hThread); pTmp = (HANDLE*) realloc(m_phRebootWarningClients, (m_dwRebootWarningClientNum+1)*sizeof(HANDLE)); if (NULL == pTmp) { return FALSE; } m_phRebootWarningClients = pTmp; m_phRebootWarningClients[m_dwRebootWarningClientNum] = ProcessInfo.hProcess; m_dwRebootWarningClientNum ++; return TRUE; } void RemoveHandle(HANDLE hProcess) { if (m_fRebootWarningMode) { for (DWORD i = 0; i < m_dwRebootWarningClientNum; i++) { if (hProcess == m_phRebootWarningClients[i]) { CloseHandle(hProcess); m_phRebootWarningClients[i] = m_phRebootWarningClients[m_dwRebootWarningClientNum -1]; m_dwRebootWarningClientNum --; DEBUGMSG("RemoveHandle in Reboot warning mode"); } } if (0 == m_dwRebootWarningClientNum) {//all clients are gone Reset(); } } else { DEBUGMSG("RemoveHandle in regular mode"); if (hProcess == m_hClientProcess) { //all clients are gone Reset(); } } } void InitHandle(void) { DEBUGMSG("WUAUENG client handles initialized"); m_hClientProcess = NULL; m_dwProcId = -1; m_dwRebootWarningClientNum = 0; m_phRebootWarningClients = NULL; m_fRebootWarningMode = FALSE; m_fAsLocalSystem = FALSE; m_hClientExitEvt = NULL; } DWORD GetProcId(void) { if (m_fRebootWarningMode) { DEBUGMSG("WARNING: GetProcId() called in wrong mode"); return -1; } return m_dwProcId; } CONST HANDLE hClientProcess(void) { if (m_fRebootWarningMode) { DEBUGMSG("WARNING: hClientProcess() called in wrong mode"); return NULL; } return m_hClientProcess; } void WaitForClientExits() { HANDLE *pTmp; if (!m_fRebootWarningMode) { if (NULL != m_hClientProcess) { WaitForSingleObject(m_hClientProcess, INFINITE); } } else { if (m_dwRebootWarningClientNum > 0) { WaitForMultipleObjects(m_dwRebootWarningClientNum, m_phRebootWarningClients, TRUE, INFINITE); } } Reset(); return; } ////////////////////////////////////////////////////////////////// // szName should have size of at least MAX_PATH characters ////////////////////////////////////////////////////////////////// BOOL CreateClientExitEvt(LPTSTR OUT szName, DWORD dwCchSize) { const TCHAR szClientName[] = _T("Global\\Microsoft.WindowsUpdate.AU.ClientExitEvt."); TCHAR szBuf[50]; GUID guid; HRESULT hr; AUASSERT(NULL == m_hClientExitEvt); if (FAILED(hr = CoCreateGuid(&guid))) { DEBUGMSG("Fail to Create guid with error %#lx", hr); return FALSE; } StringFromGUID2(guid, szBuf, ARRAYSIZE(szBuf)); // szBuf should be big enough, function always succeed if (FAILED(hr = StringCchCopyEx(szName, dwCchSize, szClientName, NULL, NULL, MISTSAFE_STRING_FLAGS)) || FAILED(hr = StringCchCatEx(szName, dwCchSize, szBuf, NULL, NULL, MISTSAFE_STRING_FLAGS))) //szName is now 86 characters long { DEBUGMSG("Fail to construct client exit event name with error %#lx", hr); return FALSE; } if (NULL == (m_hClientExitEvt = CreateEvent(NULL, TRUE, FALSE, szName))) { DEBUGMSG("Fail to create client exit event with error %d", GetLastError()); return FALSE; } if (!AllowEveryOne(m_hClientExitEvt)) { DEBUGMSG("Fail to grant access on client exit event to everyone"); SafeCloseHandleNULL(m_hClientExitEvt); return FALSE; } DEBUGMSG("access granted to everyone on client exit event"); return TRUE; } private: void NotifyClient(CLIENT_NOTIFY_CODE notClientCode) { //notify client even before or after it is created #ifdef DBG LPCSTR aClientCodeMsg[] = {"stop client", "add trayicon", "remove trayicon", "state change", "show install warning", "reset client", "relaunch client"}; DEBUGMSG("Notify Client for %s", aClientCodeMsg[notClientCode-1]); #endif gClientNotifyData.actionCode = notClientCode; SetEvent(ghNotifyClient); return; } //////////////////////////////////////////////////////////////////// // grant SYNCHRONIZE access on hObject to everyone //////////////////////////////////////////////////////////////////// BOOL AllowEveryOne (HANDLE hObject) // handle to the event { LPTSTR pszTrustee; // trustee for new ACE TRUSTEE_FORM TrusteeForm; // format of trustee structure DWORD dwRes; PACL pOldDACL = NULL, pNewDACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; EXPLICIT_ACCESS ea; PSID pWorldSid = NULL; BOOL fRet; // World SID SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY; if (! (fRet =AllocateAndInitializeSid(&WorldAuth,1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0,&pWorldSid))) { DEBUGMSG("WUAUENG: AllowEveryOne() failed with error %d", GetLastError()); goto Cleanup; } // Get a pointer to the existing DACL. dwRes = GetSecurityInfo(hObject, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDACL, NULL, &pSD); if (!(fRet = (ERROR_SUCCESS == dwRes))) { DEBUGMSG( "GetSecurityInfo Error %u", dwRes ); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for the new ACE. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); ea.grfAccessPermissions = SYNCHRONIZE; ea.grfAccessMode = SET_ACCESS; ea.grfInheritance= NO_INHERITANCE; ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea.Trustee.ptstrName = (LPTSTR)pWorldSid; // Create a new ACL that merges the new ACE // into the existing DACL. dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL); if (!(fRet = (ERROR_SUCCESS == dwRes))) { DEBUGMSG( "SetEntriesInAcl Error %u", dwRes ); goto Cleanup; } // Attach the new ACL as the object's DACL. dwRes = SetSecurityInfo(hObject, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL); if (!(fRet = (ERROR_SUCCESS == dwRes))) { DEBUGMSG( "SetSecurityInfo Error %u", dwRes ); goto Cleanup; } Cleanup: if(pSD != NULL) LocalFree((HLOCAL) pSD); if(pNewDACL != NULL) LocalFree((HLOCAL) pNewDACL); if (NULL != pWorldSid) { FreeSid(pWorldSid); } return fRet; } void Reset( BOOL fDestructor = FALSE) { SafeCloseHandleNULL(m_hClientProcess); SafeCloseHandleNULL(m_hClientExitEvt); m_dwProcId = -1; if (!fDestructor) { ResetEvent(ghNotifyClient); } if (m_dwRebootWarningClientNum > 0) { DEBUGMSG("WUAUENG CLIENT_HANDLES::Reset() close %d handles", m_dwRebootWarningClientNum); for (DWORD i = 0; i < m_dwRebootWarningClientNum; i++) { CloseHandle(m_phRebootWarningClients[i]); } } SafeFreeNULL(m_phRebootWarningClients); //still need to free even m_dwRebootWarningClientNum is 0 m_dwRebootWarningClientNum = 0; m_phRebootWarningClients = NULL; m_fRebootWarningMode = FALSE; m_fAsLocalSystem = FALSE; } private: HANDLE m_hClientProcess; //Handle to the client process DWORD m_dwProcId; HANDLE *m_phRebootWarningClients; DWORD m_dwRebootWarningClientNum; //number of valid handles in m_phRebootWarningClients BOOL m_fRebootWarningMode; BOOL m_fAsLocalSystem; HANDLE m_hClientExitEvt; }; extern CLIENT_HANDLES ghClientHandles;