windows-nt/Source/XPSP1/NT/base/cluster/service/api/registry.c

994 lines
24 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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);
}