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.
 
 
 
 
 
 

826 lines
24 KiB

/////////////////////////////////////////////////////////////////////////////
// FILE : SecurityInfo.cpp //
// //
// DESCRIPTION : The ISecurityInformation implmentation used to //
// instantiate a security page. //
// //
// AUTHOR : yossg //
// //
// HISTORY : //
// Feb 7 2000 yossg Create //
// //
// Copyright (C) 2000 Microsoft Corporation All Rights Reserved //
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SecurityInfo.h"
#include "FaxServer.h"
#include "FaxServerNode.h"
#include "MsFxsSnp.h"
//#pragma hdrstop
const GENERIC_MAPPING gc_FaxGenericMapping =
{
(STANDARD_RIGHTS_READ | FAX_GENERIC_READ),
(STANDARD_RIGHTS_WRITE | FAX_GENERIC_WRITE),
(STANDARD_RIGHTS_EXECUTE | FAX_GENERIC_EXECUTE),
(READ_CONTROL | WRITE_DAC | WRITE_OWNER | FAX_GENERIC_ALL)
};
CFaxSecurityInformation::CFaxSecurityInformation()
{
DebugPrint(( TEXT("CFaxSecurityInfo Created") ));
}
CFaxSecurityInformation::~CFaxSecurityInformation()
{
DebugPrint(( TEXT("CFaxSecurityInfo Destroyed") ));
}
/////////////////////////////////////////////////////////////////////////////
// CFaxSecurityInformation
// *** ISecurityInformation methods implementation ***
/*
- CFaxSecurityInformation::GetObjectInformation
-
* Purpose:
* Performs an access check against the fax service security descriptor
*
* Arguments:
* [in] pObjectInfo - pointer to object information structure.
*
* Return:
* OLE error code
*/
HRESULT
STDMETHODCALLTYPE
CFaxSecurityInformation::GetObjectInformation(
IN OUT PSI_OBJECT_INFO pObjectInfo
)
{
DEBUG_FUNCTION_NAME( _T("CFaxSecurityInformation::GetObjectInformation"));
DWORD ec = ERROR_SUCCESS;
CFaxServer * pFaxServer = NULL;
HINSTANCE hInst;
HANDLE hPrivBeforeSE_TAKE_OWNERSHIP = INVALID_HANDLE_VALUE;
HANDLE hPrivBeforeSE_SECURITY = INVALID_HANDLE_VALUE;
ATLASSERT( pObjectInfo != NULL );
if( pObjectInfo == NULL )
{
DebugPrintEx( DEBUG_ERR,
_T("Invalid parameter - pObjectInfo == NULL"));
return E_POINTER;
}
//
// Set Flags
//
pObjectInfo->dwFlags = SI_EDIT_ALL |
SI_NO_TREE_APPLY |
SI_NO_ACL_PROTECT |
SI_ADVANCED;
pFaxServer = m_pFaxServerNode->GetFaxServer();
ATLASSERT(pFaxServer);
if (!pFaxServer->GetFaxServerHandle())
{
ec= GetLastError();
DebugPrintEx(
DEBUG_ERR,
_T("Failed to GetFaxServerHandle. (ec: %ld)"),
ec);
goto Error;
}
//
// Check if to add SI_READONLY
//
if (!FaxAccessCheckEx(
pFaxServer->GetFaxServerHandle(),
WRITE_DAC,
NULL))
{
ec = GetLastError();
if (ERROR_SUCCESS == ec)
{
pObjectInfo->dwFlags |= SI_READONLY;
}
else
{
DebugPrintEx(
DEBUG_ERR,
_T("Fail check access for WRITE_DAC."));
goto Error;
}
}
//
// Check if to add SI_OWNER_READONLY
//
hPrivBeforeSE_TAKE_OWNERSHIP = EnablePrivilege (SE_TAKE_OWNERSHIP_NAME);
//
// No error checking - If we failed we will get ERROR_ACCESS_DENIED in the access check
//
if (!FaxAccessCheckEx(
pFaxServer->GetFaxServerHandle(),
WRITE_OWNER,
NULL))
{
ec = GetLastError();
if (ERROR_SUCCESS == ec)
{
pObjectInfo->dwFlags |= SI_OWNER_READONLY;
}
else
{
DebugPrintEx(
DEBUG_ERR,
_T("Fail check access for WRITE_OWNER."));
goto Error;
}
}
//
// Check if to remove SI_EDIT_AUDITS
//
hPrivBeforeSE_SECURITY = EnablePrivilege (SE_SECURITY_NAME);
//
// No error checking - If we failed we will get ERROR_ACCESS_DENIED in the access check
//
if (!FaxAccessCheckEx(
pFaxServer->GetFaxServerHandle(),
ACCESS_SYSTEM_SECURITY,
NULL))
{
ec = GetLastError();
if (ERROR_SUCCESS == ec)
{
pObjectInfo->dwFlags &= ~SI_EDIT_AUDITS;
}
else
{
DebugPrintEx(
DEBUG_ERR,
_T("Fail check access for ACCESS_SYSTEM_SECURITY."));
goto Error;
}
}
//
// Set all other fields
//
hInst = _Module.GetResourceInstance();
pObjectInfo->hInstance = hInst;
m_bstrServerName = m_pFaxServerNode->GetServerName();
if ( 0 == m_bstrServerName.Length() )
{
pObjectInfo->pszServerName = NULL;
DebugPrintEx( DEBUG_MSG,
_T("NULL ServerName ie: Local machine."));
}
else
{
pObjectInfo->pszServerName = m_bstrServerName;
DebugPrintEx( DEBUG_MSG,
_T("ServerName is: %s."),
pObjectInfo->pszServerName);
}
if (!m_bstrObjectName.LoadString(IDS_SECURITY_CAT_NODE_DESC))
{
ec = ERROR_NOT_ENOUGH_MEMORY;
DebugPrintEx(
DEBUG_ERR,
TEXT("Out of memory. Failed to load string."));
goto Error;
}
pObjectInfo->pszObjectName = m_bstrObjectName;
ATLASSERT ( ERROR_SUCCESS == ec );
ReleasePrivilege (hPrivBeforeSE_SECURITY);
ReleasePrivilege (hPrivBeforeSE_TAKE_OWNERSHIP);
goto Exit;
Error:
ATLASSERT(ERROR_SUCCESS != ec);
ReleasePrivilege (hPrivBeforeSE_SECURITY);
ReleasePrivilege (hPrivBeforeSE_TAKE_OWNERSHIP);
return HRESULT_FROM_WIN32(ec);
Exit:
return S_OK;
}
/*
- CFaxSecurityInformation::GetSecurity
-
* Purpose:
* requests a security descriptor for the securable object whose
* security descriptor is being edited. The access control editor
* calls this method to retrieve the object's current or default security descriptor.
*
* Arguments:
* [in] RequestedInformation - security information.
* [out] ppSecurityDescriptor - pointer to security descriptor.
* [in] fDefault - not implemented
*
* Return:
* OLE error code
*/
HRESULT
STDMETHODCALLTYPE
CFaxSecurityInformation::GetSecurity(
IN SECURITY_INFORMATION RequestedInformation,
OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
IN BOOL fDefault
)
{
DEBUG_FUNCTION_NAME( _T("CFaxSecurityInformation::GetSecurity"));
HRESULT hRc = S_OK;
CFaxServer * pFaxServer = NULL;
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
DWORD ec = ERROR_SUCCESS;
BOOL bResult;
HANDLE hPrivBeforeSE_SECURITY = INVALID_HANDLE_VALUE;
ATLASSERT( ppSecurityDescriptor);
if( fDefault == TRUE )
{
DebugPrintEx( DEBUG_MSG,
_T("Non implemeted feature -> fDefault == TRUE"));
return E_NOTIMPL;
}
if (RequestedInformation & SACL_SECURITY_INFORMATION)
{
hPrivBeforeSE_SECURITY = EnablePrivilege (SE_SECURITY_NAME);
}
pFaxServer = m_pFaxServerNode->GetFaxServer();
ATLASSERT(pFaxServer);
if (!pFaxServer->GetFaxServerHandle())
{
ec= GetLastError();
DebugPrintEx(
DEBUG_ERR,
_T("Failed to GetFaxServerHandle. (ec: %ld)"),
ec);
hRc = HRESULT_FROM_WIN32(ec);
goto Exit;
}
//
// Get the current relative descriptor from the fax server
//
bResult = FaxGetSecurityEx( pFaxServer->GetFaxServerHandle(),
RequestedInformation,
&pSecurityDescriptor);
if( bResult == FALSE )
{
ec = GetLastError();
if (IsNetworkError(ec))
{
DebugPrintEx(
DEBUG_ERR,
_T("Network Error was found. Failed to set security info.(ec: %ld)"),
ec);
pFaxServer->Disconnect();
}
else
{
DebugPrintEx(
DEBUG_ERR,
_T("Failed while call to FaxGetSecurityEx. (ec: %ld)"),
ec);
}
hRc = HRESULT_FROM_WIN32(ec);
goto Exit;
}
//
// return a self relative descriptor copy allocated with LocalAlloc()
//
hRc = MakeSelfRelativeCopy( pSecurityDescriptor, ppSecurityDescriptor );
if( FAILED( hRc ) )
{
DebugPrintEx(
DEBUG_ERR,
_T("MakeSelfRelativeCopy Failed. (hRc : %08X)"),
hRc);
goto Exit;
}
ATLASSERT(S_OK == hRc);
Exit:
if (NULL != pSecurityDescriptor)
{
FaxFreeBuffer(pSecurityDescriptor);
}
ReleasePrivilege (hPrivBeforeSE_SECURITY);
return hRc;
}
/*
- CFaxSecurityInformation::SetSecurity
-
* Purpose:
* Provides a security descriptor containing the security information
* the user wants to apply to the securable object. The access control
* editor calls this method when the user clicks the Okay or Apply buttons.
*
* Arguments:
* [in] SecurityInformation - security information structure.
* [in] pSecurityDescriptor - pointer to security descriptor.
*
* Return:
* OLE error code
*/
HRESULT
STDMETHODCALLTYPE
CFaxSecurityInformation::SetSecurity(
IN SECURITY_INFORMATION SecurityInformation,
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
)
{
DEBUG_FUNCTION_NAME( _T("CFaxSecurityInformation::SetSecurity"));
HRESULT hRc = S_OK;
DWORD ec = ERROR_SUCCESS;
BOOL bResult;
HINSTANCE hInst = _Module.GetResourceInstance();
PSECURITY_DESCRIPTOR psdSelfRelativeCopy = NULL;
CFaxServer * pFaxServer = NULL;
HANDLE hPrivBeforeSE_TAKE_OWNERSHIP = INVALID_HANDLE_VALUE;
HANDLE hPrivBeforeSE_SECURITY = INVALID_HANDLE_VALUE;
ATLASSERT( NULL != pSecurityDescriptor );
ATLASSERT( IsValidSecurityDescriptor( pSecurityDescriptor ) );
//
// Prepare self relative descriptor
//
hRc = MakeSelfRelativeCopy( pSecurityDescriptor, &psdSelfRelativeCopy );
if( FAILED( hRc ) )
{
DebugPrintEx(
DEBUG_ERR,
_T("MakeSelfRelativeCopy Failed. (hRc : %08X)"),
hRc);
goto Exit;
}
if (SecurityInformation & OWNER_SECURITY_INFORMATION)
{
hPrivBeforeSE_TAKE_OWNERSHIP = EnablePrivilege (SE_TAKE_OWNERSHIP_NAME);
}
if (SecurityInformation & SACL_SECURITY_INFORMATION)
{
hPrivBeforeSE_SECURITY = EnablePrivilege (SE_SECURITY_NAME);
}
pFaxServer = m_pFaxServerNode->GetFaxServer();
ATLASSERT(pFaxServer);
if (!pFaxServer->GetFaxServerHandle())
{
ec= GetLastError();
DebugPrintEx(
DEBUG_ERR,
_T("Failed to GetFaxServerHandle. (ec: %ld)"),
ec);
hRc = HRESULT_FROM_WIN32(ec);
goto Exit;
}
//
// save the new relative descriptor to the fax server
//
bResult = FaxSetSecurity( pFaxServer->GetFaxServerHandle(),
SecurityInformation,
psdSelfRelativeCopy);
if( bResult == FALSE )
{
ec = GetLastError();
if (IsNetworkError(ec))
{
DebugPrintEx(
DEBUG_ERR,
_T("Network Error was found. Failed to set security info.(ec: %ld)"),
ec);
pFaxServer->Disconnect();
}
else
{
DebugPrintEx(
DEBUG_ERR,
_T("Failed while call to FaxSetSecurity. (ec: %ld)"),
ec);
}
hRc = HRESULT_FROM_WIN32(ec);
goto Exit;
}
ATLASSERT( S_OK == hRc || E_ACCESSDENIED == hRc);
Exit:
if (NULL != psdSelfRelativeCopy)
{
::LocalFree(psdSelfRelativeCopy);
psdSelfRelativeCopy = NULL;
}
ReleasePrivilege (hPrivBeforeSE_SECURITY);
ReleasePrivilege (hPrivBeforeSE_TAKE_OWNERSHIP);
return hRc;
}
/*
- CFaxSecurityInformation::GetAccessRights
-
* Purpose:
* Requests information about the access rights that can be
* controlled for a securable object. The access control
* editor calls this method to retrieve display strings and
* other information used to initialize the property pages.
*
* Arguments:
* [in] pguidObjectType - Pointer to a GUID structure that
* identifies the type of object for which
* access rights are being requested.
* [in] dwFlags - A set of bit flags that indicate the property
* page being initialized
* [out] ppAccess - Pointer to a variable that you should
* set to a pointer to an array of SI_ACCESS
* structures.
* [out] pcAccesses - Pointer to a variable that you should set
* to indicate the number of entries in the ppAccess array.
* [out] piDefaultAccess - Pointer to a variable that you should set
* to indicate the zero-based index of the array entry that contains
* the default access rights.
* The access control editor uses this entry as the initial access rights in a new ACE.
*
* Return:
* OLE error code
*/
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
)
{
DEBUG_FUNCTION_NAME( _T("CFaxSecurityInformation::GetAccessRights"));
ATLASSERT( ppAccess );
ATLASSERT( pcAccesses );
ATLASSERT( piDefaultAccess );
//
// Access rights for the Advanced security page
//
static SI_ACCESS siFaxAccesses[] =
{
// 0 submit permission
{
&GUID_NULL,
FAX_ACCESS_SUBMIT ,
MAKEINTRESOURCE(IDS_FAXSEC_SUB_LOW),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 1 submit normal permission
{
&GUID_NULL,
FAX_ACCESS_SUBMIT_NORMAL ,
MAKEINTRESOURCE(IDS_FAXSEC_SUB_NORMAL),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 2 submit high permission
{
&GUID_NULL,
FAX_ACCESS_SUBMIT_HIGH ,
MAKEINTRESOURCE(IDS_FAXSEC_SUB_HIGH),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 3 query jobs
{
&GUID_NULL,
FAX_ACCESS_QUERY_JOBS,
MAKEINTRESOURCE(IDS_FAXSEC_JOB_QRY),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 4 Manage jobs
{
&GUID_NULL,
FAX_ACCESS_MANAGE_JOBS,
MAKEINTRESOURCE(IDS_FAXSEC_JOB_MNG),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 5 query configuration
{
&GUID_NULL,
FAX_ACCESS_QUERY_CONFIG,
MAKEINTRESOURCE(IDS_FAXSEC_CONFIG_QRY),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 6 Manage configuration
{
&GUID_NULL,
FAX_ACCESS_MANAGE_CONFIG,
MAKEINTRESOURCE(IDS_FAXSEC_CONFIG_SET),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 7 Query incoming faxes archive
{
&GUID_NULL,
FAX_ACCESS_QUERY_IN_ARCHIVE,
MAKEINTRESOURCE(IDS_FAXSEC_QRY_IN_ARCH),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 8 Manage incoming faxes archive
{
&GUID_NULL,
FAX_ACCESS_MANAGE_IN_ARCHIVE,
MAKEINTRESOURCE(IDS_FAXSEC_MNG_IN_ARCH),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 9 Query outgoing faxes archive
{
&GUID_NULL,
FAX_ACCESS_QUERY_OUT_ARCHIVE,
MAKEINTRESOURCE(IDS_FAXSEC_QRY_OUT_ARCH),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 10 Manage outgoing faxes archive
{
&GUID_NULL,
FAX_ACCESS_MANAGE_OUT_ARCHIVE,
MAKEINTRESOURCE(IDS_FAXSEC_MNG_OUT_ARCH),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// specific permissions
// 11 Read permission
{
&GUID_NULL,
READ_CONTROL,
MAKEINTRESOURCE(IDS_FAXSEC_READ_PERM),
SI_ACCESS_SPECIFIC
},
// 12 Change Permissions
{
&GUID_NULL,
WRITE_DAC,
MAKEINTRESOURCE(IDS_FAXSEC_CHNG_PERM),
SI_ACCESS_SPECIFIC
},
// 13 Take ownership
{
&GUID_NULL,
WRITE_OWNER,
MAKEINTRESOURCE(IDS_FAXSEC_CHNG_OWNER),
SI_ACCESS_SPECIFIC
}
};
//
// Access rights for the Basic security page
//
static SI_ACCESS siFaxBasicAccess[] =
{
// 0 Fax
{
&GUID_NULL,
FAX_ACCESS_SUBMIT_NORMAL | FAX_ACCESS_SUBMIT,
MAKEINTRESOURCE(IDS_RIGHT_FAX),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 1 Manage fax configuration
{
&GUID_NULL,
FAX_ACCESS_MANAGE_CONFIG | FAX_ACCESS_QUERY_CONFIG,
MAKEINTRESOURCE(IDS_RIGHT_MNG_CFG),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
},
// 2 Manage fax documents
{
&GUID_NULL,
FAX_ACCESS_MANAGE_JOBS | FAX_ACCESS_QUERY_JOBS |
FAX_ACCESS_MANAGE_IN_ARCHIVE | FAX_ACCESS_QUERY_IN_ARCHIVE |
FAX_ACCESS_MANAGE_OUT_ARCHIVE | FAX_ACCESS_QUERY_OUT_ARCHIVE,
MAKEINTRESOURCE(IDS_RIGHT_MNG_DOC),
SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC
}
};
*ppAccess = (0 == dwFlags) ? siFaxBasicAccess : siFaxAccesses;
*pcAccesses = ULONG((0 == dwFlags) ? ARR_SIZE(siFaxBasicAccess) : ARR_SIZE(siFaxAccesses));
*piDefaultAccess = (0 == dwFlags) ? 0 : 1;
return S_OK;
}
/*
- CFaxSecurityInformation::MapGeneric
-
* Purpose:
* Requests that the generic access rights in an access mask
* be mapped to their corresponding standard and specific access rights.
*
* Arguments:
*
* Return:
* OLE error code
*/
HRESULT
STDMETHODCALLTYPE
CFaxSecurityInformation::MapGeneric(
IN const GUID *pguidObjectType,
IN UCHAR *pAceFlags,
IN OUT ACCESS_MASK *pMask
)
{
DEBUG_FUNCTION_NAME( _T("CFaxSecurityInformation::MapGeneric"));
MapGenericMask( pMask, const_cast<PGENERIC_MAPPING>(&gc_FaxGenericMapping) );
return S_OK;
}
/*
- CFaxSecurityInformation::GetInheritTypes
-
* Purpose:
* Not implemented.
*
* Arguments:
*
* Return:
* OLE error code
*/
HRESULT
STDMETHODCALLTYPE
CFaxSecurityInformation::GetInheritTypes(
OUT PSI_INHERIT_TYPE *ppInheritTypes,
OUT ULONG *pcInheritTypes
)
{
DEBUG_FUNCTION_NAME( _T("CFaxSecurityInformation::GetInheritTypes --- Not implemented"));
return E_NOTIMPL;
}
/*
- CFaxSecurityInformation::PropertySheetPageCallback
-
* Purpose:
* Notifies an EditSecurity or CreateSecurityPage caller
* that an access control editor property page is being created or destroyed.
*
* Arguments:
*
* Return:
* OLE error code
*/
HRESULT
STDMETHODCALLTYPE
CFaxSecurityInformation::PropertySheetPageCallback(
IN HWND hwnd,
IN UINT uMsg,
IN SI_PAGE_TYPE uPage
)
{
DEBUG_FUNCTION_NAME( _T("CFaxSecurityInformation::PropertySheetPageCallback"));
return S_OK;
}
/*
- CFaxSecurityInformation::MakeSelfRelativeCopy
-
* Purpose:
* This pravite method copies Security descriptors
*
* Arguments:
*
* Return:
* OLE error code
*/
HRESULT CFaxSecurityInformation::MakeSelfRelativeCopy(
PSECURITY_DESCRIPTOR psdOriginal,
PSECURITY_DESCRIPTOR* ppsdNew
)
{
DEBUG_FUNCTION_NAME( _T("CFaxSecurityInformation::MakeSelfRelativeCopy"));
ATLASSERT( 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;
ATLASSERT( IsValidSecurityDescriptor( psdOriginal ) );
if( !::GetSecurityDescriptorControl( psdOriginal, &sdc, &dwRevision ) )
{
DWORD err = ::GetLastError();
DebugPrintEx( DEBUG_ERR,
_T("Invalid security descriptor."));
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)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Out of memory."));
//GetRootNode()->NodeMsgBox(IDS_MEMORY);
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)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Out of memory."));
//GetRootNode()->NodeMsgBox(IDS_MEMORY);
return E_OUTOFMEMORY; // just in case the exception is ignored
}
if( !::MakeSelfRelativeSD( psdOriginal, psdSelfRelativeCopy, &cb ) )
{
DebugPrintEx(
DEBUG_ERR,
_T("::MakeSelfRelativeSD returned NULL"));
if( NULL == ::LocalFree( psdSelfRelativeCopy ) )
{
DWORD err = ::GetLastError();
return HRESULT_FROM_WIN32( err );
}
psdSelfRelativeCopy = NULL;
}
}
*ppsdNew = psdSelfRelativeCopy;
return S_OK;
}