|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: sidcache.cpp
//
// This file contains the implementation of a SID/Name cache.
//
//--------------------------------------------------------------------------
#include "aclpriv.h"
#include <dsgetdc.h> // DsGetDcName
#include <iads.h>
#define SECURITY_WIN32
#include <security.h> // TranslateName
#include <lm.h> // NetApiBufferFree
#include <shlwapi.h> // StrChr, StrRChr
// 10 minutes
#define SID_CACHE_AGE_LIMIT (10*60*1000)
TCHAR const c_szNTProvider[] = TEXT("WinNT://"); #define NTPROV_LEN (ARRAYSIZE(c_szNTProvider)-1)
#define ACLUI_ALIGNED_SID_LENGTH(p) ((PtrAlignSize(RtlLengthSid((p)))))
PSIDCACHE g_pSidCache = NULL;
PSIDCACHE GetSidCache() { if (NULL == g_pSidCache) { // The cache starts with an extra ref here that will be released
// during our DLL_PROCESS_DETACH
g_pSidCache = new CSidCache;
if (g_pSidCache) { g_pSidCache->AddRef(); } } else { g_pSidCache->AddRef(); }
return g_pSidCache; }
void FreeSidCache() { if (g_pSidCache) { g_pSidCache->Release(); g_pSidCache = NULL; } }
//
// CSidCache implementation
//
CSidCache::CSidCache() : m_pszCachedServer(NULL), m_pszCachedDomain(NULL), m_hInitThread(NULL), m_pszLastDc(NULL), m_pszLastDomain(NULL), m_cRef(1) { HINSTANCE hInstThisDll; DWORD dwThreadID;
ZeroMemory(m_dpaSidHashTable, SIZEOF(m_dpaSidHashTable)); ExceptionPropagatingInitializeCriticalSection(&m_csHashTableLock); ExceptionPropagatingInitializeCriticalSection(&m_csDomainNameLock); ExceptionPropagatingInitializeCriticalSection(&m_csDcNameLock);
// Give the thread we are about to create a ref to the dll,
// so that the dll will remain for the lifetime of the thread
hInstThisDll = LoadLibrary(c_szDllName); if (hInstThisDll != NULL) { // also do an AddRef() for the worker thread to release later
AddRef();
// Start a thread to cache the well-known and built-in SIDs
m_hInitThread = CreateThread(NULL, 0, InitThread, this, 0, &dwThreadID);
if (!m_hInitThread) { // Failed to create the thread, do cleanup
FreeLibrary(hInstThisDll); Release(); } } }
ULONG CSidCache::AddRef() { return InterlockedIncrement(&m_cRef); }
ULONG CSidCache::Release() { ASSERT( 0 != m_cRef ); ULONG cRef = InterlockedDecrement(&m_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
CSidCache::~CSidCache() { int i;
TraceEnter(TRACE_SIDCACHE, "CSidCache::~CSidCache");
Lock(); for (i = 0; i < BUCKET_COUNT; i++) { DestroyDPA(m_dpaSidHashTable[i]); m_dpaSidHashTable[i] = NULL; } Unlock();
LockDomain(); LocalFreeString(&m_pszCachedServer); LocalFreeString(&m_pszCachedDomain); UnlockDomain();
LockDc(); LocalFreeString(&m_pszLastDc); LocalFreeString(&m_pszLastDomain); UnlockDc();
DeleteCriticalSection(&m_csHashTableLock); DeleteCriticalSection(&m_csDomainNameLock); DeleteCriticalSection(&m_csDcNameLock);
if (m_hInitThread != NULL) { CloseHandle(m_hInitThread); }
TraceLeaveVoid(); }
BOOL CSidCache::LookupSids(HDPA hSids, LPCTSTR pszServer, LPSECURITYINFO2 psi2, PUSER_LIST *ppUserList) { BOOL fResult = FALSE;
TraceEnter(TRACE_SIDCACHE, "CSidCache::LookupSids"); TraceAssert(hSids != NULL);
if (NULL == hSids) { SetLastError(ERROR_INVALID_PARAMETER); TraceLeaveValue(FALSE); }
if (NULL != ppUserList) *ppUserList = NULL;
if (0 != DPA_GetPtrCount(hSids)) { HDPA hEntryList = DPA_Create(4);
if (NULL == hEntryList) TraceLeaveValue(FALSE);
InternalLookupSids(hSids, pszServer, psi2, hEntryList);
if (0 != DPA_GetPtrCount(hEntryList) && NULL != ppUserList) fResult = BuildUserList(hEntryList, pszServer, ppUserList);
DPA_Destroy(hEntryList); }
TraceLeaveValue(fResult); }
BOOL CSidCache::LookupSidsAsync(HDPA hSids, LPCTSTR pszServer, LPSECURITYINFO2 psi2, HWND hWndNotify, UINT uMsgNotify) { BOOL fResult = FALSE;
TraceEnter(TRACE_SIDCACHE, "CSidCache::LookupSids"); TraceAssert(hSids != NULL);
if (NULL == hSids) { SetLastError(ERROR_INVALID_PARAMETER); TraceLeaveValue(FALSE); }
if (0 != DPA_GetPtrCount(hSids)) { fResult = InternalLookupSids(hSids, pszServer, psi2, NULL, hWndNotify, uMsgNotify); }
TraceLeaveValue(fResult); }
BOOL CSidCache::LookupNames(PDS_SELECTION_LIST pDsSelList, LPCTSTR pszServer, PUSER_LIST *ppUserList, BOOL bStandalone) { BOOL fResult = FALSE; HDPA hEntryList;
TraceEnter(TRACE_SIDCACHE, "CSidCache::LookupNames"); TraceAssert(pDsSelList != NULL); TraceAssert(ppUserList != NULL);
if (NULL == pDsSelList) { SetLastError(ERROR_INVALID_PARAMETER); TraceLeaveValue(FALSE); }
if (NULL != ppUserList) *ppUserList = NULL;
hEntryList = DPA_Create(4);
if (NULL == hEntryList) TraceLeaveValue(FALSE);
InternalLookupNames(pDsSelList, pszServer, hEntryList, bStandalone);
if (0 != DPA_GetPtrCount(hEntryList)) { fResult = TRUE; // so far, so good
if (NULL != ppUserList) fResult = BuildUserList(hEntryList, pszServer, ppUserList); }
DPA_Destroy(hEntryList);
TraceLeaveValue(fResult); }
void CSidCache::GetDomainName(LPCTSTR pszServer, LPTSTR pszDomain, ULONG cchDomain) { TraceEnter(TRACE_SIDCACHE, "CSidCache::GetDomainName"); TraceAssert(NULL != pszDomain); TraceAssert(0 != cchDomain);
pszDomain[0] = TEXT('\0');
LockDomain();
if (m_pszCachedDomain == NULL || (pszServer == NULL && m_pszCachedServer != NULL) || (pszServer != NULL && (m_pszCachedServer == NULL || CompareString(LOCALE_USER_DEFAULT, 0, pszServer, -1, m_pszCachedServer, -1) != CSTR_EQUAL))) { //
// It's a different server than last time, so ask LSA
// for the domain name.
//
LocalFreeString(&m_pszCachedDomain); LocalFreeString(&m_pszCachedServer);
if (pszServer != NULL) LocalAllocString(&m_pszCachedServer, pszServer);
LSA_HANDLE hLSA = GetLSAConnection(pszServer, POLICY_VIEW_LOCAL_INFORMATION); if (hLSA != NULL) { PPOLICY_ACCOUNT_DOMAIN_INFO pDomainInfo = NULL;
LsaQueryInformationPolicy(hLSA, PolicyAccountDomainInformation, (PVOID*)&pDomainInfo); if (pDomainInfo != NULL) { CopyUnicodeString(&m_pszCachedDomain, &pDomainInfo->DomainName); LsaFreeMemory(pDomainInfo);
Trace((TEXT("Domain for %s is %s"), pszServer, m_pszCachedDomain)); } LsaClose(hLSA); } else if (NULL != pszServer) // use the server name
{ // Skip leading backslashes
while (TEXT('\\') == *pszServer) pszServer++;
LocalAllocString(&m_pszCachedDomain, pszServer);
if (m_pszCachedDomain) { // If there is a period, truncate the name at that point so
// that something like "nttest.microsoft.com" becomes "nttest"
LPTSTR pszDot = StrChr(m_pszCachedDomain, TEXT('.')); if (pszDot) *pszDot = TEXT('\0'); } } }
if (m_pszCachedDomain) lstrcpyn(pszDomain, m_pszCachedDomain, cchDomain);
UnlockDomain();
TraceLeaveVoid(); }
DWORD _GetDcName(LPCTSTR pszServer, LPCTSTR pszDomain, LPTSTR *ppszDC) { DWORD dwErr;
if (!ppszDC) return ERROR_INVALID_PARAMETER;
*ppszDC = NULL;
PDOMAIN_CONTROLLER_INFO pDCInfo = NULL; TraceMsg("Calling DsGetDcName"); dwErr = DsGetDcName(pszServer, pszDomain, NULL, NULL, DS_IS_FLAT_NAME, &pDCInfo); if (ERROR_SUCCESS == dwErr) { TraceAssert(NULL != pDCInfo); LocalAllocString(ppszDC, pDCInfo->DomainControllerName); NetApiBufferFree(pDCInfo); }
if (ERROR_SUCCESS == dwErr && !*ppszDC) dwErr = ERROR_OUTOFMEMORY;
return dwErr; }
void CSidCache::GetDcName(LPCTSTR pszDomain, LPTSTR pszDC, ULONG cchDC) { TraceEnter(TRACE_SIDCACHE, "CSidCache::GetDcName"); TraceAssert(NULL != pszDC); TraceAssert(0 != cchDC);
pszDC[0] = TEXT('\0');
LockDc();
if (m_pszLastDc == NULL || (pszDomain == NULL && m_pszLastDomain != NULL) || (pszDomain != NULL && (m_pszLastDomain == NULL || CompareString(LOCALE_USER_DEFAULT, 0, pszDomain, -1, m_pszLastDomain, -1) != CSTR_EQUAL))) { //
// It's a different domain than last time, so look for a DC
//
LocalFreeString(&m_pszLastDc); LocalFreeString(&m_pszLastDomain);
if (pszDomain != NULL) LocalAllocString(&m_pszLastDomain, pszDomain);
_GetDcName(NULL, pszDomain, &m_pszLastDc);
Trace((TEXT("DC for %s is %s"), pszDomain, m_pszLastDc)); }
if (m_pszLastDc) lstrcpyn(pszDC, m_pszLastDc, cchDC);
UnlockDc();
TraceLeaveVoid(); }
BSTR CSidCache::GetNT4DisplayName(LPCTSTR pszAccount, LPCTSTR pszName, LPCTSTR pszServer, BOOL bStandalone) { BSTR strResult = NULL; TCHAR szComputer[UNCLEN]; LPTSTR pszT = NULL; PUSER_INFO_2 pui = NULL;
if (!pszAccount || !*pszAccount || !pszName || !*pszName) return NULL;
TraceEnter(TRACE_SIDCACHE, "CSidCache::GetNT4DisplayName");
if (!bStandalone && (pszT = StrChr(pszAccount, TEXT('\\')))) { // Copy the domain name
TCHAR szDomain[DNLEN + 1]; lstrcpyn(szDomain, pszAccount, min((size_t)(pszT - pszAccount + 1), ARRAYSIZE(szDomain)));
// See if we can use pszServer for NetUserGetInfo
TCHAR szAccountDomain[DNLEN +1]; szAccountDomain[0] = TEXT('\0'); GetDomainName(pszServer, szAccountDomain, ARRAYSIZE(szAccountDomain));
if (lstrcmpi(szDomain, szAccountDomain)) { // Different domain, find a DC
szComputer[0] = TEXT('\0'); GetDcName(szDomain, szComputer, ARRAYSIZE(szComputer)); if (TEXT('\0') != szComputer[0]) pszServer = szComputer; } }
TraceMsg("Calling NetUserGetInfo"); if (NERR_Success == NetUserGetInfo(pszServer, pszName, 2, (LPBYTE *)&pui) && NULL != pui->usri2_full_name && *pui->usri2_full_name) { strResult = SysAllocString(pui->usri2_full_name); }
NetApiBufferFree(pui);
Trace((TEXT("Returning Full Name '%s' for '%s'"), strResult, pszAccount)); TraceLeaveValue(strResult); }
int CSidCache::HashSid(PSID pSid) { DWORD dwHash = 0;
if (NULL != pSid) { PBYTE pbSid = (PBYTE)pSid; PBYTE pbEndSid = pbSid + GetLengthSid(pSid);
while (pbSid < pbEndSid) dwHash += *pbSid++; }
return dwHash % BUCKET_COUNT; }
int CALLBACK CSidCache::CompareSid(LPVOID p1, LPVOID p2, LPARAM lParam) { int nResult = 0; PSID_CACHE_ENTRY pEntry1 = (PSID_CACHE_ENTRY)p1; PSID_CACHE_ENTRY pEntry2 = (PSID_CACHE_ENTRY)p2; PSID pSid1 = NULL; PSID pSid2 = NULL;
if (pEntry1) pSid1 = pEntry1->pSid; else if (lParam) pSid1 = (PSID)lParam;
if (pEntry2) pSid2 = pEntry2->pSid;
if (pSid1 == NULL) nResult = -1; else if (pSid2 == NULL) nResult = 1; else { DWORD dwLength = GetLengthSid(pSid1);
// Compare SID lengths
nResult = dwLength - GetLengthSid(pSid2);
if (nResult == 0) { // Lengths are equal, compare the bits
PBYTE pbSid1 = (PBYTE)pSid1; PBYTE pbSid2 = (PBYTE)pSid2;
// Could compare Identifier Authorities and SubAuthorities instead
while (nResult == 0 && dwLength != 0) { dwLength--; nResult = *pbSid1++ - *pbSid2++; } } }
return nResult; }
PSID_CACHE_ENTRY CSidCache::FindSid(PSID pSid) { PSID_CACHE_ENTRY pEntry = NULL; int iBucket;
TraceEnter(TRACE_SIDCACHE, "CSidCache::FindSid"); TraceAssert(pSid != NULL); TraceAssert(IsValidSid(pSid));
iBucket = HashSid(pSid);
Lock();
if (m_dpaSidHashTable[iBucket] != NULL) { int iEntry = DPA_Search(m_dpaSidHashTable[iBucket], NULL, 0, CompareSid, (LPARAM)pSid, DPAS_SORTED); if (iEntry != -1) { pEntry = (PSID_CACHE_ENTRY)DPA_FastGetPtr(m_dpaSidHashTable[iBucket], iEntry); TraceAssert(pEntry != NULL); TraceAssert(EqualSid(pSid, pEntry->pSid));
if (0 != pEntry->dwLastAccessTime) { DWORD dwCurrentTime = GetTickCount();
if ((dwCurrentTime - pEntry->dwLastAccessTime) > SID_CACHE_AGE_LIMIT) { // The entry has aged out, remove it.
Trace((TEXT("Removing stale entry: %s"), pEntry->pszName)); DPA_DeletePtr(m_dpaSidHashTable[iBucket], iEntry); LocalFree(pEntry); pEntry = NULL; } else pEntry->dwLastAccessTime = dwCurrentTime; } } }
Unlock();
TraceLeaveValue(pEntry); }
PSID_CACHE_ENTRY CSidCache::MakeEntry(PSID pSid, SID_NAME_USE SidType, LPCTSTR pszName, LPCTSTR pszLogonName) { PSID_CACHE_ENTRY pEntry = NULL; ULONG cbSid; ULONG cbName = 0; ULONG cbLogonName = 0;
TraceEnter(TRACE_SIDCACHE, "CSidCache::MakeEntry"); TraceAssert(pSid != NULL);
cbSid = GetLengthSid(pSid); if (NULL != pszName && *pszName) cbName = StringByteSize(pszName); if (NULL != pszLogonName && *pszLogonName) cbLogonName = StringByteSize(pszLogonName);
pEntry = (PSID_CACHE_ENTRY)LocalAlloc(LPTR, SIZEOF(SID_CACHE_ENTRY) + cbSid + cbName + cbLogonName); if (pEntry != NULL) { PBYTE pData = (PBYTE)(pEntry+1);
pEntry->SidType = SidType;
pEntry->pSid = (PSID)pData; CopyMemory(pData, pSid, cbSid); pData += cbSid;
if (0 != cbName) { pEntry->pszName = (LPCTSTR)pData; CopyMemory(pData, pszName, cbName); pData += cbName; }
if (0 != cbLogonName) { pEntry->pszLogonName = (LPCTSTR)pData; CopyMemory(pData, pszLogonName, cbLogonName); //pData += cbLogonName;
}
// Well-known entries never age out
if (SidTypeWellKnownGroup == SidType || IsAliasSid(pSid)) pEntry->dwLastAccessTime = 0; else pEntry->dwLastAccessTime = GetTickCount(); }
TraceLeaveValue(pEntry); }
BOOL CSidCache::AddEntry(PSID_CACHE_ENTRY pEntry) { BOOL fResult = FALSE; int iSidBucket;
TraceEnter(TRACE_SIDCACHE, "CSidCache::AddEntry"); TraceAssert(pEntry != NULL);
if (NULL == pEntry) TraceLeaveValue(FALSE);
iSidBucket = HashSid(pEntry->pSid);
Lock();
if (m_dpaSidHashTable[iSidBucket] == NULL) m_dpaSidHashTable[iSidBucket] = DPA_Create(4);
if (NULL != m_dpaSidHashTable[iSidBucket]) { DPA_AppendPtr(m_dpaSidHashTable[iSidBucket], pEntry); DPA_Sort(m_dpaSidHashTable[iSidBucket], CompareSid, 0); fResult = TRUE; }
Unlock();
TraceLeaveValue(fResult); }
BOOL CSidCache::BuildUserList(HDPA hEntryList, LPCTSTR pszServer, PUSER_LIST *ppUserList) { ULONG cEntries; TCHAR szAliasDomain[MAX_PATH]; PSID_CACHE_ENTRY pEntry; ULONG cb = 0; ULONG cSidsLen = 0; ULONG cbAliasDomain = 0; ULONG i;
TraceEnter(TRACE_SIDCACHE, "CSidCache::BuildUserList"); TraceAssert(hEntryList != NULL); TraceAssert(ppUserList != NULL);
cEntries = DPA_GetPtrCount(hEntryList); TraceAssert(0 != cEntries);
//
// This name replaces "BUILTIN" for Alias SIDs
//
GetDomainName(pszServer, szAliasDomain, ARRAYSIZE(szAliasDomain)); cbAliasDomain = StringByteSize(szAliasDomain);
//
// Add the sizes
//
cb = SIZEOF(USER_LIST) + ((cEntries - 1) * SIZEOF(USER_INFO)); for (i = 0; i < cEntries; i++) { pEntry = (PSID_CACHE_ENTRY)DPA_FastGetPtr(hEntryList, i); TraceAssert(NULL != pEntry); cSidsLen += ACLUI_ALIGNED_SID_LENGTH(pEntry->pSid); if (SidTypeAlias == pEntry->SidType) cb += cbAliasDomain; else if (pEntry->pszLogonName) cb += StringByteSize(pEntry->pszLogonName);
if (pEntry->pszName) cb += StringByteSize(pEntry->pszName); }
cb += cSidsLen; //
// Allocate and build the return buffer
//
*ppUserList = (PUSER_LIST)LocalAlloc(LPTR, cb);
if (NULL == *ppUserList) TraceLeaveValue(FALSE);
(*ppUserList)->cUsers = cEntries;
PBYTE pData = NULL; PBYTE pCharData = NULL;
//
//NTRAID#NTBUG9-364410-2001/20/23-hiteshr
//Sids were non aligned if cEntries > 1
//
pData = (PBYTE)&(*ppUserList)->rgUsers[cEntries]; pCharData = pData + cSidsLen;
for (i = 0; i < cEntries; i++) { pEntry = (PSID_CACHE_ENTRY)DPA_FastGetPtr(hEntryList, i); TraceAssert(NULL != pEntry);
(*ppUserList)->rgUsers[i].SidType = pEntry->SidType;
TraceAssert(NULL != pEntry->pSid); (*ppUserList)->rgUsers[i].pSid = (PSID)pData; cb = GetLengthSid(pEntry->pSid); CopyMemory(pData, pEntry->pSid, cb); pData += cb;
if (SidTypeAlias == pEntry->SidType) { (*ppUserList)->rgUsers[i].pszLogonName = (LPCTSTR)pCharData;
// Copy the "BUILTIN" domain name
if (cbAliasDomain) { CopyMemory(pCharData, szAliasDomain, cbAliasDomain); pCharData += cbAliasDomain - SIZEOF(TCHAR);
if (NULL != pEntry->pszName) *(LPTSTR)pCharData = TEXT('\\'); else *(LPTSTR)pCharData = TEXT('\0');
pCharData += SIZEOF(TCHAR); } // The rest of the name is copied below
} else if (NULL != pEntry->pszLogonName) { (*ppUserList)->rgUsers[i].pszLogonName = (LPCTSTR)pCharData; cb = StringByteSize(pEntry->pszLogonName); CopyMemory(pCharData, pEntry->pszLogonName, cb); pCharData += cb; }
if (NULL != pEntry->pszName) { (*ppUserList)->rgUsers[i].pszName = (LPCTSTR)pCharData; cb = StringByteSize(pEntry->pszName); CopyMemory(pCharData, pEntry->pszName, cb); pCharData += cb; } }
TraceLeaveValue(TRUE); }
//
// Wrapper around sspi's TranslateName that automatically handles
// the buffer sizing
//
HRESULT TranslateNameInternal(LPCTSTR pszAccountName, EXTENDED_NAME_FORMAT AccountNameFormat, EXTENDED_NAME_FORMAT DesiredNameFormat, BSTR *pstrTranslatedName) {
#if DBG
//
// These match up with the EXTENDED_NAME_FORMAT enumeration.
// They're for debugger output only.
//
static const LPCTSTR rgpszFmt[] = { TEXT("NameUnknown"), TEXT("FullyQualifiedDN"), TEXT("NameSamCompatible"), TEXT("NameDisplay"), TEXT("NameDomainSimple"), TEXT("NameEnterpriseSimple"), TEXT("NameUniqueId"), TEXT("NameCanonical"), TEXT("NameUserPrincipal"), TEXT("NameCanonicalEx"), TEXT("NameServicePrincipal") }; #endif // DBG
TraceEnter(TRACE_SIDCACHE, "TranslateNameInternal"); Trace((TEXT("Calling TranslateName for \"%s\""), pszAccountName)); Trace((TEXT("Translating %s -> %s"), rgpszFmt[AccountNameFormat], rgpszFmt[DesiredNameFormat]));
if (!pszAccountName || !*pszAccountName || !pstrTranslatedName) TraceLeaveResult(E_INVALIDARG);
HRESULT hr = NOERROR; //
// cchTrans is static so that if a particular installation's
// account names are really long, we'll not be resizing the
// buffer for each account.
//
static ULONG cchTrans = MAX_PATH; ULONG cch = cchTrans;
*pstrTranslatedName = SysAllocStringLen(NULL, cch); if (NULL == *pstrTranslatedName) ExitGracefully(hr, E_OUTOFMEMORY, "Unable to allocate name buffer");
**pstrTranslatedName = L'\0';
//
// TranslateName is delay-loaded from secur32.dll using the linker's
// delay-load mechanism. Therefore, wrap with an exception handler.
//
__try { while(!::TranslateName(pszAccountName, AccountNameFormat, DesiredNameFormat, *pstrTranslatedName, &cch)) { if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { Trace((TEXT("Resizing buffer to %d chars"), cch)); if (!SysReAllocStringLen(pstrTranslatedName, NULL, cch)) ExitGracefully(hr, E_OUTOFMEMORY, "Unable to reallocate name buffer");
**pstrTranslatedName = L'\0'; } else { hr = E_FAIL; break; } }
cchTrans = max(cch, cchTrans); } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; }
exit_gracefully:
if (FAILED(hr)) { SysFreeString(*pstrTranslatedName); *pstrTranslatedName = NULL; }
TraceLeaveResult(hr); }
void CSidCache::GetUserFriendlyName(LPCTSTR pszSamLogonName, LPCTSTR pszSamAccountName, LPCTSTR pszServer, BOOL bUseSamCompatibleInfo, BOOL bIsStandalone, BSTR *pstrLogonName, BSTR *pstrDisplayName) { BSTR strFQDN = NULL;
TraceEnter(TRACE_SIDCACHE, "CSidCache::GetUserFriendlyName"); TraceAssert(NULL != pszSamLogonName);
//
// Start by getting the FQDN. Cracking is most efficient when the
// FQDN is the starting point.
//
// TranslateName takes a while to complete, so bUseSamCompatibleInfo
// should be TRUE whenever possible, e.g. for local accounts on a non-DC
// or anything where we know a FQDN doesn't exist.
//
if (!bUseSamCompatibleInfo && FAILED(TranslateNameInternal(pszSamLogonName, NameSamCompatible, NameFullyQualifiedDN, &strFQDN))) { //
// No FQDN available for this account. Must be an NT4
// account. Return SAM-compatible info to the caller.
//
bUseSamCompatibleInfo = TRUE; }
if (NULL != pstrLogonName) { *pstrLogonName = NULL;
if (!bUseSamCompatibleInfo) { TranslateNameInternal(strFQDN, NameFullyQualifiedDN, NameUserPrincipal, pstrLogonName); } }
if (NULL != pstrDisplayName) { *pstrDisplayName = NULL;
if (bUseSamCompatibleInfo || FAILED(TranslateNameInternal(strFQDN, NameFullyQualifiedDN, NameDisplay, pstrDisplayName))) { *pstrDisplayName = GetNT4DisplayName(pszSamLogonName, pszSamAccountName, pszServer, bIsStandalone); } }
SysFreeString(strFQDN);
TraceLeaveVoid(); }
BOOL CSidCache::InternalLookupSids(HDPA hSids, LPCTSTR pszServer, LPSECURITYINFO2 psi2, HDPA hEntryList, HWND hWndNotify, UINT uMsgNotify) { ULONG cSids; HDPA hUnknownSids; PSID_CACHE_ENTRY pEntry; ULONG i;
TraceEnter(TRACE_SIDCACHE, "CSidCache::InternalLookupSids"); TraceAssert(hSids != NULL);
if (hSids == NULL) { SetLastError(ERROR_INVALID_PARAMETER); TraceLeaveValue(FALSE); }
cSids = DPA_GetPtrCount(hSids); TraceAssert(0 != cSids);
hUnknownSids = DPA_Create(4);
if (NULL == hUnknownSids) TraceLeaveValue(FALSE);
//
// See if any exist in the cache already
//
for (i = 0; i < cSids; i++) { pEntry = FindSid((PSID)DPA_FastGetPtr(hSids, i));
if (pEntry) { if (hWndNotify) PostMessage(hWndNotify, uMsgNotify, 0, (LPARAM)pEntry->pSid); else if (hEntryList) DPA_AppendPtr(hEntryList, pEntry); } else DPA_AppendPtr(hUnknownSids, DPA_FastGetPtr(hSids, i)); }
//
// Call LSA to lookup any that we don't have cached
//
if (0 != DPA_GetPtrCount(hUnknownSids)) { if (!psi2 || FAILED(LookupSidsFromObject(hUnknownSids, psi2, hEntryList))) { LookupSidsHelper(hUnknownSids, pszServer, hEntryList, hWndNotify, uMsgNotify); } }
DPA_Destroy(hUnknownSids);
TraceLeaveValue(TRUE); }
#include <adsnms.h> // USER_CLASS_NAME, etc.
TCHAR const c_szForeignSecurityPrincipal[] = TEXT("foreignSecurityPrincipal");
static const struct { LPCTSTR pszClass; SID_NAME_USE sidType; } c_aSidClasses[] = { USER_CLASS_NAME, SidTypeUser, GROUP_CLASS_NAME, SidTypeGroup, GLOBALGROUP_CLASS_NAME, SidTypeGroup, LOCALGROUP_CLASS_NAME, SidTypeGroup, COMPUTER_CLASS_NAME, SidTypeComputer, c_szForeignSecurityPrincipal, SidTypeGroup, };
SID_NAME_USE GetSidType(PSID pSid, LPCTSTR pszClass) { SID_NAME_USE sidType = SidTypeUnknown;
TraceEnter(TRACE_SIDCACHE, "GetSidType");
if (pSid) { TraceAssert(IsValidSid(pSid));
if (EqualSystemSid(pSid, UI_SID_World) || IsCreatorSid(pSid)) TraceLeaveValue(SidTypeWellKnownGroup);
if (IsAliasSid(pSid)) TraceLeaveValue(SidTypeAlias);
if (*GetSidSubAuthorityCount(pSid) == 1 && IsNTAuthority(pSid)) { DWORD sa = *GetSidSubAuthority(pSid, 0); if (sa && sa <= SECURITY_RESTRICTED_CODE_RID && sa != SECURITY_LOGON_IDS_RID) TraceLeaveValue(SidTypeWellKnownGroup); if (SECURITY_LOCAL_SYSTEM_RID == sa) TraceLeaveValue(SidTypeWellKnownGroup); } }
if (pszClass) { // Didn't recognize the SID, try the class name
for (int i = 0; i < ARRAYSIZE(c_aSidClasses); i++) { if (!lstrcmpi(pszClass, c_aSidClasses[i].pszClass)) TraceLeaveValue(c_aSidClasses[i].sidType); } Trace((TEXT("Unexpected class type: %s"), pszClass)); }
// Don't know what type it is, so take a guess. This is just
// for picking an icon, so it doesn't matter too much.
TraceLeaveValue(SidTypeUser); // SidTypeGroup would be just as valid
}
HRESULT CSidCache::LookupSidsFromObject(HDPA hSids, LPSECURITYINFO2 psi2, HDPA hEntryList) { HRESULT hr; ULONG cSids; LPDATAOBJECT pdoNames = NULL; STGMEDIUM medium = {0}; FORMATETC fe = { (CLIPFORMAT)g_cfSidInfoList, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; PSID_INFO_LIST pSidList = NULL; UINT i;
TraceEnter(TRACE_SIDCACHE, "CSidCache::LookupSidsFromObject"); TraceAssert(hSids != NULL); TraceAssert(psi2 != NULL);
cSids = DPA_GetPtrCount(hSids); TraceAssert(cSids != 0);
hr = psi2->LookupSids(cSids, DPA_GetPtrPtr(hSids), &pdoNames); FailGracefully(hr, "ISecurityInformation2::LookupSids failed");
hr = pdoNames->GetData(&fe, &medium); FailGracefully(hr, "Unable to get CFSTR_ACLUI_SID_INFO_LIST from DataObject");
pSidList = (PSID_INFO_LIST)GlobalLock(medium.hGlobal); if (!pSidList) ExitGracefully(hr, E_FAIL, "Unable to lock stgmedium.hGlobal");
TraceAssert(pSidList->cItems > 0);
for (i = 0; i < pSidList->cItems; i++) { PSID_CACHE_ENTRY pEntry = MakeEntry(pSidList->aSidInfo[i].pSid, GetSidType(pSidList->aSidInfo[i].pSid, pSidList->aSidInfo[i].pwzClass), pSidList->aSidInfo[i].pwzCommonName, pSidList->aSidInfo[i].pwzUPN); if (pEntry) { if (AddEntry(pEntry)) { if (hEntryList) DPA_AppendPtr(hEntryList, pEntry); } else LocalFree(pEntry); } }
exit_gracefully:
if (pSidList) GlobalUnlock(medium.hGlobal); ReleaseStgMedium(&medium); DoRelease(pdoNames);
TraceLeaveResult(hr); }
BOOL CSidCache::LookupSidsHelper(HDPA hSids, LPCTSTR pszServer, HDPA hEntryList, HWND hWndNotify, UINT uMsgNotify, BOOL bSecondTry, BOOL bWellKnown) { BOOL fResult = FALSE; ULONG cSids; LSA_HANDLE hlsa = NULL; PLSA_REFERENCED_DOMAIN_LIST pRefDomains = NULL; PLSA_TRANSLATED_NAME pTranslatedNames = NULL; DWORD dwStatus; BOOL bIsDC = FALSE; BOOL bIsStandalone = FALSE; HDPA hUnknownSids = NULL;
TraceEnter(TRACE_SIDCACHE, "CSidCache::LookupSidsHelper"); TraceAssert(hSids != NULL);
cSids = DPA_GetPtrCount(hSids); if (!cSids) TraceLeaveValue(FALSE);
//
// Call LSA to lookup SIDs for the names
//
hlsa = GetLSAConnection(pszServer, POLICY_LOOKUP_NAMES); if (NULL == hlsa && NULL != pszServer && !bSecondTry) { // Try the local machine
pszServer = NULL; hlsa = GetLSAConnection(NULL, POLICY_LOOKUP_NAMES); } if (NULL == hlsa) TraceLeaveValue(FALSE);
dwStatus = LsaLookupSids(hlsa, cSids, DPA_GetPtrPtr(hSids), &pRefDomains, &pTranslatedNames);
bIsStandalone = IsStandalone(pszServer, &bIsDC);
if (STATUS_SUCCESS == dwStatus || STATUS_SOME_NOT_MAPPED == dwStatus) { TraceAssert(pTranslatedNames); TraceAssert(pRefDomains);
//
// Build cache entries with NT4 style names
//
for (ULONG i = 0; i < cSids; i++) { BOOL bTryUPN = TRUE; BSTR strLogonName = NULL; BSTR strDisplayName = NULL; LPTSTR pszDeletedAccount = NULL; LPTSTR pszSID = NULL;
PLSA_TRANSLATED_NAME pLsaName = &pTranslatedNames[i]; PLSA_TRUST_INFORMATION pLsaDomain = NULL; PSID pSid = DPA_FastGetPtr(hSids, i);
TCHAR szAccountName[MAX_PATH]; TCHAR szDomainName[MAX_PATH];
BOOL bNoCache = FALSE;
szAccountName[0] = TEXT('\0'); szDomainName[0] = TEXT('\0');
// Get the referenced domain, if any
if (pLsaName->DomainIndex >= 0 && pRefDomains) { TraceAssert((ULONG)pLsaName->DomainIndex < pRefDomains->Entries); pLsaDomain = &pRefDomains->Domains[pLsaName->DomainIndex]; }
// Make NULL-terminated copies of the domain and account name strings
CopyUnicodeString(szAccountName, ARRAYSIZE(szAccountName), &pLsaName->Name); if (pLsaDomain) CopyUnicodeString(szDomainName, ARRAYSIZE(szDomainName), &pLsaDomain->Name);
// Some optimization to avoid TranslateName when possible
if (!bIsDC) { if (bIsStandalone) { // Non-DC, standalone, therefore no UPN
bTryUPN = FALSE; } else if (SidTypeUser == pLsaName->Use) { TCHAR szTargetDomain[DNLEN + 1]; szTargetDomain[0] = TEXT('\0'); GetDomainName(pszServer, szTargetDomain, ARRAYSIZE(szTargetDomain)); if (CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, szTargetDomain, -1, szDomainName, -1)) { // Local account on non-DC, therefore no UPN
bTryUPN = FALSE; } } }
//
// Build NT4 "domain\user" style name
//
if (szDomainName[0] != TEXT('\0')) { StringCchCat(szDomainName,ARRAYSIZE(szDomainName),TEXT("\\")); StringCchCat(szDomainName, ARRAYSIZE(szDomainName), szAccountName); }
// What we've got so far is our baseline.
// Adjust these based on SID type.
LPTSTR pszName = szAccountName; LPTSTR pszLogonName = szDomainName;
switch (pLsaName->Use) { case SidTypeUser: // 1
// Get "User Principal Name" etc.
GetUserFriendlyName(pszLogonName, pszName, pszServer, !bTryUPN, bIsStandalone, &strLogonName, &strDisplayName); if (strLogonName) pszLogonName = strLogonName; if (strDisplayName) pszName = strDisplayName; break;
case SidTypeGroup: // 2
case SidTypeDomain: // 3
// nothing
break;
case SidTypeAlias: // 4
if (!IsAliasSid(pSid)) { // Sometimes get SidTypeAlias for non-BUILTIN sids,
// e.g. Domain Local Groups. Treat these as groups
// so we don't replace the Domain name.
// Raid #383755
pLsaName->Use = SidTypeGroup; break; } // else Fall Through
case SidTypeWellKnownGroup: // 5
// No logon name for these
pszLogonName = NULL; break;
case SidTypeDeletedAccount: // 6
// Display "Account Deleted(Sid)"
ConvertSidToStringSid(pSid, &pszSID); if(FormatStringID(&pszDeletedAccount, ::hModule, IDS_SID_DELETED_1, pszSID)) { if (pszSID) LocalFreeString(&pszSID); if (pszDeletedAccount) pszName = pszDeletedAccount; pszLogonName = NULL; } else { bNoCache = TRUE; } break;
case SidTypeInvalid: // 7
bNoCache = TRUE; break;
case SidTypeUnknown: // 8
// Some SIDs can only be looked up on a DC, so
// if pszServer is not a DC, remember them and
// look them up on a DC after this loop is done.
if (!bSecondTry && !bIsStandalone && !bIsDC) { if (!hUnknownSids) hUnknownSids = DPA_Create(4); if (hUnknownSids) DPA_AppendPtr(hUnknownSids, pSid);
bNoCache = TRUE; } else if(bWellKnown) bNoCache = TRUE; else { // Display "Account Unknown(Sid)"
ConvertSidToStringSid(pSid, &pszSID); if(FormatStringID(&pszDeletedAccount, ::hModule, IDS_SID_UNKNOWN_1, pszSID)) { if (pszSID) LocalFreeString(&pszSID); if (pszDeletedAccount) pszName = pszDeletedAccount; pszLogonName = NULL; } else { bNoCache = TRUE; } } break;
case SidTypeComputer: // 9
if (*pszName) { // Strip the trailing '$'
int nLen = lstrlen(pszName); if (nLen && pszName[nLen-1] == TEXT('$')) { pszName[nLen-1] = TEXT('\0'); } } break;
}
if (!bNoCache) { //
// Make a cache entry and save it
//
PSID_CACHE_ENTRY pEntry = MakeEntry(pSid, pLsaName->Use, pszName, pszLogonName); if (pEntry) { if (AddEntry(pEntry)) { fResult = TRUE; // we added something to the cache
if (hWndNotify) PostMessage(hWndNotify, uMsgNotify, 0, (LPARAM)pEntry->pSid); else if (hEntryList) DPA_AppendPtr(hEntryList, pEntry); } else LocalFree(pEntry); } }
if (strLogonName) SysFreeString(strLogonName); if (strDisplayName) SysFreeString(strDisplayName); LocalFreeString(&pszDeletedAccount); } } else if (STATUS_NONE_MAPPED == dwStatus && !bSecondTry && !bIsStandalone && !bIsDC) { hUnknownSids = DPA_Clone(hSids, NULL); }
// Cleanup
if (pTranslatedNames) LsaFreeMemory(pTranslatedNames); if (pRefDomains) LsaFreeMemory(pRefDomains); LsaClose(hlsa);
if (hUnknownSids) { //
// Some (or all) SIDs were unknown on the target machine,
// try a DC for the target machine's primary domain.
//
// This typically happens for certain Alias SIDs, such
// as Print Operators and System Operators, for which LSA
// only returns names if the lookup is done on a DC.
//
LPTSTR pszDC = NULL;
TraceAssert(!bSecondTry);
// We don't bother trying if standalone, and don't
// do this if the target machine is already a DC.
TraceAssert(!bIsStandalone && !bIsDC);
_GetDcName(pszServer, NULL, &pszDC);
if (pszDC) { // Recurse
if (LookupSidsHelper(hUnknownSids, pszDC, hEntryList, hWndNotify, uMsgNotify, TRUE)) { fResult = TRUE; } LocalFree(pszDC); }
DPA_Destroy(hUnknownSids); }
TraceLeaveValue(fResult); }
BSTR GetNT4AccountName(LPTSTR pszWinNTPath) { // pszWinNTPath is expected to look like
// "WinNT://domain/user"
// or
// "WinNT://domain/machine/user"
//
// The "WinNT://" part is optional.
//
// In either case, we want the last 2 elements,
// e.g. "domain/user" and "machine/user".
//
// The approach is to find the next to last '/' and add 1.
// If there are less than 2 slashes, return the original string.
BSTR strResult = NULL; LPTSTR pszResult = pszWinNTPath; if (pszWinNTPath) { LPTSTR pszSlash = StrRChr(pszWinNTPath, pszWinNTPath + lstrlen(pszWinNTPath) - 1, TEXT('/')); if (pszSlash) { pszSlash = StrRChr(pszWinNTPath, pszSlash-1, TEXT('/')); if (pszSlash) pszResult = pszSlash + 1; } }
if (pszResult) { strResult = SysAllocString(pszResult); if (strResult) { // At this point, there is at most one forward slash
// in the string. Convert it to a backslash.
LPTSTR pszSlash = StrChr(strResult, TEXT('/')); if (pszSlash) *pszSlash = TEXT('\\'); } }
return strResult; }
BOOL _LookupName(LPCTSTR pszServer, LPCTSTR pszAccount, PSID *ppSid, SID_NAME_USE *pSidType) { BOOL fResult = FALSE; BYTE buffer[sizeof(SID) + SID_MAX_SUB_AUTHORITIES*sizeof(ULONG)]; PSID pSid = (PSID)buffer; DWORD cbSid = sizeof(buffer); TCHAR szDomain[MAX_PATH]; DWORD cchDomain = ARRAYSIZE(szDomain); SID_NAME_USE sidType;
fResult = LookupAccountName(pszServer, pszAccount, pSid, &cbSid, szDomain, &cchDomain, &sidType); if (fResult) { *ppSid = LocalAllocSid(pSid); if (*ppSid) { if (pSidType) *pSidType = sidType; } else fResult = FALSE; }
return fResult; }
BOOL CSidCache::InternalLookupNames(PDS_SELECTION_LIST pDsSelList, LPCTSTR pszServer, HDPA hEntryList, BOOL bStandalone) { BOOL fResult = FALSE; ULONG cNames; HDPA hSids = NULL; PSID_CACHE_ENTRY pEntry; ULONG i; ULONG cNoSID = 0; HRESULT hrCom = E_FAIL; IADsPathname *pPath = NULL;
TraceEnter(TRACE_SIDCACHE, "CSidCache::InternalLookupNames"); TraceAssert(pDsSelList != NULL); TraceAssert(hEntryList != NULL);
if (pDsSelList == NULL || hEntryList == NULL) { SetLastError(ERROR_INVALID_PARAMETER); TraceLeaveValue(FALSE); }
cNames = pDsSelList->cItems; TraceAssert(cNames != 0);
if (0 == cNames) { SetLastError(ERROR_INVALID_PARAMETER); TraceLeaveValue(FALSE); }
hSids = DPA_Create(4);
for (i = 0; i < cNames; i++) { PSID pSid = NULL; PSID pSidFree = NULL; LPVARIANT pvarSid = pDsSelList->aDsSelection[i].pvarFetchedAttributes; SID_NAME_USE sidType = SidTypeUnknown; BSTR strNT4Name = NULL;
if (NULL == pvarSid || (VT_ARRAY | VT_UI1) != V_VT(pvarSid) || FAILED(SafeArrayAccessData(V_ARRAY(pvarSid), &pSid))) { // If there's no SID, then we can't use it in an ACL
Trace((TEXT("No SID returned for %s"), pDsSelList->aDsSelection[i].pwzADsPath));
// If it's the NT provider, try to lookup the SID by name
if (CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, 0, c_szNTProvider, NTPROV_LEN, pDsSelList->aDsSelection[i].pwzADsPath, NTPROV_LEN)) { strNT4Name = GetNT4AccountName(pDsSelList->aDsSelection[i].pwzADsPath + NTPROV_LEN); if (strNT4Name) { Trace((TEXT("Using LSA to lookup SID for %s"), strNT4Name)); if (_LookupName(pszServer, strNT4Name, &pSidFree, &sidType)) { pSid = pSidFree; } } }
if (NULL == pSid) { cNoSID++; continue; } } TraceAssert(NULL != pSid);
// Is it already in the cache?
pEntry = FindSid(pSid); if (pEntry) { DPA_AppendPtr(hEntryList, pEntry); } else { // Not cached, try to make an entry using the info returned
// by the object picker.
if (SidTypeUnknown == sidType) sidType = GetSidType(pSid, pDsSelList->aDsSelection[i].pwzClass);
if (!lstrcmpi(c_szForeignSecurityPrincipal, pDsSelList->aDsSelection[i].pwzClass)) { // Object picker returns non-localized names for these (the
// DS Configuration Container is not localized). Look up the
// localized name from LSA. 175278
// This happens automatically below (pEntry is NULL).
} else if (SidTypeAlias == sidType || SidTypeWellKnownGroup == sidType) { // Only need the name
pEntry = MakeEntry(pSid, sidType, pDsSelList->aDsSelection[i].pwzName, NULL); } else if (pDsSelList->aDsSelection[i].pwzUPN && *pDsSelList->aDsSelection[i].pwzUPN) { // We have both name and UPN
pEntry = MakeEntry(pSid, sidType, pDsSelList->aDsSelection[i].pwzName, pDsSelList->aDsSelection[i].pwzUPN); } else if (CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, 0, c_szNTProvider, NTPROV_LEN, pDsSelList->aDsSelection[i].pwzADsPath, NTPROV_LEN)) { // It's downlevel ("WinNT://blah")
if (NULL == strNT4Name) strNT4Name = GetNT4AccountName(pDsSelList->aDsSelection[i].pwzADsPath + NTPROV_LEN); if (strNT4Name) { // We have the NT4 name, now look for a Friendly Name
BSTR strDisplay = GetNT4DisplayName(strNT4Name, pDsSelList->aDsSelection[i].pwzName, pszServer, bStandalone); pEntry = MakeEntry(pSid, sidType, strDisplay ? strDisplay : pDsSelList->aDsSelection[i].pwzName, strNT4Name); SysFreeString(strDisplay); } } else { // It's not a downlevel, so it must be
// 1. WellKnown/Universal (no ADsPath)
// or
// 2. Uplevel ("GC:" or "LDAP:") but
// has no UPN
//
// If it has an ADs path, try to get an
// NT4 name such as "NTDEV\Domain Users".
//
// Note that wellknown things such "Authenticated User"
// can fall under either 1 or 2 above, depending on what
// scope it was selected from. That's why we try to pick
// them off higher up.
TraceAssert(NULL == strNT4Name); if (pDsSelList->aDsSelection[i].pwzADsPath && *pDsSelList->aDsSelection[i].pwzADsPath) { // DsCrackNames doesn't accept full ADs paths, so use
// IADsPathname to retrieve the DN (no provider/server).
if (FAILED(hrCom)) hrCom = CoInitialize(NULL); if (!pPath) { CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (LPVOID*)&pPath); } if (pPath) { BSTR strT; if (SUCCEEDED(pPath->Set(AutoBstr(pDsSelList->aDsSelection[i].pwzADsPath), ADS_SETTYPE_FULL))) { if (SUCCEEDED(pPath->Retrieve(ADS_FORMAT_X500_DN, &strT))) { // Try to get an NT4 account name
TranslateNameInternal(strT, NameFullyQualifiedDN, NameSamCompatible, &strNT4Name); SysFreeString(strT); } if (!strNT4Name) { // Retrieve or CrackName failed. Try to build
// an NT4-style name from the server name.
if (SUCCEEDED(pPath->Retrieve(ADS_FORMAT_SERVER, &strT))) { TCHAR szNT4Name[MAX_PATH]; GetDomainName(strT, szNT4Name, ARRAYSIZE(szNT4Name)); PathAppend(szNT4Name, pDsSelList->aDsSelection[i].pwzName); strNT4Name = SysAllocString(szNT4Name); SysFreeString(strT); } } } } } pEntry = MakeEntry(pSid, sidType, pDsSelList->aDsSelection[i].pwzName, strNT4Name); }
//
// Do we have a cache entry yet?
//
if (pEntry) { if (AddEntry(pEntry)) { DPA_AppendPtr(hEntryList, pEntry); } else { LocalFree(pEntry); pEntry = NULL; } }
if (!pEntry && hSids) { // Look up the SID the hard way
Trace((TEXT("Using LSA to lookup %s"), pDsSelList->aDsSelection[i].pwzADsPath)); PSID pSidCopy = LocalAllocSid(pSid); if (pSidCopy) { DPA_AppendPtr(hSids, pSidCopy); } } }
SysFreeString(strNT4Name);
if (pSidFree) LocalFree(pSidFree); else SafeArrayUnaccessData(V_ARRAY(pvarSid)); }
TraceAssert(0 == cNoSID);
//
// Call LSA to lookup names for the SIDs that aren't cached yet
//
if (hSids && 0 != DPA_GetPtrCount(hSids)) LookupSidsHelper(hSids, pszServer, hEntryList);
if (NULL != hSids) DestroyDPA(hSids);
DoRelease(pPath);
if (SUCCEEDED(hrCom)) CoUninitialize();
TraceLeaveValue(TRUE); }
DWORD WINAPI CSidCache::InitThread(LPVOID pvThreadData) { PSIDCACHE pThis = (PSIDCACHE)pvThreadData;
// Our caller already gave us a ref on the dll to prevent the race window where
// we are created but we the dll is freed before we can call LoadLibrary()
// HINSTANCE hInstThisDll = LoadLibrary(c_szDllName);
TraceEnter(TRACE_SIDCACHE, "CSidCache::InitThread");
if (pThis) { // Lookup some well-known SIDs to pre-load the cache
HDPA hSids; //-1 becuase we donot want to create cache for Admininstrators sid
hSids = DPA_Create(COUNT_SYSTEM_SID_TYPES -1); if (hSids) { for (int i = 0; i < (COUNT_SYSTEM_SID_TYPES -1); i++) { DPA_AppendPtr(hSids, QuerySystemSid((UI_SystemSid)i)); }
pThis->LookupSidsHelper(hSids, NULL, NULL, NULL, 0,FALSE,TRUE);
DPA_Destroy(hSids); }
pThis->Release(); }
TraceLeave(); FreeLibraryAndExitThread(GetModuleHandle(c_szDllName), 0); return 0; }
|