Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

2511 lines
55 KiB

/*++
Copyright (c) 1995-1999 Microsoft Corporation
Module Name:
rndsec.cpp
Abstract:
Security utilities for Rendezvous Control.
Author:
KrishnaG (from OLEDS team)
Environment:
User Mode - Win32
Revision History:
12-Dec-1997 DonRyan
Munged KrishnaG's code to work with Rendezvous Control.
--*/
///////////////////////////////////////////////////////////////////////////////
// //
// Include files //
// //
///////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <security.h>
#include <initguid.h>
#include <iads.h>
#include <ntlsa.h>
#include <stdlib.h>
#include <limits.h>
#include <io.h>
#include <wchar.h>
#include <tchar.h>
#include "rndsec.h"
///////////////////////////////////////////////////////////////////////////////
// //
// Private macros //
// //
///////////////////////////////////////////////////////////////////////////////
#define BAIL_ON_FAILURE(hr) \
if (FAILED(hr)) { goto error; }
#define CONTINUE_ON_FAILURE(hr) \
if (FAILED(hr)) { continue; }
///////////////////////////////////////////////////////////////////////////////
// //
// Private procedures //
// //
///////////////////////////////////////////////////////////////////////////////
LPWSTR
AllocADsStr(
LPWSTR pStr
)
{
LPWSTR pMem;
if (!pStr)
return NULL;
if (pMem = new WCHAR[wcslen(pStr) + 1])
wcscpy(pMem, pStr);
return pMem;
}
HRESULT
ConvertSidToString(
PSID pSid,
LPWSTR String
)
/*++
Routine Description:
This function generates a printable unicode string representation
of a SID.
The resulting string will take one of two forms. If the
IdentifierAuthority value is not greater than 2^32, then
the SID will be in the form:
S-1-281736-12-72-9-110
^ ^^ ^^ ^ ^^^
| | | | |
+-----+--+-+--+---- Decimal
Otherwise it will take the form:
S-1-0x173495281736-12-72-9-110
^^^^^^^^^^^^^^ ^^ ^^ ^ ^^^
Hexidecimal | | | |
+--+-+--+---- Decimal
Arguments:
pSid - opaque pointer that supplies the SID that is to be
converted to Unicode.
Return Value:
If the Sid is successfully converted to a Unicode string, a
pointer to the Unicode string is returned, else NULL is
returned.
--*/
{
WCHAR Buffer[256];
UCHAR i;
ULONG Tmp;
HRESULT hr = S_OK;
SID_IDENTIFIER_AUTHORITY *pSidIdentifierAuthority;
PUCHAR pSidSubAuthorityCount;
//
// IsValidSid fiers an AV is pSid == NULL
//
if( NULL == pSid )
{
*String= L'\0';
hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
return(hr);
}
if (!IsValidSid( pSid )) {
*String= L'\0';
hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
return(hr);
}
wsprintf(Buffer, L"S-%u-", (USHORT)(((PISID)pSid)->Revision ));
wcscpy(String, Buffer);
pSidIdentifierAuthority = GetSidIdentifierAuthority(pSid);
if ( (pSidIdentifierAuthority->Value[0] != 0) ||
(pSidIdentifierAuthority->Value[1] != 0) ){
wsprintf(Buffer, L"0x%02hx%02hx%02hx%02hx%02hx%02hx",
(USHORT)pSidIdentifierAuthority->Value[0],
(USHORT)pSidIdentifierAuthority->Value[1],
(USHORT)pSidIdentifierAuthority->Value[2],
(USHORT)pSidIdentifierAuthority->Value[3],
(USHORT)pSidIdentifierAuthority->Value[4],
(USHORT)pSidIdentifierAuthority->Value[5] );
wcscat(String, Buffer);
} else {
Tmp = (ULONG)pSidIdentifierAuthority->Value[5] +
(ULONG)(pSidIdentifierAuthority->Value[4] << 8) +
(ULONG)(pSidIdentifierAuthority->Value[3] << 16) +
(ULONG)(pSidIdentifierAuthority->Value[2] << 24);
wsprintf(Buffer, L"%lu", Tmp);
wcscat(String, Buffer);
}
pSidSubAuthorityCount = GetSidSubAuthorityCount(pSid);
for (i=0;i< *(pSidSubAuthorityCount);i++ ) {
wsprintf(Buffer, L"-%lu", *(GetSidSubAuthority(pSid, i)));
wcscat(String, Buffer);
}
return(S_OK);
}
HRESULT
ConvertSidToFriendlyName(
PSID pSid,
LPWSTR * ppszAccountName
)
{
HRESULT hr = S_OK;
SID_NAME_USE eUse;
WCHAR szAccountName[MAX_PATH];
WCHAR szDomainName[MAX_PATH];
DWORD dwLen = 0;
DWORD dwRet = 0;
LPWSTR pszAccountName = NULL;
DWORD dwAcctLen = 0;
DWORD dwDomainLen = 0;
dwAcctLen = sizeof(szAccountName);
dwDomainLen = sizeof(szDomainName);
dwRet = LookupAccountSid(
NULL,
pSid,
szAccountName,
&dwAcctLen,
szDomainName,
&dwDomainLen,
(PSID_NAME_USE)&eUse
);
if (!dwRet) {
hr = ConvertSidToString(
pSid,
szAccountName
);
BAIL_ON_FAILURE(hr);
pszAccountName = AllocADsStr(szAccountName);
if (!pszAccountName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
*ppszAccountName = pszAccountName;
}else {
dwLen = wcslen(szAccountName) + wcslen(szDomainName) + 1 + 1;
pszAccountName = new WCHAR [dwLen];
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;
}
error:
return(hr);
}
//
// Converts an ACE to a variant, but leaves the trustee name unset.
// Instead it returns a pointer to the SID in this ACE, so that
// we can go back and convert all the SIDs to trustee names at once
// and set them on the ACEs later.
//
HRESULT
ConvertAceToVariant(
PBYTE pAce,
LPVARIANT pvarAce,
PSID * ppSid
)
{
IADsAccessControlEntry * pAccessControlEntry = NULL;
IDispatch * pDispatch = NULL;
DWORD dwAceType = 0;
DWORD dwAceFlags = 0;
DWORD dwAccessMask = 0;
PACE_HEADER pAceHeader = NULL;
LPBYTE pSidAddress = NULL;
LPBYTE pOffset = NULL;
DWORD dwFlags = 0;
GUID ObjectGUID;
GUID InheritedObjectGUID;
WCHAR szObjectGUID[MAX_PATH];
WCHAR szInheritedObjectGUID[MAX_PATH];
HRESULT hr = S_OK;
szObjectGUID[0] = L'\0';
szInheritedObjectGUID[0] = L'\0';
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));
StringFromGUID2(ObjectGUID, szObjectGUID, MAX_PATH);
pOffset += sizeof (GUID);
}
if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) {
memcpy(&InheritedObjectGUID, pOffset, sizeof(GUID));
StringFromGUID2(InheritedObjectGUID, szInheritedObjectGUID, MAX_PATH);
pOffset += sizeof (GUID);
}
pSidAddress = pOffset;
break;
default:
break;
}
//
// return a pointer to the SID for this ACE, rather than converting the
// SID to a trustee name (and taking forever for a large ACL)
//
*ppSid = (PSID) pSidAddress;
//
// 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(szObjectGUID);
}
if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) {
//
// Add in the Inherited Object Type GUID
//
hr = pAccessControlEntry->put_InheritedObjectType(szInheritedObjectGUID);
}
hr = pAccessControlEntry->QueryInterface(
IID_IDispatch,
(void **)&pDispatch
);
BAIL_ON_FAILURE(hr);
V_DISPATCH(pvarAce) = pDispatch;
V_VT(pvarAce) = VT_DISPATCH;
cleanup:
if (pAccessControlEntry) {
pAccessControlEntry->Release();
}
return(hr);
error:
if (pDispatch) {
pDispatch->Release();
}
goto cleanup;
}
BOOL
APIENTRY
LookupArrayOfSids(
DWORD dwCount,
PSID * ppSids,
LSA_REFERENCED_DOMAIN_LIST ** ppDomains,
LSA_TRANSLATED_NAME ** ppTrustees
)
{
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains;
PLSA_TRANSLATED_NAME Names;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
OBJECT_ATTRIBUTES ObjectAttributes;
LSA_HANDLE PolicyHandle;
NTSTATUS Status;
NTSTATUS TmpStatus;
SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
SecurityQualityOfService.EffectiveOnly = FALSE;
//
// Set up the object attributes prior to opening the LSA.
//
InitializeObjectAttributes(
&ObjectAttributes,
NULL,
0L,
NULL,
NULL
);
//
// The InitializeObjectAttributes macro presently stores NULL for
// the SecurityQualityOfService field, so we must manually copy that
// structure for now.
//
ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
Status = LsaOpenPolicy(
NULL,
&ObjectAttributes,
POLICY_LOOKUP_NAMES,
&PolicyHandle
);
if ( !NT_SUCCESS( Status )) {
// BaseSetLastNTError( Status );
return( FALSE );
}
Status = LsaLookupSids(
PolicyHandle,
dwCount,
ppSids,
ppDomains,
ppTrustees
);
TmpStatus = LsaClose( PolicyHandle );
//
// If an error was returned, check specifically for STATUS_NONE_MAPPED.
// In this case, we may need to dispose of the returned Referenced Domain
// List and Names structures. For all other errors, LsaLookupSids()
// frees these structures prior to exit.
//
if ( !NT_SUCCESS( Status ))
{
if (Status == STATUS_NONE_MAPPED)
{
if ( *ppDomains != NULL)
{
TmpStatus = LsaFreeMemory( *ppDomains );
_ASSERTE( NT_SUCCESS( TmpStatus ));
*ppDomains = NULL;
}
if ( *ppTrustees != NULL) {
TmpStatus = LsaFreeMemory( *ppTrustees );
_ASSERTE( NT_SUCCESS( TmpStatus ));
*ppTrustees = NULL;
}
}
// BaseSetLastNTError( Status );
return( FALSE );
}
//
// The Sids were successfully translated.
//
return TRUE;
}
//
// ZoltanS
//
HRESULT SetTrusteeOnACE(
VARIANT * pVarAce,
PLSA_REFERENCED_DOMAIN_LIST pDomains,
PLSA_TRANSLATED_NAME pName
)
{
//
// Make sure pName is valid
//
if ((pName->Use == SidTypeInvalid) ||
(pName->Use == SidTypeUnknown))
{
return E_INVALIDARG;
}
//
// Find the domain and account names.
//
DWORD dwAccountNameSize = pName->Name.Length / 2;
WCHAR * szAccountName = pName->Name.Buffer;
DWORD dwDomainNameSize =
(pDomains->Domains + pName->DomainIndex)->Name.Length / 2;
WCHAR * szDomainName =
(pDomains->Domains + pName->DomainIndex)->Name.Buffer;
//
// Allocate space for the compound name
//
DWORD dwLen = dwAccountNameSize + dwDomainNameSize + 1 + 1;
WCHAR * pszAccountName = new WCHAR [dwLen];
if (!pszAccountName)
{
return E_OUTOFMEMORY;
}
//
// Copy in the domain and user name
// to get the trustee name
//
if ( dwDomainNameSize != 0 )
{
// strange +1 needed because it will also put in a NULL terminator
lstrcpynW(pszAccountName, szDomainName, dwDomainNameSize + 1);
lstrcatW(pszAccountName, L"\\");
}
else
{
pszAccountName[0] = L'\0';
}
wcsncat(pszAccountName, szAccountName, dwAccountNameSize);
//
// Set the trustee name on the ACE
//
IDispatch * pDispatch = V_DISPATCH(pVarAce);
IADsAccessControlEntry * pACE;
HRESULT hr;
hr = pDispatch->QueryInterface(IID_IADsAccessControlEntry,
(void **) & pACE);
hr = pACE->put_Trustee(pszAccountName);
pACE->Release();
return hr;
}
//
// ZoltanS optimized version of ConvertACLToVariant
//
HRESULT
ConvertACLToVariant(
PACL pACL,
LPVARIANT pvarACL
)
{
IADsAccessControlList * pAccessControlList = NULL;
IDispatch * pDispatch = NULL;
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;
memset(&AclSize, 0, sizeof(ACL_SIZE_INFORMATION));
memset(&AclRevision, 0, sizeof(ACL_REVISION_INFORMATION));
dwStatus = GetAclInformation(
pACL,
&AclSize,
sizeof(ACL_SIZE_INFORMATION),
AclSizeInformation
);
dwStatus = GetAclInformation(
pACL,
&AclRevision,
sizeof(ACL_REVISION_INFORMATION),
AclRevisionInformation
);
dwAceCount = AclSize.AceCount;
dwAclRevision = AclRevision.AclRevision;
VariantInit(pvarACL);
hr = CoCreateInstance(
CLSID_AccessControlList,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsAccessControlList,
(void **)&pAccessControlList
);
if ( FAILED(hr) )
{
return hr;
}
PSID * apSids = new PSID[ dwAceCount ];
if ( apSids == NULL )
{
pAccessControlList->Release();
return E_OUTOFMEMORY;
}
VARIANT * aVarAces = new VARIANT[ dwAceCount ];
if ( aVarAces == NULL )
{
pAccessControlList->Release();
delete apSids;
return E_OUTOFMEMORY;
}
for (i = 0; i < dwAceCount; i++)
{
dwStatus = GetAce(pACL, i, (void **)&pAceAddress);
hr = ConvertAceToVariant(
pAceAddress,
aVarAces + i,
apSids + i );
}
//
// Above, ConvertAceToVariant did not set the trustee names on the ACEs.
// Instead we have an array (apSids) of dwNewAceCount valid PSIDs.
// Convert all of these to trustees now.
//
PLSA_REFERENCED_DOMAIN_LIST pDomains = NULL;
PLSA_TRANSLATED_NAME pTrustees = NULL;
BOOL fStatus = LookupArrayOfSids(
dwAceCount, // IN count
apSids, // IN array of sid pointers
&pDomains, // OUT referenced domain list
&pTrustees); // OUT translated name list
delete apSids;
if ( fStatus == FALSE )
{
// LookupArrayOfSids failed
hr = E_FAIL;
}
else
{
//
// Set the trustees on the ACEs here
//
for ( i = 0; i < dwAceCount; i++ )
{
VARIANT * pVarAce = aVarAces + i;
hr = SetTrusteeOnACE(
pVarAce,
pDomains,
pTrustees + i
);
hr = pAccessControlList->AddAce( V_DISPATCH ( pVarAce ) );
VariantClear( pVarAce );
if ( SUCCEEDED(hr) )
{
dwNewAceCount++;
}
}
//
// Free output buffers returned by LsaLookupSids
//
DWORD Status;
Status = LsaFreeMemory( pTrustees );
_ASSERTE( NT_SUCCESS( Status ));
Status = LsaFreeMemory( pDomains );
_ASSERTE( NT_SUCCESS( Status ));
pAccessControlList->put_AclRevision(dwAclRevision);
pAccessControlList->put_AceCount(dwNewAceCount);
hr = pAccessControlList->QueryInterface(
IID_IDispatch,
(void **)&pDispatch
);
V_VT(pvarACL) = VT_DISPATCH;
V_DISPATCH(pvarACL) = pDispatch;
}
pAccessControlList->Release();
//
// aVarAces was dynamic allocated
// aVarAces should be deallocated
//
delete aVarAces;
return(hr);
}
HRESULT
SecCreateSidFromArray (
OUT PSID *PPSid,
IN PSID_IDENTIFIER_AUTHORITY PSidAuthority,
IN UCHAR SubAuthorityCount,
IN ULONG SubAuthorities[],
OUT PDWORD pdwSidSize
)
/*++
Routine Description:
Creates a SID with desired authority and sub authorities.
NOTE: This routine allocates memory for the SID. When finished
the caller should free memory using SEC_FREE (PSid).
Arguments:
PPSid -- addr of ptr to SID to be created
Note: if SID creation fails ptr set to NULL
PSidAuthority -- desired value for SID authority
SubAuthorityCount -- number of sub authorities desired
SubAuthorities -- sub-authority values, MUST SPECIFY contain
at least SubAuthorityCount number of values
Return Value:
STATUS_SUCCESS if SID created.
STATUS_UNSUCCESSFUL otherwise.
--*/
{
USHORT iSub; /* sub-authority index */
DWORD dwSidSize = 0;
HRESULT hr = S_OK;
/* allocate memory for SID */
dwSidSize = RtlLengthRequiredSid(SubAuthorityCount);
*PPSid = (PSID) new BYTE[dwSidSize];
if (! *PPSid){
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
*pdwSidSize = dwSidSize;
/* initialize SID with top level SID identifier authority */
RtlInitializeSid( *PPSid, PSidAuthority, SubAuthorityCount);
/* fill in sub authorities */
for (iSub=0; iSub < SubAuthorityCount; iSub++)
* RtlSubAuthoritySid( *PPSid, iSub) = SubAuthorities[iSub];
/* sanity check */
if ( ! RtlValidSid( *PPSid) ) {
delete (*PPSid);
*PPSid = NULL;
hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
BAIL_ON_FAILURE(hr);
}
error:
return(hr);
}
HRESULT
ConvertStringToSid(
IN PWSTR string,
OUT PSID *sid,
OUT PDWORD pdwSidSize,
OUT PWSTR *end
)
{
HRESULT hr = S_OK;
UCHAR revision;
UCHAR sub_authority_count;
SID_IDENTIFIER_AUTHORITY authority;
ULONG sub_authority[SID_MAX_SUB_AUTHORITIES];
PWSTR end_list;
PWSTR current;
PWSTR next;
ULONG x;
*sid = NULL;
if ( string == NULL )
{
return E_POINTER;
}
if (((*string != L'S') && (*string != L's')) || (*(string + 1) != L'-'))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
BAIL_ON_FAILURE(hr);
}
current = string + 2;
revision = (UCHAR)wcstol(current, &end_list, 10);
current = end_list + 1;
//
// Count the number of characters in the indentifer authority...
//
next = wcschr(current, L'-');
if((next != NULL) &&
(next - current == 6))
{
for(x = 0; x < 6; x++)
{
authority.Value[x] = (UCHAR)next[x];
}
current +=6;
}
else
{
ULONG Auto = wcstoul(current, &end_list, 10);
authority.Value[0] = authority.Value[1] = 0;
authority.Value[5] = (UCHAR)Auto & 0xF;
authority.Value[4] = (UCHAR)((Auto >> 8) & 0xFF);
authority.Value[3] = (UCHAR)((Auto >> 16) & 0xFF);
authority.Value[2] = (UCHAR)((Auto >> 24) & 0xFF);
current = end_list;
}
//
// Now, count the number of sub auths
//
sub_authority_count = 0;
//
// Initialize sub_authority array
//
memset( sub_authority, 0, sizeof(ULONG) * SID_MAX_SUB_AUTHORITIES );
next = current;
//
// We'll have to count our sub authoritys one character at a time,
// since there are several deliminators that we can have...
//
while(next)
{
next++;
if(*next == L'-')
{
//
// We've found one!
//
sub_authority_count++;
}
else if(*next == L';' || *next == L'\0')
{
*end = next;
sub_authority_count++;
break;
}
}
if(sub_authority_count != 0)
{
current++;
for(x = 0; x < sub_authority_count; x++)
{
sub_authority[x] = wcstoul(current, &end_list, 10);
current = end_list + 1;
}
}
//
// Now, create the SID
//
hr = SecCreateSidFromArray(
sid,
&authority,
sub_authority_count,
sub_authority,
pdwSidSize
);
if (SUCCEEDED(hr))
{
/* Set the revision to what was specified in the string, in case, our
system creates one with newer revision */
((SID *)(*sid))->Revision = revision;
}
error:
return(hr);
}
HRESULT
ConvertTrusteeToSid(
BSTR bstrTrustee,
PSID * ppSid,
PDWORD pdwSidSize
)
{
HRESULT hr = S_OK;
BYTE Sid[MAX_PATH];
DWORD dwSidSize = sizeof(Sid);
DWORD dwRet = 0;
WCHAR szDomainName[MAX_PATH];
DWORD dwDomainSize = sizeof(szDomainName)/sizeof(WCHAR);
SID_NAME_USE eUse;
PSID pSid = NULL;
LPWSTR pszEnd = NULL;
BOOL fNTDSType = FALSE;
dwSidSize = sizeof(Sid);
dwRet = LookupAccountName(
NULL,
bstrTrustee,
Sid,
&dwSidSize,
szDomainName,
&dwDomainSize,
(PSID_NAME_USE)&eUse
);
if (!dwRet) {
hr = HRESULT_FROM_WIN32(GetLastError());
}
//
// If neither the NTDS nor the U2 conversion
// worked, then try a textual translation
//
if (FAILED(hr)) {
hr = ConvertStringToSid(
bstrTrustee,
&pSid,
&dwSidSize,
&pszEnd
);
BAIL_ON_FAILURE(hr);
memcpy(Sid,pSid, dwSidSize);
if (pSid) {
delete pSid;
}
}
pSid = (PSID) new BYTE[dwSidSize];
if (!pSid) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
memcpy(pSid, Sid, dwSidSize);
*pdwSidSize = dwSidSize;
*ppSid = pSid;
error:
return(hr);
}
HRESULT
GetOwnerSecurityIdentifier(
IADsSecurityDescriptor FAR * pSecDes,
PSID * ppSid,
PBOOL pfOwnerDefaulted
)
{
BSTR bstrOwner = NULL;
DWORD dwSidSize = 0;
HRESULT hr = S_OK;
VARIANT_BOOL varBool = VARIANT_FALSE;
hr = pSecDes->get_Owner(
&bstrOwner
);
BAIL_ON_FAILURE(hr);
hr = pSecDes->get_OwnerDefaulted(
&varBool
);
BAIL_ON_FAILURE(hr);
if (varBool == VARIANT_FALSE) {
if (bstrOwner && *bstrOwner) {
hr = ConvertTrusteeToSid(
bstrOwner,
ppSid,
&dwSidSize
);
BAIL_ON_FAILURE(hr);
*pfOwnerDefaulted = FALSE;
}else {
*ppSid = NULL;
*pfOwnerDefaulted = FALSE;
}
}else {
*ppSid = NULL;
dwSidSize = 0;
*pfOwnerDefaulted = TRUE;
}
error:
if (bstrOwner) {
SysFreeString(bstrOwner);
}
return(hr);
}
HRESULT
ComputeTotalAclSize(
PACE_HEADER * ppAceHdr,
DWORD dwAceCount,
PDWORD pdwAclSize
)
{
DWORD i = 0;
PACE_HEADER pAceHdr = NULL;
DWORD dwAceSize = 0;
DWORD dwAclSize = 0;
for (i = 0; i < dwAceCount; i++) {
pAceHdr = *(ppAceHdr + i);
dwAceSize = pAceHdr->AceSize;
dwAclSize += dwAceSize;
}
dwAclSize += sizeof(ACL);
*pdwAclSize = dwAclSize;
return(S_OK);
}
HRESULT
ConvertAccessControlEntryToAce(
IADsAccessControlEntry * pAccessControlEntry,
LPBYTE * ppAce
)
{
DWORD dwAceType = 0;
HRESULT hr = S_OK;
BSTR bstrTrustee = NULL;
PSID pSid = NULL;
DWORD dwSidSize = 0;
DWORD dwAceFlags = 0;
DWORD dwAccessMask = 0;
DWORD dwAceSize = 0;
LPBYTE pAce = NULL;
PACCESS_MASK pAccessMask = NULL;
PSID pSidAddress = NULL;
PUSHORT pCompoundAceType = NULL;
DWORD dwCompoundAceType = 0;
PACE_HEADER pAceHeader = NULL;
LPBYTE pOffset = NULL;
BSTR bstrObjectTypeClsid = NULL;
BSTR bstrInheritedObjectTypeClsid = NULL;
GUID ObjectTypeGUID;
GUID InheritedObjectTypeGUID;
PULONG pFlags;
DWORD dwFlags = 0;
hr = pAccessControlEntry->get_AceType((LONG *)&dwAceType);
BAIL_ON_FAILURE(hr);
hr = pAccessControlEntry->get_Trustee(&bstrTrustee);
BAIL_ON_FAILURE(hr);
hr = ConvertTrusteeToSid(
bstrTrustee,
&pSid,
&dwSidSize
);
BAIL_ON_FAILURE(hr);
hr = pAccessControlEntry->get_AceFlags((long *)&dwAceFlags);
BAIL_ON_FAILURE(hr);
hr = pAccessControlEntry->get_AccessMask((long *)&dwAccessMask);
BAIL_ON_FAILURE(hr);
if( pSid )
{
PSID_IDENTIFIER_AUTHORITY pSIA = GetSidIdentifierAuthority( pSid );
if( pSIA )
{
SID_IDENTIFIER_AUTHORITY sidEveryone = SECURITY_WORLD_SID_AUTHORITY;
if( memcmp(pSIA, &sidEveryone, sizeof(SID_IDENTIFIER_AUTHORITY))== 0)
{
// It is an Everyone user
dwAccessMask |= ADS_RIGHT_READ_CONTROL;
}
}
}
//
// we will compensateby adding the entire ACE size
//
dwAceSize = dwSidSize - sizeof(ULONG);
switch (dwAceType) {
case ACCESS_ALLOWED_ACE_TYPE:
dwAceSize += sizeof(ACCESS_ALLOWED_ACE);
pAce = new BYTE[dwAceSize];
if (!pAce) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pAceHeader = (PACE_HEADER)pAce;
pAceHeader->AceType = (UCHAR)dwAceType;
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
pAceHeader->AceSize = (USHORT)dwAceSize;
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
*pAccessMask = (ACCESS_MASK)dwAccessMask;
pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK));
memcpy(pSidAddress, pSid, dwSidSize);
break;
case ACCESS_DENIED_ACE_TYPE:
dwAceSize += sizeof(ACCESS_ALLOWED_ACE);
pAce = new BYTE[dwAceSize];
if (!pAce) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pAceHeader = (PACE_HEADER)pAce;
pAceHeader->AceType = (UCHAR)dwAceType;
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
pAceHeader->AceSize = (USHORT)dwAceSize;
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
*pAccessMask = (ACCESS_MASK)dwAccessMask;
pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK));
memcpy(pSidAddress, pSid, dwSidSize);
break;
case SYSTEM_AUDIT_ACE_TYPE:
dwAceSize += sizeof(ACCESS_ALLOWED_ACE);
pAce = new BYTE[dwAceSize];
if (!pAce) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pAceHeader = (PACE_HEADER)pAce;
pAceHeader->AceType = (UCHAR)dwAceType;
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
pAceHeader->AceSize = (USHORT)dwAceSize;
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
*pAccessMask = (ACCESS_MASK)dwAccessMask;
pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK));
memcpy(pSidAddress, pSid, dwSidSize);
break;
case SYSTEM_ALARM_ACE_TYPE:
dwAceSize += sizeof(ACCESS_ALLOWED_ACE);
pAce = new BYTE[dwAceSize];
if (!pAce) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pAceHeader = (PACE_HEADER)pAce;
pAceHeader->AceType = (UCHAR)dwAceType;
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
pAceHeader->AceSize = (USHORT)dwAceSize;
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
*pAccessMask = (ACCESS_MASK)dwAccessMask;
pSidAddress = (PSID)((LPBYTE)pAccessMask + sizeof(ACCESS_MASK));
memcpy(pSidAddress, pSid, dwSidSize);
break;
case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
dwAceSize += sizeof(COMPOUND_ACCESS_ALLOWED_ACE);
pAce = new BYTE[dwAceSize];
if (!pAce) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pAceHeader = (PACE_HEADER)pAce;
pAceHeader->AceType = (UCHAR)dwAceType;
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
pAceHeader->AceSize = (USHORT)dwAceSize;
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
*pAccessMask = (ACCESS_MASK)dwAccessMask;
pCompoundAceType = (PUSHORT)(pAccessMask + sizeof(ACCESS_MASK));
*pCompoundAceType = (USHORT)dwCompoundAceType;
//
// Fill in the reserved field here.
//
pSidAddress = (PSID)((LPBYTE)pCompoundAceType + sizeof(DWORD));
memcpy(pSidAddress, pSid, dwSidSize);
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:
hr = pAccessControlEntry->get_AceFlags((LONG *)&dwAceFlags);
BAIL_ON_FAILURE(hr);
hr = pAccessControlEntry->get_Flags((LONG *)&dwFlags);
BAIL_ON_FAILURE(hr);
if (dwFlags & ACE_OBJECT_TYPE_PRESENT) {
dwAceSize += sizeof(GUID);
}
if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) {
dwAceSize += sizeof(GUID);
}
hr = pAccessControlEntry->get_ObjectType(&bstrObjectTypeClsid);
BAIL_ON_FAILURE(hr);
hr = CLSIDFromString(bstrObjectTypeClsid, &ObjectTypeGUID);
BAIL_ON_FAILURE(hr);
hr = pAccessControlEntry->get_InheritedObjectType(&bstrInheritedObjectTypeClsid);
BAIL_ON_FAILURE(hr);
hr = CLSIDFromString(bstrInheritedObjectTypeClsid, &InheritedObjectTypeGUID);
BAIL_ON_FAILURE(hr);
dwAceSize += sizeof(ACCESS_ALLOWED_OBJECT_ACE);
pAce = new BYTE[dwAceSize];
if (!pAce) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
pAceHeader = (PACE_HEADER)pAce;
pAceHeader->AceType = (UCHAR)dwAceType;
pAceHeader->AceFlags = (UCHAR)dwAceFlags;
pAceHeader->AceSize = (USHORT)dwAceSize;
pAccessMask = (PACCESS_MASK)((LPBYTE)pAceHeader + sizeof(ACE_HEADER));
*pAccessMask = (ACCESS_MASK)dwAccessMask;
//
// Fill in Flags
//
pOffset = (LPBYTE)((LPBYTE)pAceHeader + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
pFlags = (PULONG)(pOffset);
*pFlags = dwFlags;
pOffset += sizeof(ULONG);
if (dwFlags & ACE_OBJECT_TYPE_PRESENT) {
memcpy(pOffset, &ObjectTypeGUID, sizeof(GUID));
pOffset += sizeof(GUID);
}
if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT) {
memcpy(pOffset, &InheritedObjectTypeGUID, sizeof(GUID));
pOffset += sizeof(GUID);
}
pSidAddress = (PSID)((LPBYTE)pOffset);
memcpy(pSidAddress, pSid, dwSidSize);
break;
}
*ppAce = pAce;
error:
if (bstrTrustee) {
SysFreeString(bstrTrustee);
}
if (pSid) {
delete (pSid);
}
return(hr);
}
HRESULT AddACEEveryone(
IADsAccessControlList FAR * pAccessList
)
{
// Declarations
DWORD dwAceCount = 0;
HRESULT hr = S_OK;
IUnknown * pUnknown = NULL;
IEnumVARIANT * pEnumerator = NULL;
DWORD i = 0;
DWORD cReturned = 0;
VARIANT varAce;
BOOL bEveryone = FALSE;
IADsAccessControlEntry FAR * pAccessControlEntry = NULL;
IDispatch* pACEDispatch = NULL;
PSID pSid = NULL;
DWORD dwSidSize = 0;
BSTR bstrTrustee = NULL;
// Get the ACE count
hr = pAccessList->get_AceCount((long*)&dwAceCount);
BAIL_ON_FAILURE(hr);
// Get the ACE enumeration
hr = pAccessList->get__NewEnum( &pUnknown );
BAIL_ON_FAILURE(hr);
hr = pUnknown->QueryInterface(
IID_IEnumVARIANT,
(void FAR * FAR *)&pEnumerator);
BAIL_ON_FAILURE(hr);
// Browse the enumeration
for (i = 0; i < dwAceCount; i++)
{
VariantInit(&varAce);
hr = pEnumerator->Next(
1,
&varAce,
&cReturned
);
CONTINUE_ON_FAILURE(hr);
hr = (V_DISPATCH(&varAce))->QueryInterface(
IID_IADsAccessControlEntry,
(void **)&pAccessControlEntry
);
CONTINUE_ON_FAILURE(hr);
//
// Get the user
//
hr = pAccessControlEntry->get_Trustee(&bstrTrustee);
if( FAILED(hr) )
{
// Clean-up
VariantClear(&varAce);
pAccessControlEntry->Release();
pAccessControlEntry = NULL;
continue;
}
//
// Get the SID
//
hr = ConvertTrusteeToSid(
bstrTrustee,
&pSid,
&dwSidSize
);
if( FAILED(hr) )
{
// Clean-up
if( bstrTrustee )
{
SysFreeString( bstrTrustee );
bstrTrustee = NULL;
}
VariantClear(&varAce);
pAccessControlEntry->Release();
pAccessControlEntry = NULL;
continue;
}
//
// Validate if is the Everyone SID
//
if( pSid )
{
PSID_IDENTIFIER_AUTHORITY pSIA = GetSidIdentifierAuthority( pSid );
if( pSIA )
{
SID_IDENTIFIER_AUTHORITY sidEveryone = SECURITY_WORLD_SID_AUTHORITY;
if( memcmp(pSIA, &sidEveryone, sizeof(SID_IDENTIFIER_AUTHORITY))== 0)
{
// It is an Everyone user
bEveryone = TRUE;
// Clean-up
VariantClear(&varAce);
pAccessControlEntry->Release();
pAccessControlEntry = NULL;
// Break the loop
break;
}
}
}
VariantClear(&varAce);
if (pAccessControlEntry)
{
pAccessControlEntry->Release();
pAccessControlEntry = NULL;
}
if( bstrTrustee )
{
SysFreeString( bstrTrustee );
bstrTrustee = NULL;
}
}
if( !bEveryone)
{
// We have to add an everyone entry
hr = CoCreateInstance(
CLSID_AccessControlEntry,
NULL,
CLSCTX_INPROC_SERVER,
IID_IADsAccessControlEntry,
(void**)&pAccessControlEntry);
BAIL_ON_FAILURE(hr);
// Access mask
hr = pAccessControlEntry->put_AccessMask( ADS_RIGHT_READ_CONTROL );
BAIL_ON_FAILURE(hr);
// Ace type
hr = pAccessControlEntry->put_AceType( 0 );
BAIL_ON_FAILURE(hr);
// Ace flags
hr = pAccessControlEntry->put_AceFlags( 0 );
BAIL_ON_FAILURE(hr);
// Get the SID for everyone
WCHAR Trustee[256];
PSID pSidEveryone = NULL;
SID_IDENTIFIER_AUTHORITY siaEveryone = SECURITY_WORLD_SID_AUTHORITY;
BOOL bAllocate = AllocateAndInitializeSid(
&siaEveryone,
1,0,0,0,0,0,0,0,0,
&pSidEveryone);
if( !bAllocate )
{
BAIL_ON_FAILURE(E_OUTOFMEMORY);
}
// Get the trustee for everyone
hr = ConvertSidToString( pSidEveryone, Trustee );
FreeSid( pSidEveryone);
BAIL_ON_FAILURE(hr);
bstrTrustee = SysAllocString( Trustee );
if( bstrTrustee == NULL)
{
BAIL_ON_FAILURE(E_OUTOFMEMORY);
}
// Add trustee
hr = pAccessControlEntry->put_Trustee( bstrTrustee );
BAIL_ON_FAILURE(hr);
// Get the IDispatch
hr = pAccessControlEntry->QueryInterface(
IID_IDispatch,
(void**)&pACEDispatch);
BAIL_ON_FAILURE(hr);
// Add ACE to the ACL
hr = pAccessList->AddAce( pACEDispatch );
BAIL_ON_FAILURE(hr);
}
error:
if (pUnknown) {
pUnknown->Release();
}
if (pEnumerator) {
pEnumerator->Release();
}
if( pACEDispatch )
{
pACEDispatch->Release();
}
if(pAccessControlEntry)
{
pAccessControlEntry->Release();
}
if( bstrTrustee )
{
SysFreeString( bstrTrustee );
}
return(hr);
}
HRESULT
ConvertAccessControlListToAcl(
IADsAccessControlList FAR * pAccessList,
PACL * ppAcl
)
{
IUnknown * pUnknown = NULL;
IEnumVARIANT * pEnumerator = NULL;
HRESULT hr = S_OK;
DWORD i = 0;
DWORD cReturned = 0;
VARIANT varAce;
DWORD dwAceCount = 0;
IADsAccessControlEntry FAR * pAccessControlEntry = NULL;
LPBYTE pTempAce = NULL;
DWORD dwCount = 0;
PACL pAcl = NULL;
DWORD dwAclSize = 0;
PACE_HEADER * ppAceHdr = NULL;
DWORD dwRet = 0;
DWORD dwAclRevision = 0;
DWORD dwStatus = 0;
DWORD dwError = 0;
hr = AddACEEveryone( pAccessList );
BAIL_ON_FAILURE(hr);
hr = pAccessList->get_AceCount((long *)&dwAceCount);
BAIL_ON_FAILURE(hr);
hr = pAccessList->get__NewEnum(
&pUnknown
);
BAIL_ON_FAILURE(hr);
hr = pUnknown->QueryInterface(
IID_IEnumVARIANT,
(void FAR * FAR *)&pEnumerator
);
BAIL_ON_FAILURE(hr);
ppAceHdr = new PACE_HEADER [dwAceCount];
if (!ppAceHdr) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
for (i = 0; i < dwAceCount; i++) {
VariantInit(&varAce);
hr = pEnumerator->Next(
1,
&varAce,
&cReturned
);
CONTINUE_ON_FAILURE(hr);
hr = (V_DISPATCH(&varAce))->QueryInterface(
IID_IADsAccessControlEntry,
(void **)&pAccessControlEntry
);
CONTINUE_ON_FAILURE(hr);
hr = ConvertAccessControlEntryToAce(
pAccessControlEntry,
&(pTempAce)
);
// ZoltanS: Rather than CONTINUE_ON_FAILURE, let's bail so that we
// know if the Ace we set is invalid.
BAIL_ON_FAILURE(hr);
*(ppAceHdr + dwCount) = (PACE_HEADER)pTempAce;
VariantClear(&varAce);
if (pAccessControlEntry) {
pAccessControlEntry->Release();
pAccessControlEntry = NULL;
}
dwCount++;
}
hr = ComputeTotalAclSize(ppAceHdr, dwCount, &dwAclSize);
BAIL_ON_FAILURE(hr);
pAcl = (PACL)new BYTE[dwAclSize];
if (!pAcl) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
hr = pAccessList->get_AclRevision((long *)&dwAclRevision);
//
// we have to deallocate memory
//
if( FAILED(hr) && (NULL != pAcl) )
delete( pAcl );
BAIL_ON_FAILURE(hr);
dwRet = InitializeAcl(
pAcl,
dwAclSize,
dwAclRevision
);
if (!dwRet) {
hr = HRESULT_FROM_WIN32(GetLastError());
//
// we have to deallocate memory
//
if( FAILED(hr) && (NULL != pAcl) )
delete( pAcl );
BAIL_ON_FAILURE(hr);
}
for (i = 0; i < dwCount; i++) {
dwStatus = AddAce(
pAcl,
dwAclRevision,
i,
(LPBYTE)*(ppAceHdr + i),
(*(ppAceHdr + i))->AceSize
);
if (!dwStatus) {
dwError = GetLastError();
}
}
*ppAcl = pAcl;
error:
if (ppAceHdr) {
for (i = 0; i < dwCount; i++) {
if (*(ppAceHdr + i)) {
delete (*(ppAceHdr + i));
}
}
delete (ppAceHdr);
}
if (pUnknown) {
pUnknown->Release();
}
if (pEnumerator) {
pEnumerator->Release();
}
return(hr);
}
HRESULT
GetGroupSecurityIdentifier(
IADsSecurityDescriptor FAR * pSecDes,
PSID * ppSid,
PBOOL pfGroupDefaulted
)
{
BSTR bstrGroup = NULL;
DWORD dwSidSize = 0;
HRESULT hr = S_OK;
VARIANT_BOOL varBool = VARIANT_FALSE;
hr = pSecDes->get_Group(
&bstrGroup
);
BAIL_ON_FAILURE(hr);
hr = pSecDes->get_GroupDefaulted(
&varBool
);
BAIL_ON_FAILURE(hr);
if (varBool == VARIANT_FALSE) {
if (bstrGroup && *bstrGroup) {
hr = ConvertTrusteeToSid(
bstrGroup,
ppSid,
&dwSidSize
);
BAIL_ON_FAILURE(hr);
*pfGroupDefaulted = FALSE;
}else {
*ppSid = NULL;
*pfGroupDefaulted = FALSE;
}
}else {
*ppSid = NULL;
dwSidSize = 0;
*pfGroupDefaulted = TRUE;
}
error:
if (bstrGroup) {
SysFreeString(bstrGroup);
}
return(hr);
}
HRESULT
GetDacl(
IADsSecurityDescriptor FAR * pSecDes,
PACL * ppDacl,
PBOOL pfDaclDefaulted
)
{
IADsAccessControlList FAR * pDiscAcl = NULL;
IDispatch FAR * pDispatch = NULL;
HRESULT hr = S_OK;
VARIANT_BOOL varBool = VARIANT_FALSE;
hr = pSecDes->get_DaclDefaulted(
&varBool
);
BAIL_ON_FAILURE(hr);
if (varBool == VARIANT_FALSE) {
*pfDaclDefaulted = FALSE;
}else {
*pfDaclDefaulted = TRUE;
}
hr = pSecDes->get_DiscretionaryAcl(
&pDispatch
);
BAIL_ON_FAILURE(hr);
if (!pDispatch) {
*ppDacl = NULL;
goto error;
}
hr = pDispatch->QueryInterface(
IID_IADsAccessControlList,
(void **)&pDiscAcl
);
BAIL_ON_FAILURE(hr);
hr = ConvertAccessControlListToAcl(
pDiscAcl,
ppDacl
);
BAIL_ON_FAILURE(hr);
error:
if (pDispatch) {
pDispatch->Release();
}
if (pDiscAcl) {
pDiscAcl->Release();
}
return(hr);
}
HRESULT
GetSacl(
IADsSecurityDescriptor FAR * pSecDes,
PACL * ppSacl,
PBOOL pfSaclDefaulted
)
{
IADsAccessControlList FAR * pSystemAcl = NULL;
IDispatch FAR * pDispatch = NULL;
HRESULT hr = S_OK;
VARIANT_BOOL varBool = VARIANT_FALSE;
hr = pSecDes->get_SaclDefaulted(
&varBool
);
BAIL_ON_FAILURE(hr);
if (varBool == VARIANT_FALSE) {
*pfSaclDefaulted = FALSE;
}else {
*pfSaclDefaulted = TRUE;
}
hr = pSecDes->get_SystemAcl(
&pDispatch
);
BAIL_ON_FAILURE(hr);
if (!pDispatch) {
*ppSacl = NULL;
goto error;
}
hr = pDispatch->QueryInterface(
IID_IADsAccessControlList,
(void **)&pSystemAcl
);
BAIL_ON_FAILURE(hr);
hr = ConvertAccessControlListToAcl(
pSystemAcl,
ppSacl
);
BAIL_ON_FAILURE(hr);
error:
if (pDispatch) {
pDispatch->Release();
}
if (pSystemAcl) {
pSystemAcl->Release();
}
return(hr);
}
///////////////////////////////////////////////////////////////////////////////
// //
// Public procedures //
// //
///////////////////////////////////////////////////////////////////////////////
HRESULT
ConvertSDToIDispatch(
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
OUT IDispatch ** ppIDispatch
)
{
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;
memset(&varSACL, 0, sizeof(VARIANT));
memset(&varDACL, 0, sizeof(VARIANT));
if (!pSecurityDescriptor) {
return(E_FAIL);
}
dwRet = GetSecurityDescriptorControl(
pSecurityDescriptor,
&wControl,
&dwRevision
);
if (!dwRet){
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
dwRet = GetSecurityDescriptorOwner(
pSecurityDescriptor,
(PSID *)&pOwnerSidAddress,
&fOwnerDefaulted
);
if (!dwRet){
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
hr = ConvertSidToFriendlyName(
pOwnerSidAddress,
&pszOwner
);
BAIL_ON_FAILURE(hr);
dwRet = GetSecurityDescriptorGroup(
pSecurityDescriptor,
(PSID *)&pGroupSidAddress,
&fOwnerDefaulted
);
if (!dwRet){
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
hr = ConvertSidToFriendlyName(
pGroupSidAddress,
&pszGroup
);
BAIL_ON_FAILURE(hr);
dwRet = GetSecurityDescriptorDacl(
pSecurityDescriptor,
&fDaclPresent,
(PACL*)&pDACLAddress,
&fDaclDefaulted
);
if (pDACLAddress) {
hr = ConvertACLToVariant(
(PACL)pDACLAddress,
&varDACL
);
BAIL_ON_FAILURE(hr);
}
dwRet = GetSecurityDescriptorSacl(
pSecurityDescriptor,
&fSaclPresent,
(PACL *)&pSACLAddress,
&fSaclDefaulted
);
if (!dwRet){
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
if (pSACLAddress) {
hr = ConvertACLToVariant(
(PACL)pSACLAddress,
&varSACL
);
BAIL_ON_FAILURE(hr);
}
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);
*ppIDispatch = pDispatch;
error:
VariantClear(&varSACL);
VariantClear(&varDACL);
if (pszOwner) {
delete (pszOwner);
}
if (pszGroup) {
delete (pszGroup);
}
if (pSecDes) {
pSecDes->Release();
}
return(hr);
}
HRESULT
ConvertSDToVariant(
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
OUT VARIANT * pVarSec
)
{
IDispatch *pIDispatch;
HRESULT hr = ConvertSDToIDispatch(pSecurityDescriptor, &pIDispatch);
if (FAILED(hr))
{
return hr;
}
VariantInit(pVarSec);
V_VT(pVarSec) = VT_DISPATCH;
V_DISPATCH(pVarSec) = pIDispatch;
return S_OK;
}
HRESULT
ConvertObjectToSD(
IN IADsSecurityDescriptor FAR * pSecDes,
OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor,
OUT PDWORD pdwSDLength
)
{
HRESULT hr = S_OK;
SECURITY_DESCRIPTOR AbsoluteSD;
PSECURITY_DESCRIPTOR pRelative = NULL;
BOOL Defaulted = FALSE;
BOOL DaclPresent = FALSE;
BOOL SaclPresent = FALSE;
BOOL fDaclDefaulted = FALSE;
BOOL fSaclDefaulted = FALSE;
BOOL fOwnerDefaulted = FALSE;
BOOL fGroupDefaulted = FALSE;
PSID pOwnerSid = NULL;
PSID pGroupSid = NULL;
PACL pDacl = NULL;
PACL pSacl = NULL;
DWORD dwSDLength = 0;
DWORD dwRet = 0;
BOOL dwStatus = 0;
//
// Initialize *pSizeSD = 0;
//
dwRet = InitializeSecurityDescriptor (
&AbsoluteSD,
SECURITY_DESCRIPTOR_REVISION1
);
if (!dwRet) {
hr = E_FAIL;
BAIL_ON_FAILURE(hr);
}
hr = GetOwnerSecurityIdentifier(
pSecDes,
&pOwnerSid,
&fOwnerDefaulted
);
BAIL_ON_FAILURE(hr);
dwStatus = SetSecurityDescriptorOwner(
&AbsoluteSD,
pOwnerSid,
fOwnerDefaulted
);
if (!dwStatus) {
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
hr = GetGroupSecurityIdentifier(
pSecDes,
&pGroupSid,
&fGroupDefaulted
);
BAIL_ON_FAILURE(hr);
dwStatus = SetSecurityDescriptorGroup(
&AbsoluteSD,
pGroupSid,
fGroupDefaulted
);
if (!dwStatus) {
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
hr = GetDacl(
pSecDes,
&pDacl,
&fDaclDefaulted
);
BAIL_ON_FAILURE(hr);
if (pDacl || fDaclDefaulted) {
DaclPresent = TRUE;
}
dwStatus = SetSecurityDescriptorDacl(
&AbsoluteSD,
DaclPresent,
pDacl,
fDaclDefaulted
);
if (!dwStatus) {
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
hr = GetSacl(
pSecDes,
&pSacl,
&fSaclDefaulted
);
BAIL_ON_FAILURE(hr);
if (pSacl || fSaclDefaulted) {
SaclPresent = TRUE;
}
dwStatus = SetSecurityDescriptorSacl(
&AbsoluteSD,
SaclPresent,
pSacl,
fSaclDefaulted
);
if (!dwStatus) {
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
dwSDLength = GetSecurityDescriptorLength(
&AbsoluteSD
);
pRelative = new BYTE[dwSDLength];
if (!pRelative) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
if (!MakeSelfRelativeSD (&AbsoluteSD, pRelative, &dwSDLength)) {
delete (pRelative);
hr = HRESULT_FROM_WIN32(GetLastError());
BAIL_ON_FAILURE(hr);
}
*ppSecurityDescriptor = pRelative;
*pdwSDLength = dwSDLength;
cleanup:
if (pDacl) {
delete (pDacl);
}
if (pSacl) {
delete (pSacl);
}
if (pOwnerSid) {
delete (pOwnerSid);
}
if (pGroupSid) {
delete (pGroupSid);
}
return(hr);
error:
if (pRelative) {
delete (pRelative);
}
*ppSecurityDescriptor = NULL;
*pdwSDLength = 0;
goto cleanup;
}
HRESULT
ConvertObjectToSDDispatch(
IN IDispatch * pDisp,
OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor,
OUT PDWORD pdwSDLength
)
{
HRESULT hr;
IADsSecurityDescriptor * pSecDes;
hr = pDisp->QueryInterface(
IID_IADsSecurityDescriptor,
(VOID **)&pSecDes
);
if (FAILED(hr))
{
return hr;
}
hr = ConvertObjectToSD(pSecDes, ppSecurityDescriptor, pdwSDLength);
return hr;
}
// Returns FALSE if these two security descriptors are identical.
// Returns TRUE if they differ, or if there is any error parsing either of them
BOOL CheckIfSecurityDescriptorsDiffer(PSECURITY_DESCRIPTOR pSD1,
DWORD dwSDSize1,
PSECURITY_DESCRIPTOR pSD2,
DWORD dwSDSize2)
{
//
// If one of them is null, then they differ. (It should be impossible for them
// to both be null, but if they are, they had better both have size 0, which
// would just make us return TRUE below, so that's ok.)
//
if ( ( pSD1 == NULL ) || ( pSD2 == NULL ) )
{
return TRUE;
}
// if they converted to different sized structures then they are different
if ( dwSDSize1 != dwSDSize2 )
{
return TRUE;
}
// we know both succeeded conversion and converted to the same sized structures
// if the structures contain the same bytes then they are identical
if ( 0 == memcmp(pSD1, pSD2, dwSDSize1) )
{
return FALSE;
}
// else they differ
return TRUE;
}
// eof