You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1279 lines
35 KiB
1279 lines
35 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
|