|
|
/*++
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"
#define STRSAFE_NO_DEPRECATE
#include <strsafe.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(AUTHZ_RM_FLAG_NO_AUDIT, 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 ) { StringCchCopyW(pstrCompleteName, len, m_strMachineName); StringCchCatW(pstrCompleteName, len, L"\\"); }
StringCchCatW(pstrCompleteName, len, _PredefinedKeyName[m_PredefinedKey]); StringCchCatW(pstrCompleteName, len, L"\\"); if(m_strParentName) { StringCchCatW(pstrCompleteName, len, m_strParentName); StringCchCatW(pstrCompleteName, len, L"\\"); }
if(m_strKeyName) { StringCchCatW(pstrCompleteName, len, m_strKeyName ); StringCchCatW(pstrCompleteName, len, 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) { StringCchCopyW(pstrCompleteName, len, m_strParentName); StringCchCatW(pstrCompleteName, len, L"\\"); }
if(m_strKeyName) { StringCchCatW(pstrCompleteName, len, m_strKeyName ); StringCchCatW(pstrCompleteName, len, 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(daclEmpty), 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; } }
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; }
|