//****************************************************************************** // // Copyright (c) 1999-2000, Microsoft Corporation, All rights reserved // //***************************************************************************** #include "precomp.h" #include #include #include #include #include #include CWmiToken::CWmiToken(ADDREF CTokenCache* pCache, const PSID pSid, ACQUIRE HANDLE hToken) : CUnkBase(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(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 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 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_