|
|
//*************************************************************
//
// Microsoft Confidential. Copyright (c) Microsoft Corporation 1999. All rights reserved
//
// File: diagprov.cpp
//
// Description: Rsop diagnostic mode provider
//
// History: 8-20-99 leonardm Created
//
//*************************************************************
#include "uenv.h"
#include "diagprov.h"
#include "rsopinc.h"
#include "Indicate.h"
#include "rsopdbg.h"
#include "rsopsec.h"
HRESULT EnumerateUserNameSpace( IWbemLocator *pWbemLocator, HANDLE hToken, SAFEARRAY **psaUserSids );
HRESULT UpdateGPCoreStatus(IWbemLocator *pWbemLocator, LPWSTR szSid, LPWSTR szNameSpace);
//*************************************************************
//
// GetMachAccountName()
//
// Purpose: Gets Machine account name
//
// Return: Machine Account
//
// Note: Need to call it w/o impersonation
//*************************************************************
LPTSTR GetMachAccountName() { return MyGetUserName(NameSamCompatible); }
//*************************************************************
//
// GetUserAccountName()
//
// Purpose: Gets the user account given the Sid
//
// Parameters: lpSidString - Sid in string format that we are interested in
//
// Return: Account Name
//
//*************************************************************
LPTSTR GetUserAccountName(LPTSTR lpSidString) { SID_NAME_USE peUse; DWORD dwNameSize = 0; PSID pSid = NULL; DWORD dwDomainSize = 0; LPTSTR szRetAccount = NULL;
if (AllocateAndInitSidFromString(lpSidString, &pSid) != STATUS_SUCCESS ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("GetUserAccountName::AllocateAndInitSidFromString failed.")); goto Exit; }
LookupAccountSid(NULL, pSid, NULL, &dwNameSize, NULL, &dwDomainSize, &peUse);
if (dwNameSize && dwDomainSize) { XPtrLF<TCHAR> xszAccount = LocalAlloc(LPTR, sizeof(TCHAR)*(dwNameSize+dwDomainSize+4));
XPtrLF<TCHAR> xszDomainName = LocalAlloc(LPTR, sizeof(TCHAR)*(dwDomainSize+1));
XPtrLF<TCHAR> xszName = LocalAlloc(LPTR, sizeof(TCHAR)*(dwNameSize+1));
if (!xszAccount || !xszDomainName || !xszName ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("GetUserAccountName::AllocMem failed with 0x%x."), GetLastError()); goto Exit; }
if (!LookupAccountSid(NULL, pSid, xszName, &dwNameSize, xszDomainName, &dwDomainSize, &peUse)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("GetUserAccountName::LookupaccountSid failed with 0x%x."), GetLastError()); goto Exit; }
lstrcpy(xszAccount, xszDomainName); lstrcat(xszAccount, TEXT("\\")); lstrcat(xszAccount, xszName);
dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("GetUserAccountName::User account is %s."), xszAccount);
szRetAccount = xszAccount.Acquire(); }
Exit: if (pSid) FreeSid(pSid);
return szRetAccount; }
//*************************************************************
//
// CheckRsopDiagPolicyInteractive()
//
// Purpose: Can this user get the rsop data even if the user is logged
// on interactively
//
// Parameters:
//
// Return: CheckRsopDiagPolicyInteractive
//
//*************************************************************
BOOL CheckRsopDiagPolicyInteractive() { HKEY hKeyUser = NULL; HKEY hKey; DWORD dwSize = 0, dwType = 0; BOOL bDeny = FALSE;
CoImpersonateClient();
if (!RegOpenCurrentUser(KEY_READ, &hKeyUser) == ERROR_SUCCESS) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("CheckRsopDiagPolicyInteractive:: couldn't access registry of interactive user.")); hKeyUser = NULL; }
CoRevertToSelf();
//
// First, check for a user preference
//
if (hKeyUser) { if (RegOpenKeyEx (hKeyUser, WINLOGON_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
dwSize = sizeof(bDeny); RegQueryValueEx (hKey, DENY_RSOP_FROM_INTERACTIVE_USER, NULL, &dwType, (LPBYTE) &bDeny, &dwSize);
RegCloseKey (hKey); } }
//
// Check for a machine preference
//
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
dwSize = sizeof(bDeny); RegQueryValueEx (hKey, DENY_RSOP_FROM_INTERACTIVE_USER, NULL, &dwType, (LPBYTE) &bDeny, &dwSize);
RegCloseKey (hKey); }
//
// Check for a user policy
//
if (hKeyUser) { if (RegOpenKeyEx (hKeyUser, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = sizeof(bDeny); RegQueryValueEx (hKey, DENY_RSOP_FROM_INTERACTIVE_USER, NULL, &dwType, (LPBYTE) &bDeny, &dwSize); RegCloseKey (hKey); } }
//
// Check for a machine policy
//
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
dwSize = sizeof(bDeny); RegQueryValueEx (hKey, DENY_RSOP_FROM_INTERACTIVE_USER, NULL, &dwType, (LPBYTE) &bDeny, &dwSize);
RegCloseKey (hKey); }
if (hKeyUser) { RegCloseKey(hKeyUser); }
return (!bDeny); }
//*************************************************************
//
// Functions: Constructor, Destructor, QueryInterface, AddRef, Release
//
//*************************************************************
CSnapProv::CSnapProv() : m_cRef(1), m_bInitialized(false), m_pNamespace(NULL) { InterlockedIncrement(&g_cObj);
m_xbstrUserSid = L"userSid"; if ( !m_xbstrUserSid ) return;
m_xbstrUserSids = L"userSids"; if ( !m_xbstrUserSids ) return;
m_xbstrNameSpace = L"nameSpace"; if ( !m_xbstrNameSpace ) return;
m_xbstrResult = L"hResult"; if ( !m_xbstrResult ) return;
m_xbstrFlags = L"flags"; if ( !m_xbstrFlags ) return;
m_xbstrExtendedInfo = L"ExtendedInfo"; if ( !m_xbstrExtendedInfo ) return;
m_xbstrClass = L"RsopLoggingModeProvider"; if ( !m_xbstrClass ) return;
m_bInitialized = TRUE; }
CSnapProv::~CSnapProv() { if(m_pNamespace != NULL) { m_pNamespace->Release(); }
InterlockedDecrement(&g_cObj); }
STDMETHODIMP CSnapProv::QueryInterface (REFIID riid, LPVOID* ppv) { if(riid == IID_IUnknown || riid == IID_IWbemServices) { *ppv = static_cast<IWbemServices*>(this); } else if(riid == IID_IWbemProviderInit) { *ppv = static_cast<IWbemProviderInit*>(this); } else { *ppv=NULL; return E_NOINTERFACE; }
AddRef(); return S_OK; }
STDMETHODIMP_(ULONG) CSnapProv::AddRef() { return InterlockedIncrement( &m_cRef ); }
STDMETHODIMP_(ULONG) CSnapProv::Release() { if (!InterlockedDecrement(&m_cRef)) { delete this; return 0; } return m_cRef; }
//*************************************************************
//
// Initialize()
//
// Purpose: WbemProvider's initialize method
//
// Parameters: See IWbemProivderInit::Initialize
//
// Return: hresult
//
//*************************************************************
STDMETHODIMP CSnapProv::Initialize( LPWSTR pszUser, LONG lFlags, LPWSTR pszNamespace, LPWSTR pszLocale, IWbemServices __RPC_FAR *pNamespace, IWbemContext __RPC_FAR *pCtx, IWbemProviderInitSink __RPC_FAR *pInitSink) { HRESULT hr;
if ( !m_bInitialized ) { hr = pInitSink->SetStatus(E_FAIL, 0); return hr; }
//
// No need to authenticate user. The ACLs on Rsop namespace will
// deny access to users that cannot snapshot diagnostic mode data.
//
m_pNamespace = pNamespace; m_pNamespace->AddRef();
hr = pInitSink->SetStatus(WBEM_S_INITIALIZED, 0);
return hr; }
#if _MSC_FULL_VER <= 13008827 && defined(_M_IX86)
#pragma optimize("", off)
#endif
//*************************************************************
//
// ExecMethodAsync()
//
// Purpose: Execute method
//
// Parameters: See IWbemServices::ExecMethodAsync
//
// Return: hresult
//
//*************************************************************
STDMETHODIMP CSnapProv::ExecMethodAsync( const BSTR bstrObject, const BSTR bstrMethod, long lFlags, IWbemContext __RPC_FAR *pCtx, IWbemClassObject __RPC_FAR *pInParams, IWbemObjectSink __RPC_FAR *pResponseHandler) { HRESULT hr;
CFailRetStatus retStatus( pResponseHandler ); IUnknown *pOldSecContext;
//
// Make sure the provider is properly initialized
//
//
// Allow for debugging level to be dynamically changed during queries
//
dbgRsop.Initialize( L"Software\\Microsoft\\Windows NT\\CurrentVersion\\winlogon", L"RsopDebugLevel", L"userenv.log", L"userenv.bak", FALSE );
InitDebugSupport(0);
if ( !m_bInitialized ) { hr = E_OUTOFMEMORY; retStatus.SetError( hr ); return hr; }
//
// Initialize the return status object to fail status
//
IWbemLocator *pWbemLocator = NULL; hr = CoCreateInstance( CLSID_WbemAuthenticatedLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pWbemLocator ); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecMethodAsync: CoCreateInstance returned 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
XInterface<IWbemLocator> xLocator( pWbemLocator );
IWbemClassObject* pProvClass = NULL; IWbemClassObject* pOutClass = NULL; IWbemClassObject* pOutParams = NULL;
hr = m_pNamespace->GetObject( m_xbstrClass, 0, pCtx, &pProvClass, NULL); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::GetObject failed with 0x%x."), hr ); retStatus.SetError( hr ); return hr; }
XInterface<IWbemClassObject> xProvClass( pProvClass );
hr = pProvClass->GetMethod( bstrMethod, 0, NULL, &pOutClass); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::GetMethod failed with 0x%x."), hr ); retStatus.SetError( hr ); return hr; }
XInterface<IWbemClassObject> xOutClass( pOutClass );
hr = pOutClass->SpawnInstance(0, &pOutParams); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::SpawnInstance failed with 0x%x."), hr ); retStatus.SetError( hr ); return hr; }
//
// Get the tokens and Sids upfront
//
XPtrLF <WCHAR> xszSidString; XPtrLF <SID> xSid; XHandle xUserToken;
hr = CoImpersonateClient(); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoImpersonateClient failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
if (OpenThreadToken (GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &xUserToken)) {
LPWSTR szSid = GetSidString(xUserToken); if (!szSid) { hr = HRESULT_FROM_WIN32(GetLastError()); dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::GetSidString failed with %d"), GetLastError() ); CoRevertToSelf(); retStatus.SetError( hr ); return hr; } else { xszSidString = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*(lstrlen(szSid)+1));
if (!xszSidString) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::LocalAlloc failed with %d"), GetLastError() ); hr = HRESULT_FROM_WIN32(GetLastError()); DeleteSidString(szSid); CoRevertToSelf(); retStatus.SetError( hr ); return hr; }
lstrcpy(xszSidString, szSid);
DeleteSidString(szSid); }
xSid = (SID *)GetUserSid(xUserToken); if (!xSid) { hr = HRESULT_FROM_WIN32(GetLastError()); dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::GetUserSid failed with %d"), GetLastError() ); CoRevertToSelf(); retStatus.SetError( hr ); return hr; } } else { hr = HRESULT_FROM_WIN32(GetLastError()); dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Openthreadtoken failed with 0x%x"), hr ); CoRevertToSelf(); retStatus.SetError( hr ); return hr; }
CoRevertToSelf();
XInterface<IWbemClassObject> xOutParams( pOutParams );
if ( _wcsicmp( (WCHAR *) bstrMethod, L"RsopDeleteSession" ) == 0 ) {
//
// rsopdeletesession
//
VARIANT vNameSpace; hr = pInParams->Get( m_xbstrNameSpace, 0, &vNameSpace, NULL, NULL); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Get machine name failed with 0x%x."), hr ); retStatus.SetError( hr ); return hr; } XVariant xvNameSpace( &vNameSpace );
if (vNameSpace.vt != VT_NULL ) { //
// We want to run as LS
//
hr = CoSwitchCallContext(NULL, &pOldSecContext);
if (FAILED(hr)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; } hr = ProviderDeleteRsopNameSpace( pWbemLocator, vNameSpace.bstrVal, xUserToken, xszSidString, SETUP_NS_SM);
IUnknown *pNewObject; HRESULT hr2 = CoSwitchCallContext(pOldSecContext, &pNewObject);
if (FAILED(hr2)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr2 ); } } else { hr = E_INVALIDARG; }
VARIANT var; var.vt = VT_I4; var.lVal = hr;
hr = pOutParams->Put( m_xbstrResult, 0, &var, 0); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Put result failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
hr = pResponseHandler->Indicate(1, &pOutParams); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod:: Indicate failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
return hr; } else if ( _wcsicmp( (WCHAR *) bstrMethod, L"RsopEnumerateUsers" ) == 0 ) {
//
// RsopenumerateUsers
//
SAFEARRAY *pArray;
hr = EnumerateUserNameSpace( pWbemLocator, xUserToken, &pArray ); XSafeArray xsaUserSids(pArray); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::EnumerateUserNameSpace failed") ); }
VARIANT var; var.vt = VT_I4; var.lVal = hr;
hr = pOutParams->Put( m_xbstrResult, 0, &var, 0); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Put result failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
var.vt = VT_ARRAY | VT_BSTR; var.parray = xsaUserSids;
hr = pOutParams->Put( m_xbstrUserSids, 0, &var, 0 ); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Put sids failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
hr = pResponseHandler->Indicate(1, &pOutParams); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod:: Indicate failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
return hr; }
//
// progress indicator.
// 25% done when we enter the first critical section.
// 50% done when we enter the second critical section.
// 100% complete when we copy the namespace.
//
CProgressIndicator Indicator( pResponseHandler, (lFlags & WBEM_FLAG_SEND_STATUS) != 0 );
//
// 5% done. Hack for UI.
//
hr = Indicator.IncrementBy( 5 );
VARIANT vUserSid; hr = pInParams->Get( m_xbstrUserSid, 0, &vUserSid, NULL, NULL); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Get RemoteComputer failed with 0x%x."), hr ); retStatus.SetError( hr ); return hr; } XVariant xvUserSid ( &vUserSid );
VARIANT vFlags; VariantInit( &vFlags ); hr = pInParams->Get( m_xbstrFlags, 0, &vFlags, NULL, NULL); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Get dwFlags failed with 0x%x."), hr ); retStatus.SetError( hr ); return hr; }
DWORD dwFlags = vFlags.vt == VT_EMPTY || vFlags.vt == VT_NULL ? 0 : vFlags.ulVal; //
// Flags specific to Diagnostic mode provider
//
if ((dwFlags & FLAG_NO_USER) && (dwFlags & FLAG_NO_COMPUTER)) { hr = WBEM_E_INVALID_PARAMETER; dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod:: Both user and computer are null.")); retStatus.SetError( hr ); return hr; }
//
// We can dump out all the input parameters here later on.
//
dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::---------------RsopCreateSession::Input Parameters--------------------")); dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::UserSid = <%s>"), vUserSid.vt == VT_NULL ? L"NULL" : vUserSid.bstrVal); dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::flags = <%d>"), dwFlags); dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::---------------RsopCreateSession::Input Parameters--------------------"));
//
// Code for RsopCreateSession method
//
XPtrLF<TCHAR> xszMachSOM; XPtrLF<TCHAR> xszUserSOM; BOOL bDelegated = FALSE; BOOL bCheckAccess = FALSE; DWORD dwExtendedInfo = 0; XPtrLF<TCHAR> xszUserAccount; XPtrLF<TCHAR> xszMachAccount;
//
// Get the machine SOM
//
if ( !(dwFlags & FLAG_NO_COMPUTER) ) {
xszMachAccount = GetMachAccountName();
dwExtendedInfo |= RSOP_COMPUTER_ACCESS_DENIED;
if (!xszMachAccount) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::No machine account. error %d"), GetLastError() ); } else { xszMachSOM = GetSOM(xszMachAccount);
if (xszMachSOM) { bCheckAccess = TRUE; dwExtendedInfo &= ~RSOP_COMPUTER_ACCESS_DENIED; } else { dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::No machine SOM. error %d"), GetLastError() ); } } } else { bCheckAccess = TRUE; }
//
// Get the User SOM
//
if ((bCheckAccess) && ( !(dwFlags & FLAG_NO_USER) ) ) {
bCheckAccess = FALSE; dwExtendedInfo |= RSOP_USER_ACCESS_DENIED;
xszUserAccount = GetUserAccountName(vUserSid.vt == VT_NULL ? xszSidString : vUserSid.bstrVal);
if (!xszUserAccount) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::No User account. error %d"), GetLastError() ); } else { xszUserSOM = GetSOM(xszUserAccount);
if (xszUserSOM) { bCheckAccess = TRUE; dwExtendedInfo &= ~RSOP_USER_ACCESS_DENIED; } else { dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::No User SOM. error %d"), GetLastError() ); } } }
//
// Check access now
//
if (bCheckAccess) { hr = AuthenticateUser(xUserToken, xszMachSOM, xszUserSOM, TRUE, &dwExtendedInfo);
if (FAILED(hr)) { dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::User is not a delegated admin. Error 0x%x"), hr ); hr = S_OK; } else { dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::User is a delegated admin. Error 0x%x"), hr ); bDelegated = TRUE; } }
dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecMethodAsync::Getting policy critical sections"));
XCriticalPolicySection criticalPolicySectionMACHINE( EnterCriticalPolicySectionEx(TRUE, 40000, ECP_FAIL_ON_WAIT_TIMEOUT) );
if ( !criticalPolicySectionMACHINE ) { hr = HRESULT_FROM_WIN32( GetLastError() ); dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecMethodAsync::EnterCriticalPolicySection failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
//
// 25% done when we enter the first critical section.
//
hr = Indicator.IncrementBy( 20 ); if ( FAILED( hr ) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecMethodAsync::IncrementBy() failed with 0x%x"), hr ); }
XCriticalPolicySection criticalPolicySectionUSER( EnterCriticalPolicySectionEx(FALSE, 40000, ECP_FAIL_ON_WAIT_TIMEOUT) );
if ( !criticalPolicySectionUSER ) { hr = HRESULT_FROM_WIN32( GetLastError() ); dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecMethodAsync::EnterCriticalPolicySection failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
//
// 50% done when we enter the second critical section.
//
hr = Indicator.IncrementBy( 25 ); if ( FAILED( hr ) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecMethodAsync::IncrementBy() failed with 0x%x"), hr ); }
LPWSTR wszNameSpace = 0;
//
// Impersonate if not delegated
//
if (!bDelegated) { hr = CoImpersonateClient(); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoImpersonateClient failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; } } else {
//
// We want to run as LS
//
hr = CoSwitchCallContext(NULL, &pOldSecContext);
if (FAILED(hr)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; } }
XPtrLF<WCHAR> xwszNameSpace;
DWORD dwNewNameSpaceFlags = SETUP_NS_SM; dwNewNameSpaceFlags |= (dwFlags & FLAG_NO_USER) ? SETUP_NS_SM_NO_USER : 0; dwNewNameSpaceFlags |= (dwFlags & FLAG_NO_COMPUTER) ? SETUP_NS_SM_NO_COMPUTER : 0;
dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::UserSid = <%s>"), vUserSid.vt == VT_NULL ? L"NULL" : vUserSid.bstrVal); dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::User who is running the tool = <%s>"), (LPWSTR)xszSidString);
hr = SetupNewNameSpace( &xwszNameSpace, 0, // namespace on this machine
(vUserSid.vt == VT_NULL) ? ((LPWSTR)xszSidString) : vUserSid.bstrVal, xSid, pWbemLocator, dwNewNameSpaceFlags, &dwExtendedInfo);
if (!bDelegated) { CoRevertToSelf(); } else {
//
// restore call context
//
IUnknown *pNewObject; HRESULT hr2 = CoSwitchCallContext(pOldSecContext, &pNewObject);
if (FAILED(hr2)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr2 ); } }
if ( FAILED(hr) && !bDelegated) { dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::SetupNewNameSpace failed with 0x%x"), hr );
if (IsUserAnInteractiveUser(xUserToken) && CheckRsopDiagPolicyInteractive()) { if ( (vUserSid.vt == VT_NULL) || (_wcsicmp(vUserSid.bstrVal, xszSidString) == 0 )) {
dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::SetupNewNameSpace failed. retrying in interactive mode"), hr );
//
// We want to run as LS
//
hr = CoSwitchCallContext(NULL, &pOldSecContext);
if (FAILED(hr)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; } //
// if the namespace is null, get the name of the interactive namespace
//
XPtrLF<WCHAR> xszInteractiveNS; hr = GetInteractiveNameSpace(xszSidString, &xszInteractiveNS); if (FAILED(hr)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
BOOL bContinue=TRUE;
if (dwFlags & FLAG_FORCE_CREATENAMESPACE) { hr = DeleteRsopNameSpace( xszInteractiveNS, pWbemLocator ); // ignore error
} else { XInterface<IWbemServices> xWbemServices;
hr = pWbemLocator->ConnectServer( xszInteractiveNS, NULL, NULL, 0L, 0L, NULL, NULL, &xWbemServices );
if (SUCCEEDED(hr)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod:: Namespace already exists. Failing call")); hr = WBEM_E_ALREADY_EXISTS; dwExtendedInfo = RSOP_TEMPNAMESPACE_EXISTS; bContinue = FALSE; } } if (bContinue) { dwNewNameSpaceFlags |= SETUP_NS_SM_INTERACTIVE;
hr = SetupNewNameSpace( &xwszNameSpace, 0, // namespace on this machine
xszSidString, xSid, pWbemLocator, dwNewNameSpaceFlags, &dwExtendedInfo);
} //
// restore call context
//
IUnknown *pNewObject; HRESULT hr2 = CoSwitchCallContext(pOldSecContext, &pNewObject);
if (FAILED(hr2)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr2 ); } } } }
if (FAILED(hr)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::SetupNewNameSpace failed with 0x%x"), hr ); } else { HRESULT hr2; VARIANT var; //
// if we managed to get a snapshot, then ignore the extended access denied info
//
dwExtendedInfo = 0;
//
// We want to run as LS
//
hr = CoSwitchCallContext(NULL, &pOldSecContext);
if (FAILED(hr)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
if ( !(dwFlags & FLAG_NO_COMPUTER) ) {
hr = UpdateGPCoreStatus(pWbemLocator, NULL, xwszNameSpace); }
if ( (SUCCEEDED(hr)) && (!(dwFlags & FLAG_NO_USER)) ) { hr = UpdateGPCoreStatus(pWbemLocator, vUserSid.vt == VT_NULL ? xszSidString : vUserSid.bstrVal, xwszNameSpace); }
//
// restore call context
//
IUnknown *pNewObject; hr2 = CoSwitchCallContext(pOldSecContext, &pNewObject);
if (FAILED(hr2)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr2 ); }
//
// Return the error code if the status cannot be updated..
//
if (FAILED(hr)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::UpdateGPCoreStatus failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
XBStr xbstrNS( xwszNameSpace ); if ( !xbstrNS ) { hr2 = HRESULT_FROM_WIN32( E_OUTOFMEMORY ); dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Memory allocate failed") ); retStatus.SetError( hr2 ); return hr2; }
var.vt = VT_BSTR; var.bstrVal = xbstrNS; hr2 = pOutParams->Put( m_xbstrNameSpace, 0, &var, 0); if ( FAILED(hr2) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Put namespace failed with 0x%x"), hr ); retStatus.SetError( hr2 ); return hr2; } }
VARIANT var; var.vt = VT_I4; var.lVal = hr;
hr = pOutParams->Put( m_xbstrResult, 0, &var, 0); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Put result failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
var.lVal = dwExtendedInfo; hr = pOutParams->Put( m_xbstrExtendedInfo, 0, &var, 0); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::Put result failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
//
// 100% complete when we copy the namespace.
//
hr = Indicator.SetComplete(); if ( FAILED( hr ) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecMethodAsync::IncrementBy() failed with 0x%x"), hr ); }
hr = pResponseHandler->Indicate(1, &pOutParams); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod:: Indicate failed with 0x%x"), hr ); retStatus.SetError( hr ); return hr; }
return hr; }
#if _MSC_FULL_VER <= 13008827 && defined(_M_IX86)
#pragma optimize("", on)
#endif
//*************************************************************
//
// EnumerateUserNameSpace()
//
// Purpose: EnumerateUserNameSpace
//
// Parameters:
// pWbemLocator - Pointer to a locator
// [out] psaUserSids - Pointer to User Sids
//
// Return: hresult
//
//*************************************************************
typedef struct _UserSidList { LPWSTR szUserSid; struct _UserSidList *pNext; } USERSIDLIST, *PUSERSIDLIST;
HRESULT EnumerateUserNameSpace( IWbemLocator *pWbemLocator, HANDLE hToken, SAFEARRAY **psaUserSids ) { USERSIDLIST SidList = {0,0}; DWORD dwNum = 0; PUSERSIDLIST pElem = NULL; HRESULT hr = S_OK; DWORD dwExtendedInfo; IUnknown *pOldSecContext; //
// Connect to namespace ROOT\RSOP\User
//
*psaUserSids = NULL; XInterface<IWbemServices>xpWbemServices = NULL;
XBStr xbstrNamespace = RSOP_NS_DIAG_USERROOT;
if(!xbstrNamespace) { DebugMsg((DM_WARNING, TEXT("EnumerateUserNameSpace: Failed to allocate memory."))); return E_OUTOFMEMORY; }
hr = pWbemLocator->ConnectServer(xbstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &xpWbemServices); if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("EnumerateUserNameSpace: ConnectServer failed. hr=0x%x" ), hr )); return hr; }
//
// Enumerate all instances of __namespace at the root\rsop\user level.
//
XInterface<IEnumWbemClassObject> xpEnum; XBStr xbstrClass = L"__namespace"; if(!xbstrClass) { DebugMsg((DM_WARNING, TEXT("EnumerateUserNameSpace: Failed to allocate memory."))); return E_OUTOFMEMORY; }
hr = xpWbemServices->CreateInstanceEnum( xbstrClass, WBEM_FLAG_SHALLOW | WBEM_FLAG_FORWARD_ONLY, NULL, &xpEnum); if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("EnumerateUserNameSpace: CreateInstanceEnum failed. hr=0x%x" ), hr )); return hr; }
XBStr xbstrProperty = L"Name"; if(!xbstrProperty) { DebugMsg((DM_WARNING, TEXT("EnumerateUserNameSpace: Failed to allocate memory"))); return E_FAIL; }
XInterface<IWbemClassObject>xpInstance = NULL; ULONG ulReturned = 1;
while(1) { hr = xpEnum->Next( WBEM_NO_WAIT, 1, &xpInstance, &ulReturned); if (hr != WBEM_S_NO_ERROR || !ulReturned) { break; }
VARIANT var; VariantInit(&var);
hr = xpInstance->Get(xbstrProperty, 0L, &var, NULL, NULL); xpInstance = NULL; if(FAILED(hr)) { DebugMsg((DM_VERBOSE, TEXT("EnumerateUserNameSpace: Get failed. hr=0x%x" ), hr )); goto Exit; // continue
}
//
// Check to see whether user is delegated admin for the user account
//
XPtrLF<WCHAR> xszUserSid = (LPWSTR)LocalAlloc(LPTR, (1+lstrlen(var.bstrVal))*sizeof(WCHAR));
if (!xszUserSid) { hr = HRESULT_FROM_WIN32(GetLastError()); DebugMsg((DM_VERBOSE, TEXT("EnumerateUserNameSpace: AllocMem failed. hr=0x%x" ), hr )); goto Exit; }
ConvertWMINameToSid(var.bstrVal, xszUserSid);
//
// See whether it is a valid Sid
//
PSID pSid = NULL;
if (AllocateAndInitSidFromString(xszUserSid, &pSid) != STATUS_SUCCESS ) { DebugMsg((DM_VERBOSE, TEXT("EnumerateUserNameSpace: AllocateAndInitSidFromString - %s is not a valid Sid" ), xszUserSid)); continue; }
if (!IsValidSid(pSid)) { DebugMsg((DM_VERBOSE, TEXT("EnumerateUserNameSpace: %s is not a valid Sid" ), xszUserSid)); FreeSid(pSid); continue; }
FreeSid(pSid);
//
// First try to connect to the NameSpace
//
hr = CoImpersonateClient(); if ( FAILED(hr) ) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoImpersonateClient failed with 0x%x"), hr ); goto Exit; }
XInterface<IWbemServices> xpChildNamespace = NULL; hr = xpWbemServices->OpenNamespace( var.bstrVal, 0, NULL, &xpChildNamespace, NULL); CoRevertToSelf();
if(FAILED(hr)) { IUnknown *pNewObject; HRESULT hr2=S_OK; BOOL bDelegated = TRUE;
DebugMsg((DM_VERBOSE, TEXT("EnumerateUserNameSpace: OpenNamespace returned 0x%x"), hr));
//
// Check whether user has access as LS
//
//
// We want to run as LS
//
hr = CoSwitchCallContext(NULL, &pOldSecContext);
if (FAILED(hr)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr ); goto Exit; }
XPtrLF<TCHAR> xszAccount = GetUserAccountName(xszUserSid);
if (!xszAccount) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::No User account. error %d"), GetLastError() ); bDelegated = FALSE; } XPtrLF<TCHAR> xszUserSOM; if (bDelegated) { xszUserSOM = GetSOM(xszAccount); if (!xszUserSOM) { dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::No User SOM. Probably local account. error %d"), GetLastError() ); bDelegated = FALSE; } }
//
// Check access now
//
if (bDelegated) { hr = AuthenticateUser(hToken, NULL, xszUserSOM, TRUE, &dwExtendedInfo);
if (FAILED(hr)) { dbg.Msg( DEBUG_MESSAGE_VERBOSE, TEXT("ExecAsyncMethod::User is not a delegated admin. Error 0x%x"), hr ); bDelegated = FALSE; } } //
// restore call context
//
hr2 = CoSwitchCallContext(pOldSecContext, &pNewObject);
if (FAILED(hr2)) { dbg.Msg( DEBUG_MESSAGE_WARNING, TEXT("ExecAsyncMethod::CoSwitchCallContext failed with 0x%x"), hr2 ); }
if (!bDelegated) { continue; }
}
//
// For every instance of __namespace under ROOT\RSOP\user
// convert it to Sid and return
//
pElem = (PUSERSIDLIST)LocalAlloc(LPTR, sizeof(USERSIDLIST));
if (!pElem) { DebugMsg((DM_WARNING, TEXT("EnumerateUserNameSpace: Couldn't allocate memory Error = GetLastError()" ), GetLastError())); goto Exit; }
pElem->szUserSid = xszUserSid.Acquire();
//
// Attach to the beginning of the list
//
pElem->pNext = SidList.pNext; SidList.pNext = pElem; dwNum++; VariantClear( &var );
}
if(hr != WBEM_S_FALSE || ulReturned) { DebugMsg((DM_WARNING, TEXT("EnumerateUserNameSpace: Get failed. hr=0x%x" ), hr )); hr = E_FAIL; goto Exit; }
//
// Now make the safe array from the list that we got
//
SAFEARRAYBOUND arrayBound[1]; arrayBound[0].lLbound = 0; arrayBound[0].cElements = dwNum;
*psaUserSids = SafeArrayCreate( VT_BSTR, 1, arrayBound ); if ( *psaUserSids == NULL ) { DebugMsg((DM_WARNING, TEXT("EnumerateUserNameSpace: Failed to allocate memory. Error = %d" ), GetLastError() )); hr = E_FAIL; goto Exit; }
//
// traverse the list
//
DWORD i; for (i=0, pElem = SidList.pNext; (i < dwNum); i++, pElem = pElem->pNext) { XBStr xbstrUserSid(pElem->szUserSid);
SafeArrayPutElement( *psaUserSids, (LONG *)&i, xbstrUserSid); } hr = S_OK;
Exit:
// free
for (i=0, pElem = SidList.pNext; (i < dwNum); i++ ) { if (pElem->szUserSid) LocalFree(pElem->szUserSid);
PUSERSIDLIST pTemp = pElem;
pElem = pElem->pNext; LocalFree(pTemp); }
return hr; }
|