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);
|
||
}
|
||
|