Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1459 lines
58 KiB

/*****************************************************************************/
/* Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved /
/*****************************************************************************/
//=================================================================
//
// SecUtils.cpp -- Security utilities useful to wbem mof classes
//
// Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved
//
// Revisions: 6/9/99 a-kevhu Created
//
//=================================================================
#include "precomp.h"
#include <assertbreak.h>
#include "AccessEntry.h" // CAccessEntry class
#include "AccessEntryList.h"
#include "DACL.h" // CDACL class
#include "SACL.h"
#include "SecurityDescriptor.h"
#include <accctrl.h>
#include "AccessRights.h"
#include "SecureFile.h"
#include "SecureShare.h"
#include "wbemnetapi32.h"
#include "SecUtils.h"
///////////////////////////////////////////////////////////////////
//
// Function: FillTrusteeFromSid
//
// Default class constructor.
//
// Inputs:
// None.
//
// Outputs:
// None.
//
// Returns:
// None.
//
// Comments:
//
///////////////////////////////////////////////////////////////////
void FillTrusteeFromSid (CInstance *pInstance, CSid &sid)
{
if (pInstance)
{
PSID pSid;
CHString chstrName;
CHString chstrDomain;
VARIANT vValue;
if (sid.IsValid())
{
pSid = sid.GetPSid();
chstrName = sid.GetAccountName();
chstrDomain = sid.GetDomainName();
// set the UINT8 array for the pSid
DWORD dwSidLength = sid.GetLength();
// BYTE bByte;
SAFEARRAY* sa;
SAFEARRAYBOUND rgsabound[1];
VariantInit(&vValue);
rgsabound[0].cElements = dwSidLength;
PSID pSidTrustee = NULL ;
rgsabound[0].lLbound = 0;
sa = SafeArrayCreate(VT_UI1, 1, rgsabound);
// Get a pointer to read the data into
SafeArrayAccessData(sa, &pSidTrustee);
memcpy(pSidTrustee, pSid, rgsabound[0].cElements);
SafeArrayUnaccessData(sa);
// Put the safearray into a variant, and send it off
V_VT(&vValue) = VT_UI1 | VT_ARRAY; V_ARRAY(&vValue) = sa;
pInstance->SetVariant(IDS_Sid, vValue);
VariantClear(&vValue);
// fill in the rest of the stuff.
if(!chstrName.IsEmpty())
{
pInstance->SetCHString(IDS_Name, chstrName);
}
if(!chstrDomain.IsEmpty())
{
pInstance->SetCHString(IDS_Domain, chstrDomain);
}
pInstance->SetDWORD(IDS_SidLength, dwSidLength);
// Fill in the SIDString property...
pInstance->SetCHString(IDS_SIDString, sid.GetSidString());
}
}
}
///////////////////////////////////////////////////////////////////
//
// Function: FillInstanceDACL
//
// Default class constructor.
//
// Inputs:
// None.
//
// Outputs:
// None.
//
// Returns:
// None.
//
// Comments:
//
///////////////////////////////////////////////////////////////////
void FillInstanceDACL(CInstance *pInstance, CDACL &dacl)
{
CAccessEntry ace;
SAFEARRAY* saDACL;
SAFEARRAYBOUND rgsabound[1];
VARIANT vValue;
if ( pInstance && !dacl.IsEmpty() )
{
// First need merged list...
CAccessEntryList t_cael;
if(dacl.GetMergedACL(t_cael))
{
DWORD dwSize;
long ix[1];
dwSize = t_cael.NumEntries();
rgsabound[0].cElements = dwSize;
rgsabound[0].lLbound = 0;
saDACL = SafeArrayCreate(VT_UNKNOWN, 1, rgsabound);
ix[0] = 0;
ACLPOSITION pos;
t_cael.BeginEnum(pos);
while (t_cael.GetNext(pos, ace))
{
CInstancePtr pAce;
CInstancePtr pTrustee;
// now that we have the ACE, let's create a Win32_ACE object so we can
// add it to the embedded object list.
if (SUCCEEDED(CWbemProviderGlue::GetEmptyInstance(pInstance->GetMethodContext(), L"Win32_Ace", &pAce, IDS_CimWin32Namespace ) ) )
{
// fill trustee from SID
CSid sid;
ace.GetSID(sid);
if (SUCCEEDED(CWbemProviderGlue::GetEmptyInstance(pInstance->GetMethodContext(), L"Win32_Trustee", &pTrustee, IDS_CimWin32Namespace )))
{
FillTrusteeFromSid(pTrustee, sid);
pAce->SetEmbeddedObject(IDS_Trustee, *pTrustee);
// pTrustee->Release() ;
} // end if
DWORD dwAceType = ace.GetACEType();
DWORD dwAceFlags = ace.GetACEFlags();
DWORD dwAccessMask = ace.GetAccessMask ();
pAce->SetDWORD(IDS_AceType, dwAceType);
pAce->SetDWORD(IDS_AceFlags, dwAceFlags);
pAce->SetDWORD(IDS_AccessMask, dwAccessMask);
#ifdef NTONLY
#if NTONLY > 5
// fill Guids
GUID guidObjType, guidInhObjType;
if(ace.GetObjType(guidObjType))
{
WCHAR wstrGuid[39];
if(::StringFromGUID2(&guidObjType, wstrGuid, 39))
{
pAce->SetWCHARSplat(IDS_GuidObjectType, wstrGuid);
}
}
if(ace.GetInhObjType(guidInhObjType))
{
WCHAR wstrGuid[39];
if(::StringFromGUID2(&guidInhObjType, wstrGuid, 39))
{
pAce->SetWCHARSplat(IDS_GuidInheritedObjectType, wstrGuid);
}
}
#endif
#endif
// Get the IUnknown of the Win32_ACE object. Convert it to a
// variant of type VT_UNKNOWN. Then, add the variant to the
// SafeArray. Eventually, to add the list to the actual
// Win32_SecurityDescriptor object, we will be using SetVariant.
// Note: it is intentional that we are not decrementing the Addref
// done on pAce by the following call.
IWbemClassObjectPtr pClassObject(pAce->GetClassObjectInterface());
if ( pClassObject )
{
VARIANT v;
VariantInit(&v);
v.vt = VT_UNKNOWN;
v.punkVal = pClassObject ;
SafeArrayPutElement(saDACL, ix, pClassObject);
VariantClear(&v);
} // end if
} // end if
ix[0]++ ;
} // end while
VariantInit(&vValue);
V_VT(&vValue) = VT_UNKNOWN | VT_ARRAY; V_ARRAY(&vValue) = saDACL;
pInstance->SetVariant(IDS_DACL, vValue);
VariantClear(&vValue);
t_cael.EndEnum(pos);
}
}
}
///////////////////////////////////////////////////////////////////
//
// Function: FillInstanceSACL
//
// Default class constructor.
//
// Inputs:
// None.
//
// Outputs:
// None.
//
// Returns:
// None.
//
// Comments:
//
///////////////////////////////////////////////////////////////////
void FillInstanceSACL(CInstance *pInstance, CSACL &sacl)
{
CAccessEntry ace;
CInstancePtr pAce;
CInstancePtr pTrustee;
SAFEARRAY* saSACL;
SAFEARRAYBOUND rgsabound[1];
VARIANT vValue;
if ( pInstance && !sacl.IsEmpty() )
{
// First need merged list...
CAccessEntryList t_cael;
if(sacl.GetMergedACL(t_cael))
{
DWORD dwSize;
long ix[1];
dwSize = t_cael.NumEntries();
rgsabound[0].cElements = dwSize;
rgsabound[0].lLbound = 0;
saSACL = SafeArrayCreate(VT_UNKNOWN, 1, rgsabound);
ix[0] = 0;
ACLPOSITION pos;
t_cael.BeginEnum(pos);
while (t_cael.GetNext(pos, ace))
{
// now that we have the ACE, let's create a Win32_ACE object so we can
// add it to the embedded object list.
if (SUCCEEDED(CWbemProviderGlue::GetEmptyInstance(pInstance->GetMethodContext(), L"Win32_Ace", &pAce, IDS_CimWin32Namespace)))
{
// fill trustee from SID
CSid sid;
ace.GetSID(sid);
if (SUCCEEDED(CWbemProviderGlue::GetEmptyInstance(pInstance->GetMethodContext(), L"Win32_Trustee", &pTrustee, IDS_CimWin32Namespace )))
{
FillTrusteeFromSid(pTrustee, sid);
pAce->SetEmbeddedObject(IDS_Trustee, *pTrustee);
} // end if
DWORD dwAceType = ace.GetACEType();
DWORD dwAceFlags = ace.GetACEFlags();
DWORD dwAccessMask = ace.GetAccessMask ();
pAce->SetDWORD(IDS_AceType, dwAceType);
pAce->SetDWORD(IDS_AceFlags, dwAceFlags);
pAce->SetDWORD(IDS_AccessMask, dwAccessMask);
#ifdef NTONLY
#if NTONLY > 5
// fill Guids
GUID guidObjType, guidInhObjType;
if(ace.GetObjType(guidObjType))
{
WCHAR wstrGuid[39];
if(::StringFromGUID2(&guidObjType, wstrGuid, 39))
{
pAce->SetWCHARSplat(IDS_GuidObjectType, wstrGuid);
}
}
if(ace.GetInhObjType(guidInhObjType))
{
WCHAR wstrGuid[39];
if(::StringFromGUID2(&guidInhObjType, wstrGuid, 39))
{
pAce->SetWCHARSplat(IDS_GuidInheritedObjectType, wstrGuid);
}
}
#endif
#endif
// Get the IUnknown of the Win32_ACE object. Convert it to a
// variant of type VT_UNKNOWN. Then, add the variant to the
// SafeArray. Eventually, to add the list to the actual
// Win32_SecurityDescriptor object, we will be using SetVariant
IWbemClassObjectPtr pClassObject(pAce->GetClassObjectInterface());
if ( pClassObject )
{
VARIANT v;
VariantInit(&v);
v.vt = VT_UNKNOWN;
v.punkVal = pClassObject ;
SafeArrayPutElement(saSACL, ix, pClassObject);
VariantClear(&v);
} // end if
} // end if
ix[0]++ ;
} // end while
VariantInit(&vValue);
V_VT(&vValue) = VT_UNKNOWN | VT_ARRAY; V_ARRAY(&vValue) = saSACL;
pInstance->SetVariant(IDS_SACL, vValue);
VariantClear(&vValue);
t_cael.EndEnum(pos);
}
}
}
///////////////////////////////////////////////////////////////////
//
// Function: FillDACLFromInstance
//
// Default class constructor.
//
// Inputs:
// None.
//
// Outputs:
// None.
//
// Returns:
// None.
//
// Comments:
//
///////////////////////////////////////////////////////////////////
DWORD FillDACLFromInstance(CInstance *pInstance,
CDACL &dacl,
MethodContext *pMethodContext)
{
IWbemClassObjectPtr piClassObject;
piClassObject.Attach(pInstance->GetClassObjectInterface());
DWORD dwStatus = ERROR_SUCCESS ;
if(piClassObject)
{
VARIANT vDacl ;
if(GetArray(piClassObject,IDS_DACL, vDacl, VT_UNKNOWN|VT_ARRAY) )
{
if( vDacl.vt != VT_NULL && vDacl.parray != NULL )
{
// walk DACL
LONG lDimension = 1 ;
LONG lLowerBound ;
SafeArrayGetLBound ( vDacl.parray , lDimension , &lLowerBound ) ;
LONG lUpperBound ;
SafeArrayGetUBound ( vDacl.parray , lDimension , &lUpperBound ) ;
for ( LONG lIndex = lLowerBound ; lIndex <= lUpperBound ; lIndex++ )
{
if( dwStatus != ERROR_SUCCESS )
{
break ;
}
IWbemClassObjectPtr pACEObject;
SafeArrayGetElement ( vDacl.parray , &lIndex , &pACEObject ) ;
// take out IWbemClassObject and cast it to a Win32_ACE object.
if(pACEObject)
{
CInstance ACEInstance(pACEObject, pMethodContext);
// create an AccessEntry object from the Win32_ACE object.
bool bExists =false ;
VARTYPE eType ;
// get Win32_Trustee object from Win32_ACE ...& decipher the ACE
if ( ACEInstance.GetStatus ( IDS_Trustee, bExists , eType ) && bExists && eType == VT_UNKNOWN )
{
CInstancePtr pTrustee;
if ( ACEInstance.GetEmbeddedObject ( IDS_Trustee, &pTrustee, ACEInstance.GetMethodContext() ) )
{
CSid sid ;
if((dwStatus = FillSIDFromTrustee(pTrustee, sid)) == ERROR_SUCCESS)
{
DWORD dwAceType, dwAceFlags, dwAccessMask ;
CHString chstrInhObjGuid;
GUID *pguidInhObjGuid = NULL;
CHString chstrObjGuid;
GUID *pguidObjGuid = NULL;
ACEInstance.GetDWORD(IDS_AceType, dwAceType);
ACEInstance.GetDWORD(IDS_AceFlags, dwAceFlags);
ACEInstance.GetDWORD(IDS_AccessMask, dwAccessMask);
// The OS doesn't seem to support 0x01000000 or 0x02000000, so we won't either. We
// will translate 0x02000000 into FILE_ALL_ACCESS, however (seems like the nice thing to do)
// but only if that is the exact value they set.
if(dwAccessMask == 0x02000000)
{
dwAccessMask = FILE_ALL_ACCESS;
}
#if NTONLY >= 5
// On NT5 and greater, if the user specified an ACE with the Ace Flag bit INHERIT_ACE set,
// the OS will make these local, not inherited ACE entries. However, the OS will not reorder
// the DACL, possibly resulting in a situation in which denied ACEs (that had been inherited)
// follow allowed ACEs.
// So if the Ace flags specify INHERITED_ACE, we need to turn
// off this bit...
dwAceFlags &= ~INHERITED_ACE;
#endif
if(!(dwAceFlags & INHERITED_ACE))
{
switch (dwAceType)
{
case ACCESS_DENIED_ACE_TYPE:
{
dacl.AddDACLEntry( sid.GetPSid(), ENUM_ACCESS_DENIED_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL );
break;
}
case ACCESS_ALLOWED_ACE_TYPE:
{
dacl.AddDACLEntry( sid.GetPSid(), ENUM_ACCESS_ALLOWED_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL );
break;
}
#if NTONLY >= 5
// Not yet supported under W2K
//case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
// {
// dacl.AddDACLEntry( sid.GetPSid(), ENUM_ACCESS_ALLOWED_COMPOUND_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL );
// break;
// }
case ACCESS_DENIED_OBJECT_ACE_TYPE:
{
// Need to get the guids for this type...
if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid))
{
if(chstrObjGuid.GetLength() != 0)
{
try
{
pguidObjGuid = new GUID;
}
catch(...)
{
if(pguidObjGuid != NULL)
{
delete pguidObjGuid;
pguidObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid);
}
}
if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid))
{
if(chstrInhObjGuid.GetLength() != 0)
{
try
{
pguidInhObjGuid = new GUID;
}
catch(...)
{
if(pguidInhObjGuid != NULL)
{
delete pguidInhObjGuid;
pguidInhObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid);
}
}
dacl.AddDACLEntry( sid.GetPSid(), ENUM_ACCESS_DENIED_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid);
if(pguidObjGuid != NULL) delete pguidObjGuid;
if(pguidInhObjGuid != NULL) delete pguidInhObjGuid;
break;
}
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
{
// Need to get the guids for this type...
if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid))
{
if(chstrObjGuid.GetLength() != 0)
{
try
{
pguidObjGuid = new GUID;
}
catch(...)
{
if(pguidObjGuid != NULL)
{
delete pguidObjGuid;
pguidObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid);
}
}
if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid))
{
if(chstrInhObjGuid.GetLength() != 0)
{
try
{
pguidInhObjGuid = new GUID;
}
catch(...)
{
if(pguidInhObjGuid != NULL)
{
delete pguidInhObjGuid;
pguidInhObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid);
}
}
dacl.AddDACLEntry( sid.GetPSid(), ENUM_ACCESS_ALLOWED_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid);
if(pguidObjGuid != NULL) delete pguidObjGuid;
if(pguidInhObjGuid != NULL) delete pguidInhObjGuid;
break;
}
#endif
default:
{
dwStatus = ERROR_INVALID_PARAMETER ;
break ;
}
}
}
else
{
switch (dwAceType)
{
case ACCESS_DENIED_ACE_TYPE:
{
dacl.AddDACLEntry( sid.GetPSid(), ENUM_INH_ACCESS_DENIED_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL );
break;
}
case ACCESS_ALLOWED_ACE_TYPE:
{
dacl.AddDACLEntry( sid.GetPSid(), ENUM_INH_ACCESS_ALLOWED_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL );
break;
}
#if NTONLY >= 5
// Not yet supported under W2K
//case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
// {
// dacl.AddDACLEntry( sid.GetPSid(), ENUM_INH_ACCESS_ALLOWED_COMPOUND_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL );
// break;
// }
case ACCESS_DENIED_OBJECT_ACE_TYPE:
{
// Need to get the guids for this type...
if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid))
{
if(chstrObjGuid.GetLength() != 0)
{
try
{
pguidObjGuid = new GUID;
}
catch(...)
{
if(pguidObjGuid != NULL)
{
delete pguidObjGuid;
pguidObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid);
}
}
if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid))
{
if(chstrInhObjGuid.GetLength() != 0)
{
try
{
pguidInhObjGuid = new GUID;
}
catch(...)
{
if(pguidInhObjGuid != NULL)
{
delete pguidInhObjGuid;
pguidInhObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid);
}
}
dacl.AddDACLEntry( sid.GetPSid(), ENUM_INH_ACCESS_DENIED_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid );
if(pguidObjGuid != NULL) delete pguidObjGuid;
if(pguidInhObjGuid != NULL) delete pguidInhObjGuid;
break;
}
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
{
// Need to get the guids for this type...
if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid))
{
if(chstrObjGuid.GetLength() != 0)
{
try
{
pguidObjGuid = new GUID;
}
catch(...)
{
if(pguidObjGuid != NULL)
{
delete pguidObjGuid;
pguidObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid);
}
}
if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid))
{
if(chstrInhObjGuid.GetLength() != 0)
{
try
{
pguidInhObjGuid = new GUID;
}
catch(...)
{
if(pguidInhObjGuid != NULL)
{
delete pguidInhObjGuid;
pguidInhObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid);
}
}
dacl.AddDACLEntry( sid.GetPSid(), ENUM_INH_ACCESS_ALLOWED_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid );
if(pguidObjGuid != NULL) delete pguidObjGuid;
if(pguidInhObjGuid != NULL) delete pguidInhObjGuid;
break;
}
#endif
default:
{
dwStatus = ERROR_INVALID_PARAMETER ;
break ;
}
}
}
}
else
{
dwStatus = ERROR_INVALID_PARAMETER;
}
//pTrustee->Release(); // smartpointer already releases when goes out of scope
}
} // get Win32_Trustee object from Win32_ACE ...& decipher the ACE
}
} // end for loop
if(lLowerBound == 0 && lUpperBound == -1L)
{
// DACL was EMPTY - not necessarily wrong
dwStatus = STATUS_EMPTY_DACL;
}
}
VariantClear( &vDacl ) ;
}
else //DACL was NULL - not nescessarily wrong.
{
dwStatus = STATUS_NULL_DACL ;
}
}
return dwStatus ;
}
///////////////////////////////////////////////////////////////////
//
// Function: FillSACLFromInstance
//
// Default class constructor.
//
// Inputs:
// None.
//
// Outputs:
// None.
//
// Returns:
// None.
//
// Comments:
//
///////////////////////////////////////////////////////////////////
DWORD FillSACLFromInstance(CInstance *pInstance,
CSACL &sacl,
MethodContext *pMethodContext)
{
IWbemClassObjectPtr piClassObject;
piClassObject.Attach(pInstance->GetClassObjectInterface());
DWORD dwStatus = ERROR_SUCCESS ;
if(piClassObject)
{
VARIANT vSacl ;
if(GetArray(piClassObject, IDS_SACL, vSacl, VT_UNKNOWN|VT_ARRAY ) )
{
if( vSacl.vt != VT_NULL && vSacl.parray != NULL )
{
// walk DACL
LONG lDimension = 1 ;
LONG lLowerBound ;
SafeArrayGetLBound ( vSacl.parray , lDimension , &lLowerBound ) ;
LONG lUpperBound ;
SafeArrayGetUBound ( vSacl.parray , lDimension , &lUpperBound ) ;
for ( LONG lIndex = lLowerBound ; lIndex <= lUpperBound ; lIndex++ )
{
if( dwStatus != ERROR_SUCCESS )
{
break ;
}
IWbemClassObjectPtr pACEObject;
SafeArrayGetElement ( vSacl.parray , &lIndex , &pACEObject ) ;
// take out IWbemClassObject and cast it to a Win32_ACE object.
if(pACEObject)
{
CInstance ACEInstance(pACEObject, pMethodContext);
// create an AccessEntry object from the Win32_ACE object.
bool bExists =false ;
VARTYPE eType ;
// get Win32_Trustee object from Win32_ACE ...& decipher the ACE
if ( ACEInstance.GetStatus ( IDS_Trustee, bExists , eType ) && bExists && eType == VT_UNKNOWN )
{
CInstancePtr pTrustee;
if ( ACEInstance.GetEmbeddedObject ( IDS_Trustee, &pTrustee, ACEInstance.GetMethodContext() ) )
{
CSid sid ;
if(FillSIDFromTrustee(pTrustee, sid) == ERROR_SUCCESS)
{
DWORD dwAceType, dwAceFlags, dwAccessMask ;
CHString chstrInhObjGuid;
GUID *pguidInhObjGuid = NULL;
CHString chstrObjGuid;
GUID *pguidObjGuid = NULL;
ACEInstance.GetDWORD(IDS_AceType, dwAceType);
ACEInstance.GetDWORD(IDS_AceFlags, dwAceFlags);
ACEInstance.GetDWORD(IDS_AccessMask, dwAccessMask);
switch(dwAceType)
{
case SYSTEM_AUDIT_ACE_TYPE:
{
sacl.AddSACLEntry( sid.GetPSid(), ENUM_SYSTEM_AUDIT_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL );
break;
}
#if NTONLY >= 5
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
{
// Need to get the guids for this type...
if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid))
{
if(chstrObjGuid.GetLength() != 0)
{
try
{
pguidObjGuid = new GUID;
}
catch(...)
{
if(pguidObjGuid != NULL)
{
delete pguidObjGuid;
pguidObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid);
}
}
if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid))
{
if(chstrInhObjGuid.GetLength() != 0)
{
try
{
pguidInhObjGuid = new GUID;
}
catch(...)
{
if(pguidInhObjGuid != NULL)
{
delete pguidInhObjGuid;
pguidInhObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid);
}
}
sacl.AddSACLEntry( sid.GetPSid(), ENUM_SYSTEM_AUDIT_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid );
if(pguidObjGuid != NULL) delete pguidObjGuid;
if(pguidInhObjGuid != NULL) delete pguidInhObjGuid;
break;
}
/********************************* type not yet supported under w2k ********************************************
case SYSTEM_ALARM_ACE_TYPE:
{
sacl.AddSACLEntry( sid.GetPSid(), ENUM_SYSTEM_ALARM_ACE_TYPE, dwAccessMask, dwAceFlags, NULL, NULL );
break;
}
/********************************* type not yet supported under w2k ********************************************
/********************************* type not yet supported under w2k ********************************************
case SYSTEM_ALARM_OBJECT_ACE_TYPE:
{
// Need to get the guids for this type...
if(!ACEInstance.IsNull(IDS_ObjectTypeGUID) && ACEInstance.GetCHString(IDS_ObjectTypeGUID, chstrObjGuid))
{
if(chstrObjGuid.GetLength() != 0)
{
try
{
pguidObjGuid = new GUID;
}
catch(...)
{
if(pguidObjGuid != NULL)
{
delete pguidObjGuid;
pguidObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrObjGuid, pguidObjGuid);
}
}
if(!ACEInstance.IsNull(IDS_InheritedObjectGUID) && ACEInstance.GetCHString(IDS_InheritedObjectGUID, chstrInhObjGuid))
{
if(chstrInhObjGuid.GetLength() != 0)
{
try
{
pguidInhObjGuid = new GUID;
}
catch(...)
{
if(pguidInhObjGuid != NULL)
{
delete pguidInhObjGuid;
pguidInhObjGuid = NULL;
}
}
CLSIDFromString((LPWSTR)(LPCWSTR)chstrInhObjGuid, pguidInhObjGuid);
}
}
sacl.AddSACLEntry( sid.GetPSid(), ENUM_SYSTEM_ALARM_OBJECT_ACE_TYPE, dwAccessMask, dwAceFlags, pguidObjGuid, pguidInhObjGuid );
if(pguidObjGuid != NULL) delete pguidObjGuid;
if(pguidInhObjGuid != NULL) delete pguidInhObjGuid;
break;
}
/********************************* type not yet supported under w2k ********************************************/
#endif
default:
{
dwStatus = ERROR_INVALID_PARAMETER ;
break;
}
}
}
else
{
dwStatus = ERROR_INVALID_PARAMETER;
}
//pTrustee->Release(); // smartpointer already releases when goes out of scope
}
} // get Win32_Trustee object from Win32_ACE ...& decipher the ACE
} //if(pACEObject)
} //for
} //if(pSACL)
VariantClear( &vSacl ) ;
}
else
{
dwStatus = ERROR_INVALID_PARAMETER ;
}
}
return dwStatus ;
}
bool GetArray(IWbemClassObject *piClassObject,
const CHString &name,
VARIANT &v,
VARTYPE eVariantType)
{
bool bRet = FALSE;
VariantInit(&v);
if (piClassObject)
{
BSTR pName = NULL;
HRESULT hr;
try
{
pName = name.AllocSysString();
hr = piClassObject->Get(pName, 0, &v, NULL, NULL);
SysFreeString(pName);
}
catch(...)
{
if(pName != NULL)
{
SysFreeString(pName);
pName = NULL;
}
throw;
}
ASSERT_BREAK((SUCCEEDED(hr)) && ((v.vt == VT_NULL) || (v.vt == eVariantType )));
if (bRet = (bool)SUCCEEDED(hr))
{
if ( v.vt != VT_NULL && v.parray != NULL )
{
if (v.vt == eVariantType )
{
bRet = TRUE ;
}
else
{
bRet = FALSE;
}
}
else
{
bRet = FALSE;
}
}
}
if (!bRet)
{
VariantClear(&v);
}
return bRet;
}
DWORD FillSIDFromTrustee(CInstance *pTrustee, CSid &sid)
{
IWbemClassObjectPtr m_piClassObject;
DWORD dwStatus = ERROR_SUCCESS ;
if(pTrustee)
{
m_piClassObject.Attach(pTrustee->GetClassObjectInterface());
VARIANT vtmp ;
bool fSidObtained = false;
if(GetArray(m_piClassObject,IDS_SID, vtmp, VT_UI1|VT_ARRAY ) )
{
if( vtmp.vt != VT_NULL && vtmp.parray != NULL )
{
if ( ::SafeArrayGetDim ( vtmp.parray ) == 1 )
{
long lLowerBound , lUpperBound = 0 ;
::SafeArrayGetLBound ( vtmp.parray, 1, & lLowerBound ) ;
::SafeArrayGetUBound ( vtmp.parray, 1, & lUpperBound ) ;
PSID pSid = NULL ;
PVOID pTmp = NULL ;
if(SUCCEEDED(::SafeArrayAccessData(vtmp.parray, &pTmp) ) )
{
pSid = (PSID) malloc(lUpperBound - lLowerBound + 1) ;
if(pSid)
{
try
{
memcpy(pSid,pTmp,lUpperBound - lLowerBound + 1) ;
::SafeArrayUnaccessData(vtmp.parray) ;
sid = CSid(pSid);
free(pSid) ;
pSid = NULL;
fSidObtained = true;
}
catch(...)
{
free(pSid) ;
pSid = NULL;
throw;
}
}
else
{
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
}
}
else
{
dwStatus = ERROR_INVALID_PARAMETER ;
}
}
else
{
dwStatus = ERROR_INVALID_PARAMETER ;
}
}
::VariantClear( &vtmp ) ;
}
if(!fSidObtained && (dwStatus == ERROR_SUCCESS))
{
// If we couldn't obtain the sid from the binary
// representation, try to do so from the sid string
// representation (the SIDString property)...
CHString chstrSIDString;
if(pTrustee->GetCHString(IDS_SIDString, chstrSIDString) &&
chstrSIDString.GetLength() > 0)
{
PSID pSid = NULL;
pSid = StrToSID(chstrSIDString);
if(pSid)
{
try
{
sid = CSid(pSid);
::FreeSid(pSid);
pSid = NULL;
fSidObtained = true;
}
catch(...)
{
::FreeSid(pSid);
pSid = NULL;
throw;
}
}
else
{
dwStatus = ERROR_INVALID_PARAMETER;
}
}
// If we couldn't obtain the sid from either the binary
// representation or the SIDString representation, try to
// do so from the Domain and Name properties (attempting
// resolution on the local machine for lack of a better
// choice)...
if(!fSidObtained && (dwStatus == ERROR_SUCCESS))
{
CHString chstrDomain, chstrName;
pTrustee->GetCHString(IDS_Domain, chstrDomain);
// Although we don't care whether we were able
// to get the Domain above, we must at least have
// a Name property specified...
if(pTrustee->GetCHString(IDS_Name, chstrName) &&
chstrName.GetLength() > 0)
{
CSid csTmp(chstrDomain, chstrName, NULL);
if(csTmp.IsOK() && csTmp.IsValid())
{
sid = csTmp;
fSidObtained = true;
}
}
}
}
if(!fSidObtained && (dwStatus == ERROR_SUCCESS))
{
dwStatus = ERROR_INVALID_PARAMETER ;
}
}
else
{
dwStatus = ERROR_INVALID_PARAMETER;
}
return dwStatus ;
}
#ifdef NTONLY
// Handy utility to dump the contents of a descriptor to
// our log file.
void DumpWin32Descriptor(PSECURITY_DESCRIPTOR psd, LPCWSTR wstrFilename)
{
CSecurityDescriptor csd(psd);
csd.DumpDescriptor();
}
#endif
#ifdef NTONLY
void Output(LPCWSTR wstrOut, LPCWSTR wstrFilename)
{
// Single point where we can control where output from
// all security utility class Dump routines goes...
if(wstrFilename == NULL)
{
LogMessage(wstrOut);
}
else
{
FILE *fp = NULL;
if((fp = _wfopen(wstrFilename, L"at")) != NULL)
{
fwprintf(fp, wstrOut);
fwprintf(fp,L"\r\n");
fclose(fp);
}
fp = NULL;
}
}
#endif
// Returns true if the user associated with the current
// thread is either the owner or is a member of the group
// that is the owner - e.g., it returns true if said user
// has ownership of the object specified by chstrName.
#ifdef NTONLY
bool AmIAnOwner(const CHString &chstrName, SE_OBJECT_TYPE ObjectType)
{
bool fRet = false;
// ALGORITHM OVERVIEW
// 1) Get the sid of the user associated with the current thread.
// 2) Get the owner of the object.
// 3a) Compare the sid from #2 to that from #1. fRet is true if they are equal.
// 3b) If not, owner's sid may be that of a group, and the user might be a
// member of that group, or of a group (which would have to be a global group)
// within that group. Fortunately that doesnt't recurse indefinitely, since
// local groups can contain only global groups, and global groups can contain
// only users (they can't be a container for other global or local groups) - see
// "Windows NT Security" (Nik Okuntseff), pp. 34-35.
// So here we go...
// 1) Get the sid of the user associated with the current thread. Also filter out only object types we are equiped to deal with...
if(ObjectType == SE_FILE_OBJECT || ObjectType == SE_LMSHARE)
{
CAccessRights car(true); // true tells car to use the user associated with the current thread token
CSid csidCurrentUser;
if(car.GetCSid(csidCurrentUser, true)) // true signals that we want car to be initialized with the domain and name looked up
{
// 2) Get the owner of the object.
CSid csidOwner;
switch(ObjectType)
{
case SE_FILE_OBJECT:
{
CSecureFile csf;
if(csf.SetFileName(chstrName, FALSE) == ERROR_SUCCESS) //FALSE means we don't need the SACL
{
csf.GetOwner(csidOwner);
}
break;
}
case SE_LMSHARE:
{
CSecureShare css;
if(css.SetShareName(chstrName) == ERROR_SUCCESS)
{
css.GetOwner(csidOwner);
}
break;
}
default:
{
ASSERT_BREAK(0);
}
}
// Proceed as long as the owner sid is valid and 'ok'...
if(csidOwner.IsValid() && csidOwner.IsOK())
{
// 3a) Compare the sid from #2 to that from #1. fRet is true if they are equal.
if(csidCurrentUser == csidOwner)
{
fRet = true;
}
else // owner might be a group...
{
// 3b) If not, owner's sid may be that of a group, and the user might be a
// member of that group, or of a group (which would have to be a global group)
// within that group. Fortunately that doesnt't recurse indefinitely, since
// local groups can contain only global groups, and global groups can contain
// only users (they can't be a container for other global or local groups) - see
// "Windows NT Security" (Nik Okuntseff), pp. 34-35.
// Since this could be a pain, call a friendly helper...
SID_NAME_USE snuOwner = csidOwner.GetAccountType();
if(snuOwner == SidTypeGroup || snuOwner == SidTypeAlias || snuOwner == SidTypeWellKnownGroup)
{
if(IsUserInGroup(csidCurrentUser, csidOwner, snuOwner))
{
fRet = true;
}
}
}
}
} // we got the thread sid
} // its an object we like
return fRet;
}
#endif
// Helper to determine if a particular is a member of a group, or of one of the
// (global) groups that might be a member of that group.
#ifdef NTONLY
bool IsUserInGroup(const CSid &csidUser,
const CSid &csidGroup,
SID_NAME_USE snuGroup)
{
bool fRet = false;
CNetAPI32 netapi ;
if(netapi.Init() == ERROR_SUCCESS)
{
fRet = RecursiveFindUserInGroup(netapi,
csidGroup.GetDomainName(),
csidGroup.GetAccountName(),
snuGroup,
csidUser);
}
return fRet;
}
#endif
#ifdef NTONLY
bool RecursiveFindUserInGroup(CNetAPI32 &netapi,
const CHString &chstrDomainName,
const CHString &chstrGroupName,
SID_NAME_USE snuGroup,
const CSid &csidUser)
{
bool fRet = false;
NET_API_STATUS stat;
DWORD dwNumReturnedEntries = 0, dwIndex = 0, dwTotalEntries = 0;
DWORD_PTR dwptrResume = NULL;
// Domain Groups
if (snuGroup == SidTypeGroup)
{
GROUP_USERS_INFO_0 *pGroupMemberData = NULL;
CHString chstrDCName;
if (netapi.GetDCName(chstrDomainName, chstrDCName) == ERROR_SUCCESS)
{
do
{
// Accept up to 256k worth of data.
stat = netapi.NetGroupGetUsers(chstrDCName,
chstrGroupName,
0,
(LPBYTE *)&pGroupMemberData,
262144,
&dwNumReturnedEntries,
&dwTotalEntries,
&dwptrResume);
// If we got some data
if(ERROR_SUCCESS == stat || ERROR_MORE_DATA == stat)
{
try
{
// Walk through all the returned entries...
for(DWORD dwCtr = 0; dwCtr < dwNumReturnedEntries; dwCtr++)
{
// Get the sid type for this object...
CSid sid(chstrDomainName, CHString(pGroupMemberData[dwCtr].grui0_name), NULL);
if(sid == csidUser)
{
fRet = true;
}
}
}
catch ( ... )
{
netapi.NetApiBufferFree( pGroupMemberData );
throw ;
}
netapi.NetApiBufferFree( pGroupMemberData );
} // IF stat OK
} while ( ERROR_MORE_DATA == stat && !fRet);
}
// Local Groups
}
else if(snuGroup == SidTypeAlias || snuGroup == SidTypeWellKnownGroup)
{
LOCALGROUP_MEMBERS_INFO_1 *pGroupMemberData = NULL;
do
{
// Accept up to 256k worth of data.
stat = netapi.NetLocalGroupGetMembers(NULL,
chstrGroupName,
1,
(LPBYTE *)&pGroupMemberData,
262144,
&dwNumReturnedEntries,
&dwTotalEntries,
&dwptrResume);
// If we got some data
if ( ERROR_SUCCESS == stat || ERROR_MORE_DATA == stat )
{
try
{
// Walk through all the returned entries
for(DWORD dwCtr = 0; dwCtr < dwNumReturnedEntries && !fRet; dwCtr++)
{
// If this is a recognized type...
CSid sid(pGroupMemberData[dwCtr].lgrmi1_sid);
switch(pGroupMemberData[dwCtr].lgrmi1_sidusage)
{
case SidTypeUser:
{
if(sid == csidUser)
{
fRet = true;
}
break;
}
case SidTypeGroup:
{
// If the group contained a group (would be a global group),
// we need to recurse.
fRet = RecursiveFindUserInGroup(netapi,
sid.GetDomainName(),
sid.GetAccountName(),
pGroupMemberData[dwCtr].lgrmi1_sidusage,
csidUser);
break;
}
case SidTypeWellKnownGroup:
{
// If the group contained a group (would be a global group),
// we need to recurse.
fRet = RecursiveFindUserInGroup(netapi,
sid.GetDomainName(),
sid.GetAccountName(),
pGroupMemberData[dwCtr].lgrmi1_sidusage,
csidUser);
break;
}
default:
{
ASSERT_BREAK(0);
break;
}
}
}
}
catch ( ... )
{
netapi.NetApiBufferFree( pGroupMemberData );
throw ;
}
netapi.NetApiBufferFree( pGroupMemberData );
} // IF stat OK
} while ( ERROR_MORE_DATA == stat && !fRet);
}
else
{
// Unrecognized Group type
ASSERT_BREAK(0);
}
return fRet;
}
#endif