|
|
// PermPage.cxx : Implementation ACL Editor classes
// jonn 7/14/97 copied from \nt\private\windows\shell\lmui\ntshrui\permpage.cpp
#include "headers.hxx"
#pragma hdrstop
#include "acl.hxx"
#include "resource.h" // IDS_SHAREPERM_*
// definition in headers.hxx conflicts with stddef.h (atlbase.h)
#undef offsetof
#include <atlbase.h>
CComModule _Module; #include <atlcom.h>
#include <atlimpl.cpp>
// need IID_ISecurityInformation
#define INITGUID
#include <initguid.h>
#include <aclui.h>
//
// I define my own implementation of ISecurityInformation
//
class CSecurityInformation : public ISecurityInformation, public CComObjectRoot { DECLARE_NOT_AGGREGATABLE(CSecurityInformation) BEGIN_COM_MAP(CSecurityInformation) COM_INTERFACE_ENTRY(ISecurityInformation) END_COM_MAP()
// *** ISecurityInformation methods ***
STDMETHOD(GetObjectInformation) (PSI_OBJECT_INFO pObjectInfo ) = 0; STDMETHOD(GetSecurity) (SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR *ppSecurityDescriptor, BOOL fDefault ) = 0; STDMETHOD(SetSecurity) (SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ) = 0; STDMETHOD(GetAccessRights) (const GUID* pguidObjectType, DWORD dwFlags, PSI_ACCESS *ppAccess, ULONG *pcAccesses, ULONG *piDefaultAccess ); STDMETHOD(MapGeneric) (const GUID *pguidObjectType, UCHAR *pAceFlags, ACCESS_MASK *pMask); STDMETHOD(GetInheritTypes) (PSI_INHERIT_TYPE *ppInheritTypes, ULONG *pcInheritTypes ); STDMETHOD(PropertySheetPageCallback)(HWND hwnd, UINT uMsg, SI_PAGE_TYPE uPage );
protected: HRESULT NewDefaultDescriptor( PSECURITY_DESCRIPTOR* ppsd, SECURITY_INFORMATION RequestedInformation );
HRESULT MakeSelfRelativeCopy( PSECURITY_DESCRIPTOR psdOriginal, PSECURITY_DESCRIPTOR* ppsdNew ); };
class CShareSecurityInformation : public CSecurityInformation { private: LPWSTR m_strMachineName; LPWSTR m_strShareName; public: void SetMachineName( LPWSTR pszMachineName ) { m_strMachineName = pszMachineName; } void SetShareName( LPWSTR pszShareName ) { m_strShareName = pszShareName; } // note: these should be LPCTSTR but are left this way for convenience
LPWSTR QueryMachineName() { return m_strMachineName; } LPWSTR QueryShareName() { return m_strShareName; }
// *** ISecurityInformation methods ***
STDMETHOD(GetObjectInformation) (PSI_OBJECT_INFO pObjectInfo ); };
class CSMBSecurityInformation : public CShareSecurityInformation { STDMETHOD(GetSecurity) (SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR *ppSecurityDescriptor, BOOL fDefault ); STDMETHOD(SetSecurity) (SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ); public: PSECURITY_DESCRIPTOR m_pInitialDescriptor; PSECURITY_DESCRIPTOR* m_ppCurrentDescriptor; CSMBSecurityInformation(); ~CSMBSecurityInformation(); };
// ISecurityInformation interface implementation
SI_ACCESS siShareAccesses[] = { { &GUID_NULL, FILE_ALL_ACCESS, MAKEINTRESOURCE(IDS_SHAREPERM_ALL), SI_ACCESS_GENERAL }, { &GUID_NULL, FILE_GENERIC_WRITE | DELETE, MAKEINTRESOURCE(IDS_SHAREPERM_MODIFY), SI_ACCESS_GENERAL }, { &GUID_NULL, FILE_GENERIC_READ, MAKEINTRESOURCE(IDS_SHAREPERM_READ), SI_ACCESS_GENERAL } }; #define iShareDefAccess 2 // FILE_GEN_READ
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
#endif
STDMETHODIMP CSecurityInformation::GetAccessRights ( const GUID* pguidObjectType, DWORD dwFlags, PSI_ACCESS *ppAccess, ULONG *pcAccesses, ULONG *piDefaultAccess ) { appAssert(ppAccess != NULL); appAssert(pcAccesses != NULL); appAssert(piDefaultAccess != NULL);
*ppAccess = siShareAccesses; *pcAccesses = ARRAYSIZE(siShareAccesses); *piDefaultAccess = iShareDefAccess;
return S_OK; }
// This is consistent with the NETUI code
GENERIC_MAPPING ShareMap = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
STDMETHODIMP CSecurityInformation::MapGeneric ( const GUID *pguidObjectType, UCHAR *pAceFlags, ACCESS_MASK *pMask) { appAssert(pMask != NULL);
MapGenericMask(pMask, &ShareMap);
return S_OK; }
STDMETHODIMP CSecurityInformation::GetInheritTypes ( PSI_INHERIT_TYPE *ppInheritTypes, ULONG *pcInheritTypes ) { appAssert(FALSE); return E_NOTIMPL; } STDMETHODIMP CSecurityInformation::PropertySheetPageCallback(HWND hwnd, UINT uMsg, SI_PAGE_TYPE uPage ) { return S_OK; }
/*
JeffreyS 1/24/97: If you don't set the SI_RESET flag in ISecurityInformation::GetObjectInformation, then fDefault should never be TRUE so you can ignore it. Returning E_NOTIMPL in this case is OK too.
If you want the user to be able to reset the ACL to some default state (defined by you) then turn on SI_RESET and return your default ACL when fDefault is TRUE. This happens if/when the user pushes a button that is only visible when SI_RESET is on. */ STDMETHODIMP CShareSecurityInformation::GetObjectInformation ( PSI_OBJECT_INFO pObjectInfo ) { appAssert(pObjectInfo != NULL && !IsBadWritePtr(pObjectInfo, sizeof(*pObjectInfo)));
pObjectInfo->dwFlags = SI_EDIT_ALL | SI_NO_ACL_PROTECT; pObjectInfo->hInstance = g_hInstance; pObjectInfo->pszServerName = QueryMachineName(); pObjectInfo->pszObjectName = QueryShareName();
return S_OK; }
//
// original code from \\marsslm\backup\src\ncpmgr\ncpmgr\shareacl.cxx
// ACL-wrangling templated from \net\ui\common\src\lmobj\lmobj\security.cxx
//
// caller must free using LocalFree()
//
HRESULT CSecurityInformation::NewDefaultDescriptor( PSECURITY_DESCRIPTOR* ppsd, SECURITY_INFORMATION RequestedInformation ) { *ppsd = NULL; PSID psidWorld = NULL; PSID psidAdmins = NULL; ACCESS_ALLOWED_ACE* pace = NULL; ACL* pacl = NULL; SECURITY_DESCRIPTOR sd; HRESULT hr = S_OK; do { // false loop
// build World SID
SID_IDENTIFIER_AUTHORITY IDAuthorityWorld = SECURITY_WORLD_SID_AUTHORITY; if ( !::AllocateAndInitializeSid( &IDAuthorityWorld, 1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &psidWorld ) ) { appAssert( FALSE ); hr = E_UNEXPECTED; break; }
// build Admins SID
SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY; if ( !::AllocateAndInitializeSid( &IDAuthorityNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, &psidAdmins ) ) { appAssert( FALSE ); hr = E_UNEXPECTED; break; }
// build ACE
DWORD cbSid = ::GetLengthSid(psidWorld); if ( 0 == cbSid ) { appAssert( FALSE ); hr = E_UNEXPECTED; break; } INT cbAce = sizeof(ACCESS_ALLOWED_ACE) + cbSid; pace = reinterpret_cast<ACCESS_ALLOWED_ACE*>(new BYTE[ cbAce+10 ]); if ( NULL == pace ) { appAssert( FALSE ); hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); break; } ::memset((BYTE*)pace,0,cbAce+10); pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; // SetType()
pace->Header.AceFlags = 0; // SetInheritFlags()
pace->Header.AceSize = (WORD)cbAce; // SetSize() (in SetSID())
pace->Mask = GENERIC_ALL; // SetAccessMask()
::memcpy( &(pace->SidStart), psidWorld, cbSid ); // SetSID()
// build ACL
DWORD cbAcl = sizeof(ACL) + cbAce + 10; pacl = reinterpret_cast<ACL*>(new BYTE[ cbAcl ]); if ( NULL == pacl ) { appAssert( FALSE ); hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); break; } ::memset((BYTE*)pacl,0,cbAcl); if ( !::InitializeAcl( pacl, cbAcl, ACL_REVISION2 ) ) { appAssert( FALSE ); hr = E_UNEXPECTED; break; } if ( !::AddAce( pacl, ACL_REVISION2, 0, pace, cbAce ) ) { appAssert( FALSE ); hr = E_UNEXPECTED; break; }
// build security descriptor in absolute format
if ( !::InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ) ) { appAssert( FALSE ); hr = E_UNEXPECTED; break; } if ( !::SetSecurityDescriptorOwner( &sd, psidAdmins, FALSE ) || !::SetSecurityDescriptorGroup( &sd, psidAdmins, FALSE ) || !::SetSecurityDescriptorDacl( &sd, TRUE, pacl, FALSE ) ) { appAssert( FALSE ); hr = E_UNEXPECTED; break; }
// convert security descriptor to self-relative format
DWORD cbSD = 0; // this call should fail and set cbSD to the correct size
if ( ::MakeSelfRelativeSD( &sd, NULL, &cbSD ) || 0 == cbSD ) { appAssert( FALSE ); hr = E_UNEXPECTED; break; } *ppsd = reinterpret_cast<PSECURITY_DESCRIPTOR>( ::LocalAlloc( LMEM_ZEROINIT, cbSD + 20 ) );
if (!*ppsd) { hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); break; } ::memset( (BYTE*)*ppsd, 0, cbSD + 20 ); if ( !::MakeSelfRelativeSD( &sd, *ppsd, &cbSD ) ) { appAssert( FALSE ); hr = E_UNEXPECTED; break; }
} while (FALSE); // false loop
// clean up
if ( NULL != psidWorld ) { (void)::FreeSid( psidWorld ); } if ( NULL != psidAdmins ) { (void)::FreeSid( psidAdmins ); } delete pace; delete pacl;
return hr; }
HRESULT CSecurityInformation::MakeSelfRelativeCopy( PSECURITY_DESCRIPTOR psdOriginal, PSECURITY_DESCRIPTOR* ppsdNew ) { appAssert( NULL != psdOriginal );
// we have to find out whether the original is already self-relative
SECURITY_DESCRIPTOR_CONTROL sdc = 0; DWORD dwRevision = 0; if ( !::GetSecurityDescriptorControl( psdOriginal, &sdc, &dwRevision ) ) { appAssert( FALSE ); DWORD err = ::GetLastError(); return HRESULT_FROM_WIN32( err ); }
DWORD cb = ::GetSecurityDescriptorLength( psdOriginal ) + 20; PSECURITY_DESCRIPTOR psdSelfRelativeCopy = reinterpret_cast<PSECURITY_DESCRIPTOR>( ::LocalAlloc(LMEM_ZEROINIT, cb) ); if (NULL == psdSelfRelativeCopy) { return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); }
if ( sdc & SE_SELF_RELATIVE ) // the original is in self-relative format, just byte-copy it
{ ::memcpy( psdSelfRelativeCopy, psdOriginal, cb - 20 ); } else if ( !::MakeSelfRelativeSD( psdOriginal, psdSelfRelativeCopy, &cb ) ) // the original is in absolute format, convert-copy it
{ appAssert( FALSE ); if( NULL != ::LocalFree( psdSelfRelativeCopy ) ) { appAssert(FALSE); } DWORD err = ::GetLastError(); return HRESULT_FROM_WIN32( err ); } *ppsdNew = psdSelfRelativeCopy; return S_OK; }
CSMBSecurityInformation::CSMBSecurityInformation() : CShareSecurityInformation() , m_pInitialDescriptor( NULL ) , m_ppCurrentDescriptor( NULL ) { }
CSMBSecurityInformation::~CSMBSecurityInformation() { }
STDMETHODIMP CSMBSecurityInformation::GetSecurity ( SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR *ppSecurityDescriptor, BOOL fDefault ) { appAssert( NULL != m_ppCurrentDescriptor );
// NOTE: we allow NULL == ppSecurityDescriptor, see SetSecurity
if (0 == RequestedInformation ) { appAssert(FALSE); return E_INVALIDARG; }
if (fDefault) return E_NOTIMPL;
if ( NULL == ppSecurityDescriptor ) return S_OK;
*ppSecurityDescriptor = NULL;
HRESULT hr = S_OK; if (NULL != *m_ppCurrentDescriptor) { hr = MakeSelfRelativeCopy( *m_ppCurrentDescriptor, ppSecurityDescriptor ); appAssert( SUCCEEDED(hr) && NULL != *ppSecurityDescriptor ); } else if (NULL != m_pInitialDescriptor) { hr = MakeSelfRelativeCopy( m_pInitialDescriptor, ppSecurityDescriptor ); appAssert( SUCCEEDED(hr) && NULL != *ppSecurityDescriptor ); } else { hr = NewDefaultDescriptor( ppSecurityDescriptor, RequestedInformation ); appAssert( SUCCEEDED(hr) && NULL != *ppSecurityDescriptor ); } return hr; }
STDMETHODIMP CSMBSecurityInformation::SetSecurity ( SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor ) { appAssert( NULL != m_ppCurrentDescriptor );
if (NULL != *m_ppCurrentDescriptor) { ::LocalFree(*m_ppCurrentDescriptor); *m_ppCurrentDescriptor = NULL; } HRESULT hr = MakeSelfRelativeCopy( pSecurityDescriptor, m_ppCurrentDescriptor ); appAssert( SUCCEEDED(hr) && NULL != *m_ppCurrentDescriptor ); return hr; }
HMODULE g_hlibACLUI = NULL; typedef BOOL (*EDIT_SECURITY_PROC) ( HWND, LPSECURITYINFO ); EDIT_SECURITY_PROC g_pfnEditSecurityProc;
LONG EditShareAcl( IN HWND hwndParent, IN LPWSTR pszServerName, IN TCHAR * pszShareName, IN PSECURITY_DESCRIPTOR pSecDesc, OUT BOOL* pfSecDescModified, OUT PSECURITY_DESCRIPTOR* ppSecDesc ) { appAssert( ppSecDesc != NULL ); *ppSecDesc = NULL;
if (NULL == g_hlibACLUI) { g_hlibACLUI = ::LoadLibrary(L"ACLUI.DLL"); if (NULL == g_hlibACLUI) { appAssert(FALSE); // ACLUI.DLL isn't installed?
return 0; } }
if (NULL == g_pfnEditSecurityProc) { g_pfnEditSecurityProc = reinterpret_cast<EDIT_SECURITY_PROC>( ::GetProcAddress(g_hlibACLUI,"EditSecurity") ); if (NULL == g_pfnEditSecurityProc) { appAssert(FALSE); // ACLUI.DLL is invalid?
return 0; } }
CComObject<CSMBSecurityInformation>* psecinfo = NULL; HRESULT hRes = CComObject<CSMBSecurityInformation>::CreateInstance(&psecinfo); if ( FAILED(hRes) ) return 0;
psecinfo->AddRef(); psecinfo->SetMachineName( pszServerName ); psecinfo->SetShareName( pszShareName ); psecinfo->m_pInitialDescriptor = pSecDesc; psecinfo->m_ppCurrentDescriptor = ppSecDesc; (g_pfnEditSecurityProc)(hwndParent,psecinfo);
if (NULL != pfSecDescModified) *pfSecDescModified = (NULL != *ppSecDesc);
psecinfo->Release();
return 0; }
|