|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2001.
//
// sens.cpp
//
// Modele that implements a COM+ subscriber for use with SENS notifications.
//
// 10/9/2001 annah Created
// Ported code from BITS sources. Removed SEH code,
// changed methods that threw exceptions to return
// error codes.
//
//----------------------------------------------------------------------------
#include "pch.h"
#include "ausens.h"
#include "tscompat.h"
#include "service.h"
static CLogonNotification *g_SensLogonNotification = NULL;
HRESULT ActivateSensLogonNotification() { HRESULT hr = S_OK;
// only activate once
if ( g_SensLogonNotification ) { DEBUGMSG("AUSENS Logon object was already created; reusing object."); return S_OK; }
g_SensLogonNotification = new CLogonNotification(); if (!g_SensLogonNotification) { DEBUGMSG("AUSENS Failed to alocate memory for CLogonNotification object."); return E_OUTOFMEMORY; }
hr = g_SensLogonNotification->Initialize(); if (FAILED(hr)) { DEBUGMSG( "AUSENS notification activation failed." ); } else { DEBUGMSG( "AUSENS notification activated" ); }
return hr; }
HRESULT DeactivateSensLogonNotification() { if (!g_SensLogonNotification) { DEBUGMSG("AUSENS Logon object is not activated; ignoring call."); return S_OK; }
delete g_SensLogonNotification; g_SensLogonNotification = NULL;
DEBUGMSG( "AUSENS notification deactivated" ); return S_OK; }
//----------------------------------------------------------------------------
// BSTR manipulation
//----------------------------------------------------------------------------
HRESULT AppendBSTR(BSTR *bstrDest, BSTR bstrAppend) { HRESULT hr = S_OK; BSTR bstrNew = NULL;
if (bstrDest == NULL || *bstrDest == NULL) return E_INVALIDARG;
if (bstrAppend == NULL) return S_OK;
hr = VarBstrCat(*bstrDest, bstrAppend, &bstrNew); if (SUCCEEDED(hr)) { SysFreeString(*bstrDest); *bstrDest = bstrNew; }
return hr; }
// Caller is responsible for freeing bstrOut
HRESULT BSTRFromIID(IN REFIID riid, OUT BSTR *bstrOut) { HRESULT hr = S_OK; LPOLESTR lpszGUID = NULL;
if (bstrOut == NULL) { hr = E_INVALIDARG; goto done; }
hr = StringFromIID(riid, &lpszGUID); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to extract GUID from string"); goto done; }
*bstrOut = SysAllocString(lpszGUID); if (*bstrOut == NULL) { hr = E_OUTOFMEMORY; goto done; }
done: if (lpszGUID) { CoTaskMemFree(lpszGUID); }
return hr; }
HRESULT CBstrTable::Initialize() { HRESULT hr = S_OK;
hr = BSTRFromIID(g_oLogonSubscription.MethodGuid, &m_bstrLogonMethodGuid); if (FAILED(hr)) { goto done; }
m_bstrLogonMethodName = SysAllocString(g_oLogonSubscription.pszMethodName); if (m_bstrLogonMethodName == NULL) { hr = E_OUTOFMEMORY; goto done; }
m_bstrSubscriptionName = SysAllocString(SUBSCRIPTION_NAME_TEXT); if (m_bstrSubscriptionName == NULL) { hr = E_OUTOFMEMORY; goto done; }
m_bstrSubscriptionDescription = SysAllocString(SUBSCRIPTION_DESCRIPTION_TEXT); if (m_bstrSubscriptionDescription == NULL) { hr = E_OUTOFMEMORY; goto done; }
hr = BSTRFromIID(_uuidof(ISensLogon), &m_bstrSensLogonGuid); if (FAILED(hr)) { goto done; }
hr = BSTRFromIID(SENSGUID_EVENTCLASS_LOGON, &m_bstrSensEventClassGuid); if (FAILED(hr)) { goto done; }
done: return hr; }
//----------------------------------------------------------------------------
// Implementation for CLogonNotification methods
//----------------------------------------------------------------------------
HRESULT CLogonNotification::Initialize() { HRESULT hr = S_OK; SIZE_T cSubscriptions = 0;
//
// Create auxiliary object with BSTR names used for several actions
//
m_oBstrTable = new CBstrTable(); if (!m_oBstrTable) { return E_OUTOFMEMORY; }
hr = m_oBstrTable->Initialize(); if (FAILED(hr)) { DEBUGMSG("AUSENS Could not create auxiliary structure BstrTable"); return hr; }
//
// Load the type library from SENS
//
hr = LoadTypeLibEx(L"SENS.DLL", REGKIND_NONE, &m_TypeLib); if (FAILED(hr)) { DEBUGMSG("AUSENS Could not load type library from SENS DLL"); goto done; }
//
// Get TypeInfo for ISensLogon from SENS typelib -- this will
// simplify thing for us when implementing IDispatch methods
//
hr = m_TypeLib->GetTypeInfoOfGuid(__uuidof( ISensLogon ), &m_TypeInfo); if (FAILED(hr)) { DEBUGMSG("AUSENS Could not get type info for ISensLogon."); goto done; }
//
// Grab an interface pointer of the EventSystem object
//
hr = CoCreateInstance(CLSID_CEventSystem, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IEventSystem, (void**)&m_EventSystem ); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to create EventSytem instance for Sens subscription. Error is %x.", hr); goto done; }
//
// Subscribe for the Logon notifications
//
DEBUGMSG("AUSENS Subscribing method '%S' with SENS (%S)", m_oBstrTable->m_bstrLogonMethodName, m_oBstrTable->m_bstrLogonMethodGuid); hr = SubscribeMethod(m_oBstrTable->m_bstrLogonMethodName, m_oBstrTable->m_bstrLogonMethodGuid); if (FAILED(hr)) { DEBUGMSG("AUSENS Subscription for method failed."); goto done; } m_fSubscribed = TRUE;
done:
return hr; }
HRESULT CLogonNotification::UnsubscribeAllMethods() { HRESULT hr = S_OK; BSTR bstrQuery = NULL; BSTR bstrAux = NULL; int ErrorIndex;
DEBUGMSG("AUSENS Unsubscribing all methods"); //
// The query should be a string in the following format:
// EventClassID == {D5978630-5B9F-11D1-8DD2-00AA004ABD5E} and SubscriptioniD == {XXXXXXX-5B9F-11D1-8DD2-00AA004ABD5E}
//
bstrQuery = SysAllocString(L"EventClassID == "); if (bstrQuery == NULL) { hr = E_OUTOFMEMORY; goto done; } bstrAux = SysAllocString(L" and SubscriptionID == "); if (bstrAux == NULL) { hr = E_OUTOFMEMORY; goto done; }
hr = AppendBSTR(&bstrQuery, m_oBstrTable->m_bstrSensLogonGuid); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to append BSTR string"); goto done; }
hr = AppendBSTR(&bstrQuery, bstrAux); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to append BSTR string"); goto done; }
hr = AppendBSTR(&bstrQuery, m_oBstrTable->m_bstrLogonMethodGuid); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to append BSTR string"); goto done; }
if (bstrQuery != NULL) { // Remove subscription for all ISensLogon subscription that were added for this WU component
DEBUGMSG("AUSENS remove subscription query: %S", bstrQuery); hr = m_EventSystem->Remove( PROGID_EventSubscription, bstrQuery, &ErrorIndex ); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to remove AU Subscription from COM Event System"); goto done; } m_fSubscribed = FALSE; } else { hr = E_OUTOFMEMORY; goto done; }
done:
SafeFreeBSTR(bstrQuery); SafeFreeBSTR(bstrAux);
return hr; }
HRESULT CLogonNotification::SubscribeMethod(const BSTR bstrMethodName, const BSTR bstrMethodGuid) { HRESULT hr = S_OK; IEventSubscription *pEventSubscription = NULL;
//
// Create an instance of EventSubscription
//
hr = CoCreateInstance(CLSID_CEventSubscription, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IEventSubscription, (void**)&pEventSubscription); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to instanciate EventSubscription object"); goto done; }
//
// Subscribe the method
//
hr = pEventSubscription->put_EventClassID(m_oBstrTable->m_bstrSensEventClassGuid); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to set EventClassID during method subscription"); goto done; }
hr = pEventSubscription->put_SubscriberInterface(this); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to set EventClassID during method subscription"); goto done; }
hr = pEventSubscription->put_SubscriptionName(m_oBstrTable->m_bstrSubscriptionName); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to set EventClassID during method subscription"); goto done; }
hr = pEventSubscription->put_Description(m_oBstrTable->m_bstrSubscriptionDescription); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to set subscription method during method subscription"); goto done; }
hr = pEventSubscription->put_Enabled(TRUE); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to set enabled flag during method subscription"); goto done; }
hr = pEventSubscription->put_MethodName(bstrMethodName); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to set MethodName during method subscription"); goto done; }
hr = pEventSubscription->put_SubscriptionID(bstrMethodGuid); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to set SubscriptionID during method subscription"); goto done; }
hr = m_EventSystem->Store(PROGID_EventSubscription, pEventSubscription); if (FAILED(hr)) { DEBUGMSG("AUSENS Failed to store Event Subscription in the Event System"); goto done; }
done: SafeRelease(pEventSubscription);
return hr; }
void CLogonNotification::Cleanup() { __try { if (m_EventSystem) { if (m_fSubscribed) { UnsubscribeAllMethods(); } SafeRelease(m_EventSystem); }
SafeRelease(m_TypeInfo); SafeRelease(m_TypeLib); } __except(EXCEPTION_EXECUTE_HANDLER) { DEBUGMSG("AUSENS Cleanup raised and execution exception that was trapped."); }
if (m_oBstrTable) { delete m_oBstrTable; m_oBstrTable = NULL; } }
HRESULT CLogonNotification::CheckLocalSystem() { HRESULT hr = E_FAIL; PSID pLocalSid = NULL; HANDLE hToken = NULL; SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY; BOOL fRet = FALSE; BOOL fIsLocalSystem = FALSE;
fRet = AllocateAndInitializeSid( &IDAuthorityNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0,0,0,0,0,0,0, &pLocalSid );
if (fRet == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUGMSG("AUSENS AllocateAndInitializeSid failed with error %x", hr); goto done; }
if (FAILED(hr = CoImpersonateClient())) { DEBUGMSG("AUSENS Failed to impersonate client", hr); hr = E_ACCESSDENIED; goto done; } fRet = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken); if (fRet == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUGMSG("AUSENS Failed to OpenProcessToken"); goto done; }
if (FAILED(CoRevertToSelf())) { AUASSERT(FALSE); //should never be there
hr = E_ACCESSDENIED; goto done; }
fRet = CheckTokenMembership(hToken, pLocalSid, &fIsLocalSystem); if (fRet == FALSE) { hr = HRESULT_FROM_WIN32(GetLastError()); DEBUGMSG("AUSENS fail to Check token membership with error %x", hr); goto done; }
if (fIsLocalSystem) { hr = S_OK; } else { hr = E_ACCESSDENIED; DEBUGMSG("AUSENS SECURITY CHECK Current thread is not running as LocalSystem!!"); }
done:
if (hToken != NULL) CloseHandle(hToken); if (pLocalSid != NULL) FreeSid(pLocalSid);
return hr; }
STDMETHODIMP CLogonNotification::Logon( BSTR UserName ) { DEBUGMSG("AUSENS logon notification for %S", (WCHAR*)UserName ); DEBUGMSG("AUSENS Forcing the rebuilt of the cachesessions array");
//
// fix for security bug 563054 -- annah
//
// The Logon() method is called by the COM+ Event System to notify us of a logon event
// We expose the ISensLogon interface but don't want anybody calling us
// that is not the COM+ Event System.
//
// The COM+ Event System service runs as Local System in the netsvcs svchost group.
// We will check if the caller is really the Event System by checking for
// the Local System account.
//
HRESULT hr = CheckLocalSystem(); if (FAILED(hr)) { DEBUGMSG("AUSENS CheckLocalSystem failed with error %x. Will not trigger logon notification", hr); goto done; }
//
// One big problem of the code below is that although we're validating that
// there are admins on the machine who are valid users for AU, it could be the
// same that was already there, because we don't have a reliable way of receiving
// logoff notifications. So we will raise the NEW_ADMIN event here, and
// we will block the cretiion of a new client if we detect that there's a
// a client still running.
//
gAdminSessions.RebuildSessionCache(); if (gAdminSessions.CSessions() > 0) { DEBUGMSG("AU SENS Logon: There are admins in the admin cache, raising NEW_ADMIN event (it could be a false alarm)"); SetActiveAdminSessionEvent(); }
#if DBG
gAdminSessions.m_DumpSessions(); #endif
done:
return S_OK; }
STDMETHODIMP CLogonNotification::Logoff( BSTR UserName ) { DEBUGMSG( "AUSENS logoff notification for %S", (WCHAR*)UserName );
// do nothing
#if DBG
gAdminSessions.m_DumpSessions(); #endif
return S_OK; }
STDMETHODIMP CLogonNotification::QueryInterface(REFIID iid, void** ppvObject) { HRESULT hr = S_OK; *ppvObject = NULL;
if ((iid == IID_IUnknown) || (iid == _uuidof(IDispatch)) || (iid == _uuidof(ISensLogon))) { *ppvObject = static_cast<ISensLogon *> (this); (static_cast<IUnknown *>(*ppvObject))->AddRef(); } else { hr = E_NOINTERFACE; }
return hr; }
STDMETHODIMP CLogonNotification::GetIDsOfNames(REFIID, OLECHAR ** rgszNames, unsigned int cNames, LCID, DISPID *rgDispId ) { return m_TypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId); }
STDMETHODIMP CLogonNotification::GetTypeInfo(unsigned int iTInfo, LCID, ITypeInfo **ppTInfo ) { if ( iTInfo != 0 ) return DISP_E_BADINDEX;
*ppTInfo = m_TypeInfo; m_TypeInfo->AddRef();
return S_OK; }
STDMETHODIMP CLogonNotification::GetTypeInfoCount(unsigned int *pctinfo) { *pctinfo = 1; return S_OK; }
STDMETHODIMP CLogonNotification::Invoke( DISPID dispID, REFIID riid, LCID, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pvarResult, EXCEPINFO *pExcepInfo, unsigned int *puArgErr ) {
if (riid != IID_NULL) { return DISP_E_UNKNOWNINTERFACE; }
return m_TypeInfo->Invoke( (IDispatch*) this, dispID, wFlags, pDispParams, pvarResult, pExcepInfo, puArgErr ); }
STDMETHODIMP CLogonNotification::DisplayLock( BSTR UserName ) { return S_OK; }
STDMETHODIMP CLogonNotification::DisplayUnlock( BSTR UserName ) { return S_OK; }
STDMETHODIMP CLogonNotification::StartScreenSaver( BSTR UserName ) { return S_OK; }
STDMETHODIMP CLogonNotification::StopScreenSaver( BSTR UserName ) { return S_OK; }
STDMETHODIMP CLogonNotification::StartShell( BSTR UserName ) { return S_OK; }
|