//+------------------------------------------------------------------------- // // 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; }