windows-nt/Source/XPSP1/NT/base/fs/utils/regedit/regsec.cpp
2020-09-26 16:20:57 +08:00

1618 lines
49 KiB
C++

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
regsec.cpp
Abstract:
ISecurityInformation implementation for Registry Key
Author:
Hitesh Raigandhi (raigah) May-1999
Revision History:
--*/
//Include Files:
#include "wchar.h"
#include "regsec.h"
#include "regresid.h"
#include "assert.h"
// ISecurityInformation interface implementation
EXTERN_C const GUID IID_ISecurityInformation ;
// = { 0x965fc360, 0x16ff, 0x11d0, 0x91, 0xcb, 0x0, 0xaa, 0x0, 0xbb, 0xb7, 0x23 };
//The Following array defines the permission names for Registry Key Objects
SI_ACCESS siKeyAccesses[] =
{
{ NULL,
KEY_ALL_ACCESS,
MAKEINTRESOURCE(IDS_SEC_EDITOR_FULL_ACCESS),
SI_ACCESS_GENERAL | CONTAINER_INHERIT_ACE | SI_ACCESS_SPECIFIC },
{ NULL,
KEY_QUERY_VALUE,
MAKEINTRESOURCE(IDS_SEC_EDITOR_QUERY_VALUE),
SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE },
{ NULL,
KEY_SET_VALUE,
MAKEINTRESOURCE(IDS_SEC_EDITOR_SET_VALUE),
SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE },
{ NULL,
KEY_CREATE_SUB_KEY,
MAKEINTRESOURCE(IDS_SEC_EDITOR_CREATE_SUBKEY),
SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE },
{ NULL,
KEY_ENUMERATE_SUB_KEYS,
MAKEINTRESOURCE(IDS_SEC_EDITOR_ENUM_SUBKEYS),
SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE },
{ NULL,
KEY_NOTIFY,
MAKEINTRESOURCE(IDS_SEC_EDITOR_NOTIFY),
SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE },
{ NULL,
KEY_CREATE_LINK,
MAKEINTRESOURCE(IDS_SEC_EDITOR_CREATE_LINK),
SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE },
{ NULL,
0x00010000, /* DELETE, */
MAKEINTRESOURCE(IDS_SEC_EDITOR_DELETE),
SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE },
{ NULL,
WRITE_DAC,
MAKEINTRESOURCE(IDS_SEC_EDITOR_WRITE_DAC),
SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE },
{ NULL,
WRITE_OWNER,
MAKEINTRESOURCE(IDS_SEC_EDITOR_WRITE_OWNER),
SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE },
{ NULL,
READ_CONTROL,
MAKEINTRESOURCE(IDS_SEC_EDITOR_READ_CONTROL),
SI_ACCESS_SPECIFIC | CONTAINER_INHERIT_ACE },
{ NULL,
KEY_READ,
MAKEINTRESOURCE(IDS_SEC_EDITOR_READ),
SI_ACCESS_GENERAL | CONTAINER_INHERIT_ACE },
};
// The following array defines the inheritance types for Registry.
//
//
// For Keys, objects and containers are the same, so no need for OBJECT_INHERIT_ACE
//
SI_INHERIT_TYPE siKeyInheritTypes[] =
{
NULL, 0, MAKEINTRESOURCE(IDS_KEY_FOLDER),
NULL, CONTAINER_INHERIT_ACE, MAKEINTRESOURCE(IDS_KEY_FOLDER_SUBFOLDER),
NULL, INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE, MAKEINTRESOURCE(IDS_KEY_SUBFOLDER_ONLY)
};
#define iKeyDefAccess 10 // index of value in array siKeyAccesses
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
#endif
PWSTR _PredefinedKeyName[] = { L"CLASSES_ROOT",
L"CURRENT_USER",
L"MACHINE",
L"USERS",
L"CONFIG" };
//CKeySecurityInformation Functions
HRESULT
CKeySecurityInformation::Initialize( LPCWSTR strKeyName,
LPCWSTR strParentName,
LPCWSTR strMachineName,
LPCWSTR strPageTitle,
BOOL bRemote,
PREDEFINE_KEY PredefinedKey,
BOOL bReadOnly,
HWND hWnd)
{
if( strParentName )
if( !strKeyName )
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
if( NULL == strMachineName )
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
if( NULL == hWnd )
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
if( NULL == strPageTitle )
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
AuthzInitializeResourceManager(NULL,
NULL,
NULL,
NULL,
0,
&m_ResourceManager );
HRESULT hr = S_OK;
m_strKeyName = strKeyName;
m_strParentName = strParentName;
m_strMachineName = strMachineName;
m_strPageTitle = strPageTitle;
m_bRemote = bRemote;
m_PredefinedKey = PredefinedKey;
m_bReadOnly = bReadOnly;
m_hWnd = hWnd;
m_dwFlags = SI_EDIT_ALL | SI_ADVANCED | SI_CONTAINER
| SI_RESET_DACL_TREE | SI_RESET_SACL_TREE
| SI_OWNER_RECURSE | SI_PAGE_TITLE | SI_EDIT_EFFECTIVE;
if( m_bReadOnly )
m_dwFlags |= SI_READONLY | SI_OWNER_READONLY ;
//Set Handle to Predfined key
if( S_OK != ( hr = SetHandleToPredefinedKey() ) )
return hr;
//Set CompleteName
if( S_OK != ( hr = SetCompleteName() ) )
return hr;
return S_OK;
}
CKeySecurityInformation::~CKeySecurityInformation()
{
if( m_strCompleteName )
LocalFree( m_strCompleteName );
//Close Handle to Remote Registry if it was successfully opened.
if( m_bRemote && m_hkeyPredefinedKey )
RegCloseKey(m_hkeyPredefinedKey);
AuthzFreeResourceManager(m_ResourceManager);
}
//Sets the complete name in Format:
// "\\machine_name\Predefined_keyName\regkey_path
HRESULT
CKeySecurityInformation::SetCompleteName()
{
UINT len = 0;
PWSTR pstrCompleteName;
if( m_bRemote )
{
len += wcslen( m_strMachineName );
len++;
}
len += wcslen(_PredefinedKeyName[ m_PredefinedKey]);
len++;
if( m_strParentName )
{
len += wcslen(m_strParentName);
len++;
}
if( m_strKeyName )
{
len += wcslen(m_strKeyName);
len++;
}
len++; //Terminating null
pstrCompleteName = (PWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR));
if( pstrCompleteName == NULL )
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
if( m_bRemote )
{
wcscpy(pstrCompleteName,m_strMachineName);
wcscat(pstrCompleteName, L"\\");
}
wcscat(pstrCompleteName,_PredefinedKeyName[ m_PredefinedKey]);
wcscat(pstrCompleteName,L"\\");
if(m_strParentName)
{
wcscat(pstrCompleteName,m_strParentName);
wcscat(pstrCompleteName,L"\\");
}
if(m_strKeyName)
{
wcscat(pstrCompleteName, m_strKeyName );
wcscat(pstrCompleteName,L"\\");
}
m_strCompleteName = pstrCompleteName;
return S_OK;
}
//Doesn't have Predefined key name attached
//Caller must LocalFree
LPCWSTR
CKeySecurityInformation::GetCompleteName1()
{
UINT len = 0;
PWSTR pstrCompleteName;
if( m_strParentName )
{
len += wcslen(m_strParentName);
len++;
}
if( m_strKeyName )
{
len += wcslen(m_strKeyName);
len++;
}
len++; //Terminating null
pstrCompleteName = (PWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR));
if( pstrCompleteName == NULL )
return NULL;
if(m_strParentName)
{
wcscpy(pstrCompleteName,m_strParentName);
wcscat(pstrCompleteName,L"\\");
}
if(m_strKeyName)
{
wcscat(pstrCompleteName, m_strKeyName );
wcscat(pstrCompleteName,L"\\");
}
return pstrCompleteName;
}
HRESULT
CKeySecurityInformation::SetHandleToPredefinedKey()
{
DWORD dwErr;
HRESULT hr = S_OK;
if( !m_bRemote ) {
switch ( m_PredefinedKey ){
case PREDEFINE_KEY_CLASSES_ROOT:
m_hkeyPredefinedKey= HKEY_CLASSES_ROOT;
break;
case PREDEFINE_KEY_CURRENT_USER:
m_hkeyPredefinedKey = HKEY_CURRENT_USER;
break;
case PREDEFINE_KEY_LOCAL_MACHINE :
m_hkeyPredefinedKey = HKEY_LOCAL_MACHINE;
break;
case PREDEFINE_KEY_USERS:
m_hkeyPredefinedKey = HKEY_USERS;
break;
case PREDEFINE_KEY_CURRENT_CONFIG :
m_hkeyPredefinedKey = HKEY_CURRENT_CONFIG;
break;
default:
//assert(false);
break;
}
}
else { //IsRemoteRegistry
switch ( m_PredefinedKey ){
case PREDEFINE_KEY_CLASSES_ROOT:
case PREDEFINE_KEY_CURRENT_USER:
case PREDEFINE_KEY_CURRENT_CONFIG:
m_hkeyPredefinedKey = 0;
break;
case PREDEFINE_KEY_LOCAL_MACHINE :
m_hkeyPredefinedKey = HKEY_LOCAL_MACHINE;
break;
case PREDEFINE_KEY_USERS:
m_hkeyPredefinedKey = HKEY_USERS;
break;
default:
//assert(false);
break;
}
if( m_hkeyPredefinedKey ){
dwErr = RegConnectRegistry( m_strMachineName,
m_hkeyPredefinedKey,
&m_hkeyPredefinedKey );
if( dwErr ) {
m_hkeyPredefinedKey = 0;
hr = HRESULT_FROM_WIN32( dwErr );
}
}
} //IsRemoteRegistry
return hr;
}
/*
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
CKeySecurityInformation::GetObjectInformation (
PSI_OBJECT_INFO pObjectInfo )
{
assert( NULL != pObjectInfo );
pObjectInfo->dwFlags = m_dwFlags;
pObjectInfo->hInstance = GetModuleHandle(NULL);
// pObjectInfo->pszServerName = (LPWSTR)m_strMachineName;
pObjectInfo->pszServerName = (LPWSTR)m_strMachineName;
pObjectInfo->pszObjectName = (LPWSTR)m_strPageTitle;
return S_OK;
}
STDMETHODIMP
CKeySecurityInformation::GetAccessRights(
const GUID *pguidObjectType,
DWORD dwFlags,
PSI_ACCESS *ppAccess,
ULONG *pcAccesses,
ULONG *piDefaultAccess
)
{
assert( NULL != ppAccess );
assert( NULL != pcAccesses );
assert( NULL != piDefaultAccess );
*ppAccess = siKeyAccesses;
*pcAccesses = ARRAYSIZE(siKeyAccesses);
*piDefaultAccess = iKeyDefAccess;
return S_OK;
}
GENERIC_MAPPING KeyMap =
{
KEY_READ,
KEY_WRITE,
KEY_READ,
KEY_ALL_ACCESS
};
STDMETHODIMP
CKeySecurityInformation::MapGeneric(
const GUID *pguidObjectType,
UCHAR *pAceFlags,
ACCESS_MASK *pMask
)
{
//jeffreys
// After returning from the object picker dialog, aclui passes
//CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE to MapGeneric for validation when
// initializing Permission entry for <objectname> dialog.
//hiteshr: since registry keys don't have OBJECT_INHERIT_ACE, remove this FLAG,
//this will cause "this keys and subkeys" to appear as default in combobox.
*pAceFlags &= ~OBJECT_INHERIT_ACE;
MapGenericMask(pMask, &KeyMap);
return S_OK;
}
STDMETHODIMP
CKeySecurityInformation::GetInheritTypes (
PSI_INHERIT_TYPE *ppInheritTypes,
ULONG *pcInheritTypes
)
{
assert( NULL != ppInheritTypes );
assert( NULL != pcInheritTypes );
*ppInheritTypes = siKeyInheritTypes;
*pcInheritTypes = ARRAYSIZE(siKeyInheritTypes);
return S_OK;
}
STDMETHODIMP
CKeySecurityInformation::PropertySheetPageCallback(
HWND hwnd,
UINT uMsg,
SI_PAGE_TYPE uPage
)
{
switch (uMsg)
{
case PSPCB_SI_INITDIALOG:
m_hWndProperty = hwnd;
break;
case PSPCB_RELEASE:
m_hWndProperty = NULL;
break;
}
return S_OK;
}
STDMETHODIMP
CKeySecurityInformation::GetSecurity( IN SECURITY_INFORMATION RequestedInformation,
OUT PSECURITY_DESCRIPTOR *ppSecurityDescriptor,
IN BOOL fDefault )
{
if( fDefault )
return E_NOTIMPL;
assert( NULL != ppSecurityDescriptor );
HRESULT hr;
LPCTSTR pstrKeyName = GetCompleteName();
DWORD dwErr = 0;
dwErr = GetNamedSecurityInfo( (LPTSTR)pstrKeyName,
SE_REGISTRY_KEY,
RequestedInformation,
NULL,
NULL,
NULL,
NULL,
ppSecurityDescriptor);
return ( ( dwErr != ERROR_SUCCESS ) ? HRESULT_FROM_WIN32(dwErr) : S_OK);
}
STDMETHODIMP
CKeySecurityInformation::SetSecurity(IN SECURITY_INFORMATION si,
IN PSECURITY_DESCRIPTOR pSD )
{
if( NULL == pSD )
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
HRESULT hr = S_OK;
SECURITY_INFORMATION siLocal = 0;
SECURITY_DESCRIPTOR sdLocal = {0};
ACL daclEmpty = {0};
HKEY hkeyOld = NULL;
HKEY hKeyNew = NULL;
BOOL bWriteInfo = false;
DWORD Error = 0;
//
// Create a security descriptor with no SACL and an
// empty DACL for recursively resetting security
//
InitializeSecurityDescriptor(&sdLocal, SECURITY_DESCRIPTOR_REVISION);
InitializeAcl(&daclEmpty, sizeof(ACL), ACL_REVISION);
SetSecurityDescriptorDacl(&sdLocal, TRUE, &daclEmpty, FALSE);
SetSecurityDescriptorSacl(&sdLocal, TRUE, &daclEmpty, FALSE);
//
// If we need to recursively set the Owner, get the Owner &
// Group from pSD.
//
if (si & SI_OWNER_RECURSE)
{
PSID psid;
BOOL bDefaulted;
assert(si & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION));
siLocal |= si & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);
if (GetSecurityDescriptorOwner(pSD, &psid, &bDefaulted))
SetSecurityDescriptorOwner(&sdLocal, psid, bDefaulted);
if (GetSecurityDescriptorGroup(pSD, &psid, &bDefaulted))
SetSecurityDescriptorGroup(&sdLocal, psid, bDefaulted);
}
if (si & SI_RESET_DACL_TREE)
{
assert(si & DACL_SECURITY_INFORMATION);
siLocal |= si & DACL_SECURITY_INFORMATION;
}
if (si & SI_RESET_SACL_TREE)
{
assert(si & SACL_SECURITY_INFORMATION);
siLocal |= si & SACL_SECURITY_INFORMATION;
}
if( siLocal )
{
//Open the key with current Maximum Allowed Permisson
//When applying permissons recursively , we first use current permisson,
//if current permisson doesn't have enough rights, we reopen handle to key with
//new permissons. If none (old or new )has enough permissons to enumerate child and
// Query info we fail.
REGSAM samDesired = MAXIMUM_ALLOWED;
if( si & SACL_SECURITY_INFORMATION )
samDesired |= ACCESS_SYSTEM_SECURITY;
if( si & DACL_SECURITY_INFORMATION )
samDesired |= WRITE_DAC;
if( si & OWNER_SECURITY_INFORMATION )
samDesired |= WRITE_OWNER;
//Open the selected key
if( S_OK != ( hr = OpenKey( samDesired, &hkeyOld ) ) ){
return hr;
}
//Check if key has Enumeration Permisson
DWORD NumberOfSubKeys = 0;
DWORD MaxSubKeyLength = 0;
// Find out the total number of subkeys
Error = RegQueryInfoKey(
hkeyOld,
NULL,
NULL,
NULL,
&NumberOfSubKeys,
&MaxSubKeyLength,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
if( Error != ERROR_SUCCESS ){
if( Error == ERROR_ACCESS_DENIED ) {
hr = WriteObjectSecurity( hkeyOld, si, pSD );
if( hr != S_OK )
{
if( m_hkeyPredefinedKey != hkeyOld )
RegCloseKey( hkeyOld );
return hr;
}
bWriteInfo = true;
//
// Handle doesn't allow KEY_QUERY_VALUE or READ_CONTROL access.
// Open a new handle with these accesses.
//
samDesired = MAXIMUM_ALLOWED;
if( si & SACL_SECURITY_INFORMATION ) {
samDesired |= ACCESS_SYSTEM_SECURITY;
} else if( si & DACL_SECURITY_INFORMATION ) {
samDesired |= WRITE_DAC;
} else if( si & OWNER_SECURITY_INFORMATION ) {
samDesired |= WRITE_OWNER;
}
Error = RegOpenKeyEx( hkeyOld,
NULL,
REG_OPTION_RESERVED,
samDesired,
&hKeyNew
);
if( Error != ERROR_SUCCESS )
{
if( m_hkeyPredefinedKey != hkeyOld )
RegCloseKey( hkeyOld );
return HRESULT_FROM_WIN32(Error);
}
else
{
if( m_hkeyPredefinedKey != hkeyOld )
RegCloseKey( hkeyOld );
}
Error = RegQueryInfoKey(
hKeyNew,
NULL,
NULL,
NULL,
&NumberOfSubKeys,
&MaxSubKeyLength,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL );
if( Error != ERROR_SUCCESS ) {
RegCloseKey( hKeyNew );
return HRESULT_FROM_WIN32( Error );
}
}
else
{
if( m_hkeyPredefinedKey != hkeyOld )
RegCloseKey( hkeyOld );
return HRESULT_FROM_WIN32( Error );
}
}
else
hKeyNew = hkeyOld;
if( NumberOfSubKeys )
{
assert( MaxSubKeyLength <= MAX_PATH );
DWORD SubKeyNameLength = 0;
WCHAR SubKeyName[MAX_PATH + 1];
//
// The key has subkeys.
// Find out if we are able to enumerate the key using the handle
// passed as argument.
//
SubKeyNameLength = MAX_PATH;
Error = RegEnumKey( hKeyNew,
0,
SubKeyName,
SubKeyNameLength );
if( Error != ERROR_SUCCESS ){
if( Error == ERROR_ACCESS_DENIED && bWriteInfo == false ){
hr = WriteObjectSecurity( hkeyOld, si, pSD );
if( hr != S_OK )
{
if( m_hkeyPredefinedKey != hkeyOld )
RegCloseKey( hkeyOld );
return hr;
}
bWriteInfo = true;
//
// Handle doesn't allow KEY_QUERY_VALUE or READ_CONTROL access.
// Open a new handle with these accesses.
//
samDesired = MAXIMUM_ALLOWED;
if( si & SACL_SECURITY_INFORMATION ) {
samDesired |= ACCESS_SYSTEM_SECURITY;
} else if( si & DACL_SECURITY_INFORMATION ) {
samDesired |= WRITE_DAC;
} else if( si & OWNER_SECURITY_INFORMATION ) {
samDesired |= WRITE_OWNER;
}
Error = RegOpenKeyEx( hkeyOld,
NULL,
REG_OPTION_RESERVED,
samDesired,
&hKeyNew
);
if( Error != ERROR_SUCCESS )
{
if( m_hkeyPredefinedKey != hkeyOld )
RegCloseKey( hkeyOld );
return HRESULT_FROM_WIN32(Error);
}
else
{
if( m_hkeyPredefinedKey != hkeyOld )
RegCloseKey( hkeyOld );
}
SubKeyNameLength = MAX_PATH;
Error = RegEnumKey( hKeyNew,
0,
SubKeyName,
SubKeyNameLength );
if( Error != ERROR_SUCCESS ){
RegCloseKey( hKeyNew );
return HRESULT_FROM_WIN32(Error);
}
}
else
{
if( m_hkeyPredefinedKey != hKeyNew )
RegCloseKey( hKeyNew );
return HRESULT_FROM_WIN32(Error);
}
}
}
}
//
// Recursively apply new Owner and/or reset the ACLs
//
if (siLocal)
{
BOOL bNotAllApplied = FALSE;
hr = SetSubKeysSecurity( hKeyNew, siLocal, &sdLocal, &bNotAllApplied, true );
RegFlushKey( hKeyNew );
if( m_hkeyPredefinedKey != hKeyNew )
RegCloseKey( hKeyNew );
if( bNotAllApplied )
{
if( siLocal & OWNER_SECURITY_INFORMATION )
{
DisplayMessage( GetInFocusHWnd(),
GetModuleHandle(NULL),
IDS_SET_OWNER_RECURSIVE_EX_FAIL,
IDS_SECURITY );
}
else if( ( siLocal & DACL_SECURITY_INFORMATION ) || ( siLocal & SACL_SECURITY_INFORMATION ) )
{
DisplayMessage( GetInFocusHWnd(),
GetModuleHandle(NULL),
IDS_SET_SECURITY_RECURSIVE_EX_FAIL,
IDS_SECURITY);
}
}
if( hr != S_OK )
return hr;
}
si &= ~(SI_OWNER_RECURSE | SI_RESET_DACL_TREE | SI_RESET_SACL_TREE);
//This sets the security for the top keys
if (si != 0)
{
hr = WriteObjectSecurity( GetCompleteName(),
si,
pSD );
if( hr != S_OK )
{
if( siLocal )
RegCloseKey( hkeyOld );
return hr;
}
}
return hr;
}
STDMETHODIMP
CKeySecurityInformation::WriteObjectSecurity(LPCTSTR pszObject,
IN SECURITY_INFORMATION si,
IN PSECURITY_DESCRIPTOR pSD )
{
DWORD dwErr;
SECURITY_DESCRIPTOR_CONTROL wSDControl = 0;
DWORD dwRevision;
PSID psidOwner = NULL;
PSID psidGroup = NULL;
PACL pDacl = NULL;
PACL pSacl = NULL;
BOOL bDefaulted;
BOOL bPresent;
//
// Get pointers to various security descriptor parts for
// calling SetNamedSecurityInfo
//
if( !GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision) )
{
dwErr = GetLastError();
return HRESULT_FROM_WIN32(dwErr);
}
if( !GetSecurityDescriptorOwner(pSD, &psidOwner, &bDefaulted) )
{
dwErr = GetLastError();
return HRESULT_FROM_WIN32(dwErr);
}
if( !GetSecurityDescriptorGroup(pSD, &psidGroup, &bDefaulted) )
{
dwErr = GetLastError();
return HRESULT_FROM_WIN32(dwErr);
}
if( !GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted) )
{
dwErr = GetLastError();
return HRESULT_FROM_WIN32(dwErr);
}
if( !GetSecurityDescriptorSacl(pSD, &bPresent, &pSacl, &bDefaulted) )
{
dwErr = GetLastError();
return HRESULT_FROM_WIN32(dwErr);
}
if ((si & DACL_SECURITY_INFORMATION) && (wSDControl & SE_DACL_PROTECTED))
si |= PROTECTED_DACL_SECURITY_INFORMATION;
else
si |= UNPROTECTED_DACL_SECURITY_INFORMATION;
if ((si & SACL_SECURITY_INFORMATION) && (wSDControl & SE_SACL_PROTECTED))
si |= PROTECTED_SACL_SECURITY_INFORMATION;
else
si |= UNPROTECTED_SACL_SECURITY_INFORMATION;
//if the selected key is predefined key, it has no parent and hence
//cannot inherit any permisson from parent.
//if PROTECTED_DACL_SECURITY_INFORMATION flag is not set in this case
// SetSecurityInfo succeeds, but permissions are not set.[bug in SetSecurityInfo].
if ( (si & DACL_SECURITY_INFORMATION) && !m_strKeyName )
si |= PROTECTED_DACL_SECURITY_INFORMATION;
else
si |= UNPROTECTED_DACL_SECURITY_INFORMATION;
if ( (si & SACL_SECURITY_INFORMATION) && !m_strKeyName )
si |= PROTECTED_SACL_SECURITY_INFORMATION;
else
si |= UNPROTECTED_SACL_SECURITY_INFORMATION;
//We are on the root object
if( m_strKeyName == NULL )
{
dwErr = SetSecurityInfo( m_hkeyPredefinedKey,
SE_REGISTRY_KEY,
si,
psidOwner,
psidGroup,
pDacl,
pSacl);
}else
{
dwErr = SetNamedSecurityInfo((LPWSTR)pszObject,
SE_REGISTRY_KEY,
si,
psidOwner,
psidGroup,
pDacl,
pSacl);
}
return (dwErr ? HRESULT_FROM_WIN32(dwErr) : S_OK);
}
STDMETHODIMP
CKeySecurityInformation::WriteObjectSecurity(HKEY hkey,
IN SECURITY_INFORMATION si,
IN PSECURITY_DESCRIPTOR pSD )
{
DWORD dwErr;
SECURITY_DESCRIPTOR_CONTROL wSDControl = 0;
DWORD dwRevision;
PSID psidOwner = NULL;
PSID psidGroup = NULL;
PACL pDacl = NULL;
PACL pSacl = NULL;
BOOL bDefaulted;
BOOL bPresent;
//
// Get pointers to various security descriptor parts for
// calling SetNamedSecurityInfo
//
;
if( !GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision) )
{
dwErr = GetLastError();
return HRESULT_FROM_WIN32(dwErr);
}
if( !GetSecurityDescriptorOwner(pSD, &psidOwner, &bDefaulted) )
{
dwErr = GetLastError();
return HRESULT_FROM_WIN32(dwErr);
}
if( !GetSecurityDescriptorGroup(pSD, &psidGroup, &bDefaulted) )
{
dwErr = GetLastError();
return HRESULT_FROM_WIN32(dwErr);
}
if( !GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted) )
{
dwErr = GetLastError();
return HRESULT_FROM_WIN32(dwErr);
}
if( !GetSecurityDescriptorSacl(pSD, &bPresent, &pSacl, &bDefaulted) )
{
dwErr = GetLastError();
return HRESULT_FROM_WIN32(dwErr);
}
if ((si & DACL_SECURITY_INFORMATION) && (wSDControl & SE_DACL_PROTECTED))
si |= PROTECTED_DACL_SECURITY_INFORMATION;
else
si |= UNPROTECTED_DACL_SECURITY_INFORMATION;
if ((si & SACL_SECURITY_INFORMATION) && (wSDControl & SE_SACL_PROTECTED))
si |= PROTECTED_SACL_SECURITY_INFORMATION;
else
si |= UNPROTECTED_SACL_SECURITY_INFORMATION;
dwErr = SetSecurityInfo( hkey,
SE_REGISTRY_KEY,
si,
psidOwner,
psidGroup,
pDacl,
pSacl);
return (dwErr ? HRESULT_FROM_WIN32(dwErr) : S_OK);
}
HRESULT
CKeySecurityInformation::SetSubKeysSecurity( HKEY hkey,
SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR pSD,
LPBOOL pbNotAllApplied,
bool bFirstCall )
{
ULONG Error;
REGSAM samDesired;
HRESULT hr;
HRESULT hrRet;
HKEY hKeyNew;
//For First Call we call SetSecurityInfoEx in last
if( !bFirstCall ){
SECURITY_DESCRIPTOR_CONTROL wSDControl = 0;
DWORD dwRevision;
PSID psidOwner = NULL;
PSID psidGroup = NULL;
PACL pDacl = NULL;
PACL pSacl = NULL;
BOOL bDefaulted;
BOOL bPresent;
DWORD dwErr;
//
// Get pointers to various security descriptor parts for
// calling SetNamedSecurityInfo
//
if( !GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision) )
{
*pbNotAllApplied = TRUE;
goto SET_FOR_CHILD;
}
if( !GetSecurityDescriptorOwner(pSD, &psidOwner, &bDefaulted) )
{
*pbNotAllApplied = TRUE;
goto SET_FOR_CHILD;
}
if( !GetSecurityDescriptorGroup(pSD, &psidGroup, &bDefaulted) )
{
*pbNotAllApplied = TRUE;
goto SET_FOR_CHILD;
}
if( !GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted) )
{
*pbNotAllApplied = TRUE;
goto SET_FOR_CHILD;
}
if( !GetSecurityDescriptorSacl(pSD, &bPresent, &pSacl, &bDefaulted) )
{
*pbNotAllApplied = TRUE;
goto SET_FOR_CHILD;
}
if ((si & DACL_SECURITY_INFORMATION) && (wSDControl & SE_DACL_PROTECTED))
si |= PROTECTED_DACL_SECURITY_INFORMATION;
else
si |= UNPROTECTED_DACL_SECURITY_INFORMATION;
if ((si & SACL_SECURITY_INFORMATION) && (wSDControl & SE_SACL_PROTECTED))
si |= PROTECTED_SACL_SECURITY_INFORMATION;
else
si |= UNPROTECTED_SACL_SECURITY_INFORMATION;
dwErr = SetSecurityInfo( hkey,
SE_REGISTRY_KEY,
si,
psidOwner,
psidGroup,
pDacl,
pSacl);
if( dwErr != ERROR_SUCCESS )
{
*pbNotAllApplied = TRUE;
goto SET_FOR_CHILD;
//return HRESULT_FROM_WIN32(dwErr);
}
//RegFlushKey( hkey );
}
SET_FOR_CHILD:
DWORD NumberOfSubKeys = 0;
DWORD MaxSubKeyLength = 0;
// Find out the total number of subkeys
Error = RegQueryInfoKey(
hkey,
NULL,
NULL,
NULL,
&NumberOfSubKeys,
&MaxSubKeyLength,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
if( Error != ERROR_SUCCESS ){
if( Error == ERROR_ACCESS_DENIED ) {
//
// Handle doesn't allow KEY_QUERY_VALUE or READ_CONTROL access.
// Open a new handle with these accesses.
//
samDesired = KEY_QUERY_VALUE | READ_CONTROL; // MAXIMUM_ALLOWED | READ_CONTROL;
if( si & SACL_SECURITY_INFORMATION ) {
samDesired |= ACCESS_SYSTEM_SECURITY;
} else if( si & DACL_SECURITY_INFORMATION ) {
samDesired |= WRITE_DAC;
} else if( si & OWNER_SECURITY_INFORMATION ) {
samDesired |= WRITE_OWNER;
}
Error = RegOpenKeyEx( hkey,
NULL,
REG_OPTION_RESERVED,
samDesired,
&hKeyNew
);
if( Error != ERROR_SUCCESS ) {
*pbNotAllApplied = TRUE;
return S_OK;
}
Error = RegQueryInfoKey(
hKeyNew,
NULL,
NULL,
NULL,
&NumberOfSubKeys,
&MaxSubKeyLength,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL );
if( Error != ERROR_SUCCESS ) {
RegCloseKey( hKeyNew );
*pbNotAllApplied = TRUE;
return S_OK;
}
else
RegCloseKey( hKeyNew );
}
else{
*pbNotAllApplied = TRUE;
return S_OK;
}
}
if( NumberOfSubKeys == 0 ) {
return S_OK;
}
assert( MaxSubKeyLength <= MAX_PATH );
DWORD SubKeyNameLength = 0;
WCHAR SubKeyName[MAX_PATH + 1];
//
// The key has subkeys.
// Find out if we are able to enumerate the key using the handle
// passed as argument.
//
SubKeyNameLength = MAX_PATH;
Error = RegEnumKey( hkey,
0,
SubKeyName,
SubKeyNameLength );
if( Error != ERROR_SUCCESS ){
if( Error == ERROR_ACCESS_DENIED ) {
//
// Handle doesn't allow 'enumerate' access.
// Open a new handle with KEY_ENUMERATE_SUB_KEYS access.
//
Error = RegOpenKeyEx( hkey,
NULL,
REG_OPTION_RESERVED,
KEY_ENUMERATE_SUB_KEYS, // samDesired,
&hKeyNew
);
if( Error != ERROR_SUCCESS ){
*pbNotAllApplied = TRUE;
return S_OK;
}
}
else{
*pbNotAllApplied = TRUE;
return S_OK;
}
}
else {
hKeyNew = hkey;
}
for( DWORD Index = 0; Index < NumberOfSubKeys; Index++ )
{
// If the key has subkeys, then for each subkey, do:
// - Determine the subkey name
SubKeyNameLength = MAX_PATH;
Error = RegEnumKey( hKeyNew,
Index,
SubKeyName,
SubKeyNameLength );
if( Error != ERROR_SUCCESS ) {
*pbNotAllApplied = TRUE;
continue;
//return HRESULT_FROM_WIN32( Error );
}
// - Open a handle to the subkey
samDesired = MAXIMUM_ALLOWED;
if( si & SACL_SECURITY_INFORMATION )
samDesired |= ACCESS_SYSTEM_SECURITY;
if( si & DACL_SECURITY_INFORMATION )
samDesired |= WRITE_DAC;
if( si & OWNER_SECURITY_INFORMATION )
samDesired |= WRITE_OWNER;
HKEY hkeyChild;
Error = RegOpenKeyEx( hKeyNew,
SubKeyName,
REG_OPTION_RESERVED,
samDesired,
&hkeyChild
);
if( ERROR_SUCCESS != Error ){
*pbNotAllApplied = TRUE;
continue;
// return HRESULT_FROM_WIN32( Error );
}
// - Set the security of the child's subkeys
if( S_OK != ( hr = SetSubKeysSecurity( hkeyChild,
si,
pSD,
pbNotAllApplied,
false ) ) ){
//This case will occur only if some fatal error occur which
//prevents propogation on rest of the tree.
if( hKeyNew != hkey )
RegCloseKey( hKeyNew );
RegCloseKey( hkeyChild );
return hr;
}
else{
RegCloseKey( hkeyChild );
}
} //For loop
if( hKeyNew != hkey )
RegCloseKey( hKeyNew );
return S_OK;;
}
HRESULT
CKeySecurityInformation::OpenKey(IN DWORD Permission,
OUT PHKEY pKey )
{
LPCWSTR CompleteNameString = NULL;;
ULONG Error;
if( m_strKeyName == NULL){
//This is a predefined key
*pKey = m_hkeyPredefinedKey;
}
else{
CompleteNameString = GetCompleteName1();
assert( CompleteNameString != NULL );
// Open handle to the key
Error = RegOpenKeyEx(m_hkeyPredefinedKey,
CompleteNameString,
0,
Permission,
pKey );
if( Error != ERROR_SUCCESS ) {
return HRESULT_FROM_WIN32( Error );
}
}
if( CompleteNameString )
LocalFree( (HLOCAL) CompleteNameString);
return S_OK;
}
OBJECT_TYPE_LIST g_DefaultOTL[] = {
{0, 0, (LPGUID)&GUID_NULL},
};
BOOL SkipLocalGroup(LPCWSTR pszServerName, PSID psid)
{
SID_NAME_USE use;
WCHAR szAccountName[MAX_PATH];
WCHAR szDomainName[MAX_PATH];
DWORD dwAccountLen = MAX_PATH;
DWORD dwDomainLen = MAX_PATH;
if(LookupAccountSid(pszServerName,
psid,
szAccountName,
&dwAccountLen,
szDomainName,
&dwDomainLen,
&use))
{
if(use == SidTypeWellKnownGroup)
return TRUE;
}
//Built In sids have first subauthority of 32 ( s-1-5-32 )
//
if((*(GetSidSubAuthorityCount(psid)) >= 1 ) && (*(GetSidSubAuthority(psid,0)) == 32))
return TRUE;
return FALSE;
}
STDMETHODIMP
CKeySecurityInformation::GetEffectivePermission(const GUID* pguidObjectType,
PSID pUserSid,
LPCWSTR pszServerName,
PSECURITY_DESCRIPTOR pSD,
POBJECT_TYPE_LIST *ppObjectTypeList,
ULONG *pcObjectTypeListLength,
PACCESS_MASK *ppGrantedAccessList,
ULONG *pcGrantedAccessListLength)
{
AUTHZ_RESOURCE_MANAGER_HANDLE RM = NULL; //Used for access check
AUTHZ_CLIENT_CONTEXT_HANDLE CC = NULL;
LUID luid = {0xdead,0xbeef};
AUTHZ_ACCESS_REQUEST AReq;
AUTHZ_ACCESS_REPLY AReply;
HRESULT hr = S_OK;
DWORD dwFlags;
AReq.ObjectTypeList = g_DefaultOTL;
AReq.ObjectTypeListLength = ARRAYSIZE(g_DefaultOTL);
AReply.GrantedAccessMask = NULL;
AReply.Error = NULL;
//Get RM
if( (RM = GetAUTHZ_RM()) == NULL )
return S_FALSE;
//Initialize the client context
BOOL bSkipLocalGroup = SkipLocalGroup(pszServerName, pUserSid);
if( !AuthzInitializeContextFromSid(bSkipLocalGroup? AUTHZ_SKIP_TOKEN_GROUPS :0,
pUserSid,
RM,
NULL,
luid,
NULL,
&CC) )
{
return HRESULT_FROM_WIN32(GetLastError());
}
//Do the Access Check
AReq.DesiredAccess = MAXIMUM_ALLOWED;
AReq.PrincipalSelfSid = NULL;
AReq.OptionalArguments = NULL;
AReply.ResultListLength = AReq.ObjectTypeListLength;
AReply.SaclEvaluationResults = NULL;
if( (AReply.GrantedAccessMask = (PACCESS_MASK)LocalAlloc(LPTR, sizeof(ACCESS_MASK)*AReply.ResultListLength) ) == NULL )
return E_OUTOFMEMORY;
if( (AReply.Error = (PDWORD)LocalAlloc(LPTR, sizeof(DWORD)*AReply.ResultListLength)) == NULL )
{
LocalFree(AReply.GrantedAccessMask);
return E_OUTOFMEMORY;
}
if( !AuthzAccessCheck(0,
CC,
&AReq,
NULL,
pSD,
NULL,
0,
&AReply,
NULL) )
{
LocalFree(AReply.GrantedAccessMask);
LocalFree(AReply.Error);
return HRESULT_FROM_WIN32(GetLastError());
}
if(CC)
AuthzFreeContext(CC);
*ppObjectTypeList = AReq.ObjectTypeList;
*pcObjectTypeListLength = AReq.ObjectTypeListLength;
*ppGrantedAccessList = AReply.GrantedAccessMask;
*pcGrantedAccessListLength = AReq.ObjectTypeListLength;
return S_OK;
}
STDMETHODIMP
CKeySecurityInformation::GetInheritSource(SECURITY_INFORMATION si,
PACL pACL,
PINHERITED_FROM *ppInheritArray)
{
HRESULT hr = S_OK;
if (NULL == m_strKeyName || !pACL || !ppInheritArray)
return E_UNEXPECTED;
DWORD dwErr = ERROR_SUCCESS;
PINHERITED_FROM pTempInherit = NULL;
PINHERITED_FROM pTempInherit2 = NULL;
LPWSTR pStrTemp = NULL;
LPCWSTR pszName = GetCompleteName();
pTempInherit = (PINHERITED_FROM)LocalAlloc( LPTR, sizeof(INHERITED_FROM)*pACL->AceCount);
if(pTempInherit == NULL)
{
hr = E_OUTOFMEMORY;
goto exit_gracefully;
}
dwErr = GetInheritanceSource((LPWSTR)pszName,
SE_REGISTRY_KEY,
si,
TRUE,
NULL,
0,
pACL,
NULL,
&KeyMap,
pTempInherit);
hr = HRESULT_FROM_WIN32(dwErr);
if( FAILED(hr) )
goto exit_gracefully;
DWORD nSize;
UINT i;
nSize = sizeof(INHERITED_FROM)*pACL->AceCount;
for(i = 0; i < pACL->AceCount; ++i)
{
if(pTempInherit[i].AncestorName)
nSize += ((wcslen(pTempInherit[i].AncestorName)+1)*sizeof(WCHAR));
}
pTempInherit2 = (PINHERITED_FROM)LocalAlloc( LPTR, nSize );
if(pTempInherit2 == NULL)
{
hr = E_OUTOFMEMORY;
goto exit_gracefully;
}
pStrTemp = (LPWSTR)(pTempInherit2 + pACL->AceCount);
for(i = 0; i < pACL->AceCount; ++i)
{
pTempInherit2[i].GenerationGap = pTempInherit[i].GenerationGap;
if(pTempInherit[i].AncestorName)
{
pTempInherit2[i].AncestorName = pStrTemp;
wcscpy(pStrTemp,pTempInherit[i].AncestorName);
pStrTemp += (wcslen(pTempInherit[i].AncestorName)+1);
}
}
exit_gracefully:
if(SUCCEEDED(hr))
{
//FreeInheritedFromArray(pTempInherit, pACL->AceCount,NULL);
*ppInheritArray = pTempInherit2;
}
if(pTempInherit)
LocalFree(pTempInherit);
return hr;
}
///////////////////////////////////////////////////////////
//
// IUnknown methods
//
///////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG)
CSecurityInformation::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG)
CSecurityInformation::Release()
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
STDMETHODIMP
CSecurityInformation::QueryInterface(REFIID riid, LPVOID FAR* ppv)
{
// if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ISecurityInformation))
if ( IsEqualIID(riid, IID_ISecurityInformation) )
{
*ppv = (LPSECURITYINFO)this;
m_cRef++;
return S_OK;
}
else if(IsEqualIID(riid, IID_IEffectivePermission) )
{
*ppv = (LPEFFECTIVEPERMISSION)this;
m_cRef++;
return S_OK;
}
else if(IsEqualIID(riid, IID_ISecurityObjectTypeInfo) )
{
*ppv = (LPSecurityObjectTypeInfo)this;
m_cRef++;
return S_OK;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
}
HRESULT CreateSecurityInformation( IN LPCWSTR strKeyName,
IN LPCWSTR strParentName,
IN LPCWSTR strMachineName,
IN LPCWSTR strPageTitle,
IN BOOL bRemote,
IN PREDEFINE_KEY PredefinedKey,
IN BOOL bReadOnly,
IN HWND hWnd,
OUT LPSECURITYINFO *ppSi)
{
HRESULT hr;
if( !ppSi )
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
CKeySecurityInformation *ckey = new CKeySecurityInformation;
if( NULL == ckey )
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
if( S_OK != ( hr = ckey->Initialize( strKeyName,
strParentName,
strMachineName,
strPageTitle,
bRemote,
PredefinedKey,
bReadOnly,
hWnd ) ) )
{
delete ckey;
return hr;
}
else
{
*ppSi = ckey;
return S_OK;
}
}
//Some helper functions
BOOL DisplayMessage( HWND hWnd,
HINSTANCE hInstance,
DWORD dwMessageId,
DWORD dwCaptionId )
{
WCHAR pszMessage[1025];
WCHAR pszTitle[1025];
LPWSTR lpTitle = NULL;
if( !LoadString(hInstance, dwMessageId, pszMessage, 1024 ) )
return FALSE;
if( dwCaptionId )
{
if( LoadString(hInstance, dwCaptionId, pszTitle, 1024 ) )
lpTitle = pszTitle;
}
// Display the string.
MessageBox( hWnd, (LPCTSTR)pszMessage, (LPCTSTR)lpTitle, MB_OK | MB_ICONINFORMATION |MB_APPLMODAL );
return TRUE;
}