/*++ Copyright (c) 1997 Microsoft Corporation Module Name: faxsecinfo.h Abstract: This header is the ISecurityInformation implmentation used to instantiate a security page. Environment: WIN32 User Mode Author: Darwin Ouyang (t-darouy) 30-Sept-1997 --*/ // FaxSnapin.cpp : Implementation of CFaxSnapinAbout #include "stdafx.h" #include "faxadmin.h" #include "faxsecinfo.h" #include "faxstrt.h" // string table #include "faxcompd.h" // IComponentData #include "inode.h" // CInternalNode #include "iroot.h" // CInternalRoot #include // contains FAXSTAT_WINCLASS definition #pragma hdrstop GENERIC_MAPPING FaxGenericMapping[] = { { STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_REQUIRED } }; SI_ACCESS siFaxAccesses[] = { // submit permission { &GUID_NULL, FAX_JOB_SUBMIT | STANDARD_RIGHTS_WRITE, MAKEINTRESOURCE(IDS_FAXSEC_JOB_SUB), SI_ACCESS_GENERAL }, // query permission { &GUID_NULL, FAX_JOB_QUERY | STANDARD_RIGHTS_READ, MAKEINTRESOURCE(IDS_FAXSEC_JOB_QRY), SI_ACCESS_GENERAL }, { &GUID_NULL, FAX_CONFIG_QUERY | STANDARD_RIGHTS_READ, MAKEINTRESOURCE(IDS_FAXSEC_CONFIG_QRY), SI_ACCESS_GENERAL }, { &GUID_NULL, FAX_PORT_QUERY | STANDARD_RIGHTS_READ, MAKEINTRESOURCE(IDS_FAXSEC_PORT_QRY), SI_ACCESS_GENERAL }, // manage permission { &GUID_NULL, FAX_JOB_MANAGE | STANDARD_RIGHTS_ALL, MAKEINTRESOURCE(IDS_FAXSEC_JOB_MNG), SI_ACCESS_GENERAL }, { &GUID_NULL, FAX_CONFIG_SET | STANDARD_RIGHTS_ALL, MAKEINTRESOURCE(IDS_FAXSEC_CONFIG_SET), SI_ACCESS_GENERAL }, { &GUID_NULL, FAX_PORT_SET | STANDARD_RIGHTS_ALL, MAKEINTRESOURCE(IDS_FAXSEC_PORT_SET), SI_ACCESS_GENERAL }, // custom access (We don't expose this access, but it is the default access when adding new permissions) { &GUID_NULL, FAX_READ | FAX_WRITE, TEXT("foobar"), SI_ACCESS_GENERAL } }; #define iFaxDefSecurity 7 CFaxSecurityInformation::CFaxSecurityInformation() : m_pDescriptor( NULL ), m_pCompData( NULL ), m_pOwner( NULL ), m_dwDescID( 0 ), m_pAbsoluteDescriptor( NULL ), m_pDacl( NULL ), m_pSacl( NULL ), m_pDescOwner( NULL ), m_pPrimaryGroup( NULL ) { DebugPrint(( TEXT("CFaxSecurityInfo Created") )); } CFaxSecurityInformation::~CFaxSecurityInformation() { DebugPrint(( TEXT("CFaxSecurityInfo Destroyed") )); if( m_pDescriptor != NULL ) { ::LocalFree( m_pDescriptor ); m_pDescriptor = NULL; } } ///////////////////////////////////////////////////////////////////////////// // CFaxSecurityInformation // *** ISecurityInformation methods *** HRESULT STDMETHODCALLTYPE CFaxSecurityInformation::GetObjectInformation( IN OUT PSI_OBJECT_INFO pObjectInfo ) { DebugPrint(( TEXT("Trace: CFaxSecurityInformation::GetObjectInformation") )); assert( pObjectInfo != NULL ); if( pObjectInfo == NULL ) { return E_POINTER; } pObjectInfo->dwFlags = SI_NO_TREE_APPLY | SI_EDIT_ALL | SI_NO_ACL_PROTECT; pObjectInfo->hInstance = ::GlobalStringTable->GetInstance(); pObjectInfo->pszServerName = m_pCompData->globalRoot->GetMachine(); pObjectInfo->pszObjectName = ::GlobalStringTable->GetString( IDS_SECURITY_CAT_NODE_DESC ); return S_OK; } HRESULT STDMETHODCALLTYPE CFaxSecurityInformation::GetSecurity( IN SECURITY_INFORMATION RequestedInformation, OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor, IN BOOL fDefault ) { DebugPrint(( TEXT("Trace: CFaxSecurityInformation::GetSecurity") )); SetSecurityDescriptor( m_dwDescID ); if( fDefault == TRUE ) { return E_NOTIMPL; } else { if( RequestedInformation & DACL_SECURITY_INFORMATION || RequestedInformation & OWNER_SECURITY_INFORMATION || RequestedInformation & GROUP_SECURITY_INFORMATION || RequestedInformation & SACL_SECURITY_INFORMATION ) { if( IsValidSecurityDescriptor( m_pDescriptor ) ) { if( FAILED( MakeSelfRelativeCopy( m_pDescriptor, ppSecurityDescriptor ) ) ) { assert( FALSE ); return E_UNEXPECTED; } // paranoia check if( !IsValidSecurityDescriptor( *ppSecurityDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } return S_OK; } else { assert( FALSE ); return E_UNEXPECTED; } } else { return E_NOTIMPL; } } } HRESULT STDMETHODCALLTYPE CFaxSecurityInformation::SetSecurity( IN SECURITY_INFORMATION SecurityInformation, IN PSECURITY_DESCRIPTOR pSecurityDescriptor ) { DebugPrint(( TEXT("Trace: CFaxSecurityInformation::SetSecurity") )); FAX_SECURITY_DESCRIPTOR temp; BOOL bResult; BOOL bPresent; BOOL bDefaulted; PACL pDacl = NULL; PACL pOldDacl = NULL; DWORD dwDaclSize = 0; PACL pSacl = NULL; DWORD dwSaclSize = 0; PSID pSidOwner = NULL; DWORD dwOwnerSize = 0; PSID pPrimaryGroup = NULL; DWORD dwPrimaryGroupSize = 0; SetSecurityDescriptor( m_dwDescID ); // paranoia check if( !IsValidSecurityDescriptor( pSecurityDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } if( !IsValidSecurityDescriptor( m_pAbsoluteDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } if( !IsValidSecurityDescriptor( m_pDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } if( SecurityInformation & DACL_SECURITY_INFORMATION ) { // if the descriptor we got has a DACL if( !GetSecurityDescriptorDacl( pSecurityDescriptor, // address of security descriptor &bPresent, // address of flag for presence of disc. ACL &pDacl, // address of pointer to ACL &bDefaulted // address of flag for default disc. ACL ) ) { assert( FALSE ); return E_UNEXPECTED; } else { if( bPresent ) { // delete the old DACL if( m_pDacl != NULL ) { ::LocalFree( (PVOID) m_pDacl ); m_pDacl = NULL; } m_pDacl = pDacl; // set the new DACL if( !SetSecurityDescriptorDacl( m_pAbsoluteDescriptor, bPresent, pDacl, FALSE ) ) { assert( FALSE ); return E_UNEXPECTED; } } } } if( SecurityInformation & SACL_SECURITY_INFORMATION ) { // if the descriptor we got has a SACL if( !GetSecurityDescriptorSacl( pSecurityDescriptor, // address of security descriptor &bPresent, // address of flag for presence of disc. ACL &pDacl, // address of pointer to ACL &bDefaulted // address of flag for default disc. ACL ) ) { assert( FALSE ); return E_UNEXPECTED; } else { if( bPresent ) { // delete the old SACL if( m_pSacl != NULL ) { ::LocalFree( (PVOID) m_pSacl ); m_pSacl = NULL; } m_pSacl = pSacl; // set the new SACL if( !SetSecurityDescriptorSacl( m_pAbsoluteDescriptor, bPresent, pSacl, FALSE ) ) { assert( FALSE ); return E_UNEXPECTED; } } } } if( SecurityInformation & OWNER_SECURITY_INFORMATION ) { // if the descriptor we got has a OWNER if( !GetSecurityDescriptorOwner( pSecurityDescriptor, // address of security descriptor &pSidOwner, // address of pointer to ACL &bDefaulted // address of flag for default disc. ACL ) ) { assert( FALSE ); return E_UNEXPECTED; } else { if( pSidOwner != NULL ) { // delete the old OWNER if( m_pDescOwner != NULL ) { ::LocalFree( (PVOID) m_pDescOwner ); m_pDescOwner = NULL; } m_pDescOwner = pSidOwner; // set the new owner if( !SetSecurityDescriptorOwner( m_pAbsoluteDescriptor, pSidOwner, FALSE ) ) { assert( FALSE ); return E_UNEXPECTED; } } } } if( SecurityInformation & GROUP_SECURITY_INFORMATION ) { // if the descriptor we got has a GROUP if( !GetSecurityDescriptorGroup( pSecurityDescriptor, // address of security descriptor &pPrimaryGroup, // address of pointer to ACL &bDefaulted // address of flag for default disc. ACL ) ) { assert( FALSE ); return E_UNEXPECTED; } else { if( pPrimaryGroup != NULL ) { // delete the old group if( m_pPrimaryGroup != NULL ) { ::LocalFree( (PVOID) m_pPrimaryGroup ); m_pPrimaryGroup = NULL; } m_pPrimaryGroup = pPrimaryGroup; // set the new group if( !SetSecurityDescriptorGroup( m_pAbsoluteDescriptor, pPrimaryGroup, FALSE ) ) { assert( FALSE ); return E_UNEXPECTED; } } } } // release the old relative desciptor if( m_pDescriptor != NULL ) { ::LocalFree( (PVOID)m_pDescriptor ); m_pDescriptor = NULL; } // paranoia check if( !IsValidSecurityDescriptor( m_pAbsoluteDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } // copy the new absolute descriptor to a relative version if( FAILED( MakeSelfRelativeCopy( m_pAbsoluteDescriptor, &m_pDescriptor ) ) ) { assert( FALSE ); return E_UNEXPECTED; } // paranoia check if( !IsValidSecurityDescriptor( m_pDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } if( !IsValidSecurityDescriptor( m_pAbsoluteDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } // save the new relative descriptor to the fax server temp.Id = m_dwDescID; temp.FriendlyName = NULL; temp.SecurityDescriptor = (unsigned char *)m_pDescriptor; try { bResult = FaxSetSecurityDescriptor( m_pCompData->m_FaxHandle, &temp ); if( bResult == FALSE ) { ::GlobalStringTable->SystemErrorMsg( GetLastError() ); assert( FALSE ); } } catch( ... ) { bResult = FALSE; m_pCompData->NotifyRpcError( TRUE ); assert( FALSE ); ::GlobalStringTable->SystemErrorMsg( GetLastError() ); } // paranoia check if( !IsValidSecurityDescriptor( m_pDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } if( !IsValidSecurityDescriptor( m_pAbsoluteDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } // See if faxstat is running HWND hWndFaxStat = FindWindow(FAXSTAT_WINCLASS, NULL); if (hWndFaxStat) { PostMessage(hWndFaxStat, WM_FAXSTAT_MMC, 0, 0); } return S_OK; } HRESULT STDMETHODCALLTYPE CFaxSecurityInformation::GetAccessRights( IN const GUID* pguidObjectType, IN DWORD dwFlags, // SI_EDIT_AUDITS, SI_EDIT_PROPERTIES OUT PSI_ACCESS *ppAccess, OUT ULONG *pcAccesses, OUT ULONG *piDefaultAccess ) { DebugPrint(( TEXT("Trace: CFaxSecurityInformation::GetAccessRights") )); *ppAccess = siFaxAccesses; *pcAccesses = 7; *piDefaultAccess = iFaxDefSecurity; return S_OK; } HRESULT STDMETHODCALLTYPE CFaxSecurityInformation::MapGeneric( IN const GUID *pguidObjectType, IN UCHAR *pAceFlags, IN OUT ACCESS_MASK *pMask ) { DebugPrint(( TEXT("Trace: CFaxSecurityInformation::MapGeneric") )); MapGenericMask( pMask, FaxGenericMapping ); return S_OK; } // no need to impl these HRESULT STDMETHODCALLTYPE CFaxSecurityInformation::GetInheritTypes( OUT PSI_INHERIT_TYPE *ppInheritTypes, OUT ULONG *pcInheritTypes ) { DebugPrint(( TEXT("Trace: CFaxSecurityInformation::GetInheritTypes") )); return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CFaxSecurityInformation::PropertySheetPageCallback( IN HWND hwnd, IN UINT uMsg, IN SI_PAGE_TYPE uPage ) { DebugPrint(( TEXT("Trace: CFaxSecurityInformation::PropertySheetPageCallback") )); if( uMsg == PSPCB_RELEASE ) { DestroyAbsoluteDescriptor(); } return S_OK; } // Internal Methods HRESULT CFaxSecurityInformation::SetOwner( CInternalNode * toSet ) { DebugPrint(( TEXT(" * Trace: CFaxSecurityInformation::SetOwner") )); assert( toSet != NULL ); m_pOwner = toSet; m_pCompData = m_pOwner->m_pCompData; return S_OK; } HRESULT CFaxSecurityInformation::SetSecurityDescriptor( DWORD FaxDescriptorId ) { DebugPrint(( TEXT(" * Trace: CFaxSecurityInformation::SetSecurityDescriptor") )); DWORD descLen = 0; HRESULT hr = S_OK; PFAX_SECURITY_DESCRIPTOR FaxDescriptor = NULL; BOOL bResult; try { bResult = FaxGetSecurityDescriptor( m_pOwner->m_pCompData->m_FaxHandle, FaxDescriptorId, &FaxDescriptor ); } catch( ... ) { bResult = FALSE; assert( FALSE ); } if( bResult ) { if( !IsValidSecurityDescriptor( FaxDescriptor->SecurityDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } m_dwDescID = FaxDescriptor->Id; hr = MakeSelfRelativeCopy( FaxDescriptor->SecurityDescriptor, &m_pDescriptor ); if( FAILED( hr ) ) { assert( FALSE ); return hr; } FaxFreeBuffer( FaxDescriptor ); hr = MakeAbsoluteCopyFromRelative( m_pDescriptor, &m_pAbsoluteDescriptor ); if( FAILED( hr ) ) { assert( FALSE ); return hr; } // paranoia check if( !IsValidSecurityDescriptor( m_pDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } // paranoia check if( !IsValidSecurityDescriptor( m_pAbsoluteDescriptor ) ) { assert( FALSE ); return E_UNEXPECTED; } } else { if (GetLastError() != ERROR_ACCESS_DENIED) { assert( FALSE ); m_pOwner->m_pCompData->NotifyRpcError( TRUE ); } ::GlobalStringTable->SystemErrorMsg( GetLastError() ); hr = E_UNEXPECTED; } return hr; } // stolen from \private\admin\snapin\filemgmt\permpage.cpp and modified HRESULT CFaxSecurityInformation::MakeSelfRelativeCopy( PSECURITY_DESCRIPTOR psdOriginal, PSECURITY_DESCRIPTOR* ppsdNew ) { DebugPrint(( TEXT(" * Trace: CFaxSecurityInformation::MakeSelfRelativeCopy") )); assert( NULL != psdOriginal ); // we have to find out whether the original is already self-relative SECURITY_DESCRIPTOR_CONTROL sdc = 0; PSECURITY_DESCRIPTOR psdSelfRelativeCopy = NULL; DWORD dwRevision = 0; DWORD cb = 0; if( !IsValidSecurityDescriptor( psdOriginal ) ) { assert( FALSE ); return E_INVALIDARG; } if( !::GetSecurityDescriptorControl( psdOriginal, &sdc, &dwRevision ) ) { assert( FALSE ); DWORD err = ::GetLastError(); return HRESULT_FROM_WIN32( err ); } if( sdc & SE_SELF_RELATIVE ) { // the original is in self-relative format, just byte-copy it // get size cb = ::GetSecurityDescriptorLength( psdOriginal ); // alloc the memory psdSelfRelativeCopy = (PSECURITY_DESCRIPTOR) ::LocalAlloc( LMEM_ZEROINIT, cb ); if(NULL == psdSelfRelativeCopy) { assert( FALSE ); return E_OUTOFMEMORY; } // make the copy ::memcpy( psdSelfRelativeCopy, psdOriginal, cb ); } else { // the original is in absolute format, convert-copy it // get new size - it will fail and set cb to the correct buffer size ::MakeSelfRelativeSD( psdOriginal, NULL, &cb ); // alloc the new amount of memory psdSelfRelativeCopy = (PSECURITY_DESCRIPTOR) ::LocalAlloc( LMEM_ZEROINIT, cb ); if(NULL == psdSelfRelativeCopy) { assert( FALSE ); return E_OUTOFMEMORY; // just in case the exception is ignored } if( !::MakeSelfRelativeSD( psdOriginal, psdSelfRelativeCopy, &cb ) ) { assert( FALSE ); if( NULL == ::LocalFree( psdSelfRelativeCopy ) ) { DWORD err = ::GetLastError(); return HRESULT_FROM_WIN32( err ); } psdSelfRelativeCopy = NULL; } } *ppsdNew = psdSelfRelativeCopy; return S_OK; } HRESULT CFaxSecurityInformation::MakeAbsoluteCopyFromRelative( PSECURITY_DESCRIPTOR psdOriginal, PSECURITY_DESCRIPTOR* ppsdNew ) { assert( NULL != psdOriginal ); DebugPrint(( TEXT(" * Trace: CFaxSecurityInformation::MakeAbsoluteCopyFromRelative") )); // we have to find out whether the original is already self-relative SECURITY_DESCRIPTOR_CONTROL sdc = 0; PSECURITY_DESCRIPTOR psdAbsoluteCopy = NULL; DWORD dwRevision = 0; DWORD cb = 0; BOOL bDefaulted; DWORD dwDaclSize = 0; BOOL bDaclPresent = FALSE; DWORD dwSaclSize = 0; BOOL bSaclPresent = FALSE; DWORD dwOwnerSize = 0; DWORD dwPrimaryGroupSize = 0; HRESULT hr = S_OK; if( !IsValidSecurityDescriptor( psdOriginal ) ) { assert( FALSE ); return E_INVALIDARG; } if( !::GetSecurityDescriptorControl( psdOriginal, &sdc, &dwRevision ) ) { assert( FALSE ); DWORD err = ::GetLastError(); hr = HRESULT_FROM_WIN32( err ); goto cleanup; } if( sdc & SE_SELF_RELATIVE ) { // the original is in self-relative format, build an absolute copy // get the dacl if( !GetSecurityDescriptorDacl( psdOriginal, // address of security descriptor &bDaclPresent, // address of flag for presence of disc. ACL &m_pDacl, // address of pointer to ACL &bDefaulted // address of flag for default disc. ACL ) ) { assert( FALSE ); hr = E_INVALIDARG; goto cleanup; } // get the sacl if( !GetSecurityDescriptorSacl( psdOriginal, // address of security descriptor &bSaclPresent, // address of flag for presence of disc. ACL &m_pSacl, // address of pointer to ACL &bDefaulted // address of flag for default disc. ACL ) ) { assert( FALSE ); hr = E_INVALIDARG; goto cleanup; } // get the owner if( !GetSecurityDescriptorOwner( psdOriginal, // address of security descriptor &m_pDescOwner, // address of pointer to owner security // identifier (SID) &bDefaulted // address of flag for default ) ) { assert( FALSE ); hr = E_INVALIDARG; goto cleanup; } // get the group if( !GetSecurityDescriptorGroup( psdOriginal, // address of security descriptor &m_pPrimaryGroup, // address of pointer to owner security // identifier (SID) &bDefaulted // address of flag for default ) ) { assert( FALSE ); hr = E_INVALIDARG; goto cleanup; } // get required buffer size cb = 0; MakeAbsoluteSD( psdOriginal, // address of self-relative SD psdAbsoluteCopy, // address of absolute SD &cb, // address of size of absolute SD NULL, // address of discretionary ACL &dwDaclSize, // address of size of discretionary ACL NULL, // address of system ACL &dwSaclSize, // address of size of system ACL NULL, // address of owner SID &dwOwnerSize, // address of size of owner SID NULL, // address of primary-group SID &dwPrimaryGroupSize // address of size of group SID ); // alloc the memory psdAbsoluteCopy = (PSECURITY_DESCRIPTOR) ::LocalAlloc( LMEM_ZEROINIT, cb ); m_pDacl = (PACL) ::LocalAlloc( LMEM_ZEROINIT, dwDaclSize ); m_pSacl = (PACL) ::LocalAlloc( LMEM_ZEROINIT, dwSaclSize ); m_pDescOwner = (PSID) ::LocalAlloc( LMEM_ZEROINIT, dwOwnerSize ); m_pPrimaryGroup = (PSID) ::LocalAlloc( LMEM_ZEROINIT, dwPrimaryGroupSize ); if(NULL == psdAbsoluteCopy || NULL == m_pDacl || NULL == m_pSacl || NULL == m_pDescOwner || NULL == m_pPrimaryGroup ) { assert( FALSE ); hr = E_OUTOFMEMORY; goto cleanup; } // make the copy if( !MakeAbsoluteSD( psdOriginal, // address of self-relative SD psdAbsoluteCopy, // address of absolute SD &cb, // address of size of absolute SD m_pDacl, // address of discretionary ACL &dwDaclSize, // address of size of discretionary ACL m_pSacl, // address of system ACL &dwSaclSize, // address of size of system ACL m_pDescOwner, // address of owner SID &dwOwnerSize, // address of size of owner SID m_pPrimaryGroup, // address of primary-group SID &dwPrimaryGroupSize // address of size of group SID ) ) { assert( FALSE ); hr = E_UNEXPECTED; goto cleanup; } } else { // the original is in absolute format, fail *ppsdNew = NULL; hr = E_INVALIDARG; goto cleanup; } *ppsdNew = psdAbsoluteCopy; // paranoia check if( !IsValidSecurityDescriptor( *ppsdNew ) ) { assert( FALSE ); hr = E_UNEXPECTED; goto cleanup; } if( !IsValidSecurityDescriptor( psdOriginal ) ) { assert( FALSE ); hr = E_UNEXPECTED; goto cleanup; } return hr; cleanup: if( m_pDacl != NULL && bDaclPresent == TRUE ) { ::LocalFree((PVOID) m_pDacl ); m_pDacl = NULL; } if( m_pSacl != NULL && bSaclPresent == TRUE ) { ::LocalFree((PVOID) m_pSacl ); m_pSacl = NULL; } if( m_pDescOwner != NULL ) { ::LocalFree((PVOID) m_pOwner ); m_pDescOwner = NULL; } if( m_pPrimaryGroup != NULL ) { ::LocalFree((PVOID) m_pPrimaryGroup ); m_pPrimaryGroup = NULL; } if( psdAbsoluteCopy != NULL ) { ::LocalFree((PVOID) psdAbsoluteCopy ); psdAbsoluteCopy = NULL; } return hr; } // cleanup function only called by destructor. HRESULT CFaxSecurityInformation::DestroyAbsoluteDescriptor() { DebugPrint(( TEXT(" * Trace: CFaxSecurityInformation::DestroyAbsoluteDescriptor") )); SECURITY_DESCRIPTOR_CONTROL sdc = 0; DWORD dwRevision = 0; DWORD cb = 0; HRESULT hr = S_OK; if( m_pAbsoluteDescriptor == NULL ) { assert( FALSE ); return E_POINTER; } if( !IsValidSecurityDescriptor( m_pAbsoluteDescriptor ) ) { // BUGBUG this assertion always fails for some reason unknown if // you hit apply then ok on the property sheet. something is wrong. // // for some reason, this bug does not manifest on Alpha?! // assert( FALSE ); return E_INVALIDARG; } if( !::GetSecurityDescriptorControl( m_pAbsoluteDescriptor, &sdc, &dwRevision ) ) { assert( FALSE ); DWORD err = ::GetLastError(); hr = HRESULT_FROM_WIN32( err ); goto cleanup; } if( !(sdc & SE_SELF_RELATIVE) ) { if( m_pDacl != NULL ) { ::LocalFree((PVOID) m_pDacl ); m_pDacl = NULL; } if( m_pSacl != NULL ) { ::LocalFree((PVOID) m_pSacl ); m_pSacl = NULL; } if( m_pDescOwner != NULL ) { ::LocalFree((PVOID) m_pDescOwner ); m_pDescOwner = NULL; } if( m_pPrimaryGroup != NULL ) { ::LocalFree((PVOID) m_pPrimaryGroup ); m_pPrimaryGroup = NULL; } if( m_pAbsoluteDescriptor != NULL ) { ::LocalFree((PVOID) m_pAbsoluteDescriptor ); m_pAbsoluteDescriptor = NULL; } } else { // not in absolute!! assert( FALSE ); return E_INVALIDARG; } return hr; cleanup: assert( FALSE ); return hr; }