994 lines
24 KiB
C
994 lines
24 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
registry.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Server side support for Cluster registry database APIs
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
John Vert (jvert) 8-Mar-1996
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
#include "apip.h"
|
|||
|
|
|||
|
|
|||
|
PAPI_HANDLE
|
|||
|
ApipMakeKeyHandle(
|
|||
|
IN HDMKEY Key
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Allocates and initializes an API_HANDLE structure for the
|
|||
|
specified HDMKEY.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Key - Supplies the HDMKEY.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to the initialized API_HANDLE structure on success.
|
|||
|
|
|||
|
NULL on memory allocation failure.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAPI_HANDLE Handle;
|
|||
|
|
|||
|
Handle = LocalAlloc(LMEM_FIXED, sizeof(API_HANDLE));
|
|||
|
if (Handle == NULL) {
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
Handle->Type = API_KEY_HANDLE;
|
|||
|
Handle->Flags = 0;
|
|||
|
Handle->Key = Key;
|
|||
|
InitializeListHead(&Handle->NotifyList);
|
|||
|
return(Handle);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HKEY_RPC
|
|||
|
s_ApiGetRootKey(
|
|||
|
IN handle_t IDL_handle,
|
|||
|
IN DWORD samDesired,
|
|||
|
OUT error_status_t *Status
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Opens the registry key at the root of the cluster registry database
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IDL_handle - Supplies RPC binding handle, not used.
|
|||
|
|
|||
|
samDesired - Supplies requested security access
|
|||
|
|
|||
|
Status - Returns error code, if any.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A handle to the opened registry key.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Error;
|
|||
|
HDMKEY Key;
|
|||
|
PAPI_HANDLE Handle=NULL;
|
|||
|
|
|||
|
*Status = RpcImpersonateClient(NULL);
|
|||
|
if (*Status != RPC_S_OK)
|
|||
|
{
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
Key = DmGetRootKey(samDesired);
|
|||
|
RpcRevertToSelf();
|
|||
|
if (Key == NULL) {
|
|||
|
*Status = GetLastError();
|
|||
|
} else {
|
|||
|
Handle = ApipMakeKeyHandle(Key);
|
|||
|
if (Handle == NULL) {
|
|||
|
DmCloseKey(Key);
|
|||
|
*Status = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
*Status = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
FnExit:
|
|||
|
return(Handle);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HKEY_RPC
|
|||
|
s_ApiCreateKey(
|
|||
|
IN HKEY_RPC hKey,
|
|||
|
IN LPCWSTR lpSubKey,
|
|||
|
IN DWORD dwOptions,
|
|||
|
IN DWORD samDesired,
|
|||
|
IN PRPC_SECURITY_ATTRIBUTES lpSecurityAttributes,
|
|||
|
OUT LPDWORD lpdwDisposition,
|
|||
|
OUT error_status_t *Status
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Creates a key in the cluster registry. If the key exists, it
|
|||
|
is opened. If it does not exist, it is created on all nodes in
|
|||
|
the cluster.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies the key that the create is relative to.
|
|||
|
|
|||
|
lpSubKey - Supplies the key name relative to hKey
|
|||
|
|
|||
|
dwOptions - Supplies any registry option flags. The only currently
|
|||
|
supported option is REG_OPTION_VOLATILE
|
|||
|
|
|||
|
samDesired - Supplies desired security access mask
|
|||
|
|
|||
|
lpSecurityAttributes - Supplies security for the newly created key.
|
|||
|
|
|||
|
Disposition - Returns whether the key was opened (REG_OPENED_EXISTING_KEY)
|
|||
|
or created (REG_CREATED_NEW_KEY)
|
|||
|
|
|||
|
Status - Returns the error code if the function is unsuccessful.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A handle to the specified key if successful
|
|||
|
|
|||
|
NULL otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HDMKEY NewKey;
|
|||
|
PAPI_HANDLE Handle = NULL;
|
|||
|
PAPI_HANDLE RootHandle = NULL;
|
|||
|
|
|||
|
if (hKey != NULL) {
|
|||
|
RootHandle = (PAPI_HANDLE)hKey;
|
|||
|
if (RootHandle->Type != API_KEY_HANDLE) {
|
|||
|
*Status = ERROR_INVALID_HANDLE;
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ApiState != ApiStateOnline) {
|
|||
|
*Status = ERROR_SHARING_PAUSED;
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
|
|||
|
*Status = RpcImpersonateClient(NULL);
|
|||
|
if (*Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
|
|||
|
if ( ARGUMENT_PRESENT( lpSecurityAttributes ) &&
|
|||
|
(lpSecurityAttributes->RpcSecurityDescriptor.lpSecurityDescriptor != NULL) &&
|
|||
|
!RtlValidRelativeSecurityDescriptor( lpSecurityAttributes->RpcSecurityDescriptor.lpSecurityDescriptor,
|
|||
|
lpSecurityAttributes->RpcSecurityDescriptor.cbInSecurityDescriptor,
|
|||
|
0 ) ) {
|
|||
|
*Status = ERROR_INVALID_SECURITY_DESCR;
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
NewKey = DmCreateKey(hKey ? RootHandle->Key : NULL,
|
|||
|
lpSubKey,
|
|||
|
dwOptions,
|
|||
|
samDesired,
|
|||
|
ARGUMENT_PRESENT(lpSecurityAttributes)
|
|||
|
? lpSecurityAttributes->RpcSecurityDescriptor.lpSecurityDescriptor
|
|||
|
: NULL,
|
|||
|
lpdwDisposition);
|
|||
|
if (NewKey == NULL) {
|
|||
|
*Status = GetLastError();
|
|||
|
} else {
|
|||
|
Handle = ApipMakeKeyHandle(NewKey);
|
|||
|
if (Handle == NULL) {
|
|||
|
DmCloseKey(NewKey);
|
|||
|
*Status = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
*Status = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
FnExit:
|
|||
|
RpcRevertToSelf();
|
|||
|
return(Handle);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HKEY_RPC
|
|||
|
s_ApiOpenKey(
|
|||
|
IN HKEY_RPC hKey,
|
|||
|
IN LPCWSTR lpSubKey,
|
|||
|
IN DWORD samDesired,
|
|||
|
OUT error_status_t *Status
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Opens a key in the cluster registry. If the key exists, it
|
|||
|
is opened. If it does not exist, the call fails.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies the key that the open is relative to.
|
|||
|
|
|||
|
lpSubKey - Supplies the key name relative to hKey
|
|||
|
|
|||
|
samDesired - Supplies desired security access mask
|
|||
|
|
|||
|
Status - Returns the error code if the function is unsuccessful.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A handle to the specified key if successful
|
|||
|
|
|||
|
NULL otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HDMKEY NewKey;
|
|||
|
PAPI_HANDLE Handle=NULL;
|
|||
|
PAPI_HANDLE RootHandle;
|
|||
|
|
|||
|
if (hKey != NULL) {
|
|||
|
RootHandle = (PAPI_HANDLE)hKey;
|
|||
|
if (RootHandle->Type != API_KEY_HANDLE) {
|
|||
|
*Status = ERROR_INVALID_HANDLE;
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
*Status = RpcImpersonateClient(NULL);
|
|||
|
if (*Status != RPC_S_OK)
|
|||
|
{
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
NewKey = DmOpenKey((hKey) ? RootHandle->Key : NULL,
|
|||
|
lpSubKey,
|
|||
|
samDesired);
|
|||
|
if (NewKey == NULL) {
|
|||
|
*Status = GetLastError();
|
|||
|
} else {
|
|||
|
Handle = ApipMakeKeyHandle(NewKey);
|
|||
|
if (Handle == NULL) {
|
|||
|
DmCloseKey(NewKey);
|
|||
|
*Status = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
} else {
|
|||
|
*Status = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
RpcRevertToSelf();
|
|||
|
FnExit:
|
|||
|
return(Handle);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
error_status_t
|
|||
|
s_ApiEnumKey(
|
|||
|
IN HKEY_RPC hKey,
|
|||
|
IN DWORD dwIndex,
|
|||
|
OUT LPWSTR *KeyName,
|
|||
|
OUT PFILETIME lpftLastWriteTime
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Enumerates the subkeys of a cluster registry key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies the registry key for which the subkeys should
|
|||
|
be enumerated.
|
|||
|
|
|||
|
dwIndex - Supplies the index to be enumerated.
|
|||
|
|
|||
|
KeyName - Returns the name of the dwIndex subkey. The memory
|
|||
|
allocated for this buffer must be freed by the client.
|
|||
|
|
|||
|
lpftLastWriteTime - Returns the last write time.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if successful
|
|||
|
|
|||
|
Win32 error code otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LONG Status;
|
|||
|
DWORD NameLength;
|
|||
|
HDMKEY DmKey;
|
|||
|
|
|||
|
VALIDATE_KEY(DmKey, hKey);
|
|||
|
|
|||
|
Status = DmQueryInfoKey(DmKey,
|
|||
|
NULL,
|
|||
|
&NameLength,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
if (Status != ERROR_SUCCESS) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
NameLength += 1;
|
|||
|
|
|||
|
*KeyName = MIDL_user_allocate(NameLength*sizeof(WCHAR));
|
|||
|
if (*KeyName == NULL) {
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
Status = DmEnumKey(DmKey,
|
|||
|
dwIndex,
|
|||
|
*KeyName,
|
|||
|
&NameLength,
|
|||
|
lpftLastWriteTime);
|
|||
|
if (Status != ERROR_SUCCESS) {
|
|||
|
MIDL_user_free(*KeyName);
|
|||
|
*KeyName = NULL;
|
|||
|
}
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
s_ApiSetValue(
|
|||
|
IN HKEY_RPC hKey,
|
|||
|
IN LPCWSTR lpValueName,
|
|||
|
IN DWORD dwType,
|
|||
|
IN CONST UCHAR *lpData,
|
|||
|
IN DWORD cbData
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets the named value for the specified
|
|||
|
cluster registry key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies the cluster registry subkey whose value is to be set
|
|||
|
|
|||
|
lpValueName - Supplies the name of the value to be set.
|
|||
|
|
|||
|
dwType - Supplies the value data type
|
|||
|
|
|||
|
lpData - Supplies a pointer to the value data
|
|||
|
|
|||
|
cbData - Supplies the length of the value data.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if successful
|
|||
|
|
|||
|
Win32 error code otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HDMKEY DmKey;
|
|||
|
|
|||
|
VALIDATE_KEY(DmKey, hKey);
|
|||
|
API_CHECK_INIT();
|
|||
|
|
|||
|
return(DmSetValue(DmKey,
|
|||
|
lpValueName,
|
|||
|
dwType,
|
|||
|
lpData,
|
|||
|
cbData));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
s_ApiDeleteValue(
|
|||
|
IN HKEY_RPC hKey,
|
|||
|
IN LPCWSTR lpValueName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Removes the specified value from a given registry subkey
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies the key whose value is to be deleted.
|
|||
|
|
|||
|
lpValueName - Supplies the name of the value to be removed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the function succeeds, the return value is ERROR_SUCCESS.
|
|||
|
|
|||
|
If the function fails, the return value is an error value.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HDMKEY DmKey;
|
|||
|
|
|||
|
VALIDATE_KEY(DmKey, hKey);
|
|||
|
API_CHECK_INIT();
|
|||
|
return(DmDeleteValue(DmKey, lpValueName));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
error_status_t
|
|||
|
s_ApiQueryValue(
|
|||
|
IN HKEY_RPC hKey,
|
|||
|
IN LPCWSTR lpValueName,
|
|||
|
OUT LPDWORD lpValueType,
|
|||
|
OUT PUCHAR lpData,
|
|||
|
IN DWORD cbData,
|
|||
|
OUT LPDWORD lpcbRequired
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Queries a named value for the specified cluster registry subkey
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies the subkey whose value should be queried
|
|||
|
|
|||
|
lpValueName - Supplies the named value to be queried
|
|||
|
|
|||
|
lpValueType - Returns the type of the value's data
|
|||
|
|
|||
|
lpData - Returns the value's data
|
|||
|
|
|||
|
cbData - Supplies the size (in bytes) of the lpData buffer
|
|||
|
Returns the number of bytes copied into the lpData buffer
|
|||
|
If lpData==NULL, cbData is set to the required buffer
|
|||
|
size and the function returns ERROR_SUCCESS
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if successful
|
|||
|
|
|||
|
Win32 error code otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Status;
|
|||
|
DWORD BuffSize;
|
|||
|
HDMKEY DmKey;
|
|||
|
|
|||
|
VALIDATE_KEY(DmKey, hKey);
|
|||
|
|
|||
|
BuffSize = cbData;
|
|||
|
Status = DmQueryValue(DmKey,
|
|||
|
lpValueName,
|
|||
|
lpValueType,
|
|||
|
lpData,
|
|||
|
&BuffSize);
|
|||
|
if ((Status == ERROR_SUCCESS) ||
|
|||
|
(Status == ERROR_MORE_DATA)) {
|
|||
|
*lpcbRequired = BuffSize;
|
|||
|
}
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
s_ApiDeleteKey(
|
|||
|
IN HKEY hKey,
|
|||
|
IN LPCWSTR lpSubKey
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Deletes the specified key. A key that has subkeys cannot
|
|||
|
be deleted.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies a handle to a currently open key.
|
|||
|
|
|||
|
lpSubKey - Points to a null-terminated string specifying the
|
|||
|
name of the key to delete. This parameter cannot be NULL,
|
|||
|
and the specified key must not have subkeys.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the function succeeds, the return value is ERROR_SUCCESS.
|
|||
|
|
|||
|
If the function fails, the return value is an error value.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HDMKEY DmKey;
|
|||
|
|
|||
|
VALIDATE_KEY(DmKey, hKey);
|
|||
|
API_CHECK_INIT();
|
|||
|
return(DmDeleteKey(DmKey, lpSubKey));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
error_status_t
|
|||
|
s_ApiEnumValue(
|
|||
|
IN HKEY_RPC hKey,
|
|||
|
IN DWORD dwIndex,
|
|||
|
OUT LPWSTR *lpValueName,
|
|||
|
OUT LPDWORD lpType,
|
|||
|
OUT UCHAR *lpData,
|
|||
|
IN OUT LPDWORD lpcbData,
|
|||
|
OUT LPDWORD TotalSize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Enumerates the specified value of a registry subkey
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies the registry key handle
|
|||
|
|
|||
|
dwIndex - Supplies the index of the value to be enumerated
|
|||
|
|
|||
|
lpValueName - Returns the name of the dwIndex'th value. The
|
|||
|
memory for this name is allocated on the server and must
|
|||
|
be freed by the client side.
|
|||
|
|
|||
|
lpType - Returns the value data type
|
|||
|
|
|||
|
lpData - Returns the value data
|
|||
|
|
|||
|
lpcbData - Returns the number of bytes written to the lpData buffer.
|
|||
|
|
|||
|
TotalSize - Returns the size of the data
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if successful
|
|||
|
|
|||
|
Win32 error code otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
LONG Status;
|
|||
|
DWORD OriginalNameLength;
|
|||
|
DWORD NameLength;
|
|||
|
DWORD DataLength;
|
|||
|
HDMKEY DmKey;
|
|||
|
|
|||
|
VALIDATE_KEY(DmKey, hKey);
|
|||
|
|
|||
|
Status = DmQueryInfoKey(DmKey,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&NameLength,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
if (Status != ERROR_SUCCESS) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
NameLength += 1;
|
|||
|
|
|||
|
*lpValueName = MIDL_user_allocate(NameLength * sizeof(WCHAR));
|
|||
|
if (*lpValueName == NULL) {
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
*TotalSize = *lpcbData;
|
|||
|
|
|||
|
//
|
|||
|
// Chittur Subbaraman (chitturs) - 3/13/2001
|
|||
|
//
|
|||
|
// First of all, at the beginning of this function, a big enough buffer for lpValueName
|
|||
|
// is allocated. This means that ERROR_SUCCESS or ERROR_MORE_DATA will be returned by
|
|||
|
// DmEnumValue depending ONLY on the size of the lpData buffer. This info is used by
|
|||
|
// by the clusapi layer when it makes a decision based on the return code from this
|
|||
|
// function.
|
|||
|
//
|
|||
|
// Note that *TotalSize is initialized to *lpcbData just above. The TotalSize OUT variable
|
|||
|
// allows the required lpData size to be returned without touching lpcbData. This is
|
|||
|
// important since lpcbData is declared as the sizeof lpData in the IDL file and that is
|
|||
|
// what RPC will consider the lpData buffer size as. So, it is important that if the lpData
|
|||
|
// buffer is not big enough, this function does not change the value of *lpcbData from what
|
|||
|
// it was originally at IN time.
|
|||
|
//
|
|||
|
// Strange behavior of RegEnumValue: If you supply a big enough buffer for lpValueName and
|
|||
|
// a smaller than required buffer for lpData, then RegEnumValue won't bother to fill in
|
|||
|
// lpValueName and will return ERROR_MORE_DATA. This irregular behavior is handled by
|
|||
|
// DmEnumValue.
|
|||
|
//
|
|||
|
// For reference pointers, RPC won't allow a client to pass in NULL pointers. That is why
|
|||
|
// clusapi layer uses dummy variables in case some of the parameters passed in by the
|
|||
|
// client caller is NULL.
|
|||
|
//
|
|||
|
//
|
|||
|
// Behavior of RegEnumValue (assuming lpValueName buffer is big enough):
|
|||
|
// (1) If lpData = NULL and lpcbData = NULL, then returns ERROR_SUCCESS.
|
|||
|
// (2) If lpData = NULL and lpcbData != NULL, then returns ERROR_SUCCESS and sets
|
|||
|
// *lpcbData to total buffer size required.
|
|||
|
// (3) If lpData != NULL and lpcbData != NULL, but the data buffer size is smaller than
|
|||
|
// required size, then returns ERROR_MORE_DATA and sets *lpcbData to the size required.
|
|||
|
// (4) If lpData != NULL and lpcbData != NULL and the buffer is big enough, then returns
|
|||
|
// ERROR_SUCCESS and sets *lpcbData to the size of the data copied into lpData.
|
|||
|
//
|
|||
|
// OUR GOAL: ClusterRegEnumValue == RegEnumValue.
|
|||
|
//
|
|||
|
//
|
|||
|
// The following cases are handled by this function and the clusapi layer. Note that in this
|
|||
|
// analysis, we assume that the client has called into clusapi with a big enough lpValueName
|
|||
|
// buffer size. (If this is not true, then clusapi layer handles that, check ClusterRegEnumValue.)
|
|||
|
//
|
|||
|
// Case 1: Client passes in lpData=NULL, lpcbData=NULL to ClusterRegEnumValue.
|
|||
|
//
|
|||
|
// In this case, the clusapi layer will point both lpData and lpcbData to local dummy
|
|||
|
// variables and initialize *lpcbData to 0. Thus, s_ApiEnumValue will see
|
|||
|
// both lpData and lpcbData as valid pointers. If the data value is bigger than the size of
|
|||
|
// *lpcbData, then DmEnumValue will return ERROR_MORE_DATA. In this case, *TotalSize will
|
|||
|
// contain the required buffer size and *lpcbData will be untouched. The client detects this
|
|||
|
// error code and sets the return status to ERROR_SUCCESS and *lpcbData to *TotalSize. Note
|
|||
|
// that the 2nd action has less relevance since lpcbData is pointing to a local dummy variable.
|
|||
|
// If the data value is of zero size, DmEnumValue will return ERROR_SUCCESS.
|
|||
|
// In such a case, *lpcbData will be set to *TotalSize before returning by this function.
|
|||
|
// Note that since the data size is 0, DmEnumValue would set *TotalSize to 0 and hence
|
|||
|
// *lpcbData will also be set to 0. Thus, in this case, when ApiEnumValue returns to the
|
|||
|
// clusapi layer, lpValueName will be filled in, *lpData will not be changed and *lpcbData
|
|||
|
// will be set to 0.
|
|||
|
//
|
|||
|
// Case 2: Client passes in lpData=NULL, lpcbData!=NULL and *lpcbData=0 to ClusterRegEnumValue.
|
|||
|
//
|
|||
|
// In this case, lpData alone will be pointing to a dummy clusapi buffer when ApiEnumValue
|
|||
|
// is invoked. Thus, s_ApiEnumValue will get both lpData and lpcbData as valid pointers.
|
|||
|
// If the data size is non-zero, then DmEnumValue will return ERROR_MORE_DATA and
|
|||
|
// *TotalSize will contain the size of the required buffer. When this function returns,
|
|||
|
// *lpcbData will remain untouched. As in case 1, the clusapi layer will set status
|
|||
|
// to ERROR_SUCCESS and *lpcbData to *TotalSize. Thus, the client will see the required
|
|||
|
// buffer size in *lpcbData. If the data size is zero, then it is handled as in case 1.
|
|||
|
//
|
|||
|
// Case 3: Client passes in lpData!=NULL, lpcbData!=NULL, but the data buffer size is smaller than
|
|||
|
// required.
|
|||
|
//
|
|||
|
// In this case, both lpData and lpcbData will be pointing to client buffers (or RPC buffers
|
|||
|
// representing them) at the entry to s_ApiEnumValue. DmEnumValue will return ERROR_MORE_DATA
|
|||
|
// and this function will return the size required in *TotalSize. *lpcbData will not be
|
|||
|
// touched. At the clusapi layer, *lpcbData will be set to *TotalSize and ERROR_MORE_DATA
|
|||
|
// will be returned to the client.
|
|||
|
//
|
|||
|
// Case 4: Client passes in lpData!=NULL, lpcbData!=NULL and the data buffer size is big enough.
|
|||
|
//
|
|||
|
// In this case, as in case 3, s_ApiEnumValue will have lpData and lpcbData pointing to
|
|||
|
// client buffers. DmEnumValue will return ERROR_SUCCESS, data copied to lpData and
|
|||
|
// *lpcbData will be set to *TotalSize (which is the size of the data copied into the
|
|||
|
// lpData buffer), before returning. The clusapi layer will return these values to the client.
|
|||
|
//
|
|||
|
Status = DmEnumValue(DmKey,
|
|||
|
dwIndex,
|
|||
|
*lpValueName,
|
|||
|
&NameLength,
|
|||
|
lpType,
|
|||
|
lpData,
|
|||
|
TotalSize);
|
|||
|
|
|||
|
if (Status == ERROR_MORE_DATA) {
|
|||
|
return(Status);
|
|||
|
} else if (Status != ERROR_SUCCESS) {
|
|||
|
MIDL_user_free(*lpValueName);
|
|||
|
*lpValueName = NULL;
|
|||
|
*lpcbData = 0;
|
|||
|
} else {
|
|||
|
// This tells RPC how big the lpData buffer
|
|||
|
// is so it can copy the buffer to the client.
|
|||
|
*lpcbData = *TotalSize;
|
|||
|
}
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
error_status_t
|
|||
|
s_ApiQueryInfoKey(
|
|||
|
IN HKEY_RPC hKey,
|
|||
|
OUT LPDWORD lpcSubKeys,
|
|||
|
OUT LPDWORD lpcbMaxSubKeyLen,
|
|||
|
OUT LPDWORD lpcValues,
|
|||
|
OUT LPDWORD lpcbMaxValueNameLen,
|
|||
|
OUT LPDWORD lpcbMaxValueLen,
|
|||
|
OUT LPDWORD lpcbSecurityDescriptor,
|
|||
|
OUT PFILETIME lpftLastWriteTime
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Retrieves information about a specified cluster registry key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies the handle of the key.
|
|||
|
|
|||
|
lpcSubKeys - Points to a variable that receives the number of subkeys
|
|||
|
contained by the specified key.
|
|||
|
|
|||
|
lpcbMaxSubKeyLen - Points to a variable that receives the length, in
|
|||
|
characters, of the key's subkey with the longest name.
|
|||
|
The count returned does not include the terminating null character.
|
|||
|
|
|||
|
lpcValues - Points to a variable that receives the number of values
|
|||
|
associated with the key.
|
|||
|
|
|||
|
lpcbMaxValueNameLen - Points to a variable that receives the length,
|
|||
|
in characters, of the key's longest value name. The count
|
|||
|
returned does not include the terminating null character.
|
|||
|
|
|||
|
lpcbMaxValueLen - Points to a variable that receives the length, in
|
|||
|
bytes, of the longest data component among the key's values.
|
|||
|
|
|||
|
lpcbSecurityDescriptor - Points to a variable that receives the length,
|
|||
|
in bytes, of the key's security descriptor.
|
|||
|
|
|||
|
lpftLastWriteTime - Pointer to a FILETIME structure.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if successful
|
|||
|
|
|||
|
Win32 error code otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HDMKEY DmKey;
|
|||
|
DWORD Status;
|
|||
|
|
|||
|
VALIDATE_KEY(DmKey, hKey);
|
|||
|
|
|||
|
Status = DmQueryInfoKey(DmKey,
|
|||
|
lpcSubKeys,
|
|||
|
lpcbMaxSubKeyLen,
|
|||
|
lpcValues,
|
|||
|
lpcbMaxValueNameLen,
|
|||
|
lpcbMaxValueLen,
|
|||
|
lpcbSecurityDescriptor,
|
|||
|
lpftLastWriteTime);
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
error_status_t
|
|||
|
s_ApiCloseKey(
|
|||
|
IN OUT HKEY_RPC *pKey
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Closes a cluster registry key
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pKey - Supplies the key to be closed
|
|||
|
Returns NULL
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HDMKEY DmKey;
|
|||
|
DWORD Status;
|
|||
|
|
|||
|
VALIDATE_KEY(DmKey, *pKey);
|
|||
|
|
|||
|
Status = RpcImpersonateClient(NULL);
|
|||
|
if (Status != ERROR_SUCCESS) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
Status = DmCloseKey(DmKey);
|
|||
|
RpcRevertToSelf();
|
|||
|
|
|||
|
LocalFree(*pKey);
|
|||
|
*pKey = NULL;
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
HKEY_RPC_rundown(
|
|||
|
IN HKEY_RPC Key
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
RPC rundown routine for cluster registry keys
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Key - Supplies the handle to be rundown
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HDMKEY DmKey;
|
|||
|
|
|||
|
//this should not call impersonate client
|
|||
|
|
|||
|
if (((PAPI_HANDLE)(Key))->Type == API_KEY_HANDLE)
|
|||
|
{
|
|||
|
DmKey = ((PAPI_HANDLE)(Key))->Key; \
|
|||
|
DmCloseKey(DmKey);
|
|||
|
LocalFree(Key);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
s_ApiSetKeySecurity(
|
|||
|
IN HKEY hKey,
|
|||
|
IN DWORD SecurityInformation,
|
|||
|
IN PRPC_SECURITY_DESCRIPTOR pRpcSecurityDescriptor
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Sets the security on the specified registry key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies a handle to a currently open key.
|
|||
|
|
|||
|
SecurityInformation - Supplies the type of security information to
|
|||
|
be set.
|
|||
|
|
|||
|
pRpcSecurityDescriptor - Supplies the security information
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the function succeeds, the return value is ERROR_SUCCESS.
|
|||
|
|
|||
|
If the function fails, the return value is an error value.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HDMKEY DmKey;
|
|||
|
DWORD Status;
|
|||
|
PSECURITY_DESCRIPTOR pSecurityDescriptor;
|
|||
|
|
|||
|
VALIDATE_KEY(DmKey, hKey);
|
|||
|
API_CHECK_INIT();
|
|||
|
|
|||
|
pSecurityDescriptor = pRpcSecurityDescriptor->lpSecurityDescriptor;
|
|||
|
if (!RtlValidRelativeSecurityDescriptor( pSecurityDescriptor,
|
|||
|
pRpcSecurityDescriptor->cbInSecurityDescriptor,0)){
|
|||
|
return(ERROR_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
Status = RpcImpersonateClient(NULL);
|
|||
|
if (Status != ERROR_SUCCESS) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
Status = DmSetKeySecurity(DmKey, SecurityInformation, pSecurityDescriptor);
|
|||
|
RpcRevertToSelf();
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
s_ApiGetKeySecurity(
|
|||
|
IN HKEY hKey,
|
|||
|
IN DWORD SecurityInformation,
|
|||
|
IN PRPC_SECURITY_DESCRIPTOR pRpcSecurityDescriptor
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Gets the security from the specified registry key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hKey - Supplies a handle to a currently open key.
|
|||
|
|
|||
|
SecurityInformation - Supplies the type of security information to
|
|||
|
be retrieved.
|
|||
|
|
|||
|
pRpcSecurityDescriptor - Returns the security information
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the function succeeds, the return value is ERROR_SUCCESS.
|
|||
|
|
|||
|
If the function fails, the return value is an error value.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HDMKEY DmKey;
|
|||
|
DWORD cbLength;
|
|||
|
DWORD Status;
|
|||
|
PSECURITY_DESCRIPTOR lpSD;
|
|||
|
|
|||
|
VALIDATE_KEY(DmKey, hKey);
|
|||
|
API_CHECK_INIT();
|
|||
|
|
|||
|
cbLength = pRpcSecurityDescriptor->cbInSecurityDescriptor;
|
|||
|
lpSD = LocalAlloc(LMEM_FIXED, cbLength);
|
|||
|
if (lpSD == NULL) {
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
Status = RpcImpersonateClient(NULL);
|
|||
|
if (Status != ERROR_SUCCESS) {
|
|||
|
LocalFree(lpSD);
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
Status = DmGetKeySecurity(DmKey, SecurityInformation, lpSD, &cbLength);
|
|||
|
RpcRevertToSelf();
|
|||
|
if (Status == ERROR_SUCCESS) {
|
|||
|
Status = MapSDToRpcSD(lpSD, pRpcSecurityDescriptor);
|
|||
|
}
|
|||
|
if (Status != ERROR_SUCCESS) {
|
|||
|
pRpcSecurityDescriptor->cbInSecurityDescriptor = cbLength;
|
|||
|
pRpcSecurityDescriptor->cbOutSecurityDescriptor = 0;
|
|||
|
}
|
|||
|
|
|||
|
LocalFree(lpSD);
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|