563 lines
14 KiB
C++
563 lines
14 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 2000
|
|
//
|
|
// File: SecUtil.cpp
|
|
//
|
|
// Contents: Utility functions for working with security APIs
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
|
|
#include "secutil.h"
|
|
|
|
extern const GUID GUID_CONTROL_UserChangePassword =
|
|
{ 0xab721a53, 0x1e2f, 0x11d0, { 0x98, 0x19, 0x00, 0xaa, 0x00, 0x40, 0x52, 0x9b}};
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSimpleSecurityDescriptorHolder::CSimpleSecurityDescriptorHolder
|
|
//
|
|
// Synopsis: Constructor for the smart security descriptor
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
CSimpleSecurityDescriptorHolder::CSimpleSecurityDescriptorHolder()
|
|
{
|
|
m_pSD = NULL;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSimpleSecurityDescriptorHolder::~CSimpleSecurityDescriptorHolder
|
|
//
|
|
// Synopsis: Destructor for the smart security descriptor
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
CSimpleSecurityDescriptorHolder::~CSimpleSecurityDescriptorHolder()
|
|
{
|
|
if (m_pSD != NULL)
|
|
{
|
|
::LocalFree(m_pSD);
|
|
m_pSD = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSidHolder::CSidHolder
|
|
//
|
|
// Synopsis: Constructor : initializes the member data
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
CSidHolder::CSidHolder()
|
|
{
|
|
_Init();
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSidHolder::~CSidHolder
|
|
//
|
|
// Synopsis: Destructor : Frees all data associated with the wrapped SID
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
CSidHolder::~CSidHolder()
|
|
{
|
|
_Free();
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSidHolder::Get
|
|
//
|
|
// Synopsis: Public accessor to the SID being wrapped
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: PSID : pointer to the SID being wrapped. NULL if the class
|
|
// is not currently wrapping a SID
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
PSID CSidHolder::Get()
|
|
{
|
|
return m_pSID;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSidHolder::Copy
|
|
//
|
|
// Synopsis: Frees the memory associated with the currently wrapped SID
|
|
// and then copies the new SID
|
|
//
|
|
// Arguments: [p - IN] : SID to be copied
|
|
//
|
|
// Returns: bool : true if the copy was successful, false otherwise
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
bool CSidHolder::Copy(PSID p)
|
|
{
|
|
_Free();
|
|
return _Copy(p);
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSidHolder::Attach
|
|
//
|
|
// Synopsis: Attaches the SID to the wrapper
|
|
//
|
|
// Arguments: [p - IN] : SID to be wrapped by this class
|
|
// [bLocalAlloc - OUT] : tells whether the SID should be freed
|
|
// with LocalFree
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void CSidHolder::Attach(PSID p, bool bLocalAlloc)
|
|
{
|
|
_Free();
|
|
m_pSID = p;
|
|
m_bLocalAlloc = bLocalAlloc;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSidHolder::Clear
|
|
//
|
|
// Synopsis: Frees the memory associated with the SID being wrapped
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void CSidHolder::Clear()
|
|
{
|
|
_Free();
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSidHolder::_Init
|
|
//
|
|
// Synopsis: Initializes the member data to default values
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void CSidHolder::_Init()
|
|
{
|
|
m_pSID = NULL;
|
|
m_bLocalAlloc = TRUE;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSidHolder::_Free
|
|
//
|
|
// Synopsis: Frees the memory associated with the SID being wrapped
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void CSidHolder::_Free()
|
|
{
|
|
if (m_pSID != NULL)
|
|
{
|
|
if (m_bLocalAlloc)
|
|
{
|
|
::LocalFree(m_pSID);
|
|
}
|
|
else
|
|
{
|
|
::FreeSid(m_pSID);
|
|
_Init();
|
|
}
|
|
}
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CSidHolder::_Copy
|
|
//
|
|
// Synopsis: Makes a copy of the SID being wrapped
|
|
//
|
|
// Arguments: [p - OUT] : destination of the SID being copied
|
|
//
|
|
// Returns: bool : true if SID was copied successfully
|
|
// false if there was a failure
|
|
//
|
|
// History: 15-Sep-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
bool CSidHolder::_Copy(PSID p)
|
|
{
|
|
if ( (p == NULL) || !::IsValidSid(p) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DWORD dwLen = ::GetLengthSid(p);
|
|
PSID pNew = ::LocalAlloc(LPTR, dwLen);
|
|
if (pNew == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Security Review:This is fine. Buffer is correctly allocated.
|
|
if (!::CopySid(dwLen, pNew, p))
|
|
{
|
|
::LocalFree(pNew);
|
|
return false;
|
|
}
|
|
m_bLocalAlloc = TRUE;
|
|
m_pSID = pNew;
|
|
|
|
ASSERT(dwLen == ::GetLengthSid(m_pSID));
|
|
ASSERT(memcmp(p, m_pSID, dwLen) == 0);
|
|
return true;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SetSecurityInfoMask
|
|
//
|
|
// Synopsis: Reads the security descriptor from the specied DS object
|
|
//
|
|
// Arguments: [IN punk] -- IUnknown from IDirectoryObject
|
|
// [IN si] -- SecurityInformation
|
|
//// History: 25-Dec-2000 -- Hiteshr Created
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
SetSecurityInfoMask(LPUNKNOWN punk, SECURITY_INFORMATION si)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
if (punk)
|
|
{
|
|
IADsObjectOptions *pOptions;
|
|
hr = punk->QueryInterface(IID_IADsObjectOptions, (void**)&pOptions);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT var;
|
|
VariantInit(&var);
|
|
V_VT(&var) = VT_I4;
|
|
V_I4(&var) = si;
|
|
hr = pOptions->SetOption(ADS_OPTION_SECURITY_MASK, var);
|
|
pOptions->Release();
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
WCHAR const c_szSDProperty[] = L"nTSecurityDescriptor";
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DSReadObjectSecurity
|
|
//
|
|
// Synopsis: Reads the Dacl from the specied DS object
|
|
//
|
|
// Arguments: [in pDsObject] -- IDirettoryObject for dsobject
|
|
// [psdControl] -- Control Setting for SD
|
|
// They can be returned when calling
|
|
// DSWriteObjectSecurity
|
|
// [OUT ppDacl] -- DACL returned here
|
|
//
|
|
//
|
|
// History 25-Oct-2000 -- hiteshr created
|
|
//
|
|
// Notes: If Object Doesn't have DACL, function will succeed but *ppDacl will
|
|
// be NULL.
|
|
// Caller must free *ppDacl, if not NULL, by calling LocalFree
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
DSReadObjectSecurity(IN IDirectoryObject *pDsObject,
|
|
OUT SECURITY_DESCRIPTOR_CONTROL * psdControl,
|
|
OUT PACL *ppDacl)
|
|
{
|
|
ENTER_FUNCTION_HR(LEVEL5_LOGGING, DSReadObjectSecurity, hr);
|
|
|
|
PADS_ATTR_INFO pSDAttributeInfo = NULL;
|
|
|
|
do // false loop
|
|
{
|
|
LPWSTR pszSDProperty = (LPWSTR)c_szSDProperty;
|
|
DWORD dwAttributesReturned;
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
PACL pAcl = NULL;
|
|
|
|
if(!pDsObject || !ppDacl)
|
|
{
|
|
ASSERT(FALSE);
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
*ppDacl = NULL;
|
|
|
|
// Set the SECURITY_INFORMATION mask
|
|
hr = SetSecurityInfoMask(pDsObject, DACL_SECURITY_INFORMATION);
|
|
if(FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Read the security descriptor
|
|
//
|
|
hr = pDsObject->GetObjectAttributes(&pszSDProperty,
|
|
1,
|
|
&pSDAttributeInfo,
|
|
&dwAttributesReturned);
|
|
if (SUCCEEDED(hr) && !pSDAttributeInfo)
|
|
hr = E_ACCESSDENIED; // This happens for SACL if no SecurityPrivilege
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
ASSERT(ADSTYPE_NT_SECURITY_DESCRIPTOR == pSDAttributeInfo->dwADsType);
|
|
ASSERT(ADSTYPE_NT_SECURITY_DESCRIPTOR == pSDAttributeInfo->pADsValues->dwType);
|
|
|
|
pSD = (PSECURITY_DESCRIPTOR)pSDAttributeInfo->pADsValues->SecurityDescriptor.lpValue;
|
|
|
|
ASSERT(IsValidSecurityDescriptor(pSD));
|
|
|
|
|
|
//
|
|
//Get the security descriptor control
|
|
//
|
|
if(psdControl)
|
|
{
|
|
DWORD dwRevision;
|
|
if(!GetSecurityDescriptorControl(pSD, psdControl, &dwRevision))
|
|
{
|
|
DWORD _dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32( _dwErr );
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//Get pointer to DACL
|
|
//
|
|
BOOL bDaclPresent, bDaclDefaulted;
|
|
if(!GetSecurityDescriptorDacl(pSD,
|
|
&bDaclPresent,
|
|
&pAcl,
|
|
&bDaclDefaulted))
|
|
{
|
|
DWORD _dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32( _dwErr );
|
|
break;
|
|
}
|
|
|
|
if(!bDaclPresent ||
|
|
!pAcl)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ASSERT(IsValidAcl(pAcl));
|
|
|
|
//
|
|
//Make a copy of the DACL
|
|
//
|
|
*ppDacl = (PACL)LocalAlloc(LPTR,pAcl->AclSize);
|
|
if(!*ppDacl)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
//Security Review:This is fine. Memory is correctly allocted above.
|
|
CopyMemory(*ppDacl,pAcl,pAcl->AclSize);
|
|
|
|
}while(0);
|
|
|
|
|
|
if (pSDAttributeInfo)
|
|
FreeADsMem(pSDAttributeInfo);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DSWriteObjectSecurity
|
|
//
|
|
// Synopsis: Writes the Dacl to the specied DS object
|
|
//
|
|
// Arguments: [in pDsObject] -- IDirettoryObject for dsobject
|
|
// [sdControl] -- control for security descriptor
|
|
// [IN pDacl] -- The DACL to be written
|
|
//
|
|
// History 25-Oct-2000 -- hiteshr created
|
|
//----------------------------------------------------------------------------
|
|
HRESULT
|
|
DSWriteObjectSecurity(IN IDirectoryObject *pDsObject,
|
|
IN SECURITY_DESCRIPTOR_CONTROL sdControl,
|
|
PACL pDacl)
|
|
{
|
|
ENTER_FUNCTION_HR(LEVEL5_LOGGING, DSWriteObjectSecurity, hr);
|
|
|
|
PISECURITY_DESCRIPTOR pSD = NULL;
|
|
PSECURITY_DESCRIPTOR psd = NULL;
|
|
|
|
do // false loop
|
|
{
|
|
ADSVALUE attributeValue;
|
|
ADS_ATTR_INFO attributeInfo;
|
|
DWORD dwAttributesModified;
|
|
DWORD dwSDLength;
|
|
|
|
if(!pDsObject || !pDacl)
|
|
{
|
|
ASSERT(FALSE);
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
ASSERT(IsValidAcl(pDacl));
|
|
|
|
// Set the SECURITY_INFORMATION mask
|
|
hr = SetSecurityInfoMask(pDsObject, DACL_SECURITY_INFORMATION);
|
|
if(FAILED(hr))
|
|
{
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING,
|
|
L"SetSecurityInfoMask failed: hr = 0x%x",
|
|
hr);
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
//Build the Security Descriptor
|
|
//
|
|
pSD = (PISECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
if (pSD == NULL)
|
|
{
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING,
|
|
L"Failed to allocate memory for Security Descriptor");
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
//Security Review:This is fine.
|
|
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
|
|
|
|
//
|
|
// Finally, build the security descriptor
|
|
//
|
|
pSD->Control |= SE_DACL_PRESENT | SE_DACL_AUTO_INHERIT_REQ
|
|
| (sdControl & (SE_DACL_PROTECTED | SE_DACL_AUTO_INHERITED));
|
|
|
|
if(pDacl->AclSize)
|
|
{
|
|
pSD->Dacl = pDacl;
|
|
}
|
|
|
|
//
|
|
// Need the total size
|
|
//
|
|
dwSDLength = GetSecurityDescriptorLength(pSD);
|
|
|
|
//
|
|
// If necessary, make a self-relative copy of the security descriptor
|
|
//
|
|
psd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSDLength);
|
|
|
|
if (psd == NULL ||
|
|
!MakeSelfRelativeSD(pSD, psd, &dwSDLength))
|
|
{
|
|
DWORD _dwErr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32( _dwErr );
|
|
DEBUG_OUTPUT(MINIMAL_LOGGING,
|
|
L"MakeSelfRelativeSD failed: hr = 0x%x",
|
|
hr);
|
|
break;
|
|
}
|
|
|
|
|
|
attributeValue.dwType = ADSTYPE_NT_SECURITY_DESCRIPTOR;
|
|
attributeValue.SecurityDescriptor.dwLength = dwSDLength;
|
|
attributeValue.SecurityDescriptor.lpValue = (LPBYTE)psd;
|
|
|
|
attributeInfo.pszAttrName = (LPWSTR)c_szSDProperty;
|
|
attributeInfo.dwControlCode = ADS_ATTR_UPDATE;
|
|
attributeInfo.dwADsType = ADSTYPE_NT_SECURITY_DESCRIPTOR;
|
|
attributeInfo.pADsValues = &attributeValue;
|
|
attributeInfo.dwNumValues = 1;
|
|
|
|
// Write the security descriptor
|
|
hr = pDsObject->SetObjectAttributes(&attributeInfo,
|
|
1,
|
|
&dwAttributesModified);
|
|
} while (false);
|
|
|
|
if (psd != NULL)
|
|
{
|
|
LocalFree(psd);
|
|
}
|
|
|
|
if(pSD != NULL)
|
|
{
|
|
LocalFree(pSD);
|
|
}
|
|
|
|
return hr;
|
|
}
|