windows-nt/Source/XPSP1/NT/ds/adsi/router/sec2var.cxx

1560 lines
39 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: libmain.cxx
//
// Contents: LibMain for nds.dll
//
// Functions: LibMain, DllGetClassObject
//
// History: 25-Oct-94 KrishnaG Created.
//
//----------------------------------------------------------------------------
#include "oleds.hxx"
#pragma hdrstop
#define GetAce ADSIGetAce
#define DeleteAce ADSIDeleteAce
#define GetAclInformation ADSIGetAclInformation
#define SetAclInformation ADSISetAclInformation
#define IsValidAcl ADSIIsValidAcl
#define InitializeAcl ADSIInitializeAcl
extern HRESULT
ConvertSidToString(
PSID pSid,
LPWSTR String
);
DWORD
GetDomainDNSNameForDomain(
LPWSTR pszDomainFlatName,
BOOL fVerify,
BOOL fWriteable,
LPWSTR pszServerName,
LPWSTR pszDomainDNSName
);
//
// Helper routine.
//
PSID
ComputeSidFromAceAddress(
LPBYTE pAce
);
//+---------------------------------------------------------------------------
// Function: GetLsaPolicyHandle - helper routine.
//
// Synopsis: Returns the lsa policy handle to the server in question.
// If a serverName is present we will first try that. If no servername
// is present we will try and connect up to the default server for the
// currently logged on user. If everything else fails, we will
// connnect to the local machine (NULL server).
//
// Arguments: pszServerName - Name of targtet server/domain or NULL.
// Credentials - Credentials to use for the connection.
// Currently this is not used.
// phLsaPolicy - Return ptr for lsa policy handle.
//
// Returns: S_OK or any valid error code.
//
// Modifies: phLsaPolicy.
//
//----------------------------------------------------------------------------
HRESULT
GetLsaPolicyHandle(
LPWSTR pszServerName,
CCredentials &Credentials,
PLSA_HANDLE phLsaPolicy
)
{
HRESULT hr = S_OK;
DWORD dwStatus = NO_ERROR;
NTSTATUS ntStatus = STATUS_SUCCESS;
DWORD dwErr;
DWORD dwLen = 0;
LPWSTR pszServer = NULL;
BOOL fNullServer = FALSE;
LSA_OBJECT_ATTRIBUTES lsaObjectAttributes;
LSA_UNICODE_STRING lsaSystemName;
WCHAR szDomainName[MAX_PATH];
WCHAR szServerName[MAX_PATH];
memset(&lsaObjectAttributes, 0, sizeof(LSA_OBJECT_ATTRIBUTES));
//
// First most common case of serverless paths.
//
if (!pszServerName) {
dwStatus = GetDomainDNSNameForDomain(
NULL,
FALSE, // do not force verify
FALSE, // does not need to be writable
szServerName,
szDomainName
);
//
// If we succeeded we will use the name returned,
// otherwise we will go with NULL.
//
if (dwStatus == NO_ERROR) {
pszServer = szServerName;
}
else {
fNullServer = TRUE;
}
}
else {
pszServer = pszServerName;
}
if (pszServer) {
dwLen = wcslen(pszServer);
}
lsaSystemName.Buffer = pszServer;
lsaSystemName.Length = dwLen * sizeof(WCHAR);
lsaSystemName.MaximumLength = lsaSystemName.Length;
//
// First attempt at opening policy handle.
//
ntStatus = LsaOpenPolicy(
&lsaSystemName,
&lsaObjectAttributes,
POLICY_LOOKUP_NAMES,
phLsaPolicy
);
if (ntStatus != STATUS_SUCCESS) {
//
// Irrespective of failure should retry if we have not already
// tried with a NULL serverName.
//
if (!fNullServer) {
fNullServer = TRUE;
lsaSystemName.Buffer = NULL;
lsaSystemName.Length = 0;
lsaSystemName.MaximumLength = 0;
ntStatus = LsaOpenPolicy(
&lsaSystemName,
&lsaObjectAttributes,
POLICY_LOOKUP_NAMES,
phLsaPolicy
);
}
hr = HRESULT_FROM_WIN32(
LsaNtStatusToWinError(ntStatus)
);
BAIL_ON_FAILURE(hr);
}
error:
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: GetNamesFromSids - helper routine.
//
// Synopsis: Simple helper routine that calls LsaLookupSids and if the
// the error returned is ERROR_SOME_NOT_MAPPED, then the hr is
// set S_OK.
//
// Arguments: hLsaPolicy - LSA_HANDLE to do the lookup on.
// pSidArray - Array of sid's top lookup.
// dwSidCount - Number of sids to translate.
// ppLsaRefDomList - Ret value for domain list.
// ppLsaNames - Ret value for name list.
//
// Returns: S_OK or any valid error code.
//
// Modifies: n/a.
//
//----------------------------------------------------------------------------
HRESULT
GetNamesFromSids(
LSA_HANDLE hLsaPolicy,
PSID *pSidArray,
DWORD dwSidCount,
PLSA_REFERENCED_DOMAIN_LIST *ppLsaRefDomList,
PLSA_TRANSLATED_NAME *ppLsaNames
)
{
HRESULT hr;
NTSTATUS ntStatus;
ntStatus = LsaLookupSids(
hLsaPolicy,
dwSidCount,
pSidArray,
ppLsaRefDomList,
ppLsaNames
);
hr = HRESULT_FROM_WIN32(LsaNtStatusToWinError(ntStatus));
if (hr == HRESULT_FROM_WIN32(ERROR_SOME_NOT_MAPPED)) {
hr = S_OK;
}
RRETURN(hr);
}
//+---------------------------------------------------------------------------
// Function: GetNamesForSidFromArray - helper routine.
//
// Synopsis: Given the position of the ace and the retrun value from
// LsaLookupSids, constructs the actual name of the trustee.
//
// Arguments: dwAceNumber - Position of the ace in the array.
// pLsaRefDoms - List of reference domains.
// pLsaNames - List of LSA names.
// ppszFriendlyName - Return string pointer.
//
// Returns: S_OK or any valid error code.
//
// Modifies: n/a.
//
//----------------------------------------------------------------------------
HRESULT
GetNameForSidFromArray(
DWORD dwAceNumber,
LSA_REFERENCED_DOMAIN_LIST *pLsaRefDoms,
LSA_TRANSLATED_NAME *pLsaNames,
LPWSTR * ppszFriendlyName
)
{
HRESULT hr = S_OK;
DWORD dwLengthDomain;
DWORD dwLengthName = 0;
BOOL fDomainInvalid = FALSE;
BOOL fNameInvalid = FALSE;
LPWSTR pszName = NULL;
*ppszFriendlyName = NULL;
if (!pLsaNames) {
RRETURN(hr = E_FAIL);
}
switch (pLsaNames[dwAceNumber].Use) {
case SidTypeDomain:
fNameInvalid = TRUE;
break;
case SidTypeInvalid:
fNameInvalid = TRUE;
fDomainInvalid = TRUE;
break;
case SidTypeUnknown:
fNameInvalid = TRUE;
fDomainInvalid = TRUE;
break;
case SidTypeWellKnownGroup:
if (pLsaNames[dwAceNumber].DomainIndex < 0 ) {
fDomainInvalid = TRUE;
}
break;
default:
//
// Name and domain are valid.
//
fDomainInvalid = FALSE;
fNameInvalid = FALSE;
}
if (!fNameInvalid) {
dwLengthName = ((pLsaNames[dwAceNumber]).Name).Length + sizeof(WCHAR);
}
//
// Process domain if valid.
//
if (!fDomainInvalid) {
DWORD domainIndex = pLsaNames[dwAceNumber].DomainIndex;
LSA_UNICODE_STRING lsaString;
//
// Need to make sure that the index is valid.
//
if (domainIndex > pLsaRefDoms->Entries) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
lsaString = ((pLsaRefDoms->Domains)[domainIndex]).Name;
//
// Add sizeof(WCHAR) for the trailing \0.
//
dwLengthDomain = lsaString.Length + sizeof(WCHAR);
if (lsaString.Length > 0) {
pszName = (LPWSTR) AllocADsMem( dwLengthDomain + dwLengthName);
if (!pszName) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
memcpy(
pszName,
lsaString.Buffer,
lsaString.Length
);
}
}
if (!fNameInvalid) {
LSA_UNICODE_STRING lsaNameString = (pLsaNames[dwAceNumber]).Name;
//
// Length of pszName is zero if the group name is Everyone but
// there is still a domain name component.
//
if (!fDomainInvalid
&& pszName
&& wcslen(pszName)
) {
wcscat(pszName, L"\\");
} else {
pszName = (LPWSTR) AllocADsMem(dwLengthName);
if (!pszName) {
BAIL_ON_FAILURE (hr = E_OUTOFMEMORY);
}
}
memcpy(
fDomainInvalid ? pszName : (pszName + wcslen(pszName)),
lsaNameString.Buffer,
lsaNameString.Length
);
}
*ppszFriendlyName = pszName;
RRETURN(hr);
error:
if (pszName) {
FreeADsMem(pszName);
}
RRETURN(hr);
}
HRESULT
ConvertSecDescriptorToVariant(
LPWSTR pszServerName,
CCredentials& Credentials,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
VARIANT * pVarSec,
BOOL fNTDS
)
{
IADsSecurityDescriptor * pSecDes = NULL;
IDispatch * pDispatch = NULL;
LPWSTR pszGroup = NULL;
LPWSTR pszOwner = NULL;
BOOL fOwnerDefaulted = 0;
BOOL fGroupDefaulted = 0;
BOOL fDaclDefaulted = 0;
BOOL fSaclDefaulted = 0;
BOOL fSaclPresent = 0;
BOOL fDaclPresent = 0;
LPBYTE pOwnerSidAddress = NULL;
LPBYTE pGroupSidAddress = NULL;
LPBYTE pDACLAddress = NULL;
LPBYTE pSACLAddress = NULL;
DWORD dwRet = 0;
VARIANT varDACL;
VARIANT varSACL;
HRESULT hr = S_OK;
DWORD dwRevision = 0;
WORD wControl = 0;
VariantInit(pVarSec);
memset(&varSACL, 0, sizeof(VARIANT));
memset(&varDACL, 0, sizeof(VARIANT));
if (!pSecurityDescriptor) {
RRETURN(E_FAIL);
}
//
// Control & Revision
//
dwRet = GetSecurityDescriptorControl(
pSecurityDescriptor,
&wControl,
&dwRevision
);
if (!dwRet){
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
//
// Owner
//
dwRet = GetSecurityDescriptorOwner(
pSecurityDescriptor,
(PSID *)&pOwnerSidAddress,
&fOwnerDefaulted
);
if (!dwRet){
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
if (pOwnerSidAddress) {
//
// For Owner and Group, we will convert the sid in old way without optimization
//
hr = ConvertSidToFriendlyName2(
pszServerName,
Credentials,
pOwnerSidAddress,
&pszOwner,
fNTDS
);
BAIL_ON_FAILURE(hr);
}
//
// Group
//
dwRet = GetSecurityDescriptorGroup(
pSecurityDescriptor,
(PSID *)&pGroupSidAddress,
&fOwnerDefaulted
);
if (!dwRet){
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
if (pGroupSidAddress) {
//
// For Owner and Group, we will convert the sid in old way without optimization
//
hr = ConvertSidToFriendlyName2(
pszServerName,
Credentials,
pGroupSidAddress,
&pszGroup,
fNTDS
);
BAIL_ON_FAILURE(hr);
}
//
// DACL
//
dwRet = GetSecurityDescriptorDacl(
pSecurityDescriptor,
&fDaclPresent,
(PACL*)&pDACLAddress,
&fDaclDefaulted
);
if (!dwRet){
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
if (pDACLAddress) {
hr = ConvertACLToVariant(
pszServerName,
Credentials,
(PACL)pDACLAddress,
&varDACL,
fNTDS
);
BAIL_ON_FAILURE(hr);
}
//
// SACL
//
dwRet = GetSecurityDescriptorSacl(
pSecurityDescriptor,
&fSaclPresent,
(PACL *)&pSACLAddress,
&fSaclDefaulted
);
if (!dwRet){
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
if (pSACLAddress) {
hr = ConvertACLToVariant(
pszServerName,
Credentials,
(PACL)pSACLAddress,
&varSACL,
fNTDS
);
BAIL_ON_FAILURE(hr);
}
//
// Construct an IADsSecurityDescriptor with the data
// retrieved from the raw SD
//
hr = CoCreateInstance(
CLSID_SecurityDescriptor,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsSecurityDescriptor,
(void **)&pSecDes
);
BAIL_ON_FAILURE(hr);
hr = pSecDes->put_Owner(pszOwner);
BAIL_ON_FAILURE(hr);
hr = pSecDes->put_Group(pszGroup);
BAIL_ON_FAILURE(hr);
hr = pSecDes->put_Revision(dwRevision);
BAIL_ON_FAILURE(hr);
hr = pSecDes->put_Control((DWORD)wControl);
BAIL_ON_FAILURE(hr);
hr = pSecDes->put_DiscretionaryAcl(V_DISPATCH(&varDACL));
BAIL_ON_FAILURE(hr);
hr = pSecDes->put_SystemAcl(V_DISPATCH(&varSACL));
BAIL_ON_FAILURE(hr);
hr = pSecDes->QueryInterface(IID_IDispatch, (void**)&pDispatch);
BAIL_ON_FAILURE(hr);
//
// Construct a VARIANT with the IADsSecurityDescriptor
//
V_VT(pVarSec) = VT_DISPATCH;
V_DISPATCH(pVarSec) = pDispatch;
error:
VariantClear(&varSACL);
VariantClear(&varDACL);
if (pszOwner) {
FreeADsStr(pszOwner);
}
if (pszGroup) {
FreeADsStr(pszGroup);
}
if (pSecDes) {
pSecDes->Release();
}
RRETURN(hr);
}
HRESULT
ConvertSidToFriendlyName(
LPWSTR pszServerName,
CCredentials& Credentials,
PSID pSid,
LPWSTR * ppszAccountName,
BOOL fNTDS
)
{
HRESULT hr = S_OK;
SID_NAME_USE eUse;
WCHAR szAccountName[MAX_PATH];
WCHAR szDomainName[MAX_PATH];
WCHAR szServerName[MAX_PATH];
DWORD dwLen = 0;
DWORD dwRet = 0;
LPWSTR pszAccountName = NULL;
DWORD dwAcctLen = 0;
DWORD dwDomainLen = 0;
#if 0
/**************************************************************
//
// parse Trustee and determine whether its NTDS or U2
//
if (fNTDS) {
dwAcctLen = sizeof(szAccountName);
dwDomainLen = sizeof(szDomainName);
dwRet = LookupAccountSid(
pszServerName,
pSid,
szAccountName,
&dwAcctLen,
szDomainName,
&dwDomainLen,
(PSID_NAME_USE)&eUse
);
//
// Try with NULL server name if we have not already
// done that for error cases.
//
if (!dwRet && pszServerName) {
dwRet = LookupAccountSid(
NULL,
pSid,
szAccountName,
&dwAcctLen,
szDomainName,
&dwDomainLen,
(PSID_NAME_USE)&eUse
);
}
//
// If using serverless paths, try it on the DC if it
// failed (which will happen if we're trying to resolve
// something like "BUILTIN\Print Operators" on a member
// computer)
//
if (!dwRet && !pszServerName) {
dwAcctLen = sizeof(szAccountName);
dwDomainLen = sizeof(szDomainName);
DWORD dwStatus = GetDomainDNSNameForDomain(
NULL,
FALSE, // don't force verify
FALSE, // not writable
szServerName,
szDomainName
);
if (dwStatus == NO_ERROR) {
dwRet = LookupAccountSid(
szServerName,
pSid,
szAccountName,
&dwAcctLen,
szDomainName,
&dwDomainLen,
(PSID_NAME_USE)&eUse
);
//
// If the lookup failed because the server was unavailable, try to get
// the server again, this time forcing DsGetDcName to do rediscovery
//
if (!dwRet && (GetLastError() == RPC_S_SERVER_UNAVAILABLE)) {
dwStatus = GetDomainDNSNameForDomain(
NULL,
TRUE, // force verify
FALSE,// not writable
szServerName,
szDomainName
);
if (dwStatus == NO_ERROR) {
dwRet = LookupAccountSid(
szServerName,
pSid,
szAccountName,
&dwAcctLen,
szDomainName,
&dwDomainLen,
(PSID_NAME_USE)&eUse
);
}
}
}
}
if (!dwRet) {
hr = HRESULT_FROM_WIN32(GetLastError());
}else {
dwLen = wcslen(szAccountName) + wcslen(szDomainName) + 1 + 1;
pszAccountName = (LPWSTR)AllocADsMem(dwLen * sizeof(WCHAR));
if (!pszAccountName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
if (szDomainName[0] && szAccountName[0]) {
wsprintf(pszAccountName,L"%s\\%s",szDomainName, szAccountName);
}else if (szAccountName[0]) {
wsprintf(pszAccountName,L"%s", szAccountName);
}
*ppszAccountName = pszAccountName;
}
}else {
*****************************************************************/
#endif
if (!fNTDS) {
hr = ConvertSidToU2Trustee(
pszServerName,
Credentials,
pSid,
szAccountName
);
if (SUCCEEDED(hr)) {
pszAccountName = AllocADsStr(szAccountName);
if (!pszAccountName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
*ppszAccountName = pszAccountName;
}
}
else {
//
// This is NTDS case where we need to stringize SID.
//
hr = E_FAIL;
}
if (FAILED(hr)) {
hr = ConvertSidToString(
pSid,
szAccountName
);
BAIL_ON_FAILURE(hr);
pszAccountName = AllocADsStr(szAccountName);
if (!pszAccountName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
*ppszAccountName = pszAccountName;
}
error:
RRETURN(hr);
}
HRESULT
ConvertSidToFriendlyName2(
LPWSTR pszServerName,
CCredentials& Credentials,
PSID pSid,
LPWSTR * ppszAccountName,
BOOL fNTDS
)
{
HRESULT hr = S_OK;
SID_NAME_USE eUse;
WCHAR szAccountName[MAX_PATH];
WCHAR szDomainName[MAX_PATH];
WCHAR szServerName[MAX_PATH];
DWORD dwLen = 0;
DWORD dwRet = 0;
LPWSTR pszAccountName = NULL;
DWORD dwAcctLen = 0;
DWORD dwDomainLen = 0;
//
// parse Trustee and determine whether its NTDS or U2
//
if (fNTDS) {
dwAcctLen = sizeof(szAccountName);
dwDomainLen = sizeof(szDomainName);
//
// Servername is specified
//
if (pszServerName) {
dwRet = LookupAccountSid(
pszServerName,
pSid,
szAccountName,
&dwAcctLen,
szDomainName,
&dwDomainLen,
(PSID_NAME_USE)&eUse
);
}
//
// Servername not specified
//
else {
//
// If using serverless paths, try it first on the DC
//
DWORD dwStatus = GetDomainDNSNameForDomain(
NULL,
FALSE, // don't force verify
FALSE, // not writable
szServerName,
szDomainName
);
if (dwStatus == NO_ERROR) {
dwRet = LookupAccountSid(
szServerName,
pSid,
szAccountName,
&dwAcctLen,
szDomainName,
&dwDomainLen,
(PSID_NAME_USE)&eUse
);
//
// If the lookup failed because the server was unavailable, try to get
// the server again, this time forcing DsGetDcName to do rediscovery
//
if (!dwRet && (GetLastError() == RPC_S_SERVER_UNAVAILABLE)) {
dwStatus = GetDomainDNSNameForDomain(
NULL,
TRUE, // force verify
FALSE,// not writable
szServerName,
szDomainName
);
if (dwStatus == NO_ERROR) {
dwRet = LookupAccountSid(
szServerName,
pSid,
szAccountName,
&dwAcctLen,
szDomainName,
&dwDomainLen,
(PSID_NAME_USE)&eUse
);
}
}
}
}
//
// At last try with NULL server name
//
if (!dwRet) {
dwAcctLen = sizeof(szAccountName);
dwDomainLen = sizeof(szDomainName);
dwRet = LookupAccountSid(
NULL,
pSid,
szAccountName,
&dwAcctLen,
szDomainName,
&dwDomainLen,
(PSID_NAME_USE)&eUse
);
}
if (!dwRet) {
hr = HRESULT_FROM_WIN32(GetLastError());
}else {
dwLen = wcslen(szAccountName) + wcslen(szDomainName) + 1 + 1;
pszAccountName = (LPWSTR)AllocADsMem(dwLen * sizeof(WCHAR));
if (!pszAccountName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
if (szDomainName[0] && szAccountName[0]) {
wsprintf(pszAccountName,L"%s\\%s",szDomainName, szAccountName);
}else if (szAccountName[0]) {
wsprintf(pszAccountName,L"%s", szAccountName);
}
*ppszAccountName = pszAccountName;
}
}
else {
hr = ConvertSidToU2Trustee(
pszServerName,
Credentials,
pSid,
szAccountName
);
if (SUCCEEDED(hr)) {
pszAccountName = AllocADsStr(szAccountName);
if (!pszAccountName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
*ppszAccountName = pszAccountName;
}
}
if (FAILED(hr)) {
hr = ConvertSidToString(
pSid,
szAccountName
);
BAIL_ON_FAILURE(hr);
pszAccountName = AllocADsStr(szAccountName);
if (!pszAccountName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
*ppszAccountName = pszAccountName;
}
error:
RRETURN(hr);
}
HRESULT
ConvertACLToVariant(
LPWSTR pszServerName,
CCredentials& Credentials,
PACL pACL,
PVARIANT pvarACL,
BOOL fNTDS
)
{
IADsAccessControlList * pAccessControlList = NULL;
IDispatch * pDispatch = NULL;
LPWSTR pszFriendlyName = NULL;
VARIANT varAce;
DWORD dwAclSize = 0;
DWORD dwAclRevision = 0;
DWORD dwAceCount = 0;
ACL_SIZE_INFORMATION AclSize;
ACL_REVISION_INFORMATION AclRevision;
DWORD dwStatus = 0;
DWORD i = 0;
DWORD dwNewAceCount = 0;
HRESULT hr = S_OK;
LPBYTE pAceAddress = NULL;
LSA_HANDLE hLsaPolicy = NULL;
PLSA_REFERENCED_DOMAIN_LIST pLsaRefDomList = NULL;
PLSA_TRANSLATED_NAME pLsaNames = NULL;
PSID *pSidArray = NULL;
memset(&AclSize, 0, sizeof(ACL_SIZE_INFORMATION));
memset(&AclRevision, 0, sizeof(ACL_REVISION_INFORMATION));
dwStatus = GetAclInformation(
pACL,
&AclSize,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation
);
//
// Status should be nonzero for success
//
if (!dwStatus) {
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
dwStatus = GetAclInformation(
pACL,
&AclRevision,
sizeof(ACL_REVISION_INFORMATION),
AclRevisionInformation
);
if (!dwStatus) {
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
dwAceCount = AclSize.AceCount;
dwAclRevision = AclRevision.AclRevision;
VariantInit(pvarACL);
hr = CoCreateInstance(
CLSID_AccessControlList,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsAccessControlList,
(void **)&pAccessControlList
);
BAIL_ON_FAILURE(hr);
//
// Do this only when we actually have ACE
//
if(dwAceCount > 0) {
//
// Sid lookup can be optimized only for NT style SD's.
// SiteServer style SD's will continue to be processed as before.
//
if (fNTDS) {
//
// To speed up the conversion of SID's to trustees, an array of
// SID's to lookup is built and the whole array processed in one
// shot. Then the result of the Lookup is used in contstructing
// the individual ACE's.
//
pSidArray = (PSID*) AllocADsMem(sizeof(PSID) * dwAceCount);
if (!pSidArray) {
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
}
for (i = 0; i < dwAceCount; i++) {
dwStatus = GetAce(pACL, i , (void **) &pAceAddress);
if (!dwStatus) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
}
pSidArray[i] = ComputeSidFromAceAddress(pAceAddress);
//
// Sanity check we should always have valid data.
//
if (!pSidArray[i]) {
BAIL_ON_FAILURE(hr = E_FAIL);
}
}
hr = GetLsaPolicyHandle(
pszServerName,
Credentials,
&hLsaPolicy
);
//
// Should we just convert to string SID's ?
//
BAIL_ON_FAILURE(hr);
hr = GetNamesFromSids(
hLsaPolicy,
pSidArray,
dwAceCount,
&pLsaRefDomList,
&pLsaNames
);
BAIL_ON_FAILURE(hr);
}
for (i = 0; i < dwAceCount; i++) {
if (pszFriendlyName) {
FreeADsStr(pszFriendlyName);
pszFriendlyName = NULL;
}
dwStatus = GetAce(pACL, i, (void **)&pAceAddress);
//
// Need to verify we got back the ace correctly.
//
if (!dwStatus) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
}
if(fNTDS) {
hr = GetNameForSidFromArray(
i,
pLsaRefDomList,
pLsaNames,
&pszFriendlyName
);
}
//
// We can ignore the failure.
// On failure pszFriendlyName is set to NULL in which case
// we will convert to stringised sid format (for NTDS of course).
//
hr = ConvertAceToVariant(
pszServerName,
pszFriendlyName,
Credentials,
pAceAddress,
(PVARIANT)&varAce,
fNTDS
);
//
// If we cannot convert an ACE we should error out.
//
BAIL_ON_FAILURE(hr);
hr = pAccessControlList->AddAce(V_DISPATCH(&varAce));
BAIL_ON_FAILURE(hr);
dwNewAceCount++;
VariantClear(&varAce);
}
}
pAccessControlList->put_AclRevision(dwAclRevision);
pAccessControlList->put_AceCount(dwNewAceCount);
hr = pAccessControlList->QueryInterface(
IID_IDispatch,
(void **)&pDispatch
);
V_VT(pvarACL) = VT_DISPATCH;
V_DISPATCH(pvarACL) = pDispatch;
error:
if (pAccessControlList) {
pAccessControlList->Release();
}
if (pszFriendlyName) {
FreeADsStr(pszFriendlyName);
}
if (pLsaNames) {
LsaFreeMemory(pLsaNames);
}
if (pLsaRefDomList) {
LsaFreeMemory(pLsaRefDomList);
}
if (hLsaPolicy) {
LsaClose(hLsaPolicy);
}
if(pSidArray) {
FreeADsMem(pSidArray);
}
RRETURN(hr);
}
HRESULT
ConvertAceToVariant(
LPWSTR pszServerName,
LPWSTR pszTrusteeName,
CCredentials& Credentials,
PBYTE pAce,
PVARIANT pvarAce,
BOOL fNTDS
)
{
IADsAccessControlEntry * pAccessControlEntry = NULL;
IDispatch * pDispatch = NULL;
IADsAcePrivate *pPrivAce = NULL;
DWORD dwAceType = 0;
DWORD dwAceFlags = 0;
DWORD dwAccessMask = 0;
DWORD dwLenSid = 0;
DWORD dwErr = 0;
LPWSTR pszAccountName = NULL;
PACE_HEADER pAceHeader = NULL;
LPBYTE pSidAddress = NULL;
LPBYTE pOffset = NULL;
DWORD dwFlags = 0;
GUID ObjectGUID;
GUID InheritedObjectGUID;
BSTR bstrObjectGUID = NULL;
BSTR bstrInheritedObjectGUID = NULL;
HRESULT hr = S_OK;
VariantInit(pvarAce);
hr = CoCreateInstance(
CLSID_AccessControlEntry,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsAccessControlEntry,
(void **)&pAccessControlEntry
);
BAIL_ON_FAILURE(hr);
pAceHeader = (ACE_HEADER *)pAce;
dwAceType = pAceHeader->AceType;
dwAceFlags = pAceHeader->AceFlags;
dwAccessMask = *(PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
switch (dwAceType) {
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
case SYSTEM_AUDIT_ACE_TYPE:
case SYSTEM_ALARM_ACE_TYPE:
pSidAddress = (LPBYTE)pAceHeader + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK);
break;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
pOffset = (LPBYTE)((LPBYTE)pAceHeader + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
dwFlags = (DWORD)(*(PDWORD)pOffset);
//
// Now advance by the size of the flags
//
pOffset += sizeof(ULONG);
if (dwFlags & ACE_OBJECT_TYPE_PRESENT) {
memcpy(&ObjectGUID, pOffset, sizeof(GUID));
hr = BuildADsGuid(ObjectGUID, &bstrObjectGUID);
BAIL_ON_FAILURE(hr);
pOffset += sizeof (GUID);
}
if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) {
memcpy(&InheritedObjectGUID, pOffset, sizeof(GUID));
hr = BuildADsGuid(InheritedObjectGUID, &bstrInheritedObjectGUID);
BAIL_ON_FAILURE(hr);
pOffset += sizeof (GUID);
}
pSidAddress = pOffset;
break;
default:
break;
}
if (pSidAddress) {
//
// Nt4 does not reset the last error correctly.
//
SetLastError(NO_ERROR);
dwLenSid = GetLengthSid(pSidAddress);
if ((dwErr = GetLastError()) != NO_ERROR) {
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwErr));
}
}
else {
//
// We should always have a valid sid address here.
// Should we be bailing here ? Or for that matter,
// should be bail on the default cluase of the switch ?
//
dwLenSid = 0;
}
//
// Call the old function only if we could not resolve the name
//
if (!pszTrusteeName) {
hr = ConvertSidToFriendlyName(
pszServerName,
Credentials,
pSidAddress,
&pszAccountName,
fNTDS
);
}
if (FAILED(hr)){
pszAccountName = AllocADsStr(L"Unknown Trustee");
if (!pszAccountName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
}
//
// Now set all the information in the Access Control Entry
//
hr = pAccessControlEntry->put_AccessMask(dwAccessMask);
hr = pAccessControlEntry->put_AceFlags(dwAceFlags);
hr = pAccessControlEntry->put_AceType(dwAceType);
//
// Extended ACE information
//
hr = pAccessControlEntry->put_Flags(dwFlags);
if (dwFlags & ACE_OBJECT_TYPE_PRESENT) {
//
// Add in the Object Type GUID
//
hr = pAccessControlEntry->put_ObjectType(bstrObjectGUID);
}
if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) {
//
// Add in the Inherited Object Type GUID
//
hr = pAccessControlEntry->put_InheritedObjectType(
bstrInheritedObjectGUID
);
}
//
// This is a string, so need to check the ecode. We use the
// friendlyName if that was set and if not the pszAccountName.
//
hr = pAccessControlEntry->put_Trustee(
pszTrusteeName ?
pszTrusteeName :
pszAccountName
);
BAIL_ON_FAILURE(hr);
if (pSidAddress) {
//
// We should now put the SID on this ACE for quick reverse lookup.
//
hr = pAccessControlEntry->QueryInterface(
IID_IADsAcePrivate,
(void **)&pPrivAce
);
if SUCCEEDED(hr) {
hr = pPrivAce->putSid(
pSidAddress,
dwLenSid
);
}
//
// No bail on failure here as it is not a critical failure
//
}
hr = pAccessControlEntry->QueryInterface(
IID_IDispatch,
(void **)&pDispatch
);
BAIL_ON_FAILURE(hr);
V_DISPATCH(pvarAce) = pDispatch;
V_VT(pvarAce) = VT_DISPATCH;
cleanup:
if (pszAccountName) {
FreeADsStr(pszAccountName);
}
if (pAccessControlEntry) {
pAccessControlEntry->Release();
}
if (pPrivAce) {
pPrivAce->Release();
}
if (bstrObjectGUID) {
ADsFreeString(bstrObjectGUID);
}
if (bstrInheritedObjectGUID) {
ADsFreeString(bstrInheritedObjectGUID);
}
RRETURN(hr);
error:
if (pDispatch) {
pDispatch->Release();
}
goto cleanup;
}
//+---------------------------------------------------------------------------
// Function: ComputeSidFromAceAddress - helper routine.
//
// Synopsis: Returns the pointer to the SID, given a ptr to an ACE.
//
// Arguments: pAce - ptr to the ACE.
//
// Returns: NULL on error or valid PSID.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
PSID
ComputeSidFromAceAddress(
LPBYTE pAce
)
{
PSID pSidRetVal = NULL;
PACE_HEADER pAceHeader = NULL;
LPBYTE pOffset = NULL;
DWORD dwAceType, dwAceFlags, dwAccessMask;
DWORD dwFlags;
pAceHeader = (ACE_HEADER *)pAce;
dwAceType = pAceHeader->AceType;
dwAceFlags = pAceHeader->AceFlags;
dwAccessMask = *(PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
switch (dwAceType) {
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
case SYSTEM_AUDIT_ACE_TYPE:
case SYSTEM_ALARM_ACE_TYPE:
pSidRetVal = (LPBYTE)pAceHeader
+ sizeof(ACE_HEADER)
+ sizeof(ACCESS_MASK);
break;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
case ACCESS_DENIED_OBJECT_ACE_TYPE:
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
pOffset = (LPBYTE)((LPBYTE)pAceHeader
+ sizeof(ACE_HEADER)
+ sizeof(ACCESS_MASK)
);
dwFlags = (DWORD)(*(PDWORD)pOffset);
//
// Now advance by the size of the flags
//
pOffset += sizeof(ULONG);
if (dwFlags & ACE_OBJECT_TYPE_PRESENT) {
pOffset += sizeof (GUID);
}
if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) {
pOffset += sizeof (GUID);
}
pSidRetVal = pOffset;
break;
default:
break;
} // end of switch case.
return pSidRetVal;
}