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
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
|