windows-nt/Source/XPSP1/NT/admin/wizards/shrwiz/aclpage.cpp
2020-09-26 16:20:57 +08:00

693 lines
17 KiB
C++

// AclPage.cpp : Implementation of ISecurityInformation and IDataObject
#include "stdafx.h"
#include "shrwiz.h"
#include "AclPage.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////////////////
// class CPermEntry
CPermEntry::CPermEntry()
: m_dwAccessMask(0),
m_pSid(NULL),
m_bWellKnownSid(FALSE)
{
}
CPermEntry::~CPermEntry()
{
if (m_pSid)
if (m_bWellKnownSid)
FreeSid(m_pSid);
else
LocalFree((HLOCAL)m_pSid);
}
HRESULT
CPermEntry::Initialize(
IN LPCTSTR lpszSystem,
IN LPCTSTR lpszAccount,
IN DWORD dwAccessMask
)
{
m_cstrSystem = lpszSystem;
m_cstrAccount = lpszAccount;
m_dwAccessMask = dwAccessMask;
return GetAccountSID(m_cstrSystem, m_cstrAccount, &m_pSid, &m_bWellKnownSid);
}
UINT
CPermEntry::GetLengthSid()
{
return (m_pSid ? ::GetLengthSid(m_pSid) : 0);
}
HRESULT
CPermEntry::AddAccessAllowedAce(OUT PACL pACL)
{
if ( !::AddAccessAllowedAce(pACL, ACL_REVISION, m_dwAccessMask, m_pSid) )
return HRESULT_FROM_WIN32(GetLastError());
return S_OK;
}
// NOTE: caller needs to call LocalFree() on the returned SD
HRESULT
BuildSecurityDescriptor(
IN CPermEntry *pPermEntry, // an array of CPermEntry
IN UINT cEntries, // number of entries in the array
OUT PSECURITY_DESCRIPTOR *ppSelfRelativeSD // return a security descriptor in self-relative form
)
{
if (!pPermEntry || !cEntries || !ppSelfRelativeSD)
return E_INVALIDARG;
ASSERT(!*ppSelfRelativeSD); // prevent memory leak
*ppSelfRelativeSD = NULL;
HRESULT hr = S_OK;
PSECURITY_DESCRIPTOR pAbsoluteSD = NULL;
PACL pACL = NULL;
do { // false loop
UINT i = 0;
CPermEntry *pEntry = NULL;
DWORD cbACL = sizeof(ACL);
// Initialize a new ACL
for (pEntry=pPermEntry, i=0; i<cEntries; pEntry++, i++)
cbACL += sizeof(ACCESS_ALLOWED_ACE) + pEntry->GetLengthSid() - sizeof(DWORD);
if ( !(pACL = (PACL)LocalAlloc(LPTR, cbACL)) ||
!InitializeAcl(pACL, cbACL, ACL_REVISION))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
// Add Ace
for (pEntry=pPermEntry, i=0; SUCCEEDED(hr) && i<cEntries; pEntry++, i++)
hr = pEntry->AddAccessAllowedAce(pACL);
if (FAILED(hr))
break;
// Note: this is a new object, set Dacl only.
// Initialize a new security descriptor in absolute form and add the new ACL to it
if ( !(pAbsoluteSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH)) ||
!InitializeSecurityDescriptor(pAbsoluteSD, SECURITY_DESCRIPTOR_REVISION) ||
!SetSecurityDescriptorDacl(pAbsoluteSD, TRUE, pACL, FALSE) )
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
// transform into a self-relative form
DWORD dwSDSize = 0;
MakeSelfRelativeSD(pAbsoluteSD, *ppSelfRelativeSD, &dwSDSize);
if ( !(*ppSelfRelativeSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSDSize)) ||
!MakeSelfRelativeSD(pAbsoluteSD, *ppSelfRelativeSD, &dwSDSize) )
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
} while (0);
if (FAILED(hr))
{
if (*ppSelfRelativeSD)
{
LocalFree((HLOCAL)*ppSelfRelativeSD);
*ppSelfRelativeSD = NULL;
}
}
if (pACL)
LocalFree((HLOCAL)pACL);
if (pAbsoluteSD)
LocalFree((HLOCAL)pAbsoluteSD);
return hr;
}
#define MAX_DOMAIN_NAME_LENGTH 1024
// NOTE: caller needs to call FreeSid()/LocalFree() on the returned SID
// NOTE: this function only handles limited well-known SIDs.
HRESULT
GetAccountSID(
IN LPCTSTR lpszSystem, // system where the account belongs to
IN LPCTSTR lpszAccount, // account
OUT PSID *ppSid, // return SID of the account
OUT BOOL *pbWellKnownSID // return a BOOL, caller needs to call FreeSid() on a well-known SID
)
{
if (!lpszAccount || !*lpszAccount || !ppSid || !pbWellKnownSID)
return E_INVALIDARG;
ASSERT(!*ppSid); // prevent memory leak
*ppSid = NULL;
SID_IDENTIFIER_AUTHORITY SidIdentifierNTAuthority = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SidIdentifierWORLDAuthority = SECURITY_WORLD_SID_AUTHORITY;
PSID_IDENTIFIER_AUTHORITY pSidIdentifierAuthority = NULL;
DWORD dwRet = ERROR_SUCCESS;
BYTE Count = 0;
DWORD dwRID[8];
ZeroMemory(dwRID, sizeof(dwRID));
*pbWellKnownSID = TRUE;
CString cstrAccount = lpszAccount;
cstrAccount.MakeLower();
if ( ACCOUNT_ADMINISTRATORS == cstrAccount ) {
// Administrators group
pSidIdentifierAuthority = &SidIdentifierNTAuthority;
Count = 2;
dwRID[0] = SECURITY_BUILTIN_DOMAIN_RID;
dwRID[1] = DOMAIN_ALIAS_RID_ADMINS;
} else if ( ACCOUNT_EVERYONE == cstrAccount ) {
// Everyone
pSidIdentifierAuthority = &SidIdentifierWORLDAuthority;
Count = 1;
dwRID[0] = SECURITY_WORLD_RID;
} else if ( ACCOUNT_SYSTEM == cstrAccount ) {
// SYSTEM
pSidIdentifierAuthority = &SidIdentifierNTAuthority;
Count = 1;
dwRID[0] = SECURITY_LOCAL_SYSTEM_RID;
} else if ( ACCOUNT_INTERACTIVE == cstrAccount ) {
// INTERACTIVE
pSidIdentifierAuthority = &SidIdentifierNTAuthority;
Count = 1;
dwRID[0] = SECURITY_INTERACTIVE_RID;
} else {
*pbWellKnownSID = FALSE;
}
if (*pbWellKnownSID) {
if ( !AllocateAndInitializeSid(pSidIdentifierAuthority, Count,
dwRID[0], dwRID[1], dwRID[2], dwRID[3],
dwRID[4], dwRID[5], dwRID[6], dwRID[7], ppSid) )
{
dwRet = GetLastError();
}
} else {
// get regular account sid
DWORD dwSidSize = 0;
TCHAR refDomain[MAX_DOMAIN_NAME_LENGTH];
DWORD refDomainSize = MAX_DOMAIN_NAME_LENGTH;
SID_NAME_USE snu;
LookupAccountName (lpszSystem, lpszAccount, *ppSid, &dwSidSize,
refDomain, &refDomainSize, &snu);
dwRet = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == dwRet)
{
dwRet = ERROR_SUCCESS;
if ( !(*ppSid = (PSID)LocalAlloc(LPTR, dwSidSize)) )
dwRet = ERROR_NOT_ENOUGH_MEMORY;
else
{
refDomainSize = MAX_DOMAIN_NAME_LENGTH;
if (!LookupAccountName (lpszSystem, lpszAccount, *ppSid, &dwSidSize,
refDomain, &refDomainSize, &snu))
dwRet = GetLastError();
}
}
}
if (ERROR_SUCCESS != dwRet)
{
if (*ppSid)
{
if (*pbWellKnownSID)
FreeSid(*ppSid);
else
LocalFree((HLOCAL)*ppSid);
*ppSid = NULL;
}
}
return HRESULT_FROM_WIN32(dwRet);
}
///////////////////////////////////////////////////////
// class CShareSecurityInformation
CShareSecurityInformation::CShareSecurityInformation(PSECURITY_DESCRIPTOR pSelfRelativeSD)
: m_cRef(1), m_pDefaultDescriptor(pSelfRelativeSD)
{
m_bDefaultSD = !pSelfRelativeSD;
}
CShareSecurityInformation::~CShareSecurityInformation()
{
TRACE(_T("CShareSecurityInformation::~CShareSecurityInformation m_cRef=%d\n"), m_cRef);
if (m_bDefaultSD && m_pDefaultDescriptor)
LocalFree((HLOCAL)m_pDefaultDescriptor);
}
void
CShareSecurityInformation::Initialize(
IN LPCTSTR lpszComputerName,
IN LPCTSTR lpszShareName,
IN LPCTSTR lpszPageTitle
)
{
m_cstrComputerName = lpszComputerName;
m_cstrShareName = lpszShareName;
m_cstrPageTitle = lpszPageTitle;
}
////////////////////////////////
// IUnknown methods
////////////////////////////////
STDMETHODIMP
CShareSecurityInformation::QueryInterface(REFIID riid, LPVOID *ppv)
{
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ISecurityInformation))
{
*ppv = this;
m_cRef++;
return S_OK;
} else
{
*ppv = NULL;
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG)
CShareSecurityInformation::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG)
CShareSecurityInformation::Release()
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
////////////////////////////////
// ISecurityInformation methods
////////////////////////////////
STDMETHODIMP
CShareSecurityInformation::GetObjectInformation (
PSI_OBJECT_INFO pObjectInfo
)
{
ASSERT(pObjectInfo);
ASSERT(!IsBadWritePtr(pObjectInfo, sizeof(*pObjectInfo)));
pObjectInfo->dwFlags = SI_EDIT_ALL | SI_NO_ACL_PROTECT | SI_PAGE_TITLE | SI_RESET;
pObjectInfo->hInstance = AfxGetResourceHandle();
pObjectInfo->pszServerName = const_cast<LPTSTR>(static_cast<LPCTSTR>(m_cstrComputerName));
pObjectInfo->pszObjectName = const_cast<LPTSTR>(static_cast<LPCTSTR>(m_cstrShareName));
pObjectInfo->pszPageTitle = const_cast<LPTSTR>(static_cast<LPCTSTR>(m_cstrPageTitle));
return S_OK;
}
STDMETHODIMP
CShareSecurityInformation::GetSecurity (
SECURITY_INFORMATION RequestedInformation,
PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
BOOL fDefault
)
{
ASSERT(DACL_SECURITY_INFORMATION == RequestedInformation);
ASSERT(ppSecurityDescriptor);
TRACE(_T("GetSecurity RequestedInformation=%d fDefault=%d\n"), RequestedInformation, fDefault);
*ppSecurityDescriptor = NULL;
if (NULL == m_pDefaultDescriptor)
{
HRESULT hr = GetDefaultSD(&m_pDefaultDescriptor);
if (FAILED(hr))
return hr;
}
// We have to pass back a LocalAlloc'ed copy of the SD
return MakeSelfRelativeCopy(m_pDefaultDescriptor, ppSecurityDescriptor);
}
STDMETHODIMP
CShareSecurityInformation::SetSecurity (
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor
)
{
ASSERT(DACL_SECURITY_INFORMATION == SecurityInformation);
TRACE(_T("SetSecurity SecurityInformation=%d\n"), SecurityInformation);
PSECURITY_DESCRIPTOR pNewSD = NULL;
HRESULT hr = MakeSelfRelativeCopy(pSecurityDescriptor, &pNewSD);
if (SUCCEEDED(hr))
((CShrwizApp *)AfxGetApp())->SetSecurity(pNewSD);
return hr;
}
SI_ACCESS siShareAccesses[] =
{
{ &GUID_NULL,
FILE_ALL_ACCESS,
MAKEINTRESOURCE(IDS_SHAREPERM_ALL),
SI_ACCESS_GENERAL },
{ &GUID_NULL,
FILE_GENERIC_READ | FILE_EXECUTE | FILE_GENERIC_WRITE | DELETE,
MAKEINTRESOURCE(IDS_SHAREPERM_CHANGE),
SI_ACCESS_GENERAL },
{ &GUID_NULL,
FILE_GENERIC_READ | FILE_EXECUTE,
MAKEINTRESOURCE(IDS_SHAREPERM_READ),
SI_ACCESS_GENERAL }
};
#define iShareDefAccess 2 // index of value in array siShareAccesses
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
#endif
STDMETHODIMP
CShareSecurityInformation::GetAccessRights(
const GUID *pguidObjectType,
DWORD dwFlags,
PSI_ACCESS *ppAccess,
ULONG *pcAccesses,
ULONG *piDefaultAccess
)
{
ASSERT(ppAccess);
ASSERT(pcAccesses);
ASSERT(piDefaultAccess);
*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
CShareSecurityInformation::MapGeneric(
const GUID *pguidObjectType,
UCHAR *pAceFlags,
ACCESS_MASK *pMask
)
{
ASSERT(pMask);
MapGenericMask(pMask, &ShareMap);
return S_OK;
}
STDMETHODIMP
CShareSecurityInformation::GetInheritTypes (
PSI_INHERIT_TYPE *ppInheritTypes,
ULONG *pcInheritTypes
)
{
return E_NOTIMPL;
}
STDMETHODIMP
CShareSecurityInformation::PropertySheetPageCallback(
HWND hwnd,
UINT uMsg,
SI_PAGE_TYPE uPage
)
{
return S_OK;
}
HRESULT
CShareSecurityInformation::GetDefaultSD(
OUT PSECURITY_DESCRIPTOR *ppsd
)
{
CPermEntry permEntry;
HRESULT hr = permEntry.Initialize(NULL, ACCOUNT_EVERYONE, SHARE_PERM_FULL_CONTROL);
if (SUCCEEDED(hr))
hr = BuildSecurityDescriptor(&permEntry, 1, ppsd);
return hr;
}
HRESULT
CShareSecurityInformation::MakeSelfRelativeCopy(
IN PSECURITY_DESCRIPTOR psdOriginal,
OUT PSECURITY_DESCRIPTOR *ppsdNew
)
{
ASSERT(psdOriginal);
ASSERT(ppsdNew);
*ppsdNew = NULL;
DWORD dwErr = 0;
PSECURITY_DESCRIPTOR psdSelfRelative = NULL;
do { // false loop
DWORD cbSD = ::GetSecurityDescriptorLength(psdOriginal);
if ( !(psdSelfRelative = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, cbSD)) )
{
dwErr = ::GetLastError();
break;
}
// 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) )
{
dwErr = ::GetLastError();
break;
}
if (sdc & SE_SELF_RELATIVE)
{
::memcpy(psdSelfRelative, psdOriginal, cbSD);
} else if ( !::MakeSelfRelativeSD(psdOriginal, psdSelfRelative, &cbSD) )
{
dwErr = ::GetLastError();
break;
}
*ppsdNew = psdSelfRelative;
} while (FALSE);
if (dwErr && psdSelfRelative)
LocalFree((HLOCAL)psdSelfRelative);
return (dwErr ? HRESULT_FROM_WIN32(dwErr) : S_OK);
}
///////////////////////////////////////////////////////
// class CFileSecurityDataObject
CFileSecurityDataObject::CFileSecurityDataObject()
: m_cRef(1)
{
}
CFileSecurityDataObject::~CFileSecurityDataObject()
{
TRACE(_T("CFileSecurityDataObject::~CFileSecurityDataObject m_cRef=%d\n"), m_cRef);
}
void
CFileSecurityDataObject::Initialize(
IN LPCTSTR lpszComputerName,
IN LPCTSTR lpszFolder
)
{
m_cstrComputerName = lpszComputerName;
m_cstrFolder = lpszFolder;
GetFullPath(lpszComputerName, lpszFolder, m_cstrPath);
m_cfIDList = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_SHELLIDLIST);
}
////////////////////////////////
// IUnknown methods
////////////////////////////////
STDMETHODIMP
CFileSecurityDataObject::QueryInterface(REFIID riid, LPVOID *ppv)
{
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDataObject))
{
*ppv = this;
m_cRef++;
return S_OK;
} else
{
*ppv = NULL;
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG)
CFileSecurityDataObject::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG)
CFileSecurityDataObject::Release()
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
STDMETHODIMP
CFileSecurityDataObject::GetData(
FORMATETC __RPC_FAR * pFormatEtcIn,
STGMEDIUM __RPC_FAR * pMedium
)
{
ASSERT(pFormatEtcIn);
ASSERT(pMedium);
if (m_cfIDList != pFormatEtcIn->cfFormat)
return DV_E_FORMATETC;
LPITEMIDLIST pidl = NULL;
LPITEMIDLIST pidlR = NULL;
HRESULT hr = GetFolderPIDList(&pidl);
if (SUCCEEDED(hr))
{
pidlR = ILClone(ILFindLastID(pidl)); // relative IDList
ILRemoveLastID(pidl); // folder IDList
int cidl = 1;
UINT offset = sizeof(CIDA) + sizeof(UINT)*cidl;
UINT cbFolder = ILGetSize(pidl);
UINT cbRelative = ILGetSize(pidlR);
UINT cbTotal = offset + cbFolder + cbRelative;
HGLOBAL hGlobal = ::GlobalAlloc (GPTR, cbTotal);
if ( hGlobal )
{
LPIDA pida = (LPIDA)hGlobal;
pida->cidl = cidl;
pida->aoffset[0] = offset;
MoveMemory(((LPBYTE)hGlobal+offset), pidl, cbFolder);
offset += cbFolder;
pida->aoffset[1] = offset;
MoveMemory(((LPBYTE)hGlobal+offset), pidlR, cbRelative);
pMedium->hGlobal = hGlobal;
} else
{
hr = E_OUTOFMEMORY;
}
if (pidl)
ILFree(pidl);
if (pidlR)
ILFree(pidlR);
}
return hr;
}
HRESULT
CFileSecurityDataObject::GetFolderPIDList(
OUT LPITEMIDLIST *ppidl
)
{
ASSERT(!m_cstrPath.IsEmpty());
ASSERT(ppidl);
ASSERT(!*ppidl); // prevent memory leak
*ppidl = ILCreateFromPath(m_cstrPath);
return ((*ppidl) ? S_OK : E_FAIL);
}
///////////////////////////////////////////////
// File security
// Security Shell extension CLSID - {1F2E5C40-9550-11CE-99D2-00AA006E086C}
const CLSID CLSID_ShellExtSecurity =
{0x1F2E5C40, 0x9550, 0x11CE, {0x99, 0xD2, 0x0, 0xAA, 0x0, 0x6E, 0x08, 0x6C}};
BOOL CALLBACK
AddPageProc(HPROPSHEETPAGE hPage, LPARAM lParam)
{
// pass out the created page handle
*((HPROPSHEETPAGE *)lParam) = hPage;
return TRUE;
}
HRESULT
CreateFileSecurityPropPage(
HPROPSHEETPAGE *phOutPage,
LPDATAOBJECT pDataObject
)
{
ASSERT(phOutPage);
ASSERT(pDataObject);
IShellExtInit *piShellExtInit = NULL;
HRESULT hr = CoCreateInstance(CLSID_ShellExtSecurity,
NULL,
CLSCTX_INPROC_SERVER,
IID_IShellExtInit,
(void **)&piShellExtInit);
if (SUCCEEDED(hr))
{
hr = piShellExtInit->Initialize(NULL, pDataObject, 0);
if (SUCCEEDED(hr))
{
IShellPropSheetExt *piSPSE = NULL;
hr = piShellExtInit->QueryInterface(IID_IShellPropSheetExt, (void **)&piSPSE);
if (SUCCEEDED(hr))
{
hr = piSPSE->AddPages(AddPageProc, (LPARAM)phOutPage);
piSPSE->Release();
}
}
piShellExtInit->Release();
}
return hr;
}