windows-nt/Source/XPSP1/NT/ds/security/ntmarta/newsrc/regctx.cpp
2020-09-26 16:20:57 +08:00

1927 lines
42 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1999 - 2000.
//
// File: registry.cpp
//
// Contents: NtMarta registry functions
//
// History: 4/99 philh Created
//
//----------------------------------------------------------------------------
#include <aclpch.hxx>
#pragma hdrstop
extern "C" {
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
}
#include <windows.h>
#include <kernel.h>
#include <assert.h>
#include <ntstatus.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stddef.h>
#include <registry.h>
#include <wow64reg.h>
#ifdef STATIC
#undef STATIC
#endif
#define STATIC
// Registry object names returned by NtQueryObject are prefixed by
// the following
#define REG_OBJ_TAG L"\\REGISTRY\\"
#define REG_OBJ_TAG_LEN (sizeof(REG_OBJ_TAG) / sizeof(WCHAR) - 1)
//+-------------------------------------------------------------------------
// Registry Context data structures
//--------------------------------------------------------------------------
typedef struct _REG_FIND_DATA REG_FIND_DATA, *PREG_FIND_DATA;
typedef struct _REG_CONTEXT {
DWORD dwRefCnt;
DWORD dwFlags;
// Only closed when REG_CONTEXT_CLOSE_HKEY_FLAG is set
HKEY hKey;
LPWSTR pwszObject; // optional, allocated
// Following is allocated and updated for FindFirst, FindNext
PREG_FIND_DATA pRegFindData;
} REG_CONTEXT, *PREG_CONTEXT;
#define REG_CONTEXT_CLOSE_HKEY_FLAG 0x1
struct _REG_FIND_DATA {
PREG_CONTEXT pRegParentContext; // ref counted
DWORD cSubKeys;
DWORD cchMaxSubKey;
DWORD iSubKey; // index of next FindNext
// Following isn't allocated separately, it follows this data structure
LPWSTR pwszSubKey;
};
//+-------------------------------------------------------------------------
// Registry allocation functions
//--------------------------------------------------------------------------
#define I_MartaRegZeroAlloc(size) \
LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, size)
#define I_MartaRegNonzeroAlloc(size) \
LocalAlloc(LMEM_FIXED, size)
STATIC
inline
VOID
I_MartaRegFree(
IN LPVOID pv
)
{
if (pv)
LocalFree(pv);
}
STATIC
DWORD
I_MartaRegDupString(
IN LPCWSTR pwszOrig,
OUT LPWSTR *ppwszDup
)
/*++
Routine Description:
Allocate memory and copy the given name into it.
Arguments:
pwszOrig - String to be duplicated.
ppwszDup - To return the duplicate.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_NOT_ENOUGH_MEMORY if allocation failed.
--*/
{
DWORD dwErr;
DWORD cchOrig;
LPWSTR pwszDup;
cchOrig = wcslen(pwszOrig);
if (NULL == (pwszDup = (LPWSTR) I_MartaRegNonzeroAlloc(
(cchOrig + 1) * sizeof(WCHAR)))) {
*ppwszDup = NULL;
dwErr = ERROR_NOT_ENOUGH_MEMORY;
} else {
memcpy(pwszDup, pwszOrig, (cchOrig + 1) * sizeof(WCHAR));
*ppwszDup = pwszDup;
dwErr = ERROR_SUCCESS;
}
return dwErr;
}
STATIC
DWORD
I_MartaRegGetParentString(
IN OUT LPWSTR pwszParent
)
/*++
Routine Description:
Given the name for a registry key, get the name of its parent. Does not allocate
memory. Scans till the first '\' from the right and deletes the name after
that.
Arguments:
pwszParent - Object name which will be converted to its parent name.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
DWORD dwErr;
DWORD cch;
LPWSTR pwsz;
if (NULL == pwszParent)
return ERROR_INVALID_NAME;
cch = wcslen(pwszParent);
pwsz = pwszParent + cch;
if (0 == cch)
goto InvalidNameReturn;
pwsz--;
//
// Remove any trailing '\'s
//
while (L'\\' == *pwsz) {
if (pwsz == pwszParent)
goto InvalidNameReturn;
pwsz--;
}
//
// Peal off the last path name component
//
while (L'\\' != *pwsz) {
if (pwsz == pwszParent)
goto InvalidNameReturn;
pwsz--;
}
//
// Remove all trailing '\'s from the parent.
// This could also be the leading '\\'s for a computer name.
//
while (L'\\' == *pwsz) {
if (pwsz == pwszParent)
goto InvalidNameReturn;
pwsz--;
}
pwsz++;
assert(L'\\' == *pwsz);
dwErr = ERROR_SUCCESS;
CommonReturn:
*pwsz = L'\0';
return dwErr;
InvalidNameReturn:
dwErr = ERROR_INVALID_NAME;
goto CommonReturn;
}
STATIC
DWORD
I_MartaRegCreateChildString(
IN LPCWSTR pwszParent,
IN LPCWSTR pwszSubKey,
OUT LPWSTR *ppwszChild
)
/*++
Routine Description:
Given the name of the parent and the name of the subkey, create the full
name of the child.
Arguments:
pwszParent - Name of the parent.
pwszSubKey - Name of the subkey.
ppwszChild - To return the name of the child.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_NOT_ENOUGH_MEMORY if allocation failed.
--*/
{
DWORD dwErr;
DWORD cchParent;
DWORD cchSubKey;
DWORD cchChild;
LPWSTR pwszChild = NULL;
if (NULL == pwszParent || NULL == pwszSubKey)
goto InvalidNameReturn;
cchParent = wcslen(pwszParent);
//
// Remove any trailing '\'s from parent
//
while (0 < cchParent && L'\\' == pwszParent[cchParent - 1])
cchParent--;
if (0 == cchParent)
goto InvalidNameReturn;
cchSubKey = wcslen(pwszSubKey);
if (0 == cchSubKey)
goto InvalidNameReturn;
cchChild = cchParent + 1 + cchSubKey;
if (NULL == (pwszChild = (LPWSTR) I_MartaRegNonzeroAlloc(
(cchChild + 1) * sizeof(WCHAR))))
goto NotEnoughMemoryReturn;
//
// Construct the name of the child from the given strings.
//
memcpy(pwszChild, pwszParent, cchParent * sizeof(WCHAR));
pwszChild[cchParent] = L'\\';
memcpy(pwszChild + cchParent + 1, pwszSubKey, cchSubKey * sizeof(WCHAR));
pwszChild[cchChild] = L'\0';
dwErr = ERROR_SUCCESS;
CommonReturn:
*ppwszChild = pwszChild;
return dwErr;
InvalidNameReturn:
dwErr = ERROR_INVALID_NAME;
goto CommonReturn;
NotEnoughMemoryReturn:
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto CommonReturn;
}
STATIC
DWORD
I_MartaRegParseName(
IN OUT LPWSTR pwszObject,
OUT LPWSTR *ppwszMachine,
OUT LPWSTR *ppwszRemaining
)
/*++
Routine Description:
Parses a registry object name for the machine name.
Arguments:
pwszObject - the name of the object
ppwszMachine - the machine the object is on
ppwszRemaining - the remaining name after the machine name
Return Value:
ERROR_SUCCESS in case of success.
ERROR_NOT_ENOUGH_MEMORY if allocation failed.
--*/
{
if (pwszObject == wcsstr(pwszObject, L"\\\\")) {
*ppwszMachine = pwszObject + 2;
*ppwszRemaining = wcschr(*ppwszMachine, L'\\');
if (*ppwszRemaining != NULL) {
**ppwszRemaining = L'\0';
*ppwszRemaining += 1;
}
} else {
*ppwszMachine = NULL;
*ppwszRemaining = pwszObject;
}
return ERROR_SUCCESS;
}
STATIC
DWORD
I_MartaRegInitContext(
OUT PREG_CONTEXT *ppRegContext
)
/*++
Routine Description:
Allocate and initialize memory for the context.
Arguments:
ppRegContext - To return the pointer to the allcoated memory.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
DWORD dwErr;
PREG_CONTEXT pRegContext;
if (pRegContext = (PREG_CONTEXT) I_MartaRegZeroAlloc(
sizeof(REG_CONTEXT))) {
pRegContext->dwRefCnt = 1;
dwErr = ERROR_SUCCESS;
} else {
pRegContext = NULL;
dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
*ppRegContext = pRegContext;
return dwErr;
}
DWORD
MartaOpenRegistryKeyNamedObject(
IN LPCWSTR pwszObject,
IN ACCESS_MASK AccessMask,
OUT PMARTA_CONTEXT pContext
)
/*++
Routine Description:
Open the given registry key with desired access mask and return a context
handle.
Arguments:
pwszObject - Name of the registry key which will be opened.
AccessMask - Desired access mask with which the registry key will be opened.
pContext - To return a context handle.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
DWORD dwErr = ERROR_SUCCESS;
PREG_CONTEXT pRegContext = NULL;
LPWSTR pwszDupObject = NULL;
HKEY hKeyRemote = NULL;
HKEY hKeyBase; // not opened, don't close at return
//
// Following aren't allocated
//
LPWSTR pwszMachine, pwszRemaining, pwszBaseKey, pwszSubKey;
if (NULL == pwszObject)
goto InvalidNameReturn;
if (ERROR_SUCCESS != (dwErr = I_MartaRegInitContext(&pRegContext)))
goto ErrorReturn;
//
// Allocate and copy the name into the context
//
if (ERROR_SUCCESS != (dwErr = I_MartaRegDupString(pwszObject,
&pRegContext->pwszObject)))
goto ErrorReturn;
//
// Save another copy of the name since we must crack it.
//
if (ERROR_SUCCESS != (dwErr = I_MartaRegDupString(pwszObject,
&pwszDupObject)))
goto ErrorReturn;
//
// Get the optional machine name and the remaining name
//
if (ERROR_SUCCESS != (dwErr = I_MartaRegParseName(pwszDupObject,
&pwszMachine, &pwszRemaining)))
goto ErrorReturn;
if (NULL == pwszRemaining)
goto InvalidNameReturn;
//
// Get the base key name and the subkey name
//
pwszBaseKey = pwszRemaining;
pwszSubKey = wcschr(pwszRemaining, L'\\');
if (NULL != pwszSubKey) {
*pwszSubKey = L'\0';
pwszSubKey++;
//
// Advance past any more '\'s separating the BaseKey from the SubKey
//
while (L'\\' == *pwszSubKey)
pwszSubKey++;
}
if (0 == _wcsicmp(pwszBaseKey, L"MACHINE")) {
hKeyBase = HKEY_LOCAL_MACHINE;
} else if (0 == _wcsicmp(pwszBaseKey, L"USERS") ||
0 == _wcsicmp(pwszBaseKey, L"USER")) {
hKeyBase = HKEY_USERS;
} else if (NULL == pwszMachine) {
//
// these are only valid on the local machine
//
if (0 == _wcsicmp(pwszBaseKey, L"CLASSES_ROOT")) {
hKeyBase = HKEY_CLASSES_ROOT;
} else if (0 == _wcsicmp(pwszBaseKey, L"CURRENT_USER")) {
hKeyBase = HKEY_CURRENT_USER;
} else if (0 == _wcsicmp(pwszBaseKey, L"CONFIG")) {
hKeyBase = HKEY_CURRENT_CONFIG;
} else {
goto InvalidParameterReturn;
}
} else {
goto InvalidParameterReturn;
}
//
// If it is a remote name, connect to that registry
//
if (pwszMachine) {
if (ERROR_SUCCESS != (dwErr = RegConnectRegistryW(
pwszMachine,
hKeyBase,
&hKeyRemote
)))
goto ErrorReturn;
hKeyBase = hKeyRemote;
}
if (NULL == pwszMachine && (NULL == pwszSubKey || L'\0' == *pwszSubKey))
//
// Opening a predefined handle causes the previously opened handle
// to be closed. Therefore, we won't reopen here.
//
pRegContext->hKey = hKeyBase;
else {
if (ERROR_SUCCESS != (dwErr = RegOpenKeyExW(
hKeyBase,
pwszSubKey,
0, // dwReversed
AccessMask,
&pRegContext->hKey)))
goto ErrorReturn;
pRegContext->dwFlags |= REG_CONTEXT_CLOSE_HKEY_FLAG;
}
dwErr = ERROR_SUCCESS;
CommonReturn:
I_MartaRegFree(pwszDupObject);
if (hKeyRemote)
RegCloseKey(hKeyRemote);
*pContext = (MARTA_CONTEXT) pRegContext;
return dwErr;
ErrorReturn:
if (pRegContext) {
MartaCloseRegistryKeyContext((MARTA_CONTEXT) pRegContext);
pRegContext = NULL;
}
assert(ERROR_SUCCESS != dwErr);
if (ERROR_SUCCESS == dwErr)
dwErr = ERROR_INTERNAL_ERROR;
goto CommonReturn;
InvalidNameReturn:
dwErr = ERROR_INVALID_NAME;
goto ErrorReturn;
InvalidParameterReturn:
dwErr = ERROR_INVALID_PARAMETER;
goto ErrorReturn;
}
void
I_MartaRegFreeFindData(
IN PREG_FIND_DATA pRegFindData
)
/*++
Routine Description:
Free up the memory associated with the internal structure.
Arguments:
pRegFindData - Internal structure to be freed.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
if (NULL == pRegFindData)
return;
if (pRegFindData->pRegParentContext)
MartaCloseRegistryKeyContext(pRegFindData->pRegParentContext);
I_MartaRegFree(pRegFindData);
}
DWORD
MartaCloseRegistryKeyContext(
IN MARTA_CONTEXT Context
)
/*++
Routine Description:
Close the context.
Arguments:
Context - Context to be closed.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
if (NULL == pRegContext || 0 == pRegContext->dwRefCnt)
return ERROR_INVALID_PARAMETER;
//
// If the ref cnt goes to zero then free the handle as well as all other
// associated structures.
//
if (0 == --pRegContext->dwRefCnt) {
if (pRegContext->pRegFindData)
I_MartaRegFreeFindData(pRegContext->pRegFindData);
if (pRegContext->dwFlags & REG_CONTEXT_CLOSE_HKEY_FLAG)
RegCloseKey(pRegContext->hKey);
I_MartaRegFree(pRegContext->pwszObject);
I_MartaRegFree(pRegContext);
}
return ERROR_SUCCESS;
}
DWORD
MartaAddRefRegistryKeyContext(
IN MARTA_CONTEXT Context
)
/*++
Routine Description:
Bump up the ref count for this context.
Arguments:
Context - Context whose ref count should be bumped up.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
if (NULL == pRegContext || 0 == pRegContext->dwRefCnt)
return ERROR_INVALID_PARAMETER;
pRegContext->dwRefCnt++;
return ERROR_SUCCESS;
}
STATIC
inline
BOOL
I_MartaRegIsPredefinedKey(
IN HKEY hKey
)
/*++
Routine Description:
Find if the given key is a predefined key.
Arguments:
key - Handle to the key.
Return Value:
TRUE - if the key is a predefined key.
FALSE - Otherwise.
--*/
{
if (HKEY_CURRENT_USER == hKey ||
HKEY_LOCAL_MACHINE == hKey ||
HKEY_USERS == hKey ||
HKEY_CLASSES_ROOT == hKey ||
HKEY_CURRENT_CONFIG == hKey)
return TRUE;
else
return FALSE;
}
DWORD
MartaOpenRegistryKeyHandleObject(
IN HANDLE Handle,
IN ACCESS_MASK AccessMask,
OUT PMARTA_CONTEXT pContext
)
/*++
Routine Description:
Given a registry key handle, open the context with the desired access mask and
return a context handle.
Arguments:
Handle - Existing registry key handle.
AccessMask - Desired access mask for open.
pContext - To return a handle to the context.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
DWORD dwErr;
HKEY hKey = (HKEY) Handle;
PREG_CONTEXT pRegContext = NULL;
if (ERROR_SUCCESS != (dwErr = I_MartaRegInitContext(&pRegContext)))
goto ErrorReturn;
if (0 == AccessMask || I_MartaRegIsPredefinedKey(hKey))
pRegContext->hKey = hKey;
else {
if (ERROR_SUCCESS != (dwErr = RegOpenKeyExW(
hKey,
NULL, // pwszSubKey
0, // dwReversed
AccessMask,
&pRegContext->hKey)))
goto ErrorReturn;
pRegContext->dwFlags |= REG_CONTEXT_CLOSE_HKEY_FLAG;
}
dwErr = ERROR_SUCCESS;
CommonReturn:
*pContext = (MARTA_CONTEXT) pRegContext;
return dwErr;
ErrorReturn:
if (pRegContext) {
MartaCloseRegistryKeyContext((MARTA_CONTEXT) pRegContext);
pRegContext = NULL;
}
assert(ERROR_SUCCESS != dwErr);
if (ERROR_SUCCESS == dwErr)
dwErr = ERROR_INTERNAL_ERROR;
goto CommonReturn;
}
DWORD
MartaGetRegistryKeyParentContext(
IN MARTA_CONTEXT Context,
IN ACCESS_MASK AccessMask,
OUT PMARTA_CONTEXT pParentContext
)
/*++
Routine Description:
Given the context for a registry key, get the context for its parent.
Arguments:
Context - Context for the registry key.
AccessMask - Desired access mask with which the parent will be opened.
pParentContext - To return the context for the parent.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
DWORD dwErr;
LPWSTR pwszParentObject = NULL;
if (ERROR_SUCCESS != (dwErr = MartaConvertRegistryKeyContextToName(
Context, &pwszParentObject)))
goto ErrorReturn;
if (ERROR_SUCCESS != (dwErr = I_MartaRegGetParentString(
pwszParentObject)))
goto NoParentReturn;
MartaOpenRegistryKeyNamedObject(
pwszParentObject,
AccessMask,
pParentContext
);
//
// Ignore any open errors
//
dwErr = ERROR_SUCCESS;
CommonReturn:
I_MartaRegFree(pwszParentObject);
return dwErr;
NoParentReturn:
dwErr = ERROR_SUCCESS;
ErrorReturn:
*pParentContext = NULL;
goto CommonReturn;
}
DWORD
MartaFindFirstRegistryKey(
IN MARTA_CONTEXT Context,
IN ACCESS_MASK AccessMask,
OUT PMARTA_CONTEXT pChildContext
)
/*++
Routine Description:
FInd the first registry key in the given container.
Arguments:
Context - Context for the container.
AccessMask - Desired access mask for opening the child registry key.
pChildContext - To return the context for the first child in the given container.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
Note:
Does not free up the current context.
--*/
{
DWORD dwErr;
PREG_CONTEXT pRegParentContext = (PREG_CONTEXT) Context;
HKEY hKeyParent = pRegParentContext->hKey;
PREG_CONTEXT pRegFirstContext = NULL;
PREG_FIND_DATA pRegFindData; // freed as part of pRegFirstContext
DWORD cSubKeys;
DWORD cchMaxSubKey;
if (ERROR_SUCCESS != (dwErr = I_MartaRegInitContext(&pRegFirstContext)))
goto ErrorReturn;
if (ERROR_SUCCESS != (dwErr = RegQueryInfoKeyW(
hKeyParent,
NULL, // lpszClass
NULL, // lpcchClass
NULL, // lpdwReserved
&cSubKeys,
&cchMaxSubKey,
NULL, // lpcchMaxClass
NULL, // lpcValues
NULL, // lpcchMaxValuesName
NULL, // lpcbMaxValueData
NULL, // lpcbSecurityDescriptor
NULL // lpftLastWriteTime
)))
goto ErrorReturn;
//
// Above returned count doesn't include the terminating null character
//
cchMaxSubKey++;
//
// Note: HKEY_CURRENT_CONFIG returns a cchMaxSubKey of 0 ????
//
if (MAX_PATH > cchMaxSubKey)
cchMaxSubKey = MAX_PATH;
if (NULL == (pRegFindData = (PREG_FIND_DATA) I_MartaRegZeroAlloc(
sizeof(REG_FIND_DATA) + cchMaxSubKey * sizeof(WCHAR))))
goto NotEnoughMemoryReturn;
pRegFirstContext->pRegFindData = pRegFindData;
MartaAddRefRegistryKeyContext((MARTA_CONTEXT) pRegParentContext);
pRegFindData->pRegParentContext = pRegParentContext;
pRegFindData->cSubKeys = cSubKeys;
pRegFindData->cchMaxSubKey = cchMaxSubKey;
pRegFindData->pwszSubKey =
(LPWSTR) (((BYTE *) pRegFindData) + sizeof(REG_FIND_DATA));
//
// Following closes / frees pRegFirstContext
//
dwErr = MartaFindNextRegistryKey(
(MARTA_CONTEXT) pRegFirstContext,
AccessMask,
pChildContext
);
CommonReturn:
return dwErr;
ErrorReturn:
if (pRegFirstContext)
MartaCloseRegistryKeyContext((MARTA_CONTEXT) pRegFirstContext);
*pChildContext = NULL;
assert(ERROR_SUCCESS != dwErr);
if (ERROR_SUCCESS == dwErr)
dwErr = ERROR_INTERNAL_ERROR;
goto CommonReturn;
NotEnoughMemoryReturn:
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorReturn;
}
DWORD
MartaFindNextRegistryKey(
IN MARTA_CONTEXT Context,
IN ACCESS_MASK AccessMask,
OUT PMARTA_CONTEXT pSiblingContext
)
/*++
Routine Description:
Get the next object in the tree. This is the sibling for the current context.
Arguments:
Context - Context for the current object.
AccessMask - Desired access mask for the opening the sibling.
pSiblingContext - To return a handle for the sibling.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
Note:
Closes the current context.
--*/
{
DWORD dwErr;
PREG_CONTEXT pRegPrevContext = (PREG_CONTEXT) Context;
PREG_CONTEXT pRegSiblingContext = NULL;
//
// Following don't need to be freed or closed
//
PREG_CONTEXT pRegParentContext;
PREG_FIND_DATA pRegFindData;
HKEY hKeyParent;
DWORD cchMaxSubKey;
LPWSTR pwszSubKey;
if (ERROR_SUCCESS != (dwErr = I_MartaRegInitContext(&pRegSiblingContext)))
goto ErrorReturn;
//
// Move the FindData on to the sibling context
//
pRegFindData = pRegPrevContext->pRegFindData;
if (NULL == pRegFindData)
goto InvalidParameterReturn;
pRegPrevContext->pRegFindData = NULL;
pRegSiblingContext->pRegFindData = pRegFindData;
if (pRegFindData->iSubKey >= pRegFindData->cSubKeys)
goto NoMoreItemsReturn;
pRegParentContext = pRegFindData->pRegParentContext;
hKeyParent = pRegParentContext->hKey;
pwszSubKey = pRegFindData->pwszSubKey;
cchMaxSubKey = pRegFindData->cchMaxSubKey;
if (ERROR_SUCCESS != (dwErr = RegEnumKeyExW(
hKeyParent,
pRegFindData->iSubKey,
pwszSubKey,
&cchMaxSubKey,
NULL, // lpdwReserved
NULL, // lpszClass
NULL, // lpcchClass
NULL // lpftLastWriteTime
)))
goto ErrorReturn;
pRegFindData->iSubKey++;
if (pRegParentContext->pwszObject)
//
// Ignore errors. Mainly here for testing purposes.
//
I_MartaRegCreateChildString(
pRegParentContext->pwszObject,
pwszSubKey,
&pRegSiblingContext->pwszObject
);
if (ERROR_SUCCESS == (dwErr = RegOpenKeyExW(
hKeyParent,
pwszSubKey,
0, // dwReversed
AccessMask,
&pRegSiblingContext->hKey)))
pRegSiblingContext->dwFlags |= REG_CONTEXT_CLOSE_HKEY_FLAG;
//
// For an error still return this context. This allows the caller
// to continue on to the next sibling object and know there was an
// error with this sibling object
//
CommonReturn:
MartaCloseRegistryKeyContext(Context);
*pSiblingContext = (MARTA_CONTEXT) pRegSiblingContext;
return dwErr;
ErrorReturn:
if (pRegSiblingContext) {
MartaCloseRegistryKeyContext((MARTA_CONTEXT) pRegSiblingContext);
pRegSiblingContext = NULL;
}
// kedar wants this mapped to success
if (ERROR_NO_MORE_ITEMS == dwErr)
dwErr = ERROR_SUCCESS;
goto CommonReturn;
InvalidParameterReturn:
dwErr = ERROR_INVALID_PARAMETER;
goto ErrorReturn;
NoMoreItemsReturn:
dwErr = ERROR_NO_MORE_ITEMS;
goto ErrorReturn;
}
DWORD
MartaConvertRegistryKeyContextToName(
IN MARTA_CONTEXT Context,
OUT LPWSTR *ppwszObject
)
/*++
Routine Description:
Returns the NT Object Name for the given context. Allocates memory.
Arguments:
Context - Context for the registry key.
ppwszObject - To return the name of the registry key.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
DWORD dwErr = ERROR_SUCCESS;
PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
LPWSTR pwszObject = NULL;
BYTE Buff[512];
ULONG cLen = 0;
POBJECT_NAME_INFORMATION pNI; // not allocated
POBJECT_NAME_INFORMATION pAllocNI = NULL;
NTSTATUS Status;
if (NULL == pRegContext || 0 == pRegContext->dwRefCnt)
goto InvalidParameterReturn;
if (pRegContext->pwszObject) {
//
// Already have the object's name
//
if (ERROR_SUCCESS != (dwErr = I_MartaRegDupString(
pRegContext->pwszObject, &pwszObject)))
goto ErrorReturn;
else
goto SuccessReturn;
} else {
HKEY hKey = pRegContext->hKey;
LPWSTR pwszPath;
DWORD cchPath;
//
// First, determine the size of the buffer we need...
//
pNI = (POBJECT_NAME_INFORMATION) Buff;
Status = NtQueryObject(hKey,
ObjectNameInformation,
pNI,
sizeof(Buff),
&cLen);
if (!NT_SUCCESS(Status) || sizeof(*pNI) > cLen ||
0 == pNI->Name.Length) {
if (Status == STATUS_BUFFER_TOO_SMALL ||
Status == STATUS_INFO_LENGTH_MISMATCH ||
Status == STATUS_BUFFER_OVERFLOW) {
//
// Allocate a big enough buffer
//
if (NULL == (pAllocNI = (POBJECT_NAME_INFORMATION)
I_MartaRegNonzeroAlloc(cLen)))
goto NotEnoughMemoryReturn;
pNI = pAllocNI;
Status = NtQueryObject(hKey,
ObjectNameInformation,
pNI,
cLen,
NULL);
if (!NT_SUCCESS(Status))
goto StatusErrorReturn;
} else {
//
// Check if one of the predefined base keys
//
LPCWSTR pwszBaseKey = NULL;
if (HKEY_LOCAL_MACHINE == hKey)
pwszBaseKey = L"MACHINE";
else if (HKEY_USERS == hKey)
pwszBaseKey = L"USERS";
else if (HKEY_CLASSES_ROOT == hKey)
pwszBaseKey = L"CLASSES_ROOT";
else if (HKEY_CURRENT_USER == hKey)
pwszBaseKey = L"CURRENT_USER";
else if (HKEY_CURRENT_CONFIG == hKey)
pwszBaseKey = L"CONFIG";
else if (!NT_SUCCESS(Status))
goto StatusErrorReturn;
else
goto InvalidHandleReturn;
if (ERROR_SUCCESS != (dwErr = I_MartaRegDupString(
pwszBaseKey, &pwszObject)))
goto ErrorReturn;
else
goto SuccessReturn;
}
}
pwszPath = pNI->Name.Buffer;
cchPath = pNI->Name.Length / sizeof(WCHAR);
if (REG_OBJ_TAG_LEN > cchPath ||
0 != _wcsnicmp(pwszPath, REG_OBJ_TAG, REG_OBJ_TAG_LEN))
goto BadPathnameReturn;
pwszPath += REG_OBJ_TAG_LEN;
cchPath -= REG_OBJ_TAG_LEN;
if (NULL == (pwszObject = (LPWSTR) I_MartaRegNonzeroAlloc(
(cchPath + 1) * sizeof(WCHAR))))
goto NotEnoughMemoryReturn;
memcpy(pwszObject, pwszPath, cchPath * sizeof(WCHAR));
pwszObject[cchPath] = L'\0';
}
SuccessReturn:
dwErr = ERROR_SUCCESS;
CommonReturn:
I_MartaRegFree(pAllocNI);
*ppwszObject = pwszObject;
return dwErr;
StatusErrorReturn:
dwErr = RtlNtStatusToDosError(Status);
ErrorReturn:
assert(NULL == pwszObject);
assert(ERROR_SUCCESS != dwErr);
if (ERROR_SUCCESS == dwErr)
dwErr = ERROR_INTERNAL_ERROR;
goto CommonReturn;
NotEnoughMemoryReturn:
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorReturn;
InvalidHandleReturn:
dwErr = ERROR_INVALID_HANDLE;
goto ErrorReturn;
BadPathnameReturn:
dwErr = ERROR_BAD_PATHNAME;
goto ErrorReturn;
InvalidParameterReturn:
dwErr = ERROR_INVALID_PARAMETER;
goto ErrorReturn;
}
DWORD
MartaConvertRegistryKeyContextToHandle(
IN MARTA_CONTEXT Context,
OUT HANDLE *pHandle
)
/*++
Routine Description:
The following is for testing
The returned Handle isn't duplicated. It has the same lifetime as
the Context
Arguments:
Context - Context whose properties the caller has asked for.
pHandle - To return the handle.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_NOT_ENOUGH_MEMORY if allocation failed.
--*/
{
DWORD dwErr;
PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
if (NULL == pRegContext || 0 == pRegContext->dwRefCnt) {
*pHandle = NULL;
dwErr = ERROR_INVALID_PARAMETER;
} else {
*pHandle = (HANDLE) pRegContext->hKey;
dwErr = ERROR_SUCCESS;
}
return dwErr;
}
DWORD
MartaGetRegistryKeyProperties(
IN MARTA_CONTEXT Context,
IN OUT PMARTA_OBJECT_PROPERTIES pProperties
)
/*++
Routine Description:
Return the properties for registry key represented by the context.
Arguments:
Context - Context whose properties the caller has asked for.
pProperties - To return the properties for this registry key.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
pProperties->dwFlags |= MARTA_OBJECT_IS_CONTAINER;
return ERROR_SUCCESS;
}
DWORD
MartaGetRegistryKeyTypeProperties(
IN OUT PMARTA_OBJECT_TYPE_PROPERTIES pProperties
)
/*++
Routine Description:
Return the properties of registry key objects.
Arguments:
pProperties - To return the properties of registry key objects.
Return Value:
ERROR_SUCCESS.
--*/
{
const GENERIC_MAPPING GenMap = {
KEY_READ,
KEY_WRITE,
KEY_EXECUTE,
KEY_ALL_ACCESS
};
pProperties->dwFlags |= MARTA_OBJECT_TYPE_MANUAL_PROPAGATION_NEEDED_FLAG;
pProperties->dwFlags |= MARTA_OBJECT_TYPE_INHERITANCE_MODEL_PRESENT_FLAG;
pProperties->GenMap = GenMap;
return ERROR_SUCCESS;
}
DWORD
MartaGetRegistryKeyRights(
IN MARTA_CONTEXT Context,
IN SECURITY_INFORMATION SecurityInfo,
OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
)
/*++
Routine Description:
Get the security descriptor for the given handle.
Arguments:
Context - Context for registry key.
SecurityInfo - Type of security information to be read.
ppSecurityDescriptor - To return a self-relative security decriptor pointer.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
DWORD dwErr = ERROR_SUCCESS;
PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
DWORD cbSize;
PISECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
if (NULL == pRegContext || 0 == pRegContext->dwRefCnt)
goto InvalidParameterReturn;
//
// First, get the size we need
//
cbSize = 0;
dwErr = RegGetKeySecurity(
pRegContext->hKey,
SecurityInfo,
NULL, // pSecDesc
&cbSize
);
if (ERROR_INSUFFICIENT_BUFFER == dwErr) {
if (NULL == (pSecurityDescriptor =
(PISECURITY_DESCRIPTOR) I_MartaRegNonzeroAlloc(cbSize)))
goto NotEnoughMemoryReturn;
dwErr = RegGetKeySecurity(
pRegContext->hKey,
SecurityInfo,
pSecurityDescriptor,
&cbSize
);
} else if (ERROR_SUCCESS == dwErr)
dwErr = ERROR_INTERNAL_ERROR;
if (ERROR_SUCCESS != dwErr)
goto ErrorReturn;
CommonReturn:
*ppSecurityDescriptor = pSecurityDescriptor;
return dwErr;
ErrorReturn:
if (pSecurityDescriptor) {
I_MartaRegFree(pSecurityDescriptor);
pSecurityDescriptor = NULL;
}
assert(ERROR_SUCCESS != dwErr);
if (ERROR_SUCCESS == dwErr)
dwErr = ERROR_INTERNAL_ERROR;
goto CommonReturn;
NotEnoughMemoryReturn:
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorReturn;
InvalidParameterReturn:
dwErr = ERROR_INVALID_PARAMETER;
goto ErrorReturn;
}
DWORD
MartaSetRegistryKeyRights(
IN MARTA_CONTEXT Context,
IN SECURITY_INFORMATION SecurityInfo,
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
)
/*++
Routine Description:
Set the given security descriptor on the registry key represented by the context.
Arguments:
Context - Context for the registry key.
SecurityInfo - Type of security info to be stamped on the registry key.
pSecurityDescriptor - Security descriptor to be stamped.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
DWORD dwErr = ERROR_SUCCESS;
PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
if (NULL == pRegContext || 0 == pRegContext->dwRefCnt)
goto InvalidParameterReturn;
dwErr = RegSetKeySecurity(
pRegContext->hKey,
SecurityInfo,
pSecurityDescriptor
);
CommonReturn:
return dwErr;
InvalidParameterReturn:
dwErr = ERROR_INVALID_PARAMETER;
goto CommonReturn;
}
ACCESS_MASK
MartaGetRegistryKeyDesiredAccess(
IN SECURITY_OPEN_TYPE OpenType,
IN BOOL Attribs,
IN SECURITY_INFORMATION SecurityInfo
)
/*++
Routine Description:
Gets the access required to open object to be able to set or get the
specified security info.
Arguments:
OpenType - Flag indicating if the object is to be opened to read or write
the security information
Attribs - TRUE indicates that additional access bits should be returned.
SecurityInfo - owner/group/dacl/sacl
Return Value:
Desired access mask with which open should be called.
--*/
{
ACCESS_MASK DesiredAccess = 0;
if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) ||
(SecurityInfo & GROUP_SECURITY_INFORMATION) )
{
switch (OpenType)
{
case READ_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL;
break;
case WRITE_ACCESS_RIGHTS:
DesiredAccess |= WRITE_OWNER;
break;
case MODIFY_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL | WRITE_OWNER;
break;
}
}
if (SecurityInfo & DACL_SECURITY_INFORMATION)
{
switch (OpenType)
{
case READ_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL;
break;
case WRITE_ACCESS_RIGHTS:
DesiredAccess |= WRITE_DAC;
break;
case MODIFY_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL | WRITE_DAC;
break;
}
}
if (SecurityInfo & SACL_SECURITY_INFORMATION)
{
DesiredAccess |= READ_CONTROL | ACCESS_SYSTEM_SECURITY;
}
if (TRUE == Attribs)
{
DesiredAccess |= KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE;
}
return (DesiredAccess);
}
ACCESS_MASK
MartaGetRegistryKey32DesiredAccess(
IN SECURITY_OPEN_TYPE OpenType,
IN BOOL Attribs,
IN SECURITY_INFORMATION SecurityInfo
)
/*++
Routine Description:
Gets the access required to open object to be able to set or get the
specified security info.
Arguments:
OpenType - Flag indicating if the object is to be opened to read or write
the security information
Attribs - TRUE indicates that additional access bits should be returned.
SecurityInfo - owner/group/dacl/sacl
Return Value:
Desired access mask with which open should be called.
--*/
{
ACCESS_MASK DesiredAccess = KEY_WOW64_32KEY;
if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) ||
(SecurityInfo & GROUP_SECURITY_INFORMATION) )
{
switch (OpenType)
{
case READ_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL;
break;
case WRITE_ACCESS_RIGHTS:
DesiredAccess |= WRITE_OWNER;
break;
case MODIFY_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL | WRITE_OWNER;
break;
}
}
if (SecurityInfo & DACL_SECURITY_INFORMATION)
{
switch (OpenType)
{
case READ_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL;
break;
case WRITE_ACCESS_RIGHTS:
DesiredAccess |= WRITE_DAC;
break;
case MODIFY_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL | WRITE_DAC;
break;
}
}
if (SecurityInfo & SACL_SECURITY_INFORMATION)
{
DesiredAccess |= READ_CONTROL | ACCESS_SYSTEM_SECURITY;
}
if (TRUE == Attribs)
{
DesiredAccess |= KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE;
}
return (DesiredAccess);
}
ACCESS_MASK
MartaGetDefaultDesiredAccess(
IN SECURITY_OPEN_TYPE OpenType,
IN BOOL Attribs,
IN SECURITY_INFORMATION SecurityInfo
)
/*++
Routine Description:
Gets the access required to open object to be able to set or get the
specified security info. This default routine is used for all resource
managers except for files/reg.
Arguments:
OpenType - Flag indicating if the object is to be opened to read or write
the security information
Attribs - TRUE indicates that additional access bits should be returned.
SecurityInfo - owner/group/dacl/sacl
Return Value:
Desired access mask with which open should be called.
--*/
{
ACCESS_MASK DesiredAccess = 0;
if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) ||
(SecurityInfo & GROUP_SECURITY_INFORMATION) )
{
switch (OpenType)
{
case READ_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL;
break;
case WRITE_ACCESS_RIGHTS:
DesiredAccess |= WRITE_OWNER;
break;
case MODIFY_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL | WRITE_OWNER;
break;
}
}
if (SecurityInfo & DACL_SECURITY_INFORMATION)
{
switch (OpenType)
{
case READ_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL;
break;
case WRITE_ACCESS_RIGHTS:
DesiredAccess |= WRITE_DAC;
break;
case MODIFY_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL | WRITE_DAC;
break;
}
}
if (SecurityInfo & SACL_SECURITY_INFORMATION)
{
DesiredAccess |= ACCESS_SYSTEM_SECURITY;
}
return (DesiredAccess);
}
DWORD
MartaReopenRegistryKeyContext(
IN OUT MARTA_CONTEXT Context,
IN ACCESS_MASK AccessMask
)
/*++
Routine Description:
Given the context for a registry key, close the existing handle if one exists
and reopen the context with new permissions.
Arguments:
Context - Context to be reopened.
AccessMask - Permissions for the reopen.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
DWORD dwErr;
HKEY hKey;
PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
PREG_FIND_DATA pRegFindData = pRegContext->pRegFindData;
PREG_CONTEXT pRegParentContext = pRegFindData->pRegParentContext;
dwErr = RegOpenKeyExW(
pRegParentContext->hKey,
pRegFindData->pwszSubKey,
0, // dwReversed
AccessMask,
&hKey);
if (ERROR_SUCCESS == dwErr) {
if (pRegContext->dwFlags & REG_CONTEXT_CLOSE_HKEY_FLAG)
RegCloseKey(pRegContext->hKey);
pRegContext->hKey = hKey;
pRegContext->dwFlags |= REG_CONTEXT_CLOSE_HKEY_FLAG;
}
return dwErr;
}
DWORD
MartaReopenRegistryKeyOrigContext(
IN OUT MARTA_CONTEXT Context,
IN ACCESS_MASK AccessMask
)
/*++
Routine Description:
Reopen the original context with a new access mask. Close the original
handle.
Arguments:
Context - Context to reopen.
AccessMask - Desired access for open.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_NOT_ENOUGH_MEMORY if allocation failed.
--*/
{
DWORD dwErr;
HKEY hKey;
PREG_CONTEXT pRegContext = (PREG_CONTEXT) Context;
dwErr = RegOpenKeyExW(
pRegContext->hKey,
NULL, // pwszSubKey
0, // dwReversed
AccessMask,
&hKey);
if (ERROR_SUCCESS == dwErr) {
if (pRegContext->dwFlags & REG_CONTEXT_CLOSE_HKEY_FLAG)
RegCloseKey(pRegContext->hKey);
pRegContext->hKey = hKey;
pRegContext->dwFlags |= REG_CONTEXT_CLOSE_HKEY_FLAG;
}
return dwErr;
}
DWORD
MartaGetRegistryKeyNameFromContext(
IN MARTA_CONTEXT Context,
OUT LPWSTR *pObjectName
)
/*++
Routine Description:
Get the name of the registry key from the context. This routine allocates
memory required to hold the name of the object.
Arguments:
Context - Handle to the context.
pObjectName - To return the pointer to the allocated string.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
return MartaConvertRegistryKeyContextToName(
Context,
pObjectName
);
}
DWORD
MartaGetRegistryKeyParentName(
IN LPWSTR ObjectName,
OUT LPWSTR *pParentName
)
/*++
Routine Description:
Given the name of a registry key return the name of its parent. The routine
allocates memory required to hold the parent name.
Arguments:
ObjectName - Name of the registry key.
pParentName - To return the pointer to the allocated parent name.
In case of the root of the tree, we return NULL parent with ERROR_SUCCESS.
Return Value:
ERROR_SUCCESS in case of success.
ERROR_* otherwise
--*/
{
ULONG Length = wcslen(ObjectName) + 1;
PWCHAR Name = (PWCHAR) I_MartaRegNonzeroAlloc(sizeof(WCHAR) * Length);
DWORD dwErr = ERROR_SUCCESS;
*pParentName = NULL;
if (!Name)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy((WCHAR *) Name, ObjectName);
dwErr = I_MartaRegGetParentString(Name);
if (ERROR_SUCCESS != dwErr)
{
I_MartaRegFree(Name);
if (ERROR_INVALID_NAME == dwErr)
return ERROR_SUCCESS;
return dwErr;
}
*pParentName = Name;
return dwErr;
}