windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/ess3/tkncache.cpp

401 lines
10 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//******************************************************************************
//
// Copyright (c) 1999-2000, Microsoft Corporation, All rights reserved
//
//*****************************************************************************
#include "precomp.h"
#include <stdio.h>
#include <wbemcomn.h>
#include <tkncache.h>
#include <groupsforuser.h>
#include <selfinst.h>
#include <tchar.h>
CWmiToken::CWmiToken(ADDREF CTokenCache* pCache, const PSID pSid,
ACQUIRE HANDLE hToken) :
CUnkBase<IWbemToken, &IID_IWbemToken>(NULL), m_hToken(hToken),
m_pCache(pCache), m_pSid(NULL), m_bOwnHandle(true)
{
if(m_pCache)
m_pCache->AddRef();
if(pSid)
{
m_pSid = (PSID)new BYTE[GetLengthSid(pSid)];
if(m_pSid == NULL)
return;
CopySid(GetLengthSid(pSid), m_pSid, pSid);
}
}
CWmiToken::CWmiToken(READ_ONLY HANDLE hToken) :
CUnkBase<IWbemToken, &IID_IWbemToken>(NULL), m_hToken(hToken),
m_pCache(NULL), m_pSid(NULL), m_bOwnHandle(false)
{
}
CWmiToken::~CWmiToken()
{
if(m_pCache)
m_pCache->Release();
if(m_bOwnHandle)
CloseHandle(m_hToken);
delete [] (BYTE*)m_pSid;
}
STDMETHODIMP CWmiToken::AccessCheck(DWORD dwDesiredAccess, const BYTE* pSD,
DWORD* pdwGrantedAccess)
{
if(m_hToken == NULL)
return WBEM_E_CRITICAL_ERROR;
// BUGBUG: figure out what this is for!
GENERIC_MAPPING map;
map.GenericRead = 1;
map.GenericWrite = 0x1C;
map.GenericExecute = 2;
map.GenericAll = 0x6001f;
PRIVILEGE_SET ps;
DWORD dwPrivLength = sizeof(ps);
BOOL bStatus;
BOOL bRes = ::AccessCheck((SECURITY_DESCRIPTOR*)pSD, m_hToken,
dwDesiredAccess, &map, &ps,
&dwPrivLength, pdwGrantedAccess, &bStatus);
if(!bRes)
{
return WBEM_E_ACCESS_DENIED;
}
else
{
return WBEM_S_NO_ERROR;
}
}
#ifdef __NOAUTHZ_
typedef NTSTATUS (NTAPI *PNtCreateToken)(
OUT PHANDLE TokenHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN TOKEN_TYPE TokenType,
IN PLUID AuthenticationId,
IN PLARGE_INTEGER ExpirationTime,
IN PTOKEN_USER User,
IN PTOKEN_GROUPS Groups,
IN PTOKEN_PRIVILEGES Privileges,
IN PTOKEN_OWNER Owner OPTIONAL,
IN PTOKEN_PRIMARY_GROUP PrimaryGroup,
IN PTOKEN_DEFAULT_DACL DefaultDacl OPTIONAL,
IN PTOKEN_SOURCE TokenSource
);
void EnableAllPrivileges()
{
BOOL bRes;
HANDLE hToken = NULL;
bRes = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, FALSE, &hToken);
// Get the privileges
// ==================
DWORD dwLen;
TOKEN_USER tu;
memset(&tu,0,sizeof(TOKEN_USER));
bRes = GetTokenInformation(hToken, TokenPrivileges, &tu, sizeof(TOKEN_USER), &dwLen);
BYTE* pBuffer = new BYTE[dwLen];
if(pBuffer == NULL)
{
CloseHandle(hToken);
return ;
}
bRes = GetTokenInformation(hToken, TokenPrivileges, pBuffer, dwLen,
&dwLen);
if(!bRes)
{
CloseHandle(hToken);
delete [] pBuffer;
return ;
}
// Iterate through all the privileges and enable them all
// ======================================================
TOKEN_PRIVILEGES* pPrivs = (TOKEN_PRIVILEGES*)pBuffer;
for(DWORD i = 0; i < pPrivs->PrivilegeCount; i++)
{
pPrivs->Privileges[i].Attributes |= SE_PRIVILEGE_ENABLED;
TCHAR szBuffer[256];
DWORD dwLen = 256;
LookupPrivilegeName(NULL, &pPrivs->Privileges[i].Luid, szBuffer, &dwLen);
}
// Store the information back into the token
// =========================================
bRes = AdjustTokenPrivileges(hToken, FALSE, pPrivs, 0, NULL, NULL);
delete [] pBuffer;
CloseHandle(hToken);
}
BOOL CTokenCache::ConstructTokenFromHandle(HANDLE hToken, const BYTE* pSid,
IWbemToken** ppToken)
{
BOOL bRes;
//
// Retrieve the user sid from the token given to us
//
DWORD dwSidLen = 0;
bRes = GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSidLen);
if(dwSidLen == 0)
return FALSE;
TOKEN_USER* pUser = (TOKEN_USER*)new BYTE[dwSidLen];
if(pUser == NULL)
return FALSE;
CVectorDeleteMe<BYTE> vdm1((BYTE*)pUser);
bRes = GetTokenInformation(hToken, TokenUser, pUser, dwSidLen, &dwSidLen);
if(!bRes)
return FALSE;
//
// Compare to the required SID --- must match for success
//
if(!EqualSid((PSID)pSid, pUser->User.Sid))
return FALSE;
//
// Construct an IWbemToken object to return.
//
CWmiToken* pNewToken = new CWmiToken(this, (const PSID)pSid, hToken);
if(pNewToken == NULL)
return FALSE;
pNewToken->QueryInterface(IID_IWbemToken, (void**)ppToken);
return TRUE;
}
HRESULT STDMETHODCALLTYPE CTokenCache::GetToken(const BYTE* pSid,
IWbemToken** ppToken)
{
//
// Search for the SID in the array
//
{
CInCritSec ics(&m_cs);
DWORD dwLen = GetLengthSid((const PSID)pSid);
for(int i = 0; i < m_apTokens.GetSize(); i++)
{
CWmiToken* pToken = m_apTokens[i];
if(EqualSid(pToken->m_pSid, (const PSID)pSid))
{
// Found it!
*ppToken = pToken;
pToken->AddRef();
return S_OK;
}
}
}
//
// Not there. Examine the currently available tokens to see if they match.
// Note that we are not going to cache them if found --- we do not want to
// hold on to normally available tokens after the user logs off.
//
BOOL bRes;
HRESULT hres;
// Thread token first
HANDLE hThreadToken = NULL;
bRes = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,
&hThreadToken);
if(bRes)
{
CCloseMe cm(hThreadToken);
if(ConstructTokenFromHandle(hThreadToken, pSid, ppToken))
return WBEM_S_NO_ERROR;
}
// Process token next
RevertToSelf();
HANDLE hProcessToken = NULL;
bRes = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken);
if(bRes)
{
CCloseMe cm(hProcessToken);
if(ConstructTokenFromHandle(hProcessToken, pSid, ppToken))
return WBEM_S_NO_ERROR;
}
// COM impersonation last
hres = CoImpersonateClient();
if(SUCCEEDED(hres))
{
bRes = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,
&hThreadToken);
CoRevertToSelf();
if(bRes)
{
CCloseMe cm(hThreadToken);
if(ConstructTokenFromHandle(hThreadToken, pSid, ppToken))
return WBEM_S_NO_ERROR;
}
}
//
//
// No standard token matched --- we are going to have to construct our own
// token. Get the DC to enumerate all the SIDs for this user
//
PSID* aGroupSids = NULL;
DWORD dwSidCount = 0;
try
{
NTSTATUS ntst = EnumGroupsForUser((const PSID)pSid, NULL, &aGroupSids,
&dwSidCount);
if(ntst != STATUS_SUCCESS)
{
WMI_REPORT((WMI_CANNOT_GET_USER_GROUPS, pSid));
//
// Continue --- even though we don't have all the groups, we might be
// able to get there
//
}
//
// Get the NtCreateToken entry point in NTDLL
//
ImpersonateSelf(SecurityImpersonation);
EnableAllPrivileges();
HINSTANCE hInst = LoadLibrary(_TEXT("ntdll.dll"));
PNtCreateToken pNtCreateToken = (PNtCreateToken)GetProcAddress(hInst, "NtCreateToken");
FreeLibrary(hInst);
//
// Prepare the paramters for NtCreateToken
//
HANDLE hHandle;
LUID luidAuth = SYSTEM_LUID;
LARGE_INTEGER exp;
exp.QuadPart = 0;
TOKEN_USER User;
User.User.Sid = (const PSID)pSid;
User.User.Attributes = 0;
//
// Allocate a TOKEN_GROUPS large enough for all the SIDs
//
TOKEN_GROUPS* pGroups = (TOKEN_GROUPS*)
new BYTE[sizeof(TOKEN_GROUPS) + dwSidCount* sizeof(SID_AND_ATTRIBUTES)];
if(pGroups == NULL)
return WBEM_E_OUT_OF_MEMORY;
CVectorDeleteMe<BYTE> vdm((BYTE*)pGroups);
pGroups->GroupCount = dwSidCount;
for(DWORD i = 0; i < dwSidCount; i++)
{
pGroups->Groups[i].Sid = aGroupSids[i];
pGroups->Groups[i].Attributes = 0;
}
TOKEN_PRIVILEGES Privs;
Privs.PrivilegeCount = 0;
TOKEN_PRIMARY_GROUP Prim;
if(dwSidCount > 0)
Prim.PrimaryGroup = aGroupSids[0];
else
Prim.PrimaryGroup = (const PSID)pSid;
TOKEN_SOURCE Source;
strcpy(Source.SourceName, "me");
Source.SourceIdentifier.HighPart = 0;
Source.SourceIdentifier.LowPart = 0;
NTSTATUS st = (*pNtCreateToken)(
&hHandle,
TOKEN_ALL_ACCESS,
NULL, // attr
TokenPrimary,
&luidAuth,
&exp,
&User,
pGroups,
&Privs,
NULL, // owner
&Prim,
NULL, // dacl
&Source);
if(st != STATUS_SUCCESS)
{
WMI_REPORT((WMI_CANNOT_CREATE_TOKEN, pSid, st));
return WBEM_E_FAILED;
}
//
// Construct a new CWmiToken object and add it to the list
//
{
CInCritSec ics(&m_cs);
CWmiToken* pNewToken = new CWmiToken(this, (const PSID) pSid, hHandle);
if(pNewToken == NULL)
return WBEM_E_OUT_OF_MEMORY;
m_apTokens.Add(pNewToken);
return pNewToken->QueryInterface(IID_IWbemToken, (void**)ppToken);
}
}
catch(...)
{
RevertToSelf();
if(aGroupSids)
{
for(DWORD i = 0; i < dwSidCount; i++)
delete [] aGroupSids[i];
delete [] aGroupSids;
}
throw;
}
}
HRESULT STDMETHODCALLTYPE CTokenCache::Shutdown()
{
m_apTokens.RemoveAll();
return WBEM_S_NO_ERROR;
}
#endif // __NOAUTHZ_