2025-04-27 07:49:33 -04:00

827 lines
21 KiB
C++

//***************************************************************************
//
// Copyright (c) 1998-1999 Microsoft Corporation
//
// PRIVILEGE.CPP
//
// alanbos 30-Sep-98 Created.
//
// Defines the implementation of CSWbemPrivilege
//
//***************************************************************************
#include <tchar.h>
#include "precomp.h"
#include <map>
#include <vector>
#include <wmiutils.h>
#include <wbemdisp.h>
#include <ocidl.h>
#include "disphlp.h"
#include "privilege.h"
#ifndef _UNICODE
#include <mbstring.h>
#endif
typedef struct PrivilegeDef {
WbemPrivilegeEnum privilege;
TCHAR *tName;
OLECHAR *monikerName;
} PrivilegeDef;
#define WBEMS_MAX_NUM_PRIVILEGE 26
static PrivilegeDef s_privilegeDefMap [WBEMS_MAX_NUM_PRIVILEGE] = {
{ wbemPrivilegeCreateToken, SE_CREATE_TOKEN_NAME, L"CreateToken" },
{ wbemPrivilegePrimaryToken, SE_ASSIGNPRIMARYTOKEN_NAME, L"PrimaryToken" },
{ wbemPrivilegeLockMemory, SE_LOCK_MEMORY_NAME, L"LockMemory" },
{ wbemPrivilegeIncreaseQuota, SE_INCREASE_QUOTA_NAME, L"IncreaseQuota" },
{ wbemPrivilegeMachineAccount, SE_MACHINE_ACCOUNT_NAME, L"MachineAccount" },
{ wbemPrivilegeTcb, SE_TCB_NAME, L"Tcb" },
{ wbemPrivilegeSecurity, SE_SECURITY_NAME, L"Security" },
{ wbemPrivilegeTakeOwnership, SE_TAKE_OWNERSHIP_NAME, L"TakeOwnership" },
{ wbemPrivilegeLoadDriver, SE_LOAD_DRIVER_NAME, L"LoadDriver" },
{ wbemPrivilegeSystemProfile, SE_SYSTEM_PROFILE_NAME, L"SystemProfile" },
{ wbemPrivilegeSystemtime, SE_SYSTEMTIME_NAME, L"SystemTime" },
{ wbemPrivilegeProfileSingleProcess, SE_PROF_SINGLE_PROCESS_NAME, L"ProfileSingleProcess" },
{ wbemPrivilegeIncreaseBasePriority, SE_INC_BASE_PRIORITY_NAME, L"IncreaseBasePriority" },
{ wbemPrivilegeCreatePagefile, SE_CREATE_PAGEFILE_NAME, L"CreatePagefile" },
{ wbemPrivilegeCreatePermanent, SE_CREATE_PERMANENT_NAME, L"CreatePermanent" },
{ wbemPrivilegeBackup, SE_BACKUP_NAME, L"Backup" },
{ wbemPrivilegeRestore, SE_RESTORE_NAME, L"Restore" },
{ wbemPrivilegeShutdown, SE_SHUTDOWN_NAME, L"Shutdown" },
{ wbemPrivilegeDebug, SE_DEBUG_NAME, L"Debug" },
{ wbemPrivilegeAudit, SE_AUDIT_NAME, L"Audit" },
{ wbemPrivilegeSystemEnvironment, SE_SYSTEM_ENVIRONMENT_NAME, L"SystemEnvironment" },
{ wbemPrivilegeChangeNotify, SE_CHANGE_NOTIFY_NAME, L"ChangeNotify" },
{ wbemPrivilegeRemoteShutdown, SE_REMOTE_SHUTDOWN_NAME, L"RemoteShutdown" },
{ wbemPrivilegeUndock, SE_UNDOCK_NAME, L"Undock" },
{ wbemPrivilegeSyncAgent, SE_SYNC_AGENT_NAME, L"SyncAgent" },
{ wbemPrivilegeEnableDelegation, SE_ENABLE_DELEGATION_NAME, L"EnableDelegation" }
};
TCHAR *CSWbemPrivilege::GetNameFromId (WbemPrivilegeEnum iPrivilege)
{
DWORD i = iPrivilege - 1;
return (WBEMS_MAX_NUM_PRIVILEGE > i) ?
s_privilegeDefMap [i].tName : NULL;
}
OLECHAR *CSWbemPrivilege::GetMonikerNameFromId (WbemPrivilegeEnum iPrivilege)
{
DWORD i = iPrivilege - 1;
return (WBEMS_MAX_NUM_PRIVILEGE > i) ?
s_privilegeDefMap [i].monikerName : NULL;
}
bool CSWbemPrivilege::GetIdFromMonikerName (OLECHAR *pName, WbemPrivilegeEnum &iPrivilege)
{
bool status = false;
if (pName)
{
for (DWORD i = 0; i < WBEMS_MAX_NUM_PRIVILEGE; i++)
{
if (0 == _wcsnicmp (pName, s_privilegeDefMap [i].monikerName,
wcslen (s_privilegeDefMap [i].monikerName)))
{
// Success
iPrivilege = s_privilegeDefMap [i].privilege;
status = true;
break;
}
}
}
return status;
}
bool CSWbemPrivilege::GetIdFromName (BSTR bsName, WbemPrivilegeEnum &iPrivilege)
{
bool status = false;
if (bsName)
{
#ifdef _UNICODE
for (DWORD i = 0; i < WBEMS_MAX_NUM_PRIVILEGE; i++)
{
if (0 == _wcsicmp (bsName, s_privilegeDefMap [i].tName))
{
// Success
iPrivilege = s_privilegeDefMap [i].privilege;
status = true;
break;
}
}
#else
// Convert bsName to a multibyte string
size_t mbsNameLen = wcstombs (NULL, bsName, 0);
char *mbsName = new char [mbsNameLen + 1];
wcstombs (mbsName, bsName, mbsNameLen);
mbsName [mbsNameLen] = NULL;
for (DWORD i = 0; i < WBEMS_MAX_NUM_PRIVILEGE; i++)
{
if (0 == _mbsicmp ((unsigned char *)mbsName, (unsigned char *)(s_privilegeDefMap [i].tName)))
{
// Success
iPrivilege = s_privilegeDefMap [i].privilege;
status = true;
break;
}
}
delete [] mbsName;
#endif
}
return status;
}
//***************************************************************************
//
// CSWbemPrivilege::CSWbemPrivilege
//
// CONSTRUCTOR
//
//***************************************************************************
CSWbemPrivilege::CSWbemPrivilege (
WbemPrivilegeEnum iPrivilege,
LUID &luid,
bool bIsEnabled
)
{
m_Dispatch.SetObj (this, IID_ISWbemPrivilege,
CLSID_SWbemPrivilege, L"SWbemPrivilege");
m_cRef=1;
m_privilege = iPrivilege;
m_Luid = luid;
m_bIsEnabled = bIsEnabled;
InterlockedIncrement(&g_cObj);
}
//***************************************************************************
//
// CSWbemPrivilege::~CSWbemPrivilege
//
// DESTRUCTOR
//
//***************************************************************************
CSWbemPrivilege::~CSWbemPrivilege (void)
{
InterlockedDecrement(&g_cObj);
}
//***************************************************************************
// HRESULT CSWbemPrivilege::QueryInterface
// long CSWbemPrivilege::AddRef
// long CSWbemPrivilege::Release
//
// DESCRIPTION:
//
// Standard Com IUNKNOWN functions.
//
//***************************************************************************
STDMETHODIMP CSWbemPrivilege::QueryInterface (
IN REFIID riid,
OUT LPVOID *ppv
)
{
*ppv=NULL;
if (IID_IUnknown==riid)
*ppv = reinterpret_cast<IUnknown*>(this);
else if (IID_ISWbemPrivilege==riid)
*ppv = (ISWbemPrivilege *)this;
else if (IID_IDispatch==riid)
*ppv = (IDispatch *)this;
else if (IID_ISupportErrorInfo==riid)
*ppv = (ISupportErrorInfo *)this;
else if (IID_IProvideClassInfo==riid)
*ppv = (IProvideClassInfo *)this;
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CSWbemPrivilege::AddRef(void)
{
long l = InterlockedIncrement(&m_cRef);
return l;
}
STDMETHODIMP_(ULONG) CSWbemPrivilege::Release(void)
{
long l = InterlockedDecrement(&m_cRef);
if (0L!=l)
return l;
delete this;
return 0;
}
//***************************************************************************
// HRESULT CSWbemPrivilege::InterfaceSupportsErrorInfo
//
// DESCRIPTION:
//
// Standard Com ISupportErrorInfo functions.
//
//***************************************************************************
STDMETHODIMP CSWbemPrivilege::InterfaceSupportsErrorInfo (IN REFIID riid)
{
return (IID_ISWbemPrivilege == riid) ? S_OK : S_FALSE;
}
//***************************************************************************
//
// SCODE CSWbemPrivilege::get_Identifier
//
// DESCRIPTION:
//
// Retrieve the privilege identifier
//
// PARAMETERS:
//
// pIsEnabled holds the value on return
//
// RETURN VALUES:
//
// WBEM_S_NO_ERROR success
// WBEM_E_INVALID_PARAMETER bad input parameters
// WBEM_E_FAILED otherwise
//
//***************************************************************************
HRESULT CSWbemPrivilege::get_Identifier (
WbemPrivilegeEnum *pPrivilege
)
{
HRESULT hr = WBEM_E_FAILED;
if (NULL == pPrivilege)
hr = WBEM_E_INVALID_PARAMETER;
else
{
*pPrivilege = m_privilege;
hr = WBEM_S_NO_ERROR;
}
if (FAILED(hr))
m_Dispatch.RaiseException (hr);
return hr;
}
//***************************************************************************
//
// SCODE CSWbemPrivilege::get_IsEnabled
//
// DESCRIPTION:
//
// Retrieve the override state
//
// PARAMETERS:
//
// pIsEnabled holds the value on return
//
// RETURN VALUES:
//
// WBEM_S_NO_ERROR success
// WBEM_E_INVALID_PARAMETER bad input parameters
// WBEM_E_FAILED otherwise
//
//***************************************************************************
HRESULT CSWbemPrivilege::get_IsEnabled (
VARIANT_BOOL *pIsEnabled
)
{
HRESULT hr = WBEM_E_FAILED;
if (NULL == pIsEnabled)
hr = WBEM_E_INVALID_PARAMETER;
else
{
*pIsEnabled = (m_bIsEnabled) ? VARIANT_TRUE : VARIANT_FALSE;
hr = WBEM_S_NO_ERROR;
}
if (FAILED(hr))
m_Dispatch.RaiseException (hr);
return hr;
}
//***************************************************************************
//
// SCODE CSWbemPrivilege::put_IsEnabled
//
// DESCRIPTION:
//
// Set the override state
//
// PARAMETERS:
//
// bIsEnabled the new value
//
// RETURN VALUES:
//
// WBEM_S_NO_ERROR success
// WBEM_E_INVALID_PARAMETER bad input parameters
// WBEM_E_FAILED otherwise
//
//***************************************************************************
HRESULT CSWbemPrivilege::put_IsEnabled (
VARIANT_BOOL bIsEnabled
)
{
m_bIsEnabled = (bIsEnabled) ? true : false;
return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
// SCODE CSWbemPrivilege::get_Name
//
// DESCRIPTION:
//
// Retrieve the privilege name
//
// PARAMETERS:
//
// pName holds the value on return
//
// RETURN VALUES:
//
// WBEM_S_NO_ERROR success
// WBEM_E_INVALID_PARAMETER bad input parameters
// WBEM_E_FAILED otherwise
//
//***************************************************************************
HRESULT CSWbemPrivilege::get_Name (
BSTR *pName
)
{
HRESULT hr = WBEM_E_FAILED;
if (NULL == pName)
hr = WBEM_E_INVALID_PARAMETER;
else
{
TCHAR *tName = GetNameFromId (m_privilege);
if (tName)
{
// Have a valid name - now copy it to a BSTR
#ifdef _UNICODE
*pName = SysAllocString (tName);
#else
size_t tNameLen = strlen (tName);
OLECHAR *nameW = new OLECHAR [tNameLen + 1];
mbstowcs (nameW, tName, tNameLen);
nameW [tNameLen] = NULL;
*pName = SysAllocString (nameW);
delete [] nameW;
#endif
hr = WBEM_S_NO_ERROR;
}
}
if (FAILED(hr))
m_Dispatch.RaiseException (hr);
return hr;
}
//***************************************************************************
//
// SCODE CSWbemPrivilege::get_DisplayName
//
// DESCRIPTION:
//
// Retrieve the privilege display name
//
// PARAMETERS:
//
// pDisplayName holds the value on return
//
// RETURN VALUES:
//
// WBEM_S_NO_ERROR success
// WBEM_E_INVALID_PARAMETER bad input parameters
// WBEM_E_FAILED otherwise
//
//***************************************************************************
HRESULT CSWbemPrivilege::get_DisplayName (
BSTR *pDisplayName
)
{
HRESULT hr = WBEM_E_FAILED;
if (NULL == pDisplayName)
hr = WBEM_E_INVALID_PARAMETER;
else
{
TCHAR *tName = GetNameFromId (m_privilege);
if (tName)
{
if(SUCCEEDED(hr = GetPrivilegeDisplayName (tName, pDisplayName)))
hr = WBEM_S_NO_ERROR;
}
}
if (FAILED(hr))
m_Dispatch.RaiseException (hr);
return hr;
}
void CSWbemPrivilege::GetLUID (PLUID pLuid)
{
if (pLuid)
*pLuid = m_Luid;
}
//***************************************************************************
//
// SCODE CSWbemPrivilege::GetPrivilegeDisplayName
//
// DESCRIPTION:
//
// This static function wraps the Win32 LookupPrivilegeDisplayName function,
// allowing us to do some OS-dependent stuff.
//
// PARAMETERS:
//
// tName the privilege name
// pDisplayName holds the display name on successful return
//
//***************************************************************************
HRESULT CSWbemPrivilege::GetPrivilegeDisplayName (LPCTSTR lpName, BSTR *pDisplayName)
{
HRESULT hr = E_FAIL;
*pDisplayName = NULL;
// Can't return display name on Win9x (no privilege support)
if (s_bIsNT)
{
DWORD dwLangID;
DWORD dwSize = 1;
TCHAR dummy [1];
// Get size of required buffer
::LookupPrivilegeDisplayName (NULL, lpName, dummy, &dwSize, &dwLangID);
LPTSTR dname = new TCHAR[dwSize + 1];
if(dname)
{
if (::LookupPrivilegeDisplayName (__TEXT(""), lpName, dname, &dwSize, &dwLangID))
{
// Have a valid name - now copy it to a BSTR
if(!(*pDisplayName = SysAllocString (dname)))
hr = E_OUTOFMEMORY;
}
delete [] dname;
}
else
hr = E_OUTOFMEMORY;
}
else
{
if(!(*pDisplayName = SysAllocString (L"")))
hr = E_OUTOFMEMORY;
}
return hr;
}
//***************************************************************************
//
// SCODE CSWbemPrivilege::LookupPrivilegeValue
//
// DESCRIPTION:
//
// This static function wraps the Win32 LookupPrivilegeValue function,
// allowing us to do some OS-dependent stuff.
//
// PARAMETERS:
//
// lpName the privilege name
// lpLuid holds the LUID on successful return
//
// RETURN VALUES:
//
// true On NT this means we found the privilege. On Win9x we
// always return this.
//
// false On NT this means the privilege is not recognized. This
// is never returned on Win9x.
//
//***************************************************************************
BOOL CSWbemPrivilege::GetPrivilegeValue (
LPCTSTR lpName,
PLUID lpLuid
)
{
// Allows any name to map to 0 LUID on Win9x - this aids script portability
if (s_bIsNT)
return ::LookupPrivilegeValue(NULL, lpName, lpLuid);
else
return true;
}
//***************************************************************************
//
// SCODE CSWbemPrivilege::SetSecurity
//
// DESCRIPTION:
//
// Set Privileges on the Thread Token.
//
//***************************************************************************
BOOL CSWbemPrivilege::SetSecurity (
CSWbemPrivilegeSet *pProvilegeSet,
bool &needToResetSecurity,
bool bUsingExplicitUserName,
HANDLE &hThreadToken
)
{
BOOL result = TRUE; // Default is success
DWORD lastErr = 0;
hThreadToken = NULL; // Default assume we'll modify process token
needToResetSecurity = false; // Default assume we changed no privileges
// Win9x has no security support
if (s_bIsNT)
{
// Start by checking whether we are being impersonated. On an NT4
// box (which has no cloaking, and therefore cannot allow us to
// pass on this impersonation to Winmgmt) we should RevertToSelf
// if we have been configured to allow this. If we haven't been
// configured to allow this, bail out now.
if (4 >= s_dwNTMajorVersion)
{
if (OpenThreadToken (GetCurrentThread (), TOKEN_QUERY|TOKEN_IMPERSONATE, true, &hThreadToken))
{
// We are being impersonated
if (s_bCanRevert)
{
if (result = RevertToSelf())
needToResetSecurity = true;
}
else
{
// Error - cannot do this! Time to bail out
CloseHandle (hThreadToken);
hThreadToken = NULL;
result = FALSE;
}
}
}
if (result)
{
// Now we check if we need to set privileges
/*
* Specifying a user only makes sense for remote operations, and we
* don't need to mess with privilege for remote operations since
* they are set up by server logon anyway.
*/
if (!bUsingExplicitUserName)
{
// Nothing to do unless some privilege overrides have been set
long lCount = 0;
pProvilegeSet->get_Count (&lCount);
if (0 < lCount)
{
if (4 < s_dwNTMajorVersion)
{
/*
* On NT5 we try to open the Thread token. If the client app
* is calling into us on an impersonated thread (as IIS may be,
* for example), this will succeed. Otherwise, we use the process token
*/
HANDLE hToken;
SECURITY_IMPERSONATION_LEVEL secImpLevel = SecurityImpersonation;
if (!(result = OpenThreadToken (GetCurrentThread (), TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_IMPERSONATE, true, &hToken)))
{
// No thread token - go for the Process token instead
HANDLE hProcess = GetCurrentProcess ();
result = OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE, &hToken);
CloseHandle (hProcess);
}
else
{
// We are working with a thread token
hThreadToken = hToken;
// Try and get the impersonation level of this token
DWORD dwReturnLength = 0;
BOOL thisRes = GetTokenInformation (hToken, TokenImpersonationLevel, &secImpLevel,
sizeof (SECURITY_IMPERSONATION_LEVEL), &dwReturnLength);
}
if (result)
{
/*
* Getting here means we have a valid token, be it process or thread. We
* now attempt to duplicate it before Adjusting the Privileges.
*/
HANDLE hDupToken;
result = DuplicateTokenEx (hToken, TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE, NULL,
secImpLevel, TokenImpersonation, &hDupToken);
if (result)
{
SetTokenPrivileges (hDupToken, pProvilegeSet);
// Now use this token on the current thread
if (SetThreadToken(NULL, hDupToken))
needToResetSecurity = true;
CloseHandle (hDupToken);
}
else
{
lastErr = GetLastError ();
}
/*
* If we are not using a thread token, close the token now. Otherwise
* the handle will be closed in the balanced call to RestorePrivileges ().
*/
if (!hThreadToken)
CloseHandle (hToken);
}
}
else
{
// For NT4 we adjust the privileges in the process token
HANDLE hProcessToken = NULL;
HANDLE hProcess = GetCurrentProcess ();
result = OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hProcessToken);
CloseHandle (hProcess);
// Adjust privilege on the process
if (result)
{
SetTokenPrivileges (hProcessToken, pProvilegeSet);
CloseHandle (hProcessToken);
}
}
}
}
}
}
return result;
}
//***************************************************************************
//
// SCODE CEnumPrivilegeSet::ResetSecurity
//
// DESCRIPTION:
//
// Restore Privileges on the Thread Token.
//
//***************************************************************************
void CSWbemPrivilege::ResetSecurity (
HANDLE hThreadToken
)
{
// Win9x has no security palaver
if (s_bIsNT)
{
/*
* Set the supplied token (which may be NULL) into
* the current thread.
*/
BOOL result = SetThreadToken (NULL, hThreadToken);
DWORD error = 0;
if (!result)
error = GetLastError ();
if (hThreadToken)
CloseHandle (hThreadToken);
}
}
//***************************************************************************
//
// CSWbemPrivilege::SetTokenPrivileges
//
// DESCRIPTION:
//
// Adjust the Privileges on the specified token without allowing a future
// restore of the current settings..
//
// PARAMETERS:
//
// hHandle Handle of the token on which to adjust privileges
// pPrivilegeSet Specified privilege adjustments
//
// RETURN VALUES:
// none
//***************************************************************************
void CSWbemPrivilege::SetTokenPrivileges (
HANDLE hHandle,
CSWbemPrivilegeSet *pPrivilegeSet
)
{
DWORD lastErr = 0;
if (pPrivilegeSet)
{
pPrivilegeSet->AddRef ();
long lNumPrivileges = 0;
pPrivilegeSet->get_Count (&lNumPrivileges);
if (lNumPrivileges)
{
DWORD dwPrivilegeIndex = 0;
/*
* Set up the token privileges array. Note that some jiggery-pokery
* is required here because the Privileges field is an [ANYSIZE_ARRAY]
* type.
*/
TOKEN_PRIVILEGES *pTokenPrivileges = (TOKEN_PRIVILEGES *)
new BYTE [sizeof(TOKEN_PRIVILEGES) + (lNumPrivileges * sizeof (LUID_AND_ATTRIBUTES [1]))];
// Get the iterator
PrivilegeMap::iterator next = pPrivilegeSet->m_PrivilegeMap.begin ();
while (next != pPrivilegeSet->m_PrivilegeMap.end ())
{
CSWbemPrivilege *pPrivilege = (*next).second;
pPrivilege->AddRef ();
LUID luid;
pPrivilege->GetLUID (&luid);
VARIANT_BOOL vBool;
pPrivilege->get_IsEnabled (&vBool);
pTokenPrivileges->Privileges [dwPrivilegeIndex].Luid = luid;
/*
* Note that any setting other than SE_PRIVILEGE_ENABLED
* is interpreted by AdjustTokenPrivileges as a DISABLE
* request for that Privilege.
*/
pTokenPrivileges->Privileges [dwPrivilegeIndex].Attributes
= (VARIANT_TRUE == vBool) ?
SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_ENABLED_BY_DEFAULT;
dwPrivilegeIndex++;
pPrivilege->Release ();
next++;
}
// Now we should have recorded the number of privileges that were OK
if (0 < dwPrivilegeIndex)
{
pTokenPrivileges->PrivilegeCount = dwPrivilegeIndex;
BOOL result = ::AdjustTokenPrivileges (hHandle, FALSE, pTokenPrivileges, 0, NULL, NULL);
lastErr = GetLastError ();
}
delete [] pTokenPrivileges;
}
pPrivilegeSet->Release ();
}
}