1927 lines
42 KiB
C++
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;
|
||
|
|
||
|
}
|
||
|
|