|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2000 - 2001.
//
// File: sidcache.cpp
//
// Contents:
//
// History:
//----------------------------------------------------------------------------
#include "headers.h"
const struct { SID sid; // contains 1 subauthority
DWORD dwSubAuth[1]; // we currently need at most 2 subauthorities
} g_StaticSids[] = { {{SID_REVISION,2,SECURITY_NT_AUTHORITY, {SECURITY_BUILTIN_DOMAIN_RID}}, {DOMAIN_ALIAS_RID_ADMINS} }, };
#define IsAliasSid(pSid) EqualPrefixSid(pSid, (PSID)&g_StaticSids[0])
/******************************************************************************
Class: SID_CACHE_ENTRY Purpose: Contains info for a single security principle ******************************************************************************/ DEBUG_DECLARE_INSTANCE_COUNTER(SID_CACHE_ENTRY);
SID_CACHE_ENTRY:: SID_CACHE_ENTRY(PSID pSid) :m_SidType(SidTypeUnknown) { DEBUG_INCREMENT_INSTANCE_COUNTER(SID_CACHE_ENTRY); ASSERT(pSid); DWORD dwLen = GetLengthSid(pSid); m_pSid = new BYTE[dwLen]; ASSERT(m_pSid); CopySid(dwLen,m_pSid,pSid); ConvertSidToStringSid(m_pSid,&m_strSid); m_strType.LoadString(IDS_TYPE_UNKNOWN); m_strNameToDisplay = m_strSid; m_SidType = SidTypeUnknown; }
SID_CACHE_ENTRY:: ~SID_CACHE_ENTRY() { DEBUG_DECREMENT_INSTANCE_COUNTER(SID_CACHE_ENTRY); delete[] m_pSid; }
VOID SID_CACHE_ENTRY:: AddNameAndType(IN SID_NAME_USE SidType, const CString& strAccountName, const CString& strLogonName) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); //Empty the m_strNameToDisplay which was made using
//ealier values of strAccountName and strLogonName
m_strNameToDisplay.Empty(); m_strType.Empty(); m_SidType = SidType; m_strAccountName = strAccountName; m_strLogonName = strLogonName;
//
//Set the Display Name
//
if(m_SidType == SidTypeDeletedAccount || m_SidType == SidTypeInvalid || m_SidType == SidTypeUnknown) { UINT idFormat; if(m_SidType == SidTypeDeletedAccount) idFormat = IDS_SID_DELETED; if(m_SidType == SidTypeInvalid) idFormat = IDS_SID_INVALID; if(m_SidType == SidTypeUnknown) idFormat = IDS_SID_UNKNOWN; FormatString(m_strNameToDisplay,idFormat,LPCTSTR(m_strSid)); } else if(!m_strAccountName.IsEmpty()) { if(!m_strLogonName.IsEmpty()) { //Both the names are present.
FormatString(m_strNameToDisplay, IDS_NT_USER_FORMAT, (LPCTSTR)m_strAccountName, (LPCTSTR)m_strLogonName); } else { m_strNameToDisplay = m_strAccountName; } } else { //Just return the sid in string format
m_SidType = SidTypeUnknown; m_strNameToDisplay = m_strSid; }
//
//Set Sid Type String
//
if(m_SidType == SidTypeDeletedAccount || m_SidType == SidTypeInvalid || m_SidType == SidTypeUnknown) { m_strType.LoadString(IDS_TYPE_UNKNOWN); } else if(m_SidType == SidTypeUser) { m_strType.LoadString(IDS_TYPE_WINDOWS_USER); } else if(m_SidType == SidTypeComputer) { m_strType.LoadString(IDS_TYPE_WINDOWS_COMPUTER); } else //Assume everything else is group
{ m_strType.LoadString(IDS_TYPE_WINDOWS_GROUP); } }
/******************************************************************************
Class: CMachineInfo Purpose: Contains all the info for machine. ******************************************************************************/ DEBUG_DECLARE_INSTANCE_COUNTER(CMachineInfo); CMachineInfo:: CMachineInfo():m_bIsStandAlone(TRUE), m_bIsDC(FALSE) { DEBUG_INCREMENT_INSTANCE_COUNTER(CMachineInfo); }
CMachineInfo:: ~CMachineInfo() { DEBUG_DECREMENT_INSTANCE_COUNTER(CMachineInfo); }
//+----------------------------------------------------------------------------
// Function:InitializeMacineConfiguration
// Synopsis:Get the information about TargetComputer's conficguration
//-----------------------------------------------------------------------------
VOID CMachineInfo:: InitializeMacineConfiguration(IN const CString& strTargetComputerName) { TRACE_METHOD_EX(DEB_SNAPIN,CMachineInfo,InitializeMacineConfiguration) //
//Initialize the values to default
//
m_strTargetComputerName = strTargetComputerName; m_bIsStandAlone = TRUE; m_strDCName.Empty(); m_bIsDC = FALSE; m_strTargetDomainFlat.Empty(); m_strTargetDomainDNS.Empty(); HRESULT hr = S_OK; ULONG ulResult; PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL; PDOMAIN_CONTROLLER_INFO pdci = NULL; do { PCWSTR pwzMachine = strTargetComputerName; ulResult = DsRoleGetPrimaryDomainInformation(pwzMachine, DsRolePrimaryDomainInfoBasic, (PBYTE *)&pDsRole); if (ulResult != NO_ERROR) { DBG_OUT_LRESULT(ulResult); break; } if(!pDsRole) { //We should never reach here, but sadly DsRoleGetPrimaryDomainInformation
//sometimes succeeds but pDsRole is null.
ASSERT(FALSE); break; } Dbg(DEB_SNAPIN, "DsRoleGetPrimaryDomainInformation returned:\n"); Dbg(DEB_SNAPIN, "DomainNameFlat: %ws\n", CHECK_NULL(pDsRole->DomainNameFlat)); Dbg(DEB_SNAPIN, "DomainNameDns: %ws\n", CHECK_NULL(pDsRole->DomainNameDns)); Dbg(DEB_SNAPIN, "DomainForestName: %ws\n", CHECK_NULL(pDsRole->DomainForestName)); //
// If machine is in a workgroup, we're done.
//
if (pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation || pDsRole->MachineRole == DsRole_RoleStandaloneServer) { Dbg(DEB_SNAPIN, "Target machine is not joined to a domain\n"); m_bIsStandAlone = TRUE; m_bIsDC = FALSE; break; } //
// Target Computer is joined to a domain
//
m_bIsStandAlone = FALSE; if (pDsRole->DomainNameFlat) { m_strTargetDomainFlat = pDsRole->DomainNameFlat; } if (pDsRole->DomainNameDns) { m_strTargetDomainDNS = pDsRole->DomainNameDns; } //
// TargetComputer is Joined to a domain and is dc
//
if (pDsRole->MachineRole == DsRole_RolePrimaryDomainController || pDsRole->MachineRole == DsRole_RoleBackupDomainController) { m_bIsDC = TRUE; m_strDCName = m_strTargetComputerName; break; } //
//Target computer is Joined to domain and is not a DC.
//Get a DC for the domain
//
PWSTR pwzDomainNameForDsGetDc; ULONG flDsGetDc = DS_DIRECTORY_SERVICE_PREFERRED; if (pDsRole->DomainNameDns) { pwzDomainNameForDsGetDc = pDsRole->DomainNameDns; flDsGetDc |= DS_IS_DNS_NAME; Dbg(DEB_TRACE, "DsGetDcName(Domain=%ws, flags=DS_IS_DNS_NAME | DS_DIRECTORY_SERVICE_PREFERRED)\n", CHECK_NULL(pwzDomainNameForDsGetDc)); } else { pwzDomainNameForDsGetDc = pDsRole->DomainNameFlat; flDsGetDc |= DS_IS_FLAT_NAME; Dbg(DEB_TRACE, "DsGetDcName(Domain=%ws, flags=DS_IS_FLAT_NAME | DS_DIRECTORY_SERVICE_PREFERRED)\n", CHECK_NULL(pwzDomainNameForDsGetDc)); } ulResult = DsGetDcName(NULL, pwzDomainNameForDsGetDc, NULL, NULL, flDsGetDc, &pdci); if (ulResult != NO_ERROR) { Dbg(DEB_ERROR, "DsGetDcName for domain %ws returned %#x, Too bad don't have the dc name\n", pwzDomainNameForDsGetDc, ulResult); break; } ASSERT(pdci); m_strDCName = pdci->DomainControllerName; } while (0); if (pdci) { NetApiBufferFree(pdci); } if (pDsRole) { DsRoleFreeMemory(pDsRole); } }
int CopyUnicodeString(CString* pstrDest, PLSA_UNICODE_STRING pSrc) { ULONG cchSrc;
// If UNICODE, cchDest is size of destination buffer in chars
// Else (MBCS) cchDest is size of destination buffer in bytes
if (pstrDest == NULL ) return 0;
if (pSrc == NULL || pSrc->Buffer == NULL) return 0;
// Get # of chars in source (not including NULL)
cchSrc = pSrc->Length/sizeof(WCHAR);
//
// Note that pSrc->Buffer may not be NULL terminated so we can't just
// call lstrcpynW with cchDest. Also, if we call lstrcpynW with cchSrc,
// it copies the correct # of chars, but then overwrites the last char
// with NULL giving an incorrect result. If we call lstrcpynW with
// (cchSrc+1) it reads past the end of the buffer, which may fault (360251)
// causing lstrcpynW's exception handler to return 0 without NULL-
// terminating the resulting string.
//
// So let's just copy the bits.
//
CString temp(pSrc->Buffer,cchSrc);
*pstrDest = temp; return cchSrc; }
VOID GetAccountAndDomainName(int index, PLSA_TRANSLATED_NAME pTranslatedNames, PLSA_REFERENCED_DOMAIN_LIST pRefDomains, CString* pstrAccountName, CString* pstrDomainName, SID_NAME_USE* puse) { PLSA_TRANSLATED_NAME pLsaName = &pTranslatedNames[index]; PLSA_TRUST_INFORMATION pLsaDomain = NULL;
// Get the referenced domain, if any
if (pLsaName->DomainIndex >= 0 && pRefDomains) { pLsaDomain = &pRefDomains->Domains[pLsaName->DomainIndex]; }
CopyUnicodeString(pstrAccountName,&pLsaName->Name); if (pLsaDomain) { CopyUnicodeString(pstrDomainName,&pLsaDomain->Name); }
*puse = pLsaName->Use; }
HRESULT TranslateNameInternal(IN const CString& strAccountName, IN EXTENDED_NAME_FORMAT AccountNameFormat, IN EXTENDED_NAME_FORMAT DesiredNameFormat, OUT CString* pstrTranslatedName) { if (!pstrTranslatedName) { ASSERT(pstrTranslatedName); return E_POINTER; }
HRESULT hr = S_OK; //
// 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;
LPTSTR lpszTranslatedName = (LPTSTR)LocalAlloc(LPTR, cch*sizeof(WCHAR)); if (lpszTranslatedName == NULL) return E_OUTOFMEMORY;
*lpszTranslatedName = 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(strAccountName, AccountNameFormat, DesiredNameFormat, lpszTranslatedName, &cch)) { if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { LocalFree(lpszTranslatedName); lpszTranslatedName = (LPTSTR)LocalAlloc(LPTR, cch*sizeof(WCHAR)); if (!lpszTranslatedName) { hr = E_OUTOFMEMORY; break; }
*lpszTranslatedName = L'\0'; } else { hr = E_FAIL; break; } }
cchTrans = max(cch, cchTrans); } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; }
if (FAILED(hr)) { if(lpszTranslatedName) { LocalFree(lpszTranslatedName); } } else { *pstrTranslatedName = lpszTranslatedName; } return hr; }
#define DSOP_FILTER_COMMON1 ( DSOP_FILTER_INCLUDE_ADVANCED_VIEW \
| DSOP_FILTER_USERS \ | DSOP_FILTER_UNIVERSAL_GROUPS_SE \ | DSOP_FILTER_GLOBAL_GROUPS_SE \ | DSOP_FILTER_COMPUTERS \ ) #define DSOP_FILTER_COMMON2 ( DSOP_FILTER_COMMON1 \
| DSOP_FILTER_WELL_KNOWN_PRINCIPALS \ | DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE\ ) #define DSOP_FILTER_COMMON3 ( DSOP_FILTER_COMMON2 \
| DSOP_FILTER_BUILTIN_GROUPS \ )
#define DSOP_FILTER_DL_COMMON1 ( DSOP_DOWNLEVEL_FILTER_USERS \
| DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS \ )
#define DSOP_FILTER_DL_COMMON2 ( DSOP_FILTER_DL_COMMON1 \
| DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS \ )
#define DSOP_FILTER_DL_COMMON3 ( DSOP_FILTER_DL_COMMON2 \
| DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS \ ) // Same as DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS, except no CREATOR flags.
// Note that we need to keep this in sync with any object picker changes.
#define DSOP_FILTER_DL_WELLKNOWN ( DSOP_DOWNLEVEL_FILTER_WORLD \
| DSOP_DOWNLEVEL_FILTER_AUTHENTICATED_USER \ | DSOP_DOWNLEVEL_FILTER_ANONYMOUS \ | DSOP_DOWNLEVEL_FILTER_BATCH \ | DSOP_DOWNLEVEL_FILTER_DIALUP \ | DSOP_DOWNLEVEL_FILTER_INTERACTIVE \ | DSOP_DOWNLEVEL_FILTER_NETWORK \ | DSOP_DOWNLEVEL_FILTER_SERVICE \ | DSOP_DOWNLEVEL_FILTER_SYSTEM \ | DSOP_DOWNLEVEL_FILTER_TERMINAL_SERVER \ )
#define DECLARE_SCOPE(t,f,b,m,n,d) \
{ sizeof(DSOP_SCOPE_INIT_INFO), (t), (f|DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS|DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS), { { (b), (m), (n) }, (d) }, NULL, NULL, S_OK }
// The domain to which the target computer is joined.
// Make 2 scopes, one for uplevel domains, the other for downlevel.
#define JOINED_DOMAIN_SCOPE(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN,(f),0,(DSOP_FILTER_COMMON2 & ~(DSOP_FILTER_UNIVERSAL_GROUPS_SE|DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE)),DSOP_FILTER_COMMON2,0), \ DECLARE_SCOPE(DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN,(f),0,0,0,DSOP_FILTER_DL_COMMON2)
// The domain for which the target computer is a Domain Controller.
// Make 2 scopes, one for uplevel domains, the other for downlevel.
#define JOINED_DOMAIN_SCOPE_DC(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN,(f),0,(DSOP_FILTER_COMMON3 & ~DSOP_FILTER_UNIVERSAL_GROUPS_SE),DSOP_FILTER_COMMON3,0), \ DECLARE_SCOPE(DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN,(f),0,0,0,DSOP_FILTER_DL_COMMON3)
// Target computer scope. Computer scopes are always treated as
// downlevel (i.e., they use the WinNT provider).
#define TARGET_COMPUTER_SCOPE(f)\
DECLARE_SCOPE(DSOP_SCOPE_TYPE_TARGET_COMPUTER,(f),0,0,0,DSOP_FILTER_DL_COMMON3)
// The Global Catalog
#define GLOBAL_CATALOG_SCOPE(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_GLOBAL_CATALOG,(f),DSOP_FILTER_COMMON1|DSOP_FILTER_WELL_KNOWN_PRINCIPALS,0,0,0)
// The domains in the same forest (enterprise) as the domain to which
// the target machine is joined. Note these can only be DS-aware
#define ENTERPRISE_SCOPE(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN,(f),DSOP_FILTER_COMMON1,0,0,0)
// Domains external to the enterprise but trusted directly by the
// domain to which the target machine is joined.
#define EXTERNAL_SCOPE(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN|DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN,\ (f),DSOP_FILTER_COMMON1,0,0,DSOP_DOWNLEVEL_FILTER_USERS|DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS)
// Workgroup scope. Only valid if the target computer is not joined
// to a domain.
#define WORKGROUP_SCOPE(f) \
DECLARE_SCOPE(DSOP_SCOPE_TYPE_WORKGROUP,(f),0,0,0, DSOP_FILTER_DL_COMMON1|DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS )
//
// Array of Default Scopes
//
static const DSOP_SCOPE_INIT_INFO g_aDefaultScopes[] = { JOINED_DOMAIN_SCOPE(DSOP_SCOPE_FLAG_STARTING_SCOPE), TARGET_COMPUTER_SCOPE(0), GLOBAL_CATALOG_SCOPE(0), ENTERPRISE_SCOPE(0), EXTERNAL_SCOPE(0), };
//
// Same as above, but without the Target Computer
// Used when the target is a Domain Controller
//
static const DSOP_SCOPE_INIT_INFO g_aDCScopes[] = { JOINED_DOMAIN_SCOPE_DC(DSOP_SCOPE_FLAG_STARTING_SCOPE), GLOBAL_CATALOG_SCOPE(0), ENTERPRISE_SCOPE(0), EXTERNAL_SCOPE(0), };
//
// Array of scopes for standalone machines
//
static const DSOP_SCOPE_INIT_INFO g_aStandAloneScopes[] = { //
//On Standalone machine Both User And Groups are selected by default
//
TARGET_COMPUTER_SCOPE(DSOP_SCOPE_FLAG_STARTING_SCOPE|DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS), };
//
// Attributes that we want the Object Picker to retrieve
//
static const LPCTSTR g_aszOPAttributes[] = { TEXT("ObjectSid"), };
/******************************************************************************
Class: CSidHandler Purpose: class for handling tasks related to selecting windows users, converting sids to name etc. ******************************************************************************/ DEBUG_DECLARE_INSTANCE_COUNTER(CSidHandler);
CSidHandler:: CSidHandler(CMachineInfo* pMachineInfo) :m_pMachineInfo(pMachineInfo), m_bObjectPickerInitialized(FALSE) { DEBUG_INCREMENT_INSTANCE_COUNTER(CSidHandler); InitializeCriticalSection(&m_csSidHandlerLock); InitializeCriticalSection(&m_csSidCacheLock); }
CSidHandler::~CSidHandler() { DEBUG_DECREMENT_INSTANCE_COUNTER(CSidHandler); delete m_pMachineInfo; //Remove itesm from the map
LockSidHandler(); for (SidCacheMap::iterator it = m_mapSidCache.begin(); it != m_mapSidCache.end(); ++it) { delete (*it).second; } UnlockSidHandler(); DeleteCriticalSection(&m_csSidCacheLock); DeleteCriticalSection(&m_csSidHandlerLock); }
PSID_CACHE_ENTRY CSidHandler:: GetEntryFromCache(PSID pSid) { PSID_CACHE_ENTRY pSidCache = NULL; LockSidHandler();
//Check if item in the cache
CString strSid; ConvertSidToStringSid(pSid,&strSid);
SidCacheMap::iterator it = m_mapSidCache.find(&strSid); if(it != m_mapSidCache.end()) pSidCache = (*it).second;
if(!pSidCache) { //No in the cache Create a new entry and add to the cache
pSidCache = new SID_CACHE_ENTRY(pSid); if(pSidCache) { m_mapSidCache.insert(pair<const CString*,PSID_CACHE_ENTRY>(&(pSidCache->GetStringSid()),pSidCache)); } } UnlockSidHandler(); return pSidCache; }
//+----------------------------------------------------------------------------
// Synopsis: CoCreateInstance ObjectPikcer
//-----------------------------------------------------------------------------
HRESULT CSidHandler:: GetObjectPicker() { LockSidHandler(); TRACE_METHOD_EX(DEB_SNAPIN,CSidHandler,GetObjectPicker) HRESULT hr = S_OK; if (!m_spDsObjectPicker) { hr = CoCreateInstance(CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER, IID_IDsObjectPicker, (LPVOID*)&m_spDsObjectPicker); CHECK_HRESULT(hr); } UnlockSidHandler(); return hr; }
//+----------------------------------------------------------------------------
// Function: InitObjectPicker
// Synopsis: Initializes the object picker. This needs to be done once in
// lifetime
//-----------------------------------------------------------------------------
HRESULT CSidHandler::InitObjectPicker() { TRACE_METHOD_EX(DEB_SNAPIN,CSidHandler,InitObjectPicker)
HRESULT hr = S_OK; hr = GetObjectPicker(); if(FAILED(hr)) return hr;
LockSidHandler(); do { if(m_bObjectPickerInitialized) break; DSOP_INIT_INFO InitInfo; InitInfo.cbSize = sizeof(InitInfo); InitInfo.flOptions = DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK | DSOP_FLAG_MULTISELECT;
//Select the appropriate scopes
PCDSOP_SCOPE_INIT_INFO pScopes; ULONG cScopes; if(m_pMachineInfo->IsStandAlone()) { cScopes = ARRAYLEN(g_aStandAloneScopes); pScopes = g_aStandAloneScopes; } else if(m_pMachineInfo->IsDC()) { cScopes = ARRAYLEN(g_aDCScopes); pScopes = g_aDCScopes; } else { pScopes = g_aDefaultScopes; cScopes = ARRAYLEN(g_aDefaultScopes); }
InitInfo.pwzTargetComputer = m_pMachineInfo->GetMachineName(); InitInfo.cDsScopeInfos = cScopes; InitInfo.aDsScopeInfos = (PDSOP_SCOPE_INIT_INFO)LocalAlloc(LPTR, sizeof(*pScopes)*cScopes); if (!InitInfo.aDsScopeInfos) { hr = E_OUTOFMEMORY; break; }
CopyMemory(InitInfo.aDsScopeInfos, pScopes, sizeof(*pScopes)*cScopes); InitInfo.cAttributesToFetch = ARRAYLEN(g_aszOPAttributes); InitInfo.apwzAttributeNames = (LPCTSTR*)g_aszOPAttributes; if (m_pMachineInfo->IsDC()) { for (ULONG i = 0; i < cScopes; i++) { // Set the DC name if appropriate
if(InitInfo.aDsScopeInfos[i].flType & DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN) { InitInfo.aDsScopeInfos[i].pwzDcName = InitInfo.pwzTargetComputer; } } } //Initialize the object picker
hr = m_spDsObjectPicker->Initialize(&InitInfo); if (SUCCEEDED(hr)) { m_bObjectPickerInitialized = TRUE; } if(InitInfo.aDsScopeInfos) LocalFree(InitInfo.aDsScopeInfos);
}while(0);
UnlockSidHandler(); return hr; }
//+----------------------------------------------------------------------------
// Synopsis: Pops up object pikcer. Function also does the sidlookop for
// objects selected. Information is returned in listSidCacheEntry
//-----------------------------------------------------------------------------
HRESULT CSidHandler:: GetUserGroup(IN HWND hDlg, IN CBaseAz* pOwnerAz, OUT CList<CBaseAz*,CBaseAz*>& listWindowsGroups) { if(!pOwnerAz) { ASSERT(pOwnerAz); return E_POINTER; }
TRACE_METHOD_EX(DEB_SNAPIN,CSidHandler,GetUserGroup)
HRESULT hr; LPDATAOBJECT pdoSelection = NULL; STGMEDIUM medium = {0}; FORMATETC fe = { (CLIPFORMAT)g_cfDsSelectionList, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; PDS_SELECTION_LIST pDsSelList = NULL; do {
// Create and initialize the Object Picker object
hr = InitObjectPicker(); if (FAILED(hr)) return hr;
// Bring up the object picker dialog
hr = m_spDsObjectPicker->InvokeDialog(hDlg, &pdoSelection); BREAK_ON_FAIL_HRESULT(hr);
//User Pressed cancel
if (S_FALSE == hr) { hr = S_OK; break; }
hr = pdoSelection->GetData(&fe, &medium); BREAK_ON_FAIL_HRESULT(hr);
pDsSelList = (PDS_SELECTION_LIST)GlobalLock(medium.hGlobal); if (!pDsSelList) { hr = E_FAIL; BREAK_ON_FAIL_HRESULT(hr); } CList<SID_CACHE_ENTRY*,SID_CACHE_ENTRY*> listSidCacheEntry; CList<SID_CACHE_ENTRY*,SID_CACHE_ENTRY*> listUnresolvedSidCacheEntry;
//Get the listof sidcache entries from pDsSelList
hr = GetSidCacheListFromOPOutput(pDsSelList, listSidCacheEntry, listUnresolvedSidCacheEntry); BREAK_ON_FAIL_HRESULT(hr);
//Resolve the sids not resolved in listSidCacheEntry
LookupSidsHelper(listUnresolvedSidCacheEntry, m_pMachineInfo->GetMachineName(), m_pMachineInfo->IsStandAlone(), m_pMachineInfo->IsDC(), FALSE); POSITION pos = listSidCacheEntry.GetHeadPosition(); for( int i = 0; i < listSidCacheEntry.GetCount(); ++i) { SID_CACHE_ENTRY* pSidCacheEntry = listSidCacheEntry.GetNext(pos); CSidCacheAz* pSidCacheAz = new CSidCacheAz(pSidCacheEntry, pOwnerAz); if(!pSidCacheAz) { hr = E_OUTOFMEMORY; break; } listWindowsGroups.AddTail(pSidCacheAz); } }while(0); if (pDsSelList) GlobalUnlock(medium.hGlobal);
ReleaseStgMedium(&medium); if(pdoSelection) pdoSelection->Release();
return hr; }
//+----------------------------------------------------------------------------
// Function:LookupSidsHelper
// Synopsis:Calls LsaLookupSid for sids in listSids. First it tries on
// strServerName machine and next it tries on DC( if possible).
// Arguments:listSidCacheEntry
// Returns:
//-----------------------------------------------------------------------------
VOID CSidHandler:: LookupSidsHelper(IN OUT CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY>& listSidCacheEntry, IN const CString& strServerName, IN BOOL bStandAlone, IN BOOL bIsDC, IN BOOL bSecondTry) { TRACE_METHOD_EX(DEB_SNAPIN,CSidHandler,LookupSidsHelper) PLSA_REFERENCED_DOMAIN_LIST pRefDomains = NULL; PLSA_TRANSLATED_NAME pTranslatedNames = NULL; LSA_HANDLE hlsa = NULL; CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY> listUnknownSids; PSID *ppSid = NULL;
if(!listSidCacheEntry.GetCount()) return;
do { //
//Open LsaConnection
//
hlsa = GetLSAConnection(strServerName, POLICY_LOOKUP_NAMES); if (NULL == hlsa && !strServerName.IsEmpty() && !bSecondTry) { CString strLocalMachine = L""; hlsa = GetLSAConnection(strLocalMachine, POLICY_LOOKUP_NAMES); } if (hlsa == NULL) { break; } //
//Now we have LSA Connection
//Do LookupSids
//
int cSids = (int)listSidCacheEntry.GetCount(); ppSid = new PSID[cSids]; if(!ppSid) { break; } POSITION pos = listSidCacheEntry.GetHeadPosition(); for (int i=0;i < cSids; i++) { PSID_CACHE_ENTRY pSidCacheEntry = listSidCacheEntry.GetNext(pos); ppSid[i] = pSidCacheEntry->GetSid(); }
DWORD dwStatus = 0;
dwStatus = LsaLookupSids(hlsa, cSids, ppSid, &pRefDomains, &pTranslatedNames);
if (STATUS_SUCCESS == dwStatus || STATUS_SOME_NOT_MAPPED == dwStatus || STATUS_NONE_MAPPED == dwStatus) { ASSERT(pTranslatedNames); ASSERT(pRefDomains);
//
// Build cache entries with NT4 style names
//
pos = listSidCacheEntry.GetHeadPosition(); for (int i = 0; i < cSids; i++) { PSID_CACHE_ENTRY pSidCacheEntry = listSidCacheEntry.GetNext(pos); PSID pSid = pSidCacheEntry->GetSid(); BOOL bNoCache = FALSE;
CString strAccountName; CString strDomainName; SID_NAME_USE sid_name_use; GetAccountAndDomainName(i, pTranslatedNames, pRefDomains, &strAccountName, &strDomainName, &sid_name_use); CString strLogonName; //
// Build NT4 "domain\user" style name
//
if (!strDomainName.IsEmpty() && !strAccountName.IsEmpty()) { strLogonName = strDomainName; strLogonName += L"\\"; strLogonName += strAccountName; }
switch (sid_name_use) { case SidTypeUser: { if(!bStandAlone) { // Get "User Principal Name" etc.
CString strNewLogonName; CString strNewAccountName; GetUserFriendlyName(strLogonName, &strNewLogonName, &strNewAccountName); if (!strNewLogonName.IsEmpty()) strLogonName = strNewLogonName; if (!strNewAccountName.IsEmpty()) strAccountName = strNewAccountName; } break; } case SidTypeGroup: case SidTypeDomain: break; case SidTypeAlias: { if (!IsAliasSid(pSid)) { sid_name_use = SidTypeGroup; break; } if(!m_pMachineInfo->GetTargetDomainFlat().IsEmpty() && !strAccountName.IsEmpty()) { strLogonName = m_pMachineInfo->GetTargetDomainFlat(); strLogonName += L"\\"; strLogonName += strAccountName; } break; } // else Fall Through
case SidTypeWellKnownGroup: { // No logon name for these
strLogonName.Empty(); break; } case SidTypeDeletedAccount: case SidTypeInvalid: // 7
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 && !bStandAlone && !bIsDC && !(m_pMachineInfo->GetDCName()).IsEmpty()) { //Add to unknown list
listUnknownSids.AddTail(pSidCacheEntry); bNoCache = TRUE; } break; } case SidTypeComputer: // 9
{ // TODO
// Strip the trailing '$'
break; } }
if (!bNoCache) { //Only one sidcahce entry per sid chache handler can
//be updated at a time. Which is fine.
LockSidCacheEntry(); pSidCacheEntry->AddNameAndType(sid_name_use, strAccountName, strLogonName); UnlockSidCacheEntry(); }
} }
}while(0); // Cleanup
if(pTranslatedNames) LsaFreeMemory(pTranslatedNames); if(pRefDomains) LsaFreeMemory(pRefDomains); if(hlsa) LsaClose(hlsa); if(ppSid) delete[] ppSid;
if (!listUnknownSids.IsEmpty()) { //
// 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.
//
LookupSidsHelper(listUnknownSids, m_pMachineInfo->GetDCName(), FALSE, TRUE, TRUE); } }
//+----------------------------------------------------------------------------
// Function: GetUserFriendlyName
// Synopsis: Gets name in Domain\Name format and returns UPN name and
// Display Name.
// Arguments:
// Returns:
//-----------------------------------------------------------------------------
void CSidHandler:: GetUserFriendlyName(IN const CString & strSamLogonName, OUT CString *pstrLogonName, OUT CString *pstrDisplayName) {
if(strSamLogonName.IsEmpty()|| !pstrLogonName || !pstrDisplayName) { ASSERT(strSamLogonName.IsEmpty()); ASSERT(!pstrLogonName); ASSERT(!pstrDisplayName); return; } //
// 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.
//
CString strFQDN; if (FAILED(TranslateNameInternal(strSamLogonName, NameSamCompatible, NameFullyQualifiedDN, &strFQDN))) { return; }
//
//Get UPN
//
TranslateNameInternal(strFQDN, NameFullyQualifiedDN, NameUserPrincipal, pstrLogonName);
//
//Get Display Name
//
TranslateNameInternal(strFQDN, NameFullyQualifiedDN, NameDisplay, pstrDisplayName); }
//+----------------------------------------------------------------------------
// Function: LookupSids
// Synopsis: Given a list of sids, retuns a list of corresponding
// CSidCacheAz objects
// Arguments:
// Returns:
//-----------------------------------------------------------------------------
HRESULT CSidHandler:: LookupSids(IN CBaseAz* pOwnerAz, IN CList<PSID,PSID>& listSids, OUT CList<CBaseAz*,CBaseAz*>& listSidCacheAz) { if(!pOwnerAz) { ASSERT(pOwnerAz); return E_POINTER; }
HRESULT hr = S_OK;
CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY> listSidCacheEntries; CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY> listUnResolvedSidCacheEntries;
hr = GetSidCacheListFromSidList(listSids, listSidCacheEntries, listUnResolvedSidCacheEntries); if(FAILED(hr)) { return hr; } //Do the Lookup for unresolved sids
LookupSidsHelper(listUnResolvedSidCacheEntries, m_pMachineInfo->GetMachineName(), m_pMachineInfo->IsStandAlone(), m_pMachineInfo->IsDC(), FALSE);
POSITION pos = listSidCacheEntries.GetHeadPosition(); for( int i = 0; i < listSidCacheEntries.GetCount(); ++i) { PSID_CACHE_ENTRY pSidCacheEntry = listSidCacheEntries.GetNext(pos); CSidCacheAz* pSidCacheAz = new CSidCacheAz(pSidCacheEntry, pOwnerAz); if(!pSidCacheAz) { hr = E_OUTOFMEMORY; break; } listSidCacheAz.AddTail(pSidCacheAz); }
if(FAILED(hr)) { RemoveItemsFromList(listSidCacheAz); } return hr; }
//+----------------------------------------------------------------------------
// Function: GetSidCacheListFromSidList
// Gets a list of sids and returns corresponding list of sidcache
// entries and unresolved sid cache entries
// Arguments:listSid: List of sids
// listSidCacheEntry: Gets list of SidCacheEntries
// listUnresolvedSidCacheEntry Gets List of unresolved
// SidCacheEntries
//-----------------------------------------------------------------------------
HRESULT CSidHandler:: GetSidCacheListFromSidList(IN CList<PSID,PSID>& listSid, OUT CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY>& listSidCacheEntry, OUT CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY>& listUnresolvedSidCacheEntry) { POSITION pos = listSid.GetHeadPosition(); for( int i = 0; i < listSid.GetCount(); ++i) { PSID pSid = listSid.GetNext(pos);
PSID_CACHE_ENTRY pEntry = GetEntryFromCache(pSid); if(!pEntry) { return E_OUTOFMEMORY; } listSidCacheEntry.AddTail(pEntry); if(!pEntry->IsSidResolved()) listUnresolvedSidCacheEntry.AddTail(pEntry); } return S_OK; }
//+----------------------------------------------------------------------------
// Function: GetSidCacheListFromOPOutput
// Synopsis: Gets the sid from Object Pickers output and returns corresponding
// list of SidCacheEntries. Also returns sids of unresolved sids.
//
// Arguments:pDsSelList selection list from OP.
// listSidCacheEntry: Gets list of SidCacheEntries
// listUnresolvedSidCacheEntry Gets List of unresolved
// SidCacheEntries
//-----------------------------------------------------------------------------
HRESULT CSidHandler:: GetSidCacheListFromOPOutput(IN PDS_SELECTION_LIST pDsSelList, OUT CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY>& listSidCacheEntry, OUT CList<PSID_CACHE_ENTRY,PSID_CACHE_ENTRY>& listUnresolvedSidCacheEntry) { if(!pDsSelList) { ASSERT(pDsSelList); return E_POINTER; }
HRESULT hr = S_OK; int cNames = pDsSelList->cItems; for (int i = 0; i < cNames; i++) { PSID pSid = NULL; LPVARIANT pvarSid = pDsSelList->aDsSelection[i].pvarFetchedAttributes;
if (NULL == pvarSid || (VT_ARRAY | VT_UI1) != V_VT(pvarSid) || FAILED(SafeArrayAccessData(V_ARRAY(pvarSid), &pSid))) { continue; }
PSID_CACHE_ENTRY pEntry = GetEntryFromCache(pSid); if(!pEntry) { return E_OUTOFMEMORY; } listSidCacheEntry.AddTail(pEntry); if(!pEntry->IsSidResolved()) listUnresolvedSidCacheEntry.AddTail(pEntry); } return S_OK; }
|